August 2009: new versions planned
Although the JSON format is very stable and the wxJSON library version 1.0 does implement all JSON specifications, I received some feature requests from wxJSON users so I am about to release a few new versions of the library.
- Version 1.3: implementation of the new binary buffer data type
- Version 1.4: a better copy-on-write implementation for JSON values
In the next chapters you will find the detailed description of the new features for all the planned future versions.
Version 1.3
All of you already know that JSON is a text-based data interchange format but
the word data refers especially to program variables and not other
kind of data.
JSON is not suitable for exchanging binary data such as audio, video, image or
complex documents and it should not because it was not developed for that purpose.
The goals of JSON are: simple, human-readable, fasr and compact.
On the other hand, there may be some particular situations in which a program
should store and/or transmit small amount of binary data such as a small GIF
image (for example a logo), a 1- or 2-seconds sound or a tiny memory buffer.
In these situations, JSON is very limited: you cannot use JSON strings to store
binary data because they are converted to UTF-8, the only possible solution is
to use an array of numbers.
For example, if we want to store a simple GIF image we can write something like the
following:
The above may be a solution but it consumes a lot of space because for every
byte in the buffer we need 3-4 characters. Also, the program has to convert the
buffer into an array of INTs when writing the JSON text and to convert it
back when reading the stream.
{
"image" : {
"type" : "gif",
"width" : 160,
"height" : 160,
"data" : [ 32, 160, 255, 47, 89, 47, 123, 85, ... ]
}
}
wxJSON introduces another JSON data type as an extension of the JSON syntax:
the binary buffer data type.
In order to maintain the text-based format, the binary buffer is encoded as a
string of two hexadecimal digits for every byte and it is enclosed in single
quotes.
The above example will look like the following:
The reader will store such a type in a
{
"image" : {
"type" : "gif",
"width" : 160,
"height" : 160,
"data" : '20A0FF2F592F7B55...'
}
}
wxMemoryBuffer
object and
the wxJSONValue
class will have functions to return it:
A value of that type can be stored in a
bool wxJSONValue::IsMemBuffer();
wxMemoryBuffer* wxJSONValue::AsMemBuffer();
wxJSONValue
by constructing the oject
or by assigning to it a wxMemoryBuffer
object or a void pointer.
As the memory buffer is not valid JSON text, you have to use a special
wxJSONReader's flag in order to handle it otherwise an error will be reported.
wxJSONValue( const wxMemoryBuffer& mem );
wxJSONValue( const void* mem, size_t size );
By default, the wxJSONWriter will write a wxJSONValue that contains a binary
buffer type as an array of INTs thus producing valid JSON text output.
If you want to write the special binary buffer type which will be
recognized by the reader, you have to use a special writer's flag when constructing
it.
Note that other JSON implementations will fail to read such a text.
Version 1.4
Until version 1.3, the copy-on-write (COW) tecnique used by JSON
values is not optimized: the wxJSONValue
class just contained a
pointer to the referenced data:
Every time a copy of a JSON value is done, the copy-ctor and assignment
operator just increment the counter in the referenced data structure.
class wxJSONValue
{
...
private:
wxJSONValueRefData* m_refData;
}
This is good, but not optimum. If the wxJSONValue
object just
contains a primitive type - for example an integer - than it is more convenient
to directly store the actual value at the same address instead of storing
a pointer to the referenced data.
Moreover, it is more convenient to make a real copy of a primitive value
instead of incrementing a reference counter.
The new COW organization is based upon the concept that for primitive
types no reference count is needed, hence the actual value stored in the
JSON value object is actually copied by the copy-ctor and assignment
operators.
Only complex values such as key/value maps and arrays are reference counted.
The following is the list of data members in the new wxJSONValue
class:
Data type | name | content |
---|---|---|
wxJSONType | m_type | the type of the value stored (INT, STRING, DOUBLE...) |
wxString | m_valString | the actual JSON string value: because wxString uses COW it is copied |
int | m_commentPos | position of the comment line(s) |
wxArrayString | m_comments | the array of comment lines: an array of strings |
int | m_lineNo | used by the JSON parser: the line in the JSON text input |
wxJSONValueHolder | m_value | the actual value stored in this JSON value object |
Apart from the m_valString
data member which contains the
actual value of the object when it is of string type, all values are stored
in a union of type wxJSONValueHolder
:
union wxJSONValueHolder
{
int m_valInt;
unsigned int m_valUInt;
short int m_valShort;
unsigned short m_valUShort;
long int m_valLong;
unsigned long m_valULong;
double m_valDouble;
const wxChar* m_valCString;
bool m_valBool;
wxInt64 m_valInt64;
wxUint64 m_valUInt64;
wxJSONRefData* m_refData;
};
struct wxJSONRefData
{
int m_count;
wxJSONInternalArray m_valArray;
wxJSONInternalMap m_valMap;
}
As seen, all primitive types are stored in the same memory area. It is the
m_type
data member that identifies the correct type of the
value.
The copy-ctor and assignment operator just makes a copy of m_value
and that's all for primitive types.
If the type is an array or a key/value map, then the reference counter
in the referenced data (
wxJSONRefData::m_count
) is incremented.
On destruction, nothing has to be done for primitive types or string type.
If m_type == OBJECT or ARRAY
then the destructor decrements
the referenced data counter and, if it reaches ZERO, the wxJSONRefData
structure is freed.