Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
att
GitHub Repository: att/ast
Path: blob/master/src/lib/libvdelta/vd01/vddelta01.c
1810 views
1
/***********************************************************************
2
* *
3
* This software is part of the ast package *
4
* Copyright (c) 1995-2011 AT&T Intellectual Property *
5
* and is licensed under the *
6
* Eclipse Public License, Version 1.0 *
7
* by AT&T Intellectual Property *
8
* *
9
* A copy of the License is available at *
10
* http://www.eclipse.org/org/documents/epl-v10.html *
11
* (with md5 checksum b35adb5213ca9657e911e9befb180842) *
12
* *
13
* Information and Software Systems Research *
14
* AT&T Research *
15
* Florham Park NJ *
16
* *
17
* Phong Vo <[email protected]> *
18
* *
19
***********************************************************************/
20
#include "vdelhdr01.h"
21
22
/* Compute a transformation that takes source data to target data
23
**
24
** Written by Kiem-Phong Vo, [email protected], 5/20/94
25
*/
26
27
#ifdef DEBUG
28
long S_copy, S_add; /* amount of input covered by COPY and ADD */
29
long N_copy, N_add; /* # of COPY and ADD instructions */
30
long M_copy, M_add; /* max size of a COPY or ADD instruction */
31
long N_merge; /* # of merged instructions */
32
#endif
33
34
#define MERGABLE(a,c,k) ((a) > 0 && A_ISTINY(a) && \
35
(c) > 0 && C_ISTINY(c) && \
36
(k) >= K_SELF )
37
38
typedef struct _match_s Match_t;
39
typedef struct _table_s Table_t;
40
struct _match_s
41
{ Match_t* next; /* linked list ptr */
42
};
43
struct _table_s
44
{ Vdio_t io; /* io structure */
45
uchar* src; /* source string */
46
int n_src;
47
uchar* tar; /* target string */
48
int n_tar;
49
K_DDECL(quick,recent,rhere); /* address caches */
50
Match_t* base; /* base of elements */
51
int size; /* size of hash table */
52
Match_t** table; /* hash table */
53
};
54
55
/* encode and output delta instructions */
56
#if __STD_C
57
static int vdputinst(Table_t* tab, uchar* begs, uchar* here, Match_t* match, int n_copy)
58
#else
59
static int vdputinst(tab, begs, here, match, n_copy)
60
Table_t* tab;
61
uchar* begs; /* ADD data if any */
62
uchar* here; /* current location */
63
Match_t* match; /* best match if any */
64
int n_copy; /* length of match */
65
#endif
66
{
67
reg int n_add, i_add, i_copy, k_type;
68
reg int n, c_addr, copy, best, d;
69
70
n_add = begs ? here-begs : 0; /* add size */
71
c_addr = (here-tab->tar)+tab->n_src; /* current address */
72
k_type = 0;
73
74
if(match) /* process the COPY instruction */
75
{ /**/DBTOTAL(N_copy,1); DBTOTAL(S_copy,n_copy); DBMAX(M_copy,n_copy);
76
77
best = copy = match - tab->base;
78
k_type = K_SELF;
79
if((d = c_addr - copy) < best)
80
{ best = d;
81
k_type = K_HERE;
82
}
83
for(n = 0; n < K_RTYPE; ++n)
84
{ if((d = copy - tab->recent[n]) < 0 || d >= best)
85
continue;
86
best = d;
87
k_type = K_RECENT+n;
88
}
89
if(best >= I_MORE && tab->quick[n = copy%K_QSIZE] == copy)
90
{ for(d = K_QTYPE-1; d > 0; --d)
91
if(n >= (d<<VD_BITS) )
92
break;
93
best = n - (d<<VD_BITS); /**/ASSERT(best < (1<<VD_BITS));
94
k_type = K_QUICK+d;
95
}
96
97
/**/ASSERT(best >= 0);
98
/**/ASSERT((k_type+K_MERGE) < (1<<I_BITS) );
99
100
/* update address caches */
101
K_UPDATE(tab->quick,tab->recent,tab->rhere,copy);
102
103
/* see if mergable to last ADD instruction */
104
if(MERGABLE(n_add,n_copy,k_type) )
105
{ /**/DBTOTAL(N_merge,1);
106
i_add = K_TPUT(k_type)|A_TPUT(n_add)|C_TPUT(n_copy);
107
}
108
else
109
{ i_copy = K_PUT(k_type);
110
if(C_ISLOCAL(n_copy) )
111
i_copy |= C_LPUT(n_copy);
112
}
113
}
114
115
if(n_add > 0)
116
{ /**/DBTOTAL(N_add,1); DBTOTAL(S_add,n_add); DBMAX(M_add,n_add);
117
118
if(!MERGABLE(n_add,n_copy,k_type) )
119
i_add = A_ISLOCAL(n_add) ? A_LPUT(n_add) : 0;
120
121
if(VDPUTC((Vdio_t*)tab,i_add) < 0 )
122
return -1;
123
if(!A_ISLOCAL(n_add) &&
124
(*_Vdputu)((Vdio_t*)tab, (ulong)A_PUT(n_add)) < 0 )
125
return -1;
126
if((*_Vdwrite)((Vdio_t*)tab, begs, n_add) < 0 )
127
return -1;
128
}
129
130
if(n_copy > 0)
131
{ if(!MERGABLE(n_add,n_copy,k_type) && VDPUTC((Vdio_t*)tab,i_copy) < 0 )
132
return -1;
133
134
if(!C_ISLOCAL(n_copy) &&
135
(*_Vdputu)((Vdio_t*)tab, (ulong)C_PUT(n_copy)) < 0 )
136
return -1;
137
138
if(k_type >= K_QUICK && k_type < (K_QUICK+K_QTYPE) )
139
{ if(VDPUTC((Vdio_t*)tab,(uchar)best) < 0 )
140
return -1;
141
}
142
else
143
{ if((*_Vdputu)((Vdio_t*)tab, (ulong)best) < 0 )
144
return -1;
145
}
146
}
147
else
148
{ if((*_Vdflsbuf)((Vdio_t*)tab) < 0)
149
return -1;
150
}
151
152
return 0;
153
}
154
155
156
/* Fold a string */
157
#if __STD_C
158
static int vdfold(Table_t* tab, int output)
159
#else
160
static int vdfold(tab, output)
161
Table_t* tab;
162
int output;
163
#endif
164
{
165
reg ulong key, n;
166
reg uchar *s, *sm, *ends, *ss, *heade;
167
reg Match_t *m, *list, *curm, *bestm;
168
reg uchar *add, *endfold;
169
reg int head, len, n_src = tab->n_src;
170
reg int size = tab->size;
171
reg uchar *src = tab->src, *tar = tab->tar;
172
reg Match_t *base = tab->base, **table = tab->table;
173
174
if(!output)
175
{ if(tab->n_src < M_MIN)
176
return 0;
177
endfold = (s = src) + tab->n_src;
178
curm = base;
179
}
180
else
181
{ endfold = (s = tar) + tab->n_tar;
182
curm = base+n_src;
183
if(tab->n_tar < M_MIN)
184
return vdputinst(tab,s,endfold,NIL(Match_t*),0);
185
}
186
187
add = NIL(uchar*);
188
bestm = NIL(Match_t*);
189
len = M_MIN-1;
190
HINIT(key,s,n);
191
for(;;)
192
{ for(;;) /* search for the longest match */
193
{ if(!(m = table[key&size]) )
194
goto endsearch;
195
list = m = m->next; /* head of list */
196
197
if(bestm) /* skip over past elements */
198
{ for(;;)
199
{ if(m >= bestm+len)
200
break;
201
if((m = m->next) == list)
202
goto endsearch;
203
}
204
}
205
206
head = len - (M_MIN-1); /* header before the match */
207
heade = s+head;
208
for(;;)
209
{ if((n = m-base) < n_src)
210
{ if(n < head)
211
goto next;
212
sm = src + n;
213
}
214
else
215
{ if((n -= n_src) < head)
216
goto next;
217
sm = tar + n;
218
}
219
220
/* make sure that the M_MIN bytes match */
221
if(!EQUAL(heade,sm))
222
goto next;
223
224
/* make sure this is a real match */
225
for(sm -= head, ss = s; ss < heade; )
226
if(*sm++ != *ss++)
227
goto next;
228
ss += M_MIN;
229
sm += M_MIN;
230
ends = endfold;
231
if((m-base) < n_src && (n = (src+n_src)-sm) < (ends-s) )
232
ends = s+n;
233
for(; ss < ends; ++ss, ++sm)
234
if(*sm != *ss)
235
goto extend;
236
goto extend;
237
238
next: if((m = m->next) == list )
239
goto endsearch;
240
}
241
242
extend: bestm = m-head;
243
n = len;
244
len = ss-s;
245
if(ss >= endfold) /* already match everything */
246
goto endsearch;
247
248
/* check for a longer match */
249
ss -= M_MIN-1;
250
if(len == n+1)
251
HNEXT(key,ss,n);
252
else HINIT(key,ss,n);
253
}
254
255
endsearch:
256
if(bestm)
257
{ if(output && vdputinst(tab,add,s,bestm,len) < 0)
258
return -1;
259
260
/* add a sufficient number of suffices */
261
ends = (s += len);
262
ss = ends - (M_MIN-1);
263
if(!output)
264
curm = base + (ss-src);
265
else curm = base + n_src + (ss-tar);
266
267
len = M_MIN-1;
268
add = NIL(uchar*);
269
bestm = NIL(Match_t*);
270
}
271
else
272
{ if(!add)
273
add = s;
274
ss = s;
275
ends = (s += 1); /* add one prefix */
276
}
277
278
if(ends > (endfold - (M_MIN-1)) )
279
ends = endfold - (M_MIN-1);
280
281
if(ss < ends) for(;;) /* add prefices/suffices */
282
{ n = key&size;
283
if(!(m = table[n]) )
284
curm->next = curm;
285
else
286
{ curm->next = m->next;
287
m->next = curm;
288
}
289
table[n] = curm++;
290
291
if((ss += 1) >= ends)
292
break;
293
HNEXT(key,ss,n);
294
}
295
296
if(s > endfold-M_MIN) /* too short to match */
297
{ if(!add)
298
add = s;
299
break;
300
}
301
302
HNEXT(key,s,n);
303
}
304
305
if(output) /* flush output */
306
return vdputinst(tab,add,endfold,NIL(Match_t*),0);
307
return 0;
308
}
309
310
311
#if __STD_C
312
long _vddelta_01(Vddisc_t* source, Vddisc_t* target, Vddisc_t* delta, long window)
313
#else
314
long _vddelta_01(source, target, delta, window)
315
Vddisc_t* source; /* source data */
316
Vddisc_t* target; /* target data */
317
Vddisc_t* delta; /* transform output data */
318
long window; /* amount to process each time */
319
#endif
320
{
321
reg int size, k, n;
322
reg long p, n_src, n_tar;
323
Table_t tab;
324
325
if(!target || (n_tar = target->size) < 0)
326
return -1;
327
if(n_tar > 0 && !target->data && !target->readf)
328
return -1;
329
330
if((n_src = source ? source->size : 0) < 0)
331
n_src = 0;
332
if(n_src > 0 && !source->data && !source->readf)
333
return -1;
334
335
if(!delta || (!delta->data && !delta->writef) )
336
return -1;
337
338
tab.n_src = tab.n_tar = tab.size = 0;
339
tab.tar = tab.src = NIL(uchar*);
340
tab.base = NIL(Match_t*);
341
tab.table = NIL(Match_t**);
342
INIT(&tab.io,delta);
343
344
if(window <= 0)
345
window = DFLTWINDOW;
346
else if(window > MAXWINDOW)
347
window = MAXWINDOW;
348
if(window > n_tar)
349
window = n_tar;
350
if(n_src > 0 && window > n_src)
351
window = n_src;
352
353
/* try to allocate working space */
354
while(window > 0)
355
{ /* space for the target string */
356
size = (n_tar == 0 || target->data) ? 0 : (int)window;
357
if((long)size > n_tar)
358
size = (int)n_tar;
359
if(size > 0 && !(tab.tar = (uchar*)malloc(size*sizeof(uchar))) )
360
goto reduce_window;
361
362
/* space for sliding header or source string */
363
if(n_src <= 0) /* compression only */
364
size = target->data ? 0 : HEADER(window);
365
else /* differencing */
366
{ size = source->data ? 0 : window;
367
if((long)size > n_src)
368
size = (int)n_src;
369
}
370
if(size > 0 && !(tab.src = (uchar*)malloc(size*sizeof(uchar))) )
371
goto reduce_window;
372
373
/* space for the hash table elements */
374
size = (int)(window < n_tar ? window : n_tar);
375
if(n_src <= 0)
376
size += (int)(window < n_tar ? HEADER(window) : 0);
377
else size += (int)(window < n_src ? window : n_src);
378
if(!(tab.base = (Match_t*)malloc(size*sizeof(Match_t))) )
379
goto reduce_window;
380
381
/* space for the hash table */
382
n = size/2;
383
do (size = n); while((n &= n-1) != 0);
384
if(size < 64)
385
size = 64;
386
while(!(tab.table = (Match_t**)malloc(size*sizeof(Match_t*))) )
387
if((size >>= 1) <= 0)
388
goto reduce_window;
389
390
/* if get here, successful */
391
tab.size = size-1;
392
break;
393
394
reduce_window:
395
if(tab.tar)
396
{ free((Void_t*)tab.tar);
397
tab.tar = NIL(uchar*);
398
}
399
if(tab.src)
400
{ free((Void_t*)tab.src);
401
tab.src = NIL(uchar*);
402
}
403
if(tab.base)
404
{ free((Void_t*)tab.base);
405
tab.base = NIL(Match_t*);
406
}
407
if((window >>= 1) <= 0)
408
return -1;
409
}
410
411
/* amount processed */
412
n = 0;
413
414
/* output magic bytes and sizes */
415
for(k = 0; VD_MAGIC[k]; k++)
416
;
417
if((*_Vdwrite)(&tab.io,(uchar*)VD_MAGIC,k) != k ||
418
(*_Vdputu)(&tab.io,(ulong)n_tar) <= 0 ||
419
(*_Vdputu)(&tab.io,(ulong)n_src) <= 0 ||
420
(*_Vdputu)(&tab.io,(ulong)window) <= 0 )
421
goto done;
422
423
/* do one window at a time */
424
while(n < n_tar)
425
{ /* prepare the source string */
426
if(n_src <= 0) /* data compression */
427
{ if(n <= 0)
428
tab.n_src = 0;
429
else
430
{ size = (int)HEADER(window);
431
if(target->data)
432
tab.src = tab.tar + tab.n_tar - size;
433
else memcpy((Void_t*)tab.src,
434
(Void_t*)(tab.tar + tab.n_tar - size),
435
size );
436
tab.n_src = size;
437
}
438
}
439
else /* data differencing */
440
{ if(n < n_src)
441
{ if(n+window > n_src)
442
p = n_src-window;
443
else p = n;
444
if(source->data)
445
tab.src = (uchar*)source->data + p;
446
else
447
{ size = (*source->readf)
448
(tab.src, (int)window, p, source);
449
if((long)size != window)
450
goto done;
451
}
452
} /* else use last window */
453
454
tab.n_src = window;
455
}
456
457
/* prepare the target string */
458
size = (int)((n_tar-n) < window ? (n_tar-n) : window);
459
tab.n_tar = size;
460
if(target->data)
461
tab.tar = (uchar*)target->data + n;
462
else
463
{ size = (*target->readf)(tab.tar, size, (long)n, target);
464
if((long)size != tab.n_tar)
465
goto done;
466
}
467
468
/* reinitialize table before processing */
469
for(k = tab.size; k >= 0; --k)
470
tab.table[k] = NIL(Match_t*);
471
K_INIT(tab.quick,tab.recent,tab.rhere);
472
473
if(tab.n_src > 0 && vdfold(&tab,0) < 0)
474
goto done;
475
if(vdfold(&tab,1) < 0)
476
goto done;
477
478
n += size;
479
}
480
481
done:
482
if(!target->data && tab.tar)
483
free((Void_t*)tab.tar);
484
if(tab.src && ((n_src <= 0 && !target->data) || (n_src > 0 && !source->data) ) )
485
free((Void_t*)tab.src);
486
if(tab.base)
487
free((Void_t*)tab.base);
488
if(tab.table)
489
free((Void_t*)tab.table);
490
491
return tab.io.here + (tab.io.next - tab.io.data);
492
}
493
494