1 // Copyright (c) 2010 The Chromium OS Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "brillo/key_value_store.h" 6 7 #include <map> 8 #include <string> 9 #include <vector> 10 11 #include <base/files/file_util.h> 12 #include <base/files/important_file_writer.h> 13 #include <base/strings/string_split.h> 14 #include <base/strings/string_util.h> 15 #include <brillo/strings/string_utils.h> 16 #include <brillo/map_utils.h> 17 18 using std::map; 19 using std::string; 20 using std::vector; 21 22 namespace brillo { 23 24 namespace { 25 26 // Values used for booleans. 27 const char kTrueValue[] = "true"; 28 const char kFalseValue[] = "false"; 29 30 // Returns a copy of |key| with leading and trailing whitespace removed. 31 string TrimKey(const string& key) { 32 string trimmed_key; 33 base::TrimWhitespaceASCII(key, base::TRIM_ALL, &trimmed_key); 34 CHECK(!trimmed_key.empty()); 35 return trimmed_key; 36 } 37 38 } // namespace 39 40 bool KeyValueStore::Load(const base::FilePath& path) { 41 string file_data; 42 if (!base::ReadFileToString(path, &file_data)) 43 return false; 44 return LoadFromString(file_data); 45 } 46 47 bool KeyValueStore::LoadFromString(const std::string& data) { 48 // Split along '\n', then along '='. 49 vector<string> lines = base::SplitString(data, "\n", base::KEEP_WHITESPACE, 50 base::SPLIT_WANT_ALL); 51 for (auto it = lines.begin(); it != lines.end(); ++it) { 52 std::string line; 53 base::TrimWhitespaceASCII(*it, base::TRIM_LEADING, &line); 54 if (line.empty() || line.front() == '#') 55 continue; 56 57 std::string key; 58 std::string value; 59 if (!string_utils::SplitAtFirst(line, "=", &key, &value, false)) 60 return false; 61 62 base::TrimWhitespaceASCII(key, base::TRIM_TRAILING, &key); 63 if (key.empty()) 64 return false; 65 66 // Append additional lines to the value as long as we see trailing 67 // backslashes. 68 while (!value.empty() && value.back() == '\\') { 69 ++it; 70 if (it == lines.end() || it->empty()) 71 return false; 72 value.pop_back(); 73 value += *it; 74 } 75 76 store_[key] = value; 77 } 78 return true; 79 } 80 81 bool KeyValueStore::Save(const base::FilePath& path) const { 82 return base::ImportantFileWriter::WriteFileAtomically(path, SaveToString()); 83 } 84 85 string KeyValueStore::SaveToString() const { 86 string data; 87 for (const auto& key_value : store_) 88 data += key_value.first + "=" + key_value.second + "\n"; 89 return data; 90 } 91 92 bool KeyValueStore::GetString(const string& key, string* value) const { 93 const auto key_value = store_.find(TrimKey(key)); 94 if (key_value == store_.end()) 95 return false; 96 *value = key_value->second; 97 return true; 98 } 99 100 void KeyValueStore::SetString(const string& key, const string& value) { 101 store_[TrimKey(key)] = value; 102 } 103 104 bool KeyValueStore::GetBoolean(const string& key, bool* value) const { 105 string string_value; 106 if (!GetString(key, &string_value)) 107 return false; 108 109 if (string_value == kTrueValue) { 110 *value = true; 111 return true; 112 } else if (string_value == kFalseValue) { 113 *value = false; 114 return true; 115 } 116 return false; 117 } 118 119 void KeyValueStore::SetBoolean(const string& key, bool value) { 120 SetString(key, value ? kTrueValue : kFalseValue); 121 } 122 123 std::vector<std::string> KeyValueStore::GetKeys() const { 124 return GetMapKeysAsVector(store_); 125 } 126 127 } // namespace brillo 128