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