Initial import of the CDE 2.1.30 sources from the Open Group.

This commit is contained in:
Peter Howkins
2012-03-10 18:21:40 +00:00
commit 83b6996daa
18978 changed files with 3945623 additions and 0 deletions

View File

@@ -0,0 +1,6 @@
/* $XConsortium: Makefile /main/2 1996/05/10 17:21:11 drk $ */
:PACKAGE: ast
vdelta 1.0 :LIBRARY: vdelta.3 vdelhdr.h vdelta.h vddelta.c vdio.c vdupdate.c
$(INCLUDEDIR) :INSTALLDIR: vdelta.h

View File

@@ -0,0 +1,153 @@
note : : make abstract machine file generated from Makefile : : note
info mam static 00000 07/17/94 make (AT&T Bell Laboratories) 3.2 research 07/17/95
setv INSTALLROOT ../../..
setv PACKAGE_ast ${INSTALLROOT}
setv PACKAGE_ast_INCLUDE ${PACKAGE_ast}/include
setv PACKAGE_ast_LIB ${PACKAGE_ast}/lib
setv AR ar
setv ARFLAGS cr
setv AS as
setv ASFLAGS
setv CC cc
setv CCFLAGS "-O"
setv COTEMP $$
setv CPIO cpio
setv CPIOFLAGS
setv CPP "${CC} -E"
setv F77 f77
setv HOSTCC ${CC}
setv IGNORE
setv LD ld
setv LDFLAGS
setv LEX lex
setv LEXFLAGS
setv LPR lpr
setv LPRFLAGS
setv M4FLAGS
setv MAKE nmake
setv MAKEFLAGS
setv PR pr
setv PRFLAGS
setv SHELL /bin/sh
setv SILENT
setv TAR tar
setv YACC yacc
setv YACCFLAGS -d
make install
make all
make vdelta
make libvdelta.a archive
make vddelta.o
make vddelta.c
make vdelhdr.h implicit
done vdelhdr.h
done vddelta.c
prev vddelta.c
exec - ${CC} ${CCFLAGS} -I. -I${INSTALLROOT}/include/ast -D_PACKAGE_ast -c vddelta.c
done vddelta.o generated
make vdio.o
make vdio.c
prev vdelhdr.h implicit
done vdio.c
prev vdio.c
exec - ${CC} ${CCFLAGS} -I. -I${INSTALLROOT}/include/ast -D_PACKAGE_ast -c vdio.c
done vdio.o generated
make vdupdate.o
make vdupdate.c
prev vdelhdr.h implicit
done vdupdate.c
prev vdupdate.c
exec - ${CC} ${CCFLAGS} -I. -I${INSTALLROOT}/include/ast -D_PACKAGE_ast -c vdupdate.c
done vdupdate.o generated
exec - ${AR} cr libvdelta.a vddelta.o vdio.o vdupdate.o
exec - (ranlib libvdelta.a) >/dev/null 2>&1 || true
done libvdelta.a generated
done vdelta virtual
prev libvdelta.a archive
done all virtual
make ${INSTALLROOT}/lib
exec - set -
exec - if test ! -d ${INSTALLROOT}/lib
exec - then set -x && mkdir -p ${INSTALLROOT}/lib 2>/dev/null && set - ||
exec - {
exec - test -d ./-p && rm -rf ./-p
exec - p=
exec - for d in `echo ${INSTALLROOT}/lib | sed -e 's%\\(.\\)/%\\1 %g'`
exec - do case $p in
exec - "") p=$d ;;
exec - *) p=$p/$d ;;
exec - esac
exec - case $d in
exec - .|..) ;;
exec - *) if test ! -d $p
exec - then rm -f $p
exec - set -x && mkdir $p && set -
exec - fi
exec - ;;
exec - esac
exec - done
exec - } && set -x
exec - fi
done ${INSTALLROOT}/lib generated
make ${INSTALLROOT}/lib/libvdelta.a archive
prev libvdelta.a archive
exec - { mv ${INSTALLROOT}/lib/libvdelta.a ${INSTALLROOT}/lib/libvdelta.a.old 2>/dev/null; cp libvdelta.a ${INSTALLROOT}/lib/libvdelta.a 2>/dev/null ;} || true
exec - (ranlib ${INSTALLROOT}/lib/libvdelta.a) >/dev/null 2>&1 || true
done ${INSTALLROOT}/lib/libvdelta.a generated
make ${INSTALLROOT}/man/man3
exec - set -
exec - if test ! -d ${INSTALLROOT}/man/man3
exec - then set -x && mkdir -p ${INSTALLROOT}/man/man3 2>/dev/null && set - ||
exec - {
exec - test -d ./-p && rm -rf ./-p
exec - p=
exec - for d in `echo ${INSTALLROOT}/man/man3 | sed -e 's%\\(.\\)/%\\1 %g'`
exec - do case $p in
exec - "") p=$d ;;
exec - *) p=$p/$d ;;
exec - esac
exec - case $d in
exec - .|..) ;;
exec - *) if test ! -d $p
exec - then rm -f $p
exec - set -x && mkdir $p && set -
exec - fi
exec - ;;
exec - esac
exec - done
exec - } && set -x
exec - fi
done ${INSTALLROOT}/man/man3 generated
make ${INSTALLROOT}/man/man3/vdelta.3
make vdelta.3
done vdelta.3
exec - { mv ${INSTALLROOT}/man/man3/vdelta.3 ${INSTALLROOT}/man/man3/vdelta.3.old 2>/dev/null; cp vdelta.3 ${INSTALLROOT}/man/man3/vdelta.3 2>/dev/null ;} || true
done ${INSTALLROOT}/man/man3/vdelta.3 generated
make ${INSTALLROOT}/include/ast
exec - set -
exec - if test ! -d ${INSTALLROOT}/include/ast
exec - then set -x && mkdir -p ${INSTALLROOT}/include/ast 2>/dev/null && set - ||
exec - {
exec - test -d ./-p && rm -rf ./-p
exec - p=
exec - for d in `echo ${INSTALLROOT}/include/ast | sed -e 's%\\(.\\)/%\\1 %g'`
exec - do case $p in
exec - "") p=$d ;;
exec - *) p=$p/$d ;;
exec - esac
exec - case $d in
exec - .|..) ;;
exec - *) if test ! -d $p
exec - then rm -f $p
exec - set -x && mkdir $p && set -
exec - fi
exec - ;;
exec - esac
exec - done
exec - } && set -x
exec - fi
done ${INSTALLROOT}/include/ast generated
make ${INSTALLROOT}/include/ast/vdelta.h
exec - { mv ${INSTALLROOT}/include/ast/vdelta.h ${INSTALLROOT}/include/ast/vdelta.h.old 2>/dev/null; cp vdelta.h ${INSTALLROOT}/include/ast/vdelta.h 2>/dev/null ;} || true
done ${INSTALLROOT}/include/ast/vdelta.h generated
done install virtual

