Team Fortress 2 Source Code as on 22/4/2020
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

307 lines
7.4 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose: Processes .zip directories so every file is aligned to a user-defined sector boundary.
  4. //
  5. // $NoKeywords: $
  6. //=============================================================================//
  7. #include <stdio.h>
  8. #include <stdlib.h>
  9. #include <string.h>
  10. #include "zip_uncompressed.h"
  11. #include "UtlBuffer.h"
  12. #include "zip_utils.h"
  13. typedef unsigned int uint;
  14. typedef unsigned short ushort;
  15. // Defined constant values
  16. static const uint DEF_SECTOR_SIZE = 512; // in bytes. (512 is xbox HD sector size)
  17. static const uint FILE_HEADER_SIG = 0x04034b50;
  18. static const uint DIRECTORY_HEADER_SIG = 0x02014b50;
  19. static const uint DIRECTORY_END_SIG = 0x06054b50;
  20. static const uint SIG_ERROR = 0xffffffff;
  21. // File scope globals
  22. static FILE* g_fin = 0;
  23. static FILE* g_fout = 0;
  24. static uint g_sectorSize = 0;
  25. static uint g_fileCt = 0;
  26. static uint g_sizeCt = 0;
  27. // Local function declarations
  28. static bool OpenInputStream ( const char* name, const char* mode );
  29. static void CloseInputStream ();
  30. static bool OpenOutputStream ( const char* name, const char* mode );
  31. static void CloseOutputStream ();
  32. static void FileError ();
  33. static uint FindFilenameStart ( char* name );
  34. //---------------------------------------------------------------
  35. // Returns the file header signature, which is used to determine
  36. // what type of header will follow.
  37. //---------------------------------------------------------------
  38. static uint GetHeaderSignature()
  39. {
  40. fpos_t pos;
  41. fgetpos( g_fin, &pos );
  42. unsigned int sig;
  43. if( !fread( &sig, 4, 1, g_fin ) )
  44. {
  45. FileError();
  46. return SIG_ERROR;
  47. }
  48. fsetpos( g_fin, &pos );
  49. return sig;
  50. }
  51. //---------------------------------------------------------------
  52. // Reads in the header, name, and data for a zipped file
  53. //---------------------------------------------------------------
  54. static bool ReadFileData( ZIP_LocalFileHeader& fileHeader, char* filename, char*& data )
  55. {
  56. // Read in the header
  57. if( !fread( &fileHeader, sizeof(ZIP_LocalFileHeader), 1, g_fin ) )
  58. {
  59. FileError();
  60. return false;
  61. }
  62. // buffer check
  63. if( fileHeader.fileNameLength > 256 )
  64. {
  65. printf("Error: filename too long\n");
  66. return false;
  67. }
  68. // Read in the filename
  69. if( !fread( filename, fileHeader.fileNameLength, 1, g_fin ) )
  70. {
  71. FileError();
  72. return false;
  73. }
  74. filename[fileHeader.fileNameLength] = '\0';
  75. printf("Reading file %s\n",filename);
  76. // Absorb any extra-field padding
  77. fseek( g_fin, fileHeader.extraFieldLength, SEEK_CUR );
  78. // NOTE: With zipped sub-directories, folders have their own header
  79. // with a data size of zero. These can be ignored (and will be by
  80. // zip_utils anyway)
  81. if( fileHeader.compressedSize != 0 )
  82. {
  83. // Read in the file data
  84. data = new char[fileHeader.compressedSize];
  85. if( !fread( data, fileHeader.compressedSize, 1, g_fin ) )
  86. {
  87. FileError();
  88. delete [] data;
  89. return false;
  90. }
  91. }
  92. return true;
  93. }
  94. //---------------------------------------------------------------
  95. // Does all the work of aligning each file in the directory
  96. // to start on a sector boundary. (Determined by g_sectorSize)
  97. //
  98. // .zip file format:
  99. // [local file header ][filename][extra field][data]
  100. // ....
  101. // [directory header][filename][extra field][file comment]
  102. // ....
  103. // [central directory header][end of central directory]
  104. //---------------------------------------------------------------
  105. static bool AlignZipDirectory( const char* infile, const char* outfile )
  106. {
  107. // Open and validate the input file
  108. if( !OpenInputStream( infile, "rb" ) )
  109. return false;
  110. // Read the file header sig
  111. uint sig = GetHeaderSignature();
  112. if( sig == SIG_ERROR )
  113. return false;
  114. // Open and validate the output file
  115. if( !OpenOutputStream( outfile, "wb" ) )
  116. return false;
  117. ZIP_LocalFileHeader hdr;
  118. char filename[256]; // filename size field is 2 bytes, so to be safe the filename
  119. // length is checked before copying into this buffer.
  120. IZip *zip_utils = IZip::CreateZip();
  121. if ( !zip_utils )
  122. return false;
  123. // Process all the files in the directory
  124. while( sig == FILE_HEADER_SIG )
  125. {
  126. char * data = 0; // the data buffer is allocated in ReadFileData.
  127. // Get the original file
  128. if( !ReadFileData( hdr, filename, data ) )
  129. return false;
  130. if( data )
  131. {
  132. // Add to the zip file
  133. zip_utils->AddBufferToZip( filename, data, hdr.compressedSize, false );
  134. // Update counters
  135. g_fileCt++;
  136. g_sizeCt += hdr.compressedSize;
  137. }
  138. delete data;
  139. // Read the next file header sig
  140. sig = GetHeaderSignature();
  141. if( sig == SIG_ERROR )
  142. return false;
  143. }
  144. // Set the alignment size
  145. zip_utils->ForceAlignment( true, true, g_sectorSize );
  146. // Write the padded zip out to disk
  147. printf("\nWriting aligned directory %s to disk\n",outfile);
  148. zip_utils->SaveToDisk( g_fout );
  149. IZip::ReleaseZip( zip_utils );
  150. // Alignment complete
  151. printf("\n%d Files successfully aligned.\n\n",g_fileCt);
  152. return true;
  153. }
  154. //---------------------------------------------------------------
  155. // Main function
  156. //---------------------------------------------------------------
  157. void main( int argc, char **argv )
  158. {
  159. if ( argc < 2 )
  160. {
  161. printf("\n");
  162. printf(" Usage: zipalign {input filename} [output filename] [sector size]\n\n");
  163. printf(" output filename: default = input filename prepended with \"a_\"\n");
  164. printf(" sector size: minimum sector size (in bytes) to align to. Default = %d\n\n",DEF_SECTOR_SIZE);
  165. return;
  166. }
  167. // Check the extension
  168. size_t ext = strlen( argv[1] ) - 4;
  169. if( strcmp( &argv[1][ext], ".zip" ) )
  170. {
  171. printf("Input file must be a .zip\n\n");
  172. return;
  173. }
  174. // Get the sector size
  175. g_sectorSize = DEF_SECTOR_SIZE;
  176. if( argc > 3 )
  177. {
  178. g_sectorSize = atoi(argv[3]);
  179. }
  180. if( g_sectorSize <= 1 || ( g_sectorSize & (g_sectorSize - 1) ) )
  181. {
  182. printf("Invalid sector size.\n\n");
  183. return;
  184. }
  185. // Call the align function
  186. bool success = false;
  187. if( argc > 2 )
  188. {
  189. success = AlignZipDirectory( argv[1], argv[2] );
  190. }
  191. else
  192. {
  193. // Construct an output filename by prepending "a_" (skip over path portion)
  194. char* outfile = new char[ strlen( argv[1] ) + 3 ];
  195. const uint idx = FindFilenameStart( argv[1] );
  196. strcpy( outfile, argv[1] );
  197. outfile[idx] = 'a';
  198. outfile[idx+1] = '_';
  199. strcpy( &outfile[idx+2], &argv[1][idx] );
  200. success = AlignZipDirectory( argv[1], outfile );
  201. delete [] outfile;
  202. }
  203. if( !success )
  204. {
  205. printf("\nAlignment failed.\n\n");
  206. }
  207. CloseInputStream();
  208. CloseOutputStream();
  209. }
  210. //---------------------------------------------------------------
  211. // File operations
  212. //---------------------------------------------------------------
  213. uint FindFilenameStart( char* name )
  214. {
  215. int end = (int)strlen( name );
  216. while( end >= 0 && name[end] != '\\' && name[end] != '/' )
  217. --end;
  218. return end + 1;
  219. }
  220. bool OpenInputStream( const char* name, const char* mode )
  221. {
  222. g_fin = fopen( name, mode );
  223. if( !g_fin )
  224. {
  225. printf("\nUnable to open the input file %s\n\n",name);
  226. return false;
  227. }
  228. return true;
  229. }
  230. void CloseInputStream()
  231. {
  232. if( g_fin )
  233. fclose( g_fin );
  234. }
  235. bool OpenOutputStream( const char* name, const char* mode )
  236. {
  237. g_fout = fopen( name, mode );
  238. if( !g_fout )
  239. {
  240. printf("\nUnable to open the output file %s\n\n",name);
  241. return false;
  242. }
  243. return true;
  244. }
  245. void CloseOutputStream()
  246. {
  247. if( g_fout )
  248. fclose( g_fout );
  249. }
  250. static void FileError()
  251. {
  252. if( ferror(g_fin) )
  253. printf("\nError reading the file.\n\n");
  254. else if( feof(g_fin) )
  255. printf("\nError: Unexpected end of file found.\n\n");
  256. else
  257. printf("\nUnknown file error.\n\n");
  258. }