Viewing file: json_parser.c (17.14 KB) -rw-r--r-- Select action/file-type: (+) | (+) | (+) | Code (+) | Session (+) | (+) | SDB (+) | (+) | (+) | (+) | (+) | (+) |
/* File: json_parser.c * */ #include <ctype.h> #include <string.h> #include "json_parser.h"
/* Forward declarations */ static JSON_Array_t *ParseJSONArray(char **strptr); static void FreeJSONValue(JSON_Value_t* v); static void FreeJSONPair(JSON_Pair_t *p); static void FreeJSONArray(JSON_Array_t *obj); static void DisplayObject(FILE *f, JSON_Object_t *obj, int offset); static void DisplayPair(FILE*f, JSON_Pair_t *p, int offset); static void DisplayValue(FILE* f, JSON_Value_t *v, int offset); static void DisplayArray(FILE *f, JSON_Array_t *a, int offset);
/* * Extract a JSON string from our input. * * Note that this routine is somewhat simplistic in * that it makes no effort to deal with escaped characters * (other than \") or Unicode, but simply copies everything * between quotes. In a production environment, this * would have to be smarter. * * Parameter: * strptr - The pointer into the text we're parsing * * Returns: The extracted string. */ static char *ParseJSONString(char **strptr) { char *ret =NULL; char *p1 = *strptr; char *p2; char lastchr; size_t len;
/* Skip any leading spaces */ while (*p1 && isspace(*p1)) p1++; /* Then swallow the leading quote. */ if (*p1++ != '"') return NULL;
/* Now scan forward for the first unscaped quote */ lastchr = '\0'; p2 = p1; while (*p2) { if ((*p2 == '"') && (lastchr != '\\')) break; lastchr = *p2++; } /* and copy the string we found */ len = p2-p1; ret = (char*)malloc(len+1); if (ret){ memcpy(ret, p1, len); ret[len] = '\0'; *strptr = p2+1; } return ret; }
/* * Extract a number. * * Interpret the text at *strptr as a number. * Note that no error checking is done. * * Parameter: * strptr - The pointer into the text we're parsing * * Returns: The extracted number. */ static double ParseJSONNumber(char **strptr) { char *p = *strptr; return strtod(p, strptr); }
/* * Extract an Value. * * Interpret the text at *strptr as an arbitrary * JSON Value. * * Parameter: * strptr - The pointer into the text we're parsing * * Returns: The extracted value, or NULL if an error. */ static JSON_Value_t *ParseJSONValue(char **strptr) { char *p1 = *strptr; JSON_Value_t *ret;
/* skip whitespace */ while (*p1 && isspace(*p1)) p1++; if (*p1 == '\0') return NULL;
/* allocte the JSON_Value_t we're going to return */ ret = (JSON_Value_t*)malloc(sizeof(JSON_Value_t));
/* now, examine the leading text to ascertain what sort of * value we have. */ if (*p1 == '"') { /* If a quote, then it's a string */ ret->u.string = ParseJSONString(&p1); ret->type = (ret->u.string) ? JSON_TYPE_STRING : JSON_TYPE_ERROR; } else if (isdigit(*p1) || *p1 == '+' || *p1 == '-') { /* If a digit or a sign, then it's a number */ ret->u.number = ParseJSONNumber(&p1); ret->type = JSON_TYPE_NUMBER ; } else if (*p1 == '{') { /* If a brace, then it's an object */ ret->u.obj = ParseJSONObject(&p1); ret->type = (ret->u.obj) ? JSON_TYPE_OBJECT : JSON_TYPE_ERROR; } else if (*p1 == '[') { /* If a square bracket, then it's an array */ ret->u.array = ParseJSONArray(&p1); ret->type = (ret->u.array) ? JSON_TYPE_ARRAY : JSON_TYPE_ERROR; } else if (!strncasecmp(p1,"true", 4)) { ret->u.number = 1; ret->type = JSON_TYPE_BOOL; p1 += 4; } else if (!strncasecmp(p1,"false", 5)) { ret->u.number = 0; ret->type = JSON_TYPE_BOOL; p1 += 5; } else if (!strncasecmp(p1,"null", 4)) { ret->type = JSON_TYPE_NULL; p1 += 4; } if ( ret->type == JSON_TYPE_ERROR){ free(ret); ret = NULL; } /* remember where we left off scanning */ *strptr = p1; return ret; }
/* * Extract a Pair. * * Interpret the text at *strptr as a JSON pair * * Parameter: * strptr - The pointer into the text we're parsing * * Returns: The extracted pair, or NULL if an error. */ static JSON_Pair_t *ParseJSONPair(char **strptr) { char *p = *strptr; char *name=NULL; JSON_Value_t *value=NULL; JSON_Pair_t *ret=NULL;
/* extract the name part */ name = ParseJSONString(&p); if (name) { /* then look for the colon */ while(*p && isspace(*p)) ++p; if ( *p == ':') { /* if we found the colon extract the value */ ++p; value = ParseJSONValue(&p); } if (value == NULL) { free(name); name = NULL; } } if (value) { /* If we got the name and value, allocate our JSON_Pair_t * and set the fields */ ret = (JSON_Pair_t*)malloc(sizeof(JSON_Pair_t)); ret->name = name; ret->value = value; } /* remember where we left off */ *strptr = p; return ret; }
/* * Interpret the text at *strptr as a JSON Object. * * A JSON object is represented as a list of JSON N-V Pairs, * So this routine recursively calls ParseJSONPair to * build up that list. * * If a parse error is encountered, NULL is returned and * strptr points to the region in the input string where * the error occurred. * * Parameter: * strptr - The pointer into the text we're parsing * * Returns: The extracted object, or NULL if an error. */ JSON_Object_t *ParseJSONObject(char **strptr) { int ok = 0; char *p = *strptr; JSON_Object_t *ret = NULL; /* Skip leading white space */ while(*p && isspace(*p)) ++p; /* Swallow leading brace */ if ( *p++ != '{') return NULL;
/* allocate the object we're going to return */ ret = (JSON_Object_t*)malloc(sizeof(JSON_Object_t)); if (ret) { JSON_Pair_t *pair; ret->num_pairs = 0; ret->pairs = NULL; /* No, scan through the input string, extracting * pairs until we hit the closing brace */ while(1) { while(*p && isspace(*p)) p++; /* if closing brace, we're done */ if (*p == '}') { p++; ok = 1; break; } else { /* if this is not the first pair we've seen, swallow * the seperating comma */ if (*p != ',') { if (ret->num_pairs > 0) break; } else if (ret->num_pairs == 0) { break; } else { ++p; } /* fetch the next pair */ pair = ParseJSONPair(&p); if ( pair) { /* add it to our array */ JSON_Pair_t **newpairs; newpairs = realloc(ret->pairs, (1+ret->num_pairs) * sizeof(JSON_Pair_t*)); if (newpairs) { newpairs[ret->num_pairs] = pair; ret->num_pairs += 1; ret->pairs = newpairs; }else{ break; } } else { break; } } } /* If parse failed, dispose of our allocated object */ if (!ok ) { FreeJSONObject(ret); ret = NULL; } } /* Remember where we left off */ *strptr = p; return ret; }
/* * Interpret the text at *strptr as a JSON Array. * * A JSON array is represented as a list of JSON values * So this routine recursively calls ParseJSONValue * build up that list. * * Parameter: * strptr - The pointer into the text we're parsing * * Returns: The extracted object, or NULL if an error. */ static JSON_Array_t *ParseJSONArray(char **strptr) { int ok = 0; char *p = *strptr; JSON_Array_t *ret = NULL; /* Skip leading white space */ while(*p && isspace(*p)) ++p; /* Swallow leading bracket */ if ( *p++ != '[') return NULL;
/* allocate the array we're going to return */ ret = (JSON_Array_t*)malloc(sizeof(JSON_Array_t)); if (ret) { JSON_Value_t *value; ret->num_values = 0; ret->values = NULL; /* No, scan through the input string, extracting * values until we hit the closing bracket */ while(1) { while(*p && isspace(*p)) p++; /* if closing bracket, we're done */ if (*p == ']') { p++; ok = 1; break; } else { /* if this is not the first value we've seen, swallow * the seperating comma */ if (*p != ',') { if (ret->num_values > 0) break; } else if (ret->num_values == 0) { break; } else { ++p; } /* Fetch the next value */ value = ParseJSONValue(&p); if ( value) { /* add it to our array */ JSON_Value_t **newvalues; newvalues = realloc(ret->values, (1+ret->num_values) * sizeof(JSON_Value_t*)); if (newvalues) { newvalues[ret->num_values] = value; ret->num_values += 1; ret->values = newvalues; }else{ break; } } else { break; } } } /* If parse failed, dispose of our allocated object */ if (!ok ) { FreeJSONArray(ret); ret = NULL; } } /* Remember where we left off */ *strptr = p; return ret; }
/* * Release a JSON Value allocated by ParseJSONValue() * * Parameter: * v - the value to release */ void FreeJSONValue(JSON_Value_t* v) { if (v) { if (v->type == JSON_TYPE_OBJECT) FreeJSONObject(v->u.obj); else if (v->type == JSON_TYPE_ARRAY) FreeJSONArray(v->u.array); else if (v->type == JSON_TYPE_STRING) free(v->u.string); free(v); } }
/* * * Release a JSON pair allocatd by ParseJSONPair() * * Parameter: * p - the pair to release */ static void FreeJSONPair(JSON_Pair_t *p) { if (p) { free(p->name); FreeJSONValue(p->value); free(p); } }
/* * Release a JSON Object allocatd by ParseJSONObject() * * Parameter: * obj - The object to release */ void FreeJSONObject(JSON_Object_t *obj) { if (obj) { size_t i; for (i = 0; i < obj->num_pairs; ++i) FreeJSONPair((obj->pairs)[i]); free(obj->pairs); free(obj); } }
/* * * Release a JSON array allocatd by ParseJSONArray() * * Parameter: * a - the array to release */ static void FreeJSONArray(JSON_Array_t *a) { if (a) { size_t i; for (i = 0; i < a->num_values; ++i) FreeJSONValue((a->values)[i]); free(a->values); free(a); } }
/* * Format a JSON Value an write it to a stream * * Parameters: * f - The output stream * v - the value to format */ void DisplayJSONValue(FILE* f, JSON_Value_t *v) { DisplayValue(f, v, 0); }
/* * Format a JSON Object an write it to a stream * * Parameters: * f - The output stream * obj - the object to format */ void DisplayJSONObject(FILE *f, JSON_Object_t *obj) { DisplayObject(f, obj, 0); }
/* * Pretty print an Object * * Format a JSON Object and write it to a stream. * Since this can be called recursively, it takes * an offset to indicate how far to space the output * off of the left margin. * * Parameters: * f - The output stream * obj - the object to format * offset - The offset from the margin */ static void DisplayObject(FILE *f, JSON_Object_t *obj, int offset) { if (obj->num_pairs == 0) { fprintf(f, "{}\n"); } else { size_t j; int k; printf("{\n"); for (j = 0; j < obj->num_pairs; ++j) { DisplayPair(f, obj->pairs[j], offset+1); if (j != obj->num_pairs-1) putc(',', f); putc('\n', f); } for (k = 0; k < offset; ++k) fputs(" ", f); printf("}"); } }
/* * Pretty print an Array * * Format a JSON Array an write it to a stream. * Since this can be called recursively, it takes * an offset to indicate how far to space the output * off of the left margin. * * Parameters: * f - The output stream * a - the array to format * offset - The offset from the margin */ void DisplayArray(FILE *f, JSON_Array_t *a, int offset) { if (a->num_values == 0) { fprintf(f, "[]\n"); } else { size_t j; int k; printf("[\n"); for (j = 0; j < a->num_values; ++j) { int i; for (i = 0; i < offset+1; ++i) fputs(" ", f); DisplayValue(f, a->values[j], offset+1); if (j != a->num_values-1) putc(',', f); putc('\n',f); } for (k = 0; k < offset; ++k) fputs(" ", f); printf("]"); } }
/* * Pretty print a Pair. * * Format a JSON Pair an write it to a stream. * Since this can be called recursively, it takes * an offset to indicate how far to space the output * off of the left margin. * * Parameters: * f - The output stream * p - the pair to format * offset - The offset from the margin */ static void DisplayPair(FILE*f, JSON_Pair_t *p, int offset) { int i; for (i = 0; i < offset; ++i) fputs(" ", f); fprintf(f, "\"%s\": ", p->name); DisplayValue(f, p->value, offset); }
/* * Pretty print a Value. * * Format a JSON Value an write it to a stream. * Since this can be called recursively, it takes * an offset to indicate how far to space the output * off of the left margin. * * Parameters: * f - The output stream * v - the value to format * offset - The offset from the margin */ static void DisplayValue(FILE* f, JSON_Value_t *v, int offset) { switch(v->type) { case JSON_TYPE_NULL: fprintf(f, "null"); break; case JSON_TYPE_STRING: fprintf(f, "\"%s\"", v->u.string); break; case JSON_TYPE_NUMBER: if (((double)((int)v->u.number)) == v->u.number) fprintf(f, "%d", (int)v->u.number); else fprintf(f, "%f", v->u.number); break; case JSON_TYPE_BOOL: fprintf(f, (v->u.number) ? "true" : "false"); break; case JSON_TYPE_OBJECT: DisplayObject(f, v->u.obj, offset); break; case JSON_TYPE_ARRAY: DisplayArray(f, v->u.array, offset); break; } }
/* * * Find a specific named value in an object. * This function searches the object for a value * with the given name. If found return the value, * if not return NULL. * * Parameters: * obj - The object to search * name - The name to search for. * * Returns: The found value, or NULL */ JSON_Value_t *Find(JSON_Object_t *obj, char *name) { size_t i; for (i = 0; i < obj->num_pairs; ++i) { JSON_Pair_t *p = obj->pairs[i]; if (!strcmp(name, p->name)) return p->value; } return NULL; }
/* * Find a specific named value in an object. * This function does a breadth-first deep search * of an object for a value with the given name. * If first searches the object in the same manner * as Find(). If the value is found it is returned. * If the value is not found, then this function recursively * calls itself on any objects contained in this object. * If this object contains no objects, then the function * returns NULL. * * Parameters: * obj - The object to search * name - The name to search for. * * Returns: The found value, or NULL */ JSON_Value_t *DeepFind(JSON_Object_t *obj, char *name) { size_t i; for (i = 0; i < obj->num_pairs; ++i) { JSON_Pair_t *p = obj->pairs[i]; if (!strcmp(name, p->name)) return p->value; } for (i = 0; i < obj->num_pairs; ++i) { JSON_Pair_t *p = obj->pairs[i]; if (p->value->type == JSON_TYPE_OBJECT) { JSON_Value_t *v = DeepFind(p->value->u.obj, name); if (v) return v; } } return NULL; }
/* * Return the pair indexed by idx from a JSON object. If idx is * too large, return NULL. * * Parameters: * obj - The object * idx - The index * * Returns: The specified pair, or NULL */ JSON_Pair_t *GetPairFromObject(JSON_Object_t *obj, unsigned idx) { return idx < obj->num_pairs ? obj->pairs[idx] : NULL; }
/* * Return the value indexed by idx from a JSON Array. If idx is * too large, return NULL. * * Parameters: * arr - The array * idx - The index * * Returns: The specified value, or NULL */ JSON_Value_t *GetValueFromArray(JSON_Array_t *arr, unsigned idx) { return idx < arr->num_values ? arr->values[idx] : NULL; }
|