aJson is the attempt to port a complete JSON implementation to Arduino. It is based on the cJSON implementation, reduced in size and removing one or two feature. The current mbed implementation only supports FILE* as input so you will have to use a temporary file for parsing your json input. https://github.com/interactive-matter/aJson
Revision 1:6df1d1f1b372, committed 2012-08-28
- Comitter:
- mimil
- Date:
- Tue Aug 28 08:16:29 2012 +0000
- Parent:
- 0:428cf9a51873
- Child:
- 2:ece3b5c4afed
- Commit message:
- first release of aJSON library for mbed
Changed in this revision
--- a/aJSON.cpp Mon Aug 27 15:15:45 2012 +0000 +++ b/aJSON.cpp Tue Aug 28 08:16:29 2012 +0000 @@ -1,1201 +1,1201 @@ -/* - Copyright (c) 2001, Interactive Matter, Marcus Nowotny - - Based on the cJSON Library, Copyright (C) 2009 Dave Gamble - - 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. - */ - -// aJSON -// aJson Library for Arduino. -// This library is suited for Atmega328 based Arduinos. -// The RAM on ATmega168 based Arduinos is too limited - -/****************************************************************************** - * Includes - ******************************************************************************/ - -#include <string.h> -#include <math.h> -#include <stdlib.h> -#include <float.h> -#include <ctype.h> -//#include <avr/pgmspace.h> -#include "aJSON.h" -#include "utility/streamhelper.h" -#include "utility/stringbuffer.h" - -#include "compatibility.h" -#include "stdio.h" - -/****************************************************************************** - * Definitions - ******************************************************************************/ -//Default buffer sizes - buffers get initialized and grow acc to that size -#define BUFFER_DEFAULT_SIZE 4 - -//how much digits after . for float -#define FLOAT_PRECISION 5 - - - - - - -// Internal constructor. -aJsonObject* -aJsonClass::newItem() -{ - aJsonObject* node = (aJsonObject*) malloc(sizeof(aJsonObject)); - if (node) - memset(node, 0, sizeof(aJsonObject)); - return node; -} - -// Delete a aJsonObject structure. -void -aJsonClass::deleteItem(aJsonObject *c) -{ - aJsonObject *next; - while (c) - { - next = c->next; - if (!(c->type & aJson_IsReference) && c->child) - { - deleteItem(c->child); - } - if ((c->type == aJson_String) && c->valuestring) - { - free(c->valuestring); - } - if (c->name) - { - free(c->name); - } - free(c); - c = next; - } -} - -// Parse the input text to generate a number, and populate the result into item. -int -aJsonClass::parseNumber(aJsonObject *item, FILE* stream) -{ - int i = 0; - char sign = 1; - - int in = fgetc(stream); - if (in == EOF) - { - return EOF; - } - // It is easier to decode ourselves than to use sscnaf, - // since so we can easier decide between int & double - if (in == '-') - { - //it is a negative number - sign = -1; - in = fgetc(stream); - if (in == EOF) - { - return EOF; - } - } - if (in >= '0' && in <= '9') - do - { - i = (i * 10) + (in - '0'); - in = fgetc(stream); - } - while (in >= '0' && in <= '9'); // Number? - //end of integer part � or isn't it? - if (!(in == '.' || in == 'e' || in == 'E')) - { - item->valueint = i * (int) sign; - item->type = aJson_Int; - } - //ok it seems to be a double - else - { - double n = (double) i; - int scale = 0; - int subscale = 0; - char signsubscale = 1; - if (in == '.') - { - in = fgetc(stream); - do - { - n = (n * 10.0) + (in - '0'), scale--; - in = fgetc(stream); - } - while (in >= '0' && in <= '9'); - } // Fractional part? - if (in == 'e' || in == 'E') // Exponent? - { - in = fgetc(stream); - if (in == '+') - { - in = fgetc(stream); - } - else if (in == '-') - { - signsubscale = -1; - in = fgetc(stream); - } - while (in >= '0' && in <= '9') - { - subscale = (subscale * 10) + (in - '0'); // Number? - in = fgetc(stream); - } - } - - n = sign * n * pow(10.0, ((double) scale + (double) subscale - * (double) signsubscale)); // number = +/- number.fraction * 10^+/- exponent - - item->valuefloat = n; - item->type = aJson_Float; - } - //preserve the last character for the next routine - ungetc(in, stream); - return 0; -} - -// Render the number nicely from the given item into a string. -int -aJsonClass::printInt(aJsonObject *item, FILE* stream) -{ - if (item != NULL) - { - return fprintf_P(stream, PSTR("%d"), item->valueint); - } - //printing nothing is ok - return 0; -} - -int -aJsonClass::printFloat(aJsonObject *item, FILE* stream) -{ - if (item != NULL) - { - double d = item->valuefloat; - if (d<0.0) { - fprintf_P(stream,PSTR("-")); - d=-d; - } - //print the integer part - unsigned long integer_number = (unsigned long)d; - fprintf_P(stream,PSTR("%u."),integer_number); - //print the fractional part - double fractional_part = d - ((double)integer_number); - //we do a do-while since we want to print at least one zero - //we just support a certain number of digits after the '.' - int n = FLOAT_PRECISION; - fractional_part += 0.5/pow(10.0, FLOAT_PRECISION); - do { - //make the first digit non fractional(shift it before the '.' - fractional_part *= 10.0; - //create an int out of it - unsigned int digit = (unsigned int) fractional_part; - //print it - fprintf_P(stream,PSTR("%u"),digit); - //remove it from the number - fractional_part -= (double)digit; - n--; - } while ((fractional_part!=0) && (n>0)); - } - //printing nothing is ok - return 0; -} - -// Parse the input text into an unescaped cstring, and populate item. -int -aJsonClass::parseString(aJsonObject *item, FILE* stream) -{ - //we do not need to skip here since the first byte should be '\"' - int in = fgetc(stream); - if (in != '\"') - { - return EOF; // not a string! - } - item->type = aJson_String; - //allocate a buffer & track how long it is and how much we have read - string_buffer* buffer = stringBufferCreate(); - if (buffer == NULL) - { - //unable to allocate the string - return EOF; - } - in = fgetc(stream); - if (in == EOF) - { - stringBufferFree(buffer); - return EOF; - } - while (in != EOF) - { - while (in != '\"' && in >= 32) - { - if (in != '\\') - { - stringBufferAdd((char) in, buffer); - } - else - { - in = fgetc(stream); - if (in == EOF) - { - stringBufferFree(buffer); - return EOF; - } - switch (in) - { - case '\\': - stringBufferAdd('\\', buffer); - break; - case '\"': - stringBufferAdd('\"', buffer); - break; - case 'b': - stringBufferAdd('\b', buffer); - break; - case 'f': - stringBufferAdd('\f', buffer); - break; - case 'n': - stringBufferAdd('\n', buffer); - break; - case 'r': - stringBufferAdd('\r', buffer); - break; - case 't': - stringBufferAdd('\t', buffer); - break; - default: - //we do not understand it so we skip it - break; - } - } - in = fgetc(stream); - if (in == EOF) - { - stringBufferFree(buffer); - return EOF; - } - } - //the string ends here - item->valuestring = stringBufferToString(buffer); - return 0; - } - //we should not be here but it is ok - return 0; -} - -// Render the cstring provided to an escaped version that can be printed. -int -aJsonClass::printStringPtr(const char *str, FILE* stream) -{ - if (fputc('\"', stream) == EOF) - { - return EOF; - } - char* ptr = (char*) str; - if (ptr != NULL) - { - while (*ptr != 0) - { - if ((unsigned char) *ptr > 31 && *ptr != '\"' && *ptr != '\\') - { - if (fputc(*ptr, stream) == EOF) - { - return EOF; - } - ptr++; - } - else - { - if (fputc('\\', stream) == EOF) - { - return EOF; - } - switch (*ptr++) - { - case '\\': - if (fputc('\\', stream) == EOF) - { - return EOF; - } - break; - case '\"': - if (fputc('\"', stream) == EOF) - { - return EOF; - } - break; - case '\b': - if (fputc('b', stream) == EOF) - { - return EOF; - } - break; - case '\f': - if (fputc('f', stream) == EOF) - { - return EOF; - } - break; - case '\n': - if (fputc('n', stream) == EOF) - { - return EOF; - } - break; - case '\r': - if (fputc('r', stream) == EOF) - { - return EOF; - } - break; - case '\t': - if (fputc('t', stream) == EOF) - { - return EOF; - } - break; - default: - break; // eviscerate with prejudice. - } - } - - } - } - if (fputc('\"', stream) == EOF) - { - return EOF; - } - return 0; -} - -// Invote print_string_ptr (which is useful) on an item. -int -aJsonClass::printString(aJsonObject *item, FILE* stream) -{ - return printStringPtr(item->valuestring, stream); -} - -// Utility to jump whitespace and cr/lf -int -aJsonClass::skip(FILE* stream) -{ - if (stream == NULL) - { - return EOF; - } - int in = fgetc(stream); - while (in != EOF && (in <= 32)) - { - in = fgetc(stream); - } - if (in != EOF) - { - if (ungetc(in, stream) == EOF) - { - return EOF; - } - return 0; - } - return EOF; -} - -// Parse an object - create a new root, and populate. -/*aJsonObject* -aJsonClass::parse(char *value) -{ - FILE* string_input_stream = openStringInputStream(value); - aJsonObject* result = parse(string_input_stream, NULL); - closeStringInputStream(string_input_stream); - return result; -}*/ - -// Parse an object - create a new root, and populate. -aJsonObject* -aJsonClass::parse(FILE* stream) -{ - return parse(stream, NULL); -} - -// Parse an object - create a new root, and populate. -aJsonObject* -aJsonClass::parse(FILE* stream, char** filter) -{ - if (stream == NULL) - { - return NULL; - } - aJsonObject *c = newItem(); - if (!c) - return NULL; /* memory fail */ - - skip(stream); - if (parseValue(c, stream, filter) == EOF) - { - deleteItem(c); - return NULL; - } - return c; -} - -// Render a aJsonObject item/entity/structure to text. -int -aJsonClass::print(aJsonObject* item, FILE* stream) -{ - return printValue(item, stream); -} - -/*char* -aJsonClass::print(aJsonObject* item) -{ - FILE* stream = openStringOutputStream(); - if (stream == NULL) - { - return NULL; - } - print(item, stream); - return closeStringOutputStream(stream); -}*/ - -// Parser core - when encountering text, process appropriately. -int -aJsonClass::parseValue(aJsonObject *item, FILE* stream, char** filter) -{ - if (stream == NULL) - { - return EOF; // Fail on null. - } - if (skip(stream) == EOF) - { - return EOF; - } - //read the first byte from the stream - int in = fgetc(stream); - if (in == EOF) - { - return EOF; - } - if (ungetc(in, stream) == EOF) - { - return EOF; - } - if (in == '\"') - { - return parseString(item, stream); - } - else if (in == '-' || (in >= '0' && in <= '9')) - { - return parseNumber(item, stream); - } - else if (in == '[') - { - return parseArray(item, stream, filter); - } - else if (in == '{') - { - return parseObject(item, stream, filter); - } - //it can only be null, false or true - else if (in == 'n') - { - //a buffer to read the value - char buffer[] = - { 0, 0, 0, 0 }; - if (fread(buffer, sizeof(char), 4, stream) != 4) - { - return EOF; - } - if (!strncmp(buffer, "null", 4)) - { - item->type = aJson_NULL; - return 0; - } - else - { - return EOF; - } - } - else if (in == 'f') - { - //a buffer to read the value - char buffer[] = - { 0, 0, 0, 0, 0 }; - if (fread(buffer, sizeof(char), 5, stream) != 5) - { - return EOF; - } - if (!strncmp(buffer, "false", 5)) - { - item->type = aJson_False; - item->valuebool = 0; - return 0; - } - } - else if (in == 't') - { - //a buffer to read the value - char buffer[] = - { 0, 0, 0, 0 }; - if (fread(buffer, sizeof(char), 4, stream) != 4) - { - return EOF; - } - if (!strncmp(buffer, "true", 4)) - { - item->type = aJson_True; - item->valuebool = -1; - return 0; - } - } - - return EOF; // failure. -} - -// Render a value to text. -int -aJsonClass::printValue(aJsonObject *item, FILE* stream) -{ - int result = 0; - if (item == NULL) - { - //nothing to do - return 0; - } - switch (item->type) - { - case aJson_NULL: - result = fprintf_P(stream, PSTR("null")); - break; - case aJson_False: - result = fprintf_P(stream, PSTR("false")); - break; - case aJson_True: - result = fprintf_P(stream, PSTR("true")); - break; - case aJson_Int: - result = printInt(item, stream); - break; - case aJson_Float: - result = printFloat(item, stream); - break; - case aJson_String: - result = printString(item, stream); - break; - case aJson_Array: - result = printArray(item, stream); - break; - case aJson_Object: - result = printObject(item, stream); - break; - } - //good time to flush the stream - fflush(stream); - return result; -} - -// Build an array from input text. -int -aJsonClass::parseArray(aJsonObject *item, FILE* stream, char** filter) -{ - int in = fgetc(stream); - if (in != '[') - { - return EOF; // not an array! - } - - item->type = aJson_Array; - skip(stream); - in = fgetc(stream); - //check for empty array - if (in == ']') - { - return 0; // empty array. - } - //now put back the last character - ungetc(in, stream); - aJsonObject *child; - char first = -1; - while ((first) || (in == ',')) - { - aJsonObject *new_item = newItem(); - if (new_item == NULL) - { - return EOF; // memory fail - } - if (first) - { - item->child = new_item; - first = 0; - } - else - { - child->next = new_item; - new_item->prev = child; - } - child = new_item; - skip(stream); - if (parseValue(child, stream, filter)) - { - return EOF; - } - skip(stream); - in = fgetc(stream); - } - if (in == ']') - { - return 0; // end of array - } - else - { - return EOF; // malformed. - } -} - -// Render an array to text -int -aJsonClass::printArray(aJsonObject *item, FILE* stream) -{ - if (item == NULL) - { - //nothing to do - return 0; - } - aJsonObject *child = item->child; - if (fputc('[', stream) == EOF) - { - return EOF; - } - while (child) - { - if (printValue(child, stream) == EOF) - { - return EOF; - } - child = child->next; - if (child) - { - if (fputc(',', stream) == EOF) - { - return EOF; - } - } - } - if (fputc(']', stream) == EOF) - { - return EOF; - } - return 0; -} - -// Build an object from the text. -int -aJsonClass::parseObject(aJsonObject *item, FILE* stream, char** filter) -{ - int in = fgetc(stream); - if (in != '{') - { - return EOF; // not an object! - } - - item->type = aJson_Object; - skip(stream); - //check for an empty object - in = fgetc(stream); - if (in == '}') - { - return 0; // empty object. - } - //preserve the char for the next parser - ungetc(in, stream); - - aJsonObject* child; - char first = -1; - while ((first) || (in == ',')) - { - //in = fgetc(stream); - aJsonObject* new_item = newItem(); - if (new_item == NULL) - { - return EOF; // memory fail - } - if (first) - { - first = 0; - item->child = new_item; - } - else - { - child->next = new_item; - new_item->prev = child; - } - child = new_item; - skip(stream); - if (parseString(child, stream) == EOF) - { - return EOF; - } - skip(stream); - child->name = child->valuestring; - child->valuestring = NULL; - - in = fgetc(stream); - if (in != ':') - { - return EOF; // fail! - } - // skip any spacing, get the value. - skip(stream); - if (parseValue(child, stream, filter) == EOF) - { - return EOF; - } - in = fgetc(stream); - } - - if (in == '}') - { - return 0; // end of array - } - else - { - return EOF; // malformed. - } -} - -// Render an object to text. -int -aJsonClass::printObject(aJsonObject *item, FILE* stream) -{ - if (item == NULL) - { - //nothing to do - return 0; - } - aJsonObject *child = item->child; - if (fputc('{', stream) == EOF) - { - return EOF; - } - while (child) - { - if (printStringPtr(child->name, stream) == EOF) - { - return EOF; - } - if (fputc(':', stream) == EOF) - { - return EOF; - } - if (printValue(child, stream) == EOF) - { - return EOF; - } - child = child->next; - if (child) - { - if (fputc(',', stream) == EOF) - { - return EOF; - } - } - } - if (fputc('}', stream) == EOF) - { - return EOF; - } - return 0; -} - -// Get Array size/item / object item. -unsigned char -aJsonClass::getArraySize(aJsonObject *array) -{ - aJsonObject *c = array->child; - unsigned char i = 0; - while (c) - i++, c = c->next; - return i; -} -aJsonObject* -aJsonClass::getArrayItem(aJsonObject *array, unsigned char item) -{ - aJsonObject *c = array->child; - while (c && item > 0) - item--, c = c->next; - return c; -} -aJsonObject* -aJsonClass::getObjectItem(aJsonObject *object, const char *string) -{ - aJsonObject *c = object->child; - while (c && strcasecmp(c->name, string)) - c = c->next; - return c; -} - -// Utility for array list handling. -void -aJsonClass::suffixObject(aJsonObject *prev, aJsonObject *item) -{ - prev->next = item; - item->prev = prev; -} -// Utility for handling references. -aJsonObject* -aJsonClass::createReference(aJsonObject *item) -{ - aJsonObject *ref = newItem(); - if (!ref) - return 0; - memcpy(ref, item, sizeof(aJsonObject)); - ref->name = 0; - ref->type |= aJson_IsReference; - ref->next = ref->prev = 0; - return ref; -} - -// Add item to array/object. -void -aJsonClass::addItemToArray(aJsonObject *array, aJsonObject *item) -{ - aJsonObject *c = array->child; - if (!item) - return; - if (!c) - { - array->child = item; - } - else - { - while (c && c->next) - c = c->next; - suffixObject(c, item); - } -} -void -aJsonClass::addItemToObject(aJsonObject *object, const char *string, - aJsonObject *item) -{ - if (!item) - return; - if (item->name) - free(item->name); - item->name = strdup(string); - addItemToArray(object, item); -} -void -aJsonClass::addItemReferenceToArray(aJsonObject *array, aJsonObject *item) -{ - addItemToArray(array, createReference(item)); -} -void -aJsonClass::addItemReferenceToObject(aJsonObject *object, const char *string, - aJsonObject *item) -{ - addItemToObject(object, string, createReference(item)); -} - -aJsonObject* -aJsonClass::detachItemFromArray(aJsonObject *array, unsigned char which) -{ - aJsonObject *c = array->child; - while (c && which > 0) - c = c->next, which--; - if (!c) - return 0; - if (c->prev) - c->prev->next = c->next; - if (c->next) - c->next->prev = c->prev; - if (c == array->child) - array->child = c->next; - c->prev = c->next = 0; - return c; -} -void -aJsonClass::deleteItemFromArray(aJsonObject *array, unsigned char which) -{ - deleteItem(detachItemFromArray(array, which)); -} -aJsonObject* -aJsonClass::detachItemFromObject(aJsonObject *object, const char *string) -{ - unsigned char i = 0; - aJsonObject *c = object->child; - while (c && strcasecmp(c->name, string)) - i++, c = c->next; - if (c) - return detachItemFromArray(object, i); - return 0; -} -void -aJsonClass::deleteItemFromObject(aJsonObject *object, const char *string) -{ - deleteItem(detachItemFromObject(object, string)); -} - -// Replace array/object items with new ones. -void -aJsonClass::replaceItemInArray(aJsonObject *array, unsigned char which, - aJsonObject *newitem) -{ - aJsonObject *c = array->child; - while (c && which > 0) - c = c->next, which--; - if (!c) - return; - newitem->next = c->next; - newitem->prev = c->prev; - if (newitem->next) - newitem->next->prev = newitem; - if (c == array->child) - array->child = newitem; - else - newitem->prev->next = newitem; - c->next = c->prev = 0; - deleteItem(c); -} -void -aJsonClass::replaceItemInObject(aJsonObject *object, const char *string, - aJsonObject *newitem) -{ - unsigned char i = 0; - aJsonObject *c = object->child; - while (c && strcasecmp(c->name, string)) - i++, c = c->next; - if (c) - { - newitem->name = strdup(string); - replaceItemInArray(object, i, newitem); - } -} - -// Create basic types: -aJsonObject* -aJsonClass::createNull() -{ - aJsonObject *item = newItem(); - if (item) - item->type = aJson_NULL; - return item; -} - -aJsonObject* -aJsonClass::createTrue() -{ - aJsonObject *item = newItem(); - if (item) - { - item->type = aJson_True; - item->valuebool = -1; - } - return item; -} -aJsonObject* -aJsonClass::createFalse() -{ - aJsonObject *item = newItem(); - if (item) - { - item->type = aJson_False; - item->valuebool = 0; - } - return item; -} -aJsonObject* -aJsonClass::createItem(char b) -{ - aJsonObject *item = newItem(); - if (item) - { - item->type = b ? aJson_True : aJson_False; - item->valuebool = b ? -1 : 0; - } - return item; -} - -aJsonObject* -aJsonClass::createItem(int num) -{ - aJsonObject *item = newItem(); - if (item) - { - item->type = aJson_Int; - item->valueint = (int) num; - } - return item; -} - -aJsonObject* -aJsonClass::createItem(double num) -{ - aJsonObject *item = newItem(); - if (item) - { - item->type = aJson_Float; - item->valuefloat = num; - } - return item; -} - -aJsonObject* -aJsonClass::createItem(const char *string) -{ - aJsonObject *item = newItem(); - if (item) - { - item->type = aJson_String; - item->valuestring = strdup(string); - } - return item; -} - -aJsonObject* -aJsonClass::createArray() -{ - aJsonObject *item = newItem(); - if (item) - item->type = aJson_Array; - return item; -} -aJsonObject* -aJsonClass::createObject() -{ - aJsonObject *item = newItem(); - if (item) - item->type = aJson_Object; - return item; -} - -// Create Arrays: -aJsonObject* -aJsonClass::createIntArray(int *numbers, unsigned char count) -{ - unsigned char i; - aJsonObject *n = 0, *p = 0, *a = createArray(); - for (i = 0; a && i < count; i++) - { - n = createItem(numbers[i]); - if (!i) - a->child = n; - else - suffixObject(p, n); - p = n; - } - return a; -} - -aJsonObject* -aJsonClass::createFloatArray(double *numbers, unsigned char count) -{ - unsigned char i; - aJsonObject *n = 0, *p = 0, *a = createArray(); - for (i = 0; a && i < count; i++) - { - n = createItem(numbers[i]); - if (!i) - a->child = n; - else - suffixObject(p, n); - p = n; - } - return a; -} - -aJsonObject* -aJsonClass::createDoubleArray(double *numbers, unsigned char count) -{ - unsigned char i; - aJsonObject *n = 0, *p = 0, *a = createArray(); - for (i = 0; a && i < count; i++) - { - n = createItem(numbers[i]); - if (!i) - a->child = n; - else - suffixObject(p, n); - p = n; - } - return a; -} - -aJsonObject* -aJsonClass::createStringArray(const char **strings, unsigned char count) -{ - unsigned char i; - aJsonObject *n = 0, *p = 0, *a = createArray(); - for (i = 0; a && i < count; i++) - { - n = createItem(strings[i]); - if (!i) - a->child = n; - else - suffixObject(p, n); - p = n; - } - return a; -} - -void -aJsonClass::addNullToObject(aJsonObject* object, const char* name) -{ - addItemToObject(object, name, createNull()); -} - -void -aJsonClass::addTrueToObject(aJsonObject* object, const char* name) -{ - addItemToObject(object, name, createTrue()); -} - -void -aJsonClass::addFalseToObject(aJsonObject* object, const char* name) -{ - addItemToObject(object, name, createFalse()); -} - -void -aJsonClass::addNumberToObject(aJsonObject* object, const char* name, int n) -{ - addItemToObject(object, name, createItem(n)); -} - -void -aJsonClass::addNumberToObject(aJsonObject* object, const char* name, double n) -{ - addItemToObject(object, name, createItem(n)); -} - -void -aJsonClass::addStringToObject(aJsonObject* object, const char* name, - const char* s) -{ - addItemToObject(object, name, createItem(s)); -} - -//TODO conversion routines btw. float & int types? - -aJsonClass aJson; +/* + Copyright (c) 2001, Interactive Matter, Marcus Nowotny + + Based on the cJSON Library, Copyright (C) 2009 Dave Gamble + + 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. + */ + +// aJSON +// aJson Library for Arduino. +// This library is suited for Atmega328 based Arduinos. +// The RAM on ATmega168 based Arduinos is too limited + +/****************************************************************************** + * Includes + ******************************************************************************/ + +#include <string.h> +#include <math.h> +#include <stdlib.h> +#include <float.h> +#include <ctype.h> +//#include <avr/pgmspace.h> +#include "aJSON.h" +#include "utility/streamhelper.h" +#include "utility/stringbuffer.h" + +#include "compatibility.h" +#include "stdio.h" + +/****************************************************************************** + * Definitions + ******************************************************************************/ +//Default buffer sizes - buffers get initialized and grow acc to that size +#define BUFFER_DEFAULT_SIZE 4 + +//how much digits after . for float +#define FLOAT_PRECISION 5 + + + + + + +// Internal constructor. +aJsonObject* +aJsonClass::newItem() +{ + aJsonObject* node = (aJsonObject*) malloc(sizeof(aJsonObject)); + if (node) + memset(node, 0, sizeof(aJsonObject)); + return node; +} + +// Delete a aJsonObject structure. +void +aJsonClass::deleteItem(aJsonObject *c) +{ + aJsonObject *next; + while (c) + { + next = c->next; + if (!(c->type & aJson_IsReference) && c->child) + { + deleteItem(c->child); + } + if ((c->type == aJson_String) && c->valuestring) + { + free(c->valuestring); + } + if (c->name) + { + free(c->name); + } + free(c); + c = next; + } +} + +// Parse the input text to generate a number, and populate the result into item. +int +aJsonClass::parseNumber(aJsonObject *item, FILE* stream) +{ + int i = 0; + char sign = 1; + + int in = fgetc(stream); + if (in == EOF) + { + return EOF; + } + // It is easier to decode ourselves than to use sscnaf, + // since so we can easier decide between int & double + if (in == '-') + { + //it is a negative number + sign = -1; + in = fgetc(stream); + if (in == EOF) + { + return EOF; + } + } + if (in >= '0' && in <= '9') + do + { + i = (i * 10) + (in - '0'); + in = fgetc(stream); + } + while (in >= '0' && in <= '9'); // Number? + //end of integer part � or isn't it? + if (!(in == '.' || in == 'e' || in == 'E')) + { + item->valueint = i * (int) sign; + item->type = aJson_Int; + } + //ok it seems to be a double + else + { + double n = (double) i; + int scale = 0; + int subscale = 0; + char signsubscale = 1; + if (in == '.') + { + in = fgetc(stream); + do + { + n = (n * 10.0) + (in - '0'), scale--; + in = fgetc(stream); + } + while (in >= '0' && in <= '9'); + } // Fractional part? + if (in == 'e' || in == 'E') // Exponent? + { + in = fgetc(stream); + if (in == '+') + { + in = fgetc(stream); + } + else if (in == '-') + { + signsubscale = -1; + in = fgetc(stream); + } + while (in >= '0' && in <= '9') + { + subscale = (subscale * 10) + (in - '0'); // Number? + in = fgetc(stream); + } + } + + n = sign * n * pow(10.0, ((double) scale + (double) subscale + * (double) signsubscale)); // number = +/- number.fraction * 10^+/- exponent + + item->valuefloat = n; + item->type = aJson_Float; + } + //preserve the last character for the next routine + ungetc(in, stream); + return 0; +} + +// Render the number nicely from the given item into a string. +int +aJsonClass::printInt(aJsonObject *item, FILE* stream) +{ + if (item != NULL) + { + return fprintf_P(stream, PSTR("%d"), item->valueint); + } + //printing nothing is ok + return 0; +} + +int +aJsonClass::printFloat(aJsonObject *item, FILE* stream) +{ + if (item != NULL) + { + double d = item->valuefloat; + if (d<0.0) { + fprintf_P(stream,PSTR("-")); + d=-d; + } + //print the integer part + unsigned long integer_number = (unsigned long)d; + fprintf_P(stream,PSTR("%u."),integer_number); + //print the fractional part + double fractional_part = d - ((double)integer_number); + //we do a do-while since we want to print at least one zero + //we just support a certain number of digits after the '.' + int n = FLOAT_PRECISION; + fractional_part += 0.5/pow(10.0, FLOAT_PRECISION); + do { + //make the first digit non fractional(shift it before the '.' + fractional_part *= 10.0; + //create an int out of it + unsigned int digit = (unsigned int) fractional_part; + //print it + fprintf_P(stream,PSTR("%u"),digit); + //remove it from the number + fractional_part -= (double)digit; + n--; + } while ((fractional_part!=0) && (n>0)); + } + //printing nothing is ok + return 0; +} + +// Parse the input text into an unescaped cstring, and populate item. +int +aJsonClass::parseString(aJsonObject *item, FILE* stream) +{ + //we do not need to skip here since the first byte should be '\"' + int in = fgetc(stream); + if (in != '\"') + { + return EOF; // not a string! + } + item->type = aJson_String; + //allocate a buffer & track how long it is and how much we have read + string_buffer* buffer = stringBufferCreate(); + if (buffer == NULL) + { + //unable to allocate the string + return EOF; + } + in = fgetc(stream); + if (in == EOF) + { + stringBufferFree(buffer); + return EOF; + } + while (in != EOF) + { + while (in != '\"' && in >= 32) + { + if (in != '\\') + { + stringBufferAdd((char) in, buffer); + } + else + { + in = fgetc(stream); + if (in == EOF) + { + stringBufferFree(buffer); + return EOF; + } + switch (in) + { + case '\\': + stringBufferAdd('\\', buffer); + break; + case '\"': + stringBufferAdd('\"', buffer); + break; + case 'b': + stringBufferAdd('\b', buffer); + break; + case 'f': + stringBufferAdd('\f', buffer); + break; + case 'n': + stringBufferAdd('\n', buffer); + break; + case 'r': + stringBufferAdd('\r', buffer); + break; + case 't': + stringBufferAdd('\t', buffer); + break; + default: + //we do not understand it so we skip it + break; + } + } + in = fgetc(stream); + if (in == EOF) + { + stringBufferFree(buffer); + return EOF; + } + } + //the string ends here + item->valuestring = stringBufferToString(buffer); + return 0; + } + //we should not be here but it is ok + return 0; +} + +// Render the cstring provided to an escaped version that can be printed. +int +aJsonClass::printStringPtr(const char *str, FILE* stream) +{ + if (fputc('\"', stream) == EOF) + { + return EOF; + } + char* ptr = (char*) str; + if (ptr != NULL) + { + while (*ptr != 0) + { + if ((unsigned char) *ptr > 31 && *ptr != '\"' && *ptr != '\\') + { + if (fputc(*ptr, stream) == EOF) + { + return EOF; + } + ptr++; + } + else + { + if (fputc('\\', stream) == EOF) + { + return EOF; + } + switch (*ptr++) + { + case '\\': + if (fputc('\\', stream) == EOF) + { + return EOF; + } + break; + case '\"': + if (fputc('\"', stream) == EOF) + { + return EOF; + } + break; + case '\b': + if (fputc('b', stream) == EOF) + { + return EOF; + } + break; + case '\f': + if (fputc('f', stream) == EOF) + { + return EOF; + } + break; + case '\n': + if (fputc('n', stream) == EOF) + { + return EOF; + } + break; + case '\r': + if (fputc('r', stream) == EOF) + { + return EOF; + } + break; + case '\t': + if (fputc('t', stream) == EOF) + { + return EOF; + } + break; + default: + break; // eviscerate with prejudice. + } + } + + } + } + if (fputc('\"', stream) == EOF) + { + return EOF; + } + return 0; +} + +// Invote print_string_ptr (which is useful) on an item. +int +aJsonClass::printString(aJsonObject *item, FILE* stream) +{ + return printStringPtr(item->valuestring, stream); +} + +// Utility to jump whitespace and cr/lf +int +aJsonClass::skip(FILE* stream) +{ + if (stream == NULL) + { + return EOF; + } + int in = fgetc(stream); + while (in != EOF && (in <= 32)) + { + in = fgetc(stream); + } + if (in != EOF) + { + if (ungetc(in, stream) == EOF) + { + return EOF; + } + return 0; + } + return EOF; +} + +// Parse an object - create a new root, and populate. +/*aJsonObject* +aJsonClass::parse(char *value) +{ + FILE* string_input_stream = openStringInputStream(value); + aJsonObject* result = parse(string_input_stream, NULL); + closeStringInputStream(string_input_stream); + return result; +}*/ + +// Parse an object - create a new root, and populate. +aJsonObject* +aJsonClass::parse(FILE* stream) +{ + return parse(stream, NULL); +} + +// Parse an object - create a new root, and populate. +aJsonObject* +aJsonClass::parse(FILE* stream, char** filter) +{ + if (stream == NULL) + { + return NULL; + } + aJsonObject *c = newItem(); + if (!c) + return NULL; /* memory fail */ + + skip(stream); + if (parseValue(c, stream, filter) == EOF) + { + deleteItem(c); + return NULL; + } + return c; +} + +// Render a aJsonObject item/entity/structure to text. +int +aJsonClass::print(aJsonObject* item, FILE* stream) +{ + return printValue(item, stream); +} + +/*char* +aJsonClass::print(aJsonObject* item) +{ + FILE* stream = openStringOutputStream(); + if (stream == NULL) + { + return NULL; + } + print(item, stream); + return closeStringOutputStream(stream); +}*/ + +// Parser core - when encountering text, process appropriately. +int +aJsonClass::parseValue(aJsonObject *item, FILE* stream, char** filter) +{ + if (stream == NULL) + { + return EOF; // Fail on null. + } + if (skip(stream) == EOF) + { + return EOF; + } + //read the first byte from the stream + int in = fgetc(stream); + if (in == EOF) + { + return EOF; + } + if (ungetc(in, stream) == EOF) + { + return EOF; + } + if (in == '\"') + { + return parseString(item, stream); + } + else if (in == '-' || (in >= '0' && in <= '9')) + { + return parseNumber(item, stream); + } + else if (in == '[') + { + return parseArray(item, stream, filter); + } + else if (in == '{') + { + return parseObject(item, stream, filter); + } + //it can only be null, false or true + else if (in == 'n') + { + //a buffer to read the value + char buffer[] = + { 0, 0, 0, 0 }; + if (fread(buffer, sizeof(char), 4, stream) != 4) + { + return EOF; + } + if (!strncmp(buffer, "null", 4)) + { + item->type = aJson_NULL; + return 0; + } + else + { + return EOF; + } + } + else if (in == 'f') + { + //a buffer to read the value + char buffer[] = + { 0, 0, 0, 0, 0 }; + if (fread(buffer, sizeof(char), 5, stream) != 5) + { + return EOF; + } + if (!strncmp(buffer, "false", 5)) + { + item->type = aJson_False; + item->valuebool = 0; + return 0; + } + } + else if (in == 't') + { + //a buffer to read the value + char buffer[] = + { 0, 0, 0, 0 }; + if (fread(buffer, sizeof(char), 4, stream) != 4) + { + return EOF; + } + if (!strncmp(buffer, "true", 4)) + { + item->type = aJson_True; + item->valuebool = -1; + return 0; + } + } + + return EOF; // failure. +} + +// Render a value to text. +int +aJsonClass::printValue(aJsonObject *item, FILE* stream) +{ + int result = 0; + if (item == NULL) + { + //nothing to do + return 0; + } + switch (item->type) + { + case aJson_NULL: + result = fprintf_P(stream, PSTR("null")); + break; + case aJson_False: + result = fprintf_P(stream, PSTR("false")); + break; + case aJson_True: + result = fprintf_P(stream, PSTR("true")); + break; + case aJson_Int: + result = printInt(item, stream); + break; + case aJson_Float: + result = printFloat(item, stream); + break; + case aJson_String: + result = printString(item, stream); + break; + case aJson_Array: + result = printArray(item, stream); + break; + case aJson_Object: + result = printObject(item, stream); + break; + } + //good time to flush the stream + fflush(stream); + return result; +} + +// Build an array from input text. +int +aJsonClass::parseArray(aJsonObject *item, FILE* stream, char** filter) +{ + int in = fgetc(stream); + if (in != '[') + { + return EOF; // not an array! + } + + item->type = aJson_Array; + skip(stream); + in = fgetc(stream); + //check for empty array + if (in == ']') + { + return 0; // empty array. + } + //now put back the last character + ungetc(in, stream); + aJsonObject *child; + char first = -1; + while ((first) || (in == ',')) + { + aJsonObject *new_item = newItem(); + if (new_item == NULL) + { + return EOF; // memory fail + } + if (first) + { + item->child = new_item; + first = 0; + } + else + { + child->next = new_item; + new_item->prev = child; + } + child = new_item; + skip(stream); + if (parseValue(child, stream, filter)) + { + return EOF; + } + skip(stream); + in = fgetc(stream); + } + if (in == ']') + { + return 0; // end of array + } + else + { + return EOF; // malformed. + } +} + +// Render an array to text +int +aJsonClass::printArray(aJsonObject *item, FILE* stream) +{ + if (item == NULL) + { + //nothing to do + return 0; + } + aJsonObject *child = item->child; + if (fputc('[', stream) == EOF) + { + return EOF; + } + while (child) + { + if (printValue(child, stream) == EOF) + { + return EOF; + } + child = child->next; + if (child) + { + if (fputc(',', stream) == EOF) + { + return EOF; + } + } + } + if (fputc(']', stream) == EOF) + { + return EOF; + } + return 0; +} + +// Build an object from the text. +int +aJsonClass::parseObject(aJsonObject *item, FILE* stream, char** filter) +{ + int in = fgetc(stream); + if (in != '{') + { + return EOF; // not an object! + } + + item->type = aJson_Object; + skip(stream); + //check for an empty object + in = fgetc(stream); + if (in == '}') + { + return 0; // empty object. + } + //preserve the char for the next parser + ungetc(in, stream); + + aJsonObject* child; + char first = -1; + while ((first) || (in == ',')) + { + //in = fgetc(stream); + aJsonObject* new_item = newItem(); + if (new_item == NULL) + { + return EOF; // memory fail + } + if (first) + { + first = 0; + item->child = new_item; + } + else + { + child->next = new_item; + new_item->prev = child; + } + child = new_item; + skip(stream); + if (parseString(child, stream) == EOF) + { + return EOF; + } + skip(stream); + child->name = child->valuestring; + child->valuestring = NULL; + + in = fgetc(stream); + if (in != ':') + { + return EOF; // fail! + } + // skip any spacing, get the value. + skip(stream); + if (parseValue(child, stream, filter) == EOF) + { + return EOF; + } + in = fgetc(stream); + } + + if (in == '}') + { + return 0; // end of array + } + else + { + return EOF; // malformed. + } +} + +// Render an object to text. +int +aJsonClass::printObject(aJsonObject *item, FILE* stream) +{ + if (item == NULL) + { + //nothing to do + return 0; + } + aJsonObject *child = item->child; + if (fputc('{', stream) == EOF) + { + return EOF; + } + while (child) + { + if (printStringPtr(child->name, stream) == EOF) + { + return EOF; + } + if (fputc(':', stream) == EOF) + { + return EOF; + } + if (printValue(child, stream) == EOF) + { + return EOF; + } + child = child->next; + if (child) + { + if (fputc(',', stream) == EOF) + { + return EOF; + } + } + } + if (fputc('}', stream) == EOF) + { + return EOF; + } + return 0; +} + +// Get Array size/item / object item. +unsigned char +aJsonClass::getArraySize(aJsonObject *array) +{ + aJsonObject *c = array->child; + unsigned char i = 0; + while (c) + i++, c = c->next; + return i; +} +aJsonObject* +aJsonClass::getArrayItem(aJsonObject *array, unsigned char item) +{ + aJsonObject *c = array->child; + while (c && item > 0) + item--, c = c->next; + return c; +} +aJsonObject* +aJsonClass::getObjectItem(aJsonObject *object, const char *string) +{ + aJsonObject *c = object->child; + while (c && strcasecmp(c->name, string)) + c = c->next; + return c; +} + +// Utility for array list handling. +void +aJsonClass::suffixObject(aJsonObject *prev, aJsonObject *item) +{ + prev->next = item; + item->prev = prev; +} +// Utility for handling references. +aJsonObject* +aJsonClass::createReference(aJsonObject *item) +{ + aJsonObject *ref = newItem(); + if (!ref) + return 0; + memcpy(ref, item, sizeof(aJsonObject)); + ref->name = 0; + ref->type |= aJson_IsReference; + ref->next = ref->prev = 0; + return ref; +} + +// Add item to array/object. +void +aJsonClass::addItemToArray(aJsonObject *array, aJsonObject *item) +{ + aJsonObject *c = array->child; + if (!item) + return; + if (!c) + { + array->child = item; + } + else + { + while (c && c->next) + c = c->next; + suffixObject(c, item); + } +} +void +aJsonClass::addItemToObject(aJsonObject *object, const char *string, + aJsonObject *item) +{ + if (!item) + return; + if (item->name) + free(item->name); + item->name = strdup(string); + addItemToArray(object, item); +} +void +aJsonClass::addItemReferenceToArray(aJsonObject *array, aJsonObject *item) +{ + addItemToArray(array, createReference(item)); +} +void +aJsonClass::addItemReferenceToObject(aJsonObject *object, const char *string, + aJsonObject *item) +{ + addItemToObject(object, string, createReference(item)); +} + +aJsonObject* +aJsonClass::detachItemFromArray(aJsonObject *array, unsigned char which) +{ + aJsonObject *c = array->child; + while (c && which > 0) + c = c->next, which--; + if (!c) + return 0; + if (c->prev) + c->prev->next = c->next; + if (c->next) + c->next->prev = c->prev; + if (c == array->child) + array->child = c->next; + c->prev = c->next = 0; + return c; +} +void +aJsonClass::deleteItemFromArray(aJsonObject *array, unsigned char which) +{ + deleteItem(detachItemFromArray(array, which)); +} +aJsonObject* +aJsonClass::detachItemFromObject(aJsonObject *object, const char *string) +{ + unsigned char i = 0; + aJsonObject *c = object->child; + while (c && strcasecmp(c->name, string)) + i++, c = c->next; + if (c) + return detachItemFromArray(object, i); + return 0; +} +void +aJsonClass::deleteItemFromObject(aJsonObject *object, const char *string) +{ + deleteItem(detachItemFromObject(object, string)); +} + +// Replace array/object items with new ones. +void +aJsonClass::replaceItemInArray(aJsonObject *array, unsigned char which, + aJsonObject *newitem) +{ + aJsonObject *c = array->child; + while (c && which > 0) + c = c->next, which--; + if (!c) + return; + newitem->next = c->next; + newitem->prev = c->prev; + if (newitem->next) + newitem->next->prev = newitem; + if (c == array->child) + array->child = newitem; + else + newitem->prev->next = newitem; + c->next = c->prev = 0; + deleteItem(c); +} +void +aJsonClass::replaceItemInObject(aJsonObject *object, const char *string, + aJsonObject *newitem) +{ + unsigned char i = 0; + aJsonObject *c = object->child; + while (c && strcasecmp(c->name, string)) + i++, c = c->next; + if (c) + { + newitem->name = strdup(string); + replaceItemInArray(object, i, newitem); + } +} + +// Create basic types: +aJsonObject* +aJsonClass::createNull() +{ + aJsonObject *item = newItem(); + if (item) + item->type = aJson_NULL; + return item; +} + +aJsonObject* +aJsonClass::createTrue() +{ + aJsonObject *item = newItem(); + if (item) + { + item->type = aJson_True; + item->valuebool = -1; + } + return item; +} +aJsonObject* +aJsonClass::createFalse() +{ + aJsonObject *item = newItem(); + if (item) + { + item->type = aJson_False; + item->valuebool = 0; + } + return item; +} +aJsonObject* +aJsonClass::createItem(char b) +{ + aJsonObject *item = newItem(); + if (item) + { + item->type = b ? aJson_True : aJson_False; + item->valuebool = b ? -1 : 0; + } + return item; +} + +aJsonObject* +aJsonClass::createItem(int num) +{ + aJsonObject *item = newItem(); + if (item) + { + item->type = aJson_Int; + item->valueint = (int) num; + } + return item; +} + +aJsonObject* +aJsonClass::createItem(double num) +{ + aJsonObject *item = newItem(); + if (item) + { + item->type = aJson_Float; + item->valuefloat = num; + } + return item; +} + +aJsonObject* +aJsonClass::createItem(const char *string) +{ + aJsonObject *item = newItem(); + if (item) + { + item->type = aJson_String; + item->valuestring = strdup(string); + } + return item; +} + +aJsonObject* +aJsonClass::createArray() +{ + aJsonObject *item = newItem(); + if (item) + item->type = aJson_Array; + return item; +} +aJsonObject* +aJsonClass::createObject() +{ + aJsonObject *item = newItem(); + if (item) + item->type = aJson_Object; + return item; +} + +// Create Arrays: +aJsonObject* +aJsonClass::createIntArray(int *numbers, unsigned char count) +{ + unsigned char i; + aJsonObject *n = 0, *p = 0, *a = createArray(); + for (i = 0; a && i < count; i++) + { + n = createItem(numbers[i]); + if (!i) + a->child = n; + else + suffixObject(p, n); + p = n; + } + return a; +} + +aJsonObject* +aJsonClass::createFloatArray(double *numbers, unsigned char count) +{ + unsigned char i; + aJsonObject *n = 0, *p = 0, *a = createArray(); + for (i = 0; a && i < count; i++) + { + n = createItem(numbers[i]); + if (!i) + a->child = n; + else + suffixObject(p, n); + p = n; + } + return a; +} + +aJsonObject* +aJsonClass::createDoubleArray(double *numbers, unsigned char count) +{ + unsigned char i; + aJsonObject *n = 0, *p = 0, *a = createArray(); + for (i = 0; a && i < count; i++) + { + n = createItem(numbers[i]); + if (!i) + a->child = n; + else + suffixObject(p, n); + p = n; + } + return a; +} + +aJsonObject* +aJsonClass::createStringArray(const char **strings, unsigned char count) +{ + unsigned char i; + aJsonObject *n = 0, *p = 0, *a = createArray(); + for (i = 0; a && i < count; i++) + { + n = createItem(strings[i]); + if (!i) + a->child = n; + else + suffixObject(p, n); + p = n; + } + return a; +} + +void +aJsonClass::addNullToObject(aJsonObject* object, const char* name) +{ + addItemToObject(object, name, createNull()); +} + +void +aJsonClass::addTrueToObject(aJsonObject* object, const char* name) +{ + addItemToObject(object, name, createTrue()); +} + +void +aJsonClass::addFalseToObject(aJsonObject* object, const char* name) +{ + addItemToObject(object, name, createFalse()); +} + +void +aJsonClass::addNumberToObject(aJsonObject* object, const char* name, int n) +{ + addItemToObject(object, name, createItem(n)); +} + +void +aJsonClass::addNumberToObject(aJsonObject* object, const char* name, double n) +{ + addItemToObject(object, name, createItem(n)); +} + +void +aJsonClass::addStringToObject(aJsonObject* object, const char* name, + const char* s) +{ + addItemToObject(object, name, createItem(s)); +} + +//TODO conversion routines btw. float & int types? + +aJsonClass aJson;
--- a/aJSON.h Mon Aug 27 15:15:45 2012 +0000 +++ b/aJSON.h Tue Aug 28 08:16:29 2012 +0000 @@ -1,167 +1,167 @@ -/* - Copyright (c) 2001, Interactive Matter, Marcus Nowotny - - Based on the cJSON Library, Copyright (C) 2009 Dave Gamble - - 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. - */ - -#ifndef aJson__h -#define aJson__h - -/****************************************************************************** - * Includes - ******************************************************************************/ -#include <stdio.h> - - -/****************************************************************************** - * Definitions - ******************************************************************************/ -// aJson Types: -#define aJson_False 0 -#define aJson_True 1 -#define aJson_NULL 2 -#define aJson_Int 3 -#define aJson_Float 4 -#define aJson_String 5 -#define aJson_Array 6 -#define aJson_Object 7 - -#define aJson_IsReference 128 - -// The aJson structure: -typedef struct aJsonObject { - char *name; // The item's name string, if this item is the child of, or is in the list of subitems of an object. - struct aJsonObject *next, *prev; // next/prev allow you to walk array/object chains. Alternatively, use GetArraySize/GetArrayItem/GetObjectItem - struct aJsonObject *child; // An array or object item will have a child pointer pointing to a chain of the items in the array/object. - - char type; // The type of the item, as above. - - union { - char *valuestring; // The item's string, if type==aJson_String - char valuebool; //the items value for true & false - int valueint; // The item's number, if type==aJson_Number - double valuefloat; // The item's number, if type==aJson_Number - }; -} aJsonObject; - -class aJsonClass { - /****************************************************************************** - * Constructors - ******************************************************************************/ - - /****************************************************************************** - * User API - ******************************************************************************/ -public: - // Supply a block of JSON, and this returns a aJson object you can interrogate. Call aJson.deleteItem when finished. - aJsonObject* parse(FILE* stream); //Reads from a stream - aJsonObject* parse(FILE* stream,char** filter_values); //Read from a file, but only return values include in the char* array filter_values - aJsonObject* parse(char *value); //Reads from a string - // Render a aJsonObject entity to text for transfer/storage. Free the char* when finished. - int print(aJsonObject *item, FILE* stream); - char* print(aJsonObject* item); - //Renders a aJsonObject directly to a output stream - char stream(aJsonObject *item, FILE* stream); - // Delete a aJsonObject entity and all sub-entities. - void deleteItem(aJsonObject *c); - - // Returns the number of items in an array (or object). - unsigned char getArraySize(aJsonObject *array); - // Retrieve item number "item" from array "array". Returns NULL if unsuccessful. - aJsonObject* getArrayItem(aJsonObject *array, unsigned char item); - // Get item "string" from object. Case insensitive. - aJsonObject* getObjectItem(aJsonObject *object, const char *string); - - // These calls create a aJsonObject item of the appropriate type. - aJsonObject* createNull(); - aJsonObject* createTrue(); - aJsonObject* createFalse(); - aJsonObject* createItem(char b); - aJsonObject* createItem(int num); - aJsonObject* createItem(double num); - aJsonObject* createItem(const char *string); - aJsonObject* createArray(); - aJsonObject* createObject(); - - // These utilities create an Array of count items. - aJsonObject* createIntArray(int *numbers, unsigned char count); - aJsonObject* createFloatArray(double *numbers, unsigned char count); - aJsonObject* createDoubleArray(double *numbers, unsigned char count); - aJsonObject* createStringArray(const char **strings, unsigned char count); - - // Append item to the specified array/object. - void addItemToArray(aJsonObject *array, aJsonObject *item); - void addItemToObject(aJsonObject *object, const char *string, - aJsonObject *item); - // Append reference to item to the specified array/object. Use this when you want to add an existing aJsonObject to a new aJsonObject, but don't want to corrupt your existing aJsonObject. - void addItemReferenceToArray(aJsonObject *array, aJsonObject *item); - void addItemReferenceToObject(aJsonObject *object, const char *string, - aJsonObject *item); - - // Remove/Detach items from Arrays/Objects. - aJsonObject* detachItemFromArray(aJsonObject *array, unsigned char which); - void deleteItemFromArray(aJsonObject *array, unsigned char which); - aJsonObject* detachItemFromObject(aJsonObject *object, const char *string); - void deleteItemFromObject(aJsonObject *object, const char *string); - - // Update array items. - void replaceItemInArray(aJsonObject *array, unsigned char which, - aJsonObject *newitem); - void replaceItemInObject(aJsonObject *object, const char *string, - aJsonObject *newitem); - - void addNullToObject(aJsonObject* object, const char* name); - void addTrueToObject(aJsonObject* object, const char* name); - void addFalseToObject(aJsonObject* object, const char* name); - void addNumberToObject(aJsonObject* object, const char* name, int n); - void addNumberToObject(aJsonObject* object, const char* name, double n); - void addStringToObject(aJsonObject* object, const char* name, - const char* s); - -private: - aJsonObject* newItem(); - int parseNumber(aJsonObject *item, FILE* stream); - int printInt(aJsonObject *item, FILE* stream); - int printFloat(aJsonObject *item, FILE* stream); - - int parseString(aJsonObject *item, FILE* stream); - int printStringPtr(const char *str, FILE* stream); - int printString(aJsonObject *item, FILE* stream); - - int skip(FILE* stream); - - int parseValue(aJsonObject *item, FILE* stream, char** filter); - int printValue(aJsonObject *item, FILE* stream); - - int parseArray(aJsonObject *item, FILE* stream, char** filter); - int printArray(aJsonObject *item, FILE* stream); - - int parseObject(aJsonObject *item, FILE* stream, char** filter); - int printObject(aJsonObject *item, FILE* stream); - void suffixObject(aJsonObject *prev, aJsonObject *item); - - aJsonObject* createReference(aJsonObject *item); - -}; - -extern aJsonClass aJson; - -#endif +/* + Copyright (c) 2001, Interactive Matter, Marcus Nowotny + + Based on the cJSON Library, Copyright (C) 2009 Dave Gamble + + 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. + */ + +#ifndef aJson__h +#define aJson__h + +/****************************************************************************** + * Includes + ******************************************************************************/ +#include <stdio.h> + + +/****************************************************************************** + * Definitions + ******************************************************************************/ +// aJson Types: +#define aJson_False 0 +#define aJson_True 1 +#define aJson_NULL 2 +#define aJson_Int 3 +#define aJson_Float 4 +#define aJson_String 5 +#define aJson_Array 6 +#define aJson_Object 7 + +#define aJson_IsReference 128 + +// The aJson structure: +typedef struct aJsonObject { + char *name; // The item's name string, if this item is the child of, or is in the list of subitems of an object. + struct aJsonObject *next, *prev; // next/prev allow you to walk array/object chains. Alternatively, use GetArraySize/GetArrayItem/GetObjectItem + struct aJsonObject *child; // An array or object item will have a child pointer pointing to a chain of the items in the array/object. + + char type; // The type of the item, as above. + + union { + char *valuestring; // The item's string, if type==aJson_String + char valuebool; //the items value for true & false + int valueint; // The item's number, if type==aJson_Number + double valuefloat; // The item's number, if type==aJson_Number + }; +} aJsonObject; + +class aJsonClass { + /****************************************************************************** + * Constructors + ******************************************************************************/ + + /****************************************************************************** + * User API + ******************************************************************************/ +public: + // Supply a block of JSON, and this returns a aJson object you can interrogate. Call aJson.deleteItem when finished. + aJsonObject* parse(FILE* stream); //Reads from a stream + aJsonObject* parse(FILE* stream,char** filter_values); //Read from a file, but only return values include in the char* array filter_values + aJsonObject* parse(char *value); //Reads from a string + // Render a aJsonObject entity to text for transfer/storage. Free the char* when finished. + int print(aJsonObject *item, FILE* stream); + char* print(aJsonObject* item); + //Renders a aJsonObject directly to a output stream + char stream(aJsonObject *item, FILE* stream); + // Delete a aJsonObject entity and all sub-entities. + void deleteItem(aJsonObject *c); + + // Returns the number of items in an array (or object). + unsigned char getArraySize(aJsonObject *array); + // Retrieve item number "item" from array "array". Returns NULL if unsuccessful. + aJsonObject* getArrayItem(aJsonObject *array, unsigned char item); + // Get item "string" from object. Case insensitive. + aJsonObject* getObjectItem(aJsonObject *object, const char *string); + + // These calls create a aJsonObject item of the appropriate type. + aJsonObject* createNull(); + aJsonObject* createTrue(); + aJsonObject* createFalse(); + aJsonObject* createItem(char b); + aJsonObject* createItem(int num); + aJsonObject* createItem(double num); + aJsonObject* createItem(const char *string); + aJsonObject* createArray(); + aJsonObject* createObject(); + + // These utilities create an Array of count items. + aJsonObject* createIntArray(int *numbers, unsigned char count); + aJsonObject* createFloatArray(double *numbers, unsigned char count); + aJsonObject* createDoubleArray(double *numbers, unsigned char count); + aJsonObject* createStringArray(const char **strings, unsigned char count); + + // Append item to the specified array/object. + void addItemToArray(aJsonObject *array, aJsonObject *item); + void addItemToObject(aJsonObject *object, const char *string, + aJsonObject *item); + // Append reference to item to the specified array/object. Use this when you want to add an existing aJsonObject to a new aJsonObject, but don't want to corrupt your existing aJsonObject. + void addItemReferenceToArray(aJsonObject *array, aJsonObject *item); + void addItemReferenceToObject(aJsonObject *object, const char *string, + aJsonObject *item); + + // Remove/Detach items from Arrays/Objects. + aJsonObject* detachItemFromArray(aJsonObject *array, unsigned char which); + void deleteItemFromArray(aJsonObject *array, unsigned char which); + aJsonObject* detachItemFromObject(aJsonObject *object, const char *string); + void deleteItemFromObject(aJsonObject *object, const char *string); + + // Update array items. + void replaceItemInArray(aJsonObject *array, unsigned char which, + aJsonObject *newitem); + void replaceItemInObject(aJsonObject *object, const char *string, + aJsonObject *newitem); + + void addNullToObject(aJsonObject* object, const char* name); + void addTrueToObject(aJsonObject* object, const char* name); + void addFalseToObject(aJsonObject* object, const char* name); + void addNumberToObject(aJsonObject* object, const char* name, int n); + void addNumberToObject(aJsonObject* object, const char* name, double n); + void addStringToObject(aJsonObject* object, const char* name, + const char* s); + +private: + aJsonObject* newItem(); + int parseNumber(aJsonObject *item, FILE* stream); + int printInt(aJsonObject *item, FILE* stream); + int printFloat(aJsonObject *item, FILE* stream); + + int parseString(aJsonObject *item, FILE* stream); + int printStringPtr(const char *str, FILE* stream); + int printString(aJsonObject *item, FILE* stream); + + int skip(FILE* stream); + + int parseValue(aJsonObject *item, FILE* stream, char** filter); + int printValue(aJsonObject *item, FILE* stream); + + int parseArray(aJsonObject *item, FILE* stream, char** filter); + int printArray(aJsonObject *item, FILE* stream); + + int parseObject(aJsonObject *item, FILE* stream, char** filter); + int printObject(aJsonObject *item, FILE* stream); + void suffixObject(aJsonObject *prev, aJsonObject *item); + + aJsonObject* createReference(aJsonObject *item); + +}; + +extern aJsonClass aJson; + +#endif
--- a/compatibility.h Mon Aug 27 15:15:45 2012 +0000 +++ b/compatibility.h Tue Aug 28 08:16:29 2012 +0000 @@ -1,9 +1,9 @@ -#ifndef COMPAT_AJSON__H -#define COMPAT_AJSON__H - -#define fprintf_P fprintf -#define PSTR(a) a -#define strdup(a) strcpy((char*)malloc( strlen(a) + 1),a); - - +#ifndef COMPAT_AJSON__H +#define COMPAT_AJSON__H + +#define fprintf_P fprintf +#define PSTR(a) a +#define strdup(a) strcpy((char*)malloc( strlen(a) + 1),a); + + #endif \ No newline at end of file
--- a/utility/streamhelper.c Mon Aug 27 15:15:45 2012 +0000 +++ b/utility/streamhelper.c Tue Aug 28 08:16:29 2012 +0000 @@ -1,142 +1,142 @@ -/* - * aJson - * streamhelper.c - * - * http://interactive-matter.org/ - * - * This file is part of aJson. - * - * aJson is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * aJson is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * You should have received a copy of the GNU General Public License - * along with aJson. If not, see <http://www.gnu.org/licenses/>. - * - * Created on: 10.10.2010 - * Author: marcus - */ -#include <stdio.h> -#include <stdlib.h> -#include "streamhelper.h" -#include "stringbuffer.h" - -//internal prototypes -int -stringGet(FILE* stream); -int -stringPut(char c, FILE* stream); - -typedef struct -{ - char* string; - unsigned int position; -} string_input_stream_info; - -/*FILE* -openStringInputStream(char* string) -{ - FILE* result = fdevopen(NULL, &stringGet); - if (result == NULL) - { - return NULL; - } - string_input_stream_info* udata = malloc(sizeof(string_input_stream_info)); - if (udata != NULL) - { - udata->string = string; - udata->position = 0; - fdev_set_udata(result,udata); - } - else - { - fclose(result); - return NULL; - } - return result; -}*/ - -/*void -closeStringInputStream(FILE* stream) -{ - if (stream == NULL) - { - return; - } - string_input_stream_info* udata = - (string_input_stream_info*) fdev_get_udata(stream); - if (udata != NULL) - { - free(udata); - } - fdev_set_udata(stream,NULL); - fclose(stream); -}*/ - -/*FILE* -openStringOutputStream(void) -{ - FILE* result = fdevopen(&stringPut, NULL); - if (result == NULL) - { - return NULL; - } - string_buffer* buffer = stringBufferCreate(); - if (buffer == NULL) - { - fclose(result); - return NULL; - } - fdev_set_udata(result,buffer); - return result; -}*/ - -/*char* -closeStringOutputStream(FILE* stream) -{ - //write a 0 to the end - that is how a string looks like - string_buffer* buffer = (string_buffer*) fdev_get_udata(stream); - char* result = stringBufferToString(buffer); - if (result == NULL) - { - fclose(stream); - return NULL; - } - //free(buffer); - fdev_set_udata(stream,NULL); - fclose(stream); - return result; -}*/ - -/*int -stringGet(FILE* stream) -{ - string_input_stream_info* udata = - (string_input_stream_info*) fdev_get_udata(stream); - char result = udata->string[udata->position]; - if (result == 0) - { - return EOF; - } - else - { - udata->position++; - return result; - } -}*/ - -/*int -stringPut(char c, FILE* stream) -{ - string_buffer* buffer = (string_buffer*) fdev_get_udata(stream); - if (stringBufferAdd(c, buffer)) - { - return EOF; - } - return 0; -}*/ +/* + * aJson + * streamhelper.c + * + * http://interactive-matter.org/ + * + * This file is part of aJson. + * + * aJson is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * aJson is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * You should have received a copy of the GNU General Public License + * along with aJson. If not, see <http://www.gnu.org/licenses/>. + * + * Created on: 10.10.2010 + * Author: marcus + */ +#include <stdio.h> +#include <stdlib.h> +#include "streamhelper.h" +#include "stringbuffer.h" + +//internal prototypes +int +stringGet(FILE* stream); +int +stringPut(char c, FILE* stream); + +typedef struct +{ + char* string; + unsigned int position; +} string_input_stream_info; + +/*FILE* +openStringInputStream(char* string) +{ + FILE* result = fdevopen(NULL, &stringGet); + if (result == NULL) + { + return NULL; + } + string_input_stream_info* udata = malloc(sizeof(string_input_stream_info)); + if (udata != NULL) + { + udata->string = string; + udata->position = 0; + fdev_set_udata(result,udata); + } + else + { + fclose(result); + return NULL; + } + return result; +}*/ + +/*void +closeStringInputStream(FILE* stream) +{ + if (stream == NULL) + { + return; + } + string_input_stream_info* udata = + (string_input_stream_info*) fdev_get_udata(stream); + if (udata != NULL) + { + free(udata); + } + fdev_set_udata(stream,NULL); + fclose(stream); +}*/ + +/*FILE* +openStringOutputStream(void) +{ + FILE* result = fdevopen(&stringPut, NULL); + if (result == NULL) + { + return NULL; + } + string_buffer* buffer = stringBufferCreate(); + if (buffer == NULL) + { + fclose(result); + return NULL; + } + fdev_set_udata(result,buffer); + return result; +}*/ + +/*char* +closeStringOutputStream(FILE* stream) +{ + //write a 0 to the end - that is how a string looks like + string_buffer* buffer = (string_buffer*) fdev_get_udata(stream); + char* result = stringBufferToString(buffer); + if (result == NULL) + { + fclose(stream); + return NULL; + } + //free(buffer); + fdev_set_udata(stream,NULL); + fclose(stream); + return result; +}*/ + +/*int +stringGet(FILE* stream) +{ + string_input_stream_info* udata = + (string_input_stream_info*) fdev_get_udata(stream); + char result = udata->string[udata->position]; + if (result == 0) + { + return EOF; + } + else + { + udata->position++; + return result; + } +}*/ + +/*int +stringPut(char c, FILE* stream) +{ + string_buffer* buffer = (string_buffer*) fdev_get_udata(stream); + if (stringBufferAdd(c, buffer)) + { + return EOF; + } + return 0; +}*/
--- a/utility/stringbuffer.c Mon Aug 27 15:15:45 2012 +0000 +++ b/utility/stringbuffer.c Tue Aug 28 08:16:29 2012 +0000 @@ -1,125 +1,125 @@ -/* - * aJson - * stringbuffer.c - * - * http://interactive-matter.org/ - * - * This file is part of aJson. - * - * aJson is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * aJson is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * You should have received a copy of the GNU General Public License - * along with aJson. If not, see <http://www.gnu.org/licenses/>. - * - * Created on: 14.10.2010 - * Author: marcus - */ -#include <stdlib.h> -#include <string.h> -#include "stringbuffer.h" - -//Default buffer size for strings -#define BUFFER_SIZE 256 -//there is a static buffer allocated, which is used to decode strings to -//strings cannot be longer than the buffer -char global_buffer[BUFFER_SIZE]; - -string_buffer* -stringBufferCreate(void) -{ - string_buffer* result = (string_buffer*)malloc(sizeof(string_buffer)); - if (result == NULL) - { - return NULL; - } - result->string = global_buffer; - memset((void*) global_buffer, 0, BUFFER_SIZE); - //unused - but will be usefull after realloc got fixd - /* if (result->string==NULL) { - free(result); - return NULL; - } - result->memory=BUFFER_DEFAULT_SIZE;*/ - result->memory = BUFFER_SIZE; - result->string_length = 0; - return result; -} - -char -stringBufferAdd(char value, string_buffer* buffer) -{ - if (buffer->string_length >= buffer->memory) - { - //this has to be enabled after realloc works - /*char* new_string = (char*) realloc((void*) buffer->string, (buffer->memory - + BUFFER_DEFAULT_SIZE) * sizeof(char)); - if (new_string == NULL) - { - free(buffer->string); - buffer->string = NULL; - return -1; - } else { - buffer->string = new_string; - } - buffer->memory += BUFFER_DEFAULT_SIZE;*/ - //in the meantime we just drop it - return 0; //EOF would be a better choice - but that breaks json decoding - } - buffer->string[buffer->string_length] = value; - buffer->string_length += 1; - return 0; -} - -char* -stringBufferToString(string_buffer* buffer) -{ - //this is the realloc dependent function - it does not work - // char* result = buffer->string; - //ensure that the string ends with 0 - if (buffer->string_length == 0 || buffer->string[(buffer->string_length - 1)] - != 0) - { - stringBufferAdd(0, buffer); - } - /* char* string = realloc(result, buffer->string_length); - if (string==NULL) { - free(result); - } - buffer->string=NULL; - free(buffer); - return string;*/ - char* result = (char*)malloc(buffer->string_length * sizeof(char)); - if (result == NULL) - { - return NULL; - } - strcpy(result, global_buffer); - buffer->string = NULL; - free(buffer); - return result; -} - -void -stringBufferFree(string_buffer* buffer) -{ - if (buffer == NULL) - { - //hmm it was null before - whatever - return; - } - //this is not needed in this realloc free concept - /* - if (buffer->string!=NULL) { - free(buffer->string); - } - */ - free(buffer); -} - +/* + * aJson + * stringbuffer.c + * + * http://interactive-matter.org/ + * + * This file is part of aJson. + * + * aJson is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * aJson is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * You should have received a copy of the GNU General Public License + * along with aJson. If not, see <http://www.gnu.org/licenses/>. + * + * Created on: 14.10.2010 + * Author: marcus + */ +#include <stdlib.h> +#include <string.h> +#include "stringbuffer.h" + +//Default buffer size for strings +#define BUFFER_SIZE 256 +//there is a static buffer allocated, which is used to decode strings to +//strings cannot be longer than the buffer +char global_buffer[BUFFER_SIZE]; + +string_buffer* +stringBufferCreate(void) +{ + string_buffer* result = (string_buffer*)malloc(sizeof(string_buffer)); + if (result == NULL) + { + return NULL; + } + result->string = global_buffer; + memset((void*) global_buffer, 0, BUFFER_SIZE); + //unused - but will be usefull after realloc got fixd + /* if (result->string==NULL) { + free(result); + return NULL; + } + result->memory=BUFFER_DEFAULT_SIZE;*/ + result->memory = BUFFER_SIZE; + result->string_length = 0; + return result; +} + +char +stringBufferAdd(char value, string_buffer* buffer) +{ + if (buffer->string_length >= buffer->memory) + { + //this has to be enabled after realloc works + /*char* new_string = (char*) realloc((void*) buffer->string, (buffer->memory + + BUFFER_DEFAULT_SIZE) * sizeof(char)); + if (new_string == NULL) + { + free(buffer->string); + buffer->string = NULL; + return -1; + } else { + buffer->string = new_string; + } + buffer->memory += BUFFER_DEFAULT_SIZE;*/ + //in the meantime we just drop it + return 0; //EOF would be a better choice - but that breaks json decoding + } + buffer->string[buffer->string_length] = value; + buffer->string_length += 1; + return 0; +} + +char* +stringBufferToString(string_buffer* buffer) +{ + //this is the realloc dependent function - it does not work + // char* result = buffer->string; + //ensure that the string ends with 0 + if (buffer->string_length == 0 || buffer->string[(buffer->string_length - 1)] + != 0) + { + stringBufferAdd(0, buffer); + } + /* char* string = realloc(result, buffer->string_length); + if (string==NULL) { + free(result); + } + buffer->string=NULL; + free(buffer); + return string;*/ + char* result = (char*)malloc(buffer->string_length * sizeof(char)); + if (result == NULL) + { + return NULL; + } + strcpy(result, global_buffer); + buffer->string = NULL; + free(buffer); + return result; +} + +void +stringBufferFree(string_buffer* buffer) +{ + if (buffer == NULL) + { + //hmm it was null before - whatever + return; + } + //this is not needed in this realloc free concept + /* + if (buffer->string!=NULL) { + free(buffer->string); + } + */ + free(buffer); +} +
--- a/utility/stringbuffer.h Mon Aug 27 15:15:45 2012 +0000 +++ b/utility/stringbuffer.h Tue Aug 28 08:16:29 2012 +0000 @@ -1,55 +1,55 @@ -/* - * aJson - * stringbuffer.h - * - * http://interactive-matter.org/ - * - * This file is part of aJson. - * - * aJson is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * aJson is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * You should have received a copy of the GNU General Public License - * along with aJson. If not, see <http://www.gnu.org/licenses/>. - * - * Created on: 14.10.2010 - * Author: marcus - */ - -#ifndef STRINGBUFFER_H_ -#define STRINGBUFFER_H_ - -typedef struct -{ - char* string; - unsigned int memory; - unsigned int string_length; -} string_buffer; - -#ifdef __cplusplus -extern "C" -{ -#endif - - string_buffer* - stringBufferCreate(void); - - char - stringBufferAdd(char value, string_buffer* buffer); - - char* - stringBufferToString(string_buffer* buffer); - - void - stringBufferFree(string_buffer* buffer); - -#ifdef __cplusplus -} -#endif -#endif /* STRINGBUFFER_H_ */ +/* + * aJson + * stringbuffer.h + * + * http://interactive-matter.org/ + * + * This file is part of aJson. + * + * aJson is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * aJson is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * You should have received a copy of the GNU General Public License + * along with aJson. If not, see <http://www.gnu.org/licenses/>. + * + * Created on: 14.10.2010 + * Author: marcus + */ + +#ifndef STRINGBUFFER_H_ +#define STRINGBUFFER_H_ + +typedef struct +{ + char* string; + unsigned int memory; + unsigned int string_length; +} string_buffer; + +#ifdef __cplusplus +extern "C" +{ +#endif + + string_buffer* + stringBufferCreate(void); + + char + stringBufferAdd(char value, string_buffer* buffer); + + char* + stringBufferToString(string_buffer* buffer); + + void + stringBufferFree(string_buffer* buffer); + +#ifdef __cplusplus +} +#endif +#endif /* STRINGBUFFER_H_ */