1 // Copyright 2017 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #ifndef COMPONENTS_CBOR_WRITER_H_
6 #define COMPONENTS_CBOR_WRITER_H_
7 
8 #include <stddef.h>
9 #include <stdint.h>
10 
11 #include <vector>
12 
13 #include "base/optional.h"
14 #include "components/cbor/cbor_export.h"
15 #include "components/cbor/values.h"
16 
17 // A basic Concise Binary Object Representation (CBOR) encoder as defined by
18 // https://tools.ietf.org/html/rfc7049. This is a generic encoder that supplies
19 // canonical, well-formed CBOR values but does not guarantee their validity
20 // (see https://tools.ietf.org/html/rfc7049#section-3.2).
21 // Supported:
22 //  * Major types:
23 //     * 0: Unsigned integers, up to INT64_MAX.
24 //     * 1: Negative integers, to INT64_MIN.
25 //     * 2: Byte strings.
26 //     * 3: UTF-8 strings.
27 //     * 4: Arrays, with the number of elements known at the start.
28 //     * 5: Maps, with the number of elements known at the start
29 //              of the container.
30 //     * 7: Simple values.
31 //
32 // Unsupported:
33 //  * Floating-point numbers.
34 //  * Indefinite-length encodings.
35 //  * Parsing.
36 //
37 // Requirements for canonical CBOR as suggested by RFC 7049 are:
38 //  1) All major data types for the CBOR values must be as short as possible.
39 //      * Unsigned integer between 0 to 23 must be expressed in same byte as
40 //            the major type.
41 //      * 24 to 255 must be expressed only with an additional uint8_t.
42 //      * 256 to 65535 must be expressed only with an additional uint16_t.
43 //      * 65536 to 4294967295 must be expressed only with an additional
44 //            uint32_t. * The rules for expression of length in major types
45 //            2 to 5 follow the above rule for integers.
46 //  2) Keys in every map must be sorted (first by major type, then by key
47 //         length, then by value in byte-wise lexical order).
48 //  3) Indefinite length items must be converted to definite length items.
49 //  4) All maps must not have duplicate keys.
50 //
51 // Current implementation of Writer encoder meets all the requirements of
52 // canonical CBOR.
53 
54 namespace cbor {
55 
56 class CBOR_EXPORT Writer {
57  public:
58   // Default that should be sufficiently large for most use cases.
59   static constexpr size_t kDefaultMaxNestingDepth = 16;
60 
61   struct CBOR_EXPORT Config {
62     // Controls the maximum depth of CBOR nesting that will be permitted in a
63     // Value. Nesting depth is defined as the number of arrays/maps that have to
64     // be traversed to reach the most nested contained Value. Primitive values
65     // and empty containers have nesting depths of 0.
66     int max_nesting_level = kDefaultMaxNestingDepth;
67 
68     // Controls whether the Writer allows writing string values of type
69     // Value::Type::INVALID_UTF8. Regular CBOR strings must be valid UTF-8.
70     // Writers with this setting will produce invalid CBOR, so it may only be
71     // enabled in tests.
72     bool allow_invalid_utf8_for_testing = false;
73   };
74 
75   ~Writer();
76 
77   // Returns the CBOR byte string representation of |node|, unless its nesting
78   // depth is greater than |max_nesting_level|, in which case an empty optional
79   // value is returned.
80   static base::Optional<std::vector<uint8_t>> Write(
81       const Value& node,
82       size_t max_nesting_level = kDefaultMaxNestingDepth);
83 
84   // A version of |Write| above that takes a Config.
85   static base::Optional<std::vector<uint8_t>> Write(const Value& node,
86                                                     const Config& config);
87 
88  private:
89   explicit Writer(std::vector<uint8_t>* cbor);
90 
91   // Called recursively to build the CBOR bytestring. When completed,
92   // |encoded_cbor_| will contain the CBOR.
93   bool EncodeCBOR(const Value& node,
94                   int max_nesting_level,
95                   bool allow_invalid_utf8);
96 
97   // Encodes the type and size of the data being added.
98   void StartItem(Value::Type type, uint64_t size);
99 
100   // Encodes the additional information for the data.
101   void SetAdditionalInformation(uint8_t additional_information);
102 
103   // Encodes an unsigned integer value. This is used to both write
104   // unsigned integers and to encode the lengths of other major types.
105   void SetUint(uint64_t value);
106 
107   // Returns the number of bytes needed to store the unsigned integer.
108   size_t GetNumUintBytes(uint64_t value);
109 
110   // Holds the encoded CBOR data.
111   std::vector<uint8_t>* encoded_cbor_;
112 
113   DISALLOW_COPY_AND_ASSIGN(Writer);
114 };
115 
116 }  // namespace cbor
117 
118 #endif  // COMPONENTS_CBOR_WRITER_H_
119