Merge "Upgrade bazel to 4.0.0rc6"
diff --git a/third_party/jsont/.gitignore b/third_party/jsont/.gitignore
deleted file mode 100644
index ecee4c9..0000000
--- a/third_party/jsont/.gitignore
+++ /dev/null
@@ -1,6 +0,0 @@
-example1
-example2
-*.d
-.objs
-x*
-test/build
diff --git a/third_party/jsont/BUILD b/third_party/jsont/BUILD
deleted file mode 100644
index be9e94d..0000000
--- a/third_party/jsont/BUILD
+++ /dev/null
@@ -1,30 +0,0 @@
-licenses(["notice"])
-
-cc_library(
- name = "jsont",
- srcs = [
- "jsont.c",
- ],
- hdrs = [
- "jsont.h",
- ],
- includes = ["."],
- target_compatible_with = ["@platforms//os:linux"],
- visibility = ["//visibility:public"],
-)
-
-cc_test(
- name = "jsont_test",
- srcs = ["test/test_tokenizer.c"],
- copts = [
- "-Wno-unused-parameter",
- "-Wno-unused-variable",
- ] + select({
- "@//tools:cpu_roborio": [
- "-Wno-unused-but-set-variable",
- ],
- "//conditions:default": [],
- }),
- target_compatible_with = ["@platforms//os:linux"],
- deps = [":jsont"],
-)
diff --git a/third_party/jsont/LICENSE b/third_party/jsont/LICENSE
deleted file mode 100644
index 03c7813..0000000
--- a/third_party/jsont/LICENSE
+++ /dev/null
@@ -1,19 +0,0 @@
-Copyright (c) 2012 Rasmus Andersson <http://rsms.me/>
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in
-all copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-THE SOFTWARE.
diff --git a/third_party/jsont/Makefile b/third_party/jsont/Makefile
deleted file mode 100644
index 848cdc2..0000000
--- a/third_party/jsont/Makefile
+++ /dev/null
@@ -1,57 +0,0 @@
-c_sources := jsont.c
-
-all: example1 example2 test
-
-object_dir = .objs
-objects = $(patsubst %,$(object_dir)/%,${c_sources:.c=.o})
-object_dirs = $(sort $(foreach fn,$(objects),$(dir $(fn))))
--include ${objects:.o=.d}
-
-test_dir = test
-test_sources := $(wildcard test/test*.c)
-test_object_dir = $(test_dir)/.objs
-test_build_dir = $(test_dir)/build
-test_objects = $(patsubst test/%,$(test_object_dir)/%,${test_sources:.c=.o})
-test_programs = $(patsubst test/%.c,$(test_build_dir)/%,$(test_sources))
-test_object_dirs = $(sort $(foreach fn,$(test_objects),$(dir $(fn))))
-
-CC = clang
-LD = clang
-
-CFLAGS += -Wall -g -MMD -std=c99 -I.
-TEST_CFLAGS := $(CFLAGS) -O0
-#LDFLAGS +=
-ifneq ($(DEBUG),)
- CFLAGS += -O0 -DDEBUG=1
-else
- CFLAGS += -O3 -DNDEBUG
-endif
-
-clean:
- rm -f jsont example1 example2
- rm -rf $(object_dir)
- rm -rf $(test_object_dir)
- rm -rf $(test_build_dir)
-
-example1: $(objects) $(object_dir)/example1.o
- $(LD) $(LDFLAGS) -o $@ $^
-
-example2: $(objects) $(object_dir)/example2.o
- $(LD) $(LDFLAGS) -o $@ $^
-
-test: $(objects) $(test_programs)
- $(test_programs)
-
-$(test_build_dir)/%: $(objects) $(test_object_dir)/%.o
- @mkdir -p `dirname $@`
- $(LD) $(LDFLAGS) -o $@ $^
-
-$(test_object_dir)/%.o: $(test_dir)/%.c
- @mkdir -p `dirname $@`
- $(CC) $(TEST_CFLAGS) -c -o $@ $<
-
-$(object_dir)/%.o: %.c
- @mkdir -p `dirname $@`
- $(CC) $(CFLAGS) -c -o $@ $<
-
-.PHONY: clean all test
diff --git a/third_party/jsont/README.md b/third_party/jsont/README.md
deleted file mode 100644
index 34ec56e..0000000
--- a/third_party/jsont/README.md
+++ /dev/null
@@ -1,209 +0,0 @@
-# JSON Tokenizer (jsont)
-
-A minimal and portable JSON tokenizer written in standard C and C++ (two separate versions). Performs validating and highly efficient parsing suitable for reading JSON directly into custom data structures. There are no code dependencies — simply include `jsont.{h,hh,c,cc}` in your project.
-
-Build and run unit tests:
-
- make
-
-## Synopsis
-
-C API:
-
-```c
-jsont_ctx_t* S = jsont_create(0);
-jsont_reset(S, uint8_t* inbuf, size_t inbuf_len);
-tok = jsont_next(S)
-// branch on `tok` ...
-V = jsont_*_value(S[, ...]);
-jsont_destroy(S);
-```
-
-New C++ API:
-
-```cc
-jsont::Tokenizer S(const char* inbuf, size_t length);
-jsont::Token token;
-while ((token = S.next())) {
- if (token == jsont::Float) {
- printf("%g\n", S.floatValue());
- } ... else if (t == jsont::Error) {
- // handle error
- break;
- }
-}
-```
-
-```cc
-jsont::Builder json;
-json.startObject()
- .fieldName("foo").value(123.45)
- .fieldName("bar").startArray()
- .value(678)
- .value("nine \"ten\"")
- .endArray()
- .endObject();
-std::cout << json.toString() << std::endl;
-// {"foo":123.45,"bar":[678,"nine \"ten\""]}
-```
-
-# API overview
-
-See `jsont.h` and `jsont.hh` for a complete overview of the API, incuding more detailed documentation. Here's an overview:
-
-## C++ API `namespace jsont`
-
-- `Builder build()` — convenience builder factory
-
-### class Tokenizer
-
-Reads a sequence of bytes and produces tokens and values while doing so.
-
-- `Tokenizer(const char* bytes, size_t length, TextEncoding encoding)` — initialize a new Tokenizer to read `bytes` of `length` in `encoding`
-- `void reset(const char* bytes, size_t length, TextEncoding encoding)` — Reset the tokenizer, making it possible to reuse this parser so to avoid unnecessary memory allocation and deallocation.
-
-#### Reading tokens
-
-- `const Token& next() throw(Error)` — Read next token, possibly throwing an `Error`
-- `const Token& current() const` — Access current token
-
-#### Reading values
-
-- `bool hasValue() const` — True if the current token has a value
-- `size_t dataValue(const char const** bytes)` — Returns a slice of the input which represents the current value, or nothing (returns 0) if the current token has no value (e.g. start of an object).
-- `std::string stringValue() const` — Returns a *copy* of the current string value.
-- `double floatValue() const` — Returns the current value as a double-precision floating-point number.
-- `int64_t intValue() const` — Returns the current value as a signed 64-bit integer.
-
-#### Handling errors
-
-- `ErrorCode error() const` — Returns the error code of the last error
-- `const char* errorMessage() const` — Returns a human-readable message for the last error. Never returns NULL.
-
-#### Acessing underlying input buffer
-
-- `const char* inputBytes() const` — A pointer to the input data as passed to `reset` or the constructor.
-- `size_t inputSize() const` — Total number of input bytes
-- `size_t inputOffset() const` — The byte offset into input where the tokenizer is currently at. In the event of an error, this will point to the source of the error.
-
-### enum Token
-
-- `End` — Input ended
-- `ObjectStart` — {
-- `ObjectEnd` — }
-- `ArrayStart` — [
-- `ArrayEnd` — ]
-- `True` — true
-- `False` — false
-- `Null` — null
-- `Integer` — number value without a fraction part (access as int64 through `Tokenizer::intValue()`)
-- `Float` — number value with a fraction part (access as double through `Tokenizer::floatValue()`)
-- `String` — string value (access value through `Tokenizer::stringValue()` et al)
-- `FieldName` — field name (access value through `Tokenizer::stringValue()` et al)
-- `Error` — an error occured (access error code through `Tokenizer::error()` et al)
-
-### enum TextEncoding
-
-- `UTF8TextEncoding` — Unicode UTF-8 text encoding
-
-### enum Tokenizer::ErrorCode
-
-- `UnspecifiedError` — Unspecified error
-- `UnexpectedComma` — Unexpected comma
-- `UnexpectedTrailingComma` — Unexpected trailing comma
-- `InvalidByte` — Invalid input byte
-- `PrematureEndOfInput` — Premature end of input
-- `MalformedUnicodeEscapeSequence` — Malformed Unicode escape sequence
-- `MalformedNumberLiteral` — Malformed number literal
-- `UnterminatedString` — Unterminated string
-- `SyntaxError` — Illegal JSON (syntax error)
-
-### class Builder
-
-Aids in building JSON, providing a final sequential byte buffer.
-
-- `Builder()` — initialize a new builder with an empty backing buffer
-- `Builder& startObject()` — Start an object (appends a `'{'` character to the backing buffer)
-- `Builder& endObject()` — End an object (a `'}'` character)
-- `Builder& startArray()` — Start an array (`'['`)
-- `Builder& endArray()` — End an array (`']'`)
-- `const void reset()` — Reset the builder to its neutral state. Note that the backing buffer is reused in this case.
-
-#### Building
-
-- `Builder& fieldName(const char* v, size_t length, TextEncoding encoding=UTF8TextEncoding)` — Adds a field name by copying `length` bytes from `v`.
-- `Builder& fieldName(const std::string& name, TextEncoding encoding=UTF8TextEncoding)` — Adds a field name by copying `name`.
-- `Builder& value(const char* v, size_t length, TextEncoding encoding=UTF8TextEncoding)` — Adds a string value by copying `length` bytes from `v` which content is encoded according to `encoding`.
-- `Builder& value(const char* v)` — Adds a string value by copying `strlen(v)` bytes from c-string `v`. Uses the default encoding of `value(const char*,size_t,TextEncoding)`.
-- `Builder& value(const std::string& v)` — Adds a string value by copying `v`. Uses the default encoding of `value(const char*,size_t,TextEncoding)`.
-- `Builder& value(double v)` — Adds a possibly fractional number
-- `Builder& value(int64_t v)`, `void value(int v)`, `void value(unsigned int v)`, `void value(long v)` — Adds an integer number
-- `Builder& value(bool v)` — Adds the "true" or "false" atom, depending on `v`
-- `Builder& nullValue()` — Adds the "null" atom
-
-#### Managing the result
-
-- `size_t size() const` — Number of readable bytes at the pointer returned by `bytes()`
-- `const char* bytes() const` — Pointer to the backing buffer, holding the resulting JSON.
-- `std::string toString() const` — Return a `std::string` object holding a copy of the backing buffer, representing the JSON.
-- `const char* seizeBytes(size_t& size_out)` — "Steal" the backing buffer. After this call, the caller is responsible for calling `free()` on the returned pointer. Returns NULL on failure. Sets the value of `size_out` to the number of readable bytes at the returned pointer. The builder will be reset and ready to use (which will act on a new backing buffer).
-
-----
-
-## C API
-
-### Types
-
-- `jsont_ctx_t` — A tokenizer context ("instance" in OOP lingo.)
-- `jsont_tok_t` — A token type (see "Token types".)
-- `jsont_err_t` — A user-configurable error type, which defaults to `const char*`.
-
-### Managing a tokenizer context
-
-- `jsont_ctx_t* jsont_create(void* user_data)` — Create a new JSON tokenizer context.
-- `void jsont_destroy(jsont_ctx_t* ctx)` — Destroy a JSON tokenizer context.
-- `void jsont_reset(jsont_ctx_t* ctx, const uint8_t* bytes, size_t length)` — Reset the tokenizer to parse the data pointed to by `bytes`.
-
-### Dealing with tokens
-
-- `jsont_tok_t jsont_next(jsont_ctx_t* ctx)` — Read and return the next token.
-- `jsont_tok_t jsont_current(const jsont_ctx_t* ctx)` — Returns the current token (last token read by `jsont_next`).
-
-### Accessing and comparing values
-
-- `int64_t jsont_int_value(jsont_ctx_t* ctx)` — Returns the current integer value.
-- `double jsont_float_value(jsont_ctx_t* ctx)` — Returns the current floating-point number value.
-- `size_t jsont_data_value(jsont_ctx_t* ctx, const uint8_t** bytes)` — Returns a slice of the input which represents the current value.
-- `char* jsont_strcpy_value(jsont_ctx_t* ctx)` — Retrieve a newly allocated c-string.
-- `bool jsont_data_equals(jsont_ctx_t* ctx, const uint8_t* bytes, size_t length)` — Returns true if the current data value is equal to `bytes` of `length`
-- `bool jsont_str_equals(jsont_ctx_t* ctx, const char* str)` — Returns true if the current data value is equal to c string `str`.
-
-Note that the data is not parsed until you call one of these functions. This means that if you know that a value transferred as a string will fit in a 64-bit signed integer, it's completely valid to call `jsont_int_value` to parse the string as an integer.
-
-### Miscellaneous
-
-- `uint8_t jsont_current_byte(jsont_ctx_t* ctx)` — Get the last byte read.
-- `size_t jsont_current_offset(jsont_ctx_t* ctx)` — Get the current offset of the last byte read.
-- `jsont_err_t jsont_error_info(jsont_ctx_t* ctx)` — Get information on the last error.
-- `void* jsont_user_data(const jsont_ctx_t* ctx)` — Returns the value passed to `jsont_create`
-
-### Token types
-
-- `JSONT_END` — Input ended.
-- `JSONT_ERR` — Error. Retrieve details through `jsont_error_info`
-- `JSONT_OBJECT_START` — {
-- `JSONT_OBJECT_END` — }
-- `JSONT_ARRAY_START` — [
-- `JSONT_ARRAY_END` — ]
-- `JSONT_TRUE` — true
-- `JSONT_FALSE` — false
-- `JSONT_NULL` — null
-- `JSONT_NUMBER_INT` — number value without a fraction part (access through `jsont_int_value` or `jsont_float_value`)
-- `JSONT_NUMBER_FLOAT` — number value with a fraction part (access through `jsont_float_value`)
-- `JSONT_STRING` — string value (access through `jsont_data_value` or `jsont_strcpy_value`)
-- `JSONT_FIELD_NAME` — field name (access through `jsont_data_value` or `jsont_strcpy_value`)
-
-## Further reading
-
-- See `example*.c` for working sample programs.
-- See `LICENSE` for the MIT-style license under which this project is licensed.
diff --git a/third_party/jsont/example1.c b/third_party/jsont/example1.c
deleted file mode 100644
index c36559c..0000000
--- a/third_party/jsont/example1.c
+++ /dev/null
@@ -1,76 +0,0 @@
-//
-// This is a simple example of running the tokenizer, outputting information
-// to stdout about what tokens we get and their values.
-//
-#include <jsont.h>
-#include <stdio.h>
-#include <string.h>
-
-static const char* _tok_name(jsont_tok_t tok);
-
-int main(int argc, const char** argv) {
- // Create a new reusable tokenizer
- jsont_ctx_t* S = jsont_create(0);
-
- // Sample input
- const char* inbuf = "{\"Ape\":123,\"Bro\":[400192,\"51\",true, false, null,"
- " -67,\r\n\t 6.123]}";
-
- // Reset the parser with a pointer to our sample input
- jsont_reset(S, (const uint8_t*)inbuf, strlen(inbuf));
-
- // Read each token
- jsont_tok_t tok;
- printf("Token | Value\n"
- "-------------|----------------------------------------\n");
- while ( (tok = jsont_next(S)) != JSONT_END && tok != JSONT_ERR) {
- printf("%-12s |", _tok_name(tok));
-
- // If the token has a value, also print its value
- if (tok == JSONT_STRING || tok == JSONT_FIELD_NAME) {
- const uint8_t* bytes = 0;
- size_t len = jsont_data_value(S, &bytes);
- if (len != 0)
- printf(" '%.*s'", (int)len, (const char*)bytes);
- } else if (tok == JSONT_NUMBER_INT) {
- printf(" %lld", jsont_int_value(S));
- } else if (tok == JSONT_NUMBER_FLOAT) {
- printf(" %f", jsont_float_value(S));
- }
-
- printf("\n");
- }
-
- // If we got an error, print some useful information and exit with 1
- if (tok == JSONT_ERR) {
- fprintf(stderr, "Error: %s ('%c' at offset %lu)\n",
- jsont_error_info(S),
- (char)jsont_current_byte(S),
- (unsigned long)jsont_current_offset(S));
- return 1;
- }
-
- // Destroy our reusable tokenizer and exit
- jsont_destroy(S);
- return 0;
-}
-
-// Utility to get a printable name for a token
-static const char* _tok_name(jsont_tok_t tok) {
- switch (tok) {
- case JSONT_END: return "END";
- case JSONT_ERR: return "ERR";
- case JSONT_OBJECT_START: return "OBJECT_START";
- case JSONT_OBJECT_END: return "OBJECT_END";
- case JSONT_ARRAY_START: return "ARRAY_START";
- case JSONT_ARRAY_END: return "ARRAY_END";
- case JSONT_TRUE: return "TRUE";
- case JSONT_FALSE: return "FALSE";
- case JSONT_NULL: return "NULL";
- case JSONT_NUMBER_INT: return "NUMBER_INT";
- case JSONT_NUMBER_FLOAT: return "NUMBER_FLOAT";
- case JSONT_STRING: return "STRING";
- case JSONT_FIELD_NAME: return "FIELD_NAME";
- default: return "?";
- }
-}
diff --git a/third_party/jsont/example2.c b/third_party/jsont/example2.c
deleted file mode 100644
index 5077f85..0000000
--- a/third_party/jsont/example2.c
+++ /dev/null
@@ -1,183 +0,0 @@
-//
-// This is an example of parsing and building strict documents into C structs.
-//
-// The general approach is that each object type has a struct type and a
-// builder function. The struct type has members which represents its
-// properties. The builder function is more intresting: It takes a tokenizer
-// state and a struct instance. The builder function then reads each field
-// name from the tokenizer and calls other builder functions (this is how this
-// parser does flow control), and eventually stores the values into the struct
-// instance.
-//
-#include <jsont.h>
-#include <stdio.h>
-#include <string.h>
-#include <stdbool.h>
-
-// A simple array type
-typedef struct my_array {
- size_t size;
- size_t count;
- void** items;
-} my_array_t;
-
-// Represents a user object
-typedef struct my_user {
- const char* id;
- const char* name;
-} my_user_t;
-
-// Represents a response from our imaginary service
-typedef struct my_response {
- int64_t timestamp;
- const char* viewer_id;
- my_array_t users;
-} my_response_t;
-
-// A helper macro for allocating a new struct instance
-#define MY_NEW(T) (T*)malloc(sizeof(T))
-
-// Some helper macros for dealing with growing arrays
-#define MY_ARRAY_ALLOC(A, _size) do {\
- (A).items = (void*)malloc(sizeof(void*)*_size); \
- (A).count = 0; \
- (A).size = _size; \
- } while(0)
-#define MY_ARRAY_RESIZE(A, _size) do {\
- (A).items = (void*)realloc((A).items, sizeof(void*)*_size); \
- (A).size = _size; \
- } while(0)
-#define MY_ARRAY_APPEND(A, item) (A).items[(A).count++] = (void*)(item)
-#define MY_NEXT_EXPECT(S, TOKTYPE) do { \
- if ((tok = jsont_next(S)) != TOKTYPE) { \
- printf("Error: Builder expected token " #TOKTYPE " (%d)\n", __LINE__); \
- return false; \
- }} while (0)
-
-// Builder function for user objects
-bool my_user_build(jsont_ctx_t* S, my_user_t* obj) {
- jsont_tok_t tok = jsont_current(S);
- if (tok != JSONT_OBJECT_START) return false;
-
- // for each field
- while ((tok = jsont_next(S)) == JSONT_FIELD_NAME) {
- const uint8_t* fieldname = 0;
- size_t len = jsont_data_value(S, &fieldname);
-
- if (memcmp("id", fieldname, len) == 0) {
- MY_NEXT_EXPECT(S, JSONT_STRING);
- obj->id = jsont_strcpy_value(S);
-
- } else if (memcmp("name", fieldname, len) == 0) {
- MY_NEXT_EXPECT(S, JSONT_STRING);
- obj->name = jsont_strcpy_value(S);
-
- } else {
- printf("%s: Unexpected field: \"%.*s\"\n", __FUNCTION__,
- (int)len, (const char*)fieldname);
- return false;
- }
- }
-
- return true;
-}
-
-// Builder function for response objects
-bool my_response_build(jsont_ctx_t* S, my_response_t* obj) {
- jsont_tok_t tok = jsont_current(S);
- if (tok != JSONT_OBJECT_START) return false;
-
- // for each field
- while ((tok = jsont_next(S)) == JSONT_FIELD_NAME) {
- const uint8_t* fieldname = 0;
- size_t len = jsont_data_value(S, &fieldname);
-
- if (memcmp("timestamp", fieldname, len) == 0) {
- MY_NEXT_EXPECT(S, JSONT_NUMBER_INT);
- obj->timestamp = jsont_int_value(S);
-
- } else if (memcmp("viewer_id", fieldname, len) == 0) {
- MY_NEXT_EXPECT(S, JSONT_STRING);
- obj->viewer_id = jsont_strcpy_value(S);
-
- } else if (memcmp("users", fieldname, len) == 0) {
- MY_NEXT_EXPECT(S, JSONT_ARRAY_START);
- MY_ARRAY_ALLOC(obj->users, 10);
-
- // for each user object
- while ((tok = jsont_next(S)) == JSONT_OBJECT_START) {
- if (obj->users.count == obj->users.size)
- MY_ARRAY_RESIZE(obj->users, obj->users.size * 2);
- my_user_t* user = MY_NEW(my_user_t);
- if (!my_user_build(S, user))
- return false;
- MY_ARRAY_APPEND(obj->users, user);
- }
- } else {
- printf("%s: Unexpected field: \"%.*s\"\n", __FUNCTION__,
- (int)len, (const char*)fieldname);
- return false;
- }
- }
-
- return true;
-}
-
-// Our simple response parser entry point. Returns NULL on error.
-my_response_t* my_parse_response(jsont_ctx_t* S) {
-if (jsont_next(S) != JSONT_OBJECT_START) {
- printf("Expected JSON input to start with an object.\n");
- return 0;
- }
- my_response_t* rsp = MY_NEW(my_response_t);
- if (!my_response_build(S, rsp)) {
- free(rsp);
- return 0;
- }
- return rsp;
-}
-
-int main(int argc, const char** argv) {
- // Create a new reusable tokenizer
- jsont_ctx_t* S = jsont_create(0);
-
- // Sample "response" data
- const char* inbuf = "{"
- "\"viewer_id\": \"abc123\","
- "\"timestamp\": 1234567890,"
- "\"users\":["
- "{\"name\": \"John Smith\", \"id\": \"12c39a\"},\n"
- "{\"name\": \"John Doe\", \"id\": \"01dk2\"},\n"
- "{\"name\": \"Kate Smith\", \"id\": \"apru1\"},\n"
- "{\"name\": \"Rebecca Doe\",\"id\": \"aRm26\"}\n"
- "]"
- "}";
-
- // Parse the sample "response" data
- jsont_reset(S, (const uint8_t*)inbuf, strlen(inbuf));
- my_response_t* rsp = my_parse_response(S);
-
- // Epic success?
- if (rsp) {
- printf("Built response structure.\n");
- printf("rsp->users.items[2]->name => \"%s\"\n",
- ((my_user_t*)rsp->users.items[2])->name );
-
- } else {
- printf("Failed to build response structure.\n");
- if (jsont_error_info(S) != 0) {
- fprintf(stderr, "Error: %s ('%c' at offset %lu)\n",
- jsont_error_info(S),
- (char)jsont_current_byte(S),
- (unsigned long)jsont_current_offset(S));
- }
- // Exit with error. Note: In a real application, you should call
- // `jsont_destroy` on the reusable tokenizer when done with it. Here we
- // just exit the program.
- return 1;
- }
-
- // Destroy our reusable tokenizer and exit
- jsont_destroy(S);
- return 0;
-}
diff --git a/third_party/jsont/jsont.c b/third_party/jsont/jsont.c
deleted file mode 100644
index b318494..0000000
--- a/third_party/jsont/jsont.c
+++ /dev/null
@@ -1,570 +0,0 @@
-// JSON Tokenizer. Copyright (c) 2012, Rasmus Andersson. All rights reserved.
-// Use of this source code is governed by a MIT-style license that can be
-// found in the LICENSE file.
-#include <stdlib.h>
-#include <stdint.h>
-#include <stdbool.h>
-#include <limits.h>
-#include <ctype.h> // isdigit
-#include <errno.h>
-#include <string.h>
-#include <math.h>
-#include <assert.h>
-
-// Error info
-#ifndef JSONT_ERRINFO_CUSTOM
-#define jsont_err_t const char*
-#define DEF_EM(NAME, msg) static jsont_err_t JSONT_ERRINFO_##NAME = msg
-DEF_EM(STACK_SIZE, "Stack size limit exceeded");
-DEF_EM(UNEXPECTED_OBJECT_END,
- "Unexpected end of object while not in an object");
-DEF_EM(UNEXPECTED_ARRAY_END, "Unexpected end of array while not in an array");
-DEF_EM(UNEXPECTED_COMMA, "Unexpected \",\"");
-DEF_EM(UNEXPECTED_COLON, "Unexpected \":\"");
-DEF_EM(UNEXPECTED, "Unexpected input");
-DEF_EM(UNEXPECTED_UNICODE_SEQ, "Malformed unicode encoded sequence in string");
-#undef DEF_EM
-#endif
-
-// Size of stack used for structures (in/out array and objects). This value
-// is a balance between memory size of a ctx and how many levels deep the
-// tokenizer can go.
-#define _STRUCT_TYPE_STACK_SIZE 512
-#define _VALUE_BUF_MIN_SIZE 64
-
-static const uint8_t kHexValueTable[55] = {
- 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, // 0-0
- -1, -1, -1, -1, -1, -1, -1,
- 10, 11, 12, 13, 14, 15, // A-F
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1,
- 10, 11, 12, 13, 14, 15 // a-f
-};
-
-typedef uint8_t jsont_tok_t;
-
-typedef struct jsont_ctx {
- void* user_data;
- const uint8_t* input_buf;
- const uint8_t* input_buf_ptr;
- size_t input_len;
- const uint8_t* input_buf_value_start;
- const uint8_t* input_buf_value_end;
- struct {
- uint8_t* data;
- size_t size;
- size_t length;
- bool inuse;
- } value_buf;
- jsont_err_t error_info;
- jsont_tok_t curr_tok;
- size_t st_stack_size;
- size_t st_stack_len;
- jsont_tok_t st_stack[_STRUCT_TYPE_STACK_SIZE];
-} jsont_ctx_t;
-
-#define _JSONT_IN_SOURCE
-#include <jsont.h>
-
-unsigned long _hex_str_to_ul(const uint8_t* bytes, size_t len) {
- unsigned long value = 0;
- unsigned long cutoff = ULONG_MAX / 16;
- int cutoff_digit = (int)(ULONG_MAX - cutoff * 16);
-
- for (size_t i = 0; i != len; ++i) {
- uint8_t b = bytes[i];
- int digit = (b > '0'-1 && b < 'f'+1) ? kHexValueTable[b-'0'] : -1;
- if (b == 0xff || // bad digit
- (value > cutoff) || // overflow
- ((value == cutoff) && (digit > cutoff_digit)) ) {
- return ULONG_MAX;
- } else {
- value = (value * 16) + digit;
- }
- }
-
- return value;
-}
-
-jsont_ctx_t* jsont_create(void* user_data) {
- jsont_ctx_t* ctx = (jsont_ctx_t*)calloc(1, sizeof(jsont_ctx_t));
- ctx->user_data = user_data;
- ctx->st_stack_size = _STRUCT_TYPE_STACK_SIZE;
- return ctx;
-}
-
-void jsont_destroy(jsont_ctx_t* ctx) {
- if (ctx->value_buf.data != 0) {
- free(ctx->value_buf.data);
- }
- free(ctx);
-}
-
-void jsont_reset(jsont_ctx_t* ctx, const uint8_t* bytes, size_t length) {
- ctx->input_buf_ptr = ctx->input_buf = bytes;
- ctx->input_len = length;
- ctx->st_stack_len = 0;
- ctx->curr_tok = JSONT_END;
- ctx->input_buf_value_start = 0;
- ctx->input_buf_value_end = 0;
- ctx->value_buf.length = 0;
- ctx->value_buf.inuse = false;
- ctx->error_info = 0;
-}
-
-jsont_tok_t jsont_current(const jsont_ctx_t* ctx) {
- return ctx->curr_tok;
-}
-
-void* jsont_user_data(const jsont_ctx_t* ctx) {
- return ctx->user_data;
-}
-
-// Get the current/last byte read. Suitable for debugging JSONT_ERR
-uint8_t jsont_current_byte(jsont_ctx_t* ctx) {
- return (ctx->input_buf_ptr == 0) ? 0 : *(ctx->input_buf_ptr-1);
-}
-
-size_t jsont_current_offset(jsont_ctx_t* ctx) {
- return ctx->input_buf_ptr - ctx->input_buf;
-}
-
-jsont_err_t jsont_error_info(jsont_ctx_t* ctx) {
- return ctx->error_info;
-}
-
-inline static bool _no_value(jsont_ctx_t* ctx) {
- return ctx->input_buf_value_start == 0
- || ctx->curr_tok < _JSONT_VALUES_START
- || ctx->curr_tok > _JSONT_VALUES_END;
-}
-
-inline static size_t _input_avail(jsont_ctx_t* ctx) {
- return ctx->input_len - (ctx->input_buf_ptr - ctx->input_buf);
-}
-
-inline static uint8_t _next_byte(jsont_ctx_t* ctx) {
- return (_input_avail(ctx) == 0) ? 0 : *(ctx->input_buf_ptr++);
-}
-
-inline static jsont_tok_t _st_stack_top(const jsont_ctx_t* ctx) {
- return (ctx->st_stack_len != 0) ? ctx->st_stack[ctx->st_stack_len-1]
- : JSONT_END;
-}
-
-size_t jsont_data_value(jsont_ctx_t* ctx, const uint8_t** bytes) {
- if (_no_value(ctx)) {
- return 0;
- } else {
- if (ctx->value_buf.inuse) {
- *bytes = ctx->value_buf.data;
- return ctx->value_buf.length;
- } else {
- *bytes = ctx->input_buf_value_start;
- return ctx->input_buf_value_end - ctx->input_buf_value_start;
- }
- }
-}
-
-bool jsont_data_equals(jsont_ctx_t* ctx, const uint8_t* bytes, size_t length) {
- if (ctx->value_buf.inuse) {
- return (ctx->value_buf.length == length) &&
- (memcmp((const void*)ctx->value_buf.data,
- (const void*)bytes, length) == 0);
- } else {
- return (ctx->input_buf_value_end - ctx->input_buf_value_start ==
- (ssize_t)length) &&
- (memcmp((const void *)ctx->input_buf_value_start,
- (const void *)bytes, length) == 0);
- }
-}
-
-char* jsont_strcpy_value(jsont_ctx_t* ctx) {
- if (_no_value(ctx)) {
- return 0;
- } else {
- const uint8_t* bytes = 0;
- size_t len = jsont_data_value(ctx, &bytes);
- char* buf = (char*)malloc(len+1);
- if (memcpy((void*)buf, (const void*)bytes, len) != buf) {
- return 0;
- }
- buf[len] = 0;
- return buf;
- }
-}
-
-int64_t jsont_int_value(jsont_ctx_t* ctx) {
- if (_no_value(ctx)) {
- return INT64_MIN;
- }
-
- const uint8_t* start = 0;
- size_t len = jsont_data_value(ctx, &start);
- if (len == 0) {
- return INT64_MIN;
- }
- const uint8_t* end = start + len + 1;
-
- bool negative;
- uint8_t b = *start++;
- const int base = 10;
-
- if (b == '-') {
- negative = true;
- b = *start++;
- if (start == end) {
- errno = EINVAL;
- return INT64_MIN;
- }
- } else {
- negative = false;
- if (b == '+') {
- b = *start++;
- if (start == end) {
- errno = EINVAL;
- return INT64_MIN;
- }
- }
- }
-
- uint64_t acc = 0;
- int any = 0;
- uint64_t cutoff = negative
- ? (uint64_t)-(INT64_MIN + INT64_MAX) + INT64_MAX
- : INT64_MAX;
- int cutlim = cutoff % base;
- cutoff /= base;
- for ( ; start != end; b = *start++) {
- if (b >= '0' && b <= '9') b -= '0'; else break;
- if (any < 0 || acc > cutoff || (acc == cutoff && b > cutlim)) {
- any = -1;
- } else {
- any = 1;
- acc *= base;
- acc += b;
- }
- }
-
- if (any < 0) {
- acc = negative ? INT64_MIN : INT64_MAX;
- errno = ERANGE;
- } else if (!any) {
- errno = EINVAL;
- return INT64_MIN;
- } else if (negative) {
- acc = -acc;
- }
-
- return (int64_t)acc;
-}
-
-#ifdef NAN
- #define _JSONT_NAN NAN
-#else
- #define _JSONT_NAN nan(0)
-#endif
-
-double jsont_float_value(jsont_ctx_t* ctx) {
- // Note: This might cause a segfault if the input is at the end, so we cause
- // an error if we try to read a float value while at the end of the input.
- if (_no_value(ctx) || _input_avail(ctx) == 0) {
- errno = EINVAL;
- return _JSONT_NAN;
- }
-
- const uint8_t* bytes = 0;
- size_t len = jsont_data_value(ctx, &bytes);
- if (len == 0) {
- return _JSONT_NAN;
- }
- return atof((const char*)bytes);
-}
-
-inline static jsont_tok_t _set_tok(jsont_ctx_t* ctx, jsont_tok_t tok) {
- ctx->curr_tok = tok;
-
- if (tok != JSONT_END) {
- if (tok == JSONT_OBJECT_START) {
- if (ctx->st_stack_len == ctx->st_stack_size) {
- ctx->error_info = JSONT_ERRINFO_STACK_SIZE;
- return ctx->curr_tok = JSONT_ERR; // TODO: Grow st_stack
- }
- ctx->st_stack[ctx->st_stack_len++] = JSONT_OBJECT_START;
-
- } else if (tok == JSONT_OBJECT_END) {
- if (_st_stack_top(ctx) != JSONT_OBJECT_START) {
- ctx->error_info = JSONT_ERRINFO_UNEXPECTED_OBJECT_END;
- return ctx->curr_tok = JSONT_ERR;
- }
- --ctx->st_stack_len;
-
- } else if (tok == JSONT_ARRAY_START) {
- if (ctx->st_stack_len == ctx->st_stack_size) {
- ctx->error_info = JSONT_ERRINFO_STACK_SIZE;
- return ctx->curr_tok = JSONT_ERR;
- }
- ctx->st_stack[ctx->st_stack_len++] = JSONT_ARRAY_START;
-
- } else if (tok == JSONT_ARRAY_END) {
- if (_st_stack_top(ctx) != JSONT_ARRAY_START) {
- ctx->error_info = JSONT_ERRINFO_UNEXPECTED_ARRAY_END;
- return ctx->curr_tok = JSONT_ERR;
- }
- --ctx->st_stack_len;
- }
- }
-
- return tok;
-}
-inline static void _rewind_one_byte(jsont_ctx_t* ctx) {
- --ctx->input_buf_ptr;
-}
-inline static void _rewind_bytes(jsont_ctx_t* ctx, size_t n) {
- ctx->input_buf_ptr -= n;
-}
-inline static void _skip_bytes(jsont_ctx_t* ctx, size_t n) {
- ctx->input_buf_ptr += n;
-}
-inline static uint8_t _read_atom(jsont_ctx_t* ctx, size_t slacklen,
- jsont_tok_t tok) {
- if (_input_avail(ctx) < slacklen) {
- // rewind and wait for buffer fill
- _rewind_one_byte(ctx);
- return _set_tok(ctx, JSONT_END);
- } else {
- _skip_bytes(ctx, slacklen); // e.g. "ull" after "n" or "alse" after "f"
- return _set_tok(ctx, tok);
- }
-}
-inline static bool _expects_field_name(jsont_ctx_t* ctx) {
- return ( ctx->curr_tok == JSONT_OBJECT_START
- || ( ctx->curr_tok == _JSONT_COMMA
- && _st_stack_top(ctx) == JSONT_OBJECT_START) );
-}
-
-static void _value_buf_append(jsont_ctx_t* ctx, const uint8_t* data, size_t len) {
- //printf("_value_buf_append(<ctx>, %p, %zu)\n", data, len);
- if (ctx->value_buf.size == 0) {
- assert(ctx->value_buf.data == 0);
- ctx->value_buf.length = len;
- ctx->value_buf.size = len * 2;
- if (ctx->value_buf.size < _VALUE_BUF_MIN_SIZE) {
- ctx->value_buf.size = _VALUE_BUF_MIN_SIZE;
- }
- ctx->value_buf.data = (uint8_t*)malloc(ctx->value_buf.size);
- if (len != 0) {
- memcpy(ctx->value_buf.data, data, len);
- }
- } else {
- if (ctx->value_buf.length + len > ctx->value_buf.size) {
- size_t new_size = ctx->value_buf.size + (len * 2);
- ctx->value_buf.data = realloc(ctx->value_buf.data, new_size);
- assert(ctx->value_buf.data != 0);
- ctx->value_buf.size = new_size;
- }
- memcpy(ctx->value_buf.data + ctx->value_buf.length, data, len);
- ctx->value_buf.length += len;
- }
- ctx->value_buf.inuse = true;
-}
-
-jsont_tok_t jsont_next(jsont_ctx_t* ctx) {
- //
- // { } [ ] n t f "
- // | | | |
- // | | | +- /[^"]*/ "
- // | | +- a l s e
- // | +- r u e
- // +- u l l
- //
- while (1) {
- uint8_t b = _next_byte(ctx);
- switch (b) {
- case '{': return _set_tok(ctx, JSONT_OBJECT_START);
- case '}': return _set_tok(ctx, JSONT_OBJECT_END);
- case '[': return _set_tok(ctx, JSONT_ARRAY_START);
- case ']': return _set_tok(ctx, JSONT_ARRAY_END);
- case 'n': return _read_atom(ctx, 3, JSONT_NULL);
- case 't': return _read_atom(ctx, 3, JSONT_TRUE);
- case 'f': return _read_atom(ctx, 4, JSONT_FALSE);
- case '"': {
- ctx->input_buf_value_start = ctx->input_buf_ptr;
- ctx->value_buf.inuse = false;
- ctx->value_buf.length = 0;
- uint8_t prev_b = 0;
- while (1) {
- b = _next_byte(ctx);
-
- if (b == '\\') {
- if (prev_b == '\\') {
- // This is an actual '\'.
- assert(ctx->value_buf.inuse == true); // should be buffering
- _value_buf_append(ctx, ctx->input_buf_ptr-1, 1); // append "\"
- } else {
- // Okay, this is an escape prefix. Move to buffering value.
- if (ctx->value_buf.inuse == 0) {
- _value_buf_append(ctx,
- ctx->input_buf_value_start,
- // any data before the "\":
- (ctx->input_buf_ptr-1 - ctx->input_buf_value_start) );
- }
- }
- } else {
- // Any byte except '\'
-
- if (prev_b == '\\') {
- // Currently just after an escape character
- assert(ctx->value_buf.inuse == true); // should be buffering
-
- // JSON specifies a few "magic" characters that have a different
- // meaning than their value:
- switch (b) {
- case 'b':
- _value_buf_append(ctx, (const uint8_t*)"\b", 1);
- break;
- case 'f':
- _value_buf_append(ctx, (const uint8_t*)"\f", 1);
- break;
- case 'n':
- _value_buf_append(ctx, (const uint8_t*)"\n", 1);
- break;
- case 'r':
- _value_buf_append(ctx, (const uint8_t*)"\r", 1);
- break;
- case 't':
- _value_buf_append(ctx, (const uint8_t*)"\t", 1);
- break;
- case 'u': {
- // 4 hex digits should follow
- if (_input_avail(ctx) < 4) {
- _rewind_bytes(ctx,
- ctx->input_buf_ptr - (ctx->input_buf_value_start-1));
- return _set_tok(ctx, JSONT_END);
- }
- unsigned long utf16cp = _hex_str_to_ul(ctx->input_buf_ptr, 4);
- ctx->input_buf_ptr += 4;
- if (utf16cp == ULONG_MAX) {
- ctx->error_info = JSONT_ERRINFO_UNEXPECTED_UNICODE_SEQ;
- return _set_tok(ctx, JSONT_ERR);
- }
-
- uint32_t cp = (uint16_t)(0xffff & utf16cp);
-
- // Is lead surrogate?
- if (cp >= 0xd800u && cp <= 0xdbffu) {
- // TODO: Implement pairs by reading another "\uHHHH"
- ctx->error_info = JSONT_ERRINFO_UNEXPECTED_UNICODE_SEQ;
- return _set_tok(ctx, JSONT_ERR);
- }
-
- // Append UTF-8 byte(s) representing the Unicode codepoint `cp`
- if (cp < 0x80) {
- uint8_t cp8 = ((uint8_t)cp);
- _value_buf_append(ctx, (const uint8_t*)&cp8, 1);
- } else if (cp < 0x800) {
- uint8_t cp8 = (uint8_t)((cp >> 6) | 0xc0);
- _value_buf_append(ctx, (const uint8_t*)&cp8, 1);
- cp8 = (uint8_t)((cp & 0x3f) | 0x80);
- _value_buf_append(ctx, (const uint8_t*)&cp8, 1);
- } else {
- uint8_t cp8 = (uint8_t)((cp >> 12) | 0xe0);
- _value_buf_append(ctx, (const uint8_t*)&cp8, 1);
- cp8 = (uint8_t)(((cp >> 6) & 0x3f) | 0x80);
- _value_buf_append(ctx, (const uint8_t*)&cp8, 1);
- cp8 = (uint8_t)((cp & 0x3f) | 0x80);
- _value_buf_append(ctx, (const uint8_t*)&cp8, 1);
- }
-
- break;
- }
- default: {
- _value_buf_append(ctx, &b, 1);
- break;
- }
- } // switch
-
- } else {
- // Previous character was NOT an escape character
-
- if (b == '"') {
- // Well, this marks the end of a string
- ctx->input_buf_value_end = ctx->input_buf_ptr-1;
- return _set_tok(ctx, _expects_field_name(ctx)
- ? JSONT_FIELD_NAME : JSONT_STRING);
- break;
- } else if (b == 0) {
- // Input buffer ends in the middle of a string
- _rewind_bytes(ctx,
- ctx->input_buf_ptr - (ctx->input_buf_value_start-1));
- return _set_tok(ctx, JSONT_END);
- } else {
- if (ctx->value_buf.inuse) {
- _value_buf_append(ctx, &b, 1);
- }
- }
- }
- }
-
- prev_b = b;
- }
- }
- case ',':
- if ( ctx->curr_tok == JSONT_OBJECT_START
- || ctx->curr_tok == JSONT_ARRAY_START
- || ctx->curr_tok == JSONT_END
- || ctx->curr_tok == JSONT_ERR) {
- if (ctx->curr_tok != JSONT_ERR)
- ctx->error_info = JSONT_ERRINFO_UNEXPECTED_COMMA;
- return _set_tok(ctx, JSONT_ERR);
- }
- _set_tok(ctx, _JSONT_COMMA);
- // read next by simply letting the outer "while" do its thing
- break;
-
- case ':':
- if (ctx->curr_tok != JSONT_FIELD_NAME) {
- ctx->error_info = JSONT_ERRINFO_UNEXPECTED_COLON;
- return _set_tok(ctx, JSONT_ERR);
- }
- // let the outer "while" do its thing
- break;
-
- case ' ': case '\r': case '\n': case '\t':
- // ignore whitespace and let the outer "while" do its thing
- break;
-
- case 0:
- //printf("** %d\n", __LINE__);
- return _set_tok(ctx, JSONT_END);
-
- default:
- if (isdigit((int)b) || b == '+' || b == '-') {
- // We are reading a number
- ctx->input_buf_value_start = ctx->input_buf_ptr-1;
- //uint8_t prev_b = 0;
- bool is_float = false;
- while (1) {
- b = _next_byte(ctx);
- if (b == '.') {
- is_float = true;
- } else if (!isdigit((int)b)) {
- _rewind_one_byte(ctx);
- ctx->input_buf_value_end = ctx->input_buf_ptr;
- return _set_tok(ctx, is_float ? JSONT_NUMBER_FLOAT
- : JSONT_NUMBER_INT);
- } else if (b == 0) {
- // Input buffer ends before we know that the number-value ended
- _rewind_bytes(ctx, ctx->input_buf_ptr
- - (ctx->input_buf_value_start-1));
- return _set_tok(ctx, JSONT_END);
- }
- }
- }
-
- ctx->error_info = JSONT_ERRINFO_UNEXPECTED;
- return _set_tok(ctx, JSONT_ERR);
- }
- } // while (1)
-}
-
diff --git a/third_party/jsont/jsont.cc b/third_party/jsont/jsont.cc
deleted file mode 100644
index 09b1e45..0000000
--- a/third_party/jsont/jsont.cc
+++ /dev/null
@@ -1,561 +0,0 @@
-#include "jsont.hh"
-
-namespace jsont {
-
-static const int8_t kHexValueTable[55] = {
- 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, // 0-0
- -1, -1, -1, -1, -1, -1, -1,
- 10, 11, 12, 13, 14, 15, // A-F
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1,
- 10, 11, 12, 13, 14, 15 // a-f
-};
-
-static uint64_t _xtou64(const uint8_t* bytes, size_t len) {
- uint64_t value = 0;
- uint64_t cutoff = UINT64_MAX / 16;
- int cutoff_digit = (int)(UINT64_MAX - cutoff * 16);
-
- for (size_t i = 0; i != len; ++i) {
- uint8_t b = bytes[i];
- int8_t digit = (b > '0'-1 && b < 'f'+1) ? kHexValueTable[b-'0'] : -1;
- if (b == -1 || // bad digit
- (value > cutoff) || // overflow
- ((value == cutoff) && (digit > cutoff_digit)) ) {
- return UINT64_MAX;
- } else {
- value = (value * 16) + digit;
- }
- }
-
- return value;
-}
-
-
-#ifdef NAN
- #define _JSONT_NAN NAN
-#else
- #define _JSONT_NAN nan(0)
-#endif
-
-
-const char* token_name(jsont::Token tok) {
- switch (tok) {
- case End: return "End";
- case ObjectStart: return "ObjectStart";
- case ObjectEnd: return "ObjectEnd";
- case ArrayStart: return "ArrayStart";
- case ArrayEnd: return "ArrayEnd";
- case True: return "True";
- case False: return "False";
- case Null: return "Null";
- case Integer: return "Integer";
- case Float: return "Float";
- case String: return "String";
- case FieldName: return "FieldName";
- default: return "?";
- }
-}
-
-
-class TokenizerInternal {
-public:
- inline static const uint8_t* currentInput(const Tokenizer& self) {
- return self._input.bytes + self._input.offset;
- }
-
- inline static const Token& readAtom(Tokenizer& self, const char* str,
- size_t len, const Token& token) {
- if (self.availableInput() < len) {
- return self.setError(Tokenizer::PrematureEndOfInput);
- } else if (memcmp(currentInput(self), str, len) != 0) {
- return self.setError(Tokenizer::InvalidByte);
- } else {
- self._input.offset += len;
- return self.setToken(token);
- }
- }
-};
-
-
-Tokenizer::~Tokenizer() {}
-
-
-void Tokenizer::reset(const char* bytes, size_t length, TextEncoding encoding) {
- assert(encoding == UTF8TextEncoding); // only supported encoding
- _input.bytes = (const uint8_t*)bytes;
- _input.length = length;
- _input.offset = 0;
- _error.code = UnspecifiedError;
- // Advance to first token
- next();
-}
-
-
-const char* Tokenizer::errorMessage() const {
- switch (_error.code) {
- case UnexpectedComma:
- return "Unexpected comma";
- case UnexpectedTrailingComma:
- return "Unexpected trailing comma";
- case InvalidByte:
- return "Invalid input byte";
- case PrematureEndOfInput:
- return "Premature end of input";
- case MalformedUnicodeEscapeSequence:
- return "Malformed Unicode escape sequence";
- case MalformedNumberLiteral:
- return "Malformed number literal";
- case UnterminatedString:
- return "Unterminated string";
- case SyntaxError:
- return "Illegal JSON (syntax error)";
- default:
- return "Unspecified error";
- }
-}
-
-
-size_t Tokenizer::dataValue(const char const** bytes) const {
- if (!hasValue()) { return 0; }
- if (_value.buffered) {
- *bytes = (const char const*)_value.buffer.data();
- return _value.buffer.size();
- } else {
- *bytes = (const char const*)(_input.bytes + _value.offset);
- return _value.length;
- }
-}
-
-
-double Tokenizer::floatValue() const {
- if (!hasValue()) {
- return _token == jsont::True ? 1.0 : 0.0;
- }
-
- const char* bytes;
-
- if (_value.buffered) {
- // edge-case since only happens with string values using escape sequences
- bytes = _value.buffer.c_str();
- } else {
- bytes = (const char*)_input.bytes + _value.offset;
- if (availableInput() == 0) {
- // In this case where the data lies at the edge of the buffer, we can't pass
- // it directly to atof, since there will be no sentinel byte. We are fine
- // with a copy, since this is an edge case (only happens either for broken
- // JSON or when the whole document is just a number).
- char* buf[128];
- if (_value.length > 127) {
- // We are unable to interpret such a large literal in this edge-case
- return _JSONT_NAN;
- }
- memcpy((void*)buf, (const void*)bytes, _value.length);
- buf[_value.length] = '\0';
- return strtod((const char*)buf, (char**)0);
- }
- }
-
- return strtod(bytes, (char**)0);
-}
-
-
-int64_t Tokenizer::intValue() const {
- if (!hasValue()) {
- return _token == jsont::True ? 1LL : 0LL;
- }
-
- const char* bytes;
-
- if (_value.buffered) {
- // edge-case since only happens with string values using escape sequences
- bytes = _value.buffer.c_str();
- } else {
- bytes = (const char*)_input.bytes + _value.offset;
- if (availableInput() == 0) {
- // In this case where the data lies at the edge of the buffer, we can't pass
- // it directly to atof, since there will be no sentinel byte. We are fine
- // with a copy, since this is an edge case (only happens either for broken
- // JSON or when the whole document is just a number).
- char* buf[21];
- if (_value.length > 20) {
- // We are unable to interpret such a large literal in this edge-case
- return 0;
- }
- memcpy((void*)buf, (const void*)bytes, _value.length);
- buf[_value.length] = '\0';
- return strtoll((const char*)buf, (char**)0, 10);
- }
- }
-
- return strtoll(bytes, (char**)0, 10);
-}
-
-
-const Token& Tokenizer::next() {
- //
- // { } [ ] n t f "
- // | | | |
- // | | | +- /[^"]*/ "
- // | | +- a l s e
- // | +- r u e
- // +- u l l
- //
- while (!endOfInput()) {
- uint8_t b = _input.bytes[_input.offset++];
- switch (b) {
- case '{': return setToken(ObjectStart);
- case '}': {
- if (_token == _Comma) { return setError(UnexpectedTrailingComma); }
- return setToken(ObjectEnd);
- }
-
- case '[': return setToken(ArrayStart);
- case ']': {
- if (_token == _Comma) { return setError(UnexpectedTrailingComma); }
- return setToken(ArrayEnd);
- }
-
- case 'n':
- return TokenizerInternal::readAtom(*this, "ull", 3, jsont::Null);
- case 't':
- return TokenizerInternal::readAtom(*this, "rue", 3, jsont::True);
- case 'f':
- return TokenizerInternal::readAtom(*this, "alse", 4, jsont::False);
-
- case ' ': case '\t': case '\r': case '\n': // IETF RFC4627
- // ignore whitespace and let the outer "while" do its thing
- break;
-
- case 0:
- return setError(InvalidByte);
-
- // when we read a value, we don't produce a token until we either reach
- // end of input, a colon (then the value is a field name), a comma, or an
- // array or object terminator.
-
- case '"': {
- _value.beginAtOffset(_input.offset);
-
- while (!endOfInput()) {
- b = _input.bytes[_input.offset++];
- assert(_input.offset < _input.length);
-
- switch (b) {
-
- case '\\': {
- // We must go buffered since the input segment != value
- if (!_value.buffered) {
- _value.buffered = true;
- _value.buffer.assign(
- (const char*)(_input.bytes+_value.offset),
- _input.offset - _value.offset - 1
- );
- }
-
- if (endOfInput()) {
- return setError(PrematureEndOfInput);
- }
-
- b = _input.bytes[_input.offset++];
- switch (b) {
- case 'b': _value.buffer.append(1, '\x08'); break;
- case 'f': _value.buffer.append(1, '\x0C'); break;
- case 'n': _value.buffer.append(1, '\x0A'); break;
- case 'r': _value.buffer.append(1, '\x0D'); break;
- case 't': _value.buffer.append(1, '\x09'); break;
- case 'u': {
- // \uxxxx
- if (availableInput() < 4) {
- return setError(PrematureEndOfInput);
- }
-
- uint64_t utf16cp =
- _xtou64(TokenizerInternal::currentInput(*this), 4);
- _input.offset += 4;
-
- if (utf16cp > 0xffff) {
- return setError(MalformedUnicodeEscapeSequence);
- }
-
- uint16_t cp = (uint16_t)(0xffff & utf16cp);
-
- // Append UTF-8 byte(s) representing the Unicode codepoint cp
- if (cp < 0x80) {
- // U+0000 - U+007F
- uint8_t cp8 = ((uint8_t)cp);
- _value.buffer.append(1, (char)cp8);
- } else if (cp < 0x800) {
- // U+0080 - U+07FF
- uint8_t cp8 = (uint8_t)((cp >> 6) | 0xc0);
- _value.buffer.append(1, (char)cp8);
- cp8 = (uint8_t)((cp & 0x3f) | 0x80);
- _value.buffer.append(1, (char)cp8);
- } else if (cp >= 0xD800u && cp <= 0xDFFFu) {
- // UTF-16 Surrogate pairs -- according to the UTF-8
- // definition (RFC 3629) the high and low surrogate halves
- // used by UTF-16 (U+D800 through U+DFFF) are not legal
- // Unicode values, and the UTF-8 encoding of them is an
- // invalid byte sequence. Instead of throwing an error, we
- // substitute this character with the replacement character
- // U+FFFD (UTF-8: EF,BF,BD).
- _value.buffer.append("\xEF\xBF\xBD");
- //
- } else {
- // U+0800 - U+FFFF
- uint8_t cp8 = (uint8_t)((cp >> 12) | 0xe0);
- _value.buffer.append(1, (char)cp8);
- cp8 = (uint8_t)(((cp >> 6) & 0x3f) | 0x80);
- _value.buffer.append(1, (char)cp8);
- cp8 = (uint8_t)((cp & 0x3f) | 0x80);
- _value.buffer.append(1, (char)cp8);
- }
-
- break;
- }
- default:
- _value.buffer.append(1, (char)b); break;
- }
- break;
- }
-
- case '"':
- goto after_initial_read_b;
-
- case 0:
- return setError(InvalidByte);
-
- default: {
- if (_value.buffered) {
- // TODO: Make this efficient by appending chunks between
- // boundaries instead of appending per-byte
- _value.buffer.append(1, (char)b);
- }
- break;
- }
- } // switch(b)
- } // while (!endOfInput())
-
- after_initial_read_b:
- if (b != '"') {
- return setError(UnterminatedString);
- }
-
- if (!_value.buffered) {
- _value.length = _input.offset - _value.offset - 1;
- }
-
- // is this a field name?
- while (!endOfInput()) {
- b = _input.bytes[_input.offset++];
- switch (b) {
- case ' ': case '\t': case '\r': case '\n': break;
- case ':': return setToken(FieldName);
- case ',': goto string_read_return_string;
- case ']': case '}': {
- --_input.offset; // rewind
- goto string_read_return_string;
- }
- case 0: return setError(InvalidByte);
- default: {
- // Expected a comma or a colon
- return setError(SyntaxError);
- }
- }
- }
-
- string_read_return_string:
- return setToken(jsont::String);
- }
-
- case ',': {
- if (_token == ObjectStart || _token == ArrayStart || _token == _Comma) {
- return setError(UnexpectedComma);
- }
- _token = _Comma;
- break;
- }
-
- default: {
- if (isdigit((int)b) || b == '+' || b == '-') {
- // We are reading a number
- _value.beginAtOffset(_input.offset-1);
- Token token = jsont::Integer;
-
- while (!endOfInput()) {
- b = _input.bytes[_input.offset++];
- switch (b) {
- case '0'...'9': break;
- case '.': token = jsont::Float; break;
- case 'E': case 'e': case '-': case '+': {
- if (token != jsont::Float) {
- return setError(MalformedNumberLiteral);
- }
- break;
- }
- default: {
- if ( (_input.offset - _value.offset == 1) &&
- (_input.bytes[_value.offset] == '-' ||
- _input.bytes[_value.offset] == '+') ) {
- return setError(MalformedNumberLiteral);
- }
-
- // rewind the byte that terminated this number literal
- --_input.offset;
-
- _value.length = _input.offset - _value.offset - 1;
- return setToken(token);
- }
- }
- }
- return setToken(End);
- } else {
- return setError(InvalidByte);
- }
- }
- }
- }
-
- return setToken(End);
-}
-
-
-enum {
- kUTF8ByteVerbatim = 0,
- kUTF8ByteEncode1, // "\u000x"
- kUTF8ByteEncode2, // "\u00xx"
-};
-#define V kUTF8ByteVerbatim
-#define E1 kUTF8ByteEncode1
-#define E2 kUTF8ByteEncode2
-static const uint8_t kUTF8ByteTable[256] = {
- E1, E1, E1, E1, E1, E1, E1, E1, 'b', 't', 'n', E1, 'f', 'r', E1, E1, E2, E2,
- E2, E2, E2, E2, E2, E2, E2, E2, E2, E2, E2, E2, E2, E2, V, V, '"', V, V, V, V,
- V, V, V, V, V, V, V, V, V, V, V, V, V, V, V, V, V, V, V, V, V, V, V, V, V, V,
- V, V, V, V, V, V, V, V, V, V, V, V, V, V, V, V, V, V, V, V, V, V, V, V, V, V,
- V, '\\', V, V, V, V, V, V, V, V, V, V, V, V, V, V, V, V, V, V, V, V, V, V, V,
- V, V, V, V, V, V, V, V, V, V, V, E2, V, V, V, V, V, V, V, V, V, V, V, V, V, V,
- V, V, V, V, V, V, V, V, V, V, V, V, V, V, V, V, V, V, V, V, V, V, V, V, V, V,
- V, V, V, V, V, V, V, V, V, V, V, V, V, V, V, V, V, V, V, V, V, V, V, V, V, V,
- V, V, V, V, V, V, V, V, V, V, V, V, V, V, V, V, V, V, V, V, V, V, V, V, V, V,
- V, V, V, V, V, V, V, V, V, V, V, V, V, V, V, V, V, V, V, V, V, V, V, V, V, V,
- V, V, V, V, V, V, V, V, V, V
-};
-#undef V
-#undef E1
-#undef E2
-
-// #ifndef __has_feature
-// #define __has_feature(x) 0
-// #endif
-// #if defined(__cplusplus) && __has_feature(cxx_static_assert)
-// #define JSONT_CONST_ASSERT(expr, error_msg) static_assert((expr), (error_msg))
-// #elif __has_feature(c_static_assert)
-// #define JSONT_CONST_ASSERT(expr, error_msg) _Static_assert((expr), (error_msg))
-// #else
-// #define JSONT_CONST_ASSERT(expr, error_msg) ((void)0)
-// #endif
-
-Builder& Builder::appendString(const uint8_t* v, size_t length, TextEncoding encoding) {
- reserve(length + 2);
- _buf[_size++] = '"';
-
- assert(encoding == UTF8TextEncoding /* Currently only UTF-8 is supported */);
-
- const uint8_t* end = v+length;
- while (v != end) {
- uint8_t s = kUTF8ByteTable[*v];
- switch (s) {
- case kUTF8ByteVerbatim:
- _buf[_size++] = *v;
- break;
- case kUTF8ByteEncode1: {
- assert(*v < 16);
- size_t remainingSize = end-v+1+5; // five additional bytes needed
- reserve(remainingSize);
- _buf[_size] = '\\';
- _buf[++_size] = 'u';
- _buf[++_size] = '0';
- _buf[++_size] = '0';
- _buf[++_size] = '0';
- _buf[++_size] = *v + (*v > 10 ? 55 : 48); // A-F : 0-9
- ++_size;
- assert(_size <= _capacity);
- break;
- }
- case kUTF8ByteEncode2: {
- // Note: *v is guaranteed to be within the set [16,32),127. This is
- // an affect of the kUTF8ByteTable lookup table and this code needs to
- // be revised if the lookup table adds or removes any kUTF8ByteEncode.
- assert((*v > 15 && *v < 32) || *v == 127);
- size_t remainingSize = end-v+1+5; // five additional bytes needed
- reserve(remainingSize);
- _buf[_size] = '\\';
- _buf[++_size] = 'u';
- _buf[++_size] = '0';
- _buf[++_size] = '0';
- uint8_t b1 = (*v & 0xf0) / 16;
- //uint8_t b1 = (*v & 0xf0) >> 4; // slightly faster but LE-specific
- uint8_t b2 = *v & 0x0f;
- _buf[++_size] = b1 + (b1 > 10 ? 55 : 48); // A-F : 0-9
- _buf[++_size] = b2 + (b2 > 10 ? 55 : 48); // A-F : 0-9
- ++_size;
- assert(_size <= _capacity);
- break;
- }
- default:
- // reverse solidus escape
- size_t remainingSize = end-v+1+1; // one additional byte needed
- reserve(remainingSize);
- _buf[_size++] = '\\';
- _buf[_size++] = s;
- assert(_size <= _capacity);
- break;
- }
-
- ++v;
- }
-
- _buf[_size++] = '"';
- assert(_size <= _capacity);
- return *this;
-}
-
-#if JSONT_CXX_RVALUE_REFS
- // Move constructor and assignment operator
- Builder::Builder(Builder&& other)
- : _buf(other._buf)
- , _capacity(other._capacity)
- , _size(other._size)
- , _state(other._state) {
- other._buf = 0;
- }
-
- Builder& Builder::operator=(Builder&& other) {
- _buf = other._buf; other._buf = 0;
- _capacity = other._capacity;
- _size = other._size;
- _state = other._state;
- return *this;
- }
-#endif
-
-Builder::Builder(const Builder& other)
- : _buf(0)
- , _capacity(other._capacity)
- , _size(other._size)
- , _state(other._state) {
- _buf = (char*)malloc(_capacity);
- memcpy((void*)_buf, (const void*)other._buf, _size);
-}
-
-Builder& Builder::operator=(const Builder& other) {
- _capacity = other._capacity;
- _size = other._size;
- _state = other._state;
- _buf = (char*)malloc(_capacity);
- memcpy((void*)_buf, (const void*)other._buf, _size);
- return *this;
-}
-
-} // namespace jsont
diff --git a/third_party/jsont/jsont.h b/third_party/jsont/jsont.h
deleted file mode 100644
index 22cd043..0000000
--- a/third_party/jsont/jsont.h
+++ /dev/null
@@ -1,114 +0,0 @@
-// JSON Tokenizer. Copyright (c) 2012, Rasmus Andersson. All rights reserved.
-// Use of this source code is governed by a MIT-style license that can be
-// found in the LICENSE file.
-#ifndef JSONT_INCLUDED
-#define JSONT_INCLUDED
-
-#include <stdint.h> // uint8_t, int64_t
-#include <stdlib.h> // size_t
-#include <string.h> // strlen
-#include <stdbool.h> // bool
-
-#ifndef _JSONT_IN_SOURCE
-typedef struct jsont_ctx jsont_ctx_t;
-typedef uint8_t jsont_tok_t;
-#endif
-
-#ifndef JSONT_ERRINFO_CUSTOM
-#define jsont_err_t const char*
-#endif
-
-// Token types
-enum {
- JSONT_END = 0, // Input ended
- JSONT_ERR, // Error
-
- JSONT_OBJECT_START, // {
- JSONT_OBJECT_END, // }
-
- JSONT_ARRAY_START, // [
- JSONT_ARRAY_END, // ]
-
- JSONT_TRUE, // true
- JSONT_FALSE, // false
- JSONT_NULL, // null
-
- _JSONT_VALUES_START,
- JSONT_NUMBER_INT, // number value without a fraction part
- JSONT_NUMBER_FLOAT, // number value with a fraction part
- JSONT_STRING, // string value
- JSONT_FIELD_NAME, // field name
- _JSONT_VALUES_END,
-
- _JSONT_COMMA,
-};
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-// Create a new JSON tokenizer context. `user_data` can be anything and is
-// accessible through `jsont_user_data`.
-jsont_ctx_t* jsont_create(void* user_data);
-
-// Destroy a JSON tokenizer context. This will free any internal data, except
-// from the input buffer.
-void jsont_destroy(jsont_ctx_t* ctx);
-
-// Reset the tokenizer to parse the data pointed to by `bytes`. The tokenizer
-// does NOT take ownership of `bytes`. This function can be used to recycle a
-// tokenizer context, minimizing memory reallocation.
-void jsont_reset(jsont_ctx_t* ctx, const uint8_t* bytes, size_t length);
-
-// Read and return the next token. See `jsont_tok_t` enum for a list of
-// possible return values and their meaning.
-jsont_tok_t jsont_next(jsont_ctx_t* ctx);
-
-// Returns the current token (last token read by `jsont_next`).
-jsont_tok_t jsont_current(const jsont_ctx_t* ctx);
-
-// Returns a slice of the input which represents the current value, or nothing
-// (returns 0) if the current token has no value (e.g. start of an object).
-size_t jsont_data_value(jsont_ctx_t* ctx, const uint8_t** bytes);
-
-// Returns true if the current data value is equal to `bytes` of `length`
-bool jsont_data_equals(jsont_ctx_t* ctx, const uint8_t* bytes, size_t length);
-
-// Returns true if the current data value is equal to c string `str`
-static inline bool jsont_str_equals(jsont_ctx_t* ctx, const char* str) {
- return jsont_data_equals(ctx, (const uint8_t*)str, strlen(str));
-}
-
-// Retrieve a newly allocated c-string. Similar to `jsont_data_value` but
-// returns a newly allocated copy of the current value as a C string
-// (terminated by a null byte). The calling code is responsible for calling
-// `free()` on the returned value.
-char* jsont_strcpy_value(jsont_ctx_t* ctx);
-
-// Returns the current integer value.If the number is too large or too small,
-// this function sets errno and returns INT64_MAX or INT64_MIN.
-int64_t jsont_int_value(jsont_ctx_t* ctx);
-
-// Returns the current floating-point number value. Sets errno and returns a
-// value that isnan(N)==true on error.
-double jsont_float_value(jsont_ctx_t* ctx);
-
-// Get the last byte read. Suitable for debugging JSONT_ERR.
-uint8_t jsont_current_byte(jsont_ctx_t* ctx);
-
-// Get the current offset of the last byte read.
-size_t jsont_current_offset(jsont_ctx_t* ctx);
-
-// Get information on the last error (by default a printable text message).
-// Returns NULL if no error has occured since a call to `jsont_reset`.
-jsont_err_t jsont_error_info(jsont_ctx_t* ctx);
-
-// Returns the value passed to `jsont_create`.
-void* jsont_user_data(const jsont_ctx_t* ctx);
-
-// ----------------- C++ -----------------
-#ifdef __cplusplus
-} // extern "C"
-#endif
-
-#endif // JSONT_INCLUDED
diff --git a/third_party/jsont/jsont.hh b/third_party/jsont/jsont.hh
deleted file mode 100644
index 3e86cad..0000000
--- a/third_party/jsont/jsont.hh
+++ /dev/null
@@ -1,420 +0,0 @@
-// JSON Tokenizer and builder. Copyright (c) 2012, Rasmus Andersson. All rights
-// reserved. Use of this source code is governed by a MIT-style license that can
-// be found in the LICENSE file.
-#ifndef JSONT_CXX_INCLUDED
-#define JSONT_CXX_INCLUDED
-
-#include <stdint.h> // uint8_t, int64_t
-#include <stdlib.h> // size_t
-#include <string.h> // strlen
-#include <stdbool.h> // bool
-#include <math.h>
-#include <assert.h>
-#include <string>
-#include <stdexcept>
-
-// Can haz rvalue references with move semantics?
-#if (defined(_MSC_VER) && _MSC_VER >= 1600) || \
- (defined(__GXX_EXPERIMENTAL_CXX0X__) && __GXX_EXPERIMENTAL_CXX0X__) || \
- (defined(__has_feature) && __has_feature(cxx_rvalue_references))
- #define JSONT_CXX_RVALUE_REFS 1
-#else
- #define JSONT_CXX_RVALUE_REFS 0
-#endif
-
-namespace jsont {
-
-// Tokens
-typedef enum {
- End = 0, // Input ended
- ObjectStart, // {
- ObjectEnd, // }
- ArrayStart, // [
- ArrayEnd, // ]
- True, // true
- False, // false
- Null, // null
- Integer, // number value without a fraction part
- Float, // number value with a fraction part
- String, // string value
- FieldName, // field name
- Error, // An error occured (see `error()` for details)
- _Comma,
-} Token;
-
-// String encoding
-typedef enum {
- UTF8TextEncoding = 0,
-} TextEncoding;
-
-// Name of `token`
-const char* token_name(jsont::Token token);
-
-class TokenizerInternal;
-
-// Reads a sequence of bytes and produces tokens and values while doing so
-class Tokenizer {
-public:
- Tokenizer(const char* bytes, size_t length, TextEncoding encoding);
- ~Tokenizer();
-
- // Read next token
- const Token& next();
-
- // Access current token
- const Token& current() const;
-
- // Reset the tokenizer, making it possible to reuse this parser so to avoid
- // unnecessary memory allocation and deallocation.
- void reset(const char* bytes, size_t length, TextEncoding encoding);
-
- // True if the current token has a value
- bool hasValue() const;
-
- // Returns a slice of the input which represents the current value, or nothing
- // (returns 0) if the current token has no value (e.g. start of an object).
- size_t dataValue(const char const** bytes) const;
-
- // Returns a *copy* of the current string value.
- std::string stringValue() const;
-
- // Returns the current value as a double-precision floating-point number.
- double floatValue() const;
-
- // Returns the current value as a signed 64-bit integer.
- int64_t intValue() const;
-
- // Returns the current value as a boolean
- bool boolValue() const;
-
- // Error codes
- typedef enum {
- UnspecifiedError = 0,
- UnexpectedComma,
- UnexpectedTrailingComma,
- InvalidByte,
- PrematureEndOfInput,
- MalformedUnicodeEscapeSequence,
- MalformedNumberLiteral,
- UnterminatedString,
- SyntaxError,
- } ErrorCode;
-
- // Returns the error code of the last error
- ErrorCode error() const;
-
- // Returns a human-readable message for the last error. Never returns NULL.
- const char* errorMessage() const;
-
- // The byte offset into input where the tokenizer is currently looking. In the
- // event of an error, this will point to the source of the error.
- size_t inputOffset() const;
-
- // Total number of input bytes
- size_t inputSize() const;
-
- // A pointer to the input data as passed to `reset` or the constructor.
- const char* inputBytes() const;
-
- friend class TokenizerInternal;
-private:
- size_t availableInput() const;
- size_t endOfInput() const;
- const Token& setToken(Token t);
- const Token& setError(ErrorCode error);
-
- struct {
- const uint8_t* bytes;
- size_t length;
- size_t offset;
- } _input;
- struct Value {
- Value() : offset(0), length(0), buffered(false) {}
- void beginAtOffset(size_t z);
- size_t offset; // into _input.bytes
- size_t length;
- std::string buffer;
- bool buffered; // if true, contents lives in buffer
- } _value;
- Token _token;
- struct {
- ErrorCode code;
- } _error;
-};
-
-
-// Helps in building JSON, providing a final sequential byte buffer
-class Builder {
-public:
- Builder() : _buf(0), _capacity(0), _size(0), _state(NeutralState) {}
- ~Builder() { if (_buf) { free(_buf); _buf = 0; } }
- Builder(const Builder& other);
- Builder& operator=(const Builder& other);
-#if JSONT_CXX_RVALUE_REFS
- Builder(Builder&& other);
- Builder& operator=(Builder&& other);
-#endif
-
- Builder& startObject();
- Builder& endObject();
- Builder& startArray();
- Builder& endArray();
- Builder& fieldName(const char* v, size_t length, TextEncoding e=UTF8TextEncoding);
- Builder& fieldName(const std::string& name, TextEncoding enc=UTF8TextEncoding);
- Builder& value(const char* v, size_t length, TextEncoding e=UTF8TextEncoding);
- Builder& value(const char* v);
- Builder& value(const std::string& v);
- Builder& value(double v);
- Builder& value(int64_t v);
- Builder& value(int v);
- Builder& value(unsigned int v);
- Builder& value(long v);
- Builder& value(bool v);
- Builder& nullValue();
-
- size_t size() const;
- const char* bytes() const;
- std::string toString() const;
- const char* seizeBytes(size_t& size_out);
- const void reset();
-
-private:
- size_t available() const;
- void reserve(size_t size);
- void prefix();
- Builder& appendString(const uint8_t* v, size_t length, TextEncoding enc);
- Builder& appendChar(char byte);
-
- char* _buf;
- size_t _capacity;
- size_t _size;
- enum {
- NeutralState = 0,
- AfterFieldName,
- AfterValue,
- AfterObjectStart,
- AfterArrayStart,
- } _state;
-};
-
-
-// Convenience function
-inline Builder build() { return Builder(); }
-
-
-// ------------------- internal ---------------------
-
-inline Tokenizer::Tokenizer(const char* bytes, size_t length,
- TextEncoding encoding) : _token(End) {
- reset(bytes, length, encoding);
-}
-
-inline const Token& Tokenizer::current() const { return _token; }
-
-inline bool Tokenizer::hasValue() const {
- return _token >= Integer && _token <= FieldName;
-}
-
-inline std::string Tokenizer::stringValue() const {
- const char* bytes;
- size_t size = dataValue(&bytes);
- return std::string(bytes, size);
-}
-
-inline bool Tokenizer::boolValue() const {
- return _token == True;
-}
-
-inline size_t Tokenizer::availableInput() const {
- return _input.length - _input.offset;
-}
-inline size_t Tokenizer::endOfInput() const {
- return _input.offset == _input.length;
-}
-inline const Token& Tokenizer::setToken(Token t) {
- return _token = t;
-}
-inline const Token& Tokenizer::setError(Tokenizer::ErrorCode error) {
- _error.code = error;
- return _token = Error;
-}
-inline size_t Tokenizer::inputOffset() const {
- return _input.offset;
-}
-inline size_t Tokenizer::inputSize() const {
- return _input.length;
-}
-inline const char* Tokenizer::inputBytes() const {
- return (const char*)_input.bytes;
-}
-
-inline void Tokenizer::Value::beginAtOffset(size_t z) {
- offset = z;
- length = 0;
- buffered = false;
-}
-
-inline Tokenizer::ErrorCode Tokenizer::error() const {
- return _error.code;
-}
-
-
-inline Builder& Builder::startObject() {
- prefix();
- _state = AfterObjectStart;
- return appendChar('{');
-}
-
-inline Builder& Builder::endObject() {
- _state = AfterValue;
- return appendChar('}');
-}
-
-inline Builder& Builder::startArray() {
- prefix();
- _state = AfterArrayStart;
- return appendChar('[');
-}
-
-inline Builder& Builder::endArray() {
- _state = AfterValue;
- return appendChar(']');
-}
-
-inline Builder& Builder::fieldName(const std::string& name, TextEncoding enc) {
- return fieldName(name.data(), name.size(), enc);
-}
-
-inline Builder& Builder::fieldName(const char* v, size_t length,
- TextEncoding enc) {
- prefix();
- _state = AfterFieldName;
- return appendString((const uint8_t*)v, length, enc);
-}
-
-inline Builder& Builder::value(const char* v, size_t length, TextEncoding enc) {
- prefix();
- _state = AfterValue;
- return appendString((const uint8_t*)v, length, enc);
-}
-
-inline Builder& Builder::value(const char* v) {
- return value(v, strlen(v));
-}
-
-inline Builder& Builder::value(const std::string& v) {
- return value(v.data(), v.size());
-}
-
-inline Builder& Builder::value(double v) {
- prefix();
- reserve(256);
- int z = snprintf(_buf+_size, 256, "%g", v);
- assert(z < 256);
- _size += z;
- _state = AfterValue;
- return *this;
-}
-
-inline Builder& Builder::value(int64_t v) {
- prefix();
- reserve(21);
- int z = snprintf(_buf+_size, 21, "%lld", v);
- assert(z < 21);
- _size += z;
- _state = AfterValue;
- return *this;
-}
-
-inline Builder& Builder::value(int v) { return value((int64_t)v); }
-inline Builder& Builder::value(unsigned int v) { return value((int64_t)v); }
-inline Builder& Builder::value(long v) { return value((int64_t)v); }
-
-inline Builder& Builder::value(bool v) {
- prefix();
- if (v) {
- reserve(4);
- _buf[_size] = 't';
- _buf[++_size] = 'r';
- _buf[++_size] = 'u';
- _buf[++_size] = 'e';
- ++_size;
- } else {
- reserve(5);
- _buf[_size] = 'f';
- _buf[++_size] = 'a';
- _buf[++_size] = 'l';
- _buf[++_size] = 's';
- _buf[++_size] = 'e';
- ++_size;
- }
- _state = AfterValue;
- return *this;
-}
-
-inline Builder& Builder::nullValue() {
- prefix();
- reserve(4);
- _buf[_size] = 'n';
- _buf[++_size] = 'u';
- _buf[++_size] = 'l';
- _buf[++_size] = 'l';
- ++_size;
- _state = AfterValue;
- return *this;
-}
-
-inline size_t Builder::size() const { return _size; }
-inline const char* Builder::bytes() const { return _buf; }
-inline std::string Builder::toString() const {
- return std::string(bytes(), size());
-}
-inline const char* Builder::seizeBytes(size_t& size_out) {
- const char* buf = _buf;
- size_out = _size;
- _buf = 0;
- _capacity = 0;
- reset();
- return buf;
-}
-inline const void Builder::reset() {
- _size = 0;
- _state = NeutralState;
-}
-
-inline size_t Builder::available() const {
- return _capacity - _size;
-}
-
-inline void Builder::reserve(size_t size) {
- if (available() < size) {
- #if 0
- // exact allocation for debugging purposes
- printf("DEBUG Builder::reserve: size=%zu available=%zu grow_by=%zu\n",
- size, available(), (size - available()) );
- _capacity += size - available();
- #else
- _capacity += size - available();
- _capacity = (_capacity < 64) ? 64 : (_capacity * 1.5);
- #endif
- _buf = (char*)realloc((void*)_buf, _capacity);
- }
-}
-
-inline void Builder::prefix() {
- if (_state == AfterFieldName) {
- appendChar(':');
- } else if (_state == AfterValue) {
- appendChar(',');
- }
-}
-
-inline Builder& Builder::appendChar(char byte) {
- reserve(1);
- _buf[_size++] = byte;
- return *this;
-}
-
-}
-
-#endif // JSONT_CXX_INCLUDED
diff --git a/third_party/jsont/test/test_tokenizer.c b/third_party/jsont/test/test_tokenizer.c
deleted file mode 100644
index f994c85..0000000
--- a/third_party/jsont/test/test_tokenizer.c
+++ /dev/null
@@ -1,180 +0,0 @@
-#include <jsont.h>
-#include <stdio.h>
-#include <string.h>
-#include <assert.h>
-#include <math.h>
-
-#define JSONT_ASSERT_FIELD_NAME(fieldName) do { \
- assert(jsont_current(S) == JSONT_FIELD_NAME); \
- assert(jsont_data_equals(S, (const uint8_t*)fieldName, \
- strlen(fieldName)) == true); \
-} while(0)
-
-int main(int argc, const char** argv) {
- // Create a new reusable tokenizer
- jsont_ctx_t* S = jsont_create(0);
-
- const char* inbuf = "{ "
- "\"\\\"fo\\\"o\": \"Foo\"," // "\"fo\"o": "Foo"
- "\"1\" : \"\\u2192\","
- "\"n\":1234,"
- "\"x\" : \t 12.34,"
- "\"overflow\" : \t 9999999999999999999999999999999999,"
- "\"b\\/a\\/r\":["
- "null,"
- "true,"
- "false,"
- "{"
- "\"x\":12.3"
- "},"
- "\n123,"
- "\"456\","
- "\"a\\\"b\\\"\","
- "\"a\\u0000b\","
- "\"a\\bb\","
- "\"a\\fb\","
- "\"a\\nb\","
- "\"a\\rb\","
- "\"a\\tb\","
- "\"\","
- "\" \""
- "]"
- "}";
-
- jsont_reset(S, (const uint8_t*)inbuf, strlen(inbuf));
- jsont_tok_t tok;
-
- tok = jsont_next(S);
- assert(tok == JSONT_OBJECT_START);
- assert(jsont_current(S) == JSONT_OBJECT_START);
-
- tok = jsont_next(S);
- assert(tok == JSONT_FIELD_NAME);
-
- // Expect current data to be the bytes '"fo"o'
- const char* expectedData = "\"fo\"o";
- const uint8_t* bytes;
- size_t size = jsont_data_value(S, &bytes);
- size_t expectedSize = strlen(expectedData);
- // printf("expectedData: '%s'\n", expectedData);
- // printf("currentData: '%.*s'\n", (int)size, (const char*)bytes);
- assert(size == expectedSize);
- int d = memcmp((const void*)expectedData, bytes, size);
- assert(d == 0);
-
- // Expect a string value "Foo"
- tok = jsont_next(S);
- assert(tok == JSONT_STRING);
- char* str = jsont_strcpy_value(S);
- assert(str != 0);
- assert(strcmp(str, "Foo") == 0);
- free(str); str = 0;
-
- // Expect field name "1". Also tests the integrity of jsont_data_equals
- tok = jsont_next(S);
- assert(jsont_data_equals(S, (const uint8_t*)"1", 1) == true);
- assert(jsont_str_equals(S, "1") == true);
- size = jsont_data_value(S, &bytes);
- assert(size == 1);
- assert(memcmp((const void*)"1", (const void*)bytes, 1) == 0);
-
- // Expect the string '\u2192' (RIGHTWARDS ARROW, UTF8: E2,86,92)
- assert(jsont_next(S) == JSONT_STRING);
- assert(jsont_str_equals(S, "\xe2\x86\x92") == true);
-
- // Expect a field name 'n'
- jsont_next(S);
- JSONT_ASSERT_FIELD_NAME("n");
-
- // Expect a number value '1234'
- assert(jsont_next(S) == JSONT_NUMBER_INT);
- //printf("int: %lld (str: '%s')\n", jsont_int_value(S), jsont_strcpy_value(S));
- assert(jsont_int_value(S) == 1234LL);
- assert(jsont_float_value(S) == 1234.0);
-
- // Expect a field name 'x'
- jsont_next(S);
- JSONT_ASSERT_FIELD_NAME("x");
-
- // Expect a number value '12.34'
- assert(jsont_next(S) == JSONT_NUMBER_FLOAT);
- assert(jsont_float_value(S) == 12.34);
- assert(jsont_int_value(S) == 12LL); // partial expected
-
- jsont_next(S);
- JSONT_ASSERT_FIELD_NAME("overflow");
-
- // Expect a cut-off integer value of INT64_MAX
- assert(jsont_next(S) == JSONT_NUMBER_INT);
- assert(jsont_int_value(S) == INT64_MAX);
-
- // Expect a valid floating point value (although it will have less-than
- // perfect precision)
- assert(!isnan(jsont_float_value(S)));
-
- // Expect a field name 'bar'
- jsont_next(S);
- JSONT_ASSERT_FIELD_NAME("b/a/r");
-
- // Expect start of array
- assert(jsont_next(S) == JSONT_ARRAY_START);
-
- // Expect null, true and false
- assert(jsont_next(S) == JSONT_NULL);
- assert(jsont_next(S) == JSONT_TRUE);
- assert(jsont_next(S) == JSONT_FALSE);
-
- // { "x": 12.3 }
- assert(jsont_next(S) == JSONT_OBJECT_START);
- jsont_next(S);
- JSONT_ASSERT_FIELD_NAME("x");
- assert(jsont_next(S) == JSONT_NUMBER_FLOAT);
- assert(jsont_float_value(S) == 12.3);
- assert(jsont_next(S) == JSONT_OBJECT_END);
-
- // 123, "456", "a\"b\""
- assert(jsont_next(S) == JSONT_NUMBER_INT);
- assert(jsont_int_value(S) == 123);
-
- assert(jsont_next(S) == JSONT_STRING);
- assert(jsont_str_equals(S, "456") == true);
-
- assert(jsont_next(S) == JSONT_STRING);
- assert(jsont_str_equals(S, "a\"b\"") == true);
-
- // "a\u0000b"
- assert(jsont_next(S) == JSONT_STRING);
- const uint8_t b3[] = {'a',0,'b'};
- assert(jsont_data_equals(S, b3, sizeof(b3)) == true);
-
- // "a\{b,f,n,r,t}b"
- assert(jsont_next(S) == JSONT_STRING);
- assert(jsont_str_equals(S, "a\bb") == true);
- assert(jsont_next(S) == JSONT_STRING);
- assert(jsont_str_equals(S, "a\fb") == true);
- assert(jsont_next(S) == JSONT_STRING);
- assert(jsont_str_equals(S, "a\nb") == true);
- assert(jsont_next(S) == JSONT_STRING);
- assert(jsont_str_equals(S, "a\rb") == true);
- assert(jsont_next(S) == JSONT_STRING);
- assert(jsont_str_equals(S, "a\tb") == true);
-
- // ""
- assert(jsont_next(S) == JSONT_STRING);
- assert(jsont_str_equals(S, "") == true);
- assert(jsont_str_equals(S, " ") == false);
-
- // " "
- assert(jsont_next(S) == JSONT_STRING);
- assert(jsont_str_equals(S, " ") == true);
- assert(jsont_str_equals(S, "") == false);
-
- // ] }
- assert(jsont_next(S) == JSONT_ARRAY_END);
- assert(jsont_next(S) == JSONT_OBJECT_END);
-
-
- jsont_destroy(S);
- printf("PASS\n");
- return 0;
-}