void WadImageCache::delete_storage_for_name(std::string& name) const { FileSpecifier file; file.SetToImageCacheDir(); file.AddPart(name); file.Delete(); }
void WadImageCache::save_cache() { if (!m_cache_dirty) return; InfoTree pt; for (cache_iter_t it = m_used.begin(); it != m_used.end(); ++it) { std::string name = it->second.first; WadImageDescriptor desc = boost::tuples::get<0>(it->first); pt.put(name + ".path", desc.file.GetPath()); pt.put(name + ".checksum", desc.checksum); pt.put(name + ".index", desc.index); pt.put(name + ".tag", desc.tag); pt.put(name + ".width", boost::tuples::get<1>(it->first)); pt.put(name + ".height", boost::tuples::get<2>(it->first)); pt.put(name + ".filesize", it->second.second); } FileSpecifier info; info.SetToImageCacheDir(); info.AddPart("Cache.ini"); try { pt.save_ini(info); m_cache_dirty = false; } catch (InfoTree::ini_error e) { logError("Could not save image cache to %s (%s)", info.GetPath(), e.what()); return; } }
SDL_Surface* QuickSaveImageCache::get(std::string image_name) { std::map<std::string, cache_iter_t>::iterator it = m_images.find(image_name); if (it != m_images.end()) { // found it: move to front of list m_used.splice(m_used.begin(), m_used, it->second); return it->second->second; } // didn't find: load image FileSpecifier f; f.SetToQuickSavesDir(); f.AddPart(image_name + ".sgaA"); WadImageDescriptor desc; desc.file = f; desc.checksum = 0; desc.index = SAVE_GAME_METADATA_INDEX; desc.tag = SAVE_IMG_TAG; SDL_Surface *img = WadImageCache::instance()->get_image(desc, PREVIEW_WIDTH, PREVIEW_HEIGHT); if (img) { m_used.push_front(cache_pair_t(image_name, img)); m_images[image_name] = m_used.begin(); // enforce maximum cache size if (m_used.size() > k_max_items) { cache_iter_t lru = m_used.end(); --lru; m_images.erase(lru->first); SDL_FreeSurface(lru->second); m_used.pop_back(); } } return img; }
// This tries to find a filename (in the same directory as inBaseName) based on 'inBaseName' but that is not yet used. // The current logic tries inBaseName first, then 'inBaseName 2', then 'inBaseName 3', and so on. // The resulting name will have no more than inMaxNameLength actual characters. // Returns whether it was successful (the current logic either returns true or loops forever; fortunately, the // probability of looping forever is really, REALLY tiny; the directory would have to contain every possible variant). static bool make_nonconflicting_filename_variant(/*const*/ FileSpecifier& inBaseName, FileSpecifier& outNonconflictingName, size_t inMaxNameLength) { FileSpecifier theNameToTry; DirectorySpecifier theDirectory; inBaseName.ToDirectory(theDirectory); char theBaseNameString[256]; // XXX I don't like this, but the SDL code already imposes this maxlen throughout. inBaseName.GetName(theBaseNameString); size_t theBaseNameLength = strlen(theBaseNameString); char theNameToTryString[256]; char theVariantSuffix[32]; // way more than enough unsigned int theVariant = 0; size_t theSuffixLength; size_t theBaseNameLengthToUse; bool theVariantIsAcceptable = false; while(!theVariantIsAcceptable) { theVariant++; if(theVariant == 1) { theVariantSuffix[0] = '\0'; theSuffixLength = 0; } else { theSuffixLength = sprintf(theVariantSuffix, " %d", theVariant); } assert(theSuffixLength <= inMaxNameLength); if(theSuffixLength + theBaseNameLength > inMaxNameLength) theBaseNameLengthToUse = inMaxNameLength - theSuffixLength; else theBaseNameLengthToUse = theBaseNameLength; sprintf(theNameToTryString, "%.*s%s", (int) theBaseNameLengthToUse, theBaseNameString, theVariantSuffix); theNameToTry.FromDirectory(theDirectory); #if defined(mac) || defined(SDL_RFORK_HACK) // Note: SetName() currently ignores the 'type' argument, so I feel // little compulsion to try to figure it out. theNameToTry.SetName(theNameToTryString,NONE); #else theNameToTry.AddPart(theNameToTryString); #endif if(!theNameToTry.Exists()) theVariantIsAcceptable = true; } if(theVariantIsAcceptable) { outNonconflictingName = theNameToTry; } return theVariantIsAcceptable; }
// Analogous to 'save_game()', but does not present any dialog to the user, and reports the results // using screen_printf(). If inOverwriteRecent is set, it will save over the most recently saved // or restored game (if possible). If inOverwriteRecent is not set, or if there is no recent game // to save over, it will pick a new, nonconflicting filename and save to it. // Returns whether save was successful. bool save_game_full_auto(bool inOverwriteRecent) { bool createNewFile = !inOverwriteRecent; FileSpecifier theRecentSavedGame; get_current_saved_game_name(theRecentSavedGame); char theSavedGameName[256]; // XXX // If we're supposed to overwrite, change our minds if we seem to have no 'existing file'. if(!createNewFile) { theRecentSavedGame.GetName(theSavedGameName); if(strcmp(theSavedGameName, TS_GetCString(strFILENAMES, filenameDEFAULT_SAVE_GAME)) == 0) createNewFile = true; } // Make up a filename (currently based on level name) if(createNewFile) { if(strncpy_filename_friendly(theSavedGameName, static_world->level_name, kMaxFilenameChars) <= 0) strcpy(theSavedGameName, "Automatic Save"); DirectorySpecifier theDirectory; theRecentSavedGame.ToDirectory(theDirectory); theRecentSavedGame.FromDirectory(theDirectory); #if defined(mac) || defined(SDL_RFORK_HACK) // Note: SetName() currently ignores the 'type' argument, so I feel // little compulsion to try to figure it out. theRecentSavedGame.SetName(theSavedGameName,NONE); #else theRecentSavedGame.AddPart(theSavedGameName); #endif } FileSpecifier theOutputFile; if(createNewFile) make_nonconflicting_filename_variant(theRecentSavedGame, theOutputFile, kMaxFilenameChars); else theOutputFile = theRecentSavedGame; bool successfulSave = save_game_file(theOutputFile); theOutputFile.GetName(theSavedGameName); if(successfulSave) { screen_printf("%s saved game '%s'", createNewFile ? "Created new" : "Replaced existing", theSavedGameName); // play a sound? } else { screen_printf("Unable to save game as '%s'", theSavedGameName); // play a sound? } return successfulSave; }
SDL_Surface *WadImageCache::image_from_name(std::string& name) const { FileSpecifier file; file.SetToImageCacheDir(); file.AddPart(name); OpenedFile of; if (!file.Open(of)) return NULL; #ifdef HAVE_SDL_IMAGE SDL_Surface *img = IMG_Load_RW(of.GetRWops(), 0); #else SDL_Surface *img = SDL_LoadBMP_RW(of.GetRWops(), 0); #endif return img; }
// Exchange two files bool FileSpecifier::Exchange(FileSpecifier &other) { // Create temporary name (this is cheap, we should make sure that the // name is not already in use...) FileSpecifier tmp; ToDirectory(tmp); tmp.AddPart("exchange_tmp_file"); err = 0; if (rename(GetPath(), tmp.GetPath()) < 0) err = errno; else rename(other.GetPath(), GetPath()); if (rename(tmp.GetPath(), other.GetPath()) < 0) err = errno; return err == 0; }
void WadImageCache::initialize_cache() { FileSpecifier info; info.SetToImageCacheDir(); info.AddPart("Cache.ini"); if (!info.Exists()) return; InfoTree pt; try { pt = InfoTree::load_ini(info); } catch (InfoTree::ini_error e) { logError("Could not read image cache from %s (%s)", info.GetPath(), e.what()); } for (InfoTree::iterator it = pt.begin(); it != pt.end(); ++it) { std::string name = it->first; InfoTree ptc = it->second; WadImageDescriptor desc; std::string path; ptc.read("path", path); desc.file = FileSpecifier(path); ptc.read("checksum", desc.checksum); ptc.read("index", desc.index); ptc.read("tag", desc.tag); int width = 0; ptc.read("width", width); int height = 0; ptc.read("height", height); size_t filesize = 0; ptc.read("filesize", filesize); cache_key_t key = cache_key_t(desc, width, height); cache_value_t val = cache_value_t(name, filesize); m_used.push_front(cache_pair_t(key, val)); m_cacheinfo[key] = m_used.begin(); m_cachesize += filesize; } }
FileSpecifier GetPath() { FileSpecifier dir = m_list_w->get_file(); std::string base; std::string part; dir.SplitPath(base, part); std::string filename = GetFilename(); if (part == filename) { dir = base; } if (m_extension && !boost::algorithm::ends_with(filename, m_extension)) { filename += m_extension; } dir.AddPart(filename); return dir; }
std::string WadImageCache::image_to_new_name(SDL_Surface *image, int32 *filesize) const { // create name boost::uuids::random_generator gen; boost::uuids::uuid u = gen(); std::string ustr = boost::uuids::to_string(u); FileSpecifier File; File.SetToImageCacheDir(); File.AddPart(ustr); FileSpecifier TempFile; TempFile.SetTempName(File); int ret; //#if defined(HAVE_PNG) && defined(HAVE_SDL_IMAGE) // ret = aoIMG_SavePNG(TempFile.GetPath(), image, IMG_COMPRESS_DEFAULT, NULL, 0); #ifdef HAVE_SDL_IMAGE ret = IMG_SavePNG(image, TempFile.GetPath()); #else ret = SDL_SaveBMP(image, TempFile.GetPath()); #endif if (ret == 0 && TempFile.Rename(File)) { if (filesize) { OpenedFile of; if (File.Open(of)) of.GetLength(*filesize); } return ustr; } if (filesize) *filesize = 0; return ""; }