A C++ toolbox repo until the pair uTL/dTL arives
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.
 
 
 

225 lines
7.5 KiB

  1. /*!
  2. * \file files.h
  3. * \brief
  4. * File functionality header
  5. *
  6. * \copyright Copyright (C) 2021 Christos Choutouridis <christos@choutouridis.net>
  7. *
  8. * <dl class=\"section copyright\"><dt>License</dt><dd>
  9. * All Rights Reserved.
  10. *
  11. * NOTICE: All information contained herein is, and remains
  12. * the property of Christos Choutouridis. The intellectual
  13. * and technical concepts contained herein are proprietary to
  14. * Christos Choutouridis and are protected by copyright law.
  15. * Dissemination of this information or reproduction of this material
  16. * is strictly forbidden unless prior written permission is obtained
  17. * from Christos Choutouridis.
  18. * </dd></dl>
  19. */
  20. #ifndef JSON_H_
  21. #define JSON_H_
  22. #include <cstddef>
  23. #include <cstdlib>
  24. #include <cstring>
  25. #include <cctype>
  26. #include <type_traits>
  27. #include <string_view>
  28. #include <array>
  29. using size_t = std::size_t;
  30. struct jpair_t {
  31. std::string_view key;
  32. std::string_view value;
  33. };
  34. template<size_t N>
  35. struct json_dec_t {
  36. using string_view = std::string_view;
  37. json_dec_t(const char* buffer, size_t size) noexcept :
  38. buffer_(buffer, size), valid_(true) {
  39. enum state_t {
  40. ST=0, KEY, COLON, VALUE, SP
  41. } state = ST;
  42. size_t pairs =0;
  43. char* begin = nullptr;
  44. int s =0;
  45. bool str_value = false; // flag to indicate the value is string
  46. for (size_t i=0 ; i<size ; ++i) {
  47. switch (state) {
  48. case ST:
  49. if (std::isspace(buffer[i]))
  50. continue; // skip white space
  51. if (buffer[i] == '{')
  52. state = KEY;
  53. break;
  54. case KEY:
  55. if (pairs >= N) {
  56. valid_ = false;
  57. break;
  58. }
  59. if (std::isspace(buffer[i]))
  60. continue; // skip white space
  61. if (buffer[i] == '\"') {
  62. if (!begin)
  63. begin = (char*)&buffer[i+1];
  64. else {
  65. s = (char*)&buffer[i] - begin;
  66. if (s > 0)
  67. pairs_[pairs].key = std::string_view{begin, (size_t)s};
  68. else
  69. pairs_[pairs].key = std::string_view{};
  70. begin =nullptr;
  71. s =0;
  72. state = COLON;
  73. }
  74. }
  75. else if (buffer[i] == '}')
  76. return;
  77. break;
  78. case COLON:
  79. if (std::isspace(buffer[i]))
  80. continue; // skip white space
  81. if (buffer[i] == ':')
  82. state = VALUE;
  83. else {
  84. valid_ = false;
  85. return;
  86. }
  87. break;
  88. case VALUE:
  89. if (pairs >= N) {
  90. valid_ = false;
  91. break;
  92. }
  93. if (!begin && std::isspace(buffer[i])) // consume pre-spaces
  94. continue;
  95. else if (!begin && !std::isspace(buffer[i])) { // first character
  96. if (buffer[i] == '\"') {
  97. begin = (char*)&buffer[i+1];
  98. str_value = true;
  99. }
  100. else {
  101. begin = (char*)&buffer[i];
  102. str_value = false;
  103. }
  104. }
  105. else if (begin) {
  106. if (str_value && (buffer[i] == '\"')) {
  107. s = (char*)&buffer[i] - begin;
  108. if (s > 0)
  109. pairs_[pairs].value = std::string_view{begin, (size_t)s};
  110. else
  111. pairs_[pairs].value = std::string_view{};
  112. ++pairs;
  113. begin =nullptr;
  114. s =0;
  115. state = SP;
  116. }
  117. else if (!str_value && (std::isspace(buffer[i]) || buffer[i] == ',' || buffer[i] == '}')) {
  118. s = (char*)&buffer[i] - begin;
  119. if (s > 0)
  120. pairs_[pairs].value = std::string_view{begin, (size_t)s};
  121. else
  122. pairs_[pairs].value = std::string_view{};
  123. ++pairs;
  124. begin =nullptr;
  125. s =0;
  126. if (std::isspace(buffer[i]))
  127. state = SP;
  128. else if (buffer[i] == ',')
  129. state = KEY;
  130. else if (buffer[i] == '}')
  131. return;
  132. }
  133. }
  134. break;
  135. case SP:
  136. if (std::isspace(buffer[i]))
  137. continue; // skip white space
  138. else if (buffer[i] == ',')
  139. state = KEY;
  140. else if (buffer[i] == '}')
  141. return;
  142. else {
  143. valid_ = false;
  144. return;
  145. }
  146. break;
  147. }
  148. }
  149. }
  150. template<typename T>
  151. T get (const char* key) {
  152. T t{};
  153. for (auto& it : pairs_) {
  154. if (it.key.compare(key) == 0) {
  155. extract_(it.value, &t);
  156. break;
  157. }
  158. }
  159. return t;
  160. }
  161. bool is_valid() const { return valid_; }
  162. private:
  163. /*!
  164. * Convert the text pointed by \c str to a value and store it to
  165. * \c value. The type of conversion is deduced by the compiler
  166. * \tparam T The type of the value
  167. * \param str pointer to string with the value
  168. * \param value pointer to converted value
  169. */
  170. void extract_(std::string_view str, bool* value) {
  171. *value = (
  172. !std::strncmp(str.data(), "true", str.size()) ||
  173. !std::strncmp(str.data(), "True", str.size()) ||
  174. !std::strncmp(str.data(), "TRUE", str.size()) ||
  175. !std::strncmp(str.data(), "1", str.size())
  176. ) ? true : false;
  177. }
  178. void extract_(std::string_view str, int* value) {
  179. *value = std::atoi(str.data());
  180. }
  181. void extract_(std::string_view str, unsigned int* value) {
  182. *value = (unsigned int)std::atoi(str.data());
  183. }
  184. void extract_(std::string_view str, long* value) {
  185. *value = std::atol(str.data());
  186. }
  187. void extract_(std::string_view str, unsigned long* value) {
  188. *value = (unsigned long)std::atol(str.data());
  189. }
  190. void extract_(std::string_view str, double* value) {
  191. *value = std::atof(str.data());
  192. }
  193. void extract_(std::string_view str, char** value) {
  194. *value = (char*)str.data();
  195. }
  196. void extract_(std::string_view str, string_view* value) {
  197. *value = str;
  198. }
  199. //! Specialization (as overload function) to handle void* types
  200. void extract_ (const char* str, void* value) noexcept {
  201. (void)*str; (void)value;
  202. }
  203. private:
  204. std::string_view buffer_;
  205. std::array<jpair_t, N> pairs_;
  206. bool valid_;
  207. };
  208. #endif /* JSON_H_ */