/* archive.c
- Part of the swftools installer.
+ Part of the rfx installer.
- Copyright (c) 2004 Matthias Kramm <kramm@quiss.org>
+ Copyright (c) 2004-2008 Matthias Kramm <kramm@quiss.org>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
#include <sys/stat.h>
#endif
#include "archive.h"
+#include "utils.h"
+
+#ifdef ZLIB
#include "../z/zlib.h"
#define ZLIB_BUFFER_SIZE 16384
+#else
+#include "lzma/LzmaDecode.h"
+#endif
static int verbose = 0;
static void msg(char*format, ...)
if(!verbose)
return;
va_start(arglist, format);
- vsprintf(buf, format, arglist);
+ vsnprintf(buf, sizeof(buf)-1, format, arglist);
va_end(arglist);
l = strlen(buf);
while(l && buf[l-1]=='\n') {
r->pos = 0;
return r;
}
+/* ---------------------------- lzma reader -------------------------- */
+typedef struct
+{
+ reader_t*input;
+ CLzmaDecoderState state;
+ unsigned char*mem;
+ int pos;
+ int len;
+ int lzmapos;
+ int available;
+} lzma_t;
+
+static void reader_lzma_dealloc(reader_t*reader)
+{
+ lzma_t*i = (lzma_t*)reader->internal;
+ free(i->state.Probs);i->state.Probs = 0;
+ free(i->state.Dictionary);i->state.Dictionary = 0;
+ free(reader->internal);reader->internal=0;
+}
+
+static int reader_lzma_read(reader_t*reader, void*data, int len)
+{
+ lzma_t*i = (lzma_t*)reader->internal;
+
+ SizeT processed = 0;
+ if(len>i->available)
+ len = i->available;
+ int ret = LzmaDecode(&i->state,
+ &i->mem[i->pos], i->len-i->pos, &i->lzmapos,
+ data, len, &processed);
+ i->available -= processed;
+ i->pos += i->lzmapos;
+ return processed;
+}
+
+reader_t* reader_init_lzma(void*mem, int len)
+{
+ reader_t*r = malloc(sizeof(reader_t));
+ memset(r, 0, sizeof(reader_t));
+
+ lzma_t*i = (lzma_t*)malloc(sizeof(lzma_t));
+ memset(i, 0, sizeof(lzma_t));
+ r->internal = i;
+ r->read = reader_lzma_read;
+ r->dealloc = reader_lzma_dealloc;
+ r->pos = 0;
+
+ i->mem = mem;
+ i->len = len;
+ i->lzmapos = 0;
+
+ if(LzmaDecodeProperties(&i->state.Properties, mem, LZMA_PROPERTIES_SIZE)) {
+ printf("Couldn't decode properties\n");
+ return 0;
+ }
+ i->pos += LZMA_PROPERTIES_SIZE;
+
+ unsigned char*l = &i->mem[i->pos];
+ i->available = (long long)l[0] | (long long)l[1]<<8 | (long long)l[2]<<16 | (long long)l[3]<<24 |
+ (long long)l[4]<<32 | (long long)l[5]<<40 | (long long)l[6]<<48 | (long long)l[7]<<56;
+ i->pos += 8; //uncompressed size
+ i->state.Probs = (CProb *)malloc(LzmaGetNumProbs(&i->state.Properties) * sizeof(CProb));
+ i->state.Dictionary = (unsigned char *)malloc(i->state.Properties.DictionarySize);
+ LzmaDecoderInit(&i->state);
+
+ return r;
+}
+#ifdef ZLIB
/* ---------------------------- zlibinflate reader -------------------------- */
struct zlibinflate_t
{
}
/* -------------------------------------------------------------------------- */
+#endif
-static int create_directory(char*path,statusfunc_t f)
+static int create_directory(char*path,status_t* f)
{
if(!path || !*path || (*path=='.' && (!path[1] || path[1]=='.')))
return 1; //nothing to do
perror("mkdir");
char buf[1024];
sprintf(buf, "create directory \"%s\" FAILED", path);
- f(-1, buf);
+ f->error(buf);
return 0;
}
return 1;
}
-static int goto_directory(char*path,statusfunc_t f)
+static int goto_directory(char*path,status_t* f)
{
if(chdir(path)<0) {
char buf[1024];
sprintf(buf, "changing to directory \"%s\" FAILED", path);
- f(-1, buf);
+ f->error(buf);
return 0;
}
return 1;
//msg("directory name of \"%s\" is \"%s\"", filename, basenamebuf);
return basenamebuf;
}
-static int write_file(char*filename, reader_t*r, int len,statusfunc_t f)
+static int write_file(char*filename, reader_t*r, int len,status_t* f)
{
while(filename[0]=='.' && (filename[1]=='/' || filename[1]=='\\'))
filename+=2;
p++;
}
+ f->new_file(filename);
+
msg("create file \"%s\" (%d bytes)", filename, len);
FILE*fo = fopen(filename, "wb");
if(!fo) {
char buf[1024];
sprintf(buf, "Couldn't create file %s", filename);
- f(-1, buf);
+ f->error(buf);
free(filename);
return 0;
}
if(n < l) {
char buf[1024];
sprintf(buf, "Couldn't read byte %d (pos+%d) from input buffer for file %s", pos+n, n, filename);
- f(-1, buf);
+ f->error(buf);
return 0;
}
fwrite(buf, l, 1, fo);
return 1;
}
-int unpack_archive(void*data, int len, char*destdir, statusfunc_t f)
+int unpack_archive(void*data, int len, char*destdir, status_t* f)
{
reader_t*m = reader_init_memreader(data, len);
+#ifdef ZLIB
reader_t*z = reader_init_zlibinflate(m);
+#else
+ reader_t*z = reader_init_lzma(data, len);
+#endif
+ if(!z) {
+ f->error("Couldn't decompress installation files");
+ return 0;
+ }
- f(0, "Creating installation directory");
+ f->message("Creating installation directory");
if(!create_directory(destdir,f)) return 0;
- f(0, "Changing to installation directory");
- if(!goto_directory(destdir,f)) return 0;
+
+ printf("%s\n", destdir);
+
+ unsigned b1=0,b2=0,b3=0,b4=0;
+ int l = 0;
+ l+=z->read(z, &b1, 1);
+ l+=z->read(z, &b2, 1);
+ l+=z->read(z, &b3, 1);
+ l+=z->read(z, &b4, 1);
+ if(l<4)
+ return 0;
+ /* read size */
+ int num = b1|b2<<8|b3<<16|b4<<24;
+
+ f->status(0, num);
- f(0, "Uncompressing files...");
+ f->message("Uncompressing files...");
+ int pos = 0;
while(1) {
/* read id */
unsigned char id[4];
id[3] = 0;
if(z->read(z, id, 3)<3) {
- f(-1, "Unexpected end of archive");
+ f->error("Unexpected end of archive");
return 0;
}
if(!strcmp(id, "END"))
char*filename = malloc(filename_len+1);
z->read(z, filename, filename_len);
filename[(int)filename_len] = 0;
+
+ while(filename[0]=='.' && (filename[1]=='/' || filename[1]=='\\'))
+ filename+=2;
+ filename = concatPaths(destdir, filename);
+
+ f->status(++pos, num);
if(verbose) printf("[%s] %s %d\n", id, filename, len);
char buf[2048];
sprintf(buf, "[%s] %s (%d bytes)", id, filename, len);
- f(0, buf);
+ f->message(buf);
if(!strcmp(id, "DIR")) {
+ f->new_directory(filename);
if(!create_directory(filename,f)) return 0;
} else {
if(!create_directory(get_directory(filename),f)) return 0;
-
if(!write_file(filename,z,len,f)) return 0;
}
}
- f(0, "Finishing Installation");
+ f->message("Finishing Installation");
return 1;
}