View File

@@ -0,0 +1,496 @@
/* $XConsortium: vddelta.c /main/2 1996/05/08 20:06:58 drk $ */
/***************************************************************
* *
* AT&T - PROPRIETARY *
* *
* THIS IS PROPRIETARY SOURCE CODE LICENSED BY *
* AT&T CORP. *
* *
* Copyright (c) 1995 AT&T Corp. *
* All Rights Reserved *
* *
* This software is licensed by AT&T Corp. *
* under the terms and conditions of the license in *
* http://www.research.att.com/orgs/ssr/book/reuse *
* *
* This software was created by the *
* Software Engineering Research Department *
* AT&T Bell Laboratories *
* *
* For further information contact *
* gsf@research.att.com *
* *
***************************************************************/
#include "vdelhdr.h"
/* Compute a transformation that takes source data to target data
**
** Written by (Kiem-)Phong Vo, kpv@research.att.com, 5/20/94
*/
#ifdef DEBUG
long S_copy, S_add; /* amount of input covered by COPY and ADD */
long N_copy, N_add; /* # of COPY and ADD instructions */
long M_copy, M_add; /* max size of a COPY or ADD instruction */
long N_merge; /* # of merged instructions */
#endif
#define MERGABLE(a,c,k) ((a) > 0 && A_ISTINY(a) && \
(c) > 0 && C_ISTINY(c) && \
(k) >= K_SELF )
typedef struct _match_s Match_t;
typedef struct _table_s Table_t;
struct _match_s
{ Match_t* next; /* linked list ptr */
};
struct _table_s
{ Vdio_t io; /* io structure */
uchar* src; /* source string */
int n_src;
uchar* tar; /* target string */
int n_tar;
K_DDECL(quick,recent,rhere); /* address caches */
Match_t* base; /* base of elements */
int size; /* size of hash table */
Match_t** table; /* hash table */
};
/* encode and output delta instructions */
#if __STD_C
static vdputinst(Table_t* tab, uchar* begs, uchar* here, Match_t* match, int n_copy)
#else
static vdputinst(tab, begs, here, match, n_copy)
Table_t* tab;
uchar* begs; /* ADD data if any */
uchar* here; /* current location */
Match_t* match; /* best match if any */
int n_copy; /* length of match */
#endif
{
reg int n_add, i_add, i_copy, k_type;
reg int n, c_addr, copy, best, d;
n_add = begs ? here-begs : 0; /* add size */
c_addr = (here-tab->tar)+tab->n_src; /* current address */
k_type = 0;
if(match) /* process the COPY instruction */
{ /**/DBTOTAL(N_copy,1); DBTOTAL(S_copy,n_copy); DBMAX(M_copy,n_copy);
best = copy = match - tab->base;
k_type = K_SELF;
if((d = c_addr - copy) < best)
{ best = d;
k_type = K_HERE;
}
for(n = 0; n < K_RTYPE; ++n)
{ if((d = copy - tab->recent[n]) < 0 || d >= best)
continue;
best = d;
k_type = K_RECENT+n;
}
if(best >= I_MORE && tab->quick[n = copy%K_QSIZE] == copy)
{ for(d = K_QTYPE-1; d > 0; --d)
if(n >= (d<<VD_BITS) )
break;
best = n - (d<<VD_BITS); /**/ASSERT(best < (1<<VD_BITS));
k_type = K_QUICK+d;
}
/**/ASSERT(best >= 0);
/**/ASSERT((k_type+K_MERGE) < (1<<I_BITS) );
/* update address caches */
K_UPDATE(tab->quick,tab->recent,tab->rhere,copy);
/* see if mergable to last ADD instruction */
if(MERGABLE(n_add,n_copy,k_type) )
{ /**/DBTOTAL(N_merge,1);
i_add = K_TPUT(k_type)|A_TPUT(n_add)|C_TPUT(n_copy);
}
else
{ i_copy = K_PUT(k_type);
if(C_ISLOCAL(n_copy) )
i_copy |= C_LPUT(n_copy);
}
}
if(n_add > 0)
{ /**/DBTOTAL(N_add,1); DBTOTAL(S_add,n_add); DBMAX(M_add,n_add);
if(!MERGABLE(n_add,n_copy,k_type) )
i_add = A_ISLOCAL(n_add) ? A_LPUT(n_add) : 0;
if(VDPUTC((Vdio_t*)tab,i_add) < 0 )
return -1;
if(!A_ISLOCAL(n_add) &&
(*_Vdputu)((Vdio_t*)tab, (ulong)A_PUT(n_add)) < 0 )
return -1;
if((*_Vdwrite)((Vdio_t*)tab, begs, n_add) < 0 )
return -1;
}
if(n_copy > 0)
{ if(!MERGABLE(n_add,n_copy,k_type) && VDPUTC((Vdio_t*)tab,i_copy) < 0 )
return -1;
if(!C_ISLOCAL(n_copy) &&
(*_Vdputu)((Vdio_t*)tab, (ulong)C_PUT(n_copy)) < 0 )
return -1;
if(k_type >= K_QUICK && k_type < (K_QUICK+K_QTYPE) )
{ if(VDPUTC((Vdio_t*)tab,(uchar)best) < 0 )
return -1;
}
else
{ if((*_Vdputu)((Vdio_t*)tab, (ulong)best) < 0 )
return -1;
}
}
else
{ if((*_Vdflsbuf)((Vdio_t*)tab) < 0)
return -1;
}
return 0;
}
/* Fold a string */
#if __STD_C
static vdfold(Table_t* tab, int output)
#else
static vdfold(tab, output)
Table_t* tab;
int output;
#endif
{
reg ulong key, n;
reg uchar *s, *sm, *ends, *ss, *heade;
reg Match_t *m, *list, *curm, *bestm;
reg uchar *add, *endfold;
reg int head, len, n_src = tab->n_src;
reg int size = tab->size;
reg uchar *src = tab->src, *tar = tab->tar;
reg Match_t *base = tab->base, **table = tab->table;
if(!output)
{ if(tab->n_src < M_MIN)
return 0;
endfold = (s = src) + tab->n_src;
curm = base;
}
else
{ endfold = (s = tar) + tab->n_tar;
curm = base+n_src;
if(tab->n_tar < M_MIN)
return vdputinst(tab,s,endfold,NIL(Match_t*),0);
}
add = NIL(uchar*);
bestm = NIL(Match_t*);
len = M_MIN-1;
HINIT(key,s,n);
for(;;)
{ for(;;) /* search for the longest match */
{ if(!(m = table[key&size]) )
goto endsearch;
list = m = m->next; /* head of list */
if(bestm) /* skip over past elements */
{ for(;;)
{ if(m >= bestm+len)
break;
if((m = m->next) == list)
goto endsearch;
}
}
head = len - (M_MIN-1); /* header before the match */
heade = s+head;
for(;;)
{ if((n = m-base) < n_src)
{ if(n < head)
goto next;
sm = src + n;
}
else
{ if((n -= n_src) < head)
goto next;
sm = tar + n;
}
/* make sure that the M_MIN bytes match */
if(!EQUAL(heade,sm))
goto next;
/* make sure this is a real match */
for(sm -= head, ss = s; ss < heade; )
if(*sm++ != *ss++)
goto next;
ss += M_MIN;
sm += M_MIN;
ends = endfold;
if((m-base) < n_src && (n = (src+n_src)-sm) < (ends-s) )
ends = s+n;
for(; ss < ends; ++ss, ++sm)
if(*sm != *ss)
goto extend;
goto extend;
next: if((m = m->next) == list )
goto endsearch;
}
extend: bestm = m-head;
n = len;
len = ss-s;
if(ss >= endfold) /* already match everything */
goto endsearch;
/* check for a longer match */
ss -= M_MIN-1;
if(len == n+1)
HNEXT(key,ss,n);
else HINIT(key,ss,n);
}
endsearch:
if(bestm)
{ if(output && vdputinst(tab,add,s,bestm,len) < 0)
return -1;
/* add a sufficient number of suffices */
ends = (s += len);
ss = ends - (M_MIN-1);
if(!output)
curm = base + (ss-src);
else curm = base + n_src + (ss-tar);
len = M_MIN-1;
add = NIL(uchar*);
bestm = NIL(Match_t*);
}
else
{ if(!add)
add = s;
ss = s;
ends = (s += 1); /* add one prefix */
}
if(ends > (endfold - (M_MIN-1)) )
ends = endfold - (M_MIN-1);
if(ss < ends) for(;;) /* add prefices/suffices */
{ n = key&size;
if(!(m = table[n]) )
curm->next = curm;
else
{ curm->next = m->next;
m->next = curm;
}
table[n] = curm++;
if((ss += 1) >= ends)
break;
HNEXT(key,ss,n);
}
if(s > endfold-M_MIN) /* too short to match */
{ if(!add)
add = s;
break;
}
HNEXT(key,s,n);
}
if(output) /* flush output */
return vdputinst(tab,add,endfold,NIL(Match_t*),0);
return 0;
}
#if __STD_C
long vddelta(Vddisc_t* source, Vddisc_t* target, Vddisc_t* delta, long window)
#else
long vddelta(source, target, delta, window)
Vddisc_t* source; /* source data */
Vddisc_t* target; /* target data */
Vddisc_t* delta; /* transform output data */
long window; /* amount to process each time */
#endif
{
reg int size, k, n;
reg long p, n_src, n_tar;
Table_t tab;
if(!target || (n_tar = target->size) < 0)
return -1;
if(n_tar > 0 && !target->data && !target->readf)
return -1;
if((n_src = source ? source->size : 0) < 0)
n_src = 0;
if(n_src > 0 && !source->data && !source->readf)
return -1;
if(!delta || (!delta->data && !delta->writef) )
return -1;
tab.n_src = tab.n_tar = tab.size = 0;
tab.tar = tab.src = NIL(uchar*);
tab.base = NIL(Match_t*);
tab.table = NIL(Match_t**);
INIT(&tab.io,delta);
if(window <= 0)
window = DFLTWINDOW;
else if(window > MAXWINDOW)
window = MAXWINDOW;
if(window > n_tar)
window = n_tar;
if(n_src > 0 && window > n_src)
window = n_src;
/* try to allocate working space */
while(window > 0)
{ /* space for the target string */
size = (n_tar == 0 || target->data) ? 0 : (int)window;
if((long)size > n_tar)
size = (int)n_tar;
if(size > 0 && !(tab.tar = (uchar*)malloc(size*sizeof(uchar))) )
goto reduce_window;
/* space for sliding header or source string */
if(n_src <= 0) /* compression only */
size = target->data ? 0 : HEADER(window);
else /* differencing */
{ size = source->data ? 0 : window;
if((long)size > n_src)
size = (int)n_src;
}
if(size > 0 && !(tab.src = (uchar*)malloc(size*sizeof(uchar))) )
goto reduce_window;
/* space for the hash table elements */
size = (int)(window < n_tar ? window : n_tar);
if(n_src <= 0)
size += (int)(window < n_tar ? HEADER(window) : 0);
else size += (int)(window < n_src ? window : n_src);
if(!(tab.base = (Match_t*)malloc(size*sizeof(Match_t))) )
goto reduce_window;
/* space for the hash table */
n = size/2;
do (size = n); while((n &= n-1) != 0);
if(size < 64)
size = 64;
while(!(tab.table = (Match_t**)malloc(size*sizeof(Match_t*))) )
if((size >>= 1) <= 0)
goto reduce_window;
/* if get here, successful */
tab.size = size-1;
break;
reduce_window:
if(tab.tar)
{ free((Void_t*)tab.tar);
tab.tar = NIL(uchar*);
}
if(tab.src)
{ free((Void_t*)tab.src);
tab.src = NIL(uchar*);
}
if(tab.base)
{ free((Void_t*)tab.base);
tab.base = NIL(Match_t*);
}
if((window >>= 1) <= 0)
return -1;
}
/* amount processed */
n = 0;
/* output magic bytes and sizes */
for(k = 0; VD_MAGIC[k]; k++)
;
if((*_Vdwrite)(&tab.io,(uchar*)VD_MAGIC,k) != k ||
(*_Vdputu)(&tab.io,(ulong)n_tar) <= 0 ||
(*_Vdputu)(&tab.io,(ulong)n_src) <= 0 ||
(*_Vdputu)(&tab.io,(ulong)window) <= 0 )
goto done;
/* do one window at a time */
while(n < n_tar)
{ /* prepare the source string */
if(n_src <= 0) /* data compression */
{ if(n <= 0)
tab.n_src = 0;
else
{ size = (int)HEADER(window);
if(target->data)
tab.src = tab.tar + tab.n_tar - size;
else memcpy((Void_t*)tab.src,
(Void_t*)(tab.tar + tab.n_tar - size),
size );
tab.n_src = size;
}
}
else /* data differencing */
{ if(n < n_src)
{ if(n+window > n_src)
p = n_src-window;
else p = n;
if(source->data)
tab.src = (uchar*)source->data + p;
else
{ size = (*source->readf)
(tab.src, (int)window, p, source);
if((long)size != window)
goto done;
}
} /* else use last window */
tab.n_src = window;
}
/* prepare the target string */
size = (int)((n_tar-n) < window ? (n_tar-n) : window);
tab.n_tar = size;
if(target->data)
tab.tar = (uchar*)target->data + n;
else
{ size = (*target->readf)(tab.tar, size, (long)n, target);
if((long)size != tab.n_tar)
goto done;
}
/* reinitialize table before processing */
for(k = tab.size; k >= 0; --k)
tab.table[k] = NIL(Match_t*);
K_INIT(tab.quick,tab.recent,tab.rhere);
if(tab.n_src > 0 && vdfold(&tab,0) < 0)
goto done;
if(vdfold(&tab,1) < 0)
goto done;
n += size;
}
done:
if(!target->data && tab.tar)
free((Void_t*)tab.tar);
if(tab.src && ((n_src <= 0 && !target->data) || (n_src > 0 && !source->data) ) )
free((Void_t*)tab.src);
if(tab.base)
free((Void_t*)tab.base);
if(tab.table)
free((Void_t*)tab.table);
return tab.io.here + (tab.io.next - tab.io.data);
}

