1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306 |
- //-----------------------------------------------------------------------------
- // Copyright (c) 2013 GarageGames, LLC
- //
- // Permission is hereby granted, free of charge, to any person obtaining a copy
- // of this software and associated documentation files (the "Software"), to
- // deal in the Software without restriction, including without limitation the
- // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
- // sell copies of the Software, and to permit persons to whom the Software is
- // furnished to do so, subject to the following conditions:
- //
- // The above copyright notice and this permission notice shall be included in
- // all copies or substantial portions of the Software.
- //
- // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
- // IN THE SOFTWARE.
- //-----------------------------------------------------------------------------
- #include "platform/platform.h"
- #include "console/console.h"
- #include "collection/vector.h"
- #include "io/stream.h"
- #include "io/fileStream.h"
- #include "io/resizeStream.h"
- #include "memory/frameAllocator.h"
- #include "io/zip/zipArchive.h"
- #include "io/resource/resourceManager.h"
- #include "string/findMatch.h"
- #include "console/console.h"
- #include "console/consoleTypes.h"
- #include "memory/safeDelete.h"
- #include "resourceManager_ScriptBinding.h"
- ResManager *ResourceManager = NULL;
- const char *ResManager::smExcludedDirectories = ".svn;CVS";
- //------------------------------------------------------------------------------
- ResourceObject::ResourceObject ()
- {
- next = NULL;
- prev = NULL;
- lockCount = 0;
- mInstance = NULL;
- mZipArchive = NULL;
- mCentralDir = NULL;
- }
- void ResourceObject::destruct ()
- {
- // If the resource was not loaded because of an error, the resource
- // pointer will be NULL
- SAFE_DELETE(mInstance);
- // Free if it is ResourceObject::File and is NOT ResourceObject::VolumeBlock
- if((flags & ResourceObject::File) && !(flags & ResourceObject::VolumeBlock) )
- {
- // [tom, 10/26/2006] We don't want to delete if it's a volume block since
- // the archive will be freed when the zip file resource object is freed.
- SAFE_DELETE(mZipArchive);
- }
- }
- //------------------------------------------------------------------------------
- //------------------------------------------------------------------------------
- ResManager::ResManager ()
- {
- echoFileNames = false;
- primaryPath[0] = 0;
- writeablePath[0] = 0;
- pathList = NULL;
- resourceList.nextResource = NULL;
- resourceList.next = NULL;
- resourceList.prev = NULL;
- timeoutList.nextResource = NULL;
- timeoutList.next = NULL;
- timeoutList.prev = NULL;
- registeredList = NULL;
- mLoggingMissingFiles = false;
- usingVFS = false;
- }
- void ResManager::fileIsMissing(const char *fileName)
- {
- if(mLoggingMissingFiles)
- {
- char *name = dStrdup(fileName);
- mMissingFileList.push_back(name);
- }
- }
- void ResManager::setMissingFileLogging(bool logging)
- {
- mLoggingMissingFiles = logging;
- if(!mLoggingMissingFiles)
- clearMissingFileList();
- }
- void ResManager::clearMissingFileList()
- {
- while(mMissingFileList.size())
- {
- dFree(mMissingFileList[0]);
- mMissingFileList.pop_front();
- }
- mMissingFileList.clear();
- }
- bool ResManager::getMissingFileList(Vector<char *> &list)
- {
- if(!mMissingFileList.size())
- return false;
- for(U32 i = 0; i < (U32)mMissingFileList.size();i ++)
- {
- for(U32 j = 0; j < (U32)list.size(); j++)
- {
- if(!dStrcmp(list[j], mMissingFileList[i]))
- {
- dFree(mMissingFileList[i]);
- mMissingFileList[i] = NULL;
- break;
- }
- }
- if(mMissingFileList[i])
- list.push_back(mMissingFileList[i]);
- }
- mMissingFileList.clear();
- return true;
- }
- void ResourceObject::getFileTimes (FileTime * createTime, FileTime * modifyTime)
- {
- if( !path || !name )
- {
- createTime = modifyTime = NULL;
- return;
- }
-
- char buffer[1024];
- Platform::makeFullPathName(path, buffer, sizeof(buffer));
- U32 len = dStrlen(buffer);
- dSprintf (buffer + len, sizeof (buffer) - len, "/%s", name);
-
- Platform::getFileTimes (buffer, createTime, modifyTime);
- }
- //------------------------------------------------------------------------------
- ResManager::~ResManager ()
- {
- purge ();
- // volume list should be gone.
- if (pathList)
- dFree (pathList);
- for (ResourceObject * walk = resourceList.nextResource; walk;
- walk = walk->nextResource)
- walk->destruct ();
- while (resourceList.nextResource)
- freeResource (resourceList.nextResource);
- while (registeredList)
- {
- RegisteredExtension *temp = registeredList->next;
- delete registeredList;
- registeredList = temp;
- }
- }
- #ifdef TORQUE_DEBUG
- void ResManager::dumpResources (const bool onlyLoaded)
- {
- ResourceObject *walk = resourceList.nextResource;
- while (walk != NULL)
- {
- if ( !onlyLoaded || walk->mInstance != NULL)
- {
- Con::errorf ("Resource: %s/%s (%d)", walk->path, walk->name,
- walk->lockCount);
- }
- walk = walk->nextResource;
- }
- }
- #endif
- //------------------------------------------------------------------------------
- void ResManager::create ()
- {
- AssertFatal (ResourceManager == NULL,
- "ResourceManager::create: manager already exists.");
- ResourceManager = new ResManager;
- Con::addVariable("Pref::ResourceManager::excludedDirectories", TypeString, &smExcludedDirectories);
- }
- //------------------------------------------------------------------------------
- void ResManager::destroy ()
- {
- AssertFatal (ResourceManager != NULL,
- "ResourceManager::destroy: manager does not exist.");
- delete ResourceManager;
- ResourceManager = NULL;
- }
- //------------------------------------------------------------------------------
- void ResManager::setFileNameEcho (bool on)
- {
- echoFileNames = on;
- }
- //------------------------------------------------------------------------------
- bool ResManager::isValidWriteFileName (const char *fn)
- {
- if(isUsingVFS())
- return false;
- return true;
- if (!writeablePath[0])
- return true;
- // get the path to the file
- const char * path = dStrrchr (fn, '/');
- if (!path)
- path = fn;
- else
- {
- if (!dStrchr (path, '.'))
- return false;
- }
- // now loop through the writeable path.
- const char * start = writeablePath;
- for (;;)
- {
- const char * end = dStrchr (writeablePath, ';');
- if (!end)
- end = writeablePath + dStrlen (writeablePath);
- //if (end - start == pathLen && !dStrnicmp (start, path, pathLen))
- if(dStrnicmp(start, fn, end - start) == 0)
- return true;
- if (end[0])
- start = end + 1;
- else
- break;
- }
- // now check prefs folder
- const char * prefsPath = Platform::getPrefsPath();
- if (dStrnicmp(prefsPath, fn, dStrlen(prefsPath)) == 0)
- return true;
- // now check user data folder
- const char * dataPath = Platform::getUserDataDirectory();
- if (dStrnicmp(dataPath, fn, dStrlen(dataPath)) == 0)
- return true;
- return false;
- }
- void ResManager::setWriteablePath (const char *path)
- {
- dStrcpy (writeablePath, path);
- }
- //------------------------------------------------------------------------------
- static const char * buildPath (StringTableEntry path, StringTableEntry file)
- {
- static char buf[1024];
- if (path)
- Platform::makeFullPathName(file, buf, sizeof(buf), path);
- else
- dStrcpy (buf, file);
- return buf;
- }
- //------------------------------------------------------------------------------
- static void getPaths (const char *fullPath, StringTableEntry & path,
- StringTableEntry & fileName)
- {
- static char buf[1024];
- char *ptr = (char *) dStrrchr (fullPath, '/');
- if (!ptr)
- {
- path = NULL;
- fileName = StringTable->insert (fullPath);
- }
- else
- {
- S32 len = (S32)(ptr - fullPath);
- dStrncpy (buf, fullPath, len);
- buf[len] = 0;
- fileName = StringTable->insert (ptr + 1);
- path = StringTable->insert (buf);
- }
- }
- //------------------------------------------------------------------------------
- bool ResManager::addVFSRoot(Zip::ZipArchive *vfs)
- {
- ResourceObject *ro = createResource (StringTable->EmptyString, StringTable->EmptyString);
- dictionary.pushBehind (ro, ResourceObject::File);
- // [tom, 10/28/2006] Using VolumeBlock here so that destruct() doesnt try and
- // delete the archive.
- ro->flags = ResourceObject::VolumeBlock;
- ro->fileOffset = 0;
- ro->fileSize = 0;
- ro->compressedFileSize = 0;
- ro->mZipArchive = vfs;
- ro->zipPath = StringTable->EmptyString;
- ro->zipName = StringTable->EmptyString;
- usingVFS = true;
- return scanZip(ro);
- }
- bool ResManager::scanZip (ResourceObject * zipObject)
- {
- const char *zipPath = buildPath(zipObject->zipPath, zipObject->zipName);
- if(zipObject->mZipArchive == NULL)
- {
- zipObject->mZipArchive = new Zip::ZipArchive;
- if(! zipObject->mZipArchive->openArchive(zipPath))
- {
- SAFE_DELETE(zipObject->mZipArchive);
- return false;
- }
- }
- for(U32 i = 0;i < zipObject->mZipArchive->numEntries();++i)
- {
- const Zip::CentralDir &dir = (*zipObject->mZipArchive)[i];
- // FIXME [tom, 10/26/2006] This is pretty lame
- char buf[1024];
- dStrncpy(buf, dir.mFilename, sizeof(buf));
- buf[sizeof(buf)-1] = 0;
- // Iterate through the string and change any
- // characters with \\ to /
- char* scan = buf;
- while (*scan != '\0')
- {
- if (*scan == '\\')
- *scan = '/';
- scan++;
- }
- const char *zipFN = zipObject->mZipArchive->getFilename() ? zipObject->mZipArchive->getFilename() : "";
- FrameTemp<char> zipPath(dStrlen(zipFN) + dStrlen(buf) + 2);
- dStrcpy(zipPath, zipFN);
- char* dot = dStrrchr(zipPath, '.');
- if(dot)
- {
- dot -= 2;
- dot[2] = '\0';
- dStrcat(zipPath, "/");
- }
- dStrcat(zipPath, buf);
- // Create file base name
- char* pPathEnd = dStrrchr(zipPath, '/');
- if(pPathEnd == NULL)
- continue;
- pPathEnd[0] = '\0';
- const char * path = StringTable->insert(zipPath);
- const char * file = StringTable->insert(pPathEnd + 1);
-
- ResourceObject *ro = createZipResource(path, file, zipObject->zipPath, zipObject->zipName);
- ro->flags = ResourceObject::VolumeBlock;
- ro->fileSize = dir.mUncompressedSize;
- ro->compressedFileSize = dir.mCompressedSize;
- ro->fileOffset = dir.mLocalHeadOffset;
- ro->mZipArchive = zipObject->mZipArchive;
- ro->mCentralDir = &dir;
- dictionary.pushBehind (ro, ResourceObject::File);
- }
- return true;
- }
- //------------------------------------------------------------------------------
- void ResManager::searchPath (const char *path, bool noDups /* = false */, bool ignoreZips /* = false */ )
- {
- AssertFatal (path != NULL, "No path to dump?");
- // Set up exclusions.
- initExcludedDirectories();
- Vector < Platform::FileInfo > fileInfoVec;
- Platform::dumpPath (path, fileInfoVec);
- for (U32 i = 0; i < (U32)fileInfoVec.size (); i++)
- {
- Platform::FileInfo & rInfo = fileInfoVec[i];
- // Create a resource for this file...
- //
- if(noDups && dictionary.find(rInfo.pFullPath, rInfo.pFileName) != NULL)
- continue;
- ResourceObject *ro = createResource (rInfo.pFullPath, rInfo.pFileName);
- dictionary.pushBehind (ro, ResourceObject::File);
- //Con::printf("> ResourceManager: Found file '%s' in path '%s'.", rInfo.pFileName, rInfo.pFullPath );
- ro->flags = ResourceObject::File;
- ro->fileOffset = 0;
- ro->fileSize = rInfo.fileSize;
- ro->compressedFileSize = rInfo.fileSize;
- // see if it's a zip
- const char *extension = dStrrchr (ro->name, '.');
- if (extension && !dStricmp (extension, ".zip") && !ignoreZips )
- {
- // Copy the path and files names to the zips resource object
- ro->zipName = rInfo.pFileName;
- ro->zipPath = rInfo.pFullPath;
- scanZip(ro);
- }
- }
- // Clear Exclusion list
- Platform::clearExcludedDirectories();
- }
- //------------------------------------------------------------------------------
- bool ResManager::setModZip(const char* path)
- {
- // Get the path and add .zip to the end of the dir
- const char* ext = ".zip";
- char* modPath = new char[dStrlen(path) + dStrlen(ext) + 1]; // make enough room.
- dStrcpy(modPath, path);
- dStrcat(modPath, ext);
- // Now we have to go through the root and look for our zipped up mod
- // this is unfortunately necessary because there is no means to get
- // a individual files properties -- we can only do it in one
- // big dump
- const char *basePath = Platform::getCurrentDirectory();
- Vector < Platform::FileInfo > pathInfo;
- Platform::dumpPath (basePath, pathInfo);
- for(U32 i = 0; i < (U32)pathInfo.size(); i++)
- {
- Platform::FileInfo &file = pathInfo[i];
- if(!dStricmp(file.pFileName, modPath))
- {
- // Setup the resource to the zip file itself
- ResourceObject *zip = createResource(basePath, file.pFileName);
- dictionary.pushBehind(zip, ResourceObject::File);
- zip->flags = ResourceObject::File;
- zip->fileOffset = 0;
- zip->fileSize = file.fileSize;
- zip->compressedFileSize = file.fileSize;
- zip->zipName = file.pFileName;
- zip->zipPath = basePath;
- // Setup the resource for the zip contents
- // ..now open the volume and add all its resources to the dictionary
- scanZip(zip);
- // Break from the loop since we got our one file
- delete [] modPath;
- return true;
- }
- }
- delete [] modPath;
- return false;
- }
- //------------------------------------------------------------------------------
- void ResManager::initExcludedDirectories()
- {
- // Set up our excluded directories.
- Platform::clearExcludedDirectories();
- // ignored is a semi-colon delimited list of names.
- char *working = dStrdup(smExcludedDirectories);
- char* temp = dStrtok( working, ";" );
- while ( temp )
- {
- Platform::addExcludedDirectory(temp);
- temp = dStrtok( NULL, ";" );
- }
- dFree(working);
- }
- void ResManager::addPath(const char *path, bool ignoreZips )
- {
- searchPath(path, true, ignoreZips );
- }
- void ResManager::removePath(const char *path)
- {
- ResourceObject *rwalk = resourceList.nextResource, *rtemp;
- while (rwalk != NULL)
- {
- const char *fname = buildPath(rwalk->path, rwalk->name);
- if(!rwalk->mInstance && FindMatch::isMatch(path, fname, false))
- {
- rwalk->unlink ();
- dictionary.remove (rwalk);
- rtemp = rwalk->nextResource;
- freeResource (rwalk);
- rwalk = rtemp;
- }
- else
- rwalk = rwalk->nextResource;
- }
- }
- void ResManager::setModPaths (U32 numPaths, const char **paths)
- {
- // [tom, 10/28/2006] If we're using a VFS, we don't want to do this
- // since it'll remove all the stuff we've already added.
- if(usingVFS)
- return;
- // detach all the files.
- for(ResourceObject * pwalk = resourceList.nextResource; pwalk; pwalk = pwalk->nextResource)
- pwalk->flags |= ResourceObject::Added;
- U32 pathLen = 0;
- // Set up exclusions.
- initExcludedDirectories();
- // Make sure invalid paths are not processed
- Vector<const char*> validPaths;
- // Determine if the mod paths are valid
- for (U32 i = 0; i < numPaths; i++)
- {
- pathLen += (dStrlen (paths[i]) + 1);
- // Load zip first so that local files override
- setModZip(paths[i]);
- searchPath (paths[i]);
- // Copy this path to the validPaths list
- validPaths.push_back(paths[i]);
- }
- Platform::clearExcludedDirectories();
- if (!pathLen)
- return;
- // Build the internal path list string
- pathList = (char *) dRealloc (pathList, pathLen);
- dStrcpy (pathList, validPaths[0]);
- U32 strlen;
- for (U32 i = 1; i < (U32)validPaths.size(); i++)
- {
- strlen = dStrlen (pathList);
- dSprintf (pathList + strlen, pathLen - strlen, ";%s", validPaths[i]);
- }
- // Unlink all 'added' that aren't loaded.
- ResourceObject *rwalk = resourceList.nextResource, *rtemp;
- while (rwalk != NULL)
- {
- if ((rwalk->flags & ResourceObject::Added) && !rwalk->mInstance)
- {
- rwalk->unlink ();
- dictionary.remove (rwalk);
- rtemp = rwalk->nextResource;
- freeResource (rwalk);
- rwalk = rtemp;
- }
- else
- rwalk = rwalk->nextResource;
- }
- }
- const char * ResManager::getModPaths ()
- {
- return ((const char *) pathList);
- }
- //------------------------------------------------------------------------------
- S32 ResManager::getSize (const char *fileName)
- {
- ResourceObject * ro = find (fileName);
- if (!ro)
- return 0;
- else
- return ro->fileSize;
- }
- //------------------------------------------------------------------------------
- const char * ResManager::getFullPath (const char *fileName, char *path, U32 pathlen)
- {
- AssertFatal (fileName, "ResourceManager::getFullPath: fileName is NULL");
- AssertFatal (path, "ResourceManager::getFullPath: path is NULL");
- ResourceObject *obj = find (fileName);
- if (!obj)
- dStrcpy (path, fileName);
- else
- Platform::makeFullPathName(obj->name, path, pathlen, obj->path);
- return path;
- }
- //------------------------------------------------------------------------------
- const char *ResManager::getPathOf (const char *fileName)
- {
- AssertFatal (fileName, "ResourceManager::getPathOf: fileName is NULL");
- ResourceObject *obj = find (fileName);
- if (!obj)
- return NULL;
- else
- return obj->path;
- }
- //------------------------------------------------------------------------------
- const char * ResManager::getModPathOf (const char *fileName)
- {
- AssertFatal (fileName, "ResourceManager::getModPathOf: fileName is NULL");
- if (!pathList)
- return NULL;
- ResourceObject *obj = find (fileName);
- if (!obj)
- return NULL;
- char buffer[256];
- char *base;
- const char *list = pathList;
- do
- {
- base = buffer;
- *base = 0;
- while (*list && *list != ';')
- {
- *base++ = *list++;
- }
- if (*list == ';')
- ++list;
- *base = 0;
- if (dStrncmp (buffer, obj->path, (base - buffer)) == 0)
- return StringTable->insert (buffer);
- }
- while (*list);
- return NULL;
- }
- //------------------------------------------------------------------------------
- const char *ResManager::getBasePath ()
- {
- if (!pathList)
- return NULL;
- const char *base = dStrrchr (pathList, ';');
- return base ? (base + 1) : pathList;
- }
- //------------------------------------------------------------------------------
- void ResManager::registerExtension (const char *name, RESOURCE_CREATE_FN create_fn)
- {
- AssertFatal (!getCreateFunction (name),
- "ResourceManager::registerExtension: file extension already registered.");
- const char *extension = dStrrchr (name, '.');
- AssertFatal (extension,
- "ResourceManager::registerExtension: file has no extension.");
- RegisteredExtension *add = new RegisteredExtension;
- add->mExtension = StringTable->insert (extension);
- add->mCreateFn = create_fn;
- add->next = registeredList;
- registeredList = add;
- }
- //------------------------------------------------------------------------------
- RESOURCE_CREATE_FN ResManager::getCreateFunction (const char *name)
- {
- const char * s = dStrrchr (name, '.');
- if (!s)
- return (NULL);
- RegisteredExtension * itr = registeredList;
- while (itr)
- {
- if (dStricmp (s, itr->mExtension) == 0)
- return (itr->mCreateFn);
- itr = itr->next;
- }
- return (NULL);
- }
- //------------------------------------------------------------------------------
- void ResManager::unlock (ResourceObject * obj)
- {
- if (!obj)
- return;
- AssertFatal (obj->lockCount > 0,
- "ResourceManager::unlock: lock count is zero.");
- //set the timeout to the max requested
- if (--obj->lockCount == 0)
- obj->linkAfter (&timeoutList);
- }
- //------------------------------------------------------------------------------
- // gets the crc of the file, ignores the stream type
- bool ResManager::getCrc (const char *fileName, U32 & crcVal,
- const U32 crcInitialVal)
- {
- ResourceObject *obj = find (fileName);
- if (!obj)
- return (false);
- // check if in a volume
- if (obj->flags & (ResourceObject::VolumeBlock | ResourceObject::File))
- {
- // can't crc locked resources...
- if (obj->lockCount)
- return false;
- // get rid of the resource
- // have to make sure user can't have it sitting around in the resource cache
- obj->unlink ();
- obj->destruct ();
- Stream *stream = openStream (obj);
- U32 waterMark = 0xFFFFFFFF;
- U8 *buffer;
- U32 maxSize = FrameAllocator::getHighWaterMark () - FrameAllocator::getWaterMark ();
- if (maxSize < (U32)obj->fileSize)
- buffer = new U8[obj->fileSize];
- else
- {
- waterMark = FrameAllocator::getWaterMark ();
- buffer = (U8 *) FrameAllocator::alloc (obj->fileSize);
- }
- stream->read (obj->fileSize, buffer);
- // get the crc value
- crcVal = calculateCRC (buffer, obj->fileSize, crcInitialVal);
- if (waterMark == 0xFFFFFFFF)
- delete[]buffer;
- else
- FrameAllocator::setWaterMark (waterMark);
- closeStream (stream);
- return (true);
- }
- return (false);
- }
- //------------------------------------------------------------------------------
- ResourceObject *ResManager::load (const char *fileName, bool computeCRC)
- {
- // if filename is not known, exit now
- ResourceObject *obj = find (fileName);
- if (!obj)
- return NULL;
- // if no one has a lock on this, but it's loaded and it needs to
- // be CRC'd, delete it and reload it.
- if (!obj->lockCount && computeCRC && obj->mInstance)
- obj->destruct ();
- obj->lockCount++;
- obj->unlink (); // remove from purge list
- if (!obj->mInstance)
- {
- obj->mInstance = loadInstance (obj, computeCRC);
- if (!obj->mInstance)
- {
- obj->lockCount--;
- return NULL;
- }
- }
- return obj;
- }
- //------------------------------------------------------------------------------
- ResourceInstance * ResManager::loadInstance (const char *fileName, bool computeCRC)
- {
- // if filename is not known, exit now
- ResourceObject *obj = find (fileName);
- if (!obj)
- return NULL;
- return loadInstance (obj, computeCRC);
- }
- //------------------------------------------------------------------------------
- static const char *alwaysCRCList = ".ter.dif.dts";
- ResourceInstance * ResManager::loadInstance (ResourceObject * obj, bool computeCRC)
- {
- Stream *stream = openStream (obj);
- if (!stream)
- return NULL;
- if (!computeCRC)
- {
- const char *x = dStrrchr (obj->name, '.');
- if (x && dStrstr (alwaysCRCList, x))
- computeCRC = true;
- }
- if (computeCRC)
- obj->crc = calculateCRCStream (stream, InvalidCRC);
- else
- obj->crc = InvalidCRC;
- RESOURCE_CREATE_FN createFunction = ResourceManager->getCreateFunction (obj->name);
- if(!createFunction)
- {
- AssertWarn( false, "ResourceObject::construct: NULL resource create function.");
- Con::errorf("ResourceObject::construct: NULL resource create function for '%s'.", obj->name);
- return NULL;
- }
- ResourceInstance *ret = createFunction (*stream);
- if(ret)
- ret->mSourceResource = obj;
- closeStream (stream);
- return ret;
- }
- //------------------------------------------------------------------------------
- Stream * ResManager::openStream (const char *fileName)
- {
- ResourceObject *obj = find (fileName);
- if (!obj)
- return NULL;
- return openStream (obj);
- }
- //------------------------------------------------------------------------------
- Stream * ResManager::openStream (ResourceObject * obj)
- {
- // if filename is not known, exit now
- if (!obj)
- return NULL;
- if (echoFileNames)
- Con::printf ("FILE ACCESS: %s/%s", obj->path, obj->name);
- // used for openStream stream access
- FileStream *diskStream = NULL;
- // if disk file
- if (obj->flags & (ResourceObject::File))
- {
- diskStream = new FileStream;
- if( !diskStream->open (buildPath (obj->path, obj->name), FileStream::Read) )
- {
- delete diskStream;
- return NULL;
- }
- obj->fileSize = diskStream->getStreamSize ();
- return diskStream;
- }
- // if zip file
- if (obj->flags & ResourceObject::VolumeBlock)
- {
- AssertFatal(obj->mZipArchive, "mZipArchive is NULL");
- AssertFatal(obj->mCentralDir, "mCentralDir is NULL");
- return obj->mZipArchive->openFileForRead(obj->mCentralDir);
- }
- // unknown type
- return NULL;
- }
- //------------------------------------------------------------------------------
- void ResManager::closeStream(Stream* stream)
- {
- // FIXME [tom, 10/26/2006] Note that this should really hand off to ZipArchive if it's
- // a zip stream, but there's currently no way to get the ZipArchive pointer from
- // here so we just repeat the relevant code. This is pretty lame.
- FilterStream *currentStream, *nextStream;
- // Try to cast the stream to a FilterStream
- nextStream = dynamic_cast<FilterStream*>(stream);
- bool isFilter = nextStream != NULL;
- // While the nextStream is valid (meaning it was successfully cast to a FilterStream)
- while (nextStream)
- {
- // Point currentStream to nextStream
- currentStream = nextStream;
- // Point stream to the Stream contained within the current FilterStream
- stream = currentStream->getStream();
- // Detach the current FilterStream from the Stream contained within it
- currentStream->detachStream();
- // Try to cast the stream (which was already contained within a FilterStream) to a FilterStream
- nextStream = dynamic_cast<FilterStream*>(stream);
- // Delete the FilterStream that was wrapping stream
- delete currentStream;
- }
- if(! isFilter)
- delete stream;
- }
- //------------------------------------------------------------------------------
- ResourceObject *ResManager::find (const char *fileName)
- {
- if (!fileName)
- return NULL;
- StringTableEntry path, file;
- getPaths (fileName, path, file);
- ResourceObject *ret = dictionary.find (path, file);
- if(!ret)
- {
- // If we couldn't find the file in the resource list (generated
- // by setting the modPaths) then try to load it directly
- if (Platform::isFile(fileName))
- {
- ret = createResource (path, file);
- dictionary.pushBehind (ret, ResourceObject::File);
- ret->flags = ResourceObject::File;
- ret->fileOffset = 0;
- S32 fileSize = Platform::getFileSize(fileName);
- ret->fileSize = fileSize;
- ret->compressedFileSize = fileSize;
- return ret;
- }
- fileIsMissing(fileName);
- }
- return ret;
- }
- //------------------------------------------------------------------------------
- ResourceObject *ResManager::find (const char *fileName, U32 flags)
- {
- if (!fileName)
- return NULL;
- StringTableEntry path, file;
- getPaths (fileName, path, file);
- return dictionary.find (path, file, flags);
- }
- //------------------------------------------------------------------------------
- // Add resource constructed outside the manager
- bool ResManager::add (const char *name, ResourceInstance * addInstance,
- bool extraLock)
- {
- StringTableEntry path, file;
- getPaths (name, path, file);
- ResourceObject *obj = dictionary.find (path, file);
- if (obj && obj->mInstance)
- // Resource already exists?
- return false;
- if (!obj)
- obj = createResource (path, file);
- dictionary.pushBehind (obj,
- ResourceObject::File | ResourceObject::VolumeBlock);
- obj->mInstance = addInstance;
- addInstance->mSourceResource = obj;
- obj->lockCount = extraLock ? 2 : 1;
- unlock (obj);
- return true;
- }
- //------------------------------------------------------------------------------
- void ResManager::purge ()
- {
- bool found;
- do
- {
- ResourceObject *obj = timeoutList.getNext ();
- found = false;
- while (obj)
- {
- ResourceObject *temp = obj;
- obj = obj->next;
- temp->unlink ();
- temp->destruct ();
- found = true;
- if (temp->flags & ResourceObject::Added)
- freeResource (temp);
- }
- }
- while (found);
- }
- //------------------------------------------------------------------------------
- void ResManager::purge (ResourceObject * obj)
- {
- AssertFatal (obj->lockCount == 0,
- "ResourceManager::purge: handle lock count is not ZERO.") obj->
- unlink ();
- obj->destruct ();
- }
- //------------------------------------------------------------------------------
- // serialize sorts a list of files by .zip and position within the zip
- // it allows an aggregate (material list, etc) to find the preferred
- // loading order for a set of files.
- //------------------------------------------------------------------------------
- struct ResourceObjectIndex
- {
- ResourceObject *ro;
- const char *fileName;
- static S32 QSORT_CALLBACK compare (const void *s1, const void *s2)
- {
- const ResourceObjectIndex *r1 = (ResourceObjectIndex *) s1;
- const ResourceObjectIndex *r2 = (ResourceObjectIndex *) s2;
- if (r1->ro->path != r2->ro->path)
- return (S32)(r1->ro->path - r2->ro->path);
- if (r1->ro->name != r2->ro->name)
- return (S32)(r1->ro->name - r2->ro->name);
- return r1->ro->fileOffset - r2->ro->fileOffset;
- }
- };
- //------------------------------------------------------------------------------
- void ResManager::serialize (VectorPtr < const char *>&filenames)
- {
- Vector < ResourceObjectIndex > sortVector;
- sortVector.reserve (filenames.size ());
- U32 i;
- for (i = 0; i < (U32)filenames.size (); i++)
- {
- ResourceObjectIndex roi;
- roi.ro = find (filenames[i]);
- roi.fileName = filenames[i];
- sortVector.push_back (roi);
- }
- dQsort ((void *)sortVector.address(), sortVector.size (),
- sizeof (ResourceObjectIndex), ResourceObjectIndex::compare);
- for (i = 0; i < (U32)filenames.size (); i++)
- filenames[i] = sortVector[i].fileName;
- }
- //------------------------------------------------------------------------------
- ResourceObject * ResManager::findMatch (const char *expression, const char **fn,
- ResourceObject * start)
- {
- if (!start)
- start = resourceList.nextResource;
- else
- start = start->nextResource;
- while (start)
- {
- const char *fname = buildPath (start->path, start->name);
- if (FindMatch::isMatch (expression, fname, false))
- {
- *fn = fname;
- return start;
- }
- start = start->nextResource;
- }
- return NULL;
- }
- ResourceObject * ResManager::findMatchMultiExprs (const char *multiExpression, const char **fn,
- ResourceObject * start)
- {
- if (!start)
- start = resourceList.nextResource;
- else
- start = start->nextResource;
- while (start)
- {
- const char *fname = buildPath (start->path, start->name);
- if (FindMatch::isMatchMultipleExprs(multiExpression, fname, false))
- {
- *fn = fname;
- return start;
- }
- start = start->nextResource;
- }
- return NULL;
- }
- S32 ResManager::findMatches (FindMatch * pFM)
- {
- static char buffer[16384];
- S32 bufl = 0;
- ResourceObject * walk;
- for (walk = resourceList.nextResource; walk && !pFM->isFull (); walk = walk->nextResource)
- {
- const char * fpath =
- buildPath (walk->path, walk->name);
- if (bufl + dStrlen (fpath) >= 16380)
- return pFM->numMatches ();
- dStrcpy (buffer + bufl, fpath);
- if (pFM->findMatch (buffer + bufl))
- bufl += dStrlen (fpath) + 1;
- }
- return (pFM->numMatches ());
- }
- //------------------------------------------------------------------------------
- bool ResManager::findFile (const char *name)
- {
- return (bool) find (name);
- }
- //------------------------------------------------------------------------------
- ResourceObject * ResManager::createResource (StringTableEntry path, StringTableEntry file)
- {
- ResourceObject *newRO = dictionary.find (path, file);
- if (newRO)
- return newRO;
- newRO = new ResourceObject;
- newRO->path = path;
- newRO->name = file;
- newRO->lockCount = 0;
- newRO->mInstance = NULL;
- newRO->flags = ResourceObject::Added;
- newRO->next = newRO->prev = NULL;
- newRO->nextResource = resourceList.nextResource;
- resourceList.nextResource = newRO;
- newRO->prevResource = &resourceList;
- if (newRO->nextResource)
- newRO->nextResource->prevResource = newRO;
- dictionary.insert (newRO, path, file);
- newRO->fileSize = newRO->fileOffset = newRO->compressedFileSize = 0;
- newRO->zipPath = NULL;
- newRO->zipName = NULL;
- newRO->crc = InvalidCRC;
- return newRO;
- }
- //------------------------------------------------------------------------------
- ResourceObject * ResManager::createZipResource (StringTableEntry path, StringTableEntry file,
- StringTableEntry zipPath,
- StringTableEntry zipName)
- {
- ResourceObject *newRO = dictionary.find (path, file, zipPath, zipName);
- if (newRO)
- return newRO;
- newRO = new ResourceObject;
- newRO->path = path;
- newRO->name = file;
- newRO->lockCount = 0;
- newRO->mInstance = NULL;
- newRO->flags = ResourceObject::Added;
- newRO->next = newRO->prev = NULL;
- newRO->nextResource = resourceList.nextResource;
- resourceList.nextResource = newRO;
- newRO->prevResource = &resourceList;
- if (newRO->nextResource)
- newRO->nextResource->prevResource = newRO;
- dictionary.insert (newRO, path, file);
- newRO->fileSize = newRO->fileOffset = newRO->compressedFileSize = 0;
- newRO->zipPath = zipPath;
- newRO->zipName = zipName;
- newRO->crc = InvalidCRC;
- newRO->mZipArchive = NULL;
- newRO->mCentralDir = NULL;
- return newRO;
- }
- //------------------------------------------------------------------------------
- void ResManager::freeResource (ResourceObject * ro)
- {
- ro->destruct ();
- ro->unlink ();
- // if((ro->flags & ResourceObject::File) && ro->lockedData)
- // delete[] ro->lockedData;
- if (ro->prevResource)
- ro->prevResource->nextResource = ro->nextResource;
- if (ro->nextResource)
- ro->nextResource->prevResource = ro->prevResource;
- dictionary.remove (ro);
- delete ro;
- }
- //------------------------------------------------------------------------------
- bool ResManager::openFileForWrite (FileStream & stream, const char *fileName, U32 accessMode)
- {
- //if (!isValidWriteFileName (fileName))
- //return false;
- // tag it on to the first directory
- char path[1024];
- dStrcpy (path, fileName);
- char *file = dStrrchr (path, '/');
- if (!file)
- return false; // don't allow storing files in root
- *file++ = 0;
- if (!Platform::createPath (fileName)) // create directory tree
- return false;
- if (!stream.open (fileName, (FileStream::AccessMode) accessMode))
- return false;
- // create a resource for the file.
- ResourceObject *ro = createResource (StringTable->insert (path), StringTable->insert (file));
- ro->flags = ResourceObject::File;
- ro->fileOffset = 0;
- ro->fileSize = 0;
- ro->compressedFileSize = 0;
- return true;
- }
|