initial commit
[swftools.git] / installer / archive.c
1 /* archive.c
2
3    Part of the swftools installer.
4    
5    Copyright (c) 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 <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 "depack.h"
32
33
34 typedef struct _reader
35 {
36     unsigned char*mem;
37     int readpos;
38 } reader_t;
39
40 static void myread(void*self, void*mem, int len)
41 {
42     /*if(readpos+len >= sizeof(crndata)) {
43         len = sizeof(crndata) - readpos;
44     }*/
45     reader_t*r = (reader_t*)self;
46     memcpy(mem, r->mem+r->readpos, len);
47     r->readpos += len;
48     //return len;
49 }
50
51 typedef  struct _writer
52 {
53     unsigned char*mem;
54     int memlen;
55 } writer_t;
56
57 static void mywrite(void*self, void*buf, int len)
58 {
59     writer_t*w = (writer_t*)self;
60     memcpy(w->mem+w->memlen, buf, len);
61     w->memlen += len;
62 }
63
64 static int verbose = 0;
65 static void msg(char*format, ...)
66 {
67     char buf[1024];
68     int l;
69     va_list arglist;
70     if(!verbose)
71         return;
72     va_start(arglist, format);
73     vsprintf(buf, format, arglist);
74     va_end(arglist);
75     l = strlen(buf);
76     while(l && buf[l-1]=='\n') {
77         buf[l-1] = 0;
78         l--;
79     }
80     printf("(archive) %s\n", buf);
81     fflush(stdout);
82 }
83
84 static int create_directory(char*path,statusfunc_t f)
85 {
86     if(!path || !*path || (*path=='.' && (!path[1] || path[1]=='.')))
87         return 1; //nothing to do
88     while(path[0]=='.' && (path[1]=='/' || path[1]=='\\'))
89         path+=2;
90
91 #ifdef WIN32
92     if(PathIsDirectoryA(path))
93         return 1;
94 #else
95     struct stat st;
96     if(stat(path, &st)>=0) {
97         if(S_ISDIR(st.st_mode)) {
98             return 1; /* already exists */
99         }
100     }
101 #endif
102
103     if(mkdir(path,0755)<0) {
104         char buf[1024];
105         sprintf(buf, "create directory \"%s\" FAILED", path);
106         f(-1, buf);
107         return 0;
108     }
109     return 1;
110 }
111 static int goto_directory(char*path,statusfunc_t f)
112 {
113     if(chdir(path)<0) {
114         char buf[1024];
115         sprintf(buf, "changing to directory \"%s\" FAILED", path);
116         f(-1, buf);
117         return 0;
118     }
119     return 1;
120 }
121 static char basenamebuf[256];
122 static char*get_directory(char*filename)
123 {
124     char*r1 = strrchr(filename, '\\');
125     char*r2 = strrchr(filename, '/');
126     char*r = r1>r2?r1:r2;
127     if(!r)
128         return "";
129     memcpy(basenamebuf, filename, r-filename);
130     basenamebuf[r-filename] = 0;
131     //msg("directory name of \"%s\" is \"%s\"", filename, basenamebuf);
132     return basenamebuf;
133 }
134 static int write_file(char*filename, void*mem, int len,statusfunc_t f)
135 {
136     while(filename[0]=='.' && (filename[1]=='/' || filename[1]=='\\'))
137         filename+=2;
138
139     filename=strdup(filename);
140
141     char*p = filename;
142     while(*p) {
143         if(*p=='/') *p='\\';
144         p++;
145     }
146
147     msg("create file \"%s\" (%d bytes)", filename, len);
148     FILE*fo = fopen(filename, "wb");
149     if(!fo) {
150         char buf[1024];
151         sprintf(buf, "Couldn't create file %s", filename);
152         f(-1, buf);
153         free(filename);
154         return 0;
155     }
156     fwrite(mem, len, 1, fo);
157     fclose(fo);
158     free(filename);
159     return 1;
160 }
161
162 int unpack_archive(void*data, char*destdir, statusfunc_t f)
163 {
164     depack_t d;
165
166     reader_t r;
167     r.mem = (unsigned char*)data;
168     r.readpos = 0;
169     
170     f(0, "Reading compressed data");
171     depack_init(&d,&r,myread);
172     
173     writer_t w;
174     w.mem = malloc(d.size);
175     w.memlen = 0;
176
177     f(0, "Decompressing data");
178     depack_process(&d,&w,mywrite);
179     depack_destroy(&d);
180
181     f(0, "Creating installation directory");
182     if(!create_directory(destdir,f)) return 0;
183     f(0, "Changing to installation directory");
184     if(!goto_directory(destdir,f)) return 0;
185
186     f(0, "Copying files...");
187     int pos = 0;
188     while(pos<w.memlen) {
189         unsigned char*mem = w.mem;
190         /* read id */
191         unsigned char id[4];
192         id[3] = 0;
193         memcpy(id, &mem[pos], 3);
194         pos += 3;
195
196         /* read size */
197         int len = mem[pos]|mem[pos+1]<<8|mem[pos+2]<<16|mem[pos+3]<<24;
198         pos += 4;
199         
200         /* read filename */
201         char*filename = &mem[pos];
202         int l = strlen(filename);
203         pos+=l+1;
204
205         if(verbose) printf("[%s] %s %d\n", id, filename, len);
206         char buf[2048];
207         sprintf(buf, "[%s] %s (%d bytes)", id, filename, len);
208         f(0, buf);
209         if(*(U32*)id == *(U32*)"DIR") {
210             if(!create_directory(filename,f)) return 0;
211         } else {
212             if(!create_directory(get_directory(filename),f)) return 0;
213             if(!write_file(filename,mem+pos,len,f)) return 0;
214         }
215         
216         pos += len;
217     }
218     f(0, "Finishing Installation");
219     return 1;
220 }
221
222