writer.cc 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204
  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. #include "components/cbor/writer.h"
  5. #include <ostream>
  6. #include <string>
  7. #include "base/check_op.h"
  8. #include "base/notreached.h"
  9. #include "base/numerics/safe_conversions.h"
  10. #include "base/strings/string_piece.h"
  11. #include "components/cbor/constants.h"
  12. namespace cbor {
  13. Writer::~Writer() {}
  14. // static
  15. absl::optional<std::vector<uint8_t>> Writer::Write(const Value& node,
  16. const Config& config) {
  17. std::vector<uint8_t> cbor;
  18. Writer writer(&cbor);
  19. if (!writer.EncodeCBOR(node, config.max_nesting_level,
  20. config.allow_invalid_utf8_for_testing)) {
  21. return absl::nullopt;
  22. }
  23. return cbor;
  24. }
  25. // static
  26. absl::optional<std::vector<uint8_t>> Writer::Write(const Value& node,
  27. size_t max_nesting_level) {
  28. Config config;
  29. config.max_nesting_level = base::checked_cast<int>(max_nesting_level);
  30. return Write(node, config);
  31. }
  32. Writer::Writer(std::vector<uint8_t>* cbor) : encoded_cbor_(cbor) {}
  33. bool Writer::EncodeCBOR(const Value& node,
  34. int max_nesting_level,
  35. bool allow_invalid_utf8) {
  36. if (max_nesting_level < 0)
  37. return false;
  38. switch (node.type()) {
  39. case Value::Type::NONE: {
  40. StartItem(Value::Type::BYTE_STRING, 0);
  41. return true;
  42. }
  43. case Value::Type::INVALID_UTF8: {
  44. if (!allow_invalid_utf8) {
  45. NOTREACHED() << constants::kUnsupportedMajorType;
  46. return false;
  47. }
  48. // Encode a CBOR string with invalid UTF-8 data. This may produce invalid
  49. // CBOR and is reachable in tests only. See
  50. // |allow_invalid_utf8_for_testing| in Config.
  51. const Value::BinaryValue& bytes = node.GetInvalidUTF8();
  52. StartItem(Value::Type::STRING, base::strict_cast<uint64_t>(bytes.size()));
  53. encoded_cbor_->insert(encoded_cbor_->end(), bytes.begin(), bytes.end());
  54. return true;
  55. }
  56. // Represents unsigned integers.
  57. case Value::Type::UNSIGNED: {
  58. int64_t value = node.GetUnsigned();
  59. StartItem(Value::Type::UNSIGNED, static_cast<uint64_t>(value));
  60. return true;
  61. }
  62. // Represents negative integers.
  63. case Value::Type::NEGATIVE: {
  64. int64_t value = node.GetNegative();
  65. StartItem(Value::Type::NEGATIVE, static_cast<uint64_t>(-(value + 1)));
  66. return true;
  67. }
  68. // Represents a byte string.
  69. case Value::Type::BYTE_STRING: {
  70. const Value::BinaryValue& bytes = node.GetBytestring();
  71. StartItem(Value::Type::BYTE_STRING,
  72. base::strict_cast<uint64_t>(bytes.size()));
  73. // Add the bytes.
  74. encoded_cbor_->insert(encoded_cbor_->end(), bytes.begin(), bytes.end());
  75. return true;
  76. }
  77. case Value::Type::STRING: {
  78. base::StringPiece string = node.GetString();
  79. StartItem(Value::Type::STRING,
  80. base::strict_cast<uint64_t>(string.size()));
  81. // Add the characters.
  82. encoded_cbor_->insert(encoded_cbor_->end(), string.begin(), string.end());
  83. return true;
  84. }
  85. // Represents an array.
  86. case Value::Type::ARRAY: {
  87. const Value::ArrayValue& array = node.GetArray();
  88. StartItem(Value::Type::ARRAY, array.size());
  89. for (const auto& value : array) {
  90. if (!EncodeCBOR(value, max_nesting_level - 1, allow_invalid_utf8))
  91. return false;
  92. }
  93. return true;
  94. }
  95. // Represents a map.
  96. case Value::Type::MAP: {
  97. const Value::MapValue& map = node.GetMap();
  98. StartItem(Value::Type::MAP, map.size());
  99. for (const auto& value : map) {
  100. if (!EncodeCBOR(value.first, max_nesting_level - 1, allow_invalid_utf8))
  101. return false;
  102. if (!EncodeCBOR(value.second, max_nesting_level - 1,
  103. allow_invalid_utf8))
  104. return false;
  105. }
  106. return true;
  107. }
  108. case Value::Type::TAG:
  109. NOTREACHED() << constants::kUnsupportedMajorType;
  110. return false;
  111. // Represents a simple value.
  112. case Value::Type::SIMPLE_VALUE: {
  113. const Value::SimpleValue simple_value = node.GetSimpleValue();
  114. StartItem(Value::Type::SIMPLE_VALUE,
  115. base::checked_cast<uint64_t>(simple_value));
  116. return true;
  117. }
  118. }
  119. }
  120. void Writer::StartItem(Value::Type type, uint64_t size) {
  121. encoded_cbor_->push_back(base::checked_cast<uint8_t>(
  122. static_cast<unsigned>(type) << constants::kMajorTypeBitShift));
  123. SetUint(size);
  124. }
  125. void Writer::SetAdditionalInformation(uint8_t additional_information) {
  126. DCHECK(!encoded_cbor_->empty());
  127. DCHECK_EQ(additional_information & constants::kAdditionalInformationMask,
  128. additional_information);
  129. encoded_cbor_->back() |=
  130. (additional_information & constants::kAdditionalInformationMask);
  131. }
  132. void Writer::SetUint(uint64_t value) {
  133. size_t count = GetNumUintBytes(value);
  134. int shift = -1;
  135. // Values under 24 are encoded directly in the initial byte.
  136. // Otherwise, the last 5 bits of the initial byte contains the length
  137. // of unsigned integer, which is encoded in following bytes.
  138. switch (count) {
  139. case 0:
  140. SetAdditionalInformation(base::checked_cast<uint8_t>(value));
  141. break;
  142. case 1:
  143. SetAdditionalInformation(constants::kAdditionalInformation1Byte);
  144. shift = 0;
  145. break;
  146. case 2:
  147. SetAdditionalInformation(constants::kAdditionalInformation2Bytes);
  148. shift = 1;
  149. break;
  150. case 4:
  151. SetAdditionalInformation(constants::kAdditionalInformation4Bytes);
  152. shift = 3;
  153. break;
  154. case 8:
  155. SetAdditionalInformation(constants::kAdditionalInformation8Bytes);
  156. shift = 7;
  157. break;
  158. default:
  159. NOTREACHED();
  160. break;
  161. }
  162. for (; shift >= 0; shift--) {
  163. encoded_cbor_->push_back(0xFF & (value >> (shift * 8)));
  164. }
  165. }
  166. size_t Writer::GetNumUintBytes(uint64_t value) {
  167. if (value < 24) {
  168. return 0;
  169. } else if (value <= 0xFF) {
  170. return 1;
  171. } else if (value <= 0xFFFF) {
  172. return 2;
  173. } else if (value <= 0xFFFFFFFF) {
  174. return 4;
  175. }
  176. return 8;
  177. }
  178. } // namespace cbor