View File

@@ -0,0 +1,249 @@
/* $XConsortium: vdelhdr.h /main/2 1996/05/08 20:07:13 drk $ */
/***************************************************************
* *
* AT&T - PROPRIETARY *
* *
* THIS IS PROPRIETARY SOURCE CODE LICENSED BY *
* AT&T CORP. *
* *
* Copyright (c) 1995 AT&T Corp. *
* All Rights Reserved *
* *
* This software is licensed by AT&T Corp. *
* under the terms and conditions of the license in *
* http://www.research.att.com/orgs/ssr/book/reuse *
* *
* This software was created by the *
* Software Engineering Research Department *
* AT&T Bell Laboratories *
* *
* For further information contact *
* gsf@research.att.com *
* *
***************************************************************/
#ifndef _VDELHDR_H
#define _VDELHDR_H 1
#include "vdelta.h"
#if _PACKAGE_ast
#include <ast_std.h>
#else
#if __STD_C
#include <stddef.h>
#else
#include <sys/types.h>
#endif
#endif
#ifdef DEBUG
_BEGIN_EXTERNS_
extern int abort();
_END_EXTERNS_
#define ASSERT(p) ((p) ? 0 : abort())
#define DBTOTAL(t,v) ((t) += (v))
#define DBMAX(m,v) ((m) = (m) > (v) ? (m) : (v) )
#else
#define ASSERT(p)
#define DBTOTAL(t,v)
#define DBMAX(m,v)
#endif
/* short-hand notations */
#define reg register
#define uchar unsigned char
#define uint unsigned int
#define ulong unsigned long
/* default window size - Chosen to suit malloc() even on 16-bit machines. */
#define MAXINT ((int)(((uint)~0) >> 1))
#define MAXWINDOW ((int)(((uint)~0) >> 2))
#define DFLTWINDOW (MAXWINDOW <= (1<<14) ? (1<<14) : (1<<16) )
#define HEADER(w) ((w)/4)
#define M_MIN 4 /* min number of bytes to match */
/* The hash function is s[0]*alpha^3 + s[1]*alpha^2 + s[2]*alpha + s[3] */
#define ALPHA 33
#if 0
#define A1(x,t) (ALPHA*(x))
#define A2(x,t) (ALPHA*ALPHA*(x))
#define A3(x,t) (ALPHA*ALPHA*ALPHA*(x))
#else /* fast multiplication using shifts&adds */
#define A1(x,t) ((t = (x)), (t + (t<<5)) )
#define A2(x,t) ((t = (x)), (t + (t<<6) + (t<<10)) )
#define A3(x,t) ((t = (x)), (t + (t<<5) + ((t+(t<<4))<<6) + ((t+(t<<4))<<11)) )
#endif
#define HINIT(h,s,t) ((h = A3(s[0],t)), (h += A2(s[1],t)), (h += A1(s[2],t)+s[3]) )
#define HNEXT(h,s,t) ((h -= A3(s[-1],t)), (h = A1(h,t) + s[3]) )
#define EQUAL(s,t) ((s)[0] == (t)[0] && (s)[1] == (t)[1] && \
(s)[2] == (t)[2] && (s)[3] == (t)[3] )
/* Every instruction will start with a control byte.
** For portability, only 8 bits of the byte are used.
** The bits are used as follows:
** iiii ssss
** ssss: size of data involved.
** iiii: this defines 16 instruction types:
** 0: an ADD instruction.
** 1,2,3: COPY with K_QUICK addressing scheme.
** 4,5: COPY with K_SELF,K_HERE addressing schemes.
** 6,7,8,9: COPY with K_RECENT addressing scheme.
** For the above types, ssss if not zero codes the size;
** otherwise, the size is coded in subsequent bytes.
** 10,11: merged ADD/COPY with K_SELF,K_HERE addressing
** 12,13,14,15: merged ADD/COPY with K_RECENT addressing.
** For merged ADD/COPY instructions, ssss is divided into "cc aa"
** where cc codes the size of COPY and aa codes the size of ADD.
*/
#define VD_BITS 8 /* # bits usable in a byte */
#define S_BITS 4 /* bits for the size field */
#define I_BITS 4 /* bits for the instruction type */
/* The below macros compute the coding for a COPY address.
** There are two caches, a "quick" cache of (K_QTYPE*256) addresses
** and a revolving cache of K_RTYPE "recent" addresses.
** First, we look in the quick cache to see if the address is there.
** If so, we use the cache index as the code.
** Otherwise, we compute from 0, the current location and
** the "recent" cache an address that is closest to the being coded address,
** then code the difference. The type is set accordingly.
**
** An invariance is 2*K_MERGE + K_QTYPE + 1 == 16
*/
#define K_RTYPE 4 /* # of K_RECENT types */
#define K_QTYPE 3 /* # of K_QUICK types */
#define K_MERGE (K_RTYPE+2) /* # of types allowing add+copy */
#define K_QSIZE (K_QTYPE<<VD_BITS) /* size of K_QUICK cache */
#define K_QUICK 1 /* start of K_QUICK types */
#define K_SELF (K_QUICK+K_QTYPE)
#define K_HERE (K_SELF+1)
#define K_RECENT (K_HERE+1) /* start of K_RECENT types */
#define K_DDECL(quick,recent,rhere) /* cache decls in vdelta */ \
int quick[K_QSIZE]; int recent[K_RTYPE]; int rhere/*;*/
#define K_UDECL(quick,recent,rhere) /* cache decls in vdupdate */ \
long quick[K_QSIZE]; long recent[K_RTYPE]; int rhere/*;*/
#define K_INIT(quick,recent,rhere) \
{ quick[rhere=0] = (1<<7); \
while((rhere += 1) < K_QSIZE) quick[rhere] = rhere + (1<<7); \
recent[rhere=0] = (1<<8); \
while((rhere += 1) < K_RTYPE) recent[rhere] = (rhere+1)*(1<<8); \
}
#define K_UPDATE(quick,recent,rhere,copy) \
{ quick[copy%K_QSIZE] = copy; \
if((rhere += 1) >= K_RTYPE) rhere = 0; recent[rhere] = copy; \
}
#define VD_ISCOPY(k) ((k) > 0 && (k) < (K_RECENT+K_RTYPE) )
#define K_ISMERGE(k) ((k) >= (K_RECENT+K_RTYPE))
#define A_SIZE ((1<<S_BITS)-1) /* max local ADD size */
#define A_ISLOCAL(s) ((s) <= A_SIZE ) /* can be coded locally */
#define A_LPUT(s) (s) /* coded local value */
#define A_PUT(s) ((s) - (A_SIZE+1) ) /* coded normal value */
#define A_ISHERE(i) ((i) & A_SIZE) /* locally coded size */
#define A_LGET(i) ((i) & A_SIZE)
#define A_GET(s) ((s) + (A_SIZE+1) )
#define C_SIZE ((1<<S_BITS)+M_MIN-2) /* max local COPY size */
#define C_ISLOCAL(s) ((s) <= C_SIZE ) /* can be coded locally */
#define C_LPUT(s) ((s) - (M_MIN-1) ) /* coded local value */
#define C_PUT(s) ((s) - (C_SIZE+1) ) /* coded normal value */
#define C_ISHERE(i) ((i) & ((1<<S_BITS)-1)) /* size was coded local */
#define C_LGET(i) (((i) & ((1<<S_BITS)-1)) + (M_MIN-1) )
#define C_GET(s) ((s) + (C_SIZE+1) )
#define K_PUT(k) ((k) << S_BITS)
#define K_GET(i) ((i) >> S_BITS)
/* coding merged ADD/COPY instructions */
#define A_TINY 2 /* bits for tiny ADD */
#define A_TINYSIZE (1<<A_TINY) /* max tiny ADD size */
#define A_ISTINY(s) ((s) <= A_TINYSIZE )
#define A_TPUT(s) ((s) - 1)
#define A_TGET(i) (((i) & (A_TINYSIZE-1)) + 1)
#define C_TINY 2 /* bits for tiny COPY */
#define C_TINYSIZE ((1<<C_TINY) + M_MIN-1) /* max tiny COPY size */
#define C_ISTINY(s) ((s) <= C_TINYSIZE)
#define C_TPUT(s) (((s) - M_MIN) << A_TINY)
#define C_TGET(i) ((((i) >> A_TINY) & ((1<<C_TINY)-1)) + M_MIN )
#define K_TPUT(k) (((k)+K_MERGE) << S_BITS)
#define MEMCPY(to,from,n) \
switch(n) \
{ default: memcpy((Void_t*)to,(Void_t*)from,(size_t)n); \
to += n; from += n; break; \
case 7 : *to++ = *from++; \
case 6 : *to++ = *from++; \
case 5 : *to++ = *from++; \
case 4 : *to++ = *from++; \
case 3 : *to++ = *from++; \
case 2 : *to++ = *from++; \
case 1 : *to++ = *from++; \
case 0 : break; \
}
/* Below here is code for a buffered I/O subsystem to speed up I/O */
#define I_SHIFT 7
#define I_MORE (1<<I_SHIFT) /* continuation bit */
#define I_CODE(n) ((uchar)((n)&(I_MORE-1)) ) /* get lower bits */
/* structure to do buffered IO */
typedef struct _vdio_s
{ uchar* next;
uchar* endb;
uchar* data;
int size;
long here;
Vddisc_t* delta;
uchar buf[512];
} Vdio_t;
#define ENDB(io) ((io)->endb)
#define NEXT(io) ((io)->next)
#define HERE(io) ((io)->here)
#define DATA(io) ((io)->data)
#define SIZE(io) ((io)->size)
#define DELTA(io) ((io)->delta)
#define READF(io) ((io)->delta->readf)
#define WRITEF(io) ((io)->delta->writef)
#define REMAIN(io) (ENDB(io) - NEXT(io))
#define INIT(io,delta) ((io)->endb = (io)->next = (io)->data = NIL(uchar*), \
(io)->size = 0, (io)->here = 0, (io)->delta = (delta) )
#define VDPUTC(io,c) ((REMAIN(io) > 0 || (*_Vdflsbuf)(io) > 0) ? \
(int)(*(io)->next++ = (uchar)(c)) : -1 )
#define VDGETC(io) ((REMAIN(io) > 0 || (*_Vdfilbuf)(io) > 0) ? \
(int)(*(io)->next++) : -1 )
typedef struct _vdbufio_s
{ int(* vdfilbuf)_ARG_((Vdio_t*));
int(* vdflsbuf)_ARG_((Vdio_t*));
ulong(* vdgetu)_ARG_((Vdio_t*, ulong));
int(* vdputu)_ARG_((Vdio_t*, ulong));
int(* vdread)_ARG_((Vdio_t*, uchar*, int));
int(* vdwrite)_ARG_((Vdio_t*, uchar*, int));
} Vdbufio_t;
#define _Vdfilbuf _Vdbufio.vdfilbuf
#define _Vdflsbuf _Vdbufio.vdflsbuf
#define _Vdgetu _Vdbufio.vdgetu
#define _Vdputu _Vdbufio.vdputu
#define _Vdread _Vdbufio.vdread
#define _Vdwrite _Vdbufio.vdwrite
_BEGIN_EXTERNS_
extern Vdbufio_t _Vdbufio;
extern Void_t* memcpy _ARG_((Void_t*, const Void_t*, size_t));
extern Void_t* malloc _ARG_((size_t));
extern void free _ARG_((Void_t*));
_END_EXTERNS_
#endif /*_VDELHDR_H*/

