Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions data/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@ set(PUBLIC_HEADERS
include/join/utf16.hpp
include/join/probe.hpp
include/join/value.hpp
include/join/document.hpp
include/join/value_builder.hpp
include/join/sax_error.hpp
include/join/sax.hpp
include/join/pack.hpp
include/join/json.hpp
Expand All @@ -20,7 +21,8 @@ set(PUBLIC_HEADERS
)

set(SOURCES
src/sax.cpp
src/value.cpp
src/sax_error.cpp
src/json.cpp
src/zstream.cpp
)
Expand Down
195 changes: 145 additions & 50 deletions data/include/join/json.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
#define JOIN_DATA_JSON_HPP

// libjoin.
#include <join/value_builder.hpp>
#include <join/atodpow.hpp>
#include <join/value.hpp>
#include <join/utf16.hpp>
Expand Down Expand Up @@ -385,13 +386,18 @@ namespace join
*/
int setString (std::string_view value)
{
array ();
append ('"');
if (writeEscaped (value) == -1)
if constexpr (WriteMode == JsonWriteMode::Canonical)
{
reset ();
return -1;
if (JOIN_UNLIKELY (utf8::validate (value.data (), value.data () + value.size ()) == -1))
{
join::lastError = make_error_code (JsonErrc::InvalidEncoding);
reset ();
return -1;
}
}
array ();
append ('"');
writeEscaped (value);
append ('"');
endValue ();
return 0;
Expand Down Expand Up @@ -497,39 +503,132 @@ namespace join
}

/**
* @brief set key.
* @brief set null key.
* @param key object key.
* @return -1.
*/
int setKey ([[maybe_unused]] std::nullptr_t key)
{
join::lastError = make_error_code (SaxErrc::InvalidKey);
reset ();
return -1;
}

/**
* @brief set boolean key.
* @param key object key.
* @return -1.
*/
int setKey ([[maybe_unused]] bool key)
{
join::lastError = make_error_code (SaxErrc::InvalidKey);
reset ();
return -1;
}

/**
* @brief set integer key.
* @param key object key.
* @return -1.
*/
int setKey ([[maybe_unused]] int32_t key)
{
join::lastError = make_error_code (SaxErrc::InvalidKey);
reset ();
return -1;
}

/**
* @brief set unsigned integer key.
* @param key object key.
* @return -1.
*/
int setKey ([[maybe_unused]] uint32_t key)
{
join::lastError = make_error_code (SaxErrc::InvalidKey);
reset ();
return -1;
}

/**
* @brief set 64 bits integer key.
* @param key object key.
* @return -1.
*/
int setKey ([[maybe_unused]] int64_t key)
{
join::lastError = make_error_code (SaxErrc::InvalidKey);
reset ();
return -1;
}

/**
* @brief set unsigned 64 bits integer key.
* @param key object key.
* @return -1.
*/
int setKey ([[maybe_unused]] uint64_t key)
{
join::lastError = make_error_code (SaxErrc::InvalidKey);
reset ();
return -1;
}

/**
* @brief set real key.
* @param key object key.
* @return -1.
*/
int setKey ([[maybe_unused]] double key)
{
join::lastError = make_error_code (SaxErrc::InvalidKey);
reset ();
return -1;
}

/**
* @brief set string key.
* @param key object key.
* @return 0 on success, -1 otherwise.
*/
int setKey (const Value& key)
int setKey (std::string_view key)
{
if (JOIN_UNLIKELY (_depth == 0))
{
join::lastError = make_error_code (SaxErrc::InvalidParent);
reset ();
return -1;
}
if (JOIN_UNLIKELY (!key.isString ()))
if constexpr (WriteMode == JsonWriteMode::Canonical)
{
join::lastError = make_error_code (SaxErrc::InvalidKey);
reset ();
return -1;
if (JOIN_UNLIKELY (utf8::validate (key.data (), key.data () + key.size ()) == -1))
{
join::lastError = make_error_code (JsonErrc::InvalidEncoding);
reset ();
return -1;
}
}
comma ();
newLine ();
append ('"');
if (writeEscaped (key.getString ()) == -1)
{
reset ();
return -1;
}
writeEscaped (key);
append ('"');
append (':');
space ();
_first = true;
return 0;
}

/**
* @brief set string key.
* @param key object key.
* @return 0 on success, -1 otherwise.
*/
int setKey (const char* key)
{
return setKey (std::string_view (key));
}

/**
* @brief stop object.
* @return 0 on success, -1 otherwise.
Expand Down Expand Up @@ -686,10 +785,10 @@ namespace join
*/
void writeDouble (double value)
{
char buf[25];
char* end = join::dtoa (buf, value);
if constexpr (WriteMode == JsonWriteMode::Canonical)
{
char buf[25];
char* end = join::dtoa (buf, value);
for (char* pos = buf; pos < end; ++pos)
{
append (*pos);
Expand All @@ -701,18 +800,19 @@ namespace join
}
else
{
append (buf, end - buf);
if (JOIN_UNLIKELY (sizeof (_buffer) - _size < 25))
{
flush ();
}
_size = join::dtoa (_buffer + _size, value) - _buffer;
}
}

/**
* @brief escape string value.
* @param value string value to escape.
* @return 0 on success, -1 otherwise.
*/
template <JsonWriteMode Mode = WriteMode>
int writeEscaped (std::string_view value)
requires (Mode == JsonWriteMode::None)
void writeEscaped (std::string_view value)
{
const char* cur = value.data ();
const char* end = cur + value.size ();
Expand Down Expand Up @@ -769,25 +869,6 @@ namespace join

++cur;
}

return 0;
}

/**
* @brief validate and escape string value.
* @param value string value to escape.
* @return 0 on success, -1 otherwise.
*/
template <JsonWriteMode Mode = WriteMode>
int writeEscaped (std::string_view value)
requires (Mode == JsonWriteMode::Canonical)
{
if (JOIN_UNLIKELY (utf8::validate (value.data (), value.data () + value.size ()) == -1))
{
join::lastError = make_error_code (JsonErrc::InvalidEncoding);
return -1;
}
return writeEscaped<JsonWriteMode::None> (value);
}

/**
Expand Down Expand Up @@ -964,7 +1045,7 @@ namespace join
/// JSON default writer.
using JsonWriter = BasicJsonWriter<JsonWriteMode::None>;

/// JSON canonicalizer, sorting object members when used with Document::serialize.
/// JSON canonicalizer, sorting object members when used with Value::serialize.
using JsonCanonicalizer = BasicJsonWriter<JsonWriteMode::Canonical>;

/**
Expand Down Expand Up @@ -1100,9 +1181,9 @@ namespace join
* @return 0 on success, -1 otherwise.
*/
template <typename Handler>
int deserialize (const std::string& document, Handler& handler)
int deserialize (std::string_view document, Handler& handler)
{
StringProbe in (document.c_str (), document.size ());
StringProbe in (document.data (), document.size ());
return read (in, handler);
}

Expand Down Expand Up @@ -1185,14 +1266,26 @@ namespace join
}

