3 Part of the swftools installer.
5 Copyright (c) 2004 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 */
33 #include "../z/zlib.h"
34 #define ZLIB_BUFFER_SIZE 16384
36 #include "lzma/LzmaDecode.h"
39 static int verbose = 0;
40 static void msg(char*format, ...)
47 va_start(arglist, format);
48 vsprintf(buf, format, arglist);
51 while(l && buf[l-1]=='\n') {
55 printf("(archive) %s\n", buf);
60 typedef struct _reader
62 int (*read)(struct _reader*, void*data, int len);
63 void (*dealloc)(struct _reader*);
68 /* ---------------------------- mem reader ------------------------------- */
75 static int reader_memread(reader_t*reader, void* data, int _len)
77 struct memread_t*mr = (struct memread_t*)reader->internal;
80 if(mr->length - reader->pos < len) {
81 len = mr->length - reader->pos;
83 memcpy(data, &mr->data[reader->pos], len);
84 msg("at pos %d, asked to read %d bytes, did read %d bytes\n", reader->pos, _len, len);
88 static void reader_memread_dealloc(reader_t*reader)
91 free(reader->internal);
92 memset(reader, 0, sizeof(reader_t));
94 reader_t*reader_init_memreader(void*newdata, int newlength)
96 reader_t*r = malloc(sizeof(reader_t));
97 struct memread_t*mr = (struct memread_t*)malloc(sizeof(struct memread_t));
98 mr->data = (unsigned char*)newdata;
99 mr->length = newlength;
100 r->read = reader_memread;
101 r->dealloc = reader_memread_dealloc;
102 r->internal = (void*)mr;
106 /* ---------------------------- lzma reader -------------------------- */
110 CLzmaDecoderState state;
118 static void reader_lzma_dealloc(reader_t*reader)
120 lzma_t*i = (lzma_t*)reader->internal;
121 free(i->state.Probs);i->state.Probs = 0;
122 free(i->state.Dictionary);i->state.Dictionary = 0;
123 free(reader->internal);reader->internal=0;
126 static int reader_lzma_read(reader_t*reader, void*data, int len)
128 lzma_t*i = (lzma_t*)reader->internal;
133 int ret = LzmaDecode(&i->state,
134 &i->mem[i->pos], i->len-i->pos, &i->lzmapos,
135 data, len, &processed);
136 i->available -= processed;
137 i->pos += i->lzmapos;
141 reader_t* reader_init_lzma(void*mem, int len)
143 reader_t*r = malloc(sizeof(reader_t));
144 memset(r, 0, sizeof(reader_t));
146 lzma_t*i = (lzma_t*)malloc(sizeof(lzma_t));
147 memset(i, 0, sizeof(lzma_t));
149 r->read = reader_lzma_read;
150 r->dealloc = reader_lzma_dealloc;
157 if(LzmaDecodeProperties(&i->state.Properties, mem, LZMA_PROPERTIES_SIZE)) {
158 printf("Couldn't decode properties\n");
161 i->pos += LZMA_PROPERTIES_SIZE;
163 unsigned char*l = &i->mem[i->pos];
164 i->available = (long long)l[0] | (long long)l[1]<<8 | (long long)l[2]<<16 | (long long)l[3]<<24 |
165 (long long)l[4]<<32 | (long long)l[5]<<40 | (long long)l[6]<<48 | (long long)l[7]<<56;
166 i->pos += 8; //uncompressed size
168 i->state.Probs = (CProb *)malloc(LzmaGetNumProbs(&i->state.Properties) * sizeof(CProb));
169 i->state.Dictionary = (unsigned char *)malloc(i->state.Properties.DictionarySize);
170 LzmaDecoderInit(&i->state);
176 /* ---------------------------- zlibinflate reader -------------------------- */
181 unsigned char readbuffer[ZLIB_BUFFER_SIZE];
184 static void zlib_error(int ret, char* msg, z_stream*zs)
186 fprintf(stderr, "%s: zlib error (%d): last zlib error: %s\n", msg, ret, zs->msg?zs->msg:"unknown");
191 static int reader_zlibinflate(reader_t*reader, void* data, int len)
193 struct zlibinflate_t*z = (struct zlibinflate_t*)reader->internal;
201 z->zs.next_out = (Bytef *)data;
202 z->zs.avail_out = len;
205 if(!z->zs.avail_in) {
206 z->zs.avail_in = z->input->read(z->input, z->readbuffer, ZLIB_BUFFER_SIZE);
207 z->zs.next_in = z->readbuffer;
210 ret = inflate(&z->zs, Z_NO_FLUSH);
212 ret = inflate(&z->zs, Z_FINISH);
215 ret != Z_STREAM_END) zlib_error(ret, "bitio:inflate_inflate", &z->zs);
217 if (ret == Z_STREAM_END) {
218 int pos = z->zs.next_out - (Bytef*)data;
219 ret = inflateEnd(&z->zs);
220 if (ret != Z_OK) zlib_error(ret, "bitio:inflate_end", &z->zs);
221 free(reader->internal);
222 reader->internal = 0;
226 if(!z->zs.avail_out) {
233 static void reader_zlibinflate_dealloc(reader_t*reader)
235 struct zlibinflate_t*z = (struct zlibinflate_t*)reader->internal;
238 z->input->dealloc(z->input);z->input = 0;
241 free(reader->internal);
243 memset(reader, 0, sizeof(reader_t));
245 reader_t* reader_init_zlibinflate(reader_t*input)
247 reader_t*r = malloc(sizeof(reader_t));
248 struct zlibinflate_t*z;
250 memset(r, 0, sizeof(reader_t));
251 z = (struct zlibinflate_t*)malloc(sizeof(struct zlibinflate_t));
252 memset(z, 0, sizeof(struct zlibinflate_t));
254 r->read = reader_zlibinflate;
255 r->dealloc = reader_zlibinflate_dealloc;
258 memset(&z->zs,0,sizeof(z_stream));
259 z->zs.zalloc = Z_NULL;
260 z->zs.zfree = Z_NULL;
261 z->zs.opaque = Z_NULL;
262 ret = inflateInit(&z->zs);
263 if (ret != Z_OK) zlib_error(ret, "bitio:inflate_init", &z->zs);
267 /* -------------------------------------------------------------------------- */
271 static int create_directory(char*path,statusfunc_t f)
273 if(!path || !*path || (*path=='.' && (!path[1] || path[1]=='.')))
274 return 1; //nothing to do
275 while(path[0]=='.' && (path[1]=='/' || path[1]=='\\'))
279 if(PathIsDirectoryA(path))
283 if(stat(path, &st)>=0) {
284 if(S_ISDIR(st.st_mode)) {
285 return 1; /* already exists */
290 if(mkdir(path,0755)<0) {
293 sprintf(buf, "create directory \"%s\" FAILED", path);
299 static int goto_directory(char*path,statusfunc_t f)
303 sprintf(buf, "changing to directory \"%s\" FAILED", path);
309 static char basenamebuf[256];
310 static char*get_directory(char*filename)
312 char*r1 = strrchr(filename, '\\');
313 char*r2 = strrchr(filename, '/');
314 char*r = r1>r2?r1:r2;
317 memcpy(basenamebuf, filename, r-filename);
318 basenamebuf[r-filename] = 0;
319 //msg("directory name of \"%s\" is \"%s\"", filename, basenamebuf);
322 static int write_file(char*filename, reader_t*r, int len,statusfunc_t f)
324 while(filename[0]=='.' && (filename[1]=='/' || filename[1]=='\\'))
327 filename=strdup(filename);
335 msg("create file \"%s\" (%d bytes)", filename, len);
336 FILE*fo = fopen(filename, "wb");
340 sprintf(buf, "Couldn't create file %s", filename);
351 int n = r->read(r, buf, l);
354 sprintf(buf, "Couldn't read byte %d (pos+%d) from input buffer for file %s", pos+n, n, filename);
358 fwrite(buf, l, 1, fo);
366 int unpack_archive(void*data, int len, char*destdir, statusfunc_t f)
368 reader_t*m = reader_init_memreader(data, len);
370 reader_t*z = reader_init_zlibinflate(m);
372 reader_t*z = reader_init_lzma(data, len);
375 f(1, "Couldn't decompress installation files");
379 f(0, "Creating installation directory");
380 if(!create_directory(destdir,f)) return 0;
381 f(0, "Changing to installation directory");
382 if(!goto_directory(destdir,f)) return 0;
384 f(0, "Uncompressing files...");
389 if(z->read(z, id, 3)<3) {
390 f(-1, "Unexpected end of archive");
393 if(!strcmp(id, "END"))
396 unsigned b1=0,b2=0,b3=0,b4=0;
398 l+=z->read(z, &b1, 1);
399 l+=z->read(z, &b2, 1);
400 l+=z->read(z, &b3, 1);
401 l+=z->read(z, &b4, 1);
406 int len = b1|b2<<8|b3<<16|b4<<24;
409 unsigned char filename_len;
410 z->read(z, &filename_len, 1);
411 char*filename = malloc(filename_len+1);
412 z->read(z, filename, filename_len);
413 filename[(int)filename_len] = 0;
415 if(verbose) printf("[%s] %s %d\n", id, filename, len);
417 sprintf(buf, "[%s] %s (%d bytes)", id, filename, len);
419 if(!strcmp(id, "DIR")) {
420 if(!create_directory(filename,f)) return 0;
422 if(!create_directory(get_directory(filename),f)) return 0;
424 if(!write_file(filename,z,len,f)) return 0;
427 f(0, "Finishing Installation");