| /* | 
 |  *  Copyright 2008 The WebRTC Project Authors. All rights reserved. | 
 |  * | 
 |  *  Use of this source code is governed by a BSD-style license | 
 |  *  that can be found in the LICENSE file in the root of the source | 
 |  *  tree. An additional intellectual property rights grant can be found | 
 |  *  in the file PATENTS.  All contributing project authors may | 
 |  *  be found in the AUTHORS file in the root of the source tree. | 
 |  */ | 
 |  | 
 | #include "rtc_base/optionsfile.h" | 
 |  | 
 | #include <ctype.h> | 
 |  | 
 | #include "rtc_base/logging.h" | 
 | #include "rtc_base/stream.h" | 
 | #include "rtc_base/stringencode.h" | 
 |  | 
 | namespace rtc { | 
 |  | 
 | OptionsFile::OptionsFile(const std::string &path) : path_(path) { | 
 | } | 
 |  | 
 | OptionsFile::~OptionsFile() = default; | 
 |  | 
 | bool OptionsFile::Load() { | 
 |   options_.clear(); | 
 |   // Open file. | 
 |   FileStream stream; | 
 |   int err; | 
 |   if (!stream.Open(path_, "r", &err)) { | 
 |     RTC_LOG_F(LS_WARNING) << "Could not open file, err=" << err; | 
 |     // We do not consider this an error because we expect there to be no file | 
 |     // until the user saves a setting. | 
 |     return true; | 
 |   } | 
 |   // Read in all its data. | 
 |   std::string line; | 
 |   StreamResult res; | 
 |   for (;;) { | 
 |     res = stream.ReadLine(&line); | 
 |     if (res != SR_SUCCESS) { | 
 |       break; | 
 |     } | 
 |     size_t equals_pos = line.find('='); | 
 |     if (equals_pos == std::string::npos) { | 
 |       // We do not consider this an error. Instead we ignore the line and | 
 |       // keep going. | 
 |       RTC_LOG_F(LS_WARNING) << "Ignoring malformed line in " << path_; | 
 |       continue; | 
 |     } | 
 |     std::string key(line, 0, equals_pos); | 
 |     std::string value(line, equals_pos + 1, line.length() - (equals_pos + 1)); | 
 |     options_[key] = value; | 
 |   } | 
 |   if (res != SR_EOS) { | 
 |     RTC_LOG_F(LS_ERROR) << "Error when reading from file"; | 
 |     return false; | 
 |   } else { | 
 |     return true; | 
 |   } | 
 | } | 
 |  | 
 | bool OptionsFile::Save() { | 
 |   // Open file. | 
 |   FileStream stream; | 
 |   int err; | 
 |   if (!stream.Open(path_, "w", &err)) { | 
 |     RTC_LOG_F(LS_ERROR) << "Could not open file, err=" << err; | 
 |     return false; | 
 |   } | 
 |   // Write out all the data. | 
 |   StreamResult res = SR_SUCCESS; | 
 |   size_t written; | 
 |   int error; | 
 |   for (OptionsMap::const_iterator i = options_.begin(); i != options_.end(); | 
 |        ++i) { | 
 |     res = stream.WriteAll(i->first.c_str(), i->first.length(), &written, | 
 |         &error); | 
 |     if (res != SR_SUCCESS) { | 
 |       break; | 
 |     } | 
 |     res = stream.WriteAll("=", 1, &written, &error); | 
 |     if (res != SR_SUCCESS) { | 
 |       break; | 
 |     } | 
 |     res = stream.WriteAll(i->second.c_str(), i->second.length(), &written, | 
 |         &error); | 
 |     if (res != SR_SUCCESS) { | 
 |       break; | 
 |     } | 
 |     res = stream.WriteAll("\n", 1, &written, &error); | 
 |     if (res != SR_SUCCESS) { | 
 |       break; | 
 |     } | 
 |   } | 
 |   if (res != SR_SUCCESS) { | 
 |     RTC_LOG_F(LS_ERROR) << "Unable to write to file"; | 
 |     return false; | 
 |   } else { | 
 |     return true; | 
 |   } | 
 | } | 
 |  | 
 | bool OptionsFile::IsLegalName(const std::string &name) { | 
 |   for (size_t pos = 0; pos < name.length(); ++pos) { | 
 |     if (name[pos] == '\n' || name[pos] == '\\' || name[pos] == '=') { | 
 |       // Illegal character. | 
 |       RTC_LOG(LS_WARNING) << "Ignoring operation for illegal option " << name; | 
 |       return false; | 
 |     } | 
 |   } | 
 |   return true; | 
 | } | 
 |  | 
 | bool OptionsFile::IsLegalValue(const std::string &value) { | 
 |   for (size_t pos = 0; pos < value.length(); ++pos) { | 
 |     if (value[pos] == '\n' || value[pos] == '\\') { | 
 |       // Illegal character. | 
 |       RTC_LOG(LS_WARNING) << "Ignoring operation for illegal value " << value; | 
 |       return false; | 
 |     } | 
 |   } | 
 |   return true; | 
 | } | 
 |  | 
 | bool OptionsFile::GetStringValue(const std::string& option, | 
 |                                  std::string *out_val) const { | 
 |   RTC_LOG(LS_VERBOSE) << "OptionsFile::GetStringValue " << option; | 
 |   if (!IsLegalName(option)) { | 
 |     return false; | 
 |   } | 
 |   OptionsMap::const_iterator i = options_.find(option); | 
 |   if (i == options_.end()) { | 
 |     return false; | 
 |   } | 
 |   *out_val = i->second; | 
 |   return true; | 
 | } | 
 |  | 
 | bool OptionsFile::GetIntValue(const std::string& option, | 
 |                               int *out_val) const { | 
 |   RTC_LOG(LS_VERBOSE) << "OptionsFile::GetIntValue " << option; | 
 |   if (!IsLegalName(option)) { | 
 |     return false; | 
 |   } | 
 |   OptionsMap::const_iterator i = options_.find(option); | 
 |   if (i == options_.end()) { | 
 |     return false; | 
 |   } | 
 |   return FromString(i->second, out_val); | 
 | } | 
 |  | 
 | bool OptionsFile::SetStringValue(const std::string& option, | 
 |                                  const std::string& value) { | 
 |   RTC_LOG(LS_VERBOSE) << "OptionsFile::SetStringValue " << option << ":" | 
 |                       << value; | 
 |   if (!IsLegalName(option) || !IsLegalValue(value)) { | 
 |     return false; | 
 |   } | 
 |   options_[option] = value; | 
 |   return true; | 
 | } | 
 |  | 
 | bool OptionsFile::SetIntValue(const std::string& option, | 
 |                               int value) { | 
 |   RTC_LOG(LS_VERBOSE) << "OptionsFile::SetIntValue " << option << ":" << value; | 
 |   if (!IsLegalName(option)) { | 
 |     return false; | 
 |   } | 
 |   return ToString(value, &options_[option]); | 
 | } | 
 |  | 
 | bool OptionsFile::RemoveValue(const std::string& option) { | 
 |   RTC_LOG(LS_VERBOSE) << "OptionsFile::RemoveValue " << option; | 
 |   if (!IsLegalName(option)) { | 
 |     return false; | 
 |   } | 
 |   options_.erase(option); | 
 |   return true; | 
 | } | 
 |  | 
 | }  // namespace rtc |