protected:
/**
* @brief parse a document into a value.
* @param document document to parse.
* @param value value receiving the document.
* @return 0 on success, -1 otherwise.
*/
template <typename ProbeType>
int read (ProbeType& document, Value& value)
{
return read (document, ValueBuilder (value));
}

/**
* @brief parse a document, resetting the handler on failure.
* @param document document to parse.
* @param handler handler receiving the document.
* @return 0 on success, -1 otherwise.
*/
template <typename ProbeType, typename Handler>
int read (ProbeType& document, Handler& handler)
int read (ProbeType& document, Handler&& handler)
{
try
{
Expand Down Expand Up @@ -1705,8 +1798,10 @@ namespace join
return handler.setDouble (d);
}

join::lastError = make_error_code (SaxErrc::InvalidValue); // LCOV_EXCL_LINE
return -1; // LCOV_EXCL_LINE
// LCOV_EXCL_START
join::lastError = make_error_code (SaxErrc::InvalidValue);
return -1;
// LCOV_EXCL_STOP
}

/**
Expand Down Expand Up @@ -1868,7 +1963,7 @@ namespace join
if (JOIN_LIKELY (document.peek () == '"'))
{
document.get ();
return isKey ? handler.setKey (Value (chunk)) : handler.setString (chunk);
return isKey ? handler.setKey (chunk) : handler.setString (chunk);
}
}

Expand Down Expand Up @@ -1911,7 +2006,7 @@ namespace join
}
}

int result = isKey ? handler.setKey (Value (output)) : handler.setString (output);
int result = isKey ? handler.setKey (output) : handler.setString (output);
cache = std::move (output);
return result;
}
Expand Down
Loading
Loading