2023-06-20 04:33:09 +00:00
|
|
|
#include "StarJsonBuilder.hpp"
|
|
|
|
#include "StarLexicalCast.hpp"
|
|
|
|
|
|
|
|
namespace Star {
|
|
|
|
|
|
|
|
void JsonBuilderStream::beginObject() {
|
|
|
|
pushSentry();
|
|
|
|
}
|
|
|
|
|
|
|
|
void JsonBuilderStream::objectKey(char32_t const* s, size_t len) {
|
|
|
|
push(Json(s, len));
|
|
|
|
}
|
|
|
|
|
|
|
|
void JsonBuilderStream::endObject() {
|
|
|
|
JsonObject object;
|
|
|
|
while (true) {
|
|
|
|
if (isSentry()) {
|
2024-02-19 15:55:19 +00:00
|
|
|
set(Json(std::move(object)));
|
2023-06-20 04:33:09 +00:00
|
|
|
return;
|
|
|
|
} else {
|
|
|
|
Json v = pop();
|
|
|
|
String k = pop().toString();
|
2024-02-19 15:55:19 +00:00
|
|
|
if (!object.insert(k, std::move(v)).second)
|
2023-06-27 10:23:44 +00:00
|
|
|
throw JsonParsingException(strf("Json object contains a duplicate entry for key '{}'", k));
|
2023-06-20 04:33:09 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void JsonBuilderStream::beginArray() {
|
|
|
|
pushSentry();
|
|
|
|
}
|
|
|
|
|
|
|
|
void JsonBuilderStream::endArray() {
|
|
|
|
JsonArray array;
|
|
|
|
while (true) {
|
|
|
|
if (isSentry()) {
|
|
|
|
array.reverse();
|
2024-02-19 15:55:19 +00:00
|
|
|
set(Json(std::move(array)));
|
2023-06-20 04:33:09 +00:00
|
|
|
return;
|
|
|
|
} else {
|
|
|
|
array.append(pop());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void JsonBuilderStream::putString(char32_t const* s, size_t len) {
|
|
|
|
push(Json(s, len));
|
|
|
|
}
|
|
|
|
|
|
|
|
void JsonBuilderStream::putDouble(char32_t const* s, size_t len) {
|
|
|
|
push(Json(lexicalCast<double>(String(s, len))));
|
|
|
|
}
|
|
|
|
|
|
|
|
void JsonBuilderStream::putInteger(char32_t const* s, size_t len) {
|
|
|
|
push(Json(lexicalCast<long long>(String(s, len))));
|
|
|
|
}
|
|
|
|
|
|
|
|
void JsonBuilderStream::putBoolean(bool b) {
|
|
|
|
push(Json(b));
|
|
|
|
}
|
|
|
|
|
|
|
|
void JsonBuilderStream::putNull() {
|
|
|
|
push(Json());
|
|
|
|
}
|
|
|
|
|
|
|
|
void JsonBuilderStream::putWhitespace(char32_t const*, size_t) {}
|
|
|
|
|
|
|
|
void JsonBuilderStream::putColon() {}
|
|
|
|
|
|
|
|
void JsonBuilderStream::putComma() {}
|
|
|
|
|
|
|
|
size_t JsonBuilderStream::stackSize() {
|
|
|
|
return m_stack.size();
|
|
|
|
}
|
|
|
|
|
|
|
|
Json JsonBuilderStream::takeTop() {
|
|
|
|
if (m_stack.size())
|
|
|
|
return m_stack.takeLast().take();
|
|
|
|
else
|
|
|
|
return Json();
|
|
|
|
}
|
|
|
|
|
|
|
|
void JsonBuilderStream::push(Json v) {
|
2024-02-19 15:55:19 +00:00
|
|
|
m_stack.append(std::move(v));
|
2023-06-20 04:33:09 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
Json JsonBuilderStream::pop() {
|
|
|
|
return m_stack.takeLast().take();
|
|
|
|
}
|
|
|
|
|
|
|
|
void JsonBuilderStream::set(Json v) {
|
2024-02-19 15:55:19 +00:00
|
|
|
m_stack.last() = std::move(v);
|
2023-06-20 04:33:09 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void JsonBuilderStream::pushSentry() {
|
|
|
|
m_stack.append({});
|
|
|
|
}
|
|
|
|
|
|
|
|
bool JsonBuilderStream::isSentry() {
|
|
|
|
return !m_stack.empty() && !m_stack.last();
|
|
|
|
}
|
|
|
|
|
|
|
|
void JsonStreamer<Json>::toJsonStream(Json const& val, JsonStream& stream, bool sort) {
|
|
|
|
Json::Type type = val.type();
|
|
|
|
if (type == Json::Type::Null) {
|
|
|
|
stream.putNull();
|
|
|
|
} else if (type == Json::Type::Float) {
|
|
|
|
auto d = String(toString(val.toDouble())).wideString();
|
|
|
|
stream.putDouble(d.c_str(), d.length());
|
|
|
|
} else if (type == Json::Type::Bool) {
|
|
|
|
stream.putBoolean(val.toBool());
|
|
|
|
} else if (type == Json::Type::Int) {
|
|
|
|
auto i = String(toString(val.toInt())).wideString();
|
|
|
|
stream.putInteger(i.c_str(), i.length());
|
|
|
|
} else if (type == Json::Type::String) {
|
|
|
|
auto ws = val.toString().wideString();
|
|
|
|
stream.putString(ws.c_str(), ws.length());
|
|
|
|
} else if (type == Json::Type::Array) {
|
|
|
|
stream.beginArray();
|
|
|
|
bool first = true;
|
|
|
|
for (auto const& elem : val.iterateArray()) {
|
|
|
|
if (!first)
|
|
|
|
stream.putComma();
|
|
|
|
first = false;
|
|
|
|
toJsonStream(elem, stream, sort);
|
|
|
|
}
|
|
|
|
stream.endArray();
|
|
|
|
} else if (type == Json::Type::Object) {
|
|
|
|
stream.beginObject();
|
|
|
|
if (sort) {
|
|
|
|
auto objectPtr = val.objectPtr();
|
|
|
|
List<JsonObject::const_iterator> iterators;
|
|
|
|
iterators.reserve(objectPtr->size());
|
|
|
|
for (auto i = objectPtr->begin(); i != objectPtr->end(); ++i)
|
|
|
|
iterators.append(i);
|
|
|
|
iterators.sort([](JsonObject::const_iterator a, JsonObject::const_iterator b) {
|
|
|
|
return a->first < b->first;
|
|
|
|
});
|
|
|
|
bool first = true;
|
|
|
|
for (auto const& i : iterators) {
|
|
|
|
if (!first)
|
|
|
|
stream.putComma();
|
|
|
|
first = false;
|
2023-07-06 13:59:18 +00:00
|
|
|
auto ws = i->first.wideString();
|
|
|
|
stream.objectKey(ws.c_str(), ws.length());
|
2023-06-20 04:33:09 +00:00
|
|
|
stream.putColon();
|
|
|
|
toJsonStream(i->second, stream, sort);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
bool first = true;
|
|
|
|
for (auto const& pair : val.iterateObject()) {
|
|
|
|
if (!first)
|
|
|
|
stream.putComma();
|
|
|
|
first = false;
|
|
|
|
auto ws = pair.first.wideString();
|
|
|
|
stream.objectKey(ws.c_str(), ws.length());
|
|
|
|
stream.putColon();
|
|
|
|
toJsonStream(pair.second, stream, sort);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
stream.endObject();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|