ArchiveManager.cpp
Go to the documentation of this file.00001 //*** ArchiveManager.cpp *** 00002 00003 #include "ArchiveManager.h" 00004 #include "Debug.h" 00005 #include "HashTableIterator.h" 00006 #include "ArchiveDirectory.h" 00007 #include "ArchiveFile.h" 00008 #include "Platform_FileSystem.h" 00009 #include "Platform_FileSystem_Directory.h" 00010 #include "Platform_FileSystem_File.h" 00011 #include "StandardLibrary.h" 00012 #include "Archive.h" 00013 #include "StringId.h" 00014 #include "Asset.h" 00015 #include "Filename.h" 00016 00017 //*** Constructor *** 00018 00019 ArchiveManager::ArchiveManager() 00020 { 00021 RescanHardDrive(); 00022 } 00023 00024 00025 //*** Destructor *** 00026 00027 ArchiveManager::~ArchiveManager() 00028 { 00029 UnloadAllArchives(); 00030 } 00031 00032 00033 //*** LoadArchive *** 00034 00035 void ArchiveManager::LoadArchive(const Filename& filename) 00036 { 00037 // Cache is no longer valid after we add a new archive 00038 ClearDirectoryCache(); 00039 00040 // Create new archive entry for the archive 00041 ArchiveEntry entry; 00042 entry.archive=new Archive(filename); 00043 entry.filename=filename.GetStringId(); 00044 entry.memoryBuffer=0; 00045 const ArchiveDirectory* rootDirectory=entry.archive->GetRootDirectory(); 00046 if (rootDirectory) 00047 { 00048 entry.rootDirectory=GetRootDirectory(rootDirectory->GetPath().GetString()); 00049 } 00050 00051 // Add entry to list of archives 00052 archives_.Add(entry); 00053 } 00054 00055 00056 //*** LoadArchive *** 00057 00058 void ArchiveManager::LoadArchive(const void* memoryBuffer, int size) 00059 { 00060 // Cache is no longer valid after we add a new archive 00061 ClearDirectoryCache(); 00062 00063 // Create new archive entry for the archive 00064 ArchiveEntry entry; 00065 entry.archive=new Archive(memoryBuffer,size); 00066 entry.filename=StringId(); 00067 entry.memoryBuffer=memoryBuffer; 00068 entry.rootDirectory=GetRootDirectory(entry.archive->GetRootDirectory()->GetPath().GetString()); 00069 00070 // Add entry to list of archives 00071 archives_.Add(entry); 00072 } 00073 00074 00075 //*** UnloadArchive *** 00076 00077 void ArchiveManager::UnloadArchive(const Filename& filename) 00078 { 00079 // Cache is no longer valid after we remove an archive 00080 ClearDirectoryCache(); 00081 00082 // Remove the specified archive 00083 for (int i=0; i<archives_.GetItemCount(); i++) 00084 { 00085 ArchiveEntry& entry=archives_.Get(i); 00086 if (entry.filename==filename.GetStringId()) 00087 { 00088 delete entry.archive; 00089 archives_.Remove(i); 00090 return; 00091 } 00092 } 00093 00094 Assert(false,"Archive could not be found"); 00095 } 00096 00097 00098 //*** UnloadArchive *** 00099 00100 void ArchiveManager::UnloadArchive(const void* memoryBuffer) 00101 { 00102 // Cache is no longer valid after we remove an archive 00103 ClearDirectoryCache(); 00104 00105 // Remove the specified archive 00106 for (int i=0; i<archives_.GetItemCount(); i++) 00107 { 00108 ArchiveEntry& entry=archives_.Get(i); 00109 if (entry.memoryBuffer==memoryBuffer) 00110 { 00111 delete entry.archive; 00112 archives_.Remove(i); 00113 return; 00114 } 00115 } 00116 00117 Assert(false,"Archive could not be found"); 00118 } 00119 00120 00121 //*** UnloadAllArchives *** 00122 00123 void ArchiveManager::UnloadAllArchives() 00124 { 00125 // Cache is no longer valid after we remove archives 00126 ClearDirectoryCache(); 00127 00128 for (int i=0; i<archives_.GetItemCount(); i++) 00129 { 00130 ArchiveEntry& entry=archives_.Get(i); 00131 delete entry.archive; 00132 } 00133 archives_.Clear(false); 00134 } 00135 00136 00137 //*** RescanHardDrive *** 00138 00139 void ArchiveManager::RescanHardDrive() 00140 { 00141 // Cache is no longer valid after a rescan 00142 ClearDirectoryCache(); 00143 00144 // Reset list of root directories 00145 rootDirectories_.Clear(false); 00146 00147 // We can only scan the harddrive if we have a valid file system 00148 if (Platform::GetPlatform_FileSystem()) 00149 { 00150 // Create a directory object for the current path 00151 Platform_FileSystem_Directory* directory=Platform::GetPlatform_FileSystem()->CreateDirectoryObject("."); 00152 if (directory->Exists()) 00153 { 00154 // Add all subdirectories found in the current path 00155 for (int i=0; i<directory->GetSubdirectoryCount(); i++) 00156 { 00157 rootDirectories_.Add(directory->GetSubdirectory(i)); 00158 } 00159 } 00160 delete directory; 00161 } 00162 } 00163 00164 00165 //*** GetFile *** 00166 00167 ArchiveFile* ArchiveManager::GetFile(const Filename& filename) const 00168 { 00169 // Check if there's a root directory on the harddrive which might override archives 00170 bool rootDirectoryExists=false; 00171 if (rootDirectories_.GetItemCount()>0) 00172 { 00173 StringId rootDirectory=GetRootDirectory(filename.GetString()); 00174 rootDirectoryExists=RootDirectoryExists(rootDirectory); 00175 } 00176 if (rootDirectoryExists && Platform::GetPlatform_FileSystem()) 00177 { 00178 // Check if the file exists 00179 Platform_FileSystem_File* file=Platform::GetPlatform_FileSystem()->CreateFileObject(filename.GetString()); 00180 if (file->Exists()) 00181 { 00182 // Get the file size 00183 int size=0; 00184 if (file->Open()) 00185 { 00186 file->SetPosition(0,Platform_FileSystem_File::ORIGIN_END); 00187 size=file->GetPosition(); 00188 00189 // Return a new ArchiveFile representing this file 00190 return new ArchiveFile(file,0,size,false); 00191 } 00192 } 00193 00194 delete file; 00195 } 00196 00197 // Check each matching archive, in reverse order they where added (get file from most recent added archive first) 00198 for (int i=archives_.GetItemCount()-1; i>=0; i--) 00199 { 00200 const ArchiveEntry& entry=archives_.Get(i); 00201 ArchiveFile* file=entry.archive->GetFile(filename); 00202 if (file) 00203 { 00204 return file; 00205 } 00206 } 00207 00208 return 0; 00209 } 00210 00211 00212 //*** GetDirectory *** 00213 00214 const ArchiveDirectory* ArchiveManager::GetDirectory(const Filename& path) const 00215 { 00216 // Check if the directory is already in the directory cache (have been accessed before) 00217 HashTableIterator<HashTableKey_StringId,ArchiveDirectory*> it(directoryCache_); 00218 if (it.Find(path.GetStringId())) 00219 { 00220 // If so, return it 00221 return it.GetCurrent(); 00222 } 00223 00224 // Directory doesn't exist in the cache, so create it and store it in the cache 00225 ArchiveDirectory* archiveDirectory=new ArchiveDirectory(); 00226 archiveDirectory->path_=path.GetStringId(); 00227 directoryCache_.Insert(HashTableKey_StringId(path.GetStringId()),archiveDirectory); 00228 00229 // The current path is handled differently (by just adding the root directories from HD and all archives) 00230 static StringId currentPath("."); 00231 if (path==currentPath) 00232 { 00233 // We can only scan the harddrive if we have a valid file system 00234 if (Platform::GetPlatform_FileSystem()) 00235 { 00236 // Create a directory object for the current path 00237 Platform_FileSystem_Directory* directory=Platform::GetPlatform_FileSystem()->CreateDirectoryObject("."); 00238 if (directory->Exists()) 00239 { 00240 // Add all subdirectories found in the current path 00241 for (int i=0; i<directory->GetSubdirectoryCount(); i++) 00242 { 00243 archiveDirectory->subdirectories_.Add(directory->GetSubdirectory(i)); 00244 } 00245 for (int i=0; i<directory->GetFileCount(); i++) 00246 { 00247 archiveDirectory->files_.Add(directory->GetFile(i)); 00248 } 00249 } 00250 delete directory; 00251 } 00252 00253 // Add contents from each matching archive 00254 for (int i=0; i<archives_.GetItemCount(); i++) 00255 { 00256 const ArchiveEntry& entry=archives_.Get(i); 00257 const ArchiveDirectory* directory=entry.archive->GetRootDirectory(); 00258 StringId directoryName=directory->GetPath(); 00259 // Only add it if it doesn't already exist (it might have been added by previous archive or HD) 00260 bool exists=false; 00261 for (int j=0; j<archiveDirectory->GetSubdirectoryCount(); j++) 00262 { 00263 if (archiveDirectory->GetSubdirectory(j)==directoryName) 00264 { 00265 exists=true; 00266 break; 00267 } 00268 } 00269 if (!exists) 00270 { 00271 archiveDirectory->subdirectories_.Add(directoryName); 00272 } 00273 } 00274 00275 // Return the new archiveDirectory object 00276 return archiveDirectory; 00277 } 00278 00279 // Check if there's a root directory on the harddrive which might override archives 00280 StringId rootDirectory=GetRootDirectory(path.GetString()); 00281 if (RootDirectoryExists(rootDirectory) && Platform::GetPlatform_FileSystem()) 00282 { 00283 // Check if the actual subdirectory exists too 00284 Platform_FileSystem_Directory* directory=Platform::GetPlatform_FileSystem()->CreateDirectoryObject(path.GetString()); 00285 if (directory->Exists()) 00286 { 00287 // Add the contents of the directory to the archivedirectory 00288 for (int i=0; i<directory->GetSubdirectoryCount(); i++) 00289 { 00290 // Generate the full path for this directory 00291 char directoryName[4096]; 00292 SNPrintF(directoryName,4096,"%s/%s",directory->GetPath(),directory->GetSubdirectory(i)); 00293 00294 archiveDirectory->AddSubdirectory(directoryName); 00295 } 00296 for (int i=0; i<directory->GetFileCount(); i++) 00297 { 00298 // Generate the full path for this file 00299 char filename[4096]; 00300 SNPrintF(filename,4096,"%s/%s",directory->GetPath(),directory->GetFile(i)); 00301 00302 archiveDirectory->AddFile(filename); 00303 } 00304 } 00305 delete directory; 00306 } 00307 00308 // Add contents from each matching archive 00309 for (int i=0; i<archives_.GetItemCount(); i++) 00310 { 00311 const ArchiveEntry& entry=archives_.Get(i); 00312 if (rootDirectory==entry.rootDirectory) 00313 { 00314 const ArchiveDirectory* directory=entry.archive->GetDirectory(path); 00315 if (directory) 00316 { 00317 // Add subdirectories 00318 for (int i=0; i<directory->GetSubdirectoryCount(); i++) 00319 { 00320 StringId subdirectoryName=directory->GetSubdirectory(i); 00321 // Only add it if it doesn't already exist (it might have been added by previous archive or HD) 00322 bool exists=false; 00323 for (int j=0; j<archiveDirectory->GetSubdirectoryCount(); j++) 00324 { 00325 if (archiveDirectory->GetSubdirectory(j)==subdirectoryName) 00326 { 00327 exists=true; 00328 break; 00329 } 00330 } 00331 if (!exists) 00332 { 00333 archiveDirectory->subdirectories_.Add(subdirectoryName); 00334 } 00335 } 00336 00337 // Add files 00338 for (int i=0; i<directory->GetFileCount(); i++) 00339 { 00340 StringId filename=directory->GetFile(i); 00341 // Only add it if it doesn't already exist (it might have been added by previous archive or HD pass) 00342 bool exists=false; 00343 for (int j=0; j<archiveDirectory->GetFileCount(); j++) 00344 { 00345 if (archiveDirectory->GetFile(j)==filename) 00346 { 00347 exists=true; 00348 break; 00349 } 00350 } 00351 if (!exists) 00352 { 00353 archiveDirectory->files_.Add(filename); 00354 } 00355 } 00356 } 00357 } 00358 } 00359 00360 // Return the new archiveDirectory object 00361 return archiveDirectory; 00362 } 00363 00364 00365 //*** GetRootDirectory *** 00366 00367 StringId ArchiveManager::GetRootDirectory(const char* path) const 00368 { 00369 char* tempPath=StrDup(path); 00370 const char* separator=StrChr(tempPath,'/'); 00371 const char* otherSeparator=StrChr(tempPath,'\\'); 00372 if (!separator || (otherSeparator && otherSeparator<separator)) 00373 { 00374 separator=otherSeparator; 00375 } 00376 00377 if (!separator) 00378 { 00379 Free(tempPath); 00380 return StringId(path); 00381 } 00382 00383 *(const_cast<char*>(separator))='\0'; 00384 00385 StringId returnValue=StringId(tempPath); 00386 Free(tempPath); 00387 return returnValue; 00388 } 00389 00390 00391 //*** RootDirectoryExists *** 00392 00393 bool ArchiveManager::RootDirectoryExists(StringId directoryName) const 00394 { 00395 for (int i=0; i<rootDirectories_.GetItemCount(); i++) 00396 { 00397 if (rootDirectories_.Get(i)==directoryName) 00398 { 00399 return true; 00400 } 00401 } 00402 00403 return false; 00404 } 00405 00406 00407 //*** ClearDirectoryCache *** 00408 00409 void ArchiveManager::ClearDirectoryCache() 00410 { 00411 HashTableIterator<HashTableKey_StringId,ArchiveDirectory*> it(directoryCache_); 00412 while (it.IsValid()) 00413 { 00414 delete it.GetCurrent(); 00415 it.MoveNext(); 00416 } 00417 00418 directoryCache_.Clear(false); 00419 }
Reproduction/republishing of any material on this site without permission is strictly prohibited.
