1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219
|
// Copyright 2017 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef COMPONENTS_CBOR_VALUES_H_
#define COMPONENTS_CBOR_VALUES_H_
#include <stdint.h>
#include <string>
#include <string_view>
#include <tuple>
#include <vector>
#include "base/check.h"
#include "base/containers/flat_map.h"
#include "base/containers/span.h"
#include "base/notreached.h"
#include "components/cbor/cbor_export.h"
namespace cbor {
// A class for Concise Binary Object Representation (CBOR) values.
// This does not support indefinite-length encodings.
class CBOR_EXPORT Value {
public:
struct Less {
// Comparison predicate to order keys in a dictionary as required by the
// canonical CBOR order defined in
// https://tools.ietf.org/html/rfc7049#section-3.9
// TODO(crbug.com/40560917): Clarify where this stands.
bool operator()(const Value& a, const Value& b) const {
// The current implementation only supports integer, text string, byte
// string and invalid UTF8 keys.
DCHECK((a.is_integer() || a.is_string() || a.is_bytestring() ||
a.is_invalid_utf8()) &&
(b.is_integer() || b.is_string() || b.is_bytestring() ||
b.is_invalid_utf8()));
// Below text from https://tools.ietf.org/html/rfc7049 errata 4409:
// * If the major types are different, the one with the lower value
// in numerical order sorts earlier.
if (a.type() != b.type())
return a.type() < b.type();
// * If two keys have different lengths, the shorter one sorts
// earlier;
// * If two keys have the same length, the one with the lower value
// in (byte-wise) lexical order sorts earlier.
switch (a.type()) {
case Type::UNSIGNED:
// For unsigned integers, the smaller value has shorter length,
// and (byte-wise) lexical representation.
return a.GetInteger() < b.GetInteger();
case Type::NEGATIVE:
// For negative integers, the value closer to zero has shorter length,
// and (byte-wise) lexical representation.
return a.GetInteger() > b.GetInteger();
case Type::STRING: {
const auto& a_str = a.GetString();
const size_t a_length = a_str.size();
const auto& b_str = b.GetString();
const size_t b_length = b_str.size();
return std::tie(a_length, a_str) < std::tie(b_length, b_str);
}
case Type::BYTE_STRING: {
const auto& a_str = a.GetBytestring();
const size_t a_length = a_str.size();
const auto& b_str = b.GetBytestring();
const size_t b_length = b_str.size();
return std::tie(a_length, a_str) < std::tie(b_length, b_str);
}
case Type::INVALID_UTF8: {
const auto& a_str = a.GetInvalidUTF8();
const size_t a_length = a_str.size();
const auto& b_str = b.GetInvalidUTF8();
const size_t b_length = b_str.size();
return std::tie(a_length, a_str) < std::tie(b_length, b_str);
}
default:
break;
}
NOTREACHED();
}
using is_transparent = void;
};
using BinaryValue = std::vector<uint8_t>;
using ArrayValue = std::vector<Value>;
using MapValue = base::flat_map<Value, Value, Less>;
enum class Type {
UNSIGNED = 0,
NEGATIVE = 1,
BYTE_STRING = 2,
STRING = 3,
ARRAY = 4,
MAP = 5,
TAG = 6,
SIMPLE_VALUE = 7,
// In CBOR floating types also have major type 7, but we separate them here
// for simplicity.
FLOAT_VALUE = 70,
NONE = -1,
INVALID_UTF8 = -2,
};
enum class SimpleValue {
FALSE_VALUE = 20,
TRUE_VALUE = 21,
NULL_VALUE = 22,
UNDEFINED = 23,
};
// Returns a Value with Type::INVALID_UTF8. This factory method lets tests
// encode such a value as a CBOR string. It should never be used outside of
// tests since encoding may yield invalid CBOR data.
static Value InvalidUTF8StringValueForTesting(std::string_view in_string);
Value(Value&& that) noexcept;
Value() noexcept; // A NONE value.
explicit Value(Type type);
explicit Value(SimpleValue in_simple);
explicit Value(bool boolean_value);
explicit Value(double in_float);
explicit Value(int integer_value);
explicit Value(int64_t integer_value);
explicit Value(uint64_t integer_value) = delete;
explicit Value(base::span<const uint8_t> in_bytes);
explicit Value(BinaryValue&& in_bytes) noexcept;
explicit Value(const char* in_string, Type type = Type::STRING);
explicit Value(std::string&& in_string, Type type = Type::STRING) noexcept;
explicit Value(std::string_view in_string, Type type = Type::STRING);
explicit Value(const ArrayValue& in_array);
explicit Value(ArrayValue&& in_array) noexcept;
explicit Value(const MapValue& in_map);
explicit Value(MapValue&& in_map) noexcept;
Value& operator=(Value&& that) noexcept;
Value(const Value&) = delete;
Value& operator=(const Value&) = delete;
~Value();
// Value's copy constructor and copy assignment operator are deleted.
// Use this to obtain a deep copy explicitly.
Value Clone() const;
// Returns the type of the value stored by the current Value object.
Type type() const { return type_; }
// Returns true if the current object represents a given type.
bool is_type(Type type) const { return type == type_; }
bool is_none() const { return type() == Type::NONE; }
bool is_invalid_utf8() const { return type() == Type::INVALID_UTF8; }
bool is_simple() const { return type() == Type::SIMPLE_VALUE; }
bool is_bool() const {
return is_simple() && (simple_value_ == SimpleValue::TRUE_VALUE ||
simple_value_ == SimpleValue::FALSE_VALUE);
}
bool is_double() const { return type() == Type::FLOAT_VALUE; }
bool is_unsigned() const { return type() == Type::UNSIGNED; }
bool is_negative() const { return type() == Type::NEGATIVE; }
bool is_integer() const { return is_unsigned() || is_negative(); }
bool is_bytestring() const { return type() == Type::BYTE_STRING; }
bool is_string() const { return type() == Type::STRING; }
bool is_array() const { return type() == Type::ARRAY; }
bool is_map() const { return type() == Type::MAP; }
// These will all fatally assert if the type doesn't match.
SimpleValue GetSimpleValue() const;
bool GetBool() const;
double GetDouble() const;
const int64_t& GetInteger() const;
const int64_t& GetUnsigned() const;
const int64_t& GetNegative() const;
const BinaryValue& GetBytestring() const;
std::string_view GetBytestringAsString() const;
// Returned string may contain NUL characters.
const std::string& GetString() const;
const ArrayValue& GetArray() const;
const MapValue& GetMap() const;
const BinaryValue& GetInvalidUTF8() const;
private:
friend class Reader;
// This constructor allows INVALID_UTF8 values to be created, which only
// |Reader| and InvalidUTF8StringValueForTesting() may do.
Value(base::span<const uint8_t> in_bytes, Type type);
Type type_;
union {
SimpleValue simple_value_;
int64_t integer_value_;
double float_value_;
BinaryValue bytestring_value_;
std::string string_value_;
ArrayValue array_value_;
MapValue map_value_;
};
void InternalMoveConstructFrom(Value&& that);
void InternalCleanup();
};
} // namespace cbor
#endif // COMPONENTS_CBOR_VALUES_H_
|