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