fix crashes reported by Debian Cylab Mayhem Team
[swftools.git] / installer / archive.c
blob050284558e5c747a0569544576483549c1c9bdcc
1 /* archive.c
3 Part of the rfx installer.
5 Copyright (c) 2004-2008 Matthias Kramm <kramm@quiss.org>
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.
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.
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 */
21 #include <stdlib.h>
22 #include <stdio.h>
23 #include <stdarg.h>
24 #ifdef WIN32
25 #include <windows.h>
26 #include <shlwapi.h>
27 #else
28 #include <sys/stat.h>
29 #endif
30 #include "archive.h"
31 #include "utils.h"
33 #ifdef ZLIB
34 #include "../z/zlib.h"
35 #define ZLIB_BUFFER_SIZE 16384
36 #else
37 #include "lzma/LzmaDecode.h"
38 #endif
40 static int verbose = 0;
41 static void msg(char*format, ...)
43 char buf[1024];
44 int l;
45 va_list arglist;
46 if(!verbose)
47 return;
48 va_start(arglist, format);
49 vsnprintf(buf, sizeof(buf)-1, format, arglist);
50 va_end(arglist);
51 l = strlen(buf);
52 while(l && buf[l-1]=='\n') {
53 buf[l-1] = 0;
54 l--;
56 printf("(archive) %s\n", buf);
57 fflush(stdout);
61 typedef struct _reader
63 int (*read)(struct _reader*, void*data, int len);
64 void (*dealloc)(struct _reader*);
65 void *internal;
66 int pos;
67 } reader_t;
69 /* ---------------------------- mem reader ------------------------------- */
71 struct memread_t
73 unsigned char*data;
74 int length;
76 static int reader_memread(reader_t*reader, void* data, int _len)
78 struct memread_t*mr = (struct memread_t*)reader->internal;
80 int len = _len;
81 if(mr->length - reader->pos < len) {
82 len = mr->length - reader->pos;
84 memcpy(data, &mr->data[reader->pos], len);
85 msg("at pos %d, asked to read %d bytes, did read %d bytes\n", reader->pos, _len, len);
86 reader->pos += len;
87 return len;
89 static void reader_memread_dealloc(reader_t*reader)
91 if(reader->internal)
92 free(reader->internal);
93 memset(reader, 0, sizeof(reader_t));
95 reader_t*reader_init_memreader(void*newdata, int newlength)
97 reader_t*r = malloc(sizeof(reader_t));
98 struct memread_t*mr = (struct memread_t*)malloc(sizeof(struct memread_t));
99 mr->data = (unsigned char*)newdata;
100 mr->length = newlength;
101 r->read = reader_memread;
102 r->dealloc = reader_memread_dealloc;
103 r->internal = (void*)mr;
104 r->pos = 0;
105 return r;
107 /* ---------------------------- lzma reader -------------------------- */
108 typedef struct
110 reader_t*input;
111 CLzmaDecoderState state;
112 unsigned char*mem;
113 int pos;
114 int len;
115 int lzmapos;
116 int available;
117 } lzma_t;
119 static void reader_lzma_dealloc(reader_t*reader)
121 lzma_t*i = (lzma_t*)reader->internal;
122 free(i->state.Probs);i->state.Probs = 0;
123 free(i->state.Dictionary);i->state.Dictionary = 0;
124 free(reader->internal);reader->internal=0;
127 static int reader_lzma_read(reader_t*reader, void*data, int len)
129 lzma_t*i = (lzma_t*)reader->internal;
131 SizeT processed = 0;
132 if(len>i->available)
133 len = i->available;
134 int ret = LzmaDecode(&i->state,
135 &i->mem[i->pos], i->len-i->pos, &i->lzmapos,
136 data, len, &processed);
137 i->available -= processed;
138 i->pos += i->lzmapos;
139 return processed;
142 reader_t* reader_init_lzma(void*mem, int len)
144 reader_t*r = malloc(sizeof(reader_t));
145 memset(r, 0, sizeof(reader_t));
147 lzma_t*i = (lzma_t*)malloc(sizeof(lzma_t));
148 memset(i, 0, sizeof(lzma_t));
149 r->internal = i;
150 r->read = reader_lzma_read;
151 r->dealloc = reader_lzma_dealloc;
152 r->pos = 0;
154 i->mem = mem;
155 i->len = len;
156 i->lzmapos = 0;
158 if(LzmaDecodeProperties(&i->state.Properties, mem, LZMA_PROPERTIES_SIZE)) {
159 printf("Couldn't decode properties\n");
160 return 0;
162 i->pos += LZMA_PROPERTIES_SIZE;
164 unsigned char*l = &i->mem[i->pos];
165 i->available = (long long)l[0] | (long long)l[1]<<8 | (long long)l[2]<<16 | (long long)l[3]<<24 |
166 (long long)l[4]<<32 | (long long)l[5]<<40 | (long long)l[6]<<48 | (long long)l[7]<<56;
167 i->pos += 8; //uncompressed size
169 i->state.Probs = (CProb *)malloc(LzmaGetNumProbs(&i->state.Properties) * sizeof(CProb));
170 i->state.Dictionary = (unsigned char *)malloc(i->state.Properties.DictionarySize);
171 LzmaDecoderInit(&i->state);
173 return r;
176 #ifdef ZLIB
177 /* ---------------------------- zlibinflate reader -------------------------- */
178 struct zlibinflate_t
180 z_stream zs;
181 reader_t*input;
182 unsigned char readbuffer[ZLIB_BUFFER_SIZE];
185 static void zlib_error(int ret, char* msg, z_stream*zs)
187 fprintf(stderr, "%s: zlib error (%d): last zlib error: %s\n", msg, ret, zs->msg?zs->msg:"unknown");
188 perror("errno:");
189 exit(1);
192 static int reader_zlibinflate(reader_t*reader, void* data, int len)
194 struct zlibinflate_t*z = (struct zlibinflate_t*)reader->internal;
195 int ret;
196 if(!z) {
197 return 0;
199 if(!len)
200 return 0;
202 z->zs.next_out = (Bytef *)data;
203 z->zs.avail_out = len;
205 while(1) {
206 if(!z->zs.avail_in) {
207 z->zs.avail_in = z->input->read(z->input, z->readbuffer, ZLIB_BUFFER_SIZE);
208 z->zs.next_in = z->readbuffer;
210 if(z->zs.avail_in)
211 ret = inflate(&z->zs, Z_NO_FLUSH);
212 else
213 ret = inflate(&z->zs, Z_FINISH);
215 if (ret != Z_OK &&
216 ret != Z_STREAM_END) zlib_error(ret, "bitio:inflate_inflate", &z->zs);
218 if (ret == Z_STREAM_END) {
219 int pos = z->zs.next_out - (Bytef*)data;
220 ret = inflateEnd(&z->zs);
221 if (ret != Z_OK) zlib_error(ret, "bitio:inflate_end", &z->zs);
222 free(reader->internal);
223 reader->internal = 0;
224 reader->pos += pos;
225 return pos;
227 if(!z->zs.avail_out) {
228 break;
231 reader->pos += len;
232 return len;
234 static void reader_zlibinflate_dealloc(reader_t*reader)
236 struct zlibinflate_t*z = (struct zlibinflate_t*)reader->internal;
237 if(z) {
238 if(z->input) {
239 z->input->dealloc(z->input);z->input = 0;
241 inflateEnd(&z->zs);
242 free(reader->internal);
244 memset(reader, 0, sizeof(reader_t));
246 reader_t* reader_init_zlibinflate(reader_t*input)
248 reader_t*r = malloc(sizeof(reader_t));
249 struct zlibinflate_t*z;
250 int ret;
251 memset(r, 0, sizeof(reader_t));
252 z = (struct zlibinflate_t*)malloc(sizeof(struct zlibinflate_t));
253 memset(z, 0, sizeof(struct zlibinflate_t));
254 r->internal = z;
255 r->read = reader_zlibinflate;
256 r->dealloc = reader_zlibinflate_dealloc;
257 r->pos = 0;
258 z->input = input;
259 memset(&z->zs,0,sizeof(z_stream));
260 z->zs.zalloc = Z_NULL;
261 z->zs.zfree = Z_NULL;
262 z->zs.opaque = Z_NULL;
263 ret = inflateInit(&z->zs);
264 if (ret != Z_OK) zlib_error(ret, "bitio:inflate_init", &z->zs);
265 return r;
268 /* -------------------------------------------------------------------------- */
269 #endif
272 static int create_directory(char*path,status_t* f)
274 if(!path || !*path || (*path=='.' && (!path[1] || path[1]=='.')))
275 return 1; //nothing to do
276 while(path[0]=='.' && (path[1]=='/' || path[1]=='\\'))
277 path+=2;
279 #ifdef WIN32
280 if(PathIsDirectoryA(path))
281 return 1;
282 #else
283 struct stat st;
284 if(stat(path, &st)>=0) {
285 if(S_ISDIR(st.st_mode)) {
286 return 1; /* already exists */
289 #endif
291 if(mkdir(path,0755)<0) {
292 perror("mkdir");
293 char buf[1024];
294 sprintf(buf, "create directory \"%s\" FAILED", path);
295 f->error(buf);
296 return 0;
298 return 1;
300 static int goto_directory(char*path,status_t* f)
302 if(chdir(path)<0) {
303 char buf[1024];
304 sprintf(buf, "changing to directory \"%s\" FAILED", path);
305 f->error(buf);
306 return 0;
308 return 1;
310 static char basenamebuf[256];
311 static char*get_directory(char*filename)
313 char*r1 = strrchr(filename, '\\');
314 char*r2 = strrchr(filename, '/');
315 char*r = r1>r2?r1:r2;
316 if(!r)
317 return "";
318 memcpy(basenamebuf, filename, r-filename);
319 basenamebuf[r-filename] = 0;
320 //msg("directory name of \"%s\" is \"%s\"", filename, basenamebuf);
321 return basenamebuf;
323 static int write_file(char*filename, reader_t*r, int len,status_t* f)
325 while(filename[0]=='.' && (filename[1]=='/' || filename[1]=='\\'))
326 filename+=2;
328 filename=strdup(filename);
330 char*p = filename;
331 while(*p) {
332 if(*p=='/') *p='\\';
333 p++;
336 f->new_file(filename);
338 msg("create file \"%s\" (%d bytes)", filename, len);
339 FILE*fo = fopen(filename, "wb");
341 if(!fo) {
342 char buf[1024];
343 sprintf(buf, "Couldn't create file %s", filename);
344 f->error(buf);
345 free(filename);
346 return 0;
348 int pos=0;
349 char buf[4096];
350 while(pos<len) {
351 int l = 4096;
352 if(pos+l>len)
353 l = len-pos;
354 int n = r->read(r, buf, l);
355 if(n < l) {
356 char buf[1024];
357 sprintf(buf, "Couldn't read byte %d (pos+%d) from input buffer for file %s", pos+n, n, filename);
358 f->error(buf);
359 return 0;
361 fwrite(buf, l, 1, fo);
362 pos+=l;
364 fclose(fo);
365 free(filename);
366 return 1;
369 int unpack_archive(void*data, int len, char*destdir, status_t* f)
371 reader_t*m = reader_init_memreader(data, len);
372 #ifdef ZLIB
373 reader_t*z = reader_init_zlibinflate(m);
374 #else
375 reader_t*z = reader_init_lzma(data, len);
376 #endif
377 if(!z) {
378 f->error("Couldn't decompress installation files");
379 return 0;
382 f->message("Creating installation directory");
383 if(!create_directory(destdir,f)) return 0;
385 printf("%s\n", destdir);
387 unsigned b1=0,b2=0,b3=0,b4=0;
388 int l = 0;
389 l+=z->read(z, &b1, 1);
390 l+=z->read(z, &b2, 1);
391 l+=z->read(z, &b3, 1);
392 l+=z->read(z, &b4, 1);
393 if(l<4)
394 return 0;
395 /* read size */
396 int num = b1|b2<<8|b3<<16|b4<<24;
398 f->status(0, num);
400 f->message("Uncompressing files...");
401 int pos = 0;
402 while(1) {
403 /* read id */
404 unsigned char id[4];
405 id[3] = 0;
406 if(z->read(z, id, 3)<3) {
407 f->error("Unexpected end of archive");
408 return 0;
410 if(!strcmp(id, "END"))
411 break;
413 unsigned b1=0,b2=0,b3=0,b4=0;
414 int l = 0;
415 l+=z->read(z, &b1, 1);
416 l+=z->read(z, &b2, 1);
417 l+=z->read(z, &b3, 1);
418 l+=z->read(z, &b4, 1);
419 if(l<4)
420 return 0;
422 /* read size */
423 int len = b1|b2<<8|b3<<16|b4<<24;
425 /* read filename */
426 unsigned char filename_len;
427 z->read(z, &filename_len, 1);
428 char*filename = malloc(filename_len+1);
429 z->read(z, filename, filename_len);
430 filename[(int)filename_len] = 0;
432 while(filename[0]=='.' && (filename[1]=='/' || filename[1]=='\\'))
433 filename+=2;
434 filename = concatPaths(destdir, filename);
436 f->status(++pos, num);
438 if(verbose) printf("[%s] %s %d\n", id, filename, len);
439 char buf[2048];
440 sprintf(buf, "[%s] %s (%d bytes)", id, filename, len);
441 f->message(buf);
442 if(!strcmp(id, "DIR")) {
443 f->new_directory(filename);
444 if(!create_directory(filename,f)) return 0;
445 } else {
446 if(!create_directory(get_directory(filename),f)) return 0;
447 if(!write_file(filename,z,len,f)) return 0;
450 f->message("Finishing Installation");
451 return 1;