General Purpose library for Freestanding C++ and POSIX systems
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

290 lines
7.9 KiB

4 years ago
4 years ago
4 years ago
4 years ago
  1. #pragma once
  2. #include <gp/bitops.hpp>
  3. #include <gp/optional.hpp>
  4. #include <gp/pair.hpp>
  5. #include <gp/variant.hpp>
  6. #include <gp/vector.hpp>
  7. namespace gp {
  8. enum class cbor_type : uint8_t {
  9. uint = 0,
  10. nint = 1,
  11. bstr = 2,
  12. tstr = 3,
  13. list = 4,
  14. hmap = 5,
  15. tags = 6,
  16. oths = 7
  17. };
  18. enum class cbor_oths : uint8_t {
  19. value_false = 20,
  20. value_true = 21,
  21. value_null = 22,
  22. value_undefined = 23,
  23. byte = 24,
  24. word = 25,
  25. dword = 26,
  26. qword = 27,
  27. terminator = 31
  28. };
  29. enum class cbor_tags {
  30. datetime = 0,
  31. unix_time = 1,
  32. ubignum = 2,
  33. nbignum = 3,
  34. decimal = 4,
  35. bigfloat = 5,
  36. cose_encrypt0 = 16,
  37. cose_mac0 = 17,
  38. cose_sign1 = 18,
  39. expected_base64url = 21,
  40. expected_base64 = 22,
  41. expected_base16 = 23,
  42. encoded_cbor = 24,
  43. url = 32,
  44. base64url = 33,
  45. base64 = 34,
  46. regexp = 35,
  47. mime = 36,
  48. cose_encrypt = 96,
  49. cose_mac = 97,
  50. cose_sign = 98,
  51. signature = 55799
  52. };
  53. struct cbor_number final {
  54. bool sign;
  55. uint64_t value;
  56. bool is_negative() {
  57. return sign;
  58. }
  59. cbor_number(int64_t v)
  60. : sign{v < 0}
  61. , value{uint64_t((sign ? -1 : 1) * v)}
  62. {}
  63. };
  64. struct ieee754_hf final {
  65. uint16_t sign : 1;
  66. uint16_t exponent : 5;
  67. uint16_t mantissa : 10;
  68. };
  69. using cbor_floating_point = gp::fixed_variant<
  70. ieee754_hf,
  71. float,
  72. double
  73. >;
  74. struct undefined_t final {};
  75. template<typename T>
  76. using cbor_composite = gp::fixed_variant<
  77. undefined_t,
  78. cbor_number,
  79. gp::buffer<std::byte>,
  80. bool,
  81. gp::vector<T>,
  82. gp::vector<gp::pair<T, T>>,
  83. gp::nullopt_t,
  84. cbor_floating_point
  85. >;
  86. class cbor_value {
  87. cbor_composite<cbor_value> contents;
  88. gp::reference_wrapper<allocator> alloc;
  89. public:
  90. cbor_value(allocator& alloc_v)
  91. : contents(cbor_composite<cbor_value>(undefined_t{}))
  92. , alloc(alloc_v)
  93. {}
  94. cbor_value(cbor_number number, allocator& alloc_v)
  95. : contents(number)
  96. , alloc(alloc_v)
  97. {}
  98. cbor_value(const cbor_value& oth)
  99. : contents(oth.contents)
  100. , alloc(oth.alloc)
  101. {}
  102. cbor_value(cbor_value&& oth)
  103. : contents(gp::move(oth.contents))
  104. , alloc(gp::move(oth.alloc))
  105. {}
  106. cbor_value& operator=(cbor_value& value) {
  107. contents = value.contents;
  108. alloc = value.alloc;
  109. return *this;
  110. }
  111. cbor_value& operator=(cbor_value&& value) {
  112. gp::swap(contents, value.contents);
  113. gp::swap(alloc, value.alloc);
  114. return *this;
  115. }
  116. cbor_value& operator=(cbor_composite<cbor_value>& value) {
  117. contents = value;
  118. return *this;
  119. }
  120. template<typename T>
  121. cbor_value& operator=(T& value) {
  122. contents = value;
  123. return *this;
  124. }
  125. template<typename T>
  126. cbor_value& operator=(T&& value) {
  127. contents = gp::move(value);
  128. return *this;
  129. }
  130. auto new_array() {
  131. return gp::vector<cbor_value>{alloc};
  132. }
  133. auto new_object() {
  134. return gp::vector<gp::pair<cbor_value, cbor_value>>{alloc};
  135. }
  136. static auto encode_float(buffer<std::byte> dest, cbor_floating_point& value) {
  137. switch(value.type()) {
  138. case cbor_floating_point::alt<ieee754_hf>():{
  139. if(dest.size() < 3) return dest.begin();
  140. dest[0] = std::byte(((uint8_t)cbor_type::oths << 5u) + (uint8_t)cbor_oths::word);
  141. (dest.slice_start(3).slice_end(2).cast<gp::endian_wrapper<ieee754_hf, gp::endian::big>>())[0] = value.value<ieee754_hf>();
  142. return dest.begin()+3;
  143. }
  144. case cbor_floating_point::alt<float>():{
  145. if(dest.size() < 5) return dest.begin();
  146. dest[0] = std::byte(((uint8_t)cbor_type::oths << 5u) + (uint8_t)cbor_oths::dword);
  147. (dest.slice_start(5).slice_end(4).cast<gp::endian_wrapper<float, gp::endian::big>>())[0] = value.value<float>();
  148. return dest.begin()+5;
  149. }
  150. case cbor_floating_point::alt<double>():{
  151. if(dest.size() < 9) return dest.begin();
  152. dest[0] = std::byte(((uint8_t)cbor_type::oths << 5u) + (uint8_t)cbor_oths::qword);
  153. (dest.slice_start(9).slice_end(8).cast<gp::endian_wrapper<double, gp::endian::big>>())[0] = value.value<double>();
  154. return dest.begin()+9;
  155. }
  156. default: return dest.begin();
  157. }
  158. }
  159. static auto encode_length(buffer<std::byte> dest, cbor_type major, uint64_t value) {
  160. auto num = value;
  161. if(value <= 23) {
  162. if(dest.size() < 1) return dest.begin();
  163. dest[0] = std::byte(((uint8_t)major << 5u) + value);
  164. return dest.begin()+1;
  165. } else if(value <= 255) {
  166. if(dest.size() < 2) return dest.begin();
  167. dest[0] = std::byte(((uint8_t)major << 5u) + (uint8_t)cbor_oths::byte);
  168. dest[1] = std::byte(value);
  169. return dest.begin() + 2;
  170. } else if(value <= 65535) {
  171. if(dest.size() < 3) return dest.begin();
  172. dest[0] = std::byte(((uint8_t)major << 5u) + (uint8_t)cbor_oths::word);
  173. (dest.slice_start(3).slice_end(2).cast<gp::endian_wrapper<uint16_t, gp::endian::big>>())[0] = num;
  174. return dest.begin()+3;
  175. } else if(value <= 4294967295) {
  176. if(dest.size() < 5) return dest.begin();
  177. dest[0] = std::byte(((uint8_t)major << 5u) + (uint8_t)cbor_oths::dword);
  178. (dest.slice_start(5).slice_end(4).cast<gp::endian_wrapper<uint32_t, gp::endian::big>>())[0] = num;
  179. return dest.begin()+5;
  180. } else {
  181. if(dest.size() < 9) return dest.begin();
  182. dest[0] = std::byte(((uint8_t)major << 5u) + (uint8_t)cbor_oths::qword);
  183. (dest.slice_start(9).slice_end(8).cast<gp::endian_wrapper<uint64_t, gp::endian::big>>())[0] = num;
  184. return dest.begin()+9;
  185. }
  186. }
  187. auto encode(buffer<std::byte> dest) {
  188. switch(contents.type()) {
  189. case cbor_composite<cbor_value>::alt<undefined_t>(): {
  190. if(dest.size() < 1) return dest.begin();
  191. dest[0] = std::byte(((uint8_t)cbor_type::oths << 5u) + (uint8_t)cbor_oths::value_undefined);
  192. return dest.begin()+1;
  193. }
  194. case cbor_composite<cbor_value>::alt<cbor_number>(): {
  195. auto& ref = contents.value<cbor_number>();
  196. return encode_length(
  197. dest,
  198. ref.is_negative() ? cbor_type::nint : cbor_type::uint,
  199. ref.value
  200. );
  201. }
  202. case cbor_composite<cbor_value>::alt<gp::buffer<std::byte>>(): {
  203. auto& ref = contents.value<gp::buffer<std::byte>>();
  204. auto it = encode_length(
  205. dest,
  206. cbor_type::bstr,
  207. ref.size()
  208. );
  209. if(it == dest.begin()) return it;
  210. for(auto a : ref) {
  211. *(it++) = a;
  212. }
  213. return it;
  214. }
  215. case cbor_composite<cbor_value>::alt<bool>(): {
  216. if(dest.size() < 1) return dest.begin();
  217. if(contents.value<bool>())
  218. dest[0] = std::byte(((uint8_t)cbor_type::oths << 5u) + (uint8_t)cbor_oths::value_true);
  219. else
  220. dest[0] = std::byte(((uint8_t)cbor_type::oths << 5u) + (uint8_t)cbor_oths::value_false);
  221. return dest.begin()+1;
  222. }
  223. case cbor_composite<cbor_value>::alt<gp::vector<cbor_value>>(): {
  224. auto& ary = contents.value<gp::vector<cbor_value>>();
  225. auto it_begin = encode_length(dest, cbor_type::list, ary.size());
  226. if(it_begin != dest.begin()) return dest.begin();
  227. for(auto& elem : ary) {
  228. auto slice = dest.slice_end(dest.size() - (it_begin - dest.begin()));
  229. auto it = elem.encode(slice);
  230. if(it == it_begin) return dest.begin();
  231. it_begin = it;
  232. }
  233. return it_begin;
  234. }
  235. case cbor_composite<cbor_value>::alt<gp::vector<gp::pair<cbor_value, cbor_value>>>(): {
  236. auto& ary = contents.value<gp::vector<gp::pair<cbor_value,cbor_value>>>();
  237. auto it_begin = encode_length(dest, cbor_type::hmap, ary.size());
  238. if(it_begin != dest.begin()) return dest.begin();
  239. for(auto& elem : ary) {
  240. auto slice = dest.slice_end(dest.size() - (it_begin - dest.begin()));
  241. auto it = elem.first.encode(slice);
  242. if(it == it_begin) return dest.begin();
  243. it_begin = it;
  244. slice = dest.slice_end(dest.size() - (it_begin - dest.begin()));
  245. it = elem.second.encode(slice);
  246. if(it == it_begin) return dest.begin();
  247. it_begin = it;
  248. }
  249. return it_begin;
  250. }
  251. case cbor_composite<cbor_value>::alt<gp::nullopt_t>(): {
  252. if(dest.size() < 1) return dest.begin();
  253. dest[0] = std::byte(((uint8_t)cbor_type::oths << 5u) + (uint8_t)cbor_oths::value_null);
  254. return dest.begin()+1;
  255. }
  256. case cbor_composite<cbor_value>::alt<cbor_floating_point>(): {
  257. return encode_float(dest, contents.value<cbor_floating_point>());
  258. }
  259. }
  260. }
  261. };
  262. }