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