FS2_Open
Open source remastering of the Freespace 2 engine
cfilearchiver.cpp
Go to the documentation of this file.
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 the
6  * source.
7  *
8 */
9 
10 
11 
12 #include <stdlib.h>
13 #include <stdio.h>
14 #include <string.h>
15 #ifdef _WIN32
16 #include <direct.h>
17 #include <io.h>
18 #include <conio.h>
19 #else
20 #include <dirent.h>
21 #include <unistd.h>
22 #include <sys/stat.h>
23 #include <sys/types.h>
24 #endif
25 
26 #include "globalincs/pstypes.h"
27 #include "cfile/cfile.h"
28 
29 
30 static int data_error;
31 static int no_dir;
32 
33 // right out of pstypes.h but we don't want to use the INTEL_INT macro here
34 // since it would require SDL which isn't used on WIN32 platforms
35 #if BYTE_ORDER == BIG_ENDIAN
36 #define INT_SWAP(x) ( \
37  (x << 24) | \
38  (((ulong)x) >> 24) | \
39  ((x & 0x0000ff00) << 8) | \
40  ((x & 0x00ff0000) >> 8) \
41  )
42 #else
43 #define INT_SWAP(x) (x)
44 #endif
45 
46 
47 size_t fswrite_int(int *wint, FILE *stream)
48 {
49  int tmp = *wint;
50  tmp = INT_SWAP(tmp);
51 
52  return fwrite(&tmp, 1, sizeof(int), stream);
53 }
54 
55 unsigned int Total_size=16; // Start with size of header
56 unsigned int Num_files =0;
57 FILE *fp_out = NULL;
58 FILE *fp_out_hdr = NULL;
59 
60 typedef struct vp_header {
61  char id[4];
62  int version;
64  int num_files;
65 } vp_header;
66 
67 //vp_header Vp_header;
68 
69 char archive_dat[1024];
70 char archive_hdr[1024];
71 
72 #define BLOCK_SIZE (1024*1024)
73 #define VERSION_NUMBER 2;
74 
75 char tmp_data[BLOCK_SIZE]; // 1 MB
76 
78 {
79  int ver = VERSION_NUMBER;
80 
81  fseek(fp_out, 0, SEEK_SET);
82  fwrite("VPVP", 1, 4, fp_out);
83  fswrite_int(&ver, fp_out);
84  fswrite_int((int*)&Total_size, fp_out);
85  fswrite_int((int*)&Num_files, fp_out);
86 }
87 
88 int write_index(char *hf, char *df)
89 {
90  FILE *h = NULL, *d = NULL;
91  unsigned int i;
92 
93  h = fopen(hf, "rb");
94  d = fopen(df, "a+b");
95 
96  if ( (h == NULL) || (d == NULL) )
97  {
98  if ( h )
99  fclose( h );
100  if ( d )
101  fclose( d );
102  return 0;
103  }
104 
105  for (i = 0; i < Num_files; i++) {
106  fread(tmp_data, 32+4+4+4, 1, h);
107  fwrite(tmp_data, 32+4+4+4, 1, d);
108  }
109 
110  fclose(h);
111  fclose(d);
112 
113  unlink(hf);
114 
115  return 1;
116 }
117 
118 void pack_file( char *filespec, char *filename, int filesize, _fs_time_t time_write )
119 {
120  char path[1024];
121 
122  if ( strstr( filename, ".vp" )) {
123  // Don't pack yourself!!
124  return;
125  }
126 
127  if ( strstr( filename, ".hdr" )) {
128  // Don't pack yourself!!
129  return;
130  }
131 
132  if ( filesize == 0 ) {
133  // Don't pack 0 length files, screws up directory structure!
134  return;
135  }
136 
137  if ( strlen(filename) > 31 ) {
138  printf( "Filename '%s' too long! Skipping...\n", filename );
139  return;
140  }
141 
142  memset( path, 0, sizeof(path) );
143  strcpy_s( path, filename );
144 
145  fswrite_int( (int*)&Total_size, fp_out_hdr );
146  fswrite_int( &filesize, fp_out_hdr );
147  fwrite( &path, 1, 32, fp_out_hdr );
148  fswrite_int( (int*)&time_write, fp_out_hdr );
149 
150  Total_size += filesize;
151  Num_files++;
152 
153  printf( "Packing %s%s%s...", filespec, DIR_SEPARATOR_STR, filename );
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( char * dirname)
183 {
184  char path[256];
185  char *pathptr = path;
186  char *tmpptr;
187  int i = 0;
188 
189  strcpy_s(path, dirname);
190 
192  fswrite_int( &i, fp_out_hdr);
193 
194  // strip out any directories that this dir is a subdir of
195  while ( (tmpptr = strchr(pathptr, DIR_SEPARATOR_CHAR)) != NULL ) {
196  pathptr = tmpptr+1;
197  }
198 
199  fwrite(pathptr, 1, 32, fp_out_hdr);
200  fswrite_int( &i, fp_out_hdr); // timestamp = 0
201 
202  Num_files++;
203 }
204 
205 void pack_directory( char * filespec)
206 {
207 #ifdef _WIN32
208  int find_handle;
209  _finddata_t find;
210 #endif
211  char tmp[512];
212  char tmp1[512];
213  char *ts;
214 
215  // strip trailing slash
216  ts = filespec + (strlen(filespec) - 1);
217  while ( (*ts == DIR_SEPARATOR_CHAR) && (ts > filespec) )
218  *ts = '\0';
219 
220  strcpy_s( tmp1, filespec );
221 
222  add_directory(filespec);
223  strcat( tmp1, DIR_SEPARATOR_STR"*.*" );
224 
225  printf( "In dir '%s'\n", tmp1 );
226 
227 #ifdef _WIN32
228  find_handle = _findfirst( tmp1, &find );
229  if( find_handle != -1 ) {
230  if ( find.attrib & _A_SUBDIR ) {
231  if (strcmp( "..", find.name) && strcmp( ".", find.name) && strcmp( ".svn", find.name)) {
232  strcpy_s( tmp, filespec );
233  strcat( tmp, "\\" );
234  strcat( tmp, find.name );
235  pack_directory(tmp);
236  }
237  } else {
238  pack_file( filespec, find.name, find.size, find.time_write );
239  }
240 
241  while( !_findnext( find_handle, &find ) ) {
242  if ( find.attrib & _A_SUBDIR ) {
243  if (strcmp( "..", find.name) && strcmp( ".", find.name) && strcmp( ".svn", find.name)) {
244  strcpy_s( tmp, filespec );
245  strcat( tmp, "\\" );
246  strcat( tmp, find.name );
247  pack_directory(tmp);
248 
249  }
250  } else {
251  pack_file( filespec, find.name, find.size, find.time_write );
252  }
253  }
254  }
255 #else
256  DIR *dirp;
257  struct dirent *dir;
258 
259  dirp = opendir (filespec);
260  if ( dirp ) {
261  while ((dir = readdir(dirp)) != NULL) {
262 
263  char fn[MAX_PATH];
264  snprintf(fn, MAX_PATH-1, "%s/%s", filespec, dir->d_name);
265  fn[MAX_PATH-1] = 0;
266 
267  struct stat buf;
268  if (stat(fn, &buf) == -1) {
269  continue;
270  }
271 
272  if ( (strcmp(dir->d_name, ".") == 0) || (strcmp(dir->d_name, "..") == 0) ) {
273  continue;
274  }
275 
276  if ( (strcmp(dir->d_name, ".svn") == 0) ) {
277  continue;
278  }
279 
280  if (S_ISDIR(buf.st_mode)) {
281  strcpy_s( tmp, filespec );
282  strcat( tmp, "/" );
283  strcat( tmp, dir->d_name );
284  pack_directory(tmp);
285  } else {
286  pack_file( filespec, dir->d_name, buf.st_size, buf.st_mtime );
287  }
288  }
289  closedir(dirp);
290  } else {
291  printf("Error: Source directory does not exist!\n");
292  no_dir = 1;
293  }
294 #endif
295  add_directory("..");
296 }
297 
298 int verify_directory( char *filespec )
299 {
300  char *ts;
301  char *dd;
302 
303  // strip trailing '/'
304  ts = filespec+(strlen(filespec)-1);
305  while ( (*ts == DIR_SEPARATOR_CHAR) && (ts > filespec) )
306  *ts = '\0';
307 
308  // make sure last directory is named "data", ignoring case
309  dd = filespec + (strlen(filespec) - 4);
310  if ( stricmp( dd, "data" ) )
311  data_error = 1;
312 
313  return data_error;
314 }
315 
317 {
318  printf( "Creates a vp archive out of a FreeSpace data tree.\n\n" );
319  printf( "Usage: cfilearchiver archive_name src_dir\n");
320  printf( "Example: cfilearchiver freespace /tmp/freespace/data\n\n");
321  printf( "Directory structure options:\n" );
322  printf( " Effects (.ani .pcx .neb .tga)\n" );
323  printf( " Fonts (.vf)\n" );
324  printf( " Hud (.ani .pcx .tga\n" );
325  printf( " Interface (.pcx .ani .tga)\n" );
326  printf( " Maps (.pcx .ani .tga)\n" );
327  printf( " Missions (.ntl .ssv), FS1(.fsm .fsc), FS2(.fs2 .fc2)\n" );
328  printf( " Models (.pof)\n" );
329  printf( " Music (.wav)\n" );
330  printf( " Sounds/8b22k (.wav)\n" );
331  printf( " Sounds/16b11k (.wav)\n" );
332  printf( " Tables (.tbl)\n" );
333  printf( " Voice/Briefing (.wav)\n" );
334  printf( " Voice/Command briefings (.wav)\n" );
335  printf( " Voice/Debriefing (.wav)\n" );
336  printf( " Voice/Personas (.wav)\n" );
337  printf( " Voice/Special (.wav)\n" );
338  printf( " Voice/Training (.wav)\n" );
339 
340  exit(0);
341 }
342 
343 // we end up #include'ing SDL.h which on Windows and Mac will redefine main() which is something
344 // that we don't want since we don't actually link against SDL, this solves the problem...
345 #ifdef main
346 #undef main
347 #endif
348 
349 int main(int argc, char *argv[] )
350 {
351  char archive[1024];
352  char *p;
353 
354  if ( argc < 3 ) {
355 #ifdef _WIN32
356  printf( "Usage: %s archive_name src_dir\n", argv[0] );
357  printf( "Example: %s freespace c:\\freespace\\data\n", argv[0] );
358  printf( "Creates an archive named freespace out of the\nfreespace data tree\n" );
359  printf( "Press any key to exit...\n" );
360  getch();
361  return 1;
362 #else
364 #endif
365  }
366 
367  strcpy_s( archive, argv[1] );
368  p = strchr( archive, '.' );
369  if (p) *p = 0; // remove extension
370 
371  strcpy_s( archive_dat, archive );
372  strcat( archive_dat, ".vp" );
373 
374  strcpy_s( archive_hdr, archive );
375  strcat( archive_hdr, ".hdr" );
376 
377  fp_out = fopen( archive_dat, "wb" );
378  if ( !fp_out ) {
379  printf( "Couldn't open '%s'!\n", archive_dat );
380 #ifdef _WIN32
381  printf( "Press any key to exit...\n" );
382  getch();
383  return 1;
384 #else
385  exit(1);
386 #endif
387  }
388 
389  fp_out_hdr = fopen( archive_hdr, "wb" );
390  if ( !fp_out_hdr ) {
391  printf( "Couldn't open '%s'!\n", archive_hdr );
392 #ifdef _WIN32
393  printf( "Press any key to exit...\n" );
394  getch();
395  return 1;
396 #else
397  exit(2);
398 #endif
399  }
400 
401  if ( verify_directory( argv[2] ) != 0 ) {
402  printf("Warning! Last directory must be named \"data\" (not case sensitive)\n");
403  exit(3);
404  }
405 
406  write_header();
407 
408  pack_directory( argv[2] );
409 
410  // in case the directory doesn't exist
411  if ( no_dir )
412  exit(4);
413 
414  write_header();
415 
416  fclose(fp_out);
417  fclose(fp_out_hdr);
418 
419  printf( "Data files written, appending index...\n" );
420 
422  printf("Error appending index!\n");
423 #ifdef _WIN32
424  printf("Press any key to exit...\n");
425  getch();
426 #endif
427  return 1;
428  }
429 
430  printf( "%d total KB.\n", Total_size/1024 );
431  return 0;
432 }
char archive_dat[1024]
int i
Definition: multi_pxo.cpp:466
GLuint GLuint stream
Definition: Glext.h:7079
GLfloat GLfloat GLfloat GLfloat h
Definition: Glext.h:7280
size_t fswrite_int(int *wint, FILE *stream)
#define MAX_PATH
char tmp_data[BLOCK_SIZE]
#define DIR_SEPARATOR_CHAR
Definition: pstypes.h:43
long _fs_time_t
Definition: pstypes.h:55
void print_instructions()
#define VERSION_NUMBER
char archive_hdr[1024]
unsigned int Total_size
#define DIR_SEPARATOR_STR
Definition: pstypes.h:44
char * filename
sprintf(buf,"(%f,%f,%f)", v3->xyz.x, v3->xyz.y, v3->xyz.z)
void pack_file(char *filespec, char *filename, int filesize, _fs_time_t time_write)
cfbp fp
Definition: cfile.cpp:1065
int verify_directory(char *filespec)
void pack_directory(char *filespec)
int main(int argc, char *argv[])
FILE * fp_out_hdr
struct vp_header vp_header
unsigned int Num_files
FILE * fp_out
int write_index(char *hf, char *df)
void write_header()
void add_directory(char *dirname)
GLsizei const GLchar ** path
Definition: Glext.h:6795
GLfloat GLfloat p
Definition: Glext.h:8373
#define BLOCK_SIZE
#define INT_SWAP(x)
#define stricmp(s1, s2)
Definition: config.h:271
#define strcpy_s(...)
Definition: safe_strings.h:67