Home | History | Annotate | Download | only in brillo
      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