|
|
@@ -0,0 +1,202 @@ |
|
|
|
/*! |
|
|
|
* \file files.h |
|
|
|
* \brief |
|
|
|
* File functionality header |
|
|
|
* |
|
|
|
* \copyright Copyright (C) 2021 Christos Choutouridis <christos@choutouridis.net> |
|
|
|
* |
|
|
|
* <dl class=\"section copyright\"><dt>License</dt><dd> |
|
|
|
* All Rights Reserved. |
|
|
|
* |
|
|
|
* NOTICE: All information contained herein is, and remains |
|
|
|
* the property of Christos Choutouridis. The intellectual |
|
|
|
* and technical concepts contained herein are proprietary to |
|
|
|
* Christos Choutouridis and are protected by copyright law. |
|
|
|
* Dissemination of this information or reproduction of this material |
|
|
|
* is strictly forbidden unless prior written permission is obtained |
|
|
|
* from Christos Choutouridis. |
|
|
|
* </dd></dl> |
|
|
|
*/ |
|
|
|
#ifndef JSON_H_ |
|
|
|
#define JSON_H_ |
|
|
|
|
|
|
|
#include <cstddef> |
|
|
|
#include <cstdlib> |
|
|
|
#include <cstring> |
|
|
|
#include <cctype> |
|
|
|
#include <type_traits> |
|
|
|
#include <string_view> |
|
|
|
#include <array> |
|
|
|
|
|
|
|
using size_t = std::size_t; |
|
|
|
|
|
|
|
struct jpair_t { |
|
|
|
std::string_view key; |
|
|
|
std::string_view value; |
|
|
|
}; |
|
|
|
|
|
|
|
template<size_t N> |
|
|
|
struct json_dec_t { |
|
|
|
|
|
|
|
using string_view = std::string_view; |
|
|
|
|
|
|
|
json_dec_t(const char* buffer, size_t size) noexcept : |
|
|
|
buffer_(buffer, size), valid_(true) { |
|
|
|
enum state_t { |
|
|
|
ST=0, KEY, COLON, VALUE, SP |
|
|
|
} state = ST; |
|
|
|
|
|
|
|
size_t pairs =0; |
|
|
|
char* begin = nullptr; |
|
|
|
int s =0; |
|
|
|
for (size_t i=0 ; i<size ; ++i) { |
|
|
|
switch (state) { |
|
|
|
case ST: |
|
|
|
if (std::isspace(buffer[i])) |
|
|
|
continue; // skip white space |
|
|
|
if (buffer[i] == '{') |
|
|
|
state = KEY; |
|
|
|
break; |
|
|
|
|
|
|
|
case KEY: |
|
|
|
if (pairs >= N) { |
|
|
|
valid_ = false; |
|
|
|
break; |
|
|
|
} |
|
|
|
if (std::isspace(buffer[i])) |
|
|
|
continue; // skip white space |
|
|
|
if (buffer[i] == '\"') { |
|
|
|
if (!begin) |
|
|
|
begin = (char*)&buffer[i+1]; |
|
|
|
else { |
|
|
|
s = (char*)&buffer[i] - begin; |
|
|
|
if (s > 0) |
|
|
|
pairs_[pairs].key = std::string_view{begin, (size_t)s}; |
|
|
|
else |
|
|
|
pairs_[pairs].key = std::string_view{}; |
|
|
|
begin =nullptr; |
|
|
|
s =0; |
|
|
|
state = COLON; |
|
|
|
} |
|
|
|
} |
|
|
|
else if (buffer[i] == '}') |
|
|
|
return; |
|
|
|
break; |
|
|
|
|
|
|
|
case COLON: |
|
|
|
if (std::isspace(buffer[i])) |
|
|
|
continue; // skip white space |
|
|
|
if (buffer[i] == ':') |
|
|
|
state = VALUE; |
|
|
|
else { |
|
|
|
valid_ = false; |
|
|
|
return; |
|
|
|
} |
|
|
|
break; |
|
|
|
|
|
|
|
case VALUE: |
|
|
|
if (pairs >= N) { |
|
|
|
valid_ = false; |
|
|
|
break; |
|
|
|
} |
|
|
|
if (!begin && std::isspace(buffer[i])) |
|
|
|
continue; |
|
|
|
else if (!begin && !std::isspace(buffer[i])) |
|
|
|
begin = (buffer[i] != '\"') ? (char*)&buffer[i] : (char*)&buffer[i+1]; |
|
|
|
else if (begin && (std::isspace(buffer[i]) || buffer[i] == ',' || buffer[i] == '}')) { |
|
|
|
s = (char*)&buffer[i] - begin; |
|
|
|
s -= (buffer[i-1] == '\"') ? 1:0; |
|
|
|
if (s > 0) |
|
|
|
pairs_[pairs].value = std::string_view{begin, (size_t)s}; |
|
|
|
else |
|
|
|
pairs_[pairs].value = std::string_view{}; |
|
|
|
++pairs; |
|
|
|
begin =nullptr; |
|
|
|
s =0; |
|
|
|
if (std::isspace(buffer[i])) |
|
|
|
state = SP; |
|
|
|
else if (buffer[i] == ',') |
|
|
|
state = KEY; |
|
|
|
else if (buffer[i] == '}') |
|
|
|
return; |
|
|
|
} |
|
|
|
break; |
|
|
|
|
|
|
|
case SP: |
|
|
|
if (std::isspace(buffer[i])) |
|
|
|
continue; // skip white space |
|
|
|
else if (buffer[i] == ',') |
|
|
|
state = KEY; |
|
|
|
else if (buffer[i] == '}') |
|
|
|
return; |
|
|
|
else { |
|
|
|
valid_ = false; |
|
|
|
return; |
|
|
|
} |
|
|
|
break; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
template<typename T> |
|
|
|
T get (const char* key) { |
|
|
|
T t{}; |
|
|
|
for (auto& it : pairs_) { |
|
|
|
if (it.key.compare(key) == 0) { |
|
|
|
extract_(it.value, &t); |
|
|
|
break; |
|
|
|
} |
|
|
|
} |
|
|
|
return t; |
|
|
|
} |
|
|
|
bool is_valid() const { return valid_; } |
|
|
|
|
|
|
|
private: |
|
|
|
/*! |
|
|
|
* Convert the text pointed by \c str to a value and store it to |
|
|
|
* \c value. The type of conversion is deduced by the compiler |
|
|
|
* \tparam T The type of the value |
|
|
|
* \param str pointer to string with the value |
|
|
|
* \param value pointer to converted value |
|
|
|
*/ |
|
|
|
void extract_(std::string_view str, bool* value) { |
|
|
|
*value = ( |
|
|
|
!std::strncmp(str.data(), "true", str.size()) || |
|
|
|
!std::strncmp(str.data(), "True", str.size()) || |
|
|
|
!std::strncmp(str.data(), "TRUE", str.size()) || |
|
|
|
!std::strncmp(str.data(), "1", str.size()) |
|
|
|
) ? true : false; |
|
|
|
} |
|
|
|
void extract_(std::string_view str, int* value) { |
|
|
|
*value = std::atoi(str.data()); |
|
|
|
} |
|
|
|
void extract_(std::string_view str, unsigned int* value) { |
|
|
|
*value = (unsigned int)std::atoi(str.data()); |
|
|
|
} |
|
|
|
void extract_(std::string_view str, long* value) { |
|
|
|
*value = std::atol(str.data()); |
|
|
|
} |
|
|
|
void extract_(std::string_view str, unsigned long* value) { |
|
|
|
*value = (unsigned long)std::atol(str.data()); |
|
|
|
} |
|
|
|
void extract_(std::string_view str, double* value) { |
|
|
|
*value = std::atof(str.data()); |
|
|
|
} |
|
|
|
void extract_(std::string_view str, char** value) { |
|
|
|
*value = (char*)str.data(); |
|
|
|
} |
|
|
|
void extract_(std::string_view str, string_view* value) { |
|
|
|
*value = str; |
|
|
|
} |
|
|
|
//! Specialization (as overload function) to handle void* types |
|
|
|
void extract_ (const char* str, void* value) noexcept { |
|
|
|
(void)*str; (void)value; |
|
|
|
} |
|
|
|
private: |
|
|
|
std::string_view buffer_; |
|
|
|
std::array<jpair_t, N> pairs_; |
|
|
|
bool valid_; |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#endif /* JSON_H_ */ |