ArchiveGenerator.cpp
Go to the documentation of this file.00001 //*** ArchiveGenerator.cpp *** 00002 00003 #include "ArchiveGenerator.h" 00004 #include "Debug.h" 00005 #include "Platform_FileSystem.h" 00006 #include "Platform_FileSystem_Directory.h" 00007 #include "Platform_FileSystem_File.h" 00008 #include "StandardLibrary.h" 00009 00010 extern const char* Pixie_Archive_Header; 00011 00012 00013 //*** Constructor *** 00014 00015 ArchiveGenerator::ArchiveGenerator(ProgressCallback progressCallback): 00016 progressCallback_(progressCallback), 00017 filedata_(16*1024*1024) 00018 { 00019 SetProgress(Phase_NotStarted,""); 00020 } 00021 00022 00023 //*** GenerateCPP *** 00024 00025 void ArchiveGenerator::GenerateCPP(const char* directoryPath, const char* archiveFilename, const char* archiveName) 00026 { 00027 SetProgress(Phase_Initializing,""); 00028 00029 // Make sure structures are empty 00030 root_.subDirectories.Clear(); 00031 root_.files.Clear(); 00032 filedata_.Clear(); 00033 00034 // Create archive 00035 CreateArchive(directoryPath); 00036 00037 int version=0; 00038 00039 SetProgress(Phase_CreatingHeaders,""); 00040 00041 // Calculate header size 00042 DynamicBuffer header(1024*1024); 00043 WriteDirectoryList(&header,&root_,0); 00044 int headerSize=header.GetSize(); 00045 headerSize+=StrLen(Pixie_Archive_Header); 00046 headerSize+=sizeof(version); 00047 00048 // Generate header and fixup offsets 00049 header.Clear(); 00050 WriteDirectoryList(&header,&root_,headerSize); 00051 00052 // Create output buffer 00053 DynamicBuffer buffer(filedata_.GetSize()); 00054 00055 // Write header 00056 buffer.Write(Pixie_Archive_Header,StrLen(Pixie_Archive_Header)); 00057 buffer.Write(&version); 00058 00059 // Write directory list 00060 buffer.Write(static_cast<unsigned char*>(header.GetPointer()),header.GetSize()); 00061 00062 // Write content of files 00063 buffer.Write(static_cast<unsigned char*>(filedata_.GetPointer()),filedata_.GetSize()); 00064 00065 SetProgress(Phase_GeneratingArray,"0%"); 00066 00067 DynamicBuffer textBuffer(buffer.GetSize()*5+buffer.GetSize()/100+1024); 00068 00069 // Write array declaration 00070 char str[4096]; 00071 SNPrintF(str,4096,"unsigned char %s[%d] = {\n",archiveName,buffer.GetSize()); 00072 textBuffer.Write(str,StrLen(str)); 00073 00074 // Write content of buffers 00075 unsigned char* data=static_cast<unsigned char*>(buffer.GetPointer()); 00076 for (unsigned int i=0; i<buffer.GetSize(); i++ ) 00077 { 00078 // Write hexadecimal value 00079 SNPrintF(str,4096,"0x%02X,",data[i]); 00080 textBuffer.Write(str,StrLen(str)); 00081 00082 // Every 100 bytes, do a line break 00083 if (i%100==99) 00084 { 00085 textBuffer.Write("\n"); 00086 } 00087 00088 static int lastPercentagePrinted=0; 00089 int percentageDone=(int)(100.0f*((float)i/(float)buffer.GetSize())); 00090 if (lastPercentagePrinted!=percentageDone) 00091 { 00092 DebugPrint(("GenerateCPP: %d%% done\n",percentageDone)); 00093 char buffer[6]; 00094 SNPrintF(buffer,5,"%d%%",percentageDone); 00095 SetProgress(Phase_GeneratingArray,buffer); 00096 00097 lastPercentagePrinted=percentageDone; 00098 } 00099 } 00100 00101 SetProgress(Phase_GeneratingArray,"100%"); 00102 00103 // Write right curly brace at end of array declaration 00104 SNPrintF(str,4096,"\n};"); 00105 textBuffer.Write(str,StrLen(str)); 00106 00107 00108 // Generate CPP filename 00109 Platform_FileSystem_File* file=0; 00110 if (Platform::GetPlatform_FileSystem()) 00111 { 00112 file=Platform::GetPlatform_FileSystem()->CreateFileObject(archiveFilename); 00113 } 00114 00115 SetProgress(Phase_WritingArchive,""); 00116 00117 // Create output file 00118 bool result=file->Create(); 00119 Assert(result, "Couldn't open file"); 00120 if (!result) 00121 { 00122 delete file; 00123 return; 00124 } 00125 00126 file->Write(static_cast<unsigned char*>(textBuffer.GetPointer()),textBuffer.GetSize()); 00127 00128 // Close the file 00129 file->Close(); 00130 delete file; 00131 00132 SetProgress(Phase_Done,""); 00133 } 00134 00135 00136 //*** GenerateFile *** 00137 00138 void ArchiveGenerator::GenerateFile(const char* directoryPath, const char* archiveFilename) 00139 { 00140 SetProgress(Phase_Initializing,""); 00141 00142 // Make sure structures are empty 00143 root_.subDirectories.Clear(); 00144 root_.files.Clear(); 00145 filedata_.Clear(); 00146 00147 // Create archive 00148 CreateArchive(directoryPath); 00149 00150 int version=0; 00151 00152 SetProgress(Phase_CreatingHeaders,""); 00153 00154 // Calculate header size 00155 DynamicBuffer header(1024*1024); 00156 WriteDirectoryList(&header,&root_,0); 00157 int headerSize=header.GetSize(); 00158 headerSize+=StrLen(Pixie_Archive_Header); 00159 headerSize+=sizeof(version); 00160 00161 // Generate header and fixup offsets 00162 header.Clear(); 00163 WriteDirectoryList(&header,&root_,headerSize); 00164 00165 // Generate .DAT filename 00166 Platform_FileSystem_File* file=0; 00167 if (Platform::GetPlatform_FileSystem()) 00168 { 00169 file=Platform::GetPlatform_FileSystem()->CreateFileObject(archiveFilename); 00170 } 00171 00172 Assert(file, "Couldn't create file object"); 00173 if (!file) 00174 { 00175 return; 00176 } 00177 00178 SetProgress(Phase_WritingArchive,""); 00179 00180 // Create output file 00181 bool result=file->Create(); 00182 Assert(result, "Couldn't open file"); 00183 if (!result) 00184 { 00185 return; 00186 } 00187 00188 // Write header 00189 file->Write(Pixie_Archive_Header,StrLen(Pixie_Archive_Header)); 00190 file->Write(&version); 00191 00192 // Write directory list 00193 file->Write(static_cast<unsigned char*>(header.GetPointer()),header.GetSize()); 00194 00195 // Write content of files 00196 file->Write(static_cast<unsigned char*>(filedata_.GetPointer()),filedata_.GetSize()); 00197 00198 00199 // Close the file 00200 file->Close(); 00201 delete file; 00202 00203 SetProgress(Phase_Done,""); 00204 } 00205 00206 00207 //*** WriteDirectoryList *** 00208 00209 void ArchiveGenerator::WriteDirectoryList(DynamicBuffer* buffer, DirectoryEntry* directoryEntry, int offset) 00210 { 00211 // Write directory name 00212 int nameLength=StrLen(directoryEntry->name); 00213 buffer->Write(&nameLength); 00214 buffer->Write(directoryEntry->name,nameLength); 00215 00216 // Write files 00217 int fileCount=directoryEntry->files.GetItemCount(); 00218 buffer->Write(&fileCount); 00219 for (int i=0; i<fileCount; i++) 00220 { 00221 FileEntry& fileEntry=directoryEntry->files.Get(i); 00222 00223 // Fixup offset to compensate for header 00224 fileEntry.offset+=offset; 00225 00226 // Write filename 00227 int nameLength=StrLen(fileEntry.filename); 00228 buffer->Write(&nameLength); 00229 buffer->Write(fileEntry.filename,nameLength); 00230 00231 // Write file offset and size 00232 int fileOffset=fileEntry.offset; 00233 buffer->Write(&fileOffset); 00234 int fileSize=fileEntry.size; 00235 buffer->Write(&fileSize); 00236 } 00237 00238 // Write subdirectories 00239 int directoryCount=directoryEntry->subDirectories.GetItemCount(); 00240 buffer->Write(&directoryCount); 00241 for (int i=0; i<directoryCount; i++) 00242 { 00243 DirectoryEntry& subDirectoryEntry=directoryEntry->subDirectories.Get(i); 00244 WriteDirectoryList(buffer,&subDirectoryEntry,offset); 00245 } 00246 } 00247 00248 00249 //*** CreateArchive *** 00250 00251 void ArchiveGenerator::CreateArchive(const char* directoryName) 00252 { 00253 // Create a directory object for the specified directory, which we'll use to enumerate files 00254 Platform_FileSystem_Directory* directory=0; 00255 if (Platform::GetPlatform_FileSystem()) 00256 { 00257 directory=Platform::GetPlatform_FileSystem()->CreateDirectoryObject(directoryName); 00258 } 00259 00260 const char* folderStart=StrRChr(directoryName,'\\'); 00261 const char* folderStart2=StrRChr(directoryName,'/'); 00262 if (folderStart==0 || (folderStart2 && folderStart2>folderStart)) 00263 { 00264 folderStart=folderStart2; 00265 } 00266 if (folderStart>0) 00267 { 00268 folderStart++; 00269 } 00270 else 00271 { 00272 folderStart=directoryName; 00273 } 00274 int rootPathLength=(int)(folderStart-directoryName); 00275 00276 00277 // Add all the files to the archive (will recurse down all subdirectories) 00278 ProcessDirectory(rootPathLength,directory,&root_); 00279 00280 // Delete the directory object 00281 delete directory; 00282 } 00283 00284 00285 //*** ProcessDirectory *** 00286 00287 void ArchiveGenerator::ProcessDirectory(int rootPathLength, Platform_FileSystem_Directory* directory, DirectoryEntry* directoryEntry) 00288 { 00289 SetProgress(Phase_ScanningDirectory,directory->GetPath()); 00290 00291 // Store the name of the directory 00292 const char* path=directory->GetPath(); 00293 path+=rootPathLength; 00294 if (path==0) 00295 { 00296 path=""; 00297 } 00298 const char* name=StrRChr(path,'/'); 00299 if (!name) 00300 { 00301 name=path; 00302 } 00303 if (name[0]=='/') 00304 { 00305 name++; 00306 } 00307 MemSet(directoryEntry->name,0,260); 00308 StrNCpy(directoryEntry->name,name,Max(259,StrLen(name))); 00309 00310 // Loop through all the files of this directory 00311 for (int i=0; i<directory->GetFileCount(); i++) 00312 { 00313 // Generate the full path for this filename 00314 char filename[4096]; 00315 SNPrintF(filename,4096,"%s/%s",directory->GetPath(),directory->GetFile(i)); 00316 00317 SetProgress(Phase_AddingFile,filename); 00318 00319 // Create a file object for the file 00320 Platform_FileSystem_File* file=0; 00321 if (Platform::GetPlatform_FileSystem()) 00322 { 00323 file=Platform::GetPlatform_FileSystem()->CreateFileObject(filename); 00324 } 00325 00326 // Open the file 00327 int fileSize=0; 00328 unsigned char* data=0; 00329 bool result=file->Open(); 00330 Assert(result, "Couldn't open file"); 00331 if (result) 00332 { 00333 // Determine file size 00334 file->SetPosition(0,Platform_FileSystem_File::ORIGIN_END); 00335 fileSize=file->GetPosition(); 00336 file->SetPosition(0,Platform_FileSystem_File::ORIGIN_START); 00337 00338 // Allocate a buffer for the file data 00339 data=new unsigned char[fileSize]; 00340 00341 // Read the file data 00342 file->Read(data,fileSize); 00343 00344 // Close the file 00345 file->Close(); 00346 } 00347 delete file; 00348 00349 // Create a file entry for this file 00350 FileEntry fileEntry; 00351 00352 // Store filename 00353 MemSet(fileEntry.filename,0,260); 00354 StrNCpy(fileEntry.filename,directory->GetFile(i),Max(259,StrLen(directory->GetFile(i)))); 00355 00356 // Store the file offset and size 00357 fileEntry.offset=filedata_.GetSize(); 00358 fileEntry.size=fileSize; 00359 00360 directoryEntry->files.Add(fileEntry); 00361 00362 if (data) 00363 { 00364 // Write file data to the archive buffer 00365 filedata_.Write(data,fileSize); 00366 00367 // Delete the temporary buffer for file data 00368 delete data; 00369 } 00370 } 00371 00372 // Loop through each subdirectory 00373 for (int i=0; i<directory->GetSubdirectoryCount(); i++) 00374 { 00375 // Generate the full path for this directory 00376 char directoryName[4096]; 00377 SNPrintF(directoryName,4096,"%s/%s",directory->GetPath(),directory->GetSubdirectory(i)); 00378 00379 // Create a directory object for the subdirectory 00380 Platform_FileSystem_Directory* directory=0; 00381 if (Platform::GetPlatform_FileSystem()) 00382 { 00383 directory=Platform::GetPlatform_FileSystem()->CreateDirectoryObject(directoryName); 00384 } 00385 00386 // Create a new entry for this subdirectory 00387 directoryEntry->subDirectories.Add(DirectoryEntry()); 00388 DirectoryEntry* subDirectoryEntry=&directoryEntry->subDirectories.Get(directoryEntry->subDirectories.GetItemCount()-1); 00389 00390 // Process the subdirectory 00391 ProcessDirectory(rootPathLength, directory, subDirectoryEntry); 00392 00393 // Delete the directory object 00394 delete directory; 00395 } 00396 00397 } 00398 00399 00400 //*** SetProgress *** 00401 00402 void ArchiveGenerator::SetProgress(Phase phase, const char* text) 00403 { 00404 progressData_.phase=phase; 00405 StrNCpy(progressData_.text,text,1023); 00406 progressData_.text[1023]=0; 00407 if (progressCallback_) 00408 { 00409 progressCallback_(progressData_); 00410 } 00411 }
Reproduction/republishing of any material on this site without permission is strictly prohibited.
