Home | History | Annotate | Download | only in base
      1 /*
      2  * libjingle
      3  * Copyright 2008, Google Inc.
      4  *
      5  * Redistribution and use in source and binary forms, with or without
      6  * modification, are permitted provided that the following conditions are met:
      7  *
      8  *  1. Redistributions of source code must retain the above copyright notice,
      9  *     this list of conditions and the following disclaimer.
     10  *  2. Redistributions in binary form must reproduce the above copyright notice,
     11  *     this list of conditions and the following disclaimer in the documentation
     12  *     and/or other materials provided with the distribution.
     13  *  3. The name of the author may not be used to endorse or promote products
     14  *     derived from this software without specific prior written permission.
     15  *
     16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
     17  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
     18  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
     19  * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     20  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
     21  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
     22  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
     23  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
     24  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
     25  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     26  */
     27 
     28 #include "talk/base/optionsfile.h"
     29 
     30 #include <ctype.h>
     31 
     32 #include "talk/base/logging.h"
     33 #include "talk/base/stream.h"
     34 #include "talk/base/stringencode.h"
     35 
     36 namespace talk_base {
     37 
     38 OptionsFile::OptionsFile(const std::string &path) : path_(path) {
     39 }
     40 
     41 bool OptionsFile::Load() {
     42   options_.clear();
     43   // Open file.
     44   FileStream stream;
     45   int err;
     46   if (!stream.Open(path_, "r", &err)) {
     47     LOG_F(LS_WARNING) << "Could not open file, err=" << err;
     48     // We do not consider this an error because we expect there to be no file
     49     // until the user saves a setting.
     50     return true;
     51   }
     52   // Read in all its data.
     53   std::string line;
     54   StreamResult res;
     55   for (;;) {
     56     res = stream.ReadLine(&line);
     57     if (res != SR_SUCCESS) {
     58       break;
     59     }
     60     size_t equals_pos = line.find('=');
     61     if (equals_pos == std::string::npos) {
     62       // We do not consider this an error. Instead we ignore the line and
     63       // keep going.
     64       LOG_F(LS_WARNING) << "Ignoring malformed line in " << path_;
     65       continue;
     66     }
     67     std::string key(line, 0, equals_pos);
     68     std::string value(line, equals_pos + 1, line.length() - (equals_pos + 1));
     69     options_[key] = value;
     70   }
     71   if (res != SR_EOS) {
     72     LOG_F(LS_ERROR) << "Error when reading from file";
     73     return false;
     74   } else {
     75     return true;
     76   }
     77 }
     78 
     79 bool OptionsFile::Save() {
     80   // Open file.
     81   FileStream stream;
     82   int err;
     83   if (!stream.Open(path_, "w", &err)) {
     84     LOG_F(LS_ERROR) << "Could not open file, err=" << err;
     85     return false;
     86   }
     87   // Write out all the data.
     88   StreamResult res = SR_SUCCESS;
     89   size_t written;
     90   int error;
     91   for (OptionsMap::const_iterator i = options_.begin(); i != options_.end();
     92        ++i) {
     93     res = stream.WriteAll(i->first.c_str(), i->first.length(), &written,
     94         &error);
     95     if (res != SR_SUCCESS) {
     96       break;
     97     }
     98     res = stream.WriteAll("=", 1, &written, &error);
     99     if (res != SR_SUCCESS) {
    100       break;
    101     }
    102     res = stream.WriteAll(i->second.c_str(), i->second.length(), &written,
    103         &error);
    104     if (res != SR_SUCCESS) {
    105       break;
    106     }
    107     res = stream.WriteAll("\n", 1, &written, &error);
    108     if (res != SR_SUCCESS) {
    109       break;
    110     }
    111   }
    112   if (res != SR_SUCCESS) {
    113     LOG_F(LS_ERROR) << "Unable to write to file";
    114     return false;
    115   } else {
    116     return true;
    117   }
    118 }
    119 
    120 bool OptionsFile::IsLegalName(const std::string &name) {
    121   for (size_t pos = 0; pos < name.length(); ++pos) {
    122     if (name[pos] == '\n' || name[pos] == '\\' || name[pos] == '=') {
    123       // Illegal character.
    124       LOG(LS_WARNING) << "Ignoring operation for illegal option " << name;
    125       return false;
    126     }
    127   }
    128   return true;
    129 }
    130 
    131 bool OptionsFile::IsLegalValue(const std::string &value) {
    132   for (size_t pos = 0; pos < value.length(); ++pos) {
    133     if (value[pos] == '\n' || value[pos] == '\\') {
    134       // Illegal character.
    135       LOG(LS_WARNING) << "Ignoring operation for illegal value " << value;
    136       return false;
    137     }
    138   }
    139   return true;
    140 }
    141 
    142 bool OptionsFile::GetStringValue(const std::string& option,
    143                                  std::string *out_val) const {
    144   LOG(LS_VERBOSE) << "OptionsFile::GetStringValue "
    145                   << option;
    146   if (!IsLegalName(option)) {
    147     return false;
    148   }
    149   OptionsMap::const_iterator i = options_.find(option);
    150   if (i == options_.end()) {
    151     return false;
    152   }
    153   *out_val = i->second;
    154   return true;
    155 }
    156 
    157 bool OptionsFile::GetIntValue(const std::string& option,
    158                               int *out_val) const {
    159   LOG(LS_VERBOSE) << "OptionsFile::GetIntValue "
    160                   << option;
    161   if (!IsLegalName(option)) {
    162     return false;
    163   }
    164   OptionsMap::const_iterator i = options_.find(option);
    165   if (i == options_.end()) {
    166     return false;
    167   }
    168   return FromString(i->second, out_val);
    169 }
    170 
    171 bool OptionsFile::SetStringValue(const std::string& option,
    172                                  const std::string& value) {
    173   LOG(LS_VERBOSE) << "OptionsFile::SetStringValue "
    174                   << option << ":" << value;
    175   if (!IsLegalName(option) || !IsLegalValue(value)) {
    176     return false;
    177   }
    178   options_[option] = value;
    179   return true;
    180 }
    181 
    182 bool OptionsFile::SetIntValue(const std::string& option,
    183                               int value) {
    184   LOG(LS_VERBOSE) << "OptionsFile::SetIntValue "
    185                   << option << ":" << value;
    186   if (!IsLegalName(option)) {
    187     return false;
    188   }
    189   return ToString(value, &options_[option]);
    190 }
    191 
    192 bool OptionsFile::RemoveValue(const std::string& option) {
    193   LOG(LS_VERBOSE) << "OptionsFile::RemoveValue " << option;
    194   if (!IsLegalName(option)) {
    195     return false;
    196   }
    197   options_.erase(option);
    198   return true;
    199 }
    200 
    201 }  // namespace talk_base
    202