View File

@@ -0,0 +1,83 @@
.\" $XConsortium: vdelta.3 /main/2 1996/10/29 15:17:44 drk $
.de MW
\f5\\$1\fP
..
.TH VDELTA 3 "16 July 1994"
.SH NAME
vdelta \- data differencing and compression
.SH SYNOPSIS
.MW "#include <vdelta.h>"
.nf
.MW "long vddelta(Vddisc_t* source, Vddisc_t* target, Vddisc_t* delta, int window);"
.MW "long vdupdate(Vddisc_t* source, Vddisc_t* target, Vddisc_t* delta);"
.fi
.SH DESCRIPTION
These functions embody an algorithm for determining a compressed form of the
difference between two byte streams,
and for applying that difference to a byte stream.
.PP
.I Vddelta
computes a transformation (encoded as the byte stream \f5delta\fP)
that maps the source byte stream \f5source\fP
to the target byte stream \f5target\fP.
If the source stream is empty (\f5source\fP is \f5NULL\fP or
\f5source->size\fP is non-positive),
\fIvddelta\fP acts like a compression routine.
\f5window\fP specifies the largest amount of data that
will be processed at one time.
Typically, larger values decrease the size of the transformation and increase
the time needed to calculate it.
A non-positive value for \f5window\fP indicates that \fIvddelta\fP
should pick some value at its convenience.
\fIVddelta\fP returns the length of the transformation byte stream.
.PP
.I Vdupdate
applies a transformation \f5delta\fP generated by
\fIvddelta\fP to the source byte stream \f5source\fP
and emits the target byte stream \f5target\fP.
\fIVdupdate\fP returns the length of the target byte stream.
.PP
The handling of data for a data stream is defined
by a discipline structure of type \f5Vddisc_t\fP.
This type contains the following members:
.in +.5i
.nf
.MW "long size;"
.MW "Void_t* data;"
.MW "int (*readf)(Void_t* buf, int n, long offset, Vddisc_t* disc);"
.MW "int (*writef)Void_t* buf, int n, long offset, Vddisc_t* disc);"
.fi
.in -.5i
.TP
\f5size\fP defines the length of the respective data stream.
.TP
\f5data\fP, if not \f5NULL\fP, is an array that either contains
the entire data for a read stream or is large enough to store
the entire generated data. For example, in the \fIvddelta\fP call,
\f5target->size\fP defines the length of the target stream.
In this case, if \f5target->data\fP is not \f5NULL\fP,
it is assumed to contain all of the target data
(therefore, \f5target->readf\fP is not required.)
.TP
.MW readf
points to a function that reads at most \f5n\fP bytes
into \f5buf\fP from position \f5offset\fP
in the byte stream specified by the as described above, and
returns the number of bytes actually read, or \-1 on error.
The argument \f5disc\fP is the containing discipline structure.
.TP
.MW writef
is identical to \f5readf\fP except that it writes rather than reads bytes.
.TP
.PP
\f5Void_t\fP is \f5#define\fPd as \f5void\fP if possible, otherwise \f5char\fP.
.SH DIAGNOSTICS
Both
.I vddelta
and
.I vdupdate
return \-1 on error.
.SH AUTHORS
David G. Korn, dgk@research.att.com, AT&T Bell Laboratories
.br
Kiem-Phong Vo, kpv@research.att.com, AT&T Bell Laboratories

