diff options
Diffstat (limited to 'indra/newview/llwlparammanager.cpp')
-rw-r--r-- | indra/newview/llwlparammanager.cpp | 556 |
1 files changed, 370 insertions, 186 deletions
diff --git a/indra/newview/llwlparammanager.cpp b/indra/newview/llwlparammanager.cpp index 848efcbb49..f475b3da01 100644 --- a/indra/newview/llwlparammanager.cpp +++ b/indra/newview/llwlparammanager.cpp @@ -37,23 +37,32 @@ #include "llspinctrl.h" #include "llcheckboxctrl.h" #include "lluictrlfactory.h" +#include "llviewercamera.h" #include "llcombobox.h" #include "lllineeditor.h" #include "llsdserialize.h" #include "v4math.h" +#include "llviewerdisplay.h" #include "llviewercontrol.h" +#include "llviewerwindow.h" +#include "lldrawpoolwater.h" +#include "llagent.h" +#include "llviewerregion.h" +#include "lldaycyclemanager.h" +#include "llenvmanager.h" #include "llwlparamset.h" #include "llpostprocess.h" + #include "llfloaterwindlight.h" #include "llfloaterdaycycle.h" #include "llfloaterenvsettings.h" +#include "llviewershadermgr.h" +#include "llglslshader.h" #include "curl/curl.h" - -LLWLParamManager * LLWLParamManager::sInstance = NULL; -static LLFastTimer::DeclareTimer FTM_UPDATE_WLPARAM("Update Windlight Params"); +#include "llstreamtools.h" LLWLParamManager::LLWLParamManager() : @@ -96,161 +105,237 @@ LLWLParamManager::~LLWLParamManager() { } -void LLWLParamManager::loadPresets(const std::string& file_name) +void LLWLParamManager::clearParamSetsOfScope(LLWLParamKey::EScope scope) { - std::string path_name(gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, "windlight/skies", "")); - LL_DEBUGS2("AppInit", "Shaders") << "Loading Default WindLight settings from " << path_name << LL_ENDL; - - bool found = true; - LLDirIterator app_settings_iter(path_name, "*.xml"); - while(found) + if (LLWLParamKey::SCOPE_LOCAL == scope) { - std::string name; - found = app_settings_iter.next(name); - if(found) - { - - name=name.erase(name.length()-4); - - // bugfix for SL-46920: preventing filenames that break stuff. - char * curl_str = curl_unescape(name.c_str(), name.size()); - std::string unescaped_name(curl_str); - curl_free(curl_str); - curl_str = NULL; + LL_WARNS("Windlight") << "Tried to clear windlight sky presets from local system! This shouldn't be called..." << LL_ENDL; + return; + } - LL_DEBUGS2("AppInit", "Shaders") << "name: " << name << LL_ENDL; - loadPreset(unescaped_name,FALSE); + std::set<LLWLParamKey> to_remove; + for(std::map<LLWLParamKey, LLWLParamSet>::iterator iter = mParamList.begin(); iter != mParamList.end(); ++iter) + { + if(iter->first.scope == scope) + { + to_remove.insert(iter->first); } } - // And repeat for user presets, note the user presets will modify any system presets already loaded + for(std::set<LLWLParamKey>::iterator iter = to_remove.begin(); iter != to_remove.end(); ++iter) + { + mParamList.erase(*iter); + } +} - std::string path_name2(gDirUtilp->getExpandedFilename( LL_PATH_USER_SETTINGS , "windlight/skies", "")); - LL_DEBUGS2("AppInit", "Shaders") << "Loading User WindLight settings from " << path_name2 << LL_ENDL; - - found = true; - LLDirIterator user_settings_iter(path_name2, "*.xml"); - while(found) +// returns all skies referenced by the day cycle, with their final names +// side effect: applies changes to all internal structures! +std::map<LLWLParamKey, LLWLParamSet> LLWLParamManager::finalizeFromDayCycle(LLWLParamKey::EScope scope) +{ + lldebugs << "mDay before finalizing:" << llendl; { - std::string name; - found = user_settings_iter.next(name); - if(found) + for (std::map<F32, LLWLParamKey>::iterator iter = mDay.mTimeMap.begin(); iter != mDay.mTimeMap.end(); ++iter) { - name=name.erase(name.length()-4); + LLWLParamKey& key = iter->second; + lldebugs << iter->first << "->" << key.name << llendl; + } + } - // bugfix for SL-46920: preventing filenames that break stuff. - char * curl_str = curl_unescape(name.c_str(), name.size()); - std::string unescaped_name(curl_str); - curl_free(curl_str); - curl_str = NULL; + std::map<LLWLParamKey, LLWLParamSet> final_references; - LL_DEBUGS2("AppInit", "Shaders") << "name: " << name << LL_ENDL; - loadPreset(unescaped_name,FALSE); + // Move all referenced to desired scope, renaming if necessary + // First, save skies referenced + std::map<LLWLParamKey, LLWLParamSet> current_references; // all skies referenced by the day cycle, with their current names + // guard against skies with same name and different scopes + std::set<std::string> inserted_names; + std::map<std::string, unsigned int> conflicted_names; // integer later used as a count, for uniquely renaming conflicts + + LLWLDayCycle& cycle = mDay; + for(std::map<F32, LLWLParamKey>::iterator iter = cycle.mTimeMap.begin(); + iter != cycle.mTimeMap.end(); + ++iter) + { + LLWLParamKey& key = iter->second; + std::string desired_name = key.name; + replace_newlines_with_whitespace(desired_name); // already shouldn't have newlines, but just in case + if(inserted_names.find(desired_name) == inserted_names.end()) + { + inserted_names.insert(desired_name); + } + else + { + // make exist in map + conflicted_names[desired_name] = 0; } + current_references[key] = mParamList[key]; } -} + // forget all old skies in target scope, and rebuild, renaming as needed + clearParamSetsOfScope(scope); + for(std::map<LLWLParamKey, LLWLParamSet>::iterator iter = current_references.begin(); iter != current_references.end(); ++iter) + { + const LLWLParamKey& old_key = iter->first; -void LLWLParamManager::savePresets(const std::string & fileName) -{ - //Nobody currently calls me, but if they did, then its reasonable to write the data out to the user's folder - //and not over the RO system wide version. + std::string desired_name(old_key.name); + replace_newlines_with_whitespace(desired_name); - LLSD paramsData(LLSD::emptyMap()); - - std::string pathName(gDirUtilp->getExpandedFilename( LL_PATH_USER_SETTINGS , "windlight", fileName)); + LLWLParamKey new_key(desired_name, scope); // name will be replaced later if necessary - for(std::map<std::string, LLWLParamSet>::iterator mIt = mParamList.begin(); - mIt != mParamList.end(); - ++mIt) - { - paramsData[mIt->first] = mIt->second.getAll(); - } + // if this sky is one with a non-unique name, rename via appending a number + // an existing preset of the target scope gets to keep its name + if (scope != old_key.scope && conflicted_names.find(desired_name) != conflicted_names.end()) + { + std::string& new_name = new_key.name; - llofstream presetsXML(pathName); + do + { + // if this executes more than once, this is an absurdly pathological case + // (e.g. "x" repeated twice, but "x 1" already exists, so need to use "x 2") + std::stringstream temp; + temp << desired_name << " " << (++conflicted_names[desired_name]); + new_name = temp.str(); + } while (inserted_names.find(new_name) != inserted_names.end()); - LLPointer<LLSDFormatter> formatter = new LLSDXMLFormatter(); + // yay, found one that works + inserted_names.insert(new_name); // track names we consume here; shouldn't be necessary due to ++int? but just in case - formatter->format(paramsData, presetsXML, LLSDFormatter::OPTIONS_PRETTY); + // *TODO factor out below into a rename()? - presetsXML.close(); -} + LL_INFOS("Windlight") << "Renamed " << old_key.name << " (scope" << old_key.scope << ") to " + << new_key.name << " (scope " << new_key.scope << ")" << LL_ENDL; -void LLWLParamManager::loadPreset(const std::string & name,bool propagate) -{ - - // bugfix for SL-46920: preventing filenames that break stuff. - char * curl_str = curl_escape(name.c_str(), name.size()); - std::string escaped_filename(curl_str); - curl_free(curl_str); - curl_str = NULL; + // update name in sky + iter->second.mName = new_name; + + // update keys in day cycle + for(std::map<F32, LLWLParamKey>::iterator frame = cycle.mTimeMap.begin(); frame != cycle.mTimeMap.end(); ++frame) + { + if (frame->second == old_key) + { + frame->second = new_key; + } + } - escaped_filename += ".xml"; + // add to master sky map + mParamList[new_key] = iter->second; + } - std::string pathName(gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, "windlight/skies", escaped_filename)); - LL_DEBUGS2("AppInit", "Shaders") << "Loading WindLight sky setting from " << pathName << LL_ENDL; + final_references[new_key] = iter->second; + } - llifstream presetsXML; - presetsXML.open(pathName.c_str()); + lldebugs << "mDay after finalizing:" << llendl; + { + for (std::map<F32, LLWLParamKey>::iterator iter = mDay.mTimeMap.begin(); iter != mDay.mTimeMap.end(); ++iter) + { + LLWLParamKey& key = iter->second; + lldebugs << iter->first << "->" << key.name << llendl; + } + } - // That failed, try loading from the users area instead. - if(!presetsXML) + return final_references; +} + +// static +LLSD LLWLParamManager::createSkyMap(std::map<LLWLParamKey, LLWLParamSet> refs) +{ + LLSD skies = LLSD::emptyMap(); + for(std::map<LLWLParamKey, LLWLParamSet>::iterator iter = refs.begin(); iter != refs.end(); ++iter) { - pathName=gDirUtilp->getExpandedFilename( LL_PATH_USER_SETTINGS , "windlight/skies", escaped_filename); - LL_DEBUGS2("AppInit", "Shaders") << "Loading User WindLight sky setting from " << pathName << LL_ENDL; - presetsXML.clear(); - presetsXML.open(pathName.c_str()); + skies.insert(iter->first.name, iter->second.getAll()); } + return skies; +} - if (presetsXML) +void LLWLParamManager::addAllSkies(const LLWLParamKey::EScope scope, const LLSD& sky_presets) +{ + for(LLSD::map_const_iterator iter = sky_presets.beginMap(); iter != sky_presets.endMap(); ++iter) { - LLSD paramsData(LLSD::emptyMap()); + LLWLParamSet set; + set.setAll(iter->second); + mParamList[LLWLParamKey(iter->first, scope)] = set; + } +} + +void LLWLParamManager::refreshRegionPresets() +{ + // Remove all region sky presets because they may belong to a previously visited region. + clearParamSetsOfScope(LLEnvKey::SCOPE_REGION); - LLPointer<LLSDParser> parser = new LLSDXMLParser(); + // Add all sky presets belonging to the current region. + addAllSkies(LLEnvKey::SCOPE_REGION, LLEnvManagerNew::instance().getRegionSettings().getSkyMap()); +} - parser->parse(presetsXML, paramsData, LLSDSerialize::SIZE_UNLIMITED); +void LLWLParamManager::loadAllPresets() +{ + // First, load system (coming out of the box) sky presets. + loadPresetsFromDir(getSysDir()); - std::map<std::string, LLWLParamSet>::iterator mIt = mParamList.find(name); - if(mIt == mParamList.end()) + // Then load user presets. Note that user day presets will modify any system ones already loaded. + loadPresetsFromDir(getUserDir()); +} + +void LLWLParamManager::loadPresetsFromDir(const std::string& dir) +{ + LL_INFOS2("AppInit", "Shaders") << "Loading sky presets from " << dir << LL_ENDL; + + LLDirIterator dir_iter(dir, "*.xml"); + while (1) + { + std::string file; + if (!dir_iter.next(file)) { - addParamSet(name, paramsData); + break; // no more files } - else + + std::string path = dir + file; + if (!loadPreset(path)) { - setParamSet(name, paramsData); + llwarns << "Error loading sky preset from " << path << llendl; } - presetsXML.close(); - } - else + } +} + +bool LLWLParamManager::loadPreset(const std::string& path) +{ + llifstream xml_file; + std::string name(gDirUtilp->getBaseFileName(LLURI::unescape(path), /*strip_exten = */ true)); + + xml_file.open(path.c_str()); + if (!xml_file) { - llwarns << "Can't find " << name << llendl; - return; + return false; } - - if(propagate) + LL_DEBUGS2("AppInit", "Shaders") << "Loading sky " << name << LL_ENDL; + + LLSD params_data; + LLPointer<LLSDParser> parser = new LLSDXMLParser(); + parser->parse(xml_file, params_data, LLSDSerialize::SIZE_UNLIMITED); + xml_file.close(); + + LLWLParamKey key(name, LLEnvKey::SCOPE_LOCAL); + if (hasParamSet(key)) + { + setParamSet(key, params_data); + } + else { - getParamSet(name, mCurParams); - propagateParameters(); + addParamSet(key, params_data); } -} -void LLWLParamManager::savePreset(const std::string & name) -{ - // bugfix for SL-46920: preventing filenames that break stuff. - char * curl_str = curl_escape(name.c_str(), name.size()); - std::string escaped_filename(curl_str); - curl_free(curl_str); - curl_str = NULL; + return true; +} - escaped_filename += ".xml"; +void LLWLParamManager::savePreset(LLWLParamKey key) +{ + llassert(key.scope == LLEnvKey::SCOPE_LOCAL && !key.name.empty()); // make an empty llsd LLSD paramsData(LLSD::emptyMap()); - std::string pathName(gDirUtilp->getExpandedFilename( LL_PATH_USER_SETTINGS , "windlight/skies", escaped_filename)); + std::string pathName(getUserDir() + escapeString(key.name) + ".xml"); // fill it with LLSD windlight params - paramsData = mParamList[name].getAll(); + paramsData = mParamList[key].getAll(); // write to file llofstream presetsXML(pathName); @@ -283,6 +368,8 @@ void LLWLParamManager::updateShaderUniforms(LLGLSLShader * shader) } +static LLFastTimer::DeclareTimer FTM_UPDATE_WLPARAM("Update Windlight Params"); + void LLWLParamManager::propagateParameters(void) { LLFastTimer ftm(FTM_UPDATE_WLPARAM); @@ -362,7 +449,7 @@ void LLWLParamManager::update(LLViewerCamera * cam) mCurParams.updateCloudScrolling(); // update only if running - if(mAnimator.mIsRunning) + if(mAnimator.getIsRunning()) { mAnimator.update(mCurParams); } @@ -381,7 +468,7 @@ void LLWLParamManager::update(LLViewerCamera * cam) { dlfloater->syncMenu(); } - LLFloaterEnvSettings* envfloater = LLFloaterReg::findTypedInstance<LLFloaterEnvSettings>("env_settings"); + LLFloaterEnvSettings* envfloater = LLFloaterReg::findTypedInstance<LLFloaterEnvSettings>("old_env_settings"); if (envfloater) { envfloater->syncMenu(); @@ -389,12 +476,14 @@ void LLWLParamManager::update(LLViewerCamera * cam) F32 camYaw = cam->getYaw(); + stop_glerror(); + // *TODO: potential optimization - this block may only need to be // executed some of the time. For example for water shaders only. { F32 camYawDelta = mSunDeltaYaw * DEG_TO_RAD; - LLVector3 lightNorm3(mLightDir); + LLVector3 lightNorm3(mLightDir); lightNorm3 *= LLQuaternion(-(camYaw + camYawDelta), LLVector3(0.f, 1.f, 0.f)); mRotatedLightDir = LLVector4(lightNorm3, 0.f); @@ -412,17 +501,18 @@ void LLWLParamManager::update(LLViewerCamera * cam) } } -// static -void LLWLParamManager::initClass(void) +bool LLWLParamManager::applyDayCycleParams(const LLSD& params, LLEnvKey::EScope scope, F32 time) { - instance(); + mDay.loadDayCycle(params, scope); + resetAnimator(time, true); // set to specified time and start animator + return true; } -// static -void LLWLParamManager::cleanupClass() +bool LLWLParamManager::applySkyParams(const LLSD& params) { - delete sInstance; - sInstance = NULL; + mAnimator.deactivate(); + mCurParams.setAll(params); + return true; } void LLWLParamManager::resetAnimator(F32 curTime, bool run) @@ -432,133 +522,227 @@ void LLWLParamManager::resetAnimator(F32 curTime, bool run) return; } -bool LLWLParamManager::addParamSet(const std::string& name, LLWLParamSet& param) + +bool LLWLParamManager::addParamSet(const LLWLParamKey& key, LLWLParamSet& param) { // add a new one if not one there already - std::map<std::string, LLWLParamSet>::iterator mIt = mParamList.find(name); + std::map<LLWLParamKey, LLWLParamSet>::iterator mIt = mParamList.find(key); if(mIt == mParamList.end()) { - mParamList[name] = param; + llassert(!key.name.empty()); + // *TODO: validate params + mParamList[key] = param; + mPresetListChangeSignal(); return true; } return false; } -BOOL LLWLParamManager::addParamSet(const std::string& name, LLSD const & param) +BOOL LLWLParamManager::addParamSet(const LLWLParamKey& key, LLSD const & param) { - // add a new one if not one there already - std::map<std::string, LLWLParamSet>::const_iterator finder = mParamList.find(name); - if(finder == mParamList.end()) - { - mParamList[name].setAll(param); - return TRUE; - } - else - { - return FALSE; - } + LLWLParamSet param_set; + param_set.setAll(param); + return addParamSet(key, param_set); } -bool LLWLParamManager::getParamSet(const std::string& name, LLWLParamSet& param) +bool LLWLParamManager::getParamSet(const LLWLParamKey& key, LLWLParamSet& param) { // find it and set it - std::map<std::string, LLWLParamSet>::iterator mIt = mParamList.find(name); + std::map<LLWLParamKey, LLWLParamSet>::iterator mIt = mParamList.find(key); if(mIt != mParamList.end()) { - param = mParamList[name]; - param.mName = name; + param = mParamList[key]; + param.mName = key.name; return true; } return false; } -bool LLWLParamManager::setParamSet(const std::string& name, LLWLParamSet& param) +bool LLWLParamManager::hasParamSet(const LLWLParamKey& key) { - mParamList[name] = param; + LLWLParamSet dummy; + return getParamSet(key, dummy); +} + +bool LLWLParamManager::setParamSet(const LLWLParamKey& key, LLWLParamSet& param) +{ + llassert(!key.name.empty()); + // *TODO: validate params + mParamList[key] = param; return true; } -bool LLWLParamManager::setParamSet(const std::string& name, const LLSD & param) +bool LLWLParamManager::setParamSet(const LLWLParamKey& key, const LLSD & param) { + llassert(!key.name.empty()); + // *TODO: validate params + // quick, non robust (we won't be working with files, but assets) check + // this might not actually be true anymore.... if(!param.isMap()) { return false; } - mParamList[name].setAll(param); - - return true; + LLWLParamSet param_set; + param_set.setAll(param); + return setParamSet(key, param_set); } -bool LLWLParamManager::removeParamSet(const std::string& name, bool delete_from_disk) +void LLWLParamManager::removeParamSet(const LLWLParamKey& key, bool delete_from_disk) { + // *NOTE: Removing a sky preset invalidates day cycles that refer to it. + + if (key.scope == LLEnvKey::SCOPE_REGION) + { + llwarns << "Removing region skies not supported" << llendl; + llassert(key.scope == LLEnvKey::SCOPE_LOCAL); + return; + } + // remove from param list - std::map<std::string, LLWLParamSet>::iterator mIt = mParamList.find(name); - if(mIt != mParamList.end()) + std::map<LLWLParamKey, LLWLParamSet>::iterator it = mParamList.find(key); + if (it == mParamList.end()) { - mParamList.erase(mIt); + LL_WARNS("WindLight") << "No sky preset named " << key.name << LL_ENDL; + return; } - F32 key; + mParamList.erase(it); + mDay.removeReferencesTo(key); - // remove all references - bool stat = true; - do + // remove from file system if requested + if (delete_from_disk) { - // get it - stat = mDay.getKey(name, key); - if(stat == false) + std::string path_name(getUserDir()); + std::string escaped_name = escapeString(key.name); + + if(gDirUtilp->deleteFilesInDir(path_name, escaped_name + ".xml") < 1) { - break; + LL_WARNS("WindLight") << "Error removing sky preset " << key.name << " from disk" << LL_ENDL; } + } - // and remove - stat = mDay.removeKey(key); + // signal interested parties + mPresetListChangeSignal(); +} - } while(stat == true); - - if(delete_from_disk) +bool LLWLParamManager::isSystemPreset(const std::string& preset_name) const +{ + // *TODO: file system access is excessive here. + return gDirUtilp->fileExists(getSysDir() + escapeString(preset_name) + ".xml"); +} + +void LLWLParamManager::getPresetNames(preset_name_list_t& region, preset_name_list_t& user, preset_name_list_t& sys) const +{ + region.clear(); + user.clear(); + sys.clear(); + + for (std::map<LLWLParamKey, LLWLParamSet>::const_iterator it = mParamList.begin(); it != mParamList.end(); it++) { - std::string path_name(gDirUtilp->getExpandedFilename( LL_PATH_USER_SETTINGS , "windlight/skies", "")); - - // use full curl escaped name - char * curl_str = curl_escape(name.c_str(), name.size()); - std::string escaped_name(curl_str); - curl_free(curl_str); - curl_str = NULL; - - gDirUtilp->deleteFilesInDir(path_name, escaped_name + ".xml"); - } + const LLWLParamKey& key = it->first; + const std::string& name = key.name; - return true; + if (key.scope == LLEnvKey::SCOPE_REGION) + { + region.push_back(name); + } + else + { + if (isSystemPreset(name)) + { + sys.push_back(name); + } + else + { + user.push_back(name); + } + } + } } +void LLWLParamManager::getUserPresetNames(preset_name_list_t& user) const +{ + preset_name_list_t region, sys; // unused + getPresetNames(region, user, sys); +} -// static -LLWLParamManager * LLWLParamManager::instance() +void LLWLParamManager::getPresetKeys(preset_key_list_t& keys) const { - if(NULL == sInstance) + keys.clear(); + + for (std::map<LLWLParamKey, LLWLParamSet>::const_iterator it = mParamList.begin(); it != mParamList.end(); it++) { - sInstance = new LLWLParamManager(); + keys.push_back(it->first); + } +} + +boost::signals2::connection LLWLParamManager::setPresetListChangeCallback(const preset_list_signal_t::slot_type& cb) +{ + return mPresetListChangeSignal.connect(cb); +} + +// virtual static +void LLWLParamManager::initSingleton() +{ + LL_DEBUGS("Windlight") << "Initializing sky" << LL_ENDL; - sInstance->loadPresets(LLStringUtil::null); + loadAllPresets(); - // load the day - sInstance->mDay.loadDayCycle(std::string("Default.xml")); + // load the day + std::string preferred_day = LLEnvManagerNew::instance().getDayCycleName(); + if (!LLDayCycleManager::instance().getPreset(preferred_day, mDay)) + { + // Fall back to default. + llwarns << "No day cycle named " << preferred_day << ", falling back to defaults" << llendl; + mDay.loadDayCycleFromFile("Default.xml"); - // *HACK - sets cloud scrolling to what we want... fix this better in the future - sInstance->getParamSet("Default", sInstance->mCurParams); + // *TODO: Fix user preferences accordingly. + } - // set it to noon - sInstance->resetAnimator(0.5, true); + // *HACK - sets cloud scrolling to what we want... fix this better in the future + std::string sky = LLEnvManagerNew::instance().getSkyPresetName(); + if (!getParamSet(LLWLParamKey(sky, LLWLParamKey::SCOPE_LOCAL), mCurParams)) + { + llwarns << "No sky preset named " << sky << ", falling back to defaults" << llendl; + getParamSet(LLWLParamKey("Default", LLWLParamKey::SCOPE_LOCAL), mCurParams); - // but use linden time sets it to what the estate is - sInstance->mAnimator.mUseLindenTime = true; + // *TODO: Fix user preferences accordingly. } - return sInstance; + // set it to noon + resetAnimator(0.5, LLEnvManagerNew::instance().getUseDayCycle()); + + // but use linden time sets it to what the estate is + mAnimator.setTimeType(LLWLAnimator::TIME_LINDEN); + + LLEnvManagerNew::instance().usePrefs(); +} + +// static +std::string LLWLParamManager::getSysDir() +{ + return gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, "windlight/skies", ""); +} + +// static +std::string LLWLParamManager::getUserDir() +{ + return gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS , "windlight/skies", ""); +} + +// static +std::string LLWLParamManager::escapeString(const std::string& str) +{ + // Don't use LLURI::escape() because it doesn't encode '-' characters + // which may break handling of some system presets like "A-12AM". + char* curl_str = curl_escape(str.c_str(), str.size()); + std::string escaped_str(curl_str); + curl_free(curl_str); + + return escaped_str; } |