std::string System::findDataFile (const std::string& full, bool errorIfNotFound) { // Places where specific files were most recently found. This is // used to cache seeking of common files. static Table<std::string, std::string> lastFound; // First check if the file exists as requested. This will go // through the FileSystemCache, so most calls do not touch disk. if (FileSystem::exists(full)) { return full; } // Now check where we previously found this file. std::string* last = lastFound.getPointer(full); if (last != NULL) { if (FileSystem::exists(*last)) { // Even if cwd has changed the file is still present. // We won't notice if it has been deleted, however. return *last; } else { // Remove this from the cache it is invalid lastFound.remove(full); } } // Places to look static Array<std::string> directoryArray; std::string initialAppDataDir(instance().m_appDataDir); const char* g3dPath = getenv("G3DDATA"); if (directoryArray.size() == 0) { // Initialize the directory array RealTime t0 = System::time(); Array<std::string> baseDirArray; baseDirArray.append(""); if (! initialAppDataDir.empty()) { baseDirArray.append(initialAppDataDir); } # ifdef G3D_WIN32 if (g3dPath == NULL) { // If running the demos under visual studio from the G3D.sln file, // this will locate the data directory. const char* paths[] = {"../data-files/", "../../data-files/", "../../../data-files/", NULL}; for (int i = 0; paths[i]; ++i) { if (FileSystem::exists(pathConcat(paths[i], "G3D-DATA-README.TXT"))) { g3dPath = paths[i]; break; } } } # endif if (g3dPath && (initialAppDataDir != g3dPath)) { baseDirArray.append(g3dPath); } static const std::string subdirs[] = {"font", "gui", "SuperShader", "cubemap", "icon", "material", "image", "md2", "md3", "ifs", "3ds", "sky", ""}; for (int j = 0; j < baseDirArray.size(); ++j) { std::string d = baseDirArray[j]; if ((d == "") || FileSystem::exists(d)) { directoryArray.append(d); for (int i = 0; ! subdirs[i].empty(); ++i) { const std::string& p = pathConcat(d, subdirs[i]); if (FileSystem::exists(p)) { directoryArray.append(p); } } } } logLazyPrintf("Initializing System::findDataFile took %fs\n", System::time() - t0); } for (int i = 0; i < directoryArray.size(); ++i) { const std::string& p = pathConcat(directoryArray[i], full); if (FileSystem::exists(p)) { lastFound.set(full, p); return p; } } if (errorIfNotFound) { // Generate an error message std::string locations; for (int i = 0; i < directoryArray.size(); ++i) { locations += "\'" + pathConcat(directoryArray[i], full) + "'\n"; } std::string msg = "Could not find '" + full + "'.\n\n"; msg += "cwd = \'" + FileSystem::currentDirectory() + "\'\n"; if (g3dPath) { msg += "G3DDATA = "; if (! FileSystem::exists(g3dPath)) { msg += "(illegal path!) "; } msg += std::string(g3dPath) + "\'\n"; } else { msg += "(G3DDATA environment variable is undefined)\n"; } msg += "GApp::Settings.dataDir = "; if (! FileSystem::exists(initialAppDataDir)) { msg += "(illegal path!) "; } msg += std::string(initialAppDataDir) + "\'\n"; msg += "\nLocations searched:\n" + locations; alwaysAssertM(false, msg); } // Not found return ""; }
std::string System::findDataFile (const std::string& full, bool errorIfNotFound) { // Places where specific files were most recently found. This is // used to cache seeking of common files. static Table<std::string, std::string> lastFound; // First check if the file exists as requested. This will go // through the FileSystemCache, so most calls do not touch disk. if (fileExists(full)) { return full; } // Now check where we previously found this file. std::string* last = lastFound.getPointer(full); if (last != NULL) { if (fileExists(*last)) { // Even if cwd has changed the file is still present. // We won't notice if it has been deleted, however. return *last; } else { // Remove this from the cache it is invalid lastFound.remove(full); } } // Places to look static Array<std::string> directoryArray; if (directoryArray.size() == 0) { // Initialize the directory array RealTime t0 = System::time(); Array<std::string> baseDirArray; std::string initialAppDataDir(instance().m_appDataDir); baseDirArray.append(""); if (! initialAppDataDir.empty()) { baseDirArray.append(initialAppDataDir); } const char* g3dPath = getenv("G3DDATA"); if (g3dPath && (initialAppDataDir != g3dPath)) { baseDirArray.append(g3dPath); } static const std::string subdirs[] = {"font", "gui", "SuperShader", "cubemap", "icon", "material", "image", "md2", "md3", "ifs", "3ds", "sky", ""}; for (int j = 0; j < baseDirArray.size(); ++j) { std::string d = baseDirArray[j]; if (fileExists(d)) { directoryArray.append(d); for (int i = 0; ! subdirs[i].empty(); ++i) { const std::string& p = pathConcat(d, subdirs[i]); if (fileExists(p)) { directoryArray.append(p); } } } } logLazyPrintf("Initializing System::findDataFile took %fs\n", System::time() - t0); } for (int i = 0; i < directoryArray.size(); ++i) { const std::string& p = pathConcat(directoryArray[i], full); if (fileExists(p)) { lastFound.set(full, p); return p; } } if (errorIfNotFound) { // Generate an error message std::string locations; for (int i = 0; i < directoryArray.size(); ++i) { locations += pathConcat(directoryArray[i], full) + "\n"; } alwaysAssertM(false, "Could not find '" + full + "' in:\n" + locations); } // Not found return ""; }