Archive.cpp
Go to the documentation of this file.00001 //*** Archive.cpp *** 00002 00003 #include "Archive.h" 00004 #include "Debug.h" 00005 #include "StaticBuffer.h" 00006 #include "HashTableIterator.h" 00007 #include "Platform_FileSystem.h" 00008 #include "Platform_FileSystem_File.h" 00009 #include "ArchiveFile.h" 00010 #include "ArchiveDirectory.h" 00011 #include "StandardLibrary.h" 00012 #include "Asset.h" 00013 #include "Filename.h" 00014 00015 const char* Pixie_Archive_Header="PIXIE_ARCHIVE"; 00016 00017 00018 //*** Constructor *** 00019 00020 Archive::Archive(const void* memoryBuffer, int size): 00021 archiveBuffer_(0), 00022 archiveFile_(0) 00023 { 00024 // Create a new StaticBuffer mapped to the specified memory area 00025 archiveBuffer_=new StaticBuffer(memoryBuffer, size); 00026 00027 // Read header 00028 char header[256]; 00029 archiveBuffer_->Read(header,StrLen(Pixie_Archive_Header)); 00030 Assert(StrNICmp(header,Pixie_Archive_Header,StrLen(Pixie_Archive_Header))==0,"Invalid archive header"); 00031 if (StrNICmp(header,Pixie_Archive_Header,StrLen(Pixie_Archive_Header))!=0) 00032 { 00033 delete archiveBuffer_; 00034 archiveBuffer_=0; 00035 return; 00036 } 00037 00038 // Read version 00039 int version=0; 00040 archiveBuffer_->Read(&version); 00041 Assert(version==0,"Invalid archive version"); 00042 if (version!=0) 00043 { 00044 delete archiveBuffer_; 00045 archiveBuffer_=0; 00046 return; 00047 } 00048 00049 // Read directory list 00050 ReadDirectory(&root_,0); 00051 00052 } 00053 00054 00055 //*** Constructor *** 00056 00057 Archive::Archive(const Filename& filename): 00058 archiveBuffer_(0), 00059 archiveFile_(0) 00060 { 00061 // Create the file object for the specified archive file 00062 archiveFile_=0; 00063 if (Platform::GetPlatform_FileSystem()) 00064 { 00065 archiveFile_=Platform::GetPlatform_FileSystem()->CreateFileObject(filename.GetString()); 00066 } 00067 00068 if (!archiveFile_) 00069 { 00070 Assert(false,"No file system present"); 00071 delete archiveFile_; 00072 archiveFile_=0; 00073 return; 00074 } 00075 00076 // Open the file 00077 if (!archiveFile_->Open()) 00078 { 00079 Assert(false,"Couldn't open archive file"); 00080 delete archiveFile_; 00081 archiveFile_=0; 00082 return; 00083 } 00084 00085 // Read header 00086 char header[256]; 00087 archiveFile_->Read(header,StrLen(Pixie_Archive_Header)); 00088 Assert(StrNICmp(header,Pixie_Archive_Header,StrLen(Pixie_Archive_Header))==0,"Invalid archive header"); 00089 if (StrNICmp(header,Pixie_Archive_Header,StrLen(Pixie_Archive_Header))!=0) 00090 { 00091 delete archiveFile_; 00092 archiveFile_=0; 00093 return; 00094 } 00095 00096 // Read version 00097 int version=0; 00098 archiveFile_->Read(&version); 00099 Assert(version==0,"Invalid archive version"); 00100 if (version!=0) 00101 { 00102 delete archiveFile_; 00103 archiveFile_=0; 00104 return; 00105 } 00106 00107 // Read directory list 00108 ReadDirectory(&root_,0); 00109 } 00110 00111 00112 //*** Destructor *** 00113 00114 Archive::~Archive() 00115 { 00116 // Delete the static buffer 00117 if (archiveBuffer_) 00118 { 00119 delete archiveBuffer_; 00120 } 00121 00122 // Delete archive file 00123 if (archiveFile_) 00124 { 00125 archiveFile_->Close(); 00126 delete archiveFile_; 00127 } 00128 00129 // Loop through the hash table of directories and delete all 00130 HashTableIterator<HashTableKey_StringId,ArchiveDirectory*> it(directories_); 00131 while (it.IsValid()) 00132 { 00133 ArchiveDirectory* dirEntry=it.GetCurrent(); 00134 delete dirEntry; 00135 it.MoveNext(); 00136 } 00137 } 00138 00139 00140 //*** GetRootDirectory *** 00141 00142 const ArchiveDirectory* Archive::GetRootDirectory() const 00143 { 00144 if (files_.GetItemCount()==0 && directories_.GetItemCount()==0) 00145 { 00146 return 0; 00147 } 00148 return GetDirectory(root_.name); 00149 } 00150 00151 00152 //*** GetDirectory *** 00153 00154 const ArchiveDirectory* Archive::GetDirectory(const Filename& path) const 00155 { 00156 // Try and find a directory with the specified path in the hash table 00157 HashTableIterator<HashTableKey_StringId,ArchiveDirectory*> it(directories_); 00158 if (it.Find(HashTableKey_StringId(path.GetStringId()))) 00159 { 00160 ArchiveDirectory* entry=it.GetCurrent(); 00161 return entry; 00162 } 00163 00164 return 0; 00165 } 00166 00167 00168 //*** GetFile *** 00169 00170 ArchiveFile* Archive::GetFile(const Filename& filename) const 00171 { 00172 // Try and find a file with the specified filename in the hash table 00173 HashTableIterator<HashTableKey_StringId,FileEntry> it(files_); 00174 if (it.Find(HashTableKey_StringId(filename.GetStringId()))) 00175 { 00176 const FileEntry& entry=it.GetCurrent(); 00177 00178 if (archiveFile_) 00179 { 00180 return new ArchiveFile(archiveFile_,entry.offset,entry.size,true); 00181 } 00182 00183 if (archiveBuffer_) 00184 { 00185 return new ArchiveFile(archiveBuffer_,entry.offset,entry.size); 00186 } 00187 } 00188 00189 return 0; 00190 } 00191 00192 00193 //*** ReadDirectory *** 00194 00195 void Archive::ReadDirectory(DirectoryEntry* directoryEntry, char* parentPath) 00196 { 00197 // Read name length 00198 int nameLength=0; 00199 if (archiveFile_) 00200 { 00201 archiveFile_->Read(&nameLength); 00202 } 00203 else 00204 { 00205 archiveBuffer_->Read(&nameLength); 00206 } 00207 00208 // Read name 00209 char* dirname=new char[nameLength+1]; 00210 if (archiveFile_) 00211 { 00212 archiveFile_->Read(dirname,nameLength); 00213 } 00214 else 00215 { 00216 archiveBuffer_->Read(dirname,nameLength); 00217 } 00218 dirname[nameLength]=0; 00219 directoryEntry->name=StringId(dirname); 00220 delete[] dirname; 00221 00222 // Generate full path for this directory 00223 int pathlength=nameLength+1; 00224 if (parentPath) 00225 { 00226 pathlength+=StrLen(parentPath)+1; 00227 } 00228 char* fullpath=new char[pathlength]; 00229 if (parentPath) 00230 { 00231 SNPrintF(fullpath,pathlength,"%s/%s",parentPath,directoryEntry->name.GetString()); 00232 } 00233 else 00234 { 00235 SNPrintF(fullpath,pathlength,"%s",directoryEntry->name.GetString()); 00236 } 00237 00238 ArchiveDirectory* archiveDirectory=new ArchiveDirectory(); 00239 directories_.Insert(HashTableKey_StringId(fullpath),archiveDirectory); 00240 archiveDirectory->SetPath(fullpath); 00241 00242 // Read file count 00243 int fileCount=0; 00244 if (archiveFile_) 00245 { 00246 archiveFile_->Read(&fileCount); 00247 } 00248 else 00249 { 00250 archiveBuffer_->Read(&fileCount); 00251 } 00252 00253 // Read files 00254 for (int i=0; i<fileCount; i++) 00255 { 00256 FileEntry fileEntry; 00257 00258 // Read name length 00259 int nameLength=0; 00260 if (archiveFile_) 00261 { 00262 archiveFile_->Read(&nameLength); 00263 } 00264 else 00265 { 00266 archiveBuffer_->Read(&nameLength); 00267 } 00268 00269 // Read name 00270 char* filename=new char[nameLength+1]; 00271 if (archiveFile_) 00272 { 00273 archiveFile_->Read(filename,nameLength); 00274 } 00275 else 00276 { 00277 archiveBuffer_->Read(filename,nameLength); 00278 } 00279 filename[nameLength]=0; 00280 fileEntry.filename=StringId(filename); 00281 delete[] filename; 00282 00283 // Read offset 00284 if (archiveFile_) 00285 { 00286 archiveFile_->Read(&fileEntry.offset); 00287 archiveFile_->Read(&fileEntry.size); 00288 } 00289 else 00290 { 00291 archiveBuffer_->Read(&fileEntry.offset); 00292 archiveBuffer_->Read(&fileEntry.size); 00293 } 00294 00295 // Add file to directory entry 00296 directoryEntry->files.Add(fileEntry); 00297 00298 // Add file to hashtable for quicker lookup 00299 int fullfilepathlength=StrLen(fullpath)+1+nameLength+1; 00300 char* fullfilepath=new char[fullfilepathlength]; 00301 SNPrintF(fullfilepath,fullfilepathlength,"%s/%s",fullpath,fileEntry.filename.GetString()); 00302 FileEntry entry(directoryEntry->files.Get(directoryEntry->files.GetItemCount()-1)); 00303 files_.Insert(HashTableKey_StringId(fullfilepath),entry); 00304 archiveDirectory->AddFile(fullfilepath); 00305 delete[] fullfilepath; 00306 } 00307 00308 00309 // Read subdirectory count 00310 int subdirectoryCount=0; 00311 if (archiveFile_) 00312 { 00313 archiveFile_->Read(&subdirectoryCount); 00314 } 00315 else 00316 { 00317 archiveBuffer_->Read(&subdirectoryCount); 00318 } 00319 00320 // Read subdirectories 00321 for (int i=0; i<subdirectoryCount; i++) 00322 { 00323 directoryEntry->subDirectories.Add(DirectoryEntry()); 00324 DirectoryEntry* subdirectoryEntry=&directoryEntry->subDirectories.Get(directoryEntry->subDirectories.GetItemCount()-1); 00325 ReadDirectory(subdirectoryEntry,fullpath); 00326 00327 int fulldirpathlength=StrLen(fullpath)+1+StrLen(subdirectoryEntry->name.GetString())+1; 00328 char* fulldirpath=new char[fulldirpathlength]; 00329 SNPrintF(fulldirpath,fulldirpathlength,"%s/%s",fullpath,subdirectoryEntry->name.GetString()); 00330 archiveDirectory->AddSubdirectory(fulldirpath); 00331 delete[] fulldirpath; 00332 } 00333 00334 delete[] fullpath; 00335 }
Reproduction/republishing of any material on this site without permission is strictly prohibited.
