910e62b5创建于 1月15日历史提交
// 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