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.

337 rivejä
8.1 KiB

4 vuotta sitten
4 vuotta sitten
4 vuotta sitten
4 vuotta sitten
4 vuotta sitten
4 vuotta sitten
4 vuotta sitten
4 vuotta sitten
4 vuotta sitten
3 vuotta sitten
3 vuotta sitten
3 vuotta sitten
3 vuotta sitten
3 vuotta sitten
3 vuotta sitten
3 vuotta sitten
3 vuotta sitten
3 vuotta sitten
3 vuotta sitten
3 vuotta sitten
3 vuotta sitten
3 vuotta sitten
3 vuotta sitten
3 vuotta sitten
3 vuotta sitten
3 vuotta sitten
4 vuotta sitten
  1. #pragma once
  2. #include <gp/algorithms/repeat.hpp>
  3. #include <gp/math/boolean/bitops.hpp>
  4. #include <gp/functional/optional.hpp>
  5. #include <gp/utils/pair.hpp>
  6. #include <gp/functional/variant.hpp>
  7. #include <gp/containers/vector.hpp>
  8. // TODO: Rewrite in a more ORM-like way
  9. // TODO: Implement some bignum for support
  10. namespace gp {
  11. enum class cbor_type : uint8_t {
  12. uint = 0,
  13. nint = 1,
  14. bstr = 2,
  15. tstr = 3,
  16. list = 4,
  17. hmap = 5,
  18. tags = 6,
  19. oths = 7
  20. };
  21. enum class cbor_oths : uint8_t {
  22. value_false = 20,
  23. value_true = 21,
  24. value_null = 22,
  25. value_undefined = 23,
  26. byte = 24,
  27. word = 25,
  28. dword = 26,
  29. qword = 27,
  30. terminator = 31
  31. };
  32. enum class cbor_tags {
  33. datetime = 0,
  34. unix_time = 1,
  35. ubignum = 2,
  36. nbignum = 3,
  37. decimal = 4,
  38. bigfloat = 5,
  39. cose_encrypt0 = 16,
  40. cose_mac0 = 17,
  41. cose_sign1 = 18,
  42. expected_base64url = 21,
  43. expected_base64 = 22,
  44. expected_base16 = 23,
  45. encoded_cbor = 24,
  46. url = 32,
  47. base64url = 33,
  48. base64 = 34,
  49. regexp = 35,
  50. mime = 36,
  51. cose_encrypt = 96,
  52. cose_mac = 97,
  53. cose_sign = 98,
  54. signature = 55799
  55. };
  56. struct cbor_number final {
  57. bool sign;
  58. uint64_t value;
  59. bool is_negative() {
  60. return sign;
  61. }
  62. cbor_number(int64_t v)
  63. : sign{v < 0}
  64. , value{uint64_t((sign ? -1 : 1) * v)}
  65. {}
  66. cbor_number(bool s, uint64_t v)
  67. : sign{s}
  68. , value{v}
  69. {}
  70. };
  71. struct ieee754_hf final {
  72. uint16_t sign : 1;
  73. uint16_t exponent : 5;
  74. uint16_t mantissa : 10;
  75. // TODO: support for denormalized values and NaNs
  76. operator float() {
  77. auto a = (uint32_t)((sign<<16) | ((exponent+0x1C000)<<13) | (mantissa<<13));
  78. return *(float*)&a;
  79. }
  80. operator double() {
  81. return (float)*this;
  82. }
  83. };
  84. template<typename T>
  85. vector<char>& push_as_cbor(vector<char>&, T);
  86. template<typename T>
  87. vector<char>& push_as_cbor(vector<char>&, T&);
  88. inline vector<char>& push_integer_with_header_as_cbor(vector<char>& src, uint8_t header, uint64_t value) {
  89. auto norm_v = (value<0) ? -value : value;
  90. if(norm_v <= 23) {
  91. src.push_back(header+norm_v);
  92. } else if(norm_v < (1ll<<8ll)) {
  93. src.push_back(header+24);
  94. src.push_back(norm_v);
  95. } else if(norm_v < (1ll<<16ll)) {
  96. endian_wrapper<uint16_t, endian::big> wrapper = norm_v;
  97. src.push_back(header+25);
  98. for(auto byte : wrapper.bytes) {
  99. src.push_back(byte);
  100. }
  101. } else if(norm_v < (1ll<<32ll)) {
  102. endian_wrapper<uint32_t, endian::big> wrapper = norm_v;
  103. src.push_back(header+26);
  104. for(auto byte : wrapper.bytes) {
  105. src.push_back(byte);
  106. }
  107. } else {
  108. endian_wrapper<uint64_t, endian::big> wrapper = norm_v;
  109. src.push_back(header+27);
  110. for(auto byte : wrapper.bytes) {
  111. src.push_back(byte);
  112. }
  113. }
  114. return src;
  115. }
  116. /**
  117. * @brief Pushes an integer as CBOR on the vector
  118. *
  119. * @param src the vector on which the push happens
  120. * @param value the value to push, can be signed
  121. * @return vector<char>& the same reference that was received for the source
  122. */
  123. template<>
  124. inline vector<char>& push_as_cbor<int64_t>(vector<char>& src, int64_t& value) {
  125. uint8_t sign = (value<0) ? 0b00100000 : 0;
  126. auto norm_v = (value<0) ? -value : value;
  127. return push_integer_with_header_as_cbor(src, sign, norm_v);
  128. }
  129. /**
  130. * @brief Pushes an unsigned integer as CBOR on the vector
  131. *
  132. * @param src the vector on which the push happens
  133. * @param value the value to push, cannot be signed
  134. * @return vector<char>& the same reference that was received for the source
  135. */
  136. template<>
  137. inline vector<char>& push_as_cbor<uint64_t>(vector<char>& src, uint64_t& value) {
  138. return push_integer_with_header_as_cbor(src, 0, value);
  139. }
  140. template<>
  141. inline vector<char>& push_as_cbor<std::nullptr_t>(vector<char>& src, std::nullptr_t) {
  142. src.push_back(0b11110110);
  143. return src;
  144. }
  145. struct cbor_undefined{};
  146. template<>
  147. inline vector<char>& push_as_cbor<cbor_undefined>(vector<char>& src, cbor_undefined) {
  148. src.push_back(0b11110111);
  149. return src;
  150. }
  151. template<>
  152. inline vector<char>& push_as_cbor<bool>(vector<char>& src, bool value) {
  153. src.push_back(0b11110100+(value ? 1 : 0));
  154. return src;
  155. }
  156. template<>
  157. inline vector<char>& push_as_cbor<gp::buffer<char>>(vector<char>& src, gp::buffer<char> value) {
  158. push_integer_with_header_as_cbor(src, (uint8_t)0b01000000, value.size());
  159. for(auto byte : value) {
  160. src.push_back(byte);
  161. }
  162. return src;
  163. }
  164. struct cbor_array_initiator {
  165. size_t size;
  166. };
  167. struct cbor_associative_array_initiator {
  168. size_t size;
  169. };
  170. template<>
  171. inline vector<char>& push_as_cbor<cbor_array_initiator>(vector<char>& src, cbor_array_initiator value) {
  172. return push_integer_with_header_as_cbor(src, (uint8_t)0b10000000, value.size);
  173. }
  174. template<>
  175. inline vector<char>& push_as_cbor<cbor_associative_array_initiator>(vector<char>& src, cbor_associative_array_initiator value) {
  176. return push_integer_with_header_as_cbor(src, (uint8_t)0b10100000, value.size);
  177. }
  178. template<typename First, typename Second>
  179. inline vector<char>& push_as_cbor(vector<char>& src, gp::pair<First, Second>& value) {
  180. push_as_cbor<First>(src,value.first);
  181. return push_as_cbor<Second>(src,value.second);
  182. }
  183. struct cbor_tag_initiator {
  184. union {
  185. size_t as_integer;
  186. cbor_tags tag;
  187. };
  188. };
  189. template<>
  190. inline vector<char>& push_as_cbor<cbor_tag_initiator>(vector<char>& src, cbor_tag_initiator value) {
  191. return push_integer_with_header_as_cbor(src, (uint8_t)0b11000000, value.as_integer);
  192. }
  193. using parsing_state = gp::buffer<char>;
  194. template<typename T>
  195. gp::pair<gp::optional<T>, parsing_state> read_cbor(parsing_state state);
  196. inline gp::pair<gp::optional<uint64_t>, parsing_state> pull_arbitrary_integer_from_cbor(parsing_state state) {
  197. auto local = (uint8_t)0b00011111 & (uint8_t)*state.begin();
  198. if(local <= 23) {
  199. return {*state.begin(), {state.begin()+1, state.end()}};
  200. } else {
  201. switch((cbor_oths)local) {
  202. case cbor_oths::byte: {
  203. if(state.size() < 2) return {nullopt, state};
  204. return {*(state.begin()+1), {state.begin()+2, state.end()}};
  205. }
  206. case cbor_oths::word: {
  207. if(state.size() < 3) return {nullopt, state};
  208. return {
  209. uint16_t(*(state.slice_start(3).slice_end(2).cast<gp::endian_wrapper<uint16_t, endian::big>>().begin().data)),
  210. {state.begin()+3, state.end()}
  211. };
  212. }
  213. case cbor_oths::dword: {
  214. if(state.size() < 5) return {nullopt, state};
  215. return {
  216. uint32_t(*(state.slice_start(5).slice_end(4).cast<gp::endian_wrapper<uint32_t, endian::big>>().begin().data)),
  217. {state.begin()+5, state.end()}
  218. };
  219. }
  220. case cbor_oths::qword: {
  221. if(state.size() < 9) return {nullopt, state};
  222. return {
  223. uint64_t(*(state.slice_start(9).slice_end(8).cast<gp::endian_wrapper<uint64_t, endian::big>>().begin().data)),
  224. {state.begin()+9, state.end()}
  225. };
  226. }
  227. default: {
  228. return {nullopt, state};
  229. }
  230. }
  231. }
  232. }
  233. template<>
  234. inline gp::pair<gp::optional<uint64_t>, parsing_state> read_cbor<uint64_t>(parsing_state state) {
  235. if(state.size()) return {nullopt, state};
  236. auto type = cbor_type(((uint8_t)0b11100000 & (uint8_t)*state.begin()) >> 5);
  237. switch(type) {
  238. case cbor_type::uint:
  239. {
  240. auto[value, new_state] = pull_arbitrary_integer_from_cbor(state);
  241. if(value.has_value()) return {value.value(), new_state};
  242. break;
  243. }
  244. case cbor_type::nint:
  245. {
  246. auto[value, new_state] = pull_arbitrary_integer_from_cbor(state);
  247. if(value.has_value()) return {-value.value(), new_state};
  248. break;
  249. }
  250. default:
  251. break;
  252. }
  253. return {nullopt, state};
  254. }
  255. template<>
  256. inline gp::pair<gp::optional<int64_t>, parsing_state> read_cbor<int64_t>(parsing_state state) {
  257. if(state.size()) return {nullopt, state};
  258. auto type = cbor_type(((uint8_t)0b11100000 & (uint8_t)*state.begin()) >> 5);
  259. switch(type) {
  260. case cbor_type::uint:
  261. {
  262. auto[value, new_state] = pull_arbitrary_integer_from_cbor(state);
  263. if(value.has_value()) return {value.value(), new_state};
  264. break;
  265. }
  266. case cbor_type::nint:
  267. {
  268. auto[value, new_state] = pull_arbitrary_integer_from_cbor(state);
  269. if(
  270. value.has_value()
  271. && value.value() < (uint64_t)std::numeric_limits<int64_t>::max()
  272. ) {
  273. return {-value.value(), new_state};
  274. }
  275. break;
  276. }
  277. default: break;
  278. }
  279. return {nullopt, state};
  280. }
  281. }