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 */
34 #include "../z/zlib.h"
35 #define ZLIB_BUFFER_SIZE 16384
37 #include "lzma/LzmaDecode.h"
40 static int verbose
= 0;
41 static void msg(char*format
, ...)
48 va_start(arglist
, format
);
49 vsnprintf(buf
, sizeof(buf
)-1, format
, arglist
);
52 while(l
&& buf
[l
-1]=='\n') {
56 printf("(archive) %s\n", buf
);
61 typedef struct _reader
63 int (*read
)(struct _reader
*, void*data
, int len
);
64 void (*dealloc
)(struct _reader
*);
69 /* ---------------------------- mem reader ------------------------------- */
76 static int reader_memread(reader_t
*reader
, void* data
, int _len
)
78 struct memread_t
*mr
= (struct memread_t
*)reader
->internal
;
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
);
89 static void reader_memread_dealloc(reader_t
*reader
)
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
;
107 /* ---------------------------- lzma reader -------------------------- */
111 CLzmaDecoderState state
;
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
;
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
;
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
));
150 r
->read
= reader_lzma_read
;
151 r
->dealloc
= reader_lzma_dealloc
;
158 if(LzmaDecodeProperties(&i
->state
.Properties
, mem
, LZMA_PROPERTIES_SIZE
)) {
159 printf("Couldn't decode properties\n");
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
);
177 /* ---------------------------- zlibinflate reader -------------------------- */
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");
192 static int reader_zlibinflate(reader_t
*reader
, void* data
, int len
)
194 struct zlibinflate_t
*z
= (struct zlibinflate_t
*)reader
->internal
;
202 z
->zs
.next_out
= (Bytef
*)data
;
203 z
->zs
.avail_out
= len
;
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
;
211 ret
= inflate(&z
->zs
, Z_NO_FLUSH
);
213 ret
= inflate(&z
->zs
, Z_FINISH
);
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;
227 if(!z
->zs
.avail_out
) {
234 static void reader_zlibinflate_dealloc(reader_t
*reader
)
236 struct zlibinflate_t
*z
= (struct zlibinflate_t
*)reader
->internal
;
239 z
->input
->dealloc(z
->input
);z
->input
= 0;
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
;
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
));
255 r
->read
= reader_zlibinflate
;
256 r
->dealloc
= reader_zlibinflate_dealloc
;
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
);
268 /* -------------------------------------------------------------------------- */
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]=='\\'))
280 if(PathIsDirectoryA(path
))
284 if(stat(path
, &st
)>=0) {
285 if(S_ISDIR(st
.st_mode
)) {
286 return 1; /* already exists */
291 if(mkdir(path
,0755)<0) {
294 sprintf(buf
, "create directory \"%s\" FAILED", path
);
300 static int goto_directory(char*path
,status_t
* f
)
304 sprintf(buf
, "changing to directory \"%s\" FAILED", path
);
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
;
318 memcpy(basenamebuf
, filename
, r
-filename
);
319 basenamebuf
[r
-filename
] = 0;
320 //msg("directory name of \"%s\" is \"%s\"", filename, basenamebuf);
323 static int write_file(char*filename
, reader_t
*r
, int len
,status_t
* f
)
325 while(filename
[0]=='.' && (filename
[1]=='/' || filename
[1]=='\\'))
328 filename
=strdup(filename
);
336 f
->new_file(filename
);
338 msg("create file \"%s\" (%d bytes)", filename
, len
);
339 FILE*fo
= fopen(filename
, "wb");
343 sprintf(buf
, "Couldn't create file %s", filename
);
354 int n
= r
->read(r
, buf
, l
);
357 sprintf(buf
, "Couldn't read byte %d (pos+%d) from input buffer for file %s", pos
+n
, n
, filename
);
361 fwrite(buf
, l
, 1, fo
);
369 int unpack_archive(void*data
, int len
, char*destdir
, status_t
* f
)
371 reader_t
*m
= reader_init_memreader(data
, len
);
373 reader_t
*z
= reader_init_zlibinflate(m
);
375 reader_t
*z
= reader_init_lzma(data
, len
);
378 f
->error("Couldn't decompress installation files");
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;
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);
396 int num
= b1
|b2
<<8|b3
<<16|b4
<<24;
400 f
->message("Uncompressing files...");
406 if(z
->read(z
, id
, 3)<3) {
407 f
->error("Unexpected end of archive");
410 if(!strcmp(id
, "END"))
413 unsigned b1
=0,b2
=0,b3
=0,b4
=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);
423 int len
= b1
|b2
<<8|b3
<<16|b4
<<24;
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]=='\\'))
434 filename
= concatPaths(destdir
, filename
);
436 f
->status(++pos
, num
);
438 if(verbose
) printf("[%s] %s %d\n", id
, filename
, len
);
440 sprintf(buf
, "[%s] %s (%d bytes)", id
, filename
, len
);
442 if(!strcmp(id
, "DIR")) {
443 f
->new_directory(filename
);
444 if(!create_directory(filename
,f
)) return 0;
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");