//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. // // $Id$ //============================================================================ #include #include #include #include "bspf.hxx" #include "DefProps.hxx" #include "Props.hxx" #include "PropsSet.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - PropertiesSet::PropertiesSet(const string& propsfile) { load(propsfile); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - PropertiesSet::~PropertiesSet() { myExternalProps.clear(); myTempProps.clear(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void PropertiesSet::load(const string& filename) { ifstream in(filename.c_str(), ios::in); // Loop reading properties for(;;) { // Make sure the stream is still good or we're done if(!in) break; // Get the property list associated with this profile Properties prop; prop.load(in); // If the stream is still good then insert the properties if(in) insert(prop); } if(in) in.close(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool PropertiesSet::save(const string& filename) const { ofstream out(filename.c_str(), ios::out); if(!out) return false; // Only save those entries in the external list for(const auto& i: myExternalProps) i.second.save(out); return true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool PropertiesSet::getMD5(const string& md5, Properties& properties, bool useDefaults) const { properties.setDefaults(); bool found = false; // There are three lists to search when looking for a properties entry, // which must be done in the following order // If 'useDefaults' is specified, only use the built-in list // // 'save': entries previously inserted that are saved on program exit // 'temp': entries previously inserted that are discarded // 'builtin': the defaults compiled into the program // First check properties from external file if(!useDefaults) { // Check external list const auto ext = myExternalProps.find(md5); if(ext != myExternalProps.end()) { properties = ext->second; found = true; } else // Search temp list { const auto tmp = myTempProps.find(md5); if(tmp != myTempProps.end()) { properties = tmp->second; found = true; } } } // Otherwise, search the internal database using binary search if(!found) { int low = 0, high = DEF_PROPS_SIZE - 1; while(low <= high) { int i = (low + high) / 2; int cmp = BSPF_compareIgnoreCase(md5, DefProps[i][Cartridge_MD5]); if(cmp == 0) // found it { for(int p = 0; p < LastPropType; ++p) if(DefProps[i][p][0] != 0) properties.set((PropertyType)p, DefProps[i][p]); found = true; break; } else if(cmp < 0) high = i - 1; // look at lower range else low = i + 1; // look at upper range } } return found; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void PropertiesSet::getMD5WithInsert(const FilesystemNode& rom, const string& md5, Properties& properties) { if(!getMD5(md5, properties)) { properties.set(Cartridge_MD5, md5); // Create a name suitable for using in properties properties.set(Cartridge_Name, rom.getNameWithExt("")); insert(properties, false); } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void PropertiesSet::insert(const Properties& properties, bool save) { // Note that the following code is optimized for insertion when an item // doesn't already exist, and when the external properties file is // relatively small (which is the case with current versions of Stella, // as the properties are built-in) // If an item does exist, it will be removed and insertion done again // This shouldn't be a speed issue, as insertions will only fail with // duplicates when you're changing the current ROM properties, which // most people tend not to do // Since the PropSet is keyed by md5, we can't insert without a valid one const string& md5 = properties.get(Cartridge_MD5); if(md5 == "") return; // The status of 'save' determines which list to save to PropsList& list = save ? myExternalProps : myTempProps; auto ret = list.insert(make_pair(md5, properties)); if(ret.second == false) { // Remove old item and insert again list.erase(ret.first); list.insert(make_pair(md5, properties)); } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void PropertiesSet::removeMD5(const string& md5) { // We only remove from the external list myExternalProps.erase(md5); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void PropertiesSet::print() const { // We only look at the external properties and the built-in ones; // the temp properties are ignored // Also, any properties entries in the external file override the built-in // ones // The easiest way to merge the lists is to create another temporary one // This isn't fast, but I suspect this method isn't used too often (or at all) PropsList list; // First insert all external props list = myExternalProps; // Now insert all the built-in ones // Note that if we try to insert a duplicate, the insertion will fail // This is fine, since a duplicate in the built-in list means it should // be overrided anyway (and insertion shouldn't be done) Properties properties; for(int i = 0; i < DEF_PROPS_SIZE; ++i) { properties.setDefaults(); for(int p = 0; p < LastPropType; ++p) if(DefProps[i][p][0] != 0) properties.set((PropertyType)p, DefProps[i][p]); list.insert(make_pair(DefProps[i][Cartridge_MD5], properties)); } // Now, print the resulting list Properties::printHeader(); for(const auto& i: list) i.second.print(); }