/* * Copyright (c) 2007-2014, Lloyd Hilaiel * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include "yajl_parse.h" #include "yajl_gen.h" #include #include #include #include /* memory debugging routines */ typedef struct { unsigned int numFrees; unsigned int numMallocs; /* XXX: we really need a hash table here with per-allocation * information */ } yajlTestMemoryContext; /* cast void * into context */ #define TEST_CTX(vptr) ((yajlTestMemoryContext *) (vptr)) static void yajlTestFree(void * ctx, void * ptr) { assert(ptr != NULL); TEST_CTX(ctx)->numFrees++; free(ptr); } static void * yajlTestMalloc(void * ctx, size_t sz) { assert(sz != 0); TEST_CTX(ctx)->numMallocs++; return malloc(sz); } static void * yajlTestRealloc(void * ctx, void * ptr, size_t sz) { if (ptr == NULL) { assert(sz != 0); TEST_CTX(ctx)->numMallocs++; } else if (sz == 0) { TEST_CTX(ctx)->numFrees++; } return realloc(ptr, sz); } /* begin parsing callback routines */ #define BUF_SIZE 2048 static int test_yajl_null(void *ctx) { printf("null\n"); return 1; } static int test_yajl_boolean(void * ctx, int boolVal) { printf("bool: %s\n", boolVal ? "true" : "false"); return 1; } static int test_yajl_integer(void *ctx, longlong integerVal) { printf("integer: %lld\n", integerVal); return 1; } static int test_yajl_double(void *ctx, double doubleVal) { printf("double: %g\n", doubleVal); return 1; } static int test_yajl_string(void *ctx, const unsigned char * stringVal, size_t stringLen) { printf("string: '"); fwrite(stringVal, 1, stringLen, stdout); printf("'\n"); return 1; } static int test_yajl_map_key(void *ctx, const unsigned char * stringVal, size_t stringLen) { char * str = (char *) malloc(stringLen + 1); str[stringLen] = 0; memcpy(str, stringVal, stringLen); printf("key: '%s'\n", str); free(str); return 1; } static int test_yajl_start_map(void *ctx) { printf("map open '{'\n"); return 1; } static int test_yajl_end_map(void *ctx) { printf("map close '}'\n"); return 1; } static int test_yajl_start_array(void *ctx) { printf("array open '['\n"); return 1; } static int test_yajl_end_array(void *ctx) { printf("array close ']'\n"); return 1; } static yajl_callbacks callbacks = { test_yajl_null, test_yajl_boolean, test_yajl_integer, test_yajl_double, NULL, test_yajl_string, NULL, NULL, test_yajl_start_map, test_yajl_map_key, test_yajl_end_map, test_yajl_start_array, test_yajl_end_array }; static void usage(const char * progname) { fprintf(stderr, "usage: %s [options]\n" "Parse input from stdin as JSON and ouput parsing details " "to stdout\n" " -b set the read buffer size\n" " -c allow comments\n" " -g allow *g*arbage after valid JSON text\n" " -m allows the parser to consume multiple JSON values\n" " from a single string separated by whitespace\n" " -p partial JSON documents should not cause errors\n", progname); exit(1); } int main(int argc, char ** argv) { yajl_handle hand; const char * fileName = NULL; static unsigned char * fileData = NULL; FILE *file; size_t bufSize = BUF_SIZE; yajl_status stat; size_t rd; int i, j; /* memory allocation debugging: allocate a structure which collects * statistics */ yajlTestMemoryContext memCtx = { 0,0 }; /* memory allocation debugging: allocate a structure which holds * allocation routines */ yajl_alloc_funcs allocFuncs = { yajlTestMalloc, yajlTestRealloc, yajlTestFree, (void *) NULL }; allocFuncs.ctx = (void *) &memCtx; /* allocate the parser */ hand = yajl_alloc(&callbacks, &allocFuncs, NULL); /* check arguments. We expect exactly one! */ for (i=1;i= argc) usage(argv[0]); /* validate integer */ for (j=0;j<(int)strlen(argv[i]);j++) { if (argv[i][j] <= '9' && argv[i][j] >= '0') continue; fprintf(stderr, "-b requires an integer argument. '%s' " "is invalid\n", argv[i]); usage(argv[0]); } bufSize = atoi(argv[i]); if (!bufSize) { fprintf(stderr, "%zu is an invalid buffer size\n", bufSize); } } else if (!strcmp("-g", argv[i])) { yajl_config(hand, yajl_allow_trailing_garbage, 1); } else if (!strcmp("-m", argv[i])) { yajl_config(hand, yajl_allow_multiple_values, 1); } else if (!strcmp("-p", argv[i])) { yajl_config(hand, yajl_allow_partial_values, 1); } else { fileName = argv[i]; break; } } fileData = (unsigned char *) malloc(bufSize); if (fileData == NULL) { fprintf(stderr, "failed to allocate read buffer of %zu bytes, exiting.", bufSize); yajl_free(hand); exit(2); } if (fileName) { file = fopen(fileName, "r"); } else { file = stdin; } for (;;) { rd = fread((void *) fileData, 1, bufSize, file); if (rd == 0) { if (!feof(stdin)) { fprintf(stderr, "error reading from '%s'\n", fileName); } break; } /* read file data, now pass to parser */ stat = yajl_parse(hand, fileData, rd); if (stat != yajl_status_ok) break; } stat = yajl_complete_parse(hand); if (stat != yajl_status_ok) { unsigned char * str = yajl_get_error(hand, 0, fileData, rd); fflush(stdout); fprintf(stderr, "%s", (char *) str); yajl_free_error(hand, str); } yajl_free(hand); free(fileData); if (fileName) { fclose(file); } /* finally, print out some memory statistics */ /* (lth) only print leaks here, as allocations and frees may vary depending * on read buffer size, causing false failures. * * printf("allocations:\t%u\n", memCtx.numMallocs); * printf("frees:\t\t%u\n", memCtx.numFrees); */ fflush(stderr); fflush(stdout); printf("memory leaks:\t%u\n", memCtx.numMallocs - memCtx.numFrees); return 0; }