View File

@@ -0,0 +1,92 @@
/* $XConsortium: vdelta.h /main/2 1996/05/08 20:07:29 drk $ */
/***************************************************************
* *
* AT&T - PROPRIETARY *
* *
* THIS IS PROPRIETARY SOURCE CODE LICENSED BY *
* AT&T CORP. *
* *
* Copyright (c) 1995 AT&T Corp. *
* All Rights Reserved *
* *
* This software is licensed by AT&T Corp. *
* under the terms and conditions of the license in *
* http://www.research.att.com/orgs/ssr/book/reuse *
* *
* This software was created by the *
* Software Engineering Research Department *
* AT&T Bell Laboratories *
* *
* For further information contact *
* gsf@research.att.com *
* *
***************************************************************/
#ifndef _VDELTA_H
#define _VDELTA_H 1
#ifndef __KPV__
#define __KPV__ 1
#ifndef __STD_C
#ifdef __STDC__
#define __STD_C 1
#else
#if __cplusplus
#define __STD_C 1
#else
#define __STD_C 0
#endif /*__cplusplus*/
#endif /*__STDC__*/
#endif /*__STD_C*/
#ifndef _BEGIN_EXTERNS_
#if __cplusplus
#define _BEGIN_EXTERNS_ extern "C" {
#define _END_EXTERNS_ }
#else
#define _BEGIN_EXTERNS_
#define _END_EXTERNS_
#endif
#endif /*_BEGIN_EXTERNS_*/
#ifndef _ARG_
#if __STD_C
#define _ARG_(x) x
#else
#define _ARG_(x) ()
#endif
#endif /*_ARG_*/
#ifndef Void_t
#if __STD_C
#define Void_t void
#else
#define Void_t char
#endif
#endif /*Void_t*/
#ifndef NIL
#define NIL(type) ((type)0)
#endif /*NIL*/
#endif /*__KPV__*/
/* user-supplied functions to do io */
typedef struct _vddisc_s Vddisc_t;
typedef int(* Vdio_f)_ARG_((Void_t*, int, long, Vddisc_t*));
struct _vddisc_s
{ long size; /* total data size */
Void_t* data; /* data array */
Vdio_f readf; /* to read data */
Vdio_f writef; /* to write data */
};
/* magic header for delta output */
#define VD_MAGIC "vd01"
_BEGIN_EXTERNS_
extern long vddelta _ARG_((Vddisc_t*,Vddisc_t*,Vddisc_t*,long));
extern long vdupdate _ARG_((Vddisc_t*,Vddisc_t*,Vddisc_t*));
_END_EXTERNS_
#endif /*_VDELTA_H*/

