| // Copyright (c) 2010 The Chromium OS Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "brillo/key_value_store.h" |
| |
| #include <string> |
| #include <vector> |
| |
| #include <base/check.h> |
| #include <base/files/file_util.h> |
| #include <base/files/important_file_writer.h> |
| #include <base/strings/string_split.h> |
| #include <base/strings/string_util.h> |
| #include <brillo/strings/string_utils.h> |
| #include <brillo/map_utils.h> |
| |
| using std::string; |
| using std::vector; |
| |
| namespace brillo { |
| |
| namespace { |
| |
| // Values used for booleans. |
| const char kTrueValue[] = "true"; |
| const char kFalseValue[] = "false"; |
| |
| // Returns a copy of |key| with leading and trailing whitespace removed. |
| string TrimKey(const string& key) { |
| string trimmed_key; |
| base::TrimWhitespaceASCII(key, base::TRIM_ALL, &trimmed_key); |
| CHECK(!trimmed_key.empty()); |
| return trimmed_key; |
| } |
| |
| } // namespace |
| |
| KeyValueStore::KeyValueStore() = default; |
| KeyValueStore::~KeyValueStore() = default; |
| KeyValueStore::KeyValueStore(KeyValueStore&&) = default; |
| KeyValueStore& KeyValueStore::operator=(KeyValueStore&&) = default; |
| |
| bool KeyValueStore::Load(const base::FilePath& path) { |
| string file_data; |
| if (!base::ReadFileToString(path, &file_data)) |
| return false; |
| return LoadFromString(file_data); |
| } |
| |
| bool KeyValueStore::LoadFromString(const std::string& data) { |
| // Split along '\n', then along '='. |
| vector<string> lines = base::SplitString(data, "\n", base::KEEP_WHITESPACE, |
| base::SPLIT_WANT_ALL); |
| for (auto it = lines.begin(); it != lines.end(); ++it) { |
| std::string line; |
| base::TrimWhitespaceASCII(*it, base::TRIM_LEADING, &line); |
| if (line.empty() || line.front() == '#') |
| continue; |
| |
| std::string key; |
| std::string value; |
| if (!string_utils::SplitAtFirst(line, "=", &key, &value, false)) |
| return false; |
| |
| base::TrimWhitespaceASCII(key, base::TRIM_TRAILING, &key); |
| if (key.empty()) |
| return false; |
| |
| // Append additional lines to the value as long as we see trailing |
| // backslashes. |
| while (!value.empty() && value.back() == '\\') { |
| ++it; |
| if (it == lines.end() || it->empty()) |
| return false; |
| value.pop_back(); |
| value += *it; |
| } |
| |
| store_[key] = value; |
| } |
| return true; |
| } |
| |
| bool KeyValueStore::Save(const base::FilePath& path) const { |
| return base::ImportantFileWriter::WriteFileAtomically(path, SaveToString()); |
| } |
| |
| string KeyValueStore::SaveToString() const { |
| string data; |
| for (const auto& key_value : store_) |
| data += key_value.first + "=" + key_value.second + "\n"; |
| return data; |
| } |
| |
| void KeyValueStore::Clear() { |
| store_.clear(); |
| } |
| |
| bool KeyValueStore::GetString(const string& key, string* value) const { |
| const auto key_value = store_.find(TrimKey(key)); |
| if (key_value == store_.end()) |
| return false; |
| *value = key_value->second; |
| return true; |
| } |
| |
| void KeyValueStore::SetString(const string& key, const string& value) { |
| store_[TrimKey(key)] = value; |
| } |
| |
| bool KeyValueStore::GetBoolean(const string& key, bool* value) const { |
| string string_value; |
| if (!GetString(key, &string_value)) |
| return false; |
| |
| if (string_value == kTrueValue) { |
| *value = true; |
| return true; |
| } else if (string_value == kFalseValue) { |
| *value = false; |
| return true; |
| } |
| return false; |
| } |
| |
| void KeyValueStore::SetBoolean(const string& key, bool value) { |
| SetString(key, value ? kTrueValue : kFalseValue); |
| } |
| |
| std::vector<std::string> KeyValueStore::GetKeys() const { |
| return GetMapKeysAsVector(store_); |
| } |
| |
| } // namespace brillo |