blob: c3cbbe3ab88f7a0ef58890bd6a947655052c56ee [file] [log] [blame]
// 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