Minimal JSON parser

Dependents:   WNCInterface_M2XMQTTdemo

Committer:
defmacro
Date:
Mon Jun 27 13:14:48 2016 +0000
Revision:
1:0429411f7b3a
Parent:
0:aa8ded7b33eb
Add license file

Who changed what in which revision?

UserRevisionLine numberNew contents of line
defmacro 0:aa8ded7b33eb 1 #ifndef MJSON_H_
defmacro 0:aa8ded7b33eb 2 #define MJSON_H_
defmacro 0:aa8ded7b33eb 3
defmacro 0:aa8ded7b33eb 4 #include <stdint.h>
defmacro 0:aa8ded7b33eb 5 #ifndef min
defmacro 0:aa8ded7b33eb 6 #define min(a, b) ((a) > (b) ? (b) : (a))
defmacro 0:aa8ded7b33eb 7 #endif /* min */
defmacro 0:aa8ded7b33eb 8
defmacro 0:aa8ded7b33eb 9 #define MJSON_TYPE_NULL 1
defmacro 0:aa8ded7b33eb 10 #define MJSON_TYPE_TRUE 2
defmacro 0:aa8ded7b33eb 11 #define MJSON_TYPE_FALSE 3
defmacro 0:aa8ded7b33eb 12 #define MJSON_TYPE_STRING 4
defmacro 0:aa8ded7b33eb 13 #define MJSON_TYPE_NUMBER 5
defmacro 0:aa8ded7b33eb 14 #define MJSON_TYPE_OBJECT 6
defmacro 0:aa8ded7b33eb 15 #define MJSON_TYPE_ARRAY 7
defmacro 0:aa8ded7b33eb 16
defmacro 0:aa8ded7b33eb 17 #define MJSON_SUBTYPE_OBJECT_SEPARATOR 8
defmacro 0:aa8ded7b33eb 18 #define MJSON_SUBTYPE_OBJECT_END 9
defmacro 0:aa8ded7b33eb 19 #define MJSON_SUBTYPE_ARRAY_SEPARATOR 10
defmacro 0:aa8ded7b33eb 20 #define MJSON_SUBTYPE_ARRAY_END 11
defmacro 0:aa8ded7b33eb 21
defmacro 0:aa8ded7b33eb 22 #define MJSON_OK 0
defmacro 0:aa8ded7b33eb 23 #define MJSON_ERROR_READING -1
defmacro 0:aa8ded7b33eb 24 #define MJSON_ERROR_UNKNOWN_TYPE -2
defmacro 0:aa8ded7b33eb 25 #define MJSON_ERROR_CHECK_FAILURE -3
defmacro 0:aa8ded7b33eb 26 #define MJSON_ERROR_TEST_NOT_TRUE -4
defmacro 0:aa8ded7b33eb 27
defmacro 0:aa8ded7b33eb 28 /* This should at least be 5 to hold `false` */
defmacro 0:aa8ded7b33eb 29 #define MJSON_BUFFER_MAX_LENGTH 8
defmacro 0:aa8ded7b33eb 30
defmacro 0:aa8ded7b33eb 31 typedef int16_t mjson_status_t;
defmacro 0:aa8ded7b33eb 32
defmacro 0:aa8ded7b33eb 33 struct mjson_ctx;
defmacro 0:aa8ded7b33eb 34
defmacro 0:aa8ded7b33eb 35 typedef size_t (*mjson_reader)(struct mjson_ctx *ctx, char *data, size_t limit);
defmacro 0:aa8ded7b33eb 36
defmacro 0:aa8ded7b33eb 37 struct mjson_ctx {
defmacro 0:aa8ded7b33eb 38 void *userdata;
defmacro 0:aa8ded7b33eb 39 mjson_reader reader;
defmacro 0:aa8ded7b33eb 40 char buffer[MJSON_BUFFER_MAX_LENGTH];
defmacro 0:aa8ded7b33eb 41 size_t start;
defmacro 0:aa8ded7b33eb 42 size_t length;
defmacro 0:aa8ded7b33eb 43 };
defmacro 0:aa8ded7b33eb 44
defmacro 0:aa8ded7b33eb 45 #define MJSON_BUFFER_START_(ctx) ((ctx)->buffer + (ctx)->start)
defmacro 0:aa8ded7b33eb 46
defmacro 0:aa8ded7b33eb 47 /* TODO: we can accept an optional length, so we won't read more data than
defmacro 0:aa8ded7b33eb 48 * needed when dealing with numbers directly
defmacro 0:aa8ded7b33eb 49 */
defmacro 0:aa8ded7b33eb 50 void mjson_init(struct mjson_ctx *ctx, void *userdata, mjson_reader reader)
defmacro 0:aa8ded7b33eb 51 {
defmacro 0:aa8ded7b33eb 52 ctx->userdata = userdata;
defmacro 0:aa8ded7b33eb 53 ctx->reader = reader;
defmacro 0:aa8ded7b33eb 54 ctx->start = 0;
defmacro 0:aa8ded7b33eb 55 ctx->length = 0;
defmacro 0:aa8ded7b33eb 56 }
defmacro 0:aa8ded7b33eb 57
defmacro 0:aa8ded7b33eb 58 mjson_status_t mjson_skip_value(struct mjson_ctx *ctx);
defmacro 0:aa8ded7b33eb 59
defmacro 0:aa8ded7b33eb 60 void mjson_shift_buffer_(struct mjson_ctx *ctx)
defmacro 0:aa8ded7b33eb 61 {
defmacro 0:aa8ded7b33eb 62 size_t i;
defmacro 0:aa8ded7b33eb 63 for (i = 0; i < ctx->length; i++) {
defmacro 0:aa8ded7b33eb 64 ctx->buffer[i] = ctx->buffer[i + ctx->start];
defmacro 0:aa8ded7b33eb 65 }
defmacro 0:aa8ded7b33eb 66 ctx->start = 0;
defmacro 0:aa8ded7b33eb 67 }
defmacro 0:aa8ded7b33eb 68
defmacro 0:aa8ded7b33eb 69 mjson_status_t
defmacro 0:aa8ded7b33eb 70 mjson_ensure_byte_(struct mjson_ctx *ctx, size_t byte)
defmacro 0:aa8ded7b33eb 71 {
defmacro 0:aa8ded7b33eb 72 if (ctx->length >= byte) { return MJSON_OK; }
defmacro 0:aa8ded7b33eb 73 byte -= ctx->length;
defmacro 0:aa8ded7b33eb 74 if (MJSON_BUFFER_MAX_LENGTH - ctx->length - ctx->start < byte) {
defmacro 0:aa8ded7b33eb 75 mjson_shift_buffer_(ctx);
defmacro 0:aa8ded7b33eb 76 }
defmacro 0:aa8ded7b33eb 77 if (ctx->reader(ctx, &ctx->buffer[ctx->start + ctx->length], byte) < byte) {
defmacro 0:aa8ded7b33eb 78 return MJSON_ERROR_READING;
defmacro 0:aa8ded7b33eb 79 }
defmacro 0:aa8ded7b33eb 80 ctx->length += byte;
defmacro 0:aa8ded7b33eb 81 return MJSON_OK;
defmacro 0:aa8ded7b33eb 82 }
defmacro 0:aa8ded7b33eb 83
defmacro 0:aa8ded7b33eb 84 void
defmacro 0:aa8ded7b33eb 85 mjson_consume_byte_(struct mjson_ctx *ctx, size_t byte)
defmacro 0:aa8ded7b33eb 86 {
defmacro 0:aa8ded7b33eb 87 ctx->start += byte;
defmacro 0:aa8ded7b33eb 88 ctx->length -= byte;
defmacro 0:aa8ded7b33eb 89 }
defmacro 0:aa8ded7b33eb 90
defmacro 0:aa8ded7b33eb 91 mjson_status_t
defmacro 0:aa8ded7b33eb 92 mjson_read_byte_(struct mjson_ctx *ctx, char ch)
defmacro 0:aa8ded7b33eb 93 {
defmacro 0:aa8ded7b33eb 94 mjson_status_t status;
defmacro 0:aa8ded7b33eb 95 status = mjson_ensure_byte_(ctx, 1);
defmacro 0:aa8ded7b33eb 96 if (status != MJSON_OK) { return status; }
defmacro 0:aa8ded7b33eb 97
defmacro 0:aa8ded7b33eb 98 if (*MJSON_BUFFER_START_(ctx) == ch) {
defmacro 0:aa8ded7b33eb 99 mjson_consume_byte_(ctx, 1);
defmacro 0:aa8ded7b33eb 100 return MJSON_OK;
defmacro 0:aa8ded7b33eb 101 }
defmacro 0:aa8ded7b33eb 102 return MJSON_ERROR_TEST_NOT_TRUE;
defmacro 0:aa8ded7b33eb 103 }
defmacro 0:aa8ded7b33eb 104
defmacro 0:aa8ded7b33eb 105 mjson_status_t
defmacro 0:aa8ded7b33eb 106 mjson_equal_string_(const char* a, const char* b, size_t n) {
defmacro 0:aa8ded7b33eb 107 size_t i;
defmacro 0:aa8ded7b33eb 108 for (i = 0; i < n && a[i] && a[i] == b[i]; i++) ;
defmacro 0:aa8ded7b33eb 109 return i == n ? MJSON_OK : MJSON_ERROR_TEST_NOT_TRUE;
defmacro 0:aa8ded7b33eb 110 }
defmacro 0:aa8ded7b33eb 111
defmacro 0:aa8ded7b33eb 112 mjson_status_t
defmacro 0:aa8ded7b33eb 113 mjson_read_type(struct mjson_ctx *ctx)
defmacro 0:aa8ded7b33eb 114 {
defmacro 0:aa8ded7b33eb 115 mjson_status_t status;
defmacro 0:aa8ded7b33eb 116 status = mjson_ensure_byte_(ctx, 1);
defmacro 0:aa8ded7b33eb 117 if (status != MJSON_OK) { return status; }
defmacro 0:aa8ded7b33eb 118
defmacro 0:aa8ded7b33eb 119 switch (*MJSON_BUFFER_START_(ctx)) {
defmacro 0:aa8ded7b33eb 120 case '"':
defmacro 0:aa8ded7b33eb 121 mjson_consume_byte_(ctx, 1);
defmacro 0:aa8ded7b33eb 122 return MJSON_TYPE_STRING;
defmacro 0:aa8ded7b33eb 123 case '{':
defmacro 0:aa8ded7b33eb 124 mjson_consume_byte_(ctx, 1);
defmacro 0:aa8ded7b33eb 125 return MJSON_TYPE_OBJECT;
defmacro 0:aa8ded7b33eb 126 case '[':
defmacro 0:aa8ded7b33eb 127 mjson_consume_byte_(ctx, 1);
defmacro 0:aa8ded7b33eb 128 return MJSON_TYPE_ARRAY;
defmacro 0:aa8ded7b33eb 129 case 't':
defmacro 0:aa8ded7b33eb 130 status = mjson_ensure_byte_(ctx, 4);
defmacro 0:aa8ded7b33eb 131 if (status != MJSON_OK) { return status; }
defmacro 0:aa8ded7b33eb 132 if (mjson_equal_string_(MJSON_BUFFER_START_(ctx), "true", 4) == MJSON_OK) {
defmacro 0:aa8ded7b33eb 133 mjson_consume_byte_(ctx, 4);
defmacro 0:aa8ded7b33eb 134 return MJSON_TYPE_TRUE;
defmacro 0:aa8ded7b33eb 135 } else {
defmacro 0:aa8ded7b33eb 136 return MJSON_ERROR_UNKNOWN_TYPE;
defmacro 0:aa8ded7b33eb 137 }
defmacro 0:aa8ded7b33eb 138 break;
defmacro 0:aa8ded7b33eb 139 case 'f':
defmacro 0:aa8ded7b33eb 140 status = mjson_ensure_byte_(ctx, 5);
defmacro 0:aa8ded7b33eb 141 if (status != MJSON_OK) { return status; }
defmacro 0:aa8ded7b33eb 142 if (mjson_equal_string_(MJSON_BUFFER_START_(ctx), "false", 5) == MJSON_OK) {
defmacro 0:aa8ded7b33eb 143 mjson_consume_byte_(ctx, 5);
defmacro 0:aa8ded7b33eb 144 return MJSON_TYPE_FALSE;
defmacro 0:aa8ded7b33eb 145 } else {
defmacro 0:aa8ded7b33eb 146 return MJSON_ERROR_UNKNOWN_TYPE;
defmacro 0:aa8ded7b33eb 147 }
defmacro 0:aa8ded7b33eb 148 break;
defmacro 0:aa8ded7b33eb 149 case 'n':
defmacro 0:aa8ded7b33eb 150 status = mjson_ensure_byte_(ctx, 4);
defmacro 0:aa8ded7b33eb 151 if (status != MJSON_OK) { return status; }
defmacro 0:aa8ded7b33eb 152 if (mjson_equal_string_(MJSON_BUFFER_START_(ctx), "null", 4) == MJSON_OK) {
defmacro 0:aa8ded7b33eb 153 mjson_consume_byte_(ctx, 4);
defmacro 0:aa8ded7b33eb 154 return MJSON_TYPE_NULL;
defmacro 0:aa8ded7b33eb 155 } else {
defmacro 0:aa8ded7b33eb 156 return MJSON_ERROR_UNKNOWN_TYPE;
defmacro 0:aa8ded7b33eb 157 }
defmacro 0:aa8ded7b33eb 158 break;
defmacro 0:aa8ded7b33eb 159 case '-':
defmacro 0:aa8ded7b33eb 160 case '0':
defmacro 0:aa8ded7b33eb 161 case '1':
defmacro 0:aa8ded7b33eb 162 case '2':
defmacro 0:aa8ded7b33eb 163 case '3':
defmacro 0:aa8ded7b33eb 164 case '4':
defmacro 0:aa8ded7b33eb 165 case '5':
defmacro 0:aa8ded7b33eb 166 case '6':
defmacro 0:aa8ded7b33eb 167 case '7':
defmacro 0:aa8ded7b33eb 168 case '8':
defmacro 0:aa8ded7b33eb 169 case '9':
defmacro 0:aa8ded7b33eb 170 return MJSON_TYPE_NUMBER;
defmacro 0:aa8ded7b33eb 171 }
defmacro 0:aa8ded7b33eb 172 return MJSON_ERROR_UNKNOWN_TYPE;
defmacro 0:aa8ded7b33eb 173 }
defmacro 0:aa8ded7b33eb 174
defmacro 0:aa8ded7b33eb 175 mjson_status_t mjson_readcheck_null(struct mjson_ctx *ctx)
defmacro 0:aa8ded7b33eb 176 {
defmacro 0:aa8ded7b33eb 177 return mjson_read_type(ctx) == MJSON_TYPE_NULL ?
defmacro 0:aa8ded7b33eb 178 MJSON_OK : MJSON_ERROR_CHECK_FAILURE;
defmacro 0:aa8ded7b33eb 179 }
defmacro 0:aa8ded7b33eb 180
defmacro 0:aa8ded7b33eb 181 mjson_status_t mjson_readcheck_boolean(struct mjson_ctx *ctx, int8_t *b)
defmacro 0:aa8ded7b33eb 182 {
defmacro 0:aa8ded7b33eb 183 mjson_status_t t = mjson_read_type(ctx);
defmacro 0:aa8ded7b33eb 184 switch (t) {
defmacro 0:aa8ded7b33eb 185 case MJSON_TYPE_TRUE:
defmacro 0:aa8ded7b33eb 186 *b = 1;
defmacro 0:aa8ded7b33eb 187 return MJSON_OK;
defmacro 0:aa8ded7b33eb 188 case MJSON_TYPE_FALSE:
defmacro 0:aa8ded7b33eb 189 *b = 0;
defmacro 0:aa8ded7b33eb 190 return MJSON_OK;
defmacro 0:aa8ded7b33eb 191 }
defmacro 0:aa8ded7b33eb 192 return MJSON_ERROR_CHECK_FAILURE;
defmacro 0:aa8ded7b33eb 193 }
defmacro 0:aa8ded7b33eb 194
defmacro 0:aa8ded7b33eb 195 mjson_status_t mjson_readcheck_string_start(struct mjson_ctx *ctx)
defmacro 0:aa8ded7b33eb 196 {
defmacro 0:aa8ded7b33eb 197 return mjson_read_type(ctx) == MJSON_TYPE_STRING ?
defmacro 0:aa8ded7b33eb 198 MJSON_OK : MJSON_ERROR_CHECK_FAILURE;
defmacro 0:aa8ded7b33eb 199 }
defmacro 0:aa8ded7b33eb 200
defmacro 0:aa8ded7b33eb 201 mjson_status_t mjson_read_partial_string(struct mjson_ctx *ctx,
defmacro 0:aa8ded7b33eb 202 char *data, size_t length,
defmacro 0:aa8ded7b33eb 203 size_t *out_length)
defmacro 0:aa8ded7b33eb 204 {
defmacro 0:aa8ded7b33eb 205 mjson_status_t status;
defmacro 0:aa8ded7b33eb 206 size_t i = 0;
defmacro 0:aa8ded7b33eb 207
defmacro 0:aa8ded7b33eb 208 while (i < length) {
defmacro 0:aa8ded7b33eb 209 status = mjson_ensure_byte_(ctx, 1);
defmacro 0:aa8ded7b33eb 210 if (status != MJSON_OK) { return status; }
defmacro 0:aa8ded7b33eb 211
defmacro 0:aa8ded7b33eb 212 if (*MJSON_BUFFER_START_(ctx) == '"') {
defmacro 0:aa8ded7b33eb 213 break;
defmacro 0:aa8ded7b33eb 214 } else if (*MJSON_BUFFER_START_(ctx) == '\\') {
defmacro 0:aa8ded7b33eb 215 status = mjson_ensure_byte_(ctx, 2);
defmacro 0:aa8ded7b33eb 216 if (status != MJSON_OK) { return status; }
defmacro 0:aa8ded7b33eb 217 switch (MJSON_BUFFER_START_(ctx)[1]) {
defmacro 0:aa8ded7b33eb 218 case '"':
defmacro 0:aa8ded7b33eb 219 data[i++] = '"';
defmacro 0:aa8ded7b33eb 220 break;
defmacro 0:aa8ded7b33eb 221 case '\\':
defmacro 0:aa8ded7b33eb 222 data[i++] = '\\';
defmacro 0:aa8ded7b33eb 223 break;
defmacro 0:aa8ded7b33eb 224 case '/':
defmacro 0:aa8ded7b33eb 225 data[i++] = '/';
defmacro 0:aa8ded7b33eb 226 break;
defmacro 0:aa8ded7b33eb 227 case 'b':
defmacro 0:aa8ded7b33eb 228 data[i++] = '\b';
defmacro 0:aa8ded7b33eb 229 break;
defmacro 0:aa8ded7b33eb 230 case 'f':
defmacro 0:aa8ded7b33eb 231 data[i++] = '\f';
defmacro 0:aa8ded7b33eb 232 break;
defmacro 0:aa8ded7b33eb 233 case 'n':
defmacro 0:aa8ded7b33eb 234 data[i++] = '\n';
defmacro 0:aa8ded7b33eb 235 break;
defmacro 0:aa8ded7b33eb 236 case 'r':
defmacro 0:aa8ded7b33eb 237 data[i++] = '\r';
defmacro 0:aa8ded7b33eb 238 break;
defmacro 0:aa8ded7b33eb 239 case 't':
defmacro 0:aa8ded7b33eb 240 data[i++] = '\t';
defmacro 0:aa8ded7b33eb 241 break;
defmacro 0:aa8ded7b33eb 242 default:
defmacro 0:aa8ded7b33eb 243 return MJSON_ERROR_UNKNOWN_TYPE;
defmacro 0:aa8ded7b33eb 244 }
defmacro 0:aa8ded7b33eb 245 mjson_consume_byte_(ctx, 2);
defmacro 0:aa8ded7b33eb 246 } else {
defmacro 0:aa8ded7b33eb 247 data[i++] = *MJSON_BUFFER_START_(ctx);
defmacro 0:aa8ded7b33eb 248 mjson_consume_byte_(ctx, 1);
defmacro 0:aa8ded7b33eb 249 }
defmacro 0:aa8ded7b33eb 250 }
defmacro 0:aa8ded7b33eb 251
defmacro 0:aa8ded7b33eb 252 *out_length = i;
defmacro 0:aa8ded7b33eb 253 return MJSON_OK;
defmacro 0:aa8ded7b33eb 254 }
defmacro 0:aa8ded7b33eb 255
defmacro 0:aa8ded7b33eb 256 mjson_status_t mjson_read_string_end(struct mjson_ctx *ctx)
defmacro 0:aa8ded7b33eb 257 {
defmacro 0:aa8ded7b33eb 258 return mjson_read_byte_(ctx, '"');
defmacro 0:aa8ded7b33eb 259 }
defmacro 0:aa8ded7b33eb 260
defmacro 0:aa8ded7b33eb 261 /* After this you don't have to do mjson_read_string_end */
defmacro 0:aa8ded7b33eb 262 mjson_status_t mjson_read_full_string(struct mjson_ctx *ctx,
defmacro 0:aa8ded7b33eb 263 char *data, size_t length,
defmacro 0:aa8ded7b33eb 264 size_t *out_length)
defmacro 0:aa8ded7b33eb 265 {
defmacro 0:aa8ded7b33eb 266 mjson_status_t status;
defmacro 0:aa8ded7b33eb 267 size_t full_length;
defmacro 0:aa8ded7b33eb 268 status = mjson_read_partial_string(ctx, data, length, &full_length);
defmacro 0:aa8ded7b33eb 269 if (status != MJSON_OK) { return status; }
defmacro 0:aa8ded7b33eb 270
defmacro 0:aa8ded7b33eb 271 while (1) {
defmacro 0:aa8ded7b33eb 272 status = mjson_ensure_byte_(ctx, 1);
defmacro 0:aa8ded7b33eb 273 if (status != MJSON_OK) { return status; }
defmacro 0:aa8ded7b33eb 274
defmacro 0:aa8ded7b33eb 275 if (*MJSON_BUFFER_START_(ctx) == '"') {
defmacro 0:aa8ded7b33eb 276 mjson_consume_byte_(ctx, 1);
defmacro 0:aa8ded7b33eb 277 *out_length = full_length;
defmacro 0:aa8ded7b33eb 278 return MJSON_OK;
defmacro 0:aa8ded7b33eb 279 } else if (*MJSON_BUFFER_START_(ctx) == '\\') {
defmacro 0:aa8ded7b33eb 280 status = mjson_ensure_byte_(ctx, 2);
defmacro 0:aa8ded7b33eb 281 if (status != MJSON_OK) { return status; }
defmacro 0:aa8ded7b33eb 282 mjson_consume_byte_(ctx, 2);
defmacro 0:aa8ded7b33eb 283 full_length++;
defmacro 0:aa8ded7b33eb 284 } else {
defmacro 0:aa8ded7b33eb 285 mjson_consume_byte_(ctx, 1);
defmacro 0:aa8ded7b33eb 286 full_length++;
defmacro 0:aa8ded7b33eb 287 }
defmacro 0:aa8ded7b33eb 288 }
defmacro 0:aa8ded7b33eb 289 /* Not reachable */
defmacro 0:aa8ded7b33eb 290 return MJSON_ERROR_CHECK_FAILURE;
defmacro 0:aa8ded7b33eb 291 }
defmacro 0:aa8ded7b33eb 292
defmacro 0:aa8ded7b33eb 293 mjson_status_t mjson_skip_string(struct mjson_ctx *ctx)
defmacro 0:aa8ded7b33eb 294 {
defmacro 0:aa8ded7b33eb 295 size_t temp;
defmacro 0:aa8ded7b33eb 296 return mjson_read_full_string(ctx, NULL, 0, &temp);
defmacro 0:aa8ded7b33eb 297 }
defmacro 0:aa8ded7b33eb 298
defmacro 0:aa8ded7b33eb 299 mjson_status_t mjson_readcheck_array_start(struct mjson_ctx *ctx)
defmacro 0:aa8ded7b33eb 300 {
defmacro 0:aa8ded7b33eb 301 return mjson_read_type(ctx) == MJSON_TYPE_ARRAY ?
defmacro 0:aa8ded7b33eb 302 MJSON_OK : MJSON_ERROR_CHECK_FAILURE;
defmacro 0:aa8ded7b33eb 303 }
defmacro 0:aa8ded7b33eb 304
defmacro 0:aa8ded7b33eb 305 mjson_status_t mjson_read_array_separator_or_end(struct mjson_ctx *ctx)
defmacro 0:aa8ded7b33eb 306 {
defmacro 0:aa8ded7b33eb 307 mjson_status_t status;
defmacro 0:aa8ded7b33eb 308 status = mjson_ensure_byte_(ctx, 1);
defmacro 0:aa8ded7b33eb 309 if (status != MJSON_OK) { return status; }
defmacro 0:aa8ded7b33eb 310
defmacro 0:aa8ded7b33eb 311 if (*MJSON_BUFFER_START_(ctx) == ',') {
defmacro 0:aa8ded7b33eb 312 mjson_consume_byte_(ctx, 1);
defmacro 0:aa8ded7b33eb 313 return MJSON_SUBTYPE_ARRAY_SEPARATOR;
defmacro 0:aa8ded7b33eb 314 } else if (*MJSON_BUFFER_START_(ctx) == ']') {
defmacro 0:aa8ded7b33eb 315 mjson_consume_byte_(ctx, 1);
defmacro 0:aa8ded7b33eb 316 return MJSON_SUBTYPE_ARRAY_END;
defmacro 0:aa8ded7b33eb 317 }
defmacro 0:aa8ded7b33eb 318 return MJSON_ERROR_TEST_NOT_TRUE;
defmacro 0:aa8ded7b33eb 319 }
defmacro 0:aa8ded7b33eb 320
defmacro 0:aa8ded7b33eb 321 mjson_status_t mjson_skip_array(struct mjson_ctx *ctx)
defmacro 0:aa8ded7b33eb 322 {
defmacro 0:aa8ded7b33eb 323 mjson_status_t status;
defmacro 0:aa8ded7b33eb 324
defmacro 0:aa8ded7b33eb 325 while (mjson_read_array_separator_or_end(ctx) != MJSON_SUBTYPE_ARRAY_END) {
defmacro 0:aa8ded7b33eb 326 status = mjson_skip_value(ctx);
defmacro 0:aa8ded7b33eb 327 if (status != MJSON_OK) { return status; }
defmacro 0:aa8ded7b33eb 328 }
defmacro 0:aa8ded7b33eb 329
defmacro 0:aa8ded7b33eb 330 return MJSON_OK;
defmacro 0:aa8ded7b33eb 331 }
defmacro 0:aa8ded7b33eb 332
defmacro 0:aa8ded7b33eb 333 mjson_status_t mjson_readcheck_object_start(struct mjson_ctx *ctx)
defmacro 0:aa8ded7b33eb 334 {
defmacro 0:aa8ded7b33eb 335 return mjson_read_type(ctx) == MJSON_TYPE_OBJECT ?
defmacro 0:aa8ded7b33eb 336 MJSON_OK : MJSON_ERROR_CHECK_FAILURE;
defmacro 0:aa8ded7b33eb 337 }
defmacro 0:aa8ded7b33eb 338
defmacro 0:aa8ded7b33eb 339 mjson_status_t mjson_read_object_key_separator(struct mjson_ctx *ctx)
defmacro 0:aa8ded7b33eb 340 {
defmacro 0:aa8ded7b33eb 341 return mjson_read_byte_(ctx, ':');
defmacro 0:aa8ded7b33eb 342 }
defmacro 0:aa8ded7b33eb 343
defmacro 0:aa8ded7b33eb 344 mjson_status_t mjson_read_object_separator_or_end(struct mjson_ctx *ctx)
defmacro 0:aa8ded7b33eb 345 {
defmacro 0:aa8ded7b33eb 346 mjson_status_t status;
defmacro 0:aa8ded7b33eb 347 status = mjson_ensure_byte_(ctx, 1);
defmacro 0:aa8ded7b33eb 348 if (status != MJSON_OK) { return status; }
defmacro 0:aa8ded7b33eb 349
defmacro 0:aa8ded7b33eb 350 if (*MJSON_BUFFER_START_(ctx) == ',') {
defmacro 0:aa8ded7b33eb 351 mjson_consume_byte_(ctx, 1);
defmacro 0:aa8ded7b33eb 352 return MJSON_SUBTYPE_OBJECT_SEPARATOR;
defmacro 0:aa8ded7b33eb 353 } else if (*MJSON_BUFFER_START_(ctx) == '}') {
defmacro 0:aa8ded7b33eb 354 mjson_consume_byte_(ctx, 1);
defmacro 0:aa8ded7b33eb 355 return MJSON_SUBTYPE_OBJECT_END;
defmacro 0:aa8ded7b33eb 356 }
defmacro 0:aa8ded7b33eb 357 return MJSON_ERROR_TEST_NOT_TRUE;
defmacro 0:aa8ded7b33eb 358 }
defmacro 0:aa8ded7b33eb 359
defmacro 0:aa8ded7b33eb 360 mjson_status_t mjson_skip_object(struct mjson_ctx *ctx)
defmacro 0:aa8ded7b33eb 361 {
defmacro 0:aa8ded7b33eb 362 mjson_status_t status;
defmacro 0:aa8ded7b33eb 363
defmacro 0:aa8ded7b33eb 364 while (mjson_read_object_separator_or_end(ctx) != MJSON_SUBTYPE_OBJECT_END) {
defmacro 0:aa8ded7b33eb 365 status = mjson_readcheck_string_start(ctx);
defmacro 0:aa8ded7b33eb 366 if (status != MJSON_OK) { return status; }
defmacro 0:aa8ded7b33eb 367
defmacro 0:aa8ded7b33eb 368 status = mjson_skip_string(ctx);
defmacro 0:aa8ded7b33eb 369 if (status != MJSON_OK) { return status; }
defmacro 0:aa8ded7b33eb 370
defmacro 0:aa8ded7b33eb 371 status = mjson_read_object_key_separator(ctx);
defmacro 0:aa8ded7b33eb 372 if (status != MJSON_OK) { return status; }
defmacro 0:aa8ded7b33eb 373
defmacro 0:aa8ded7b33eb 374 status = mjson_skip_value(ctx);
defmacro 0:aa8ded7b33eb 375 if (status != MJSON_OK) { return status; }
defmacro 0:aa8ded7b33eb 376 }
defmacro 0:aa8ded7b33eb 377
defmacro 0:aa8ded7b33eb 378 return MJSON_OK;
defmacro 0:aa8ded7b33eb 379 }
defmacro 0:aa8ded7b33eb 380
defmacro 0:aa8ded7b33eb 381 mjson_status_t mjson_read_int8(struct mjson_ctx *ctx, int8_t *out)
defmacro 0:aa8ded7b33eb 382 {
defmacro 0:aa8ded7b33eb 383 int8_t val = 0, sign = 1;
defmacro 0:aa8ded7b33eb 384 mjson_status_t status;
defmacro 0:aa8ded7b33eb 385
defmacro 0:aa8ded7b33eb 386 status = mjson_ensure_byte_(ctx, 1);
defmacro 0:aa8ded7b33eb 387 if (status != MJSON_OK) { return status; }
defmacro 0:aa8ded7b33eb 388 if (MJSON_BUFFER_START_(ctx)[0] == '-') {
defmacro 0:aa8ded7b33eb 389 mjson_consume_byte_(ctx, 1);
defmacro 0:aa8ded7b33eb 390 sign = -1;
defmacro 0:aa8ded7b33eb 391 }
defmacro 0:aa8ded7b33eb 392
defmacro 0:aa8ded7b33eb 393 status = mjson_ensure_byte_(ctx, 1);
defmacro 0:aa8ded7b33eb 394 if (status != MJSON_OK) { return status; }
defmacro 0:aa8ded7b33eb 395 while (MJSON_BUFFER_START_(ctx)[0] >= '0' &&
defmacro 0:aa8ded7b33eb 396 MJSON_BUFFER_START_(ctx)[0] <= '9') {
defmacro 0:aa8ded7b33eb 397 val = val * 10 + (MJSON_BUFFER_START_(ctx)[0] - '0');
defmacro 0:aa8ded7b33eb 398
defmacro 0:aa8ded7b33eb 399 mjson_consume_byte_(ctx, 1);
defmacro 0:aa8ded7b33eb 400 status = mjson_ensure_byte_(ctx, 1);
defmacro 0:aa8ded7b33eb 401 if (status != MJSON_OK) { return status; }
defmacro 0:aa8ded7b33eb 402 }
defmacro 0:aa8ded7b33eb 403 *out = val * sign;
defmacro 0:aa8ded7b33eb 404 /* Skip additional parts */
defmacro 0:aa8ded7b33eb 405 while ((MJSON_BUFFER_START_(ctx)[0] >= '0' &&
defmacro 0:aa8ded7b33eb 406 MJSON_BUFFER_START_(ctx)[0] <= '9') ||
defmacro 0:aa8ded7b33eb 407 MJSON_BUFFER_START_(ctx)[0] == '.' ||
defmacro 0:aa8ded7b33eb 408 MJSON_BUFFER_START_(ctx)[0] == 'e' ||
defmacro 0:aa8ded7b33eb 409 MJSON_BUFFER_START_(ctx)[0] == 'E' ||
defmacro 0:aa8ded7b33eb 410 MJSON_BUFFER_START_(ctx)[0] == '+' ||
defmacro 0:aa8ded7b33eb 411 MJSON_BUFFER_START_(ctx)[0] == '-') {
defmacro 0:aa8ded7b33eb 412 mjson_consume_byte_(ctx, 1);
defmacro 0:aa8ded7b33eb 413 status = mjson_ensure_byte_(ctx, 1);
defmacro 0:aa8ded7b33eb 414 if (status != MJSON_OK) { return status; }
defmacro 0:aa8ded7b33eb 415 }
defmacro 0:aa8ded7b33eb 416 return MJSON_OK;
defmacro 0:aa8ded7b33eb 417 }
defmacro 0:aa8ded7b33eb 418
defmacro 0:aa8ded7b33eb 419 mjson_status_t mjson_read_int16(struct mjson_ctx *ctx, int16_t *out)
defmacro 0:aa8ded7b33eb 420 {
defmacro 0:aa8ded7b33eb 421 int16_t val = 0, sign = 1;
defmacro 0:aa8ded7b33eb 422 mjson_status_t status;
defmacro 0:aa8ded7b33eb 423
defmacro 0:aa8ded7b33eb 424 status = mjson_ensure_byte_(ctx, 1);
defmacro 0:aa8ded7b33eb 425 if (status != MJSON_OK) { return status; }
defmacro 0:aa8ded7b33eb 426 if (MJSON_BUFFER_START_(ctx)[0] == '-') {
defmacro 0:aa8ded7b33eb 427 mjson_consume_byte_(ctx, 1);
defmacro 0:aa8ded7b33eb 428 sign = -1;
defmacro 0:aa8ded7b33eb 429 }
defmacro 0:aa8ded7b33eb 430
defmacro 0:aa8ded7b33eb 431 status = mjson_ensure_byte_(ctx, 1);
defmacro 0:aa8ded7b33eb 432 if (status != MJSON_OK) { return status; }
defmacro 0:aa8ded7b33eb 433 while (MJSON_BUFFER_START_(ctx)[0] >= '0' &&
defmacro 0:aa8ded7b33eb 434 MJSON_BUFFER_START_(ctx)[0] <= '9') {
defmacro 0:aa8ded7b33eb 435 val = val * 10 + (MJSON_BUFFER_START_(ctx)[0] - '0');
defmacro 0:aa8ded7b33eb 436
defmacro 0:aa8ded7b33eb 437 mjson_consume_byte_(ctx, 1);
defmacro 0:aa8ded7b33eb 438 status = mjson_ensure_byte_(ctx, 1);
defmacro 0:aa8ded7b33eb 439 if (status != MJSON_OK) { return status; }
defmacro 0:aa8ded7b33eb 440 }
defmacro 0:aa8ded7b33eb 441 *out = val * sign;
defmacro 0:aa8ded7b33eb 442 /* Skip additional parts */
defmacro 0:aa8ded7b33eb 443 while ((MJSON_BUFFER_START_(ctx)[0] >= '0' &&
defmacro 0:aa8ded7b33eb 444 MJSON_BUFFER_START_(ctx)[0] <= '9') ||
defmacro 0:aa8ded7b33eb 445 MJSON_BUFFER_START_(ctx)[0] == '.' ||
defmacro 0:aa8ded7b33eb 446 MJSON_BUFFER_START_(ctx)[0] == 'e' ||
defmacro 0:aa8ded7b33eb 447 MJSON_BUFFER_START_(ctx)[0] == 'E' ||
defmacro 0:aa8ded7b33eb 448 MJSON_BUFFER_START_(ctx)[0] == '+' ||
defmacro 0:aa8ded7b33eb 449 MJSON_BUFFER_START_(ctx)[0] == '-') {
defmacro 0:aa8ded7b33eb 450 mjson_consume_byte_(ctx, 1);
defmacro 0:aa8ded7b33eb 451 status = mjson_ensure_byte_(ctx, 1);
defmacro 0:aa8ded7b33eb 452 if (status != MJSON_OK) { return status; }
defmacro 0:aa8ded7b33eb 453 }
defmacro 0:aa8ded7b33eb 454 return MJSON_OK;
defmacro 0:aa8ded7b33eb 455 }
defmacro 0:aa8ded7b33eb 456
defmacro 0:aa8ded7b33eb 457 mjson_status_t mjson_read_int32(struct mjson_ctx *ctx, int32_t *out)
defmacro 0:aa8ded7b33eb 458 {
defmacro 0:aa8ded7b33eb 459 int32_t val = 0, sign = 1;
defmacro 0:aa8ded7b33eb 460 mjson_status_t status;
defmacro 0:aa8ded7b33eb 461
defmacro 0:aa8ded7b33eb 462 status = mjson_ensure_byte_(ctx, 1);
defmacro 0:aa8ded7b33eb 463 if (status != MJSON_OK) { return status; }
defmacro 0:aa8ded7b33eb 464 if (MJSON_BUFFER_START_(ctx)[0] == '-') {
defmacro 0:aa8ded7b33eb 465 mjson_consume_byte_(ctx, 1);
defmacro 0:aa8ded7b33eb 466 sign = -1;
defmacro 0:aa8ded7b33eb 467 }
defmacro 0:aa8ded7b33eb 468
defmacro 0:aa8ded7b33eb 469 status = mjson_ensure_byte_(ctx, 1);
defmacro 0:aa8ded7b33eb 470 if (status != MJSON_OK) { return status; }
defmacro 0:aa8ded7b33eb 471 while (MJSON_BUFFER_START_(ctx)[0] >= '0' &&
defmacro 0:aa8ded7b33eb 472 MJSON_BUFFER_START_(ctx)[0] <= '9') {
defmacro 0:aa8ded7b33eb 473 val = val * 10 + (MJSON_BUFFER_START_(ctx)[0] - '0');
defmacro 0:aa8ded7b33eb 474
defmacro 0:aa8ded7b33eb 475 mjson_consume_byte_(ctx, 1);
defmacro 0:aa8ded7b33eb 476 status = mjson_ensure_byte_(ctx, 1);
defmacro 0:aa8ded7b33eb 477 if (status != MJSON_OK) { return status; }
defmacro 0:aa8ded7b33eb 478 }
defmacro 0:aa8ded7b33eb 479 *out = val * sign;
defmacro 0:aa8ded7b33eb 480 /* Skip additional parts */
defmacro 0:aa8ded7b33eb 481 while ((MJSON_BUFFER_START_(ctx)[0] >= '0' &&
defmacro 0:aa8ded7b33eb 482 MJSON_BUFFER_START_(ctx)[0] <= '9') ||
defmacro 0:aa8ded7b33eb 483 MJSON_BUFFER_START_(ctx)[0] == '.' ||
defmacro 0:aa8ded7b33eb 484 MJSON_BUFFER_START_(ctx)[0] == 'e' ||
defmacro 0:aa8ded7b33eb 485 MJSON_BUFFER_START_(ctx)[0] == 'E' ||
defmacro 0:aa8ded7b33eb 486 MJSON_BUFFER_START_(ctx)[0] == '+' ||
defmacro 0:aa8ded7b33eb 487 MJSON_BUFFER_START_(ctx)[0] == '-') {
defmacro 0:aa8ded7b33eb 488 mjson_consume_byte_(ctx, 1);
defmacro 0:aa8ded7b33eb 489 status = mjson_ensure_byte_(ctx, 1);
defmacro 0:aa8ded7b33eb 490 if (status != MJSON_OK) { return status; }
defmacro 0:aa8ded7b33eb 491 }
defmacro 0:aa8ded7b33eb 492 return MJSON_OK;
defmacro 0:aa8ded7b33eb 493 }
defmacro 0:aa8ded7b33eb 494
defmacro 0:aa8ded7b33eb 495 mjson_status_t mjson_read_int64(struct mjson_ctx *ctx, int64_t *out)
defmacro 0:aa8ded7b33eb 496 {
defmacro 0:aa8ded7b33eb 497 int64_t val = 0, sign = 1;
defmacro 0:aa8ded7b33eb 498 mjson_status_t status;
defmacro 0:aa8ded7b33eb 499
defmacro 0:aa8ded7b33eb 500 status = mjson_ensure_byte_(ctx, 1);
defmacro 0:aa8ded7b33eb 501 if (status != MJSON_OK) { return status; }
defmacro 0:aa8ded7b33eb 502 if (MJSON_BUFFER_START_(ctx)[0] == '-') {
defmacro 0:aa8ded7b33eb 503 mjson_consume_byte_(ctx, 1);
defmacro 0:aa8ded7b33eb 504 sign = -1;
defmacro 0:aa8ded7b33eb 505 }
defmacro 0:aa8ded7b33eb 506
defmacro 0:aa8ded7b33eb 507 status = mjson_ensure_byte_(ctx, 1);
defmacro 0:aa8ded7b33eb 508 if (status != MJSON_OK) { return status; }
defmacro 0:aa8ded7b33eb 509 while (MJSON_BUFFER_START_(ctx)[0] >= '0' &&
defmacro 0:aa8ded7b33eb 510 MJSON_BUFFER_START_(ctx)[0] <= '9') {
defmacro 0:aa8ded7b33eb 511 val = val * 10 + (MJSON_BUFFER_START_(ctx)[0] - '0');
defmacro 0:aa8ded7b33eb 512
defmacro 0:aa8ded7b33eb 513 mjson_consume_byte_(ctx, 1);
defmacro 0:aa8ded7b33eb 514 status = mjson_ensure_byte_(ctx, 1);
defmacro 0:aa8ded7b33eb 515 if (status != MJSON_OK) { return status; }
defmacro 0:aa8ded7b33eb 516 }
defmacro 0:aa8ded7b33eb 517 *out = val * sign;
defmacro 0:aa8ded7b33eb 518 /* Skip additional parts */
defmacro 0:aa8ded7b33eb 519 while ((MJSON_BUFFER_START_(ctx)[0] >= '0' &&
defmacro 0:aa8ded7b33eb 520 MJSON_BUFFER_START_(ctx)[0] <= '9') ||
defmacro 0:aa8ded7b33eb 521 MJSON_BUFFER_START_(ctx)[0] == '.' ||
defmacro 0:aa8ded7b33eb 522 MJSON_BUFFER_START_(ctx)[0] == 'e' ||
defmacro 0:aa8ded7b33eb 523 MJSON_BUFFER_START_(ctx)[0] == 'E' ||
defmacro 0:aa8ded7b33eb 524 MJSON_BUFFER_START_(ctx)[0] == '+' ||
defmacro 0:aa8ded7b33eb 525 MJSON_BUFFER_START_(ctx)[0] == '-') {
defmacro 0:aa8ded7b33eb 526 mjson_consume_byte_(ctx, 1);
defmacro 0:aa8ded7b33eb 527 status = mjson_ensure_byte_(ctx, 1);
defmacro 0:aa8ded7b33eb 528 if (status != MJSON_OK) { return status; }
defmacro 0:aa8ded7b33eb 529 }
defmacro 0:aa8ded7b33eb 530 return MJSON_OK;
defmacro 0:aa8ded7b33eb 531 }
defmacro 0:aa8ded7b33eb 532 /*
defmacro 0:aa8ded7b33eb 533 * We don't really support parsing to double directly here, since to implement
defmacro 0:aa8ded7b33eb 534 * full double parsing semantics, we would need pow(). However, if pow() is
defmacro 0:aa8ded7b33eb 535 * available, it is very likely that atof() is also available. Hence providing
defmacro 0:aa8ded7b33eb 536 * copying number as a string will be enough.
defmacro 0:aa8ded7b33eb 537 */
defmacro 0:aa8ded7b33eb 538 mjson_status_t mjson_read_number_as_string(struct mjson_ctx *ctx,
defmacro 0:aa8ded7b33eb 539 char *data, size_t length,
defmacro 0:aa8ded7b33eb 540 size_t *out_length) {
defmacro 0:aa8ded7b33eb 541 mjson_status_t status;
defmacro 0:aa8ded7b33eb 542 size_t i = 0;
defmacro 0:aa8ded7b33eb 543 char ch;
defmacro 0:aa8ded7b33eb 544
defmacro 0:aa8ded7b33eb 545 while (i < length) {
defmacro 0:aa8ded7b33eb 546 status = mjson_ensure_byte_(ctx, 1);
defmacro 0:aa8ded7b33eb 547 if (status != MJSON_OK) { return status; }
defmacro 0:aa8ded7b33eb 548
defmacro 0:aa8ded7b33eb 549 ch = MJSON_BUFFER_START_(ctx)[0];
defmacro 0:aa8ded7b33eb 550 if ((ch >= '0' && ch <= '9') ||
defmacro 0:aa8ded7b33eb 551 ch == '.' ||
defmacro 0:aa8ded7b33eb 552 ch == '+' || ch == '-' ||
defmacro 0:aa8ded7b33eb 553 ch == 'e' || ch == 'E') {
defmacro 0:aa8ded7b33eb 554 data[i++] = ch;
defmacro 0:aa8ded7b33eb 555 mjson_consume_byte_(ctx, 1);
defmacro 0:aa8ded7b33eb 556 } else {
defmacro 0:aa8ded7b33eb 557 break;
defmacro 0:aa8ded7b33eb 558 }
defmacro 0:aa8ded7b33eb 559 }
defmacro 0:aa8ded7b33eb 560 status = mjson_ensure_byte_(ctx, 1);
defmacro 0:aa8ded7b33eb 561 if (status != MJSON_OK) { return status; }
defmacro 0:aa8ded7b33eb 562 ch = MJSON_BUFFER_START_(ctx)[0];
defmacro 0:aa8ded7b33eb 563 while ((ch >= '0' && ch <= '9') ||
defmacro 0:aa8ded7b33eb 564 ch == '.' ||
defmacro 0:aa8ded7b33eb 565 ch == '+' || ch == '-' ||
defmacro 0:aa8ded7b33eb 566 ch == 'e' || ch == 'E') {
defmacro 0:aa8ded7b33eb 567 i++;
defmacro 0:aa8ded7b33eb 568 mjson_consume_byte_(ctx, 1);
defmacro 0:aa8ded7b33eb 569 }
defmacro 0:aa8ded7b33eb 570 *out_length = i;
defmacro 0:aa8ded7b33eb 571 return MJSON_OK;
defmacro 0:aa8ded7b33eb 572 }
defmacro 0:aa8ded7b33eb 573
defmacro 0:aa8ded7b33eb 574 mjson_status_t mjson_skip_number(struct mjson_ctx *ctx)
defmacro 0:aa8ded7b33eb 575 {
defmacro 0:aa8ded7b33eb 576 size_t temp;
defmacro 0:aa8ded7b33eb 577 return mjson_read_number_as_string(ctx, NULL, 0, &temp);
defmacro 0:aa8ded7b33eb 578 }
defmacro 0:aa8ded7b33eb 579
defmacro 0:aa8ded7b33eb 580 mjson_status_t mjson_skip_value(struct mjson_ctx *ctx) {
defmacro 0:aa8ded7b33eb 581 mjson_status_t t = mjson_read_type(ctx);
defmacro 0:aa8ded7b33eb 582 switch (t) {
defmacro 0:aa8ded7b33eb 583 case MJSON_TYPE_ARRAY:
defmacro 0:aa8ded7b33eb 584 return mjson_skip_array(ctx);
defmacro 0:aa8ded7b33eb 585 case MJSON_TYPE_OBJECT:
defmacro 0:aa8ded7b33eb 586 return mjson_skip_object(ctx);
defmacro 0:aa8ded7b33eb 587 case MJSON_TYPE_NUMBER:
defmacro 0:aa8ded7b33eb 588 return mjson_skip_number(ctx);
defmacro 0:aa8ded7b33eb 589 case MJSON_TYPE_STRING:
defmacro 0:aa8ded7b33eb 590 return mjson_skip_string(ctx);
defmacro 0:aa8ded7b33eb 591 case MJSON_TYPE_NULL:
defmacro 0:aa8ded7b33eb 592 case MJSON_TYPE_TRUE:
defmacro 0:aa8ded7b33eb 593 case MJSON_TYPE_FALSE:
defmacro 0:aa8ded7b33eb 594 return MJSON_OK;
defmacro 0:aa8ded7b33eb 595 }
defmacro 0:aa8ded7b33eb 596 return t;
defmacro 0:aa8ded7b33eb 597 }
defmacro 0:aa8ded7b33eb 598
defmacro 0:aa8ded7b33eb 599 #endif /* MJSON_H_ */