diff --git a/README.md b/README.md index 2e718a2..9921a7d 100644 --- a/README.md +++ b/README.md @@ -3,6 +3,7 @@ Copyright (c) 2010, Interactive Matter, Marcus Nowotny Based on the cJSON Library, Copyright (C) 2009 Dave Gamble + Updated by anklimov - changelog on the bottom of readme Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal @@ -295,3 +296,58 @@ As soon as you call aJson.print(), it renders the structure to text. Have Fun! + +New in this fork: +adding class "aJsonFileStream" inherited from aJsonStream in order to backward- compatibility with HTTPClient library +Now is possible to operate directly with *FILE like streams, returned by HttpClient library and avoid intermediate buffering + +Code example: + + +int getConfig() +{ + FILE* result; + int returnCode ; + + HTTPClient hclient("192.168.88.2",hserver,80); + result = hclient.getURI( FEED_URI); + returnCode = hclient.getLastReturnCode(); + + if (result!=NULL) { + if (returnCode==200) { + + Serial.println("got Config :"); + aJsonFileStream as=aJsonFileStream(result); + root = aJson.parse(&as); + + hclient.closeStream(result); // this is very important -- be sure to close the STREAM + + if (!root) + { + Serial.println("parseObject() failed"); + return -11; + } else + + { + + char * outstr=aJson.print(root); + Serial.println(outstr); + items = aJson.getObjectItem(root,"items"); + } + + } + else { + Serial.print("ERROR: Server returned "); + Serial.println(returnCode); + return -11; + + } + + } + else { + Serial.println("failed to connect"); + Serial.println(" try again in 5 seconds"); + return -11; + } + return 2; +} diff --git a/aJSON.cpp b/aJSON.cpp old mode 100644 new mode 100755 index 1bb9320..74114ab --- a/aJSON.cpp +++ b/aJSON.cpp @@ -36,13 +36,16 @@ #include #include #include -#ifdef __AVR__ +#ifdef __AVR__ #include +#elif defined(__arm__) +#include #else #include #endif #include "aJSON.h" #include "utility/stringbuffer.h" +#include /****************************************************************************** * Definitions @@ -51,7 +54,7 @@ #define BUFFER_DEFAULT_SIZE 4 //how much digits after . for float -#define FLOAT_PRECISION 5 +#define FLOAT_PRECISION 2 bool @@ -81,6 +84,7 @@ aJsonStream::getch() bucket = EOF; return ret; } + // In case input was malformed - can happen, this is the // real world, we can end up in a situation where the parser // would expect another character and end up stuck on @@ -96,9 +100,23 @@ aJsonStream::ungetch(char ch) bucket = ch; } + +int +aJsonFileStream::getch() +{ + if (bucket != EOF) + { + int ret = bucket; + bucket = EOF; + return ret; + } + return fgetc(fl); +} + + size_t aJsonStream::write(uint8_t ch) -{ +{ return stream()->write(ch); } @@ -174,7 +192,6 @@ aJsonStringStream::write(uint8_t ch) return 1; } - // Internal constructor. aJsonObject* aJsonClass::newItem() @@ -189,6 +206,7 @@ aJsonClass::newItem() void aJsonClass::deleteItem(aJsonObject *c) { + if (!c) return; aJsonObject *next; while (c) { @@ -199,11 +217,11 @@ aJsonClass::deleteItem(aJsonObject *c) } if ((c->type == aJson_String) && c->valuestring) { - free(c->valuestring); + freeString(c->valuestring); } if (c->name) { - free(c->name); + freeString(c->name); } free(c); c = next; @@ -214,7 +232,7 @@ aJsonClass::deleteItem(aJsonObject *c) int aJsonStream::parseNumber(aJsonObject *item) { - int i = 0; + long int i = 0; int sign = 1; int in = this->getch(); @@ -246,6 +264,7 @@ aJsonStream::parseNumber(aJsonObject *item) { item->valueint = i * (int) sign; item->type = aJson_Int; + item->subtype = 0; } //ok it seems to be a double else @@ -288,6 +307,7 @@ aJsonStream::parseNumber(aJsonObject *item) item->valuefloat = n; item->type = aJson_Float; + item->subtype = 0; } //preserve the last character for the next routine this->ungetch(in); @@ -353,6 +373,7 @@ aJsonStream::parseString(aJsonObject *item) return EOF; // not a string! } item->type = aJson_String; + item->subtype = 0; //allocate a buffer & track how long it is and how much we have read string_buffer* buffer = stringBufferCreate(); if (buffer == NULL) @@ -493,13 +514,14 @@ aJsonStream::printString(aJsonObject *item) // Utility to jump whitespace and cr/lf int aJsonStream::skip() -{ +{ + int skipCounter=256; int in = this->getch(); - while (in != EOF && (in <= 32)) + while (in != EOF && (in <= 32) && skipCounter--) { in = this->getch(); } - if (in != EOF) + if ((in != EOF) && skipCounter) { this->ungetch(in); return 0; @@ -510,7 +532,7 @@ aJsonStream::skip() // Utility to flush our buffer in case it contains garbage // since the parser will return the buffer untouched if it // cannot understand it. -int +void aJsonStream::flush() { int in = this->getch(); @@ -518,7 +540,7 @@ aJsonStream::flush() { in = this->getch(); } - return EOF; + return;// EOF; } @@ -548,11 +570,15 @@ aJsonClass::parse(aJsonStream* stream, char** filter) } aJsonObject *c = newItem(); if (!c) + { + //debugPrint("new item fail\n"); return NULL; /* memory fail */ + } stream->skip(); if (stream->parseValue(c, filter) == EOF) { + //debugPrint("del item\n"); deleteItem(c); return NULL; } @@ -561,9 +587,9 @@ aJsonClass::parse(aJsonStream* stream, char** filter) // Render a aJsonObject item/entity/structure to text. int -aJsonClass::print(aJsonObject* item, aJsonStream* stream) +aJsonClass::print(aJsonObject* item, aJsonStream* stream, bool print_hidden) { - return stream->printValue(item); + return stream->printValue(item, print_hidden); } char* @@ -623,6 +649,7 @@ aJsonStream::parseValue(aJsonObject *item, char** filter) if (!strncmp(buffer, "null", 4)) { item->type = aJson_NULL; + item->subtype = 0; return 0; } else @@ -642,6 +669,7 @@ aJsonStream::parseValue(aJsonObject *item, char** filter) if (!strncmp(buffer, "false", 5)) { item->type = aJson_Boolean; + item->subtype = 0; item->valuebool = false; return 0; } @@ -658,6 +686,7 @@ aJsonStream::parseValue(aJsonObject *item, char** filter) if (!strncmp(buffer, "true", 4)) { item->type = aJson_Boolean; + item->subtype = 0; item->valuebool = true; return 0; } @@ -668,7 +697,7 @@ aJsonStream::parseValue(aJsonObject *item, char** filter) // Render a value to text. int -aJsonStream::printValue(aJsonObject *item) +aJsonStream::printValue(aJsonObject *item, bool print_hidden) { int result = 0; if (item == NULL) @@ -690,6 +719,7 @@ aJsonStream::printValue(aJsonObject *item) } break; case aJson_Int: + case aJson_Reserved: result = this->printInt(item); break; case aJson_Float: @@ -699,10 +729,10 @@ aJsonStream::printValue(aJsonObject *item) result = this->printString(item); break; case aJson_Array: - result = this->printArray(item); + result = this->printArray(item, print_hidden); break; case aJson_Object: - result = this->printObject(item); + result = this->printObject(item, print_hidden); break; } return result; @@ -719,6 +749,7 @@ aJsonStream::parseArray(aJsonObject *item, char** filter) } item->type = aJson_Array; + item->subtype = 0; this->skip(); in = this->getch(); //check for empty array @@ -768,7 +799,7 @@ aJsonStream::parseArray(aJsonObject *item, char** filter) // Render an array to text int -aJsonStream::printArray(aJsonObject *item) +aJsonStream::printArray(aJsonObject *item, bool print_hidden) { if (item == NULL) { @@ -782,7 +813,7 @@ aJsonStream::printArray(aJsonObject *item) } while (child) { - if (this->printValue(child) == EOF) + if (this->printValue(child, print_hidden) == EOF) { return EOF; } @@ -813,6 +844,7 @@ aJsonStream::parseObject(aJsonObject *item, char** filter) } item->type = aJson_Object; + item->subtype = 0; this->skip(); //check for an empty object in = this->getch(); @@ -879,7 +911,7 @@ aJsonStream::parseObject(aJsonObject *item, char** filter) // Render an object to text. int -aJsonStream::printObject(aJsonObject *item) +aJsonStream::printObject(aJsonObject *item, bool print_hidden) { if (item == NULL) { @@ -893,6 +925,8 @@ aJsonStream::printObject(aJsonObject *item) } while (child) { + if (print_hidden || (*child->name != '@')) /// + { if (this->printStringPtr(child->name) == EOF) { return EOF; @@ -901,12 +935,13 @@ aJsonStream::printObject(aJsonObject *item) { return EOF; } - if (this->printValue(child) == EOF) + if (this->printValue(child, print_hidden) == EOF) { return EOF; } + } //// child = child->next; - if (child) + if (child && (print_hidden || (*child->name != '@') )) { if (this->print(',') == EOF) { @@ -925,6 +960,7 @@ aJsonStream::printObject(aJsonObject *item) unsigned char aJsonClass::getArraySize(aJsonObject *array) { + if (!array) return 0; aJsonObject *c = array->child; unsigned char i = 0; while (c) @@ -934,6 +970,7 @@ aJsonClass::getArraySize(aJsonObject *array) aJsonObject* aJsonClass::getArrayItem(aJsonObject *array, unsigned char item) { + if (!array) return NULL; aJsonObject *c = array->child; while (c && item > 0) item--, c = c->next; @@ -942,6 +979,7 @@ aJsonClass::getArrayItem(aJsonObject *array, unsigned char item) aJsonObject* aJsonClass::getObjectItem(aJsonObject *object, const char *string) { + if (!object) return NULL; aJsonObject *c = object->child; while (c && strcasecmp(c->name, string)) c = c->next; @@ -973,6 +1011,7 @@ aJsonClass::createReference(aJsonObject *item) void aJsonClass::addItemToArray(aJsonObject *array, aJsonObject *item) { + if (!array) return; aJsonObject *c = array->child; if (!item) return; @@ -994,8 +1033,8 @@ aJsonClass::addItemToObject(aJsonObject *object, const char *string, if (!item) return; if (item->name) - free(item->name); - item->name = strdup(string); + freeString(item->name); + item->name = newString(string); addItemToArray(object, item); } void @@ -1013,6 +1052,7 @@ aJsonClass::addItemReferenceToObject(aJsonObject *object, const char *string, aJsonObject* aJsonClass::detachItemFromArray(aJsonObject *array, unsigned char which) { + if (!array) return NULL; aJsonObject *c = array->child; while (c && which > 0) c = c->next, which--; @@ -1036,6 +1076,7 @@ aJsonObject* aJsonClass::detachItemFromObject(aJsonObject *object, const char *string) { unsigned char i = 0; + if (!object) return NULL; aJsonObject *c = object->child; while (c && strcasecmp(c->name, string)) i++, c = c->next; @@ -1054,6 +1095,7 @@ void aJsonClass::replaceItemInArray(aJsonObject *array, unsigned char which, aJsonObject *newitem) { + if (!array) return; aJsonObject *c = array->child; while (c && which > 0) c = c->next, which--; @@ -1080,7 +1122,7 @@ aJsonClass::replaceItemInObject(aJsonObject *object, const char *string, i++, c = c->next; if (c) { - newitem->name = strdup(string); + newitem->name = newString(string); replaceItemInArray(object, i, newitem); } } @@ -1092,6 +1134,7 @@ aJsonClass::createNull() aJsonObject *item = newItem(); if (item) item->type = aJson_NULL; + item->subtype = 0; return item; } @@ -1101,6 +1144,7 @@ aJsonClass::createItem(bool b) aJsonObject *item = newItem(); if (item){ item->type = aJson_Boolean; + item->subtype = 0; item->valuebool = b; } @@ -1114,19 +1158,21 @@ aJsonClass::createItem(char b) if (item) { item->type = aJson_Boolean; + item->subtype = 0; item->valuebool = b ? -1 : 0; } return item; } aJsonObject* -aJsonClass::createItem(int num) +aJsonClass::createItem(long int num) { aJsonObject *item = newItem(); if (item) { item->type = aJson_Int; - item->valueint = (int) num; + item->subtype = 0; + item->valueint = (long int) num; } return item; } @@ -1138,6 +1184,7 @@ aJsonClass::createItem(double num) if (item) { item->type = aJson_Float; + item->subtype = 0; item->valuefloat = num; } return item; @@ -1150,7 +1197,9 @@ aJsonClass::createItem(const char *string) if (item) { item->type = aJson_String; - item->valuestring = strdup(string); + item->subtype = 0; + /// item->valuestring = strdup(string); + item->valuestring = newString(string); } return item; } @@ -1161,6 +1210,7 @@ aJsonClass::createArray() aJsonObject *item = newItem(); if (item) item->type = aJson_Array; + item->subtype = 0; return item; } aJsonObject* @@ -1169,12 +1219,13 @@ aJsonClass::createObject() aJsonObject *item = newItem(); if (item) item->type = aJson_Object; + item->subtype = 0; return item; } // Create Arrays: aJsonObject* -aJsonClass::createIntArray(int *numbers, unsigned char count) +aJsonClass::createIntArray(long int *numbers, unsigned char count) { unsigned char i; aJsonObject *n = 0, *p = 0, *a = createArray(); @@ -1254,7 +1305,7 @@ aJsonClass::addBooleanToObject(aJsonObject* object, const char* name, bool b) } void -aJsonClass::addNumberToObject(aJsonObject* object, const char* name, int n) +aJsonClass::addNumberToObject(aJsonObject* object, const char* name, long int n) { addItemToObject(object, name, createItem(n)); } @@ -1273,5 +1324,7 @@ aJsonClass::addStringToObject(aJsonObject* object, const char* name, } //TODO conversion routines btw. float & int types? +void debugPrint(const char* s){Serial.print(s);} aJsonClass aJson; + diff --git a/aJSON.h b/aJSON.h old mode 100644 new mode 100755 index a409a92..333866f --- a/aJSON.h +++ b/aJSON.h @@ -41,8 +41,11 @@ #define aJson_String 4 #define aJson_Array 5 #define aJson_Object 6 +#define aJson_Reserved 7 -#define aJson_IsReference 128 + +////#define aJson_IsReference 128 +#define aJson_IsReference 8 #ifndef EOF #define EOF -1 @@ -52,17 +55,17 @@ // 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. + 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. - + unsigned char type:4; // The type of the item, as above. + unsigned char subtype:4; // User defined field union { char *valuestring; // The item's string, if type==aJson_String char valuebool; //the items value for true & false - int valueint; // The item's value, if type==aJson_Int - double valuefloat; // The item's value, if type==aJson_Float + long int valueint; // The item's value, if type==aJson_Int + float valuefloat; // The item's value, if type==aJson_Float }; } aJsonObject; @@ -89,16 +92,16 @@ class aJsonStream : public Print { int printString(aJsonObject *item); int skip(); - int flush(); + void flush(); int parseValue(aJsonObject *item, char** filter); - int printValue(aJsonObject *item); + int printValue(aJsonObject *item, bool print_hidden = true); int parseArray(aJsonObject *item, char** filter); - int printArray(aJsonObject *item); + int printArray(aJsonObject *item, bool print_hidden = true); int parseObject(aJsonObject *item, char** filter); - int printObject(aJsonObject *item); + int printObject(aJsonObject *item, bool print_hidden = true); protected: /* Blocking load of character, returning EOF if the stream @@ -167,6 +170,20 @@ class aJsonStringStream : public aJsonStream { size_t inbuf_len, outbuf_len; }; +class aJsonFileStream : public aJsonStream { +public: + aJsonFileStream(FILE* _fl) + : aJsonStream(NULL) + { + fl=_fl; + } + + +private: + virtual int getch(); + FILE* fl; +}; + class aJsonClass { /****************************************************************************** * Constructors @@ -181,7 +198,7 @@ class aJsonClass { aJsonObject* parse(aJsonStream* 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, aJsonStream* stream); + int print(aJsonObject *item, aJsonStream* stream, bool print_hidden=true); char* print(aJsonObject* item); //Renders a aJsonObject directly to a output stream char stream(aJsonObject *item, aJsonStream* stream); @@ -199,14 +216,14 @@ class aJsonClass { aJsonObject* createNull(); aJsonObject* createItem(bool b); aJsonObject* createItem(char b); - aJsonObject* createItem(int num); + aJsonObject* createItem(long 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* createIntArray(long 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); @@ -234,7 +251,7 @@ class aJsonClass { void addNullToObject(aJsonObject* object, const char* name); void addBooleanToObject(aJsonObject* object, const char* name, bool b); - void addNumberToObject(aJsonObject* object, const char* name, int n); + void addNumberToObject(aJsonObject* object, const char* name, long int n); void addNumberToObject(aJsonObject* object, const char* name, double n); void addStringToObject(aJsonObject* object, const char* name, const char* s); @@ -251,4 +268,12 @@ class aJsonClass { extern aJsonClass aJson; +#ifdef __cplusplus +extern "C" +{ +#endif +void debugPrint(const char* s); +#ifdef __cplusplus +} +#endif #endif diff --git a/sam/pgmspace.h b/sam/pgmspace.h new file mode 100644 index 0000000..b4e8df0 --- /dev/null +++ b/sam/pgmspace.h @@ -0,0 +1,38 @@ +#ifndef __PGMSPACE_H_ +#define __PGMSPACE_H_ 1 + +#include + +#define PROGMEM +#define PGM_P const char * +#define PSTR(str) (str) + +typedef void prog_void; +typedef char prog_char; +typedef unsigned char prog_uchar; +typedef int8_t prog_int8_t; +typedef uint8_t prog_uint8_t; +typedef int16_t prog_int16_t; +typedef uint16_t prog_uint16_t; +typedef int32_t prog_int32_t; +typedef uint32_t prog_uint32_t; + +#define strcpy_P(dest, src) strcpy((dest), (src)) +#define strcat_P(dest, src) strcat((dest), (src)) +#define strcmp_P(a, b) strcmp((a), (b)) + +#define pgm_read_byte(addr) (*(const unsigned char *)(addr)) +#define pgm_read_word(addr) (*(const unsigned short *)(addr)) +#define pgm_read_dword(addr) (*(const unsigned long *)(addr)) +#define pgm_read_float(addr) (*(const float *)(addr)) + +#define pgm_read_byte_near(addr) pgm_read_byte(addr) +#define pgm_read_word_near(addr) pgm_read_word(addr) +#define pgm_read_dword_near(addr) pgm_read_dword(addr) +#define pgm_read_float_near(addr) pgm_read_float(addr) +#define pgm_read_byte_far(addr) pgm_read_byte(addr) +#define pgm_read_word_far(addr) pgm_read_word(addr) +#define pgm_read_dword_far(addr) pgm_read_dword(addr) +#define pgm_read_float_far(addr) pgm_read_float(addr) + +#endif diff --git a/utility/stringbuffer.c b/utility/stringbuffer.c index 87eda53..08249b4 100644 --- a/utility/stringbuffer.c +++ b/utility/stringbuffer.c @@ -24,9 +24,16 @@ #include #include #include "stringbuffer.h" +#include +//#include + //Default buffer size for strings +#if defined(ARDUINO_ARCH_AVR) +#define BUFFER_SIZE 64 +#else #define BUFFER_SIZE 256 +#endif //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]; @@ -55,7 +62,7 @@ stringBufferCreate(void) char stringBufferAdd(char value, string_buffer* buffer) { - if (buffer->string_length >= buffer->memory) + if (buffer->string_length >= buffer->memory-1) { //this has to be enabled after realloc works /*char* new_string = (char*) realloc((void*) buffer->string, (buffer->memory @@ -95,12 +102,20 @@ stringBufferToString(string_buffer* buffer) buffer->string=NULL; free(buffer); return string;*/ - char* result = malloc(buffer->string_length * sizeof(char)); + + ///char* result = malloc(buffer->string_length * sizeof(char)); + + char * result = newString(global_buffer); if (result == NULL) { + // debugPrint(("String allocation error\n")); return NULL; } - strcpy(result, global_buffer); + + ///strcpy(result, global_buffer); + + + buffer->string = NULL; free(buffer); return result; @@ -123,3 +138,94 @@ stringBufferFree(string_buffer* buffer) free(buffer); } +static string_card stringLib ={NULL,0,NULL}; + + string_card *findString(char * str) + { + string_card * card = &stringLib; + if (!str) return NULL; + do + { + if (card->string && !strcmp(str,card->string)) return card; + card = card->next; + } while (card); + return NULL; + } + + char *newString(const char * str) + { + //debugPrint(str); + string_card * card = findString(str); + string_card * prevCard; + if (card) + { + //debugPrint(":reused; "); + card->used++; + return card->string; + } + else + { + card = &stringLib; + do + { + if(!card->string) + { + card->string = strdup(str); + card->used=1; + //debugPrint(":added/replaced; "); + return card->string; + } + prevCard = card; + card = card->next; + } while (card); + + card = malloc (sizeof(string_card)); + if (card) + { + prevCard->next = card; + card->string = strdup(str); + card->used=1; + card->next=NULL; + //debugPrint(":added "); + return card->string; + } + } + return NULL; + } + + void freeString(char * str) + { + string_card * card = findString(str); + if (!card) return; + card->used--; + if (!card->used) + { + //debugPrint(str); + free(card->string); + card->string = NULL; + //debugPrint(":removed "); + compressList(); + } + } + + void compressList() + { + string_card * prevPtr = &stringLib; + string_card * nextPtr = prevPtr->next; + while (nextPtr) + { + if (!nextPtr->string) + { + //removing card + prevPtr->next=nextPtr->next; + free (nextPtr); + nextPtr=prevPtr->next; + } + else + { + prevPtr=nextPtr; + nextPtr=nextPtr->next; + } + } + //debugPrint(("Compressed\n")); + } \ No newline at end of file diff --git a/utility/stringbuffer.h b/utility/stringbuffer.h index b0a8181..6c9778a 100644 --- a/utility/stringbuffer.h +++ b/utility/stringbuffer.h @@ -24,7 +24,7 @@ #ifndef STRINGBUFFER_H_ #define STRINGBUFFER_H_ - +#include typedef struct { char* string; @@ -32,11 +32,12 @@ typedef struct unsigned int string_length; } string_buffer; + #ifdef __cplusplus extern "C" { #endif - +extern void debugPrint(const char*); string_buffer* stringBufferCreate(void); @@ -49,7 +50,24 @@ extern "C" void stringBufferFree(string_buffer* buffer); +typedef struct string_card string_card; +struct string_card +{ + char* string; + uint8_t used; + string_card * next; +}; + + + + string_card *findString(char *); + char *newString(const char *); + void freeString(char *); + void compressList(); + + #ifdef __cplusplus } #endif + #endif /* STRINGBUFFER_H_ */