View File

@@ -0,0 +1,207 @@
/* $XConsortium: vdio.c /main/2 1996/05/08 20:07:43 drk $ */
/***************************************************************
* *
* AT&T - PROPRIETARY *
* *
* THIS IS PROPRIETARY SOURCE CODE LICENSED BY *
* AT&T CORP. *
* *
* Copyright (c) 1995 AT&T Corp. *
* All Rights Reserved *
* *
* This software is licensed by AT&T Corp. *
* under the terms and conditions of the license in *
* http://www.research.att.com/orgs/ssr/book/reuse *
* *
* This software was created by the *
* Software Engineering Research Department *
* AT&T Bell Laboratories *
* *
* For further information contact *
* gsf@research.att.com *
* *
***************************************************************/
#include "vdelhdr.h"
/* IO subsystem for the delta routines
**
** Written by Kiem-Phong Vo (12/15/94)
*/
#if __STD_C
static _vdinit(reg Vdio_t* io)
#else
static _vdinit(io)
reg Vdio_t* io;
#endif
{
if((io->data = (uchar*)io->delta->data) )
io->size = io->delta->size;
else
{ io->data = io->buf;
io->size = sizeof(io->buf);
}
io->next = io->data;
io->endb = io->data + io->size;
}
#if __STD_C
static _vdfilbuf(reg Vdio_t* io)
#else
static _vdfilbuf(io)
reg Vdio_t* io;
#endif
{ reg int n;
if(!io->data)
_vdinit(io);
if(io->data != io->buf) /* all data was given in core */
return REMAIN(io);
if((n = (*READF(io))(DATA(io),SIZE(io),HERE(io),DELTA(io))) > 0)
{ ENDB(io) = (NEXT(io) = DATA(io)) + n;
HERE(io) += n;
}
return n;
}
#if __STD_C
static _vdflsbuf(reg Vdio_t* io)
#else
static _vdflsbuf(io)
reg Vdio_t* io;
#endif
{ reg int n;
if(!io->data )
_vdinit(io);
if(io->data != io->buf) /* all space was given */
return REMAIN(io);
if((n = NEXT(io) - DATA(io)) > 0 &&
(*WRITEF(io))(DATA(io),n,HERE(io),DELTA(io)) != n)
return -1;
HERE(io) += n;
NEXT(io) = DATA(io);
return SIZE(io);
}
#if __STD_C
static ulong _vdgetu(reg Vdio_t* io, reg ulong v)
#else
static ulong _vdgetu(io,v)
reg Vdio_t* io;
reg ulong v;
#endif
{ reg int c;
for(v &= I_MORE-1;;)
{ if((c = VDGETC(io)) < 0)
return (ulong)(-1L);
if(!(c&I_MORE) )
return ((v<<I_SHIFT) | c);
v = (v<<I_SHIFT) | (c & (I_MORE-1));
}
}
#if __STD_C
static _vdputu(reg Vdio_t* io, ulong v)
#else
static _vdputu(io, v)
reg Vdio_t* io;
reg ulong v;
#endif
{
reg uchar *s, *next;
reg int len;
uchar c[sizeof(ulong)+1];
s = next = &c[sizeof(c)-1];
*s = I_CODE(v);
while((v >>= I_SHIFT) )
*--s = I_CODE(v)|I_MORE;
len = (next-s) + 1;
if(REMAIN(io) < len && _vdflsbuf(io) < len)
return -1;
next = io->next;
switch(len)
{
default: memcpy((Void_t*)next,(Void_t*)s,len); next += len; break;
case 3: *next++ = *s++;
case 2: *next++ = *s++;
case 1: *next++ = *s;
}
io->next = next;
return len;
}
#if __STD_C
static _vdread(Vdio_t* io, reg uchar* s, reg int n)
#else
static _vdread(io, s, n)
Vdio_t* io;
reg uchar* s;
reg int n;
#endif
{
reg uchar* next;
reg int r, m;
for(m = n; m > 0; )
{ if((r = REMAIN(io)) <= 0 && (r = _vdfilbuf(io)) <= 0)
break;
if(r > m)
r = m;
next = io->next;
MEMCPY(s,next,r);
io->next = next;
m -= r;
}
return n-m;
}
#if __STD_C
static _vdwrite(Vdio_t* io, reg uchar* s, reg int n)
#else
static _vdwrite(io, s, n)
Vdio_t* io;
reg uchar* s;
reg int n;
#endif
{
reg uchar* next;
reg int w, m;
for(m = n; m > 0; )
{ if((w = REMAIN(io)) <= 0 && (w = _vdflsbuf(io)) <= 0)
break;
if(w > m)
w = m;
next = io->next;
MEMCPY(next,s,w);
io->next = next;
m -= w;
}
return n-m;
}
Vdbufio_t _Vdbufio =
{ _vdfilbuf,
_vdflsbuf,
_vdgetu,
_vdputu,
_vdread,
_vdwrite
};

View File

@@ -0,0 +1,411 @@
/* $XConsortium: vdupdate.c /main/2 1996/05/08 20:07:59 drk $ */
/***************************************************************
* *
* AT&T - PROPRIETARY *
* *
* THIS IS PROPRIETARY SOURCE CODE LICENSED BY *
* AT&T CORP. *
* *
* Copyright (c) 1995 AT&T Corp. *
* All Rights Reserved *
* *
* This software is licensed by AT&T Corp. *
* under the terms and conditions of the license in *
* http://www.research.att.com/orgs/ssr/book/reuse *
* *
* This software was created by the *
* Software Engineering Research Department *
* AT&T Bell Laboratories *
* *
* For further information contact *
* gsf@research.att.com *
* *
***************************************************************/
#include "vdelhdr.h"
/* Apply the transformation source->target to reconstruct target
** This code is designed to work even if the local machine has
** word size smaller than that of the machine where the delta
** was computed. A requirement is that "long" on the local
** machine must be large enough to hold source and target sizes.
** It is also assumed that if an array is given, the size of
** that array in bytes must be storable in an "int". This is
** used in various cast from "long" to "int".
**
** Written by (Kiem-)Phong Vo, kpv@research.att.com, 5/20/94
*/
typedef struct _table_s
{ Vdio_t io; /* io structure */
Vddisc_t* source; /* source data discipline */
Vddisc_t* target; /* target data discipline */
uchar* src; /* source string */
long n_src;
uchar* tar; /* target string */
long n_tar;
long s_org; /* start of window in source */
long t_org; /* start of window in target */
uchar data[128]; /* buffer for data transferring */
char s_alloc; /* 1 if source was allocated */
char t_alloc; /* 1 if target was allocated */
char compress; /* 1 if compressing only */
K_UDECL(quick,recent,rhere); /* address caches */
} Table_t;
#if __STD_C
static vdunfold(Table_t* tab)
#else
static vdunfold(tab)
Table_t* tab;
#endif
{
reg long size, copy;
reg int inst, k_type, n, r;
reg uchar *tar, *src, *to, *fr;
reg long t, c_addr, n_tar, n_src;
reg Vddisc_t *target, *source;
n_tar = tab->n_tar;
tar = tab->tar;
n_src = tab->n_src;
src = tab->src;
target = tab->target;
source = tab->source;
for(t = 0, c_addr = n_src; t < n_tar; )
{ if((inst = VDGETC((Vdio_t*)tab)) < 0)
return -1;
k_type = K_GET(inst);
if(!VD_ISCOPY(k_type))
{ if(K_ISMERGE(k_type)) /* merge/add instruction */
size = A_TGET(inst);
else if(A_ISHERE(inst)) /* locally coded ADD size */
size = A_LGET(inst);
else /* non-local ADD size */
{ if((size = VDGETC((Vdio_t*)tab)) < 0)
return -1;
if(size >= I_MORE &&
(size = (long)(*_Vdgetu)((Vdio_t*)tab,size)) < 0)
return -1;
size = A_GET(size);
}
if((t+size) > n_tar) /* out of sync */
return -1;
c_addr += size;
/* copy data from the delta stream to target */
for(;;)
{ if(!tar)
{ if((long)(n = sizeof(tab->data)) > size)
n = (int)size;
if((*_Vdread)((Vdio_t*)tab,tab->data,n) != n )
return -1;
r = (*target->writef)((Void_t*)tab->data, n,
tab->t_org+t, target);
if(r != n)
return -1;
}
else
{ n = (int)size;
if((*_Vdread)((Vdio_t*)tab,tar+t,n) != n)
return -1;
}
t += n;
if((size -= n) <= 0)
break;
}
if(K_ISMERGE(k_type))
{ size = C_TGET(inst);
k_type -= K_MERGE;
goto do_copy;
}
}
else
{ if(C_ISHERE(inst)) /* locally coded COPY size */
size = C_LGET(inst);
else
{ if((size = VDGETC((Vdio_t*)tab)) < 0)
return -1;
if(size >= I_MORE &&
(size = (long)(*_Vdgetu)((Vdio_t*)tab,size)) < 0)
return -1;
size = C_GET(size);
}
do_copy:
if((t+size) > n_tar) /* out of sync */
return -1;
if((copy = VDGETC((Vdio_t*)tab)) < 0)
return -1;
if(k_type >= K_QUICK && k_type < (K_QUICK+K_QTYPE) )
copy = tab->quick[copy + ((k_type-K_QUICK)<<VD_BITS)];
else
{ if(copy >= I_MORE &&
(copy = (long)(*_Vdgetu)((Vdio_t*)tab,copy)) < 0)
return -1;
if(k_type >= K_RECENT && k_type < (K_RECENT+K_RTYPE) )
copy += tab->recent[k_type - K_RECENT];
else if(k_type == K_HERE)
copy = c_addr - copy;
/* else k_type == K_SELF */
}
K_UPDATE(tab->quick,tab->recent,tab->rhere,copy);
c_addr += size;
if(copy < n_src) /* copy from source data */
{ if((copy+size) > n_src) /* out of sync */
return -1;
if(src)
{ n = (int)size;
fr = src+copy;
if(tar)
{ to = tar+t;
MEMCPY(to,fr,n);
}
else
{ r = (*target->writef)((Void_t*)fr, n,
tab->t_org+t, target);
if(r != n)
return -1;
}
t += n;
}
else
{ reg Vddisc_t* disc;
if(tab->compress)
{ copy += tab->t_org - tab->n_src;
disc = target;
}
else
{ copy += tab->s_org;
disc = source;
}
for(;;)
{ if(tar)
{ n = (int)size;
r = (*disc->readf)
((Void_t*)(tar+t), n,
copy, disc );
}
else
{ n = sizeof(tab->data);
if((long)n > size)
n = (int)size;
r = (*disc->readf)
((Void_t*)tab->data, n,
copy, disc );
if(r != n)
return -1;
r = (*target->writef)
((Void_t*)tab->data, n,
tab->t_org+t, target);
}
if(r != n)
return -1;
t += n;
if((size -= n) <= 0)
break;
copy += n;
}
}
}
else /* copy from target data */
{ copy -= n_src;
if(copy >= t || (copy+size) > n_tar) /* out-of-sync */
return -1;
for(;;) /* allow for copying overlapped data */
{ reg long s, a;
if((s = t-copy) > size)
s = size;
if(tar)
{ to = tar+t; fr = tar+copy; n = (int)s;
MEMCPY(to,fr,n);
t += n;
goto next;
}
/* hard read/write */
a = copy;
for(;;)
{ if((long)(n = sizeof(tab->data)) > s)
n = (int)s;
r = (*target->readf)
((Void_t*)tab->data, n,
a + tab->t_org, target );
if(r != n)
return -1;
r = (*target->writef)
((Void_t*)tab->data, n,
t + tab->t_org, target );
if(r != n)
return -1;
t += n;
if((s -= n) <= 0)
break;
a += n;
}
next: if((size -= s) == 0)
break;
}
}
}
}
return 0;
}
#if __STD_C
long vdupdate(Vddisc_t* source, Vddisc_t* target, Vddisc_t* delta)
#else
long vdupdate(source,target,delta)
Vddisc_t* source; /* source data */
Vddisc_t* target; /* target data */
Vddisc_t* delta; /* delta data */
#endif
{
reg int n, r;
reg uchar *tar, *src;
reg long t, p, window, n_src, n_tar;
reg uchar *data;
uchar magic[8];
Table_t tab;
if(!target || (!target->data && !target->writef) )
return -1;
if(!delta || (!delta->data && !delta->readf) )
return -1;
/* initialize I/O buffer */
INIT(&tab.io,delta);
tab.source = source;
tab.target = target;
/* check magic header */
data = (uchar*)(VD_MAGIC);
for(n = 0; data[n]; ++n)
;
if((*_Vdread)(&tab.io,magic,n) != n)
return -1;
for(n -= 1; n >= 0; --n)
if(data[n] != magic[n])
return -1;
/* get true target size */
if((t = (long)(*_Vdgetu)(&tab.io,0)) < 0 ||
(target->data && target->size < t) )
return -1;
n_tar = t;
/* get true source size */
if((t = (long)(*_Vdgetu)(&tab.io,0)) < 0)
return -1;
else if(t > 0)
{ if(!source || (!source->data && !source->readf) )
return -1;
if(source->data && source->size < t)
return -1;
}
n_src = t;
/* get window size */
if((window = (long)(*_Vdgetu)(&tab.io,0)) < 0)
return -1;
tab.compress = n_src == 0 ? 1 : 0;
/* if we have space, it'll be faster to unfold */
tab.tar = tab.src = NIL(uchar*);
tab.t_alloc = tab.s_alloc = 0;
if(n_tar > 0 && !target->data && window < (long)MAXINT)
n = (int)window;
else n = 0;
if(n > 0 && (tab.tar = (uchar*)malloc(n*sizeof(uchar))) )
tab.t_alloc = 1;
if(n_src > 0 && !source->data && window < (long)MAXINT)
n = (int)window;
else if(n_src == 0 && window < n_tar && !target->data &&
HEADER(window) < (long)MAXINT)
n = (int)HEADER(window);
else n = 0;
if(n > 0 && (tab.src = (uchar*)malloc(n*sizeof(uchar))) )
tab.s_alloc = 1;
tar = (uchar*)target->data;
src = (uchar*)(source ? source->data : NIL(Void_t*));
for(t = 0; t < n_tar; )
{ tab.t_org = t; /* current location in target stream */
if(n_src == 0) /* data compression */
{ tab.s_org = 0;
if(t == 0)
tab.n_src = 0;
else
{ tab.n_src = HEADER(window);
p = t - tab.n_src;
if(tar)
tab.src = tar + p;
else if(tab.src)
{ n = (int)tab.n_src;
if(tab.tar)
{ data = tab.tar + tab.n_tar - n;
memcpy((Void_t*)tab.src,(Void_t*)data,n);
}
else
{ r = (*target->readf)(tab.src,n,p,target);
if(r != n)
goto done;
}
}
}
}
else /* data differencing */
{ tab.n_src = window;
if(t < n_src)
{ if((t+window) > n_src)
p = n_src-window;
else p = t;
tab.s_org = p;
if(src)
tab.src = src + p;
else if(tab.src)
{ n = (int)tab.n_src;
r = (*source->readf)(tab.src,n,p,source);
if(r != n)
goto done;
}
}
}
if(tar)
tab.tar = (uchar*)tar+t;
tab.n_tar = window < (n_tar-t) ? window : (n_tar-t);
K_INIT(tab.quick,tab.recent,tab.rhere);
if(vdunfold(&tab) < 0)
goto done;
if(!target->data && tab.tar)
{ p = (*target->writef)((Void_t*)tab.tar,(int)tab.n_tar,t,target);
if(p != tab.n_tar)
goto done;
}
t += tab.n_tar;
}
done:
if(tab.t_alloc)
free((Void_t*)tab.tar);
if(tab.s_alloc)
free((Void_t*)tab.src);
return t;
}