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