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 18using std::map; 19using std::string; 20using std::vector; 21 22namespace brillo { 23 24namespace { 25 26// Values used for booleans. 27const char kTrueValue[] = "true"; 28const char kFalseValue[] = "false"; 29 30// Returns a copy of |key| with leading and trailing whitespace removed. 31string 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 40bool 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 47bool 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 81bool KeyValueStore::Save(const base::FilePath& path) const { 82 return base::ImportantFileWriter::WriteFileAtomically(path, SaveToString()); 83} 84 85string 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 92bool 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 100void KeyValueStore::SetString(const string& key, const string& value) { 101 store_[TrimKey(key)] = value; 102} 103 104bool 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 119void KeyValueStore::SetBoolean(const string& key, bool value) { 120 SetString(key, value ? kTrueValue : kFalseValue); 121} 122 123std::vector<std::string> KeyValueStore::GetKeys() const { 124 return GetMapKeysAsVector(store_); 125} 126 127} // namespace brillo 128