| // Copyright 2021 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 "rmad/utils/json_store.h" |
| |
| #include <memory> |
| #include <string> |
| #include <utility> |
| |
| #include <base/check.h> |
| #include <base/files/file_util.h> |
| #include <base/json/json_file_value_serializer.h> |
| #include <base/json/json_string_value_serializer.h> |
| #include <base/logging.h> |
| #include <base/notreached.h> |
| #include <base/values.h> |
| |
| namespace rmad { |
| |
| namespace { |
| |
| JsonStore::ReadError TranslateJsonFileReadErrors(const base::Value* value, |
| int error_code) { |
| if (!value) { |
| switch (error_code) { |
| case JSONFileValueDeserializer::JSON_ACCESS_DENIED: |
| return JsonStore::READ_ERROR_FILE_ACCESS_DENIED; |
| case JSONFileValueDeserializer::JSON_CANNOT_READ_FILE: |
| return JsonStore::READ_ERROR_FILE_OTHER; |
| case JSONFileValueDeserializer::JSON_FILE_LOCKED: |
| return JsonStore::READ_ERROR_FILE_LOCKED; |
| case JSONFileValueDeserializer::JSON_NO_SUCH_FILE: |
| return JsonStore::READ_ERROR_NO_SUCH_FILE; |
| default: |
| // JSONParser::JsonParseError errors. |
| return JsonStore::READ_ERROR_JSON_PARSE; |
| } |
| } |
| if (!value->is_dict()) |
| return JsonStore::READ_ERROR_JSON_TYPE; |
| return JsonStore::READ_ERROR_NONE; |
| } |
| |
| bool SerializeValue(const base::Value& value, std::string* output) { |
| JSONStringValueSerializer serializer(output); |
| serializer.set_pretty_print(false); |
| return serializer.Serialize(value); |
| } |
| |
| } // namespace |
| |
| struct JsonStore::ReadResult { |
| public: |
| ReadResult() = default; |
| ~ReadResult() = default; |
| |
| std::unique_ptr<base::Value> value; |
| JsonStore::ReadError read_error; |
| }; |
| |
| JsonStore::JsonStore(const base::FilePath& file_path) |
| : file_path_(file_path), |
| data_(base::Value::Type::DICTIONARY), |
| read_error_(READ_ERROR_NONE), |
| read_only_(false) { |
| InitFromFile(); |
| } |
| |
| bool JsonStore::SetValue(const std::string& key, base::Value&& value) { |
| DCHECK(data_.is_dict()); |
| if (read_only_) { |
| return false; |
| } |
| const base::Value* result = data_.FindKey(key); |
| if (!result || *result != value) { |
| data_.SetKey(key, std::move(value)); |
| return WriteToFile(); |
| } |
| return true; |
| } |
| |
| bool JsonStore::GetValue(const std::string& key, |
| const base::Value** value) const { |
| DCHECK(data_.is_dict()); |
| const base::Value* result = data_.FindKey(key); |
| if (!result) { |
| return false; |
| } |
| if (value) { |
| *value = result; |
| } |
| return true; |
| } |
| |
| bool JsonStore::GetValue(const std::string& key, base::Value* value) const { |
| const base::Value* result; |
| if (!GetValue(key, &result)) { |
| return false; |
| } |
| if (value) { |
| *value = result->Clone(); |
| } |
| return true; |
| } |
| |
| base::Value JsonStore::GetValues() const { |
| return data_.Clone(); |
| } |
| |
| bool JsonStore::Clear() { |
| data_ = base::Value(base::Value::Type::DICTIONARY); |
| return WriteToFile(); |
| } |
| |
| void JsonStore::InitFromFile() { |
| std::unique_ptr<JsonStore::ReadResult> read_result = ReadFromFile(); |
| read_error_ = read_result->read_error; |
| switch (read_error_) { |
| case READ_ERROR_JSON_PARSE: |
| case READ_ERROR_JSON_TYPE: |
| case READ_ERROR_FILE_ACCESS_DENIED: |
| case READ_ERROR_FILE_LOCKED: |
| case READ_ERROR_FILE_OTHER: |
| read_only_ = true; |
| break; |
| case READ_ERROR_NONE: |
| data_ = std::move(*read_result->value); |
| break; |
| case READ_ERROR_NO_SUCH_FILE: |
| data_ = base::Value(base::Value::Type::DICTIONARY); |
| break; |
| case READ_ERROR_MAX_ENUM: |
| NOTREACHED(); |
| break; |
| } |
| DLOG(INFO) << "JsonStore::InitFromFile complete."; |
| } |
| |
| std::unique_ptr<JsonStore::ReadResult> JsonStore::ReadFromFile() { |
| auto read_result = std::make_unique<JsonStore::ReadResult>(); |
| JSONFileValueDeserializer deserializer(file_path_); |
| int error_code = 0; |
| std::string error_msg; |
| read_result->value = deserializer.Deserialize(&error_code, &error_msg); |
| read_result->read_error = |
| TranslateJsonFileReadErrors(read_result->value.get(), error_code); |
| return read_result; |
| } |
| |
| bool JsonStore::WriteToFile() { |
| if (read_only_) |
| return false; |
| |
| std::string serialized_data; |
| if (!SerializeValue(data_, &serialized_data)) { |
| DLOG(ERROR) << "JsonStore::WriteToFile failed to serialize data."; |
| return false; |
| } |
| return base::WriteFile(file_path_, serialized_data); |
| } |
| |
| } // namespace rmad |