Implement JSON
This commit is contained in:
73
apps/tjsonpretty.cpp
Normal file
73
apps/tjsonpretty.cpp
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
#include "TessesFramework/TessesFramework.hpp"
|
||||||
|
using namespace Tesses::Framework::Streams;
|
||||||
|
using namespace Tesses::Framework::Serialization::Json;
|
||||||
|
using namespace Tesses::Framework::TextStreams;
|
||||||
|
FileStream* OpenWrite(std::string dest)
|
||||||
|
{
|
||||||
|
if(dest == "-")
|
||||||
|
{
|
||||||
|
return new FileStream(stdout,false,"w");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
FileStream* strm = new FileStream(dest,"w");
|
||||||
|
if(!strm->CanWrite())
|
||||||
|
{
|
||||||
|
delete strm;
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
return strm;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
FileStream* OpenRead(std::string src)
|
||||||
|
{
|
||||||
|
if(src == "-")
|
||||||
|
{
|
||||||
|
return new FileStream(stdin,false,"r");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
FileStream* strm = new FileStream(src,"r");
|
||||||
|
if(!strm->CanRead())
|
||||||
|
{
|
||||||
|
delete strm;
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
return strm;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
int main(int argc, char** argv)
|
||||||
|
{
|
||||||
|
if(argc < 3)
|
||||||
|
{
|
||||||
|
std::cout << "USAGE: " << argv[0] << " SRC DEST" << std::endl;
|
||||||
|
std::cout << "SRC: json file or - for stdin to make pretty" << std::endl;
|
||||||
|
std::cout << "DEST: prettied file or - for stdout" << std::endl;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
FileStream* src = OpenRead(argv[1]);
|
||||||
|
|
||||||
|
FileStream* dest = OpenWrite(argv[2]);
|
||||||
|
|
||||||
|
if(src == nullptr)
|
||||||
|
{
|
||||||
|
if(dest != nullptr) delete dest;
|
||||||
|
std::cerr << "ERROR: Input could not be read" << std::endl;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if(dest == nullptr)
|
||||||
|
{
|
||||||
|
delete src;
|
||||||
|
std::cerr << "ERROR: Output could not be read" << std::endl;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
StreamReader reader(src,true);
|
||||||
|
StreamWriter writer(dest,true);
|
||||||
|
|
||||||
|
auto str = reader.ReadToEnd();
|
||||||
|
writer.WriteLine(Json::Encode(Json::Decode(str)));
|
||||||
|
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
73
apps/tjsonunpretty.cpp
Normal file
73
apps/tjsonunpretty.cpp
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
#include "TessesFramework/TessesFramework.hpp"
|
||||||
|
using namespace Tesses::Framework::Streams;
|
||||||
|
using namespace Tesses::Framework::Serialization::Json;
|
||||||
|
using namespace Tesses::Framework::TextStreams;
|
||||||
|
FileStream* OpenWrite(std::string dest)
|
||||||
|
{
|
||||||
|
if(dest == "-")
|
||||||
|
{
|
||||||
|
return new FileStream(stdout,false,"w");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
FileStream* strm = new FileStream(dest,"w");
|
||||||
|
if(!strm->CanWrite())
|
||||||
|
{
|
||||||
|
delete strm;
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
return strm;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
FileStream* OpenRead(std::string src)
|
||||||
|
{
|
||||||
|
if(src == "-")
|
||||||
|
{
|
||||||
|
return new FileStream(stdin,false,"r");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
FileStream* strm = new FileStream(src,"r");
|
||||||
|
if(!strm->CanRead())
|
||||||
|
{
|
||||||
|
delete strm;
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
return strm;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
int main(int argc, char** argv)
|
||||||
|
{
|
||||||
|
if(argc < 3)
|
||||||
|
{
|
||||||
|
std::cout << "USAGE: " << argv[0] << " SRC DEST" << std::endl;
|
||||||
|
std::cout << "SRC: json file or - for stdin to make unpretty" << std::endl;
|
||||||
|
std::cout << "DEST: unprettied file or - for stdout" << std::endl;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
FileStream* src = OpenRead(argv[1]);
|
||||||
|
|
||||||
|
FileStream* dest = OpenWrite(argv[2]);
|
||||||
|
|
||||||
|
if(src == nullptr)
|
||||||
|
{
|
||||||
|
if(dest != nullptr) delete dest;
|
||||||
|
std::cerr << "ERROR: Input could not be read" << std::endl;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if(dest == nullptr)
|
||||||
|
{
|
||||||
|
delete src;
|
||||||
|
std::cerr << "ERROR: Output could not be read" << std::endl;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
StreamReader reader(src,true);
|
||||||
|
StreamWriter writer(dest,true);
|
||||||
|
|
||||||
|
auto str = reader.ReadToEnd();
|
||||||
|
writer.WriteLine(Json::Encode(Json::Decode(str),false));
|
||||||
|
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
13
examples/printjsondecodedemoji.cpp
Normal file
13
examples/printjsondecodedemoji.cpp
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
#include "TessesFramework/Serialization/Json.hpp"
|
||||||
|
|
||||||
|
using namespace Tesses::Framework::Serialization::Json;
|
||||||
|
|
||||||
|
int main(int argc, char** argv)
|
||||||
|
{
|
||||||
|
auto json = Json::Decode("\"\\uD83D\\uDE44\"");
|
||||||
|
std::string str;
|
||||||
|
if(TryGetJToken(json,str))
|
||||||
|
{
|
||||||
|
std::cout << str << std::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
74
include/TessesFramework/Serialization/Json.hpp
Normal file
74
include/TessesFramework/Serialization/Json.hpp
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
#include <variant>
|
||||||
|
#include <map>
|
||||||
|
#include <iostream>
|
||||||
|
namespace Tesses::Framework::Serialization::Json
|
||||||
|
{
|
||||||
|
class JArray;
|
||||||
|
class JObject;
|
||||||
|
class JUndefined {
|
||||||
|
public:
|
||||||
|
};
|
||||||
|
|
||||||
|
using JToken = std::variant<JUndefined,std::nullptr_t,bool,int64_t,double,std::string, JArray, JObject>;
|
||||||
|
|
||||||
|
class JOItem;
|
||||||
|
|
||||||
|
class JObject {
|
||||||
|
std::map<std::string,JToken> map;
|
||||||
|
public:
|
||||||
|
JObject();
|
||||||
|
JObject(std::initializer_list<JOItem> items);
|
||||||
|
void SetValue(std::string key, JToken item);
|
||||||
|
JToken GetValue(std::string key);
|
||||||
|
void Remove(std::string key);
|
||||||
|
std::map<std::string,JToken>& GetMap();
|
||||||
|
std::map<std::string,JToken>::iterator begin();
|
||||||
|
std::map<std::string,JToken>::iterator end();
|
||||||
|
};
|
||||||
|
class JArray
|
||||||
|
{
|
||||||
|
std::vector<JToken> items;
|
||||||
|
public:
|
||||||
|
JArray();
|
||||||
|
JArray(std::initializer_list<JToken> items);
|
||||||
|
std::vector<JToken>& GetVector();
|
||||||
|
void Add(JToken item);
|
||||||
|
void RemoveAt(size_t index);
|
||||||
|
size_t Count();
|
||||||
|
void SetAt(size_t index, JToken item);
|
||||||
|
JToken GetAt(size_t index);
|
||||||
|
void Clear();
|
||||||
|
|
||||||
|
std::vector<JToken>::iterator begin();
|
||||||
|
std::vector<JToken>::iterator end();
|
||||||
|
};
|
||||||
|
class JOItem {
|
||||||
|
public:
|
||||||
|
JOItem();
|
||||||
|
JOItem(std::string key, JToken value);
|
||||||
|
|
||||||
|
std::string key;
|
||||||
|
JToken value;
|
||||||
|
};
|
||||||
|
template<typename T>
|
||||||
|
bool TryGetJToken(JToken json, T& item)
|
||||||
|
{
|
||||||
|
if(std::holds_alternative<T>(json))
|
||||||
|
{
|
||||||
|
item = std::get<T>(json);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
class Json
|
||||||
|
{
|
||||||
|
static std::string tab(std::string str);
|
||||||
|
public:
|
||||||
|
static JToken Decode(std::string str);
|
||||||
|
static std::string Encode(JToken tkn, bool indent=true);
|
||||||
|
};
|
||||||
|
}
|
||||||
527
src/Serialization/Json.cpp
Normal file
527
src/Serialization/Json.cpp
Normal file
@ -0,0 +1,527 @@
|
|||||||
|
#include "TessesFramework/Serialization/Json.hpp"
|
||||||
|
#include "TessesFramework/Http/HttpUtils.hpp"
|
||||||
|
#include <functional>
|
||||||
|
|
||||||
|
#include "TessesFramework/Common.hpp"
|
||||||
|
using namespace Tesses::Framework::Http;
|
||||||
|
namespace Tesses::Framework::Serialization::Json
|
||||||
|
{
|
||||||
|
void JObject::Remove(std::string key)
|
||||||
|
{
|
||||||
|
map.erase(key);
|
||||||
|
}
|
||||||
|
void JObject::SetValue(std::string key, JToken item)
|
||||||
|
{
|
||||||
|
if(!std::holds_alternative<JUndefined>(item))
|
||||||
|
map[key] = item;
|
||||||
|
else
|
||||||
|
Remove(key);
|
||||||
|
}
|
||||||
|
JToken JObject::GetValue(std::string key)
|
||||||
|
{
|
||||||
|
if(map.count(key)>0)
|
||||||
|
return map[key];
|
||||||
|
else
|
||||||
|
return JUndefined();
|
||||||
|
}
|
||||||
|
std::map<std::string,JToken>& JObject::GetMap()
|
||||||
|
{
|
||||||
|
return map;
|
||||||
|
}
|
||||||
|
std::map<std::string,JToken>::iterator JObject::begin()
|
||||||
|
{
|
||||||
|
return map.begin();
|
||||||
|
}
|
||||||
|
std::map<std::string,JToken>::iterator JObject::end()
|
||||||
|
{
|
||||||
|
return map.end();
|
||||||
|
}
|
||||||
|
JArray::JArray()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
JArray::JArray(std::initializer_list<JToken> tokens)
|
||||||
|
{
|
||||||
|
this->items = tokens;
|
||||||
|
}
|
||||||
|
std::vector<JToken>& JArray::GetVector()
|
||||||
|
{
|
||||||
|
return items;
|
||||||
|
}
|
||||||
|
void JArray::Add(JToken item)
|
||||||
|
{
|
||||||
|
if(!std::holds_alternative<JUndefined>(item))
|
||||||
|
items.push_back(item);
|
||||||
|
}
|
||||||
|
void JArray::RemoveAt(size_t index)
|
||||||
|
{
|
||||||
|
if(index < items.size())
|
||||||
|
items.erase(items.begin()+index);
|
||||||
|
}
|
||||||
|
size_t JArray::Count()
|
||||||
|
{
|
||||||
|
return items.size();
|
||||||
|
}
|
||||||
|
void JArray::SetAt(size_t index, JToken item)
|
||||||
|
{
|
||||||
|
if(index < items.size() && !std::holds_alternative<JUndefined>(item))
|
||||||
|
items[index] = item;
|
||||||
|
}
|
||||||
|
JToken JArray::GetAt(size_t index)
|
||||||
|
{
|
||||||
|
if(index < items.size())
|
||||||
|
return items.at(index);
|
||||||
|
return JUndefined();
|
||||||
|
}
|
||||||
|
void JArray::Clear()
|
||||||
|
{
|
||||||
|
items.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<JToken>::iterator JArray::begin()
|
||||||
|
{
|
||||||
|
return items.begin();
|
||||||
|
}
|
||||||
|
std::vector<JToken>::iterator JArray::end()
|
||||||
|
{
|
||||||
|
return items.end();
|
||||||
|
}
|
||||||
|
JOItem::JOItem()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
JOItem::JOItem(std::string key, JToken value)
|
||||||
|
{
|
||||||
|
this->key = key;
|
||||||
|
this->value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
JObject::JObject()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
JObject::JObject(std::initializer_list<JOItem> items)
|
||||||
|
{
|
||||||
|
for(auto item : items)
|
||||||
|
this->map[item.key] = item.value;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string Json::tab(std::string txt)
|
||||||
|
{
|
||||||
|
std::string newStr="\t";
|
||||||
|
for(auto item : txt)
|
||||||
|
{
|
||||||
|
if(item == '\n')
|
||||||
|
{
|
||||||
|
newStr.append("\n\t");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
newStr.push_back(item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return newStr;
|
||||||
|
}
|
||||||
|
|
||||||
|
JToken Json::Decode(std::string str)
|
||||||
|
{
|
||||||
|
std::vector<std::pair<std::string,bool>> tokens;
|
||||||
|
|
||||||
|
std::string buff={};
|
||||||
|
|
||||||
|
std::function<void()> flush = [&buff,&tokens]()->void {
|
||||||
|
if(!buff.empty())
|
||||||
|
{
|
||||||
|
tokens.push_back(std::pair<std::string,bool>(buff,false));
|
||||||
|
buff={};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
for(size_t i = 0; i < str.size(); i++)
|
||||||
|
{
|
||||||
|
switch(str[i])
|
||||||
|
{
|
||||||
|
case '\"':
|
||||||
|
{
|
||||||
|
flush();
|
||||||
|
i++;
|
||||||
|
std::string str2={};
|
||||||
|
for(; i < str.size() && str[i] != '\"'; i++)
|
||||||
|
{
|
||||||
|
if(str[i] == '\\')
|
||||||
|
{
|
||||||
|
i++;
|
||||||
|
if(i < str.size())
|
||||||
|
{
|
||||||
|
if(str[i] == 'n')
|
||||||
|
{
|
||||||
|
str2.push_back('\n');
|
||||||
|
}
|
||||||
|
else if(str[i] == 'r')
|
||||||
|
{
|
||||||
|
str2.push_back('\r');
|
||||||
|
}
|
||||||
|
else if(str[i] == 't')
|
||||||
|
{
|
||||||
|
str2.push_back('\t');
|
||||||
|
}
|
||||||
|
else if(str[i] == 'f')
|
||||||
|
{
|
||||||
|
str2.push_back('\f');
|
||||||
|
}
|
||||||
|
else if(str[i] == 'b')
|
||||||
|
{
|
||||||
|
str2.push_back('\b');
|
||||||
|
}
|
||||||
|
else if(str[i] == 'u')
|
||||||
|
{
|
||||||
|
i++;
|
||||||
|
//we need to get four of these
|
||||||
|
uint16_t v = 0;
|
||||||
|
if(i + 4 <= str.size())
|
||||||
|
{
|
||||||
|
for(size_t i2 = 0; i2 < 4; i2++,i++)
|
||||||
|
{
|
||||||
|
v |= HttpUtils::HexToNibble(str[i]) << ((3-i2) * 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
uint32_t v2 = v;
|
||||||
|
|
||||||
|
if((v & 0xFC00) == 0xD800)
|
||||||
|
{
|
||||||
|
|
||||||
|
v2 = (v & 0x03FF) << 10;
|
||||||
|
if(i + 6 <= str.size() && str.substr(i,2) == "\\u")
|
||||||
|
{
|
||||||
|
i+=2;
|
||||||
|
v=0;
|
||||||
|
|
||||||
|
for(size_t i2 = 0; i2 < 4; i2++, i++)
|
||||||
|
{
|
||||||
|
v |= HttpUtils::HexToNibble(str[i]) << ((3-i2) * 4);
|
||||||
|
}
|
||||||
|
if((v & 0xFC00) != 0xDC00)
|
||||||
|
{
|
||||||
|
throw TextException("Not a lower utf-16 surrogate pair.");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
v2 |= (v & 0x03FF);
|
||||||
|
|
||||||
|
v2 += 0x10000;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
|
||||||
|
throw TextException("Could not read lower utf-16 surrogate pair.");
|
||||||
|
}
|
||||||
|
if(v2 <= 0x7F)
|
||||||
|
{
|
||||||
|
str2.push_back((char)v2);
|
||||||
|
}
|
||||||
|
else if(v2 >= 0x80 && v2 <= 0x7FF)
|
||||||
|
{
|
||||||
|
uint8_t high = 0b11000000 | ((v2 >> 6) & 0b00011111);
|
||||||
|
uint8_t low = 0b10000000 | (v2 & 0b00111111);
|
||||||
|
str2.push_back((char)high);
|
||||||
|
str2.push_back((char)low);
|
||||||
|
}
|
||||||
|
else if(v2 >= 0x800 && v2 <= 0xFFFF)
|
||||||
|
{
|
||||||
|
uint8_t highest = 0b11100000 | ((v2 >> 12) & 0b00001111);
|
||||||
|
uint8_t high = 0b10000000 | ((v2 >> 6) & 0b00111111);
|
||||||
|
uint8_t low = 0b10000000 | (v2 & 0b00111111);
|
||||||
|
str2.push_back((char)highest);
|
||||||
|
str2.push_back((char)high);
|
||||||
|
str2.push_back((char)low);
|
||||||
|
}
|
||||||
|
else if(v2 >= 0x010000 && v2 <= 0x10FFFF)
|
||||||
|
{
|
||||||
|
uint8_t highest = 0b11110000 | ((v2 >> 18) & 0b00000111);
|
||||||
|
uint8_t high = 0b10000000 | ((v2 >> 12) & 0b00111111);
|
||||||
|
uint8_t low = 0b10000000 | ((v2 >> 6) & 0b00111111);
|
||||||
|
uint8_t lowest = 0b10000000 | (v2 & 0b00111111);
|
||||||
|
str2.push_back((char)highest);
|
||||||
|
str2.push_back((char)high);
|
||||||
|
str2.push_back((char)low);
|
||||||
|
str2.push_back((char)lowest);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
str2.push_back(str[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else break;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
str2.push_back(str[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
tokens.push_back(std::pair<std::string,bool>(str2,true));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case ',':
|
||||||
|
case '[':
|
||||||
|
case ']':
|
||||||
|
case '(':
|
||||||
|
case ')':
|
||||||
|
case '{':
|
||||||
|
case '}':
|
||||||
|
case ':':
|
||||||
|
flush();
|
||||||
|
tokens.push_back(std::pair<std::string,bool>(str.substr(i,1),false));
|
||||||
|
break;
|
||||||
|
case ' ':
|
||||||
|
case '\n':
|
||||||
|
case '\r':
|
||||||
|
case '\t':
|
||||||
|
flush();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
buff.push_back(str[i]);
|
||||||
|
break;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
flush();
|
||||||
|
if(tokens.size() == 0) return JUndefined();
|
||||||
|
|
||||||
|
size_t tokenIndex=0;
|
||||||
|
|
||||||
|
std::function<std::pair<std::string,bool>()> pop_token=[&tokens,&tokenIndex]()->std::pair<std::string,bool> {
|
||||||
|
if(tokenIndex >= tokens.size()) throw TextException("Json tokens out of bounds.");
|
||||||
|
return tokens[tokenIndex++];
|
||||||
|
};
|
||||||
|
|
||||||
|
std::function<JToken()> read_token;
|
||||||
|
read_token= [&pop_token,&read_token,&tokenIndex,&tokens]()->JToken{
|
||||||
|
auto tkn = pop_token();
|
||||||
|
if(tkn.second)
|
||||||
|
{
|
||||||
|
return tkn.first;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if(tkn.first == "{")
|
||||||
|
{
|
||||||
|
|
||||||
|
JObject obj;
|
||||||
|
while(true)
|
||||||
|
{
|
||||||
|
begin_dict:
|
||||||
|
tkn = pop_token();
|
||||||
|
if(tkn.second)
|
||||||
|
{
|
||||||
|
std::string key = tkn.first;
|
||||||
|
tkn = pop_token();
|
||||||
|
if(tkn.second || tkn.first != ":")
|
||||||
|
{
|
||||||
|
throw TextException("Invalid JSON key value seperator.");
|
||||||
|
}
|
||||||
|
|
||||||
|
auto value = read_token();
|
||||||
|
obj.SetValue(key,value);
|
||||||
|
}
|
||||||
|
else if(tkn.first == ",")
|
||||||
|
{
|
||||||
|
goto begin_dict;
|
||||||
|
}
|
||||||
|
else if(tkn.first == "}")
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
|
||||||
|
throw TextException("Invalid JSON object.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return obj;
|
||||||
|
}
|
||||||
|
else if(tkn.first == "[")
|
||||||
|
{
|
||||||
|
JArray arr;
|
||||||
|
while(tokenIndex < tokens.size())
|
||||||
|
{
|
||||||
|
auto tkn = tokens[tokenIndex];
|
||||||
|
if(!tkn.second)
|
||||||
|
{
|
||||||
|
if(tkn.first == ",") tokenIndex++;
|
||||||
|
if(tkn.first == "]") {tokenIndex++; break;}
|
||||||
|
}
|
||||||
|
arr.Add(read_token());
|
||||||
|
}
|
||||||
|
return arr;
|
||||||
|
}
|
||||||
|
else if(tkn.first == "true")
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else if(tkn.first == "false")
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
else if(tkn.first == "null")
|
||||||
|
{
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
//number
|
||||||
|
if(tkn.first.find(".") != std::string::npos)
|
||||||
|
{
|
||||||
|
return std::stod(tkn.first);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return std::stoll(tkn.first);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return read_token();
|
||||||
|
}
|
||||||
|
std::string Json::Encode(JToken tkn, bool indent)
|
||||||
|
{
|
||||||
|
int64_t i64;
|
||||||
|
double f64;
|
||||||
|
std::string str;
|
||||||
|
bool b;
|
||||||
|
JArray ls;
|
||||||
|
JObject dict;
|
||||||
|
if(std::holds_alternative<std::nullptr_t>(tkn)) return "null";
|
||||||
|
if(TryGetJToken(tkn,b)) return b ? "true" : "false";
|
||||||
|
if(TryGetJToken(tkn,f64))
|
||||||
|
{
|
||||||
|
auto str = std::to_string(f64);
|
||||||
|
|
||||||
|
if(str.find(".") != std::string::npos)
|
||||||
|
{
|
||||||
|
size_t i;
|
||||||
|
for(i = str.size()-1; str[i] != '.'; i--)
|
||||||
|
{
|
||||||
|
if(str[i] != '0')
|
||||||
|
{
|
||||||
|
i++;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return str.substr(0,i);
|
||||||
|
}
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
if(TryGetJToken(tkn,i64)) return std::to_string(i64);
|
||||||
|
if(TryGetJToken(tkn,str))
|
||||||
|
{
|
||||||
|
std::string str2 = "\"";
|
||||||
|
for(auto c : str)
|
||||||
|
{
|
||||||
|
if(c == '\"')
|
||||||
|
{
|
||||||
|
str2.append("\\\"");
|
||||||
|
}
|
||||||
|
else if(c == '\n')
|
||||||
|
{
|
||||||
|
str2.append("\\n");
|
||||||
|
}
|
||||||
|
else if(c == '\t')
|
||||||
|
{
|
||||||
|
str2.append("\\t");
|
||||||
|
}
|
||||||
|
else if(c == '\r')
|
||||||
|
{
|
||||||
|
str2.append("\\r");
|
||||||
|
}
|
||||||
|
else if(c == '/')
|
||||||
|
{
|
||||||
|
str2.append("\\/");
|
||||||
|
}
|
||||||
|
else if(c == '\\')
|
||||||
|
{
|
||||||
|
str2.append("\\\\");
|
||||||
|
}
|
||||||
|
else if(c == '\f')
|
||||||
|
{
|
||||||
|
str2.append("\\f");
|
||||||
|
}
|
||||||
|
else if(c == '\b')
|
||||||
|
{
|
||||||
|
str2.append("\\b");
|
||||||
|
}
|
||||||
|
else if((c >= 0 && c < 32) || c == 127 )
|
||||||
|
{
|
||||||
|
str2.append("\\\\u00");
|
||||||
|
uint8_t c2 = (uint8_t)c;
|
||||||
|
|
||||||
|
str2.push_back(HttpUtils::NibbleToHex((c2 >> 4) & 0x0F));
|
||||||
|
str2.push_back(HttpUtils::NibbleToHex(c2 & 0x0F));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
str2.push_back(c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
str2.push_back('\"');
|
||||||
|
return str2;
|
||||||
|
}
|
||||||
|
if(TryGetJToken(tkn,dict))
|
||||||
|
{
|
||||||
|
|
||||||
|
std::string str="{";
|
||||||
|
bool first=true;
|
||||||
|
for(auto item : dict)
|
||||||
|
{
|
||||||
|
if(!first) {
|
||||||
|
str.push_back(',');
|
||||||
|
}
|
||||||
|
if(indent) {
|
||||||
|
str.append("\n");
|
||||||
|
str.append(tab(Encode(item.first,true) + ": " + Encode(item.second,true)));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
str.append(Encode(item.first,false)+": "+Encode(item.second,false));
|
||||||
|
}
|
||||||
|
first=false;
|
||||||
|
}
|
||||||
|
if(indent) str.append("\n");
|
||||||
|
str.push_back('}');
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
if(TryGetJToken(tkn,ls))
|
||||||
|
{
|
||||||
|
std::string str="[";
|
||||||
|
bool first=true;
|
||||||
|
for(auto item : ls)
|
||||||
|
{
|
||||||
|
|
||||||
|
if(!first) {
|
||||||
|
str.push_back(',');
|
||||||
|
}
|
||||||
|
if(indent) {
|
||||||
|
str.append("\n");
|
||||||
|
str.append(tab(Encode(item,true)));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
str.append(Encode(item,false));
|
||||||
|
}
|
||||||
|
first=false;
|
||||||
|
}
|
||||||
|
if(indent) str.append("\n");
|
||||||
|
str.push_back(']');
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user