blob: 7b8556d6211422d4436506c2145f64b31c954fcb [file] [log] [blame]
// After editing this file, run "go generate" in the ../data directory.
// Copyright 2020 The Wuffs Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// ---------------- Auxiliary - JSON
#if !defined(WUFFS_CONFIG__MODULES) || defined(WUFFS_CONFIG__MODULE__AUX__JSON)
#include <utility>
namespace wuffs_aux {
DecodeJsonResult::DecodeJsonResult(std::string&& error_message0,
uint64_t cursor_position0)
: error_message(std::move(error_message0)),
cursor_position(cursor_position0) {}
std::string //
DecodeJsonCallbacks::AppendByteString(std::string&& val) {
return "wuffs_aux::JsonDecoder: unexpected JSON byte string";
}
void //
DecodeJsonCallbacks::Done(DecodeJsonResult& result,
sync_io::Input& input,
IOBuffer& buffer) {}
DecodeJsonResult //
DecodeJson(DecodeJsonCallbacks&& callbacks,
sync_io::Input&& input,
wuffs_base__slice_u32 quirks) {
// Prepare the wuffs_base__io_buffer and the resultant error_message.
wuffs_base__io_buffer* io_buf = input.BringsItsOwnIOBuffer();
wuffs_base__io_buffer fallback_io_buf = wuffs_base__empty_io_buffer();
std::unique_ptr<uint8_t[]> fallback_io_array(nullptr);
if (!io_buf) {
fallback_io_array = std::unique_ptr<uint8_t[]>(new uint8_t[4096]);
fallback_io_buf = wuffs_base__ptr_u8__writer(fallback_io_array.get(), 4096);
io_buf = &fallback_io_buf;
}
size_t cursor_index = 0;
std::string ret_error_message;
std::string io_error_message;
do {
// Prepare the low-level JSON decoder.
wuffs_json__decoder::unique_ptr dec = wuffs_json__decoder::alloc();
if (!dec) {
ret_error_message = "wuffs_aux::JsonDecoder: out of memory";
goto done;
}
for (size_t i = 0; i < quirks.len; i++) {
dec->set_quirk_enabled(quirks.ptr[i], true);
}
// Prepare the wuffs_base__tok_buffer.
wuffs_base__token tok_array[256];
wuffs_base__token_buffer tok_buf =
wuffs_base__slice_token__writer(wuffs_base__make_slice_token(
&tok_array[0], (sizeof(tok_array) / sizeof(tok_array[0]))));
wuffs_base__status tok_status = wuffs_base__make_status(nullptr);
// Prepare other state.
uint32_t depth = 0;
std::string str;
// Loop, doing these two things:
// 1. Get the next token.
// 2. Process that token.
while (true) {
// 1. Get the next token.
while (tok_buf.meta.ri >= tok_buf.meta.wi) {
if (tok_status.repr == nullptr) {
// No-op.
} else if (tok_status.repr == wuffs_base__suspension__short_write) {
tok_buf.compact();
} else if (tok_status.repr == wuffs_base__suspension__short_read) {
// Read from input to io_buf.
if (!io_error_message.empty()) {
ret_error_message = std::move(io_error_message);
goto done;
} else if (cursor_index != io_buf->meta.ri) {
ret_error_message =
"wuffs_aux::JsonDecoder: internal error: bad cursor_index";
goto done;
} else if (io_buf->meta.closed) {
ret_error_message =
"wuffs_aux::JsonDecoder: internal error: io_buf is closed";
goto done;
}
io_buf->compact();
if (io_buf->meta.wi >= io_buf->data.len) {
ret_error_message =
"wuffs_aux::JsonDecoder: internal error: io_buf is full";
goto done;
}
cursor_index = io_buf->meta.ri;
io_error_message = input.CopyIn(io_buf);
} else {
ret_error_message = tok_status.message();
goto done;
}
if (WUFFS_JSON__DECODER_WORKBUF_LEN_MAX_INCL_WORST_CASE != 0) {
ret_error_message =
"wuffs_aux::JsonDecoder: internal error: bad WORKBUF_LEN";
goto done;
}
wuffs_base__slice_u8 work_buf = wuffs_base__empty_slice_u8();
tok_status = dec->decode_tokens(&tok_buf, io_buf, work_buf);
}
wuffs_base__token token = tok_buf.data.ptr[tok_buf.meta.ri++];
uint64_t token_len = token.length();
if ((io_buf->meta.ri < cursor_index) ||
((io_buf->meta.ri - cursor_index) < token_len)) {
ret_error_message =
"wuffs_aux::JsonDecoder: internal error: bad token indexes";
goto done;
}
uint8_t* token_ptr = io_buf->data.ptr + cursor_index;
cursor_index += token_len;
// 2. Process that token.
int64_t vbc = token.value_base_category();
uint64_t vbd = token.value_base_detail();
switch (vbc) {
case WUFFS_BASE__TOKEN__VBC__FILLER:
continue;
case WUFFS_BASE__TOKEN__VBC__STRUCTURE: {
if (vbd & WUFFS_BASE__TOKEN__VBD__STRUCTURE__PUSH) {
ret_error_message = callbacks.Push(static_cast<uint32_t>(vbd));
if (!ret_error_message.empty()) {
goto done;
}
depth++;
continue;
}
ret_error_message = callbacks.Pop(static_cast<uint32_t>(vbd));
depth--;
goto parsed_a_value;
}
case WUFFS_BASE__TOKEN__VBC__STRING: {
if (vbd & WUFFS_BASE__TOKEN__VBD__STRING__CONVERT_0_DST_1_SRC_DROP) {
// No-op.
} else if (vbd &
WUFFS_BASE__TOKEN__VBD__STRING__CONVERT_1_DST_1_SRC_COPY) {
const char* ptr = // Convert from (uint8_t*).
static_cast<const char*>(static_cast<void*>(token_ptr));
str.append(ptr, token_len);
} else if (
vbd &
WUFFS_BASE__TOKEN__VBD__STRING__CONVERT_1_DST_4_SRC_BACKSLASH_X) {
wuffs_base__slice_u8 encoded =
wuffs_base__make_slice_u8(token_ptr, token_len);
while (encoded.len > 0) {
uint8_t decoded[64];
constexpr bool src_closed = true;
wuffs_base__transform__output o = wuffs_base__base_16__decode4(
wuffs_base__make_slice_u8(&decoded[0], sizeof decoded),
encoded, src_closed, WUFFS_BASE__BASE_16__DEFAULT_OPTIONS);
if (o.status.is_error()) {
ret_error_message = o.status.message();
goto done;
} else if ((o.num_dst > (sizeof decoded)) ||
(o.num_src > encoded.len)) {
ret_error_message =
"wuffs_aux::JsonDecoder: internal error: inconsistent "
"base16 decoding";
goto done;
}
str.append( // Convert from (uint8_t*).
static_cast<const char*>(static_cast<void*>(&decoded[0])),
o.num_dst);
encoded.ptr += o.num_src;
encoded.len -= o.num_src;
}
} else {
goto fail;
}
if (token.continued()) {
continue;
}
ret_error_message =
(vbd & WUFFS_BASE__TOKEN__VBD__STRING__CHAIN_MUST_BE_UTF_8)
? callbacks.AppendTextString(std::move(str))
: callbacks.AppendByteString(std::move(str));
str.clear();
goto parsed_a_value;
}
case WUFFS_BASE__TOKEN__VBC__UNICODE_CODE_POINT: {
uint8_t u[WUFFS_BASE__UTF_8__BYTE_LENGTH__MAX_INCL];
size_t n = wuffs_base__utf_8__encode(
wuffs_base__make_slice_u8(
&u[0], WUFFS_BASE__UTF_8__BYTE_LENGTH__MAX_INCL),
static_cast<uint32_t>(vbd));
const char* ptr = // Convert from (uint8_t*).
static_cast<const char*>(static_cast<void*>(&u[0]));
str.append(ptr, n);
if (token.continued()) {
continue;
}
goto fail;
}
case WUFFS_BASE__TOKEN__VBC__LITERAL: {
ret_error_message =
(vbd & WUFFS_BASE__TOKEN__VBD__LITERAL__NULL)
? callbacks.AppendNull()
: callbacks.AppendBool(vbd &
WUFFS_BASE__TOKEN__VBD__LITERAL__TRUE);
goto parsed_a_value;
}
case WUFFS_BASE__TOKEN__VBC__NUMBER: {
if (vbd & WUFFS_BASE__TOKEN__VBD__NUMBER__FORMAT_TEXT) {
if (vbd & WUFFS_BASE__TOKEN__VBD__NUMBER__CONTENT_INTEGER_SIGNED) {
wuffs_base__result_i64 r = wuffs_base__parse_number_i64(
wuffs_base__make_slice_u8(token_ptr, token_len),
WUFFS_BASE__PARSE_NUMBER_XXX__DEFAULT_OPTIONS);
if (r.status.is_ok()) {
ret_error_message = callbacks.AppendI64(r.value);
goto parsed_a_value;
}
}
if (vbd & WUFFS_BASE__TOKEN__VBD__NUMBER__CONTENT_FLOATING_POINT) {
wuffs_base__result_f64 r = wuffs_base__parse_number_f64(
wuffs_base__make_slice_u8(token_ptr, token_len),
WUFFS_BASE__PARSE_NUMBER_XXX__DEFAULT_OPTIONS);
if (r.status.is_ok()) {
ret_error_message = callbacks.AppendF64(r.value);
goto parsed_a_value;
}
}
} else if (vbd & WUFFS_BASE__TOKEN__VBD__NUMBER__CONTENT_NEG_INF) {
ret_error_message = callbacks.AppendF64(
wuffs_base__ieee_754_bit_representation__from_u64_to_f64(
0xFFF0000000000000ul));
goto parsed_a_value;
} else if (vbd & WUFFS_BASE__TOKEN__VBD__NUMBER__CONTENT_POS_INF) {
ret_error_message = callbacks.AppendF64(
wuffs_base__ieee_754_bit_representation__from_u64_to_f64(
0x7FF0000000000000ul));
goto parsed_a_value;
} else if (vbd & WUFFS_BASE__TOKEN__VBD__NUMBER__CONTENT_NEG_NAN) {
ret_error_message = callbacks.AppendF64(
wuffs_base__ieee_754_bit_representation__from_u64_to_f64(
0xFFFFFFFFFFFFFFFFul));
goto parsed_a_value;
} else if (vbd & WUFFS_BASE__TOKEN__VBD__NUMBER__CONTENT_POS_NAN) {
ret_error_message = callbacks.AppendF64(
wuffs_base__ieee_754_bit_representation__from_u64_to_f64(
0x7FFFFFFFFFFFFFFFul));
goto parsed_a_value;
}
goto fail;
}
}
fail:
ret_error_message =
"wuffs_aux::JsonDecoder: internal error: unexpected token";
goto done;
parsed_a_value:
if (!ret_error_message.empty() || (depth == 0)) {
goto done;
}
}
} while (false);
done:
DecodeJsonResult result(
std::move(ret_error_message),
wuffs_base__u64__sat_add(io_buf->meta.pos, cursor_index));
callbacks.Done(result, input, *io_buf);
return result;
}
} // namespace wuffs_aux
#endif // !defined(WUFFS_CONFIG__MODULES) ||
// defined(WUFFS_CONFIG__MODULE__AUX__JSON)