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