Add json QUIRK_JSON_POINTER_ALLOW_TILDE_R_TILDE_N
diff --git a/example/jsonfindptrs/jsonfindptrs.cc b/example/jsonfindptrs/jsonfindptrs.cc
index 4794279..b4ca64b 100644
--- a/example/jsonfindptrs/jsonfindptrs.cc
+++ b/example/jsonfindptrs/jsonfindptrs.cc
@@ -501,6 +501,9 @@
std::string //
main1(int argc, char** argv) {
TRY(parse_flags(argc, argv));
+ if (!g_flags.strict_json_pointer_syntax) {
+ g_quirks.push_back(WUFFS_JSON__QUIRK_JSON_POINTER_ALLOW_TILDE_R_TILDE_N);
+ }
FILE* in = stdin;
if (g_flags.remaining_argc > 1) {
diff --git a/internal/cgen/auxiliary/json.cc b/internal/cgen/auxiliary/json.cc
index bcd3908..1946112 100644
--- a/internal/cgen/auxiliary/json.cc
+++ b/internal/cgen/auxiliary/json.cc
@@ -92,10 +92,15 @@
namespace {
-// DecodeJson_SplitJsonPointer returns ("bar", 8) for ("/foo/bar/baz/qux", 5).
-// It returns a 0 size_t when s has invalid JSON Pointer syntax.
+// DecodeJson_SplitJsonPointer returns ("bar", 8) for ("/foo/bar/b~1z/qux", 5,
+// etc). It returns a 0 size_t when s has invalid JSON Pointer syntax.
+//
+// The string returned is unescaped. If calling it again, this time with i=8,
+// the "b~1z" substring would be returned as "b/z".
std::pair<std::string, size_t> //
-DecodeJson_SplitJsonPointer(std::string& s, size_t i) {
+DecodeJson_SplitJsonPointer(std::string& s,
+ size_t i,
+ bool allow_tilde_r_tilde_n) {
std::string fragment;
while (i < s.size()) {
char c = s[i];
@@ -119,6 +124,16 @@
fragment.push_back('/');
i++;
continue;
+ } else if (allow_tilde_r_tilde_n) {
+ if (c == 'r') {
+ fragment.push_back('\r');
+ i++;
+ continue;
+ } else if (c == 'n') {
+ fragment.push_back('\n');
+ i++;
+ continue;
+ }
}
return std::make_pair(std::string(), 0);
}
@@ -366,8 +381,13 @@
ret_error_message = "wuffs_aux::DecodeJson: out of memory";
goto done;
}
+ bool allow_tilde_r_tilde_n = false;
for (size_t i = 0; i < quirks.len; i++) {
dec->set_quirk_enabled(quirks.ptr[i], true);
+ if (quirks.ptr[i] ==
+ WUFFS_JSON__QUIRK_JSON_POINTER_ALLOW_TILDE_R_TILDE_N) {
+ allow_tilde_r_tilde_n = true;
+ }
}
// Prepare the wuffs_base__tok_buffer.
@@ -387,8 +407,8 @@
ret_error_message = DecodeJson_BadJsonPointer;
goto done;
}
- std::pair<std::string, size_t> split =
- DecodeJson_SplitJsonPointer(json_pointer, i + 1);
+ std::pair<std::string, size_t> split = DecodeJson_SplitJsonPointer(
+ json_pointer, i + 1, allow_tilde_r_tilde_n);
i = std::move(split.second);
if (i == 0) {
ret_error_message = DecodeJson_BadJsonPointer;
diff --git a/internal/cgen/data/data.go b/internal/cgen/data/data.go
index 97a3686..a2772a9 100644
--- a/internal/cgen/data/data.go
+++ b/internal/cgen/data/data.go
@@ -652,22 +652,23 @@
"{ \\\n } else if (tok_status.repr == wuffs_base__suspension__short_write) { \\\n tok_buf.compact(); \\\n } else if (tok_status.repr == wuffs_base__suspension__short_read) { \\\n if (!io_error_message.empty()) { \\\n ret_error_message = std::move(io_error_message); \\\n goto done; \\\n } else if (cursor_index != io_buf->meta.ri) { \\\n ret_error_message = \\\n \"wuffs_aux::DecodeJson: internal error: bad cursor_index\"; \\\n goto done; \\\n } else if (io_buf->meta.closed) { \\\n ret_error_message = \\\n \"wuffs_aux::DecodeJson: internal error: io_buf is closed\"; \\\n go" +
"to done; \\\n } \\\n io_buf->compact(); \\\n if (io_buf->meta.wi >= io_buf->data.len) { \\\n ret_error_message = \\\n \"wuffs_aux::DecodeJson: internal error: io_buf is full\"; \\\n goto done; \\\n } \\\n cursor_index = io_buf->meta.ri; \\\n io_error_message = input.CopyIn(io_buf); \\\n } else { \\\n ret_error_message = tok_status.message(); \\\n goto done; \\\n } " +
" \\\n if (WUFFS_JSON__DECODER_WORKBUF_LEN_MAX_INCL_WORST_CASE != 0) { \\\n ret_error_message = \\\n \"wuffs_aux::DecodeJson: internal error: bad WORKBUF_LEN\"; \\\n goto done; \\\n } \\\n wuffs_base__slice_u8 work_buf = wuffs_base__empty_slice_u8(); \\\n tok_status = dec->decode_tokens(&tok_buf, io_buf, work_buf); \\\n } \\\n wuffs_base__token token = tok_buf.data.ptr[tok_buf.meta.ri++]; \\\n uint64_t token_len = token.length(); \\\n if ((io_buf->meta.ri < cursor_index) || \\\n ((io_buf->meta.ri - cursor_index) < token_len)) { \\\n ret_error_message = \\\n \"wuffs_aux::DecodeJson: i" +
- "nternal error: bad token indexes\"; \\\n goto done; \\\n } \\\n uint8_t* token_ptr = io_buf->data.ptr + cursor_index; \\\n cursor_index += token_len\n\nnamespace {\n\n// DecodeJson_SplitJsonPointer returns (\"bar\", 8) for (\"/foo/bar/baz/qux\", 5).\n// It returns a 0 size_t when s has invalid JSON Pointer syntax.\nstd::pair<std::string, size_t> //\nDecodeJson_SplitJsonPointer(std::string& s, size_t i) {\n std::string fragment;\n while (i < s.size()) {\n char c = s[i];\n if (c == '/') {\n break;\n } else if (c != '~') {\n fragment.push_back(c);\n i++;\n continue;\n }\n i++;\n if (i >= s.size()) {\n return std::make_pair(std::string(), 0);\n }\n c = s[i];\n if (c == '0') {\n fragment.push_back('~');\n i++;\n continue;\n } else if (c == '1') {\n fragment.push_back('/');\n i++;\n continue;\n }\n return std::make" +
- "_pair(std::string(), 0);\n }\n return std::make_pair(std::move(fragment), i);\n}\n\nstd::string //\nDecodeJson_DecodeBackslashX(std::string& str,\n uint8_t* token_ptr,\n size_t token_len) {\n wuffs_base__slice_u8 encoded =\n wuffs_base__make_slice_u8(token_ptr, token_len);\n while (encoded.len > 0) {\n uint8_t decoded[64];\n constexpr bool src_closed = true;\n wuffs_base__transform__output o = wuffs_base__base_16__decode4(\n wuffs_base__make_slice_u8(&decoded[0], sizeof decoded), encoded,\n src_closed, WUFFS_BASE__BASE_16__DEFAULT_OPTIONS);\n if (o.status.is_error()) {\n return o.status.message();\n } else if ((o.num_dst > (sizeof decoded)) || (o.num_src > encoded.len)) {\n return \"wuffs_aux::DecodeJson: internal error: inconsistent base16 \"\n \"decoding\";\n }\n str.append( // Convert from (uint8_t*).\n static_cast<const char*>(static_cast<void*>(&decoded[0])), o.num_dst);\n encoded.ptr += o.num_src;\n " +
- "encoded.len -= o.num_src;\n }\n return \"\";\n}\n\nstd::string //\nDecodeJson_WalkJsonPointerFragment(wuffs_base__token_buffer& tok_buf,\n wuffs_base__status& tok_status,\n wuffs_json__decoder::unique_ptr& dec,\n wuffs_base__io_buffer* io_buf,\n std::string& io_error_message,\n size_t& cursor_index,\n sync_io::Input& input,\n std::string& json_pointer_fragment) {\n std::string ret_error_message;\n while (true) {\n WUFFS_AUX__DECODE_JSON__GET_THE_NEXT_TOKEN;\n\n int64_t vbc = token.value_base_category();\n uint64_t vbd = token.value_base_detail();\n if (vbc == WUFFS_BASE__TOKEN__VBC__FILLER) {\n continue;\n } else if ((vbc != WUFFS_BASE__TOKEN__VBC__STRUCTURE) ||\n !(vbd & WUFFS_BASE__TOKEN__VBD__STRUCTURE__PUSH)) {\n return DecodeJson_NoMatch;\n } else if " +
- "(vbd & WUFFS_BASE__TOKEN__VBD__STRUCTURE__TO_LIST) {\n goto do_list;\n }\n goto do_dict;\n }\n\ndo_dict:\n // Alternate between these two things:\n // 1. Decode the next dict key (a string). If it matches the fragment, we're\n // done (success). If we've reached the dict's end (VBD__STRUCTURE__POP)\n // so that there was no next dict key, we're done (failure).\n // 2. Otherwise, skip the next dict value.\n while (true) {\n for (std::string str; true;) {\n WUFFS_AUX__DECODE_JSON__GET_THE_NEXT_TOKEN;\n\n int64_t vbc = token.value_base_category();\n uint64_t vbd = token.value_base_detail();\n switch (vbc) {\n case WUFFS_BASE__TOKEN__VBC__FILLER:\n continue;\n\n case WUFFS_BASE__TOKEN__VBC__STRUCTURE:\n if (vbd & WUFFS_BASE__TOKEN__VBD__STRUCTURE__PUSH) {\n goto fail;\n }\n return DecodeJson_NoMatch;\n\n case WUFFS_BASE__TOKEN__VBC__STRING: {\n if (vbd & WUFFS_BASE__TOKEN__VBD__STRING__CONVERT_0_DST_1_SRC_DROP) {\n " +
- " // No-op.\n } else if (vbd &\n WUFFS_BASE__TOKEN__VBD__STRING__CONVERT_1_DST_1_SRC_COPY) {\n const char* ptr = // Convert from (uint8_t*).\n static_cast<const char*>(static_cast<void*>(token_ptr));\n str.append(ptr, token_len);\n } else if (\n vbd &\n WUFFS_BASE__TOKEN__VBD__STRING__CONVERT_1_DST_4_SRC_BACKSLASH_X) {\n ret_error_message =\n DecodeJson_DecodeBackslashX(str, token_ptr, token_len);\n if (!ret_error_message.empty()) {\n goto done;\n }\n } else {\n goto fail;\n }\n break;\n }\n\n case WUFFS_BASE__TOKEN__VBC__UNICODE_CODE_POINT: {\n uint8_t u[WUFFS_BASE__UTF_8__BYTE_LENGTH__MAX_INCL];\n size_t n = wuffs_base__utf_8__encode(\n wuffs_base__make_slice_u8(\n &u[0], WUFFS_BASE__UTF_8__BYTE_LENGTH__MAX_INCL),\n static_cast<uint32_t>(vbd));\n " +
- "const char* ptr = // Convert from (uint8_t*).\n static_cast<const char*>(static_cast<void*>(&u[0]));\n str.append(ptr, n);\n break;\n }\n\n default:\n goto fail;\n }\n\n if (token.continued()) {\n continue;\n }\n if (str == json_pointer_fragment) {\n return \"\";\n }\n goto skip_the_next_dict_value;\n }\n\n skip_the_next_dict_value:\n for (uint32_t skip_depth = 0; true;) {\n WUFFS_AUX__DECODE_JSON__GET_THE_NEXT_TOKEN;\n\n int64_t vbc = token.value_base_category();\n uint64_t vbd = token.value_base_detail();\n if (token.continued() || (vbc == WUFFS_BASE__TOKEN__VBC__FILLER)) {\n continue;\n } else if (vbc == WUFFS_BASE__TOKEN__VBC__STRUCTURE) {\n if (vbd & WUFFS_BASE__TOKEN__VBD__STRUCTURE__PUSH) {\n skip_depth++;\n continue;\n }\n skip_depth--;\n }\n\n if (skip_depth == 0) {\n break;\n }\n } // skip_the_next_dict_value\n } // do_dict\n\ndo_list:\n " +
- "do {\n wuffs_base__result_u64 result_u64 = wuffs_base__parse_number_u64(\n wuffs_base__make_slice_u8(\n static_cast<uint8_t*>(static_cast<void*>(\n const_cast<char*>(json_pointer_fragment.data()))),\n json_pointer_fragment.size()),\n WUFFS_BASE__PARSE_NUMBER_XXX__DEFAULT_OPTIONS);\n if (!result_u64.status.is_ok()) {\n return DecodeJson_NoMatch;\n }\n uint64_t remaining = result_u64.value;\n if (remaining == 0) {\n goto check_that_a_value_follows;\n }\n for (uint32_t skip_depth = 0; true;) {\n WUFFS_AUX__DECODE_JSON__GET_THE_NEXT_TOKEN;\n\n int64_t vbc = token.value_base_category();\n uint64_t vbd = token.value_base_detail();\n if (token.continued() || (vbc == WUFFS_BASE__TOKEN__VBC__FILLER)) {\n continue;\n } else if (vbc == WUFFS_BASE__TOKEN__VBC__STRUCTURE) {\n if (vbd & WUFFS_BASE__TOKEN__VBD__STRUCTURE__PUSH) {\n skip_depth++;\n continue;\n }\n if (skip_depth == 0) {\n ret" +
- "urn DecodeJson_NoMatch;\n }\n skip_depth--;\n }\n\n if (skip_depth > 0) {\n continue;\n }\n remaining--;\n if (remaining == 0) {\n goto check_that_a_value_follows;\n }\n }\n } while (false); // do_list\n\ncheck_that_a_value_follows:\n while (true) {\n WUFFS_AUX__DECODE_JSON__GET_THE_NEXT_TOKEN;\n\n int64_t vbc = token.value_base_category();\n uint64_t vbd = token.value_base_detail();\n if (vbc == WUFFS_BASE__TOKEN__VBC__FILLER) {\n continue;\n }\n\n // Undo the last part of WUFFS_AUX__DECODE_JSON__GET_THE_NEXT_TOKEN, so that\n // we're only peeking at the next token.\n tok_buf.meta.ri--;\n cursor_index -= token_len;\n\n if ((vbc == WUFFS_BASE__TOKEN__VBC__STRUCTURE) &&\n (vbd & WUFFS_BASE__TOKEN__VBD__STRUCTURE__POP)) {\n return DecodeJson_NoMatch;\n }\n return \"\";\n } // check_that_a_value_follows\n\nfail:\n return \"wuffs_aux::DecodeJson: internal error: unexpected token\";\ndone:\n return ret_error_message;\n}\n\n} // namespace\n\nD" +
- "ecodeJsonResult //\nDecodeJson(DecodeJsonCallbacks&& callbacks,\n sync_io::Input&& input,\n wuffs_base__slice_u32 quirks,\n std::string json_pointer) {\n // Prepare the wuffs_base__io_buffer and the resultant error_message.\n wuffs_base__io_buffer* io_buf = input.BringsItsOwnIOBuffer();\n wuffs_base__io_buffer fallback_io_buf = wuffs_base__empty_io_buffer();\n std::unique_ptr<uint8_t[]> fallback_io_array(nullptr);\n if (!io_buf) {\n fallback_io_array = std::unique_ptr<uint8_t[]>(new uint8_t[4096]);\n fallback_io_buf = wuffs_base__ptr_u8__writer(fallback_io_array.get(), 4096);\n io_buf = &fallback_io_buf;\n }\n size_t cursor_index = 0;\n std::string ret_error_message;\n std::string io_error_message;\n\n do {\n // Prepare the low-level JSON decoder.\n wuffs_json__decoder::unique_ptr dec = wuffs_json__decoder::alloc();\n if (!dec) {\n ret_error_message = \"wuffs_aux::DecodeJson: out of memory\";\n goto done;\n }\n for (size_t i = 0; i < quirks.len; i++) {\n dec" +
- "->set_quirk_enabled(quirks.ptr[i], true);\n }\n\n // Prepare the wuffs_base__tok_buffer.\n wuffs_base__token tok_array[256];\n wuffs_base__token_buffer tok_buf =\n wuffs_base__slice_token__writer(wuffs_base__make_slice_token(\n &tok_array[0], (sizeof(tok_array) / sizeof(tok_array[0]))));\n wuffs_base__status tok_status = wuffs_base__make_status(nullptr);\n\n // Prepare other state.\n uint32_t depth = 0;\n std::string str;\n\n // Walk the (optional) JSON Pointer.\n for (size_t i = 0; i < json_pointer.size();) {\n if (json_pointer[i] != '/') {\n ret_error_message = DecodeJson_BadJsonPointer;\n goto done;\n }\n std::pair<std::string, size_t> split =\n DecodeJson_SplitJsonPointer(json_pointer, i + 1);\n i = std::move(split.second);\n if (i == 0) {\n ret_error_message = DecodeJson_BadJsonPointer;\n goto done;\n }\n ret_error_message = DecodeJson_WalkJsonPointerFragment(\n tok_buf, tok_status, dec, io_buf, io_error_" +
- "message, cursor_index,\n input, split.first);\n if (!ret_error_message.empty()) {\n goto done;\n }\n }\n\n // Loop, doing these two things:\n // 1. Get the next token.\n // 2. Process that token.\n while (true) {\n WUFFS_AUX__DECODE_JSON__GET_THE_NEXT_TOKEN;\n\n int64_t vbc = token.value_base_category();\n uint64_t vbd = token.value_base_detail();\n switch (vbc) {\n case WUFFS_BASE__TOKEN__VBC__FILLER:\n continue;\n\n case WUFFS_BASE__TOKEN__VBC__STRUCTURE: {\n if (vbd & WUFFS_BASE__TOKEN__VBD__STRUCTURE__PUSH) {\n ret_error_message = callbacks.Push(static_cast<uint32_t>(vbd));\n if (!ret_error_message.empty()) {\n goto done;\n }\n depth++;\n continue;\n }\n ret_error_message = callbacks.Pop(static_cast<uint32_t>(vbd));\n depth--;\n goto parsed_a_value;\n }\n\n case WUFFS_BASE__TOKEN__VBC__STRING: {\n if (vbd & WUFFS_BASE__T" +
- "OKEN__VBD__STRING__CONVERT_0_DST_1_SRC_DROP) {\n // No-op.\n } else if (vbd &\n WUFFS_BASE__TOKEN__VBD__STRING__CONVERT_1_DST_1_SRC_COPY) {\n const char* ptr = // Convert from (uint8_t*).\n static_cast<const char*>(static_cast<void*>(token_ptr));\n str.append(ptr, token_len);\n } else if (\n vbd &\n WUFFS_BASE__TOKEN__VBD__STRING__CONVERT_1_DST_4_SRC_BACKSLASH_X) {\n ret_error_message =\n DecodeJson_DecodeBackslashX(str, token_ptr, token_len);\n if (!ret_error_message.empty()) {\n goto done;\n }\n } else {\n goto fail;\n }\n if (token.continued()) {\n continue;\n }\n ret_error_message =\n (vbd & WUFFS_BASE__TOKEN__VBD__STRING__CHAIN_MUST_BE_UTF_8)\n ? callbacks.AppendTextString(std::move(str))\n : callbacks.AppendByteString(std::move(str));\n " +
- " str.clear();\n goto parsed_a_value;\n }\n\n case WUFFS_BASE__TOKEN__VBC__UNICODE_CODE_POINT: {\n uint8_t u[WUFFS_BASE__UTF_8__BYTE_LENGTH__MAX_INCL];\n size_t n = wuffs_base__utf_8__encode(\n wuffs_base__make_slice_u8(\n &u[0], WUFFS_BASE__UTF_8__BYTE_LENGTH__MAX_INCL),\n static_cast<uint32_t>(vbd));\n const char* ptr = // Convert from (uint8_t*).\n static_cast<const char*>(static_cast<void*>(&u[0]));\n str.append(ptr, n);\n if (token.continued()) {\n continue;\n }\n goto fail;\n }\n\n case WUFFS_BASE__TOKEN__VBC__LITERAL: {\n ret_error_message =\n (vbd & WUFFS_BASE__TOKEN__VBD__LITERAL__NULL)\n ? callbacks.AppendNull()\n : callbacks.AppendBool(vbd &\n WUFFS_BASE__TOKEN__VBD__LITERAL__TRUE);\n goto parsed_a_value;\n }\n\n case WUFFS_BASE__TOKEN__VBC__NUM" +
- "BER: {\n if (vbd & WUFFS_BASE__TOKEN__VBD__NUMBER__FORMAT_TEXT) {\n if (vbd & WUFFS_BASE__TOKEN__VBD__NUMBER__CONTENT_INTEGER_SIGNED) {\n wuffs_base__result_i64 r = wuffs_base__parse_number_i64(\n wuffs_base__make_slice_u8(token_ptr, token_len),\n WUFFS_BASE__PARSE_NUMBER_XXX__DEFAULT_OPTIONS);\n if (r.status.is_ok()) {\n ret_error_message = callbacks.AppendI64(r.value);\n goto parsed_a_value;\n }\n }\n if (vbd & WUFFS_BASE__TOKEN__VBD__NUMBER__CONTENT_FLOATING_POINT) {\n wuffs_base__result_f64 r = wuffs_base__parse_number_f64(\n wuffs_base__make_slice_u8(token_ptr, token_len),\n WUFFS_BASE__PARSE_NUMBER_XXX__DEFAULT_OPTIONS);\n if (r.status.is_ok()) {\n ret_error_message = callbacks.AppendF64(r.value);\n goto parsed_a_value;\n }\n }\n } else if (vbd & WUFFS_BASE__T" +
- "OKEN__VBD__NUMBER__CONTENT_NEG_INF) {\n ret_error_message = callbacks.AppendF64(\n wuffs_base__ieee_754_bit_representation__from_u64_to_f64(\n 0xFFF0000000000000ul));\n goto parsed_a_value;\n } else if (vbd & WUFFS_BASE__TOKEN__VBD__NUMBER__CONTENT_POS_INF) {\n ret_error_message = callbacks.AppendF64(\n wuffs_base__ieee_754_bit_representation__from_u64_to_f64(\n 0x7FF0000000000000ul));\n goto parsed_a_value;\n } else if (vbd & WUFFS_BASE__TOKEN__VBD__NUMBER__CONTENT_NEG_NAN) {\n ret_error_message = callbacks.AppendF64(\n wuffs_base__ieee_754_bit_representation__from_u64_to_f64(\n 0xFFFFFFFFFFFFFFFFul));\n goto parsed_a_value;\n } else if (vbd & WUFFS_BASE__TOKEN__VBD__NUMBER__CONTENT_POS_NAN) {\n ret_error_message = callbacks.AppendF64(\n wuffs_base__ieee_754_bit_representation__from_u64_to_f64(\n " +
- " 0x7FFFFFFFFFFFFFFFul));\n goto parsed_a_value;\n }\n goto fail;\n }\n }\n\n fail:\n ret_error_message =\n \"wuffs_aux::DecodeJson: internal error: unexpected token\";\n goto done;\n\n parsed_a_value:\n if (!ret_error_message.empty() || (depth == 0)) {\n goto done;\n }\n }\n } while (false);\n\ndone:\n DecodeJsonResult result(\n std::move(ret_error_message),\n wuffs_base__u64__sat_add(io_buf->meta.pos, cursor_index));\n callbacks.Done(result, input, *io_buf);\n return result;\n}\n\n#undef WUFFS_AUX__DECODE_JSON__GET_THE_NEXT_TOKEN\n\n} // namespace wuffs_aux\n\n#endif // !defined(WUFFS_CONFIG__MODULES) ||\n // defined(WUFFS_CONFIG__MODULE__AUX__JSON)\n" +
+ "nternal error: bad token indexes\"; \\\n goto done; \\\n } \\\n uint8_t* token_ptr = io_buf->data.ptr + cursor_index; \\\n cursor_index += token_len\n\nnamespace {\n\n// DecodeJson_SplitJsonPointer returns (\"bar\", 8) for (\"/foo/bar/b~1z/qux\", 5,\n// etc). It returns a 0 size_t when s has invalid JSON Pointer syntax.\n//\n// The string returned is unescaped. If calling it again, this time with i=8,\n// the \"b~1z\" substring would be returned as \"b/z\".\nstd::pair<std::string, size_t> //\nDecodeJson_SplitJsonPointer(std::string& s,\n size_t i,\n bool allow_tilde_r_tilde_n) {\n std::string fragment;\n while (i < s.size()) {\n char c = s[i];\n if (c == '/') {\n break;\n } else if (c != '~') {\n fragment.push_back(c);\n i++;\n continue;\n }\n i++;\n if (i >= s.size()) {\n return std::make_pair(std::" +
+ "string(), 0);\n }\n c = s[i];\n if (c == '0') {\n fragment.push_back('~');\n i++;\n continue;\n } else if (c == '1') {\n fragment.push_back('/');\n i++;\n continue;\n } else if (allow_tilde_r_tilde_n) {\n if (c == 'r') {\n fragment.push_back('\\r');\n i++;\n continue;\n } else if (c == 'n') {\n fragment.push_back('\\n');\n i++;\n continue;\n }\n }\n return std::make_pair(std::string(), 0);\n }\n return std::make_pair(std::move(fragment), i);\n}\n\nstd::string //\nDecodeJson_DecodeBackslashX(std::string& str,\n uint8_t* token_ptr,\n size_t token_len) {\n wuffs_base__slice_u8 encoded =\n wuffs_base__make_slice_u8(token_ptr, token_len);\n while (encoded.len > 0) {\n uint8_t decoded[64];\n constexpr bool src_closed = true;\n wuffs_base__transform__output o = wuffs_base__base_16__decode4(\n wuffs_base__make_slice_u8(&decoded[0], sizeof decoded), encoded,\n src_c" +
+ "losed, WUFFS_BASE__BASE_16__DEFAULT_OPTIONS);\n if (o.status.is_error()) {\n return o.status.message();\n } else if ((o.num_dst > (sizeof decoded)) || (o.num_src > encoded.len)) {\n return \"wuffs_aux::DecodeJson: internal error: inconsistent base16 \"\n \"decoding\";\n }\n str.append( // Convert from (uint8_t*).\n static_cast<const char*>(static_cast<void*>(&decoded[0])), o.num_dst);\n encoded.ptr += o.num_src;\n encoded.len -= o.num_src;\n }\n return \"\";\n}\n\nstd::string //\nDecodeJson_WalkJsonPointerFragment(wuffs_base__token_buffer& tok_buf,\n wuffs_base__status& tok_status,\n wuffs_json__decoder::unique_ptr& dec,\n wuffs_base__io_buffer* io_buf,\n std::string& io_error_message,\n size_t& cursor_index,\n sync_io::Input& input,\n std::string& json_" +
+ "pointer_fragment) {\n std::string ret_error_message;\n while (true) {\n WUFFS_AUX__DECODE_JSON__GET_THE_NEXT_TOKEN;\n\n int64_t vbc = token.value_base_category();\n uint64_t vbd = token.value_base_detail();\n if (vbc == WUFFS_BASE__TOKEN__VBC__FILLER) {\n continue;\n } else if ((vbc != WUFFS_BASE__TOKEN__VBC__STRUCTURE) ||\n !(vbd & WUFFS_BASE__TOKEN__VBD__STRUCTURE__PUSH)) {\n return DecodeJson_NoMatch;\n } else if (vbd & WUFFS_BASE__TOKEN__VBD__STRUCTURE__TO_LIST) {\n goto do_list;\n }\n goto do_dict;\n }\n\ndo_dict:\n // Alternate between these two things:\n // 1. Decode the next dict key (a string). If it matches the fragment, we're\n // done (success). If we've reached the dict's end (VBD__STRUCTURE__POP)\n // so that there was no next dict key, we're done (failure).\n // 2. Otherwise, skip the next dict value.\n while (true) {\n for (std::string str; true;) {\n WUFFS_AUX__DECODE_JSON__GET_THE_NEXT_TOKEN;\n\n int64_t vbc = token.value_base_category()" +
+ ";\n uint64_t vbd = token.value_base_detail();\n switch (vbc) {\n case WUFFS_BASE__TOKEN__VBC__FILLER:\n continue;\n\n case WUFFS_BASE__TOKEN__VBC__STRUCTURE:\n if (vbd & WUFFS_BASE__TOKEN__VBD__STRUCTURE__PUSH) {\n goto fail;\n }\n return DecodeJson_NoMatch;\n\n case WUFFS_BASE__TOKEN__VBC__STRING: {\n if (vbd & WUFFS_BASE__TOKEN__VBD__STRING__CONVERT_0_DST_1_SRC_DROP) {\n // No-op.\n } else if (vbd &\n WUFFS_BASE__TOKEN__VBD__STRING__CONVERT_1_DST_1_SRC_COPY) {\n const char* ptr = // Convert from (uint8_t*).\n static_cast<const char*>(static_cast<void*>(token_ptr));\n str.append(ptr, token_len);\n } else if (\n vbd &\n WUFFS_BASE__TOKEN__VBD__STRING__CONVERT_1_DST_4_SRC_BACKSLASH_X) {\n ret_error_message =\n DecodeJson_DecodeBackslashX(str, token_ptr, token_len);\n if (!ret_error_message.empty()) {\n " +
+ " goto done;\n }\n } else {\n goto fail;\n }\n break;\n }\n\n case WUFFS_BASE__TOKEN__VBC__UNICODE_CODE_POINT: {\n uint8_t u[WUFFS_BASE__UTF_8__BYTE_LENGTH__MAX_INCL];\n size_t n = wuffs_base__utf_8__encode(\n wuffs_base__make_slice_u8(\n &u[0], WUFFS_BASE__UTF_8__BYTE_LENGTH__MAX_INCL),\n static_cast<uint32_t>(vbd));\n const char* ptr = // Convert from (uint8_t*).\n static_cast<const char*>(static_cast<void*>(&u[0]));\n str.append(ptr, n);\n break;\n }\n\n default:\n goto fail;\n }\n\n if (token.continued()) {\n continue;\n }\n if (str == json_pointer_fragment) {\n return \"\";\n }\n goto skip_the_next_dict_value;\n }\n\n skip_the_next_dict_value:\n for (uint32_t skip_depth = 0; true;) {\n WUFFS_AUX__DECODE_JSON__GET_THE_NEXT_TOKEN;\n\n int64_t vbc = token.value_base_category();\n uint64" +
+ "_t vbd = token.value_base_detail();\n if (token.continued() || (vbc == WUFFS_BASE__TOKEN__VBC__FILLER)) {\n continue;\n } else if (vbc == WUFFS_BASE__TOKEN__VBC__STRUCTURE) {\n if (vbd & WUFFS_BASE__TOKEN__VBD__STRUCTURE__PUSH) {\n skip_depth++;\n continue;\n }\n skip_depth--;\n }\n\n if (skip_depth == 0) {\n break;\n }\n } // skip_the_next_dict_value\n } // do_dict\n\ndo_list:\n do {\n wuffs_base__result_u64 result_u64 = wuffs_base__parse_number_u64(\n wuffs_base__make_slice_u8(\n static_cast<uint8_t*>(static_cast<void*>(\n const_cast<char*>(json_pointer_fragment.data()))),\n json_pointer_fragment.size()),\n WUFFS_BASE__PARSE_NUMBER_XXX__DEFAULT_OPTIONS);\n if (!result_u64.status.is_ok()) {\n return DecodeJson_NoMatch;\n }\n uint64_t remaining = result_u64.value;\n if (remaining == 0) {\n goto check_that_a_value_follows;\n }\n for (uint32_t skip_depth = 0; true;) {\n WU" +
+ "FFS_AUX__DECODE_JSON__GET_THE_NEXT_TOKEN;\n\n int64_t vbc = token.value_base_category();\n uint64_t vbd = token.value_base_detail();\n if (token.continued() || (vbc == WUFFS_BASE__TOKEN__VBC__FILLER)) {\n continue;\n } else if (vbc == WUFFS_BASE__TOKEN__VBC__STRUCTURE) {\n if (vbd & WUFFS_BASE__TOKEN__VBD__STRUCTURE__PUSH) {\n skip_depth++;\n continue;\n }\n if (skip_depth == 0) {\n return DecodeJson_NoMatch;\n }\n skip_depth--;\n }\n\n if (skip_depth > 0) {\n continue;\n }\n remaining--;\n if (remaining == 0) {\n goto check_that_a_value_follows;\n }\n }\n } while (false); // do_list\n\ncheck_that_a_value_follows:\n while (true) {\n WUFFS_AUX__DECODE_JSON__GET_THE_NEXT_TOKEN;\n\n int64_t vbc = token.value_base_category();\n uint64_t vbd = token.value_base_detail();\n if (vbc == WUFFS_BASE__TOKEN__VBC__FILLER) {\n continue;\n }\n\n // Undo the last part of WUFFS_AUX__DECODE_JSON__GET_THE" +
+ "_NEXT_TOKEN, so that\n // we're only peeking at the next token.\n tok_buf.meta.ri--;\n cursor_index -= token_len;\n\n if ((vbc == WUFFS_BASE__TOKEN__VBC__STRUCTURE) &&\n (vbd & WUFFS_BASE__TOKEN__VBD__STRUCTURE__POP)) {\n return DecodeJson_NoMatch;\n }\n return \"\";\n } // check_that_a_value_follows\n\nfail:\n return \"wuffs_aux::DecodeJson: internal error: unexpected token\";\ndone:\n return ret_error_message;\n}\n\n} // namespace\n\nDecodeJsonResult //\nDecodeJson(DecodeJsonCallbacks&& callbacks,\n sync_io::Input&& input,\n wuffs_base__slice_u32 quirks,\n std::string json_pointer) {\n // Prepare the wuffs_base__io_buffer and the resultant error_message.\n wuffs_base__io_buffer* io_buf = input.BringsItsOwnIOBuffer();\n wuffs_base__io_buffer fallback_io_buf = wuffs_base__empty_io_buffer();\n std::unique_ptr<uint8_t[]> fallback_io_array(nullptr);\n if (!io_buf) {\n fallback_io_array = std::unique_ptr<uint8_t[]>(new uint8_t[4096]);\n fallback_io_buf = wuffs_base__ptr_u" +
+ "8__writer(fallback_io_array.get(), 4096);\n io_buf = &fallback_io_buf;\n }\n size_t cursor_index = 0;\n std::string ret_error_message;\n std::string io_error_message;\n\n do {\n // Prepare the low-level JSON decoder.\n wuffs_json__decoder::unique_ptr dec = wuffs_json__decoder::alloc();\n if (!dec) {\n ret_error_message = \"wuffs_aux::DecodeJson: out of memory\";\n goto done;\n }\n bool allow_tilde_r_tilde_n = false;\n for (size_t i = 0; i < quirks.len; i++) {\n dec->set_quirk_enabled(quirks.ptr[i], true);\n if (quirks.ptr[i] ==\n WUFFS_JSON__QUIRK_JSON_POINTER_ALLOW_TILDE_R_TILDE_N) {\n allow_tilde_r_tilde_n = true;\n }\n }\n\n // Prepare the wuffs_base__tok_buffer.\n wuffs_base__token tok_array[256];\n wuffs_base__token_buffer tok_buf =\n wuffs_base__slice_token__writer(wuffs_base__make_slice_token(\n &tok_array[0], (sizeof(tok_array) / sizeof(tok_array[0]))));\n wuffs_base__status tok_status = wuffs_base__make_status(nullptr);\n\n // Pre" +
+ "pare other state.\n uint32_t depth = 0;\n std::string str;\n\n // Walk the (optional) JSON Pointer.\n for (size_t i = 0; i < json_pointer.size();) {\n if (json_pointer[i] != '/') {\n ret_error_message = DecodeJson_BadJsonPointer;\n goto done;\n }\n std::pair<std::string, size_t> split = DecodeJson_SplitJsonPointer(\n json_pointer, i + 1, allow_tilde_r_tilde_n);\n i = std::move(split.second);\n if (i == 0) {\n ret_error_message = DecodeJson_BadJsonPointer;\n goto done;\n }\n ret_error_message = DecodeJson_WalkJsonPointerFragment(\n tok_buf, tok_status, dec, io_buf, io_error_message, cursor_index,\n input, split.first);\n if (!ret_error_message.empty()) {\n goto done;\n }\n }\n\n // Loop, doing these two things:\n // 1. Get the next token.\n // 2. Process that token.\n while (true) {\n WUFFS_AUX__DECODE_JSON__GET_THE_NEXT_TOKEN;\n\n int64_t vbc = token.value_base_category();\n uint64_t vbd = to" +
+ "ken.value_base_detail();\n switch (vbc) {\n case WUFFS_BASE__TOKEN__VBC__FILLER:\n continue;\n\n case WUFFS_BASE__TOKEN__VBC__STRUCTURE: {\n if (vbd & WUFFS_BASE__TOKEN__VBD__STRUCTURE__PUSH) {\n ret_error_message = callbacks.Push(static_cast<uint32_t>(vbd));\n if (!ret_error_message.empty()) {\n goto done;\n }\n depth++;\n continue;\n }\n ret_error_message = callbacks.Pop(static_cast<uint32_t>(vbd));\n depth--;\n goto parsed_a_value;\n }\n\n case WUFFS_BASE__TOKEN__VBC__STRING: {\n if (vbd & WUFFS_BASE__TOKEN__VBD__STRING__CONVERT_0_DST_1_SRC_DROP) {\n // No-op.\n } else if (vbd &\n WUFFS_BASE__TOKEN__VBD__STRING__CONVERT_1_DST_1_SRC_COPY) {\n const char* ptr = // Convert from (uint8_t*).\n static_cast<const char*>(static_cast<void*>(token_ptr));\n str.append(ptr, token_len);\n } else if " +
+ "(\n vbd &\n WUFFS_BASE__TOKEN__VBD__STRING__CONVERT_1_DST_4_SRC_BACKSLASH_X) {\n ret_error_message =\n DecodeJson_DecodeBackslashX(str, token_ptr, token_len);\n if (!ret_error_message.empty()) {\n goto done;\n }\n } else {\n goto fail;\n }\n if (token.continued()) {\n continue;\n }\n ret_error_message =\n (vbd & WUFFS_BASE__TOKEN__VBD__STRING__CHAIN_MUST_BE_UTF_8)\n ? callbacks.AppendTextString(std::move(str))\n : callbacks.AppendByteString(std::move(str));\n str.clear();\n goto parsed_a_value;\n }\n\n case WUFFS_BASE__TOKEN__VBC__UNICODE_CODE_POINT: {\n uint8_t u[WUFFS_BASE__UTF_8__BYTE_LENGTH__MAX_INCL];\n size_t n = wuffs_base__utf_8__encode(\n wuffs_base__make_slice_u8(\n &u[0], WUFFS_BASE__UTF_8__BYTE_LENGTH__MAX_INCL),\n static_cast<uint32_t" +
+ ">(vbd));\n const char* ptr = // Convert from (uint8_t*).\n static_cast<const char*>(static_cast<void*>(&u[0]));\n str.append(ptr, n);\n if (token.continued()) {\n continue;\n }\n goto fail;\n }\n\n case WUFFS_BASE__TOKEN__VBC__LITERAL: {\n ret_error_message =\n (vbd & WUFFS_BASE__TOKEN__VBD__LITERAL__NULL)\n ? callbacks.AppendNull()\n : callbacks.AppendBool(vbd &\n WUFFS_BASE__TOKEN__VBD__LITERAL__TRUE);\n goto parsed_a_value;\n }\n\n case WUFFS_BASE__TOKEN__VBC__NUMBER: {\n if (vbd & WUFFS_BASE__TOKEN__VBD__NUMBER__FORMAT_TEXT) {\n if (vbd & WUFFS_BASE__TOKEN__VBD__NUMBER__CONTENT_INTEGER_SIGNED) {\n wuffs_base__result_i64 r = wuffs_base__parse_number_i64(\n wuffs_base__make_slice_u8(token_ptr, token_len),\n WUFFS_BASE__PARSE_NUMBER_XXX__DEFAULT_OPTIONS);\n " +
+ " if (r.status.is_ok()) {\n ret_error_message = callbacks.AppendI64(r.value);\n goto parsed_a_value;\n }\n }\n if (vbd & WUFFS_BASE__TOKEN__VBD__NUMBER__CONTENT_FLOATING_POINT) {\n wuffs_base__result_f64 r = wuffs_base__parse_number_f64(\n wuffs_base__make_slice_u8(token_ptr, token_len),\n WUFFS_BASE__PARSE_NUMBER_XXX__DEFAULT_OPTIONS);\n if (r.status.is_ok()) {\n ret_error_message = callbacks.AppendF64(r.value);\n goto parsed_a_value;\n }\n }\n } else if (vbd & WUFFS_BASE__TOKEN__VBD__NUMBER__CONTENT_NEG_INF) {\n ret_error_message = callbacks.AppendF64(\n wuffs_base__ieee_754_bit_representation__from_u64_to_f64(\n 0xFFF0000000000000ul));\n goto parsed_a_value;\n } else if (vbd & WUFFS_BASE__TOKEN__VBD__NUMBER__CONTENT_POS_INF) {\n ret_error_message = callbacks.AppendF" +
+ "64(\n wuffs_base__ieee_754_bit_representation__from_u64_to_f64(\n 0x7FF0000000000000ul));\n goto parsed_a_value;\n } else if (vbd & WUFFS_BASE__TOKEN__VBD__NUMBER__CONTENT_NEG_NAN) {\n ret_error_message = callbacks.AppendF64(\n wuffs_base__ieee_754_bit_representation__from_u64_to_f64(\n 0xFFFFFFFFFFFFFFFFul));\n goto parsed_a_value;\n } else if (vbd & WUFFS_BASE__TOKEN__VBD__NUMBER__CONTENT_POS_NAN) {\n ret_error_message = callbacks.AppendF64(\n wuffs_base__ieee_754_bit_representation__from_u64_to_f64(\n 0x7FFFFFFFFFFFFFFFul));\n goto parsed_a_value;\n }\n goto fail;\n }\n }\n\n fail:\n ret_error_message =\n \"wuffs_aux::DecodeJson: internal error: unexpected token\";\n goto done;\n\n parsed_a_value:\n if (!ret_error_message.empty() || (depth == 0)) {\n goto done;\n }\n }\n } while (false);\n\nd" +
+ "one:\n DecodeJsonResult result(\n std::move(ret_error_message),\n wuffs_base__u64__sat_add(io_buf->meta.pos, cursor_index));\n callbacks.Done(result, input, *io_buf);\n return result;\n}\n\n#undef WUFFS_AUX__DECODE_JSON__GET_THE_NEXT_TOKEN\n\n} // namespace wuffs_aux\n\n#endif // !defined(WUFFS_CONFIG__MODULES) ||\n // defined(WUFFS_CONFIG__MODULE__AUX__JSON)\n" +
""
const AuxJsonHh = "" +
diff --git a/release/c/wuffs-unsupported-snapshot.c b/release/c/wuffs-unsupported-snapshot.c
index 4b75f86..32567aa 100644
--- a/release/c/wuffs-unsupported-snapshot.c
+++ b/release/c/wuffs-unsupported-snapshot.c
@@ -7625,7 +7625,9 @@
#define WUFFS_JSON__QUIRK_ALLOW_TRAILING_NEW_LINE 1225364497
-#define WUFFS_JSON__QUIRK_REPLACE_INVALID_UNICODE 1225364498
+#define WUFFS_JSON__QUIRK_JSON_POINTER_ALLOW_TILDE_R_TILDE_N 1225364498
+
+#define WUFFS_JSON__QUIRK_REPLACE_INVALID_UNICODE 1225364499
// ---------------- Struct Declarations
@@ -7715,7 +7717,7 @@
wuffs_base__vtable vtable_for__wuffs_base__token_decoder;
wuffs_base__vtable null_vtable;
- bool f_quirks[19];
+ bool f_quirks[20];
bool f_allow_leading_ars;
bool f_allow_leading_ubom;
bool f_end_of_data;
@@ -25710,7 +25712,7 @@
#define WUFFS_JSON__QUIRKS_BASE 1225364480
-#define WUFFS_JSON__QUIRKS_COUNT 19
+#define WUFFS_JSON__QUIRKS_COUNT 20
// ---------------- Private Initializer Prototypes
@@ -25852,7 +25854,7 @@
if (a_quirk >= 1225364480) {
a_quirk -= 1225364480;
- if (a_quirk < 19) {
+ if (a_quirk < 20) {
self->private_impl.f_quirks[a_quirk] = a_enabled;
}
}
@@ -26214,7 +26216,7 @@
} else {
if (((uint64_t)(io2_a_src - iop_a_src)) < 12) {
if (a_src && a_src->meta.closed) {
- if (self->private_impl.f_quirks[18]) {
+ if (self->private_impl.f_quirks[19]) {
(iop_a_src += 6, wuffs_base__make_empty_struct());
*iop_a_dst++ = wuffs_base__make_token(
(((uint64_t)(6356989)) << WUFFS_BASE__TOKEN__VALUE_MINOR__SHIFT) |
@@ -26265,7 +26267,7 @@
goto label__string_loop_outer__continue;
}
}
- if (self->private_impl.f_quirks[18]) {
+ if (self->private_impl.f_quirks[19]) {
if (((uint64_t)(io2_a_src - iop_a_src)) < 6) {
status = wuffs_base__make_status(wuffs_json__error__internal_error_inconsistent_i_o);
goto exit;
@@ -26324,7 +26326,7 @@
(((uint64_t)(1)) << WUFFS_BASE__TOKEN__CONTINUED__SHIFT) |
(((uint64_t)(10)) << WUFFS_BASE__TOKEN__LENGTH__SHIFT));
goto label__string_loop_outer__continue;
- } else if (self->private_impl.f_quirks[18]) {
+ } else if (self->private_impl.f_quirks[19]) {
(iop_a_src += 10, wuffs_base__make_empty_struct());
*iop_a_dst++ = wuffs_base__make_token(
(((uint64_t)(6356989)) << WUFFS_BASE__TOKEN__VALUE_MINOR__SHIFT) |
@@ -26416,7 +26418,7 @@
}
}
if (a_src && a_src->meta.closed) {
- if (self->private_impl.f_quirks[18]) {
+ if (self->private_impl.f_quirks[19]) {
*iop_a_dst++ = wuffs_base__make_token(
(((uint64_t)(6356989)) << WUFFS_BASE__TOKEN__VALUE_MINOR__SHIFT) |
(((uint64_t)(1)) << WUFFS_BASE__TOKEN__CONTINUED__SHIFT) |
@@ -26461,7 +26463,7 @@
}
}
if (a_src && a_src->meta.closed) {
- if (self->private_impl.f_quirks[18]) {
+ if (self->private_impl.f_quirks[19]) {
*iop_a_dst++ = wuffs_base__make_token(
(((uint64_t)(6356989)) << WUFFS_BASE__TOKEN__VALUE_MINOR__SHIFT) |
(((uint64_t)(1)) << WUFFS_BASE__TOKEN__CONTINUED__SHIFT) |
@@ -26508,7 +26510,7 @@
}
}
if (a_src && a_src->meta.closed) {
- if (self->private_impl.f_quirks[18]) {
+ if (self->private_impl.f_quirks[19]) {
*iop_a_dst++ = wuffs_base__make_token(
(((uint64_t)(6356989)) << WUFFS_BASE__TOKEN__VALUE_MINOR__SHIFT) |
(((uint64_t)(1)) << WUFFS_BASE__TOKEN__CONTINUED__SHIFT) |
@@ -26568,7 +26570,7 @@
status = wuffs_base__make_status(wuffs_json__error__bad_c0_control_code);
goto exit;
}
- if (self->private_impl.f_quirks[18]) {
+ if (self->private_impl.f_quirks[19]) {
*iop_a_dst++ = wuffs_base__make_token(
(((uint64_t)(6356989)) << WUFFS_BASE__TOKEN__VALUE_MINOR__SHIFT) |
(((uint64_t)(1)) << WUFFS_BASE__TOKEN__CONTINUED__SHIFT) |
@@ -29435,10 +29437,15 @@
namespace {
-// DecodeJson_SplitJsonPointer returns ("bar", 8) for ("/foo/bar/baz/qux", 5).
-// It returns a 0 size_t when s has invalid JSON Pointer syntax.
+// DecodeJson_SplitJsonPointer returns ("bar", 8) for ("/foo/bar/b~1z/qux", 5,
+// etc). It returns a 0 size_t when s has invalid JSON Pointer syntax.
+//
+// The string returned is unescaped. If calling it again, this time with i=8,
+// the "b~1z" substring would be returned as "b/z".
std::pair<std::string, size_t> //
-DecodeJson_SplitJsonPointer(std::string& s, size_t i) {
+DecodeJson_SplitJsonPointer(std::string& s,
+ size_t i,
+ bool allow_tilde_r_tilde_n) {
std::string fragment;
while (i < s.size()) {
char c = s[i];
@@ -29462,6 +29469,16 @@
fragment.push_back('/');
i++;
continue;
+ } else if (allow_tilde_r_tilde_n) {
+ if (c == 'r') {
+ fragment.push_back('\r');
+ i++;
+ continue;
+ } else if (c == 'n') {
+ fragment.push_back('\n');
+ i++;
+ continue;
+ }
}
return std::make_pair(std::string(), 0);
}
@@ -29709,8 +29726,13 @@
ret_error_message = "wuffs_aux::DecodeJson: out of memory";
goto done;
}
+ bool allow_tilde_r_tilde_n = false;
for (size_t i = 0; i < quirks.len; i++) {
dec->set_quirk_enabled(quirks.ptr[i], true);
+ if (quirks.ptr[i] ==
+ WUFFS_JSON__QUIRK_JSON_POINTER_ALLOW_TILDE_R_TILDE_N) {
+ allow_tilde_r_tilde_n = true;
+ }
}
// Prepare the wuffs_base__tok_buffer.
@@ -29730,8 +29752,8 @@
ret_error_message = DecodeJson_BadJsonPointer;
goto done;
}
- std::pair<std::string, size_t> split =
- DecodeJson_SplitJsonPointer(json_pointer, i + 1);
+ std::pair<std::string, size_t> split = DecodeJson_SplitJsonPointer(
+ json_pointer, i + 1, allow_tilde_r_tilde_n);
i = std::move(split.second);
if (i == 0) {
ret_error_message = DecodeJson_BadJsonPointer;
diff --git a/std/json/decode_quirks.wuffs b/std/json/decode_quirks.wuffs
index 2d9a97c..6fbe85f 100644
--- a/std/json/decode_quirks.wuffs
+++ b/std/json/decode_quirks.wuffs
@@ -197,6 +197,13 @@
// line comment.
pub const QUIRK_ALLOW_TRAILING_NEW_LINE : base.u32 = 0x4909_9400 | 0x11
+// When this quirk is enabled, JSON Pointer strings containing "~r" or "~n",
+// which would otherwise be invalid, are unescaped as "\r" or "\n".
+//
+// This quirk isn't used by Wuffs' std/json package per se, but it is used by
+// the wuffs_aux::DecodeJson function.
+pub const QUIRK_JSON_POINTER_ALLOW_TILDE_R_TILDE_N : base.u32 = 0x4909_9400 | 0x12
+
// When this quirk is enabled, invalid UTF-8 inside a JSON string is accepted.
// Each byte of invalid UTF-8 is equivalent to "\uFFFD", the Unicode
// Replacement Character. The UTF-8 encoding of U+FFFD is "\xEF\xBF\xBD".
@@ -211,6 +218,6 @@
// When combined with QUIRK_ALLOW_BACKSLASH_CAPITAL_U, a "\U12345678" 10-byte
// unit that is an invalid Unicode code point (i.e. in the range U+D800 ..=
// U+DFFF or above U+10FFFF) is similarly replaced with U+FFFD.
-pub const QUIRK_REPLACE_INVALID_UNICODE : base.u32 = 0x4909_9400 | 0x12
+pub const QUIRK_REPLACE_INVALID_UNICODE : base.u32 = 0x4909_9400 | 0x13
-pri const QUIRKS_COUNT : base.u32 = 0x13
+pri const QUIRKS_COUNT : base.u32 = 0x14