lzma implementation
[swftools.git] / installer / depack.c
1 /* depack.c
2
3    Part of the swftools installer.
4    
5    Copyright (c) 1997-2004 Matthias Kramm <kramm@quiss.org> 
6  
7    This program is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 2 of the License, or
10    (at your option) any later version.
11
12    This program is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16
17    You should have received a copy of the GNU General Public License
18    along with this program; if not, write to the Free Software
19    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
20
21 #include "stdlib.h"
22 #include "stdio.h"
23 #include "depack.h"
24
25 U32 dbittab[] = {
26     0x1,       0x2,       0x4,       0x8,
27     0x10,      0x20,      0x40,      0x80,
28     0x100,     0x200,     0x400,     0x800,
29     0x1000,    0x2000,    0x4000,    0x8000,
30     0x10000,   0x20000,   0x40000,   0x80000, 
31     0x100000,  0x200000,  0x400000,  0x800000,
32     0x1000000, 0x2000000, 0x4000000, 0x8000000,
33     0x10000000,0x20000000,0x40000000,0x80000000
34 };
35
36 static void* malloc_z(int len)
37 {
38     void* buf = malloc(len);
39     if(buf == 0) {
40         fprintf(stderr, "\nout of memory\n");
41         exit(1);
42     }
43     memset(buf, 0, len);
44     return buf;
45 }
46
47 typedef struct _dpackead {
48     int back;
49     int len;
50 } dpackead_t;
51
52 typedef struct _tree {   
53     int depth;
54     U8  bits[17];
55     U32 base[17];
56 } tree_t;
57
58 typedef struct _depack_internal
59 {
60     int DMEMSIZE;
61     int DMEMSIZEA;
62
63     tree_t T_REP;
64     tree_t T_STORE;
65     tree_t T_CNUM;
66     tree_t T_BACK;
67     tree_t T_BACK2;
68     tree_t T_BACK3;
69
70     dpackead_t dpackead;
71
72     void*reader;
73     readfunc_t readfunc;
74     void*writer;
75     writefunc_t writefunc;
76
77     U8* mem;
78     int mempos;
79     int pos;
80     U8 c;
81     U32 b;
82 } depack_internal_t;
83
84 void depack_destroy(depack_t*d)
85 {
86     depack_internal_t*i = (depack_internal_t*)d->internal;
87     free(i->mem);i->mem=0;
88     free(d->internal);d->internal=0;i=0;
89 }
90
91 static readbytes(depack_t*d, int num)
92 {
93     depack_internal_t*i = (depack_internal_t*)d->internal;
94
95     if(i->mempos+num<=i->DMEMSIZE) {
96         i->readfunc(i->reader, &i->mem[i->mempos],num);
97         i->writefunc(i->writer, &i->mem[i->mempos],num);
98     } else {
99         i->readfunc(i->reader, &i->mem[i->mempos],i->DMEMSIZE - i->mempos);
100         i->writefunc(i->writer, &i->mem[i->mempos],i->DMEMSIZE - i->mempos);
101         i->readfunc(i->reader, &i->mem[0],num-(i->DMEMSIZE - i->mempos));
102         i->writefunc(i->writer, &i->mem[0],num-(i->DMEMSIZE - i->mempos));
103     }
104     i->mempos=(i->mempos+num)&i->DMEMSIZEA;
105     i->pos+=num;
106 }
107
108 int move(U8*dest, U8*src, int len)
109 {
110     if(len) do {
111         *dest=*src;
112         src++;
113         dest++;
114     } while(--len);
115 }
116
117 static lookback(depack_t*d, int back,int len)
118 {
119     depack_internal_t*i = (depack_internal_t*)d->internal;
120
121     int x,z=(i->mempos-back)&i->DMEMSIZEA;
122     char fail=0;
123
124     if(i->mempos+len <= i->DMEMSIZE && 
125        z+len <= i->DMEMSIZE) 
126     {
127         move(&i->mem[i->mempos],&i->mem[z],len);
128         i->writefunc(i->writer, &i->mem[i->mempos],len);
129         i->mempos=(i->mempos+len)&i->DMEMSIZEA;
130     } else {
131         for(x=0;x<len;x++) {
132             i->mem[i->mempos]=i->mem[z];
133             i->writefunc(i->writer, &i->mem[i->mempos],1);
134             i->mempos=(i->mempos+1)&i->DMEMSIZEA;
135             z=(z+1)&i->DMEMSIZEA;
136         }
137     }
138     i->pos += len;
139 }
140
141 static inline U8 readbit(depack_internal_t*i)
142 {
143     i->c&=31;
144     if(i->c==0) i->readfunc(i->reader, &i->b,4);
145     return (i->b>>(31-i->c++))&1;
146 }
147
148 static inline U32 readval(depack_internal_t*i,int b)
149 {
150     unsigned v=0;
151     signed char l;
152     for(l=b-1;l>=0;l--)
153         v|=readbit(i)<<l;
154     return v;
155 }
156
157 static tree_t gettree(depack_t*d)
158 {
159     depack_internal_t*i = (depack_internal_t*)d->internal;
160
161     int l;
162     int x,y,z=0,b=0,r;
163     tree_t tree;
164     memset(&tree, 0, sizeof(tree));
165    
166     tree.depth = readval(i,4)+1;
167
168     for(x=0;x<tree.depth;x++)
169     {
170         tree.base[x]=z;
171         r=0;while(!readbit(i)) r++;
172         if(readbit(i)) r=-r;
173         b+=r;
174         tree.bits[x]=b;
175         z+=dbittab[b];
176     }
177     tree.base[tree.depth]=z;
178     tree.bits[tree.depth]=0;
179     return tree;
180
181 /*    for(z=0;z<=l;z++)
182     {
183         if(i->ttree[n].bits[z]>16) 
184             printf(".");
185         else                       
186             printf("%c","0123456789abcdefg"[ttree[n].bits[z]]);
187     }
188     printf("\n");*/
189 }
190
191 static void showtree(tree_t tree)
192 {
193     int t;
194     int last=0;
195     int lastbits = 0;
196     for(t=0;t<=tree.depth;t++)
197     {
198         if(t>0)
199             printf("[%d] %d: %05x-%05x (%d=%d+%d+1)\n",t,lastbits, last,tree.base[t],lastbits+(t-1)+1, lastbits,t-1);
200         last=tree.base[t];
201         lastbits = tree.bits[t];
202     }
203 }
204
205 static int gettreeval(depack_t*d, tree_t*tree)
206 {
207     depack_internal_t*i = (depack_internal_t*)d->internal;
208
209     U8 x=0;
210     while(!readbit(i)) x++;
211     if(x<17) return tree->base[x]+readval(i, tree->bits[x]);
212     else     return -1;
213 }
214
215 static int get_memsize(int b)
216 {
217     int t,c=1;
218     for(t=0;;t++) {
219         if(c>=b) return c;
220         c<<=1;
221     }
222     return 0;
223 }
224
225 void depack_init(depack_t*d, void*reader, readfunc_t readfunc)
226 {
227     d->internal = malloc_z(sizeof(depack_internal_t));
228     depack_internal_t*i = (depack_internal_t*)d->internal;
229     if(i==0) {
230         fprintf(stderr, "depacker not initialized yet"); exit(1);
231     }
232
233     i->reader = reader;
234     i->readfunc = readfunc;
235
236     i->mempos=0;
237     i->pos=0;
238     i->b=i->c=0;
239
240     i->readfunc(i->reader,&i->dpackead.back, 4);
241     i->readfunc(i->reader,&i->dpackead.len, 4);
242
243     i->DMEMSIZE = get_memsize(i->dpackead.len);
244     i->DMEMSIZEA = i->DMEMSIZE-1;
245     i->mem = malloc_z(i->DMEMSIZE);
246
247     i->T_REP = gettree(d);
248     i->T_STORE = gettree(d);
249     i->T_CNUM = gettree(d);
250     //showtree(i->T_CNUM);
251     i->T_BACK = gettree(d);
252     //showtree(i->T_BACK);
253     i->T_BACK2 = gettree(d);
254     //showtree(i->T_BACK);
255     i->T_BACK3 = gettree(d);
256     //showtree(i->T_BACK3);
257
258     d->size = i->dpackead.len;
259 }
260
261 void depack_process(depack_t*d, void*writer,writefunc_t writefunc)
262 {
263     depack_internal_t*i = (depack_internal_t*)d->internal;
264     i->writer = writer;
265     i->writefunc = writefunc;
266     while(i->pos<i->dpackead.len)
267     {
268         int store,rep,x;
269
270         store=gettreeval(d,&i->T_STORE)+1;
271
272         readbytes(d,store);
273
274         if(i->pos<i->dpackead.len)
275         {
276             rep = gettreeval(d,&i->T_REP)+1;
277
278             for(x=0;x<rep;x++)
279             {
280                 int back,len;
281                 len = gettreeval(d,&i->T_CNUM)+1;
282
283                 if(len == 1) back = readval(i,3)+1;
284                 if(len == 2) back = gettreeval(d,&i->T_BACK2)+1;
285                 if(len == 3) back = gettreeval(d,&i->T_BACK3)+1;
286                 if(len >= 4) back = gettreeval(d,&i->T_BACK)+1;
287
288                 lookback(d,back,len);
289             }
290         }
291     }
292
293     if(i->pos!=i->dpackead.len) {
294         fprintf(stderr, "Internal error");
295         exit(1);
296     }
297 }
298
299 /*
300
301                 mov eax,[b1]
302                 mov ebx,[b2]
303                 shld eax,ebx,cl
304                 mov [b1],eax
305                 shr ebx,cl
306                 mov [b2],ebx
307                 sub cnt,cl
308                 cmp cnt,32-8
309                 ja jj
310 mm:             xor eax,eax
311                 call read
312                 shl eax,[cnt]
313                 or  [b2],eax
314                 add cnt,8
315                 cmp cnt,32-8
316                 jb mm
317 jj:
318
319 */
320
321