]> icculus.org git repositories - taylor/freespace2.git/blob - src/cfilearchiver/cfilearchiver.cpp
clean up Windows #include's and use winsock2
[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 <io.h>
52 #include <conio.h>
53 #else
54 #include <dirent.h>
55 #include <unistd.h>
56 #include <sys/stat.h>
57 #include <sys/types.h>
58 #endif
59
60 #define SDL_MAIN_HANDLED
61
62 #include "pstypes.h"
63
64 #ifndef PLAT_UNIX
65 #define strcasecmp stricmp
66 #endif
67
68 static int data_error;
69 static int no_dir;
70
71 unsigned int Total_size=16; // Start with size of header
72 unsigned int Num_files =0;
73 FILE * fp_out = NULL;
74 FILE * fp_out_hdr = NULL;
75
76 typedef struct vp_header {
77         char id[4];
78         int version;
79         int index_offset;
80         int num_files;
81 } vp_header;
82
83 //vp_header Vp_header;
84
85 char archive_dat[1024];
86 char archive_hdr[1024];
87
88 #define BLOCK_SIZE (1024*1024)
89 #define VERSION_NUMBER 2;
90
91 char tmp_data[BLOCK_SIZE];              // 1 MB
92
93 void write_header()
94 {
95         fseek(fp_out, 0, SEEK_SET);
96         fwrite("VPVP", 1, 4, fp_out);
97         int ver = VERSION_NUMBER;
98         fwrite(&ver, 1, 4, fp_out);
99         fwrite(&Total_size, 1, 4, fp_out);
100         fwrite(&Num_files, 1, 4, fp_out);
101 }
102
103 int write_index(char *hf, char *df)
104 {
105         FILE *h = fopen(hf, "rb");
106
107         if ( !h ) {
108                 return 0;
109         }
110
111         FILE *d = fopen(df, "a+b");
112
113         if ( !d ) {
114                 fclose(h);
115                 return 0;
116         }
117
118         for (unsigned int i=0;i<Num_files;i++) {
119                 if ( !fread(tmp_data, 32+4+4+4, 1, h) ) {
120                         fclose(h);
121                         fclose(d);
122                         return 0;
123                 }
124
125                 fwrite(tmp_data, 32+4+4+4, 1, d);
126         }
127
128         fclose(h);
129         fclose(d);
130
131         return 1;
132 }
133
134 void pack_file(const char *filespec, const char *filename, int filesize, fs_time_t time_write )
135 {
136         char path[1024];
137
138         if ( strstr( filename, ".vp" )) {
139                 // Don't pack yourself!!
140                 return;
141         }
142
143         if ( strstr( filename, ".hdr" ))        {
144                 // Don't pack yourself!!
145                 return;
146         }
147
148         if ( filesize == 0 ) {
149                 // Don't pack 0 length files, screws up directory structure!
150                 return;
151         }
152
153         memset( path, 0, sizeof(path));
154         strcpy( path, filename );
155         if ( strlen(filename)>31 )      {
156                 printf( "Filename '%s' too long\n", filename );
157                 exit(1);
158         }
159         fwrite( &Total_size, 1, 4, fp_out_hdr );
160         fwrite( &filesize, 1, 4, fp_out_hdr );
161         fwrite( &path, 1, 32, fp_out_hdr );
162         fwrite( &time_write, 1, sizeof(fs_time_t), fp_out_hdr);
163
164         Total_size += filesize;
165         Num_files++;
166
167         printf( "Packing %s%s%s...", filespec, DIR_SEPARATOR_STR, filename );
168
169
170         sprintf( path, "%s%s%s", filespec, DIR_SEPARATOR_STR, filename );
171
172
173         FILE *fp = fopen( path, "rb" );
174         
175         if ( fp == NULL )       {
176                 printf( "Error opening '%s'\n", path );
177                 exit(1);
178         }
179
180         int nbytes, nbytes_read=0;
181
182         do      {
183                 nbytes = fread( tmp_data, 1, BLOCK_SIZE, fp );
184                 if ( nbytes > 0 )       {
185                         fwrite( tmp_data, 1, nbytes, fp_out );
186                         nbytes_read += nbytes;
187
188                 }
189         } while( nbytes > 0 );
190
191         fclose(fp);
192
193         printf( " %d bytes\n", nbytes_read );
194 }
195
196 // This function adds a directory marker to the header file
197 void add_directory(const char * dirname)
198 {
199         char path[256];
200         char *pathptr = path;
201         char *tmpptr;
202
203         if ( strlen(dirname) >= sizeof(path) )
204                 return;
205
206         strcpy(path, dirname);
207         fwrite(&Total_size, 1, 4, fp_out_hdr);
208         int i = 0;
209         fwrite(&i, 1, 4, fp_out_hdr);
210         // strip out any directories that this dir is a subdir of
211         while ((tmpptr = strchr(pathptr, DIR_SEPARATOR_CHAR)) != NULL) {
212                 pathptr = tmpptr+1;
213         }
214         fwrite(pathptr, 1, 32, fp_out_hdr);
215         fwrite(&i, 1, 4, fp_out_hdr); // timestamp = 0
216         Num_files++;
217 }
218
219 void pack_directory(const char * filespec)
220 {
221 #ifndef PLAT_UNIX
222         int find_handle;
223         _finddata_t find;
224 #endif
225         char tmp[512];
226         char tmp1[512];
227         char *ts;
228
229         // size safety check
230         if ( strlen(filespec) >= (sizeof(tmp1) + 5) )
231                 return;
232
233 /*
234         char dir_name[512];
235         char *last_slash;
236
237         last_slash = strrchr(filespec, '\\');
238         if ( last_slash ) {
239                 strcpy(dir_name, last_slash+1);
240         } else {
241                 strcpy(dir_name, filespec);
242         }
243
244         if ( !strcasecmp(dir_name, "voice") ) {
245                 return;
246         }
247 */
248
249         strcpy( tmp1, filespec );
250
251         // strip trailing slash
252         ts = tmp1+(strlen(tmp1)-1);
253         if (*ts == DIR_SEPARATOR_CHAR)
254                 *ts = '\0';
255
256         add_directory(tmp1);
257         strcat( tmp1, DIR_SEPARATOR_STR );
258         strcat( tmp1, "*.*" );
259
260         printf( "In dir '%s'\n", tmp1 );
261
262 #ifndef PLAT_UNIX
263         find_handle = _findfirst( tmp1, &find );
264         if( find_handle != -1 ) {
265                 if ( find.attrib & _A_SUBDIR )  {
266                         if (strcmp( "..", find.name) && strcmp( ".", find.name))        {
267                                 strcpy( tmp, filespec );
268                                 strcat( tmp, "\\" );
269                                 strcat( tmp, find.name );
270                                 pack_directory(tmp);
271                         }
272                 } else {
273                         pack_file( filespec, find.name, find.size, (fs_time_t)find.time_write );
274                 }
275
276                 while( !_findnext( find_handle, &find ) )       {
277                         if ( find.attrib & _A_SUBDIR )  {
278                                 if (strcmp( "..", find.name) && strcmp( ".", find.name))        {
279                                         strcpy( tmp, filespec );
280                                         strcat( tmp, "\\" );
281                                         strcat( tmp, find.name );
282                                         pack_directory(tmp);
283
284                                 }
285                         } else {
286                                 pack_file( filespec, find.name, find.size, (fs_time_t)find.time_write );
287                         }
288                 }
289         }
290 #else
291         DIR *dirp;
292         struct dirent *dir;
293
294         dirp = opendir (filespec);
295         if ( dirp ) {
296                 while ((dir = readdir(dirp)) != NULL) {
297
298                         char fn[MAX_PATH_LEN];
299                         snprintf(fn, MAX_PATH_LEN-1, "%s/%s", filespec, dir->d_name);
300                         fn[MAX_PATH_LEN-1] = 0;
301                         
302                         struct stat buf;
303                         if (stat(fn, &buf) == -1) {
304                                 continue;
305                         }
306
307                         if ( (strcmp(dir->d_name, ".") == 0) || (strcmp(dir->d_name, "..") == 0) ) {
308                                 continue;
309                         }
310
311                         if (S_ISDIR(buf.st_mode)) {
312                                 strcpy( tmp, filespec );
313                                 strcat( tmp, "/" );
314                                 strcat( tmp, dir->d_name );
315                                 pack_directory(tmp);
316                         } else {
317                                 pack_file( filespec, dir->d_name, buf.st_size, buf.st_mtime );
318                         }
319                 }
320                 closedir(dirp);
321         } else {
322                 printf("Error: Source directory does not exist!\n");
323                 no_dir = 1;
324         }
325 #endif
326         add_directory("..");
327 }
328
329 int verify_directory(const char *filespec )
330 {
331         char tmp[512] = { 0 };
332         char *ts;
333         char *dd;
334
335         // strip trailing slash
336         strncpy(tmp, filespec, sizeof(tmp)-1);
337
338         ts = tmp+(strlen(tmp)-1);
339         if (*ts == DIR_SEPARATOR_CHAR)
340                 *ts = '\0';
341
342         // make sure last directory is named "data", ignoring case
343         dd = tmp+(strlen(tmp)-4);
344         if ( strcasecmp( dd, "data" ) )
345                 data_error = 1;
346
347         return data_error;
348 }
349
350 int main(int argc, char *argv[] )
351 {
352         char archive[1024];
353         char *p;
354
355         if ( argc < 3 ) {
356                 printf("Creates a vp archive out of a FreeSpace data tree.\n\n");
357                 printf("Usage:          cfilearchiver archive_name src_dir\n");
358 #ifdef PLAT_UNIX
359                 printf("Example:        cfilearchiver freespace /tmp/freespace/data\n\n");
360 #else
361                 printf("Example:        cfilearchiver freespace c:\\freespace\\data\n\n");
362                 printf("Press any key to exit...\n");
363                 getch();
364 #endif
365                 return 1;
366         }
367
368         strcpy( archive, argv[1] );
369         p = strchr( archive, '.' );
370         if (p) *p = 0;          // remove extension     
371
372         strcpy( archive_dat, archive );
373         strcat( archive_dat, ".vp" );
374
375         strcpy( archive_hdr, archive );
376         strcat( archive_hdr, ".hdr" );
377
378         fp_out = fopen( archive_dat, "wb" );
379         if ( !fp_out )  {
380                 printf( "Couldn't open '%s'!\n", archive_dat );
381 #ifndef PLAT_UNIX
382                 printf( "Press any key to exit...\n" );
383                 getch();
384 #endif
385                 return 2;
386         }
387
388         fp_out_hdr = fopen( archive_hdr, "wb" );
389         if ( !fp_out_hdr )      {
390                 printf( "Couldn't open '%s'!\n", archive_hdr );
391 #ifndef PLAT_UNIX
392                 printf( "Press any key to exit...\n" );
393                 getch();
394 #endif
395                 return 3;
396         }
397
398         if ( verify_directory( argv[2] ) != 0 ) {
399                 printf("Warning! Last directory must be named \"data\" (not case sensitive)\n");
400                 return 4;
401         }
402
403         write_header();
404
405         pack_directory( argv[2] );
406
407         // in case the directory doesn't exist
408         if ( no_dir )
409                 return 5;
410
411         write_header();
412
413         fclose(fp_out);
414         fclose(fp_out_hdr);
415
416         printf( "Data files written, appending index...\n" );
417
418         if (!write_index(archive_hdr, archive_dat)) {
419                 printf("Error appending index!\n");
420 #ifndef PLAT_UNIX
421                 printf("Press any key to exit...\n");
422                 getch();
423 #endif
424                 return 6;
425         }
426         
427         printf( "%d total KB.\n", Total_size/1024 );
428         return 0;
429 }