apple2ix/src/json_parse.c

210 lines
6.0 KiB
C

/*
* Apple // emulator for *ix
*
* This software package is subject to the GNU General Public License
* version 3 or later (your choice) as published by the Free Software
* Foundation.
*
* Copyright 2013-2015 Aaron Culliney
*
*/
#include "json_parse.h"
#define JSON_LENGTH 16
#define DEFAULT_NUMTOK 16
int json_createFromFile(const char *filePath, INOUT JSON_s *parsedData) {
int fd = -1;
jsmnerr_t errCount = JSMN_ERROR_NOMEM;
ssize_t jsonIdx = 0;
ssize_t jsonLen = 0;
char *jsonString = NULL;
jsmntok_t *jsonTokens = NULL;
do {
if (!parsedData) {
break;
}
parsedData->jsonString = NULL;
parsedData->jsonTokens = NULL;
TEMP_FAILURE_RETRY(fd = open(filePath, O_RDONLY));
if (fd < 0) {
ERRLOG("Error opening file : %s", strerror(errno));
break;
}
jsonLen = JSON_LENGTH*2;
jsonString = malloc(jsonLen);
if (jsonString == NULL) {
ERRLOG("WHOA : %s", strerror(errno));
break;
}
ssize_t bytesRead = 0;
do {
TEMP_FAILURE_RETRY(bytesRead = read(fd, jsonString+jsonIdx, JSON_LENGTH));
if (bytesRead < 0) {
ERRLOG("Error reading file : %s", strerror(errno));
break;
}
if (bytesRead) {
jsonIdx += bytesRead;
if (jsonLen - jsonIdx < JSON_LENGTH) {
//LOG("reallocating json string ...");
jsonLen <<= 1;
char *newString = realloc(jsonString, jsonLen);
if (!newString) {
ERRLOG("WHOA2 : %s", strerror(errno));
bytesRead = -1;
break;
}
jsonString = newString;
}
}
} while (bytesRead);
if (bytesRead < 0) {
break;
}
jsonLen = jsonIdx;
TEMP_FAILURE_RETRY(close(fd));
fd = 0;
// now parse the string
jsmn_parser parser = { 0 };
unsigned int numTokens = DEFAULT_NUMTOK;
do {
if (!jsonTokens) {
jsonTokens = calloc(numTokens, sizeof(jsmntok_t));
if (!jsonTokens) {
ERRLOG("WHOA3 : %s", strerror(errno));
break;
}
} else {
//LOG("reallocating json tokens ...");
numTokens <<= 1;
jsmntok_t *newTokens = realloc(jsonTokens, numTokens * sizeof(jsmntok_t));
memset(newTokens, '\0', numTokens * sizeof(jsmntok_t));
if (!newTokens) {
ERRLOG("WHOA4 : %s", strerror(errno));
break;
}
jsonTokens = newTokens;
}
jsmn_init(&parser);
errCount = jsmn_parse(&parser, jsonString, jsonLen, jsonTokens, numTokens-(numTokens/2));
} while (errCount == JSMN_ERROR_NOMEM);
if (errCount == JSMN_ERROR_NOMEM) {
break;
}
if (errCount < 0) {
ERRLOG("%s", "OOPS error parsing JSON : ");
switch (errCount) {
case JSMN_ERROR_NOMEM:
assert(0 && "should not happen");
break;
case JSMN_ERROR_INVAL:
ERRLOG("%s", "Invalid character inside JSON string");
break;
case JSMN_ERROR_PART:
ERRLOG("%s", "String is not a complete JSON packet, moar bytes expected");
break;
default:
ERRLOG("UNKNOWN errCount : %d", errCount);
break;
}
break;
}
parsedData->jsonString = jsonString;
parsedData->jsonTokens = jsonTokens;
} while (0);
if (fd > 0) {
TEMP_FAILURE_RETRY(close(fd));
fd = 0;
}
if (errCount < 0) {
if (jsonString) {
FREE(jsonString);
}
if (jsonTokens) {
FREE(jsonTokens);
}
}
return errCount;
}
void json_destroy(JSON_s *parsedData) {
FREE(parsedData->jsonString);
FREE(parsedData->jsonTokens);
}
#if TEST_JSON
bool do_logging = true;
FILE *error_log = NULL;
// Runs jsmn against an arbitrary a test_file.json
int main(int argc, char **argv) {
error_log = stderr;
if (argc < 2) {
fprintf(stderr, "Please specify a JSON file to parse on CLI, e.g. : %s path/to/some_file.json\n", argv[0]);
exit(1);
}
JSON_s parsedData = { 0 };
int tokCount = json_createFromFile(argv[1], &parsedData);
if (tokCount < 0) {
return 1;
}
fprintf(stderr, "TOK COUNT:%d\n", tokCount);
for (int i=0; i<tokCount; i++) {
fprintf(stderr, "%s", "type:");
switch(parsedData.jsonTokens[i].type) {
case JSMN_PRIMITIVE:
fprintf(stderr, "%s", "PRIMITIVE ");
break;
case JSMN_OBJECT:
fprintf(stderr, "%s", "OBJECT ");
break;
case JSMN_ARRAY:
fprintf(stderr, "%s", "ARRAY ");
break;
case JSMN_STRING:
fprintf(stderr, "%s", "STRING ");
break;
default:
fprintf(stderr, "%s", "UNKNOWN ");
break;
}
int start = parsedData.jsonTokens[i].start;
int end = parsedData.jsonTokens[i].end;
fprintf(stderr, "start:%6d end:%6d size:%6d parent:%3d", start, end, parsedData.jsonTokens[i].size, parsedData.jsonTokens[i].parent);
if (parsedData.jsonTokens[i].type == JSMN_STRING) {
char lastChar = parsedData.jsonString[end];
parsedData.jsonString[end] = '\0';
fprintf(stderr, " VALUE:%s", &parsedData.jsonString[start]);
parsedData.jsonString[end] = lastChar;
}
fprintf(stderr, "%s", "\n");
}
return 0;
}
#endif