blob: 1f65498f003008285709521b72fb77fbfd39dd30 [file] [log] [blame]
// Copyright 2023 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "services/data_decoder/cbor_parser_impl.h"
#include <algorithm>
#include <cstddef>
#include <cstdint>
#include <cstdio>
#include <memory>
#include <optional>
#include <string>
#include <utility>
#include <vector>
#include "base/value_iterators.h"
#include "base/values.h"
#include "components/cbor/reader.h"
#include "components/cbor/values.h"
#include "mojo/public/cpp/base/big_buffer.h"
namespace data_decoder {
namespace {
std::optional<base::Value> ConvertToBaseValue(const cbor::Value& cbor_value) {
switch (cbor_value.type()) {
case cbor::Value::Type::UNSIGNED:
case cbor::Value::Type::NEGATIVE:
return base::Value(static_cast<int>(cbor_value.GetInteger()));
case cbor::Value::Type::ARRAY: {
const std::vector<cbor::Value>& input_array = cbor_value.GetArray();
base::Value::List output_array;
for (const auto& el : input_array) {
std::optional<base::Value> converted_el = ConvertToBaseValue(el);
if (!converted_el.has_value()) {
return std::nullopt;
}
output_array.Append(*std::move(converted_el));
}
return base::Value(std::move(output_array));
}
case cbor::Value::Type::MAP: {
const cbor::Value::MapValue& input_map = cbor_value.GetMap();
base::Value::Dict output_map;
for (const auto& el : input_map) {
std::string key;
if (el.first.is_string()) {
key = el.first.GetString();
} else if (el.first.is_bytestring()) {
key = el.first.GetBytestringAsString();
} else {
// not supporting anything that is not a string or a bytestring at the
// moment.
return std::nullopt;
}
std::optional<base::Value> converted_value =
ConvertToBaseValue(el.second);
if (!converted_value.has_value()) {
return std::nullopt;
}
output_map.Set(key, *std::move(converted_value));
}
return base::Value(std::move(output_map));
}
case cbor::Value::Type::SIMPLE_VALUE:
switch (cbor_value.GetSimpleValue()) {
case cbor::Value::SimpleValue::FALSE_VALUE:
return base::Value(false);
case cbor::Value::SimpleValue::TRUE_VALUE:
return base::Value(true);
case cbor::Value::SimpleValue::UNDEFINED:
case cbor::Value::SimpleValue::NULL_VALUE:
return std::nullopt;
}
case cbor::Value::Type::STRING:
return base::Value(cbor_value.GetString());
case cbor::Value::Type::BYTE_STRING:
return base::Value(cbor_value.GetBytestring());
case cbor::Value::Type::FLOAT_VALUE:
return base::Value(cbor_value.GetDouble());
default:
return std::nullopt;
}
}
} // namespace
CborParserImpl::CborParserImpl() = default;
CborParserImpl::~CborParserImpl() = default;
void CborParserImpl::Parse(mojo_base::BigBuffer cbor, ParseCallback callback) {
cbor::Reader::DecoderError error;
cbor::Reader::Config config;
config.error_code_out = &error;
config.allow_floating_point = true;
auto ret = cbor::Reader::Read(cbor, config);
if (!ret.has_value()) {
std::move(callback).Run(std::nullopt,
cbor::Reader::ErrorCodeToString(error));
return;
}
std::optional<::base::Value> temp_value = ConvertToBaseValue(*ret);
if (temp_value.has_value()) {
std::move(callback).Run(std::move(*temp_value), std::nullopt);
} else {
std::move(callback).Run(std::nullopt, "Error unexpected CBOR value.");
}
}
} // namespace data_decoder