mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
Serialize JSON directly to cout
This commit is contained in:
parent
61a16f78a8
commit
20f58d7211
@ -105,26 +105,24 @@ parse_id(std::wstring_view const& s) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static std::string
|
static void
|
||||||
serialize_string_for_json(std::string const &src) {
|
serialize_string_for_json(std::string const &src, std::ostream &out) {
|
||||||
std::string ans("\"");
|
out << '"';
|
||||||
ans.reserve(src.size() + 16);
|
|
||||||
for (auto ch : src) {
|
for (auto ch : src) {
|
||||||
switch(ch) {
|
switch(ch) {
|
||||||
case '\\':
|
case '\\':
|
||||||
ans += "\\\\"; break;
|
out << "\\\\"; break;
|
||||||
case '"':
|
case '"':
|
||||||
ans += "\\\""; break;
|
out << "\\\""; break;
|
||||||
case '\n':
|
case '\n':
|
||||||
ans += "\\n"; break;
|
out << "\\n"; break;
|
||||||
case '\r':
|
case '\r':
|
||||||
ans += "\\r"; break;
|
out << "\\r"; break;
|
||||||
default:
|
default:
|
||||||
ans += ch; break;
|
out << ch; break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ans += '"';
|
out << '"';
|
||||||
return ans;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class json_val { // {{{
|
class json_val { // {{{
|
||||||
@ -181,41 +179,38 @@ public:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string serialize() const {
|
void serialize(std::ostream &out) const {
|
||||||
switch(type) {
|
switch(type) {
|
||||||
case DT_NONE:
|
case DT_NONE:
|
||||||
return "nil";
|
out << "nil"; break;
|
||||||
case DT_BOOL:
|
case DT_BOOL:
|
||||||
return b ? "true" : "false";
|
out << b ? "true" : "false"; break;
|
||||||
case DT_INT:
|
case DT_INT:
|
||||||
// this is not really correct since JS has various limits on numeric types, but good enough for us
|
// this is not really correct since JS has various limits on numeric types, but good enough for us
|
||||||
return std::to_string(i);
|
out << i; break;
|
||||||
case DT_STRING:
|
case DT_STRING:
|
||||||
return serialize_string_for_json(s);
|
return serialize_string_for_json(s, out);
|
||||||
case DT_LIST: {
|
case DT_LIST: {
|
||||||
std::string ans("[");
|
out << '[';
|
||||||
ans.reserve(list.size() * 32);
|
|
||||||
for (auto const &i : list) {
|
for (auto const &i : list) {
|
||||||
ans += i.serialize();
|
i.serialize(out);
|
||||||
ans += ", ";
|
out << ", ";
|
||||||
}
|
}
|
||||||
ans.erase(ans.size() - 2); ans += "]";
|
out << ']';
|
||||||
return ans;
|
break;
|
||||||
}
|
}
|
||||||
case DT_OBJECT: {
|
case DT_OBJECT: {
|
||||||
std::string ans("{");
|
out << '{';
|
||||||
ans.reserve(object.size() * 64);
|
|
||||||
for (const auto& [key, value]: object) {
|
for (const auto& [key, value]: object) {
|
||||||
ans += serialize_string_for_json(key);
|
serialize_string_for_json(key, out);
|
||||||
ans += ": ";
|
out << ": ";
|
||||||
ans += value.serialize();
|
value.serialize(out);
|
||||||
ans += ", ";
|
out << ", ";
|
||||||
}
|
}
|
||||||
ans.erase(ans.size() - 2); ans += "}";
|
out << '}';
|
||||||
return ans;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return "";
|
|
||||||
}
|
}
|
||||||
}; // }}}
|
}; // }}}
|
||||||
|
|
||||||
@ -223,7 +218,9 @@ static void
|
|||||||
output(id_type cmd_id, std::string_view const &msg_type, json_val const &&msg) {
|
output(id_type cmd_id, std::string_view const &msg_type, json_val const &&msg) {
|
||||||
std::scoped_lock sl(output_lock);
|
std::scoped_lock sl(output_lock);
|
||||||
try {
|
try {
|
||||||
std::cout << cmd_id << " " << msg_type << " " << msg.serialize() << std::endl;
|
std::cout << cmd_id << " " << msg_type << " ";
|
||||||
|
msg.serialize(std::cout);
|
||||||
|
std::cout << std::endl;
|
||||||
} catch(...) {}
|
} catch(...) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -704,30 +701,6 @@ class Synthesizer {
|
|||||||
|
|
||||||
static Synthesizer sx;
|
static Synthesizer sx;
|
||||||
|
|
||||||
static inline std::wstring
|
|
||||||
decode_utf8(std::string_view const& src) {
|
|
||||||
std::wstring ans(src.length() + 1, 0);
|
|
||||||
size_t count = MultiByteToWideChar(CP_UTF8, 0, src.data(), (int)src.length(), ans.data(), (int)ans.length());
|
|
||||||
if (count == 0) {
|
|
||||||
switch(GetLastError()) {
|
|
||||||
case ERROR_INSUFFICIENT_BUFFER:
|
|
||||||
throw std::exception("Could not convert UTF-8 to UTF-16: buffer too small");
|
|
||||||
case ERROR_INVALID_PARAMETER:
|
|
||||||
throw std::exception("Could not convert UTF-8 to UTF-16: invalid parameter");
|
|
||||||
case ERROR_NO_UNICODE_TRANSLATION:
|
|
||||||
throw std::exception("Could not convert UTF-8 to UTF-16: invalid UTF-8 encountered");
|
|
||||||
default:
|
|
||||||
throw std::exception("Could not convert UTF-8 to UTF-16: unknown error");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
count++; // ensure trailing null
|
|
||||||
if (ans.length() > count) {
|
|
||||||
auto extra = ans.length() - count;
|
|
||||||
ans.erase(ans.length() - extra, extra);
|
|
||||||
}
|
|
||||||
return ans;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
handle_speak(id_type cmd_id, std::vector<std::wstring_view> &parts) {
|
handle_speak(id_type cmd_id, std::vector<std::wstring_view> &parts) {
|
||||||
bool is_ssml = false, is_shm = false;
|
bool is_ssml = false, is_shm = false;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user