summaryrefslogtreecommitdiff
path: root/utils/zipalign/align.cpp
diff options
context:
space:
mode:
authorFluorescentCIAAfricanAmerican <[email protected]>2020-04-22 12:56:21 -0400
committerFluorescentCIAAfricanAmerican <[email protected]>2020-04-22 12:56:21 -0400
commit3bf9df6b2785fa6d951086978a3e66f49427166a (patch)
tree2c0f1f0c63c4832882bc93814ebd2c2b1c6224e5 /utils/zipalign/align.cpp
downloadarchived-source-engine-2018-hl2-src-master.tar.xz
archived-source-engine-2018-hl2-src-master.zip
Diffstat (limited to 'utils/zipalign/align.cpp')
-rw-r--r--utils/zipalign/align.cpp307
1 files changed, 307 insertions, 0 deletions
diff --git a/utils/zipalign/align.cpp b/utils/zipalign/align.cpp
new file mode 100644
index 0000000..6dcff87
--- /dev/null
+++ b/utils/zipalign/align.cpp
@@ -0,0 +1,307 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose: Processes .zip directories so every file is aligned to a user-defined sector boundary.
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "zip_uncompressed.h"
+#include "UtlBuffer.h"
+#include "zip_utils.h"
+
+typedef unsigned int uint;
+typedef unsigned short ushort;
+
+// Defined constant values
+static const uint DEF_SECTOR_SIZE = 512; // in bytes. (512 is xbox HD sector size)
+static const uint FILE_HEADER_SIG = 0x04034b50;
+static const uint DIRECTORY_HEADER_SIG = 0x02014b50;
+static const uint DIRECTORY_END_SIG = 0x06054b50;
+static const uint SIG_ERROR = 0xffffffff;
+
+// File scope globals
+static FILE* g_fin = 0;
+static FILE* g_fout = 0;
+static uint g_sectorSize = 0;
+static uint g_fileCt = 0;
+static uint g_sizeCt = 0;
+
+// Local function declarations
+static bool OpenInputStream ( const char* name, const char* mode );
+static void CloseInputStream ();
+static bool OpenOutputStream ( const char* name, const char* mode );
+static void CloseOutputStream ();
+static void FileError ();
+static uint FindFilenameStart ( char* name );
+
+//---------------------------------------------------------------
+// Returns the file header signature, which is used to determine
+// what type of header will follow.
+//---------------------------------------------------------------
+static uint GetHeaderSignature()
+{
+ fpos_t pos;
+ fgetpos( g_fin, &pos );
+
+ unsigned int sig;
+ if( !fread( &sig, 4, 1, g_fin ) )
+ {
+ FileError();
+ return SIG_ERROR;
+ }
+
+ fsetpos( g_fin, &pos );
+ return sig;
+}
+
+//---------------------------------------------------------------
+// Reads in the header, name, and data for a zipped file
+//---------------------------------------------------------------
+static bool ReadFileData( ZIP_LocalFileHeader& fileHeader, char* filename, char*& data )
+{
+ // Read in the header
+ if( !fread( &fileHeader, sizeof(ZIP_LocalFileHeader), 1, g_fin ) )
+ {
+ FileError();
+ return false;
+ }
+
+ // buffer check
+ if( fileHeader.fileNameLength > 256 )
+ {
+ printf("Error: filename too long\n");
+ return false;
+ }
+
+ // Read in the filename
+ if( !fread( filename, fileHeader.fileNameLength, 1, g_fin ) )
+ {
+ FileError();
+ return false;
+ }
+
+ filename[fileHeader.fileNameLength] = '\0';
+ printf("Reading file %s\n",filename);
+
+ // Absorb any extra-field padding
+ fseek( g_fin, fileHeader.extraFieldLength, SEEK_CUR );
+
+ // NOTE: With zipped sub-directories, folders have their own header
+ // with a data size of zero. These can be ignored (and will be by
+ // zip_utils anyway)
+ if( fileHeader.compressedSize != 0 )
+ {
+ // Read in the file data
+ data = new char[fileHeader.compressedSize];
+ if( !fread( data, fileHeader.compressedSize, 1, g_fin ) )
+ {
+ FileError();
+ delete [] data;
+ return false;
+ }
+ }
+
+ return true;
+}
+
+//---------------------------------------------------------------
+// Does all the work of aligning each file in the directory
+// to start on a sector boundary. (Determined by g_sectorSize)
+//
+// .zip file format:
+// [local file header ][filename][extra field][data]
+// ....
+// [directory header][filename][extra field][file comment]
+// ....
+// [central directory header][end of central directory]
+//---------------------------------------------------------------
+static bool AlignZipDirectory( const char* infile, const char* outfile )
+{
+ // Open and validate the input file
+ if( !OpenInputStream( infile, "rb" ) )
+ return false;
+
+ // Read the file header sig
+ uint sig = GetHeaderSignature();
+ if( sig == SIG_ERROR )
+ return false;
+
+ // Open and validate the output file
+ if( !OpenOutputStream( outfile, "wb" ) )
+ return false;
+
+ ZIP_LocalFileHeader hdr;
+ char filename[256]; // filename size field is 2 bytes, so to be safe the filename
+ // length is checked before copying into this buffer.
+
+ IZip *zip_utils = IZip::CreateZip();
+ if ( !zip_utils )
+ return false;
+
+ // Process all the files in the directory
+ while( sig == FILE_HEADER_SIG )
+ {
+ char * data = 0; // the data buffer is allocated in ReadFileData.
+
+ // Get the original file
+ if( !ReadFileData( hdr, filename, data ) )
+ return false;
+
+ if( data )
+ {
+ // Add to the zip file
+ zip_utils->AddBufferToZip( filename, data, hdr.compressedSize, false );
+
+ // Update counters
+ g_fileCt++;
+ g_sizeCt += hdr.compressedSize;
+ }
+
+ delete data;
+
+ // Read the next file header sig
+ sig = GetHeaderSignature();
+ if( sig == SIG_ERROR )
+ return false;
+ }
+
+ // Set the alignment size
+ zip_utils->ForceAlignment( true, true, g_sectorSize );
+
+ // Write the padded zip out to disk
+ printf("\nWriting aligned directory %s to disk\n",outfile);
+ zip_utils->SaveToDisk( g_fout );
+
+ IZip::ReleaseZip( zip_utils );
+
+ // Alignment complete
+ printf("\n%d Files successfully aligned.\n\n",g_fileCt);
+
+ return true;
+}
+
+//---------------------------------------------------------------
+// Main function
+//---------------------------------------------------------------
+void main( int argc, char **argv )
+{
+ if ( argc < 2 )
+ {
+ printf("\n");
+ printf(" Usage: zipalign {input filename} [output filename] [sector size]\n\n");
+ printf(" output filename: default = input filename prepended with \"a_\"\n");
+ printf(" sector size: minimum sector size (in bytes) to align to. Default = %d\n\n",DEF_SECTOR_SIZE);
+ return;
+ }
+
+ // Check the extension
+ size_t ext = strlen( argv[1] ) - 4;
+ if( strcmp( &argv[1][ext], ".zip" ) )
+ {
+ printf("Input file must be a .zip\n\n");
+ return;
+ }
+
+ // Get the sector size
+ g_sectorSize = DEF_SECTOR_SIZE;
+ if( argc > 3 )
+ {
+ g_sectorSize = atoi(argv[3]);
+ }
+
+ if( g_sectorSize <= 1 || ( g_sectorSize & (g_sectorSize - 1) ) )
+ {
+ printf("Invalid sector size.\n\n");
+ return;
+ }
+
+ // Call the align function
+ bool success = false;
+ if( argc > 2 )
+ {
+ success = AlignZipDirectory( argv[1], argv[2] );
+ }
+ else
+ {
+ // Construct an output filename by prepending "a_" (skip over path portion)
+ char* outfile = new char[ strlen( argv[1] ) + 3 ];
+ const uint idx = FindFilenameStart( argv[1] );
+ strcpy( outfile, argv[1] );
+ outfile[idx] = 'a';
+ outfile[idx+1] = '_';
+ strcpy( &outfile[idx+2], &argv[1][idx] );
+
+ success = AlignZipDirectory( argv[1], outfile );
+
+ delete [] outfile;
+ }
+
+ if( !success )
+ {
+ printf("\nAlignment failed.\n\n");
+ }
+
+ CloseInputStream();
+ CloseOutputStream();
+}
+
+//---------------------------------------------------------------
+// File operations
+//---------------------------------------------------------------
+uint FindFilenameStart( char* name )
+{
+ int end = (int)strlen( name );
+ while( end >= 0 && name[end] != '\\' && name[end] != '/' )
+ --end;
+ return end + 1;
+}
+
+bool OpenInputStream( const char* name, const char* mode )
+{
+ g_fin = fopen( name, mode );
+ if( !g_fin )
+ {
+ printf("\nUnable to open the input file %s\n\n",name);
+ return false;
+ }
+
+ return true;
+}
+
+void CloseInputStream()
+{
+ if( g_fin )
+ fclose( g_fin );
+}
+
+bool OpenOutputStream( const char* name, const char* mode )
+{
+ g_fout = fopen( name, mode );
+ if( !g_fout )
+ {
+ printf("\nUnable to open the output file %s\n\n",name);
+ return false;
+ }
+
+ return true;
+}
+
+void CloseOutputStream()
+{
+ if( g_fout )
+ fclose( g_fout );
+}
+
+static void FileError()
+{
+ if( ferror(g_fin) )
+ printf("\nError reading the file.\n\n");
+ else if( feof(g_fin) )
+ printf("\nError: Unexpected end of file found.\n\n");
+ else
+ printf("\nUnknown file error.\n\n");
+}
+