]> icculus.org git repositories - taylor/freespace2.git/blob - src/cfilearchiver/cfilearchiver.cpp
fix toolset breakage
[taylor/freespace2.git] / src / cfilearchiver / cfilearchiver.cpp
1 /*
2  * Copyright (C) Volition, Inc. 1999.  All rights reserved.
3  *
4  * All source code herein is the property of Volition, Inc. You may not sell 
5  * or otherwise commercially exploit the source or things you created based on
6  * the source.
7  */
8
9 /*
10  * $Logfile: /Freespace2/code/Cfilearchiver/CfileArchiver.cpp $
11  * $Revision$
12  * $Date$
13  * $Author$
14  *
15  * Program to create an archive file for use with cfile stuff
16  *
17  * $Log$
18  * Revision 1.6  2004/12/15 04:10:45  taylor
19  * outwnd_unix.cpp from fs2_open for logging to file in debug mode
20  * fixes for default function values
21  * always use vm_* functions for sanity sake
22  * make cfilearchiver 64-bit compatible
23  * fix crash on exit from double free()
24  * fix crash on startup from extra long GL extension string in debug
25  *
26  * Revision 1.5  2003/05/04 04:49:48  taylor
27  * improve error handling, instructions
28  *
29  * Revision 1.4  2003/01/30 20:01:46  relnev
30  * ported (Taylor Richards)
31  *
32  * Revision 1.3  2002/06/09 04:41:15  relnev
33  * added copyright header
34  *
35  * Revision 1.2  2002/05/07 03:16:43  theoddone33
36  * The Great Newline Fix
37  *
38  * Revision 1.1.1.1  2002/05/03 03:28:08  root
39  * Initial import.
40  *
41  * 
42  * 2     10/23/98 6:15p Dave
43  *
44  * $NoKeywords: $
45  */
46
47 #include <stdlib.h>
48 #include <stdio.h>
49 #include <string.h>
50 #ifndef PLAT_UNIX
51 #include <direct.h>
52 #include <io.h>
53 #include <conio.h>
54 #else
55 #include <dirent.h>
56 #include <unistd.h>
57 #include <sys/stat.h>
58 #include <sys/types.h>
59 #endif
60
61 #define SDL_MAIN_HANDLED
62
63 #include "pstypes.h"
64
65 #ifndef PLAT_UNIX
66 #define strcasecmp stricmp
67 #endif
68
69 static int data_error;
70 static int no_dir;
71
72 unsigned int Total_size=16; // Start with size of header
73 unsigned int Num_files =0;
74 FILE * fp_out = NULL;
75 FILE * fp_out_hdr = NULL;
76
77 typedef struct vp_header {
78         char id[4];
79         int version;
80         int index_offset;
81         int num_files;
82 } vp_header;
83
84 //vp_header Vp_header;
85
86 char archive_dat[1024];
87 char archive_hdr[1024];
88
89 #define BLOCK_SIZE (1024*1024)
90 #define VERSION_NUMBER 2;
91
92 char tmp_data[BLOCK_SIZE];              // 1 MB
93
94 void write_header()
95 {
96         fseek(fp_out, 0, SEEK_SET);
97         fwrite("VPVP", 1, 4, fp_out);
98         int ver = VERSION_NUMBER;
99         fwrite(&ver, 1, 4, fp_out);
100         fwrite(&Total_size, 1, 4, fp_out);
101         fwrite(&Num_files, 1, 4, fp_out);
102 }
103
104 int write_index(char *hf, char *df)
105 {
106         FILE *h = fopen(hf, "rb");
107         if (!h) return 0;
108         FILE *d = fopen(df, "a+b");
109         if (!d) return 0;
110         for (unsigned int i=0;i<Num_files;i++) {
111                 fread(tmp_data, 32+4+4+4, 1, h);
112                 fwrite(tmp_data, 32+4+4+4, 1, d);
113         }
114         fclose(h);
115         fclose(d);
116         return 1;
117 }
118
119 void pack_file(const char *filespec, const char *filename, int filesize, fs_time_t time_write )
120 {
121         char path[1024];
122
123         if ( strstr( filename, ".vp" )) {
124                 // Don't pack yourself!!
125                 return;
126         }
127
128         if ( strstr( filename, ".hdr" ))        {
129                 // Don't pack yourself!!
130                 return;
131         }
132
133         if ( filesize == 0 ) {
134                 // Don't pack 0 length files, screws up directory structure!
135                 return;
136         }
137
138         memset( path, 0, sizeof(path));
139         strcpy( path, filename );
140         if ( strlen(filename)>31 )      {
141                 printf( "Filename '%s' too long\n", filename );
142                 exit(1);
143         }
144         fwrite( &Total_size, 1, 4, fp_out_hdr );
145         fwrite( &filesize, 1, 4, fp_out_hdr );
146         fwrite( &path, 1, 32, fp_out_hdr );
147         fwrite( &time_write, 1, sizeof(fs_time_t), fp_out_hdr);
148
149         Total_size += filesize;
150         Num_files++;
151
152         printf( "Packing %s%s%s...", filespec, DIR_SEPARATOR_STR, filename );
153
154
155         sprintf( path, "%s%s%s", filespec, DIR_SEPARATOR_STR, filename );
156
157
158         FILE *fp = fopen( path, "rb" );
159         
160         if ( fp == NULL )       {
161                 printf( "Error opening '%s'\n", path );
162                 exit(1);
163         }
164
165         int nbytes, nbytes_read=0;
166
167         do      {
168                 nbytes = fread( tmp_data, 1, BLOCK_SIZE, fp );
169                 if ( nbytes > 0 )       {
170                         fwrite( tmp_data, 1, nbytes, fp_out );
171                         nbytes_read += nbytes;
172
173                 }
174         } while( nbytes > 0 );
175
176         fclose(fp);
177
178         printf( " %d bytes\n", nbytes_read );
179 }
180
181 // This function adds a directory marker to the header file
182 void add_directory(const char * dirname)
183 {
184         char path[256];
185         char *pathptr = path;
186         char *tmpptr;
187
188         if ( strlen(dirname) >= sizeof(path) )
189                 return;
190
191         strcpy(path, dirname);
192         fwrite(&Total_size, 1, 4, fp_out_hdr);
193         int i = 0;
194         fwrite(&i, 1, 4, fp_out_hdr);
195         // strip out any directories that this dir is a subdir of
196         while ((tmpptr = strchr(pathptr, DIR_SEPARATOR_CHAR)) != NULL) {
197                 pathptr = tmpptr+1;
198         }
199         fwrite(pathptr, 1, 32, fp_out_hdr);
200         fwrite(&i, 1, 4, fp_out_hdr); // timestamp = 0
201         Num_files++;
202 }
203
204 void pack_directory(const char * filespec)
205 {
206 #ifndef PLAT_UNIX
207         int find_handle;
208         _finddata_t find;
209 #endif
210         char tmp[512];
211         char tmp1[512];
212         char *ts;
213
214         // size safety check
215         if ( strlen(filespec) >= (sizeof(tmp1) + 5) )
216                 return;
217
218 /*
219         char dir_name[512];
220         char *last_slash;
221
222         last_slash = strrchr(filespec, '\\');
223         if ( last_slash ) {
224                 strcpy(dir_name, last_slash+1);
225         } else {
226                 strcpy(dir_name, filespec);
227         }
228
229         if ( !strcasecmp(dir_name, "voice") ) {
230                 return;
231         }
232 */
233
234         strcpy( tmp1, filespec );
235
236         // strip trailing slash
237         ts = tmp1+(strlen(tmp1)-1);
238         if (*ts == DIR_SEPARATOR_CHAR)
239                 *ts = '\0';
240
241         add_directory(tmp1);
242         strcat( tmp1, DIR_SEPARATOR_STR );
243         strcat( tmp1, "*.*" );
244
245         printf( "In dir '%s'\n", tmp1 );
246
247 #ifndef PLAT_UNIX
248         find_handle = _findfirst( tmp1, &find );
249         if( find_handle != -1 ) {
250                 if ( find.attrib & _A_SUBDIR )  {
251                         if (strcmp( "..", find.name) && strcmp( ".", find.name))        {
252                                 strcpy( tmp, filespec );
253                                 strcat( tmp, "\\" );
254                                 strcat( tmp, find.name );
255                                 pack_directory(tmp);
256                         }
257                 } else {
258                         pack_file( filespec, find.name, find.size, (fs_time_t)find.time_write );
259                 }
260
261                 while( !_findnext( find_handle, &find ) )       {
262                         if ( find.attrib & _A_SUBDIR )  {
263                                 if (strcmp( "..", find.name) && strcmp( ".", find.name))        {
264                                         strcpy( tmp, filespec );
265                                         strcat( tmp, "\\" );
266                                         strcat( tmp, find.name );
267                                         pack_directory(tmp);
268
269                                 }
270                         } else {
271                                 pack_file( filespec, find.name, find.size, find.time_write );
272                         }
273                 }
274         }
275 #else
276         DIR *dirp;
277         struct dirent *dir;
278
279         dirp = opendir (filespec);
280         if ( dirp ) {
281                 while ((dir = readdir(dirp)) != NULL) {
282
283                         char fn[MAX_PATH_LEN];
284                         snprintf(fn, MAX_PATH_LEN-1, "%s/%s", filespec, dir->d_name);
285                         fn[MAX_PATH_LEN-1] = 0;
286                         
287                         struct stat buf;
288                         if (stat(fn, &buf) == -1) {
289                                 continue;
290                         }
291
292                         if ( (strcmp(dir->d_name, ".") == 0) || (strcmp(dir->d_name, "..") == 0) ) {
293                                 continue;
294                         }
295
296                         if (S_ISDIR(buf.st_mode)) {
297                                 strcpy( tmp, filespec );
298                                 strcat( tmp, "/" );
299                                 strcat( tmp, dir->d_name );
300                                 pack_directory(tmp);
301                         } else {
302                                 pack_file( filespec, dir->d_name, buf.st_size, buf.st_mtime );
303                         }
304                 }
305                 closedir(dirp);
306         } else {
307                 printf("Error: Source directory does not exist!\n");
308                 no_dir = 1;
309         }
310 #endif
311         add_directory("..");
312 }
313
314 int verify_directory(const char *filespec )
315 {
316         char tmp[512] = { 0 };
317         char *ts;
318         char *dd;
319
320         // strip trailing slash
321         strncpy(tmp, filespec, sizeof(tmp)-1);
322
323         ts = tmp+(strlen(tmp)-1);
324         if (*ts == DIR_SEPARATOR_CHAR)
325                 *ts = '\0';
326
327         // make sure last directory is named "data", ignoring case
328         dd = tmp+(strlen(tmp)-4);
329         if ( strcasecmp( dd, "data" ) )
330                 data_error = 1;
331
332         return data_error;
333 }
334
335 int main(int argc, char *argv[] )
336 {
337         char archive[1024];
338         char *p;
339
340         if ( argc < 3 ) {
341                 printf("Creates a vp archive out of a FreeSpace data tree.\n\n");
342                 printf("Usage:          cfilearchiver archive_name src_dir\n");
343 #ifdef PLAT_UNIX
344                 printf("Example:        cfilearchiver freespace /tmp/freespace/data\n\n");
345 #else
346                 printf("Example:        cfilearchiver freespace c:\\freespace\\data\n\n");
347                 printf("Press any key to exit...\n");
348                 getch();
349 #endif
350                 return 1;
351         }
352
353         strcpy( archive, argv[1] );
354         p = strchr( archive, '.' );
355         if (p) *p = 0;          // remove extension     
356
357         strcpy( archive_dat, archive );
358         strcat( archive_dat, ".vp" );
359
360         strcpy( archive_hdr, archive );
361         strcat( archive_hdr, ".hdr" );
362
363         fp_out = fopen( archive_dat, "wb" );
364         if ( !fp_out )  {
365                 printf( "Couldn't open '%s'!\n", archive_dat );
366 #ifndef PLAT_UNIX
367                 printf( "Press any key to exit...\n" );
368                 getch();
369 #endif
370                 return 2;
371         }
372
373         fp_out_hdr = fopen( archive_hdr, "wb" );
374         if ( !fp_out_hdr )      {
375                 printf( "Couldn't open '%s'!\n", archive_hdr );
376 #ifndef PLAT_UNIX
377                 printf( "Press any key to exit...\n" );
378                 getch();
379 #endif
380                 return 3;
381         }
382
383         if ( verify_directory( argv[2] ) != 0 ) {
384                 printf("Warning! Last directory must be named \"data\" (not case sensitive)\n");
385                 return 4;
386         }
387
388         write_header();
389
390         pack_directory( argv[2] );
391
392         // in case the directory doesn't exist
393         if ( no_dir )
394                 return 5;
395
396         write_header();
397
398         fclose(fp_out);
399         fclose(fp_out_hdr);
400
401         printf( "Data files written, appending index...\n" );
402
403         if (!write_index(archive_hdr, archive_dat)) {
404                 printf("Error appending index!\n");
405 #ifndef PLAT_UNIX
406                 printf("Press any key to exit...\n");
407                 getch();
408 #endif
409                 return 6;
410         }
411         
412         printf( "%d total KB.\n", Total_size/1024 );
413         return 0;
414 }