| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252 |
- #include "JSONNode.h"
- #ifdef JSON_WRITE_PRIORITY
- #include "JSONWorker.h"
- #include "JSONGlobals.h"
- extern bool used_ascii_one;
- #ifdef JSON_INDENT
- inline json_string makeIndent(unsigned int amount) json_nothrow json_write_priority;
- inline json_string makeIndent(unsigned int amount) json_nothrow {
- if (amount == 0xFFFFFFFF) return json_global(EMPTY_JSON_STRING);
- json_string result;
- result.reserve(amount * json_global(INDENT).length());
- for(unsigned int i = 0; i < amount; ++i){
- result += json_global(INDENT);
- }
- JSON_ASSERT(result.capacity() == amount * json_global(INDENT).length(), JSON_TEXT("makeIndent made a string too big"));
- return result;
- }
- #else
- inline json_string makeIndent(unsigned int amount) json_nothrow {
- if (amount == 0xFFFFFFFF) return json_global(EMPTY_JSON_STRING);
- if (json_likely(amount < 8)){
- static const json_string cache[] = {
- json_string(),
- json_string(JSON_TEXT("\t")),
- json_string(JSON_TEXT("\t\t")),
- json_string(JSON_TEXT("\t\t\t")),
- json_string(JSON_TEXT("\t\t\t\t")),
- json_string(JSON_TEXT("\t\t\t\t\t")),
- json_string(JSON_TEXT("\t\t\t\t\t\t")),
- json_string(JSON_TEXT("\t\t\t\t\t\t\t"))
- };
- return cache[amount];
- }
- #ifndef JSON_LESS_MEMORY
- if (json_likely(amount < 16)){
- static const json_string cache[] = {
- json_string(JSON_TEXT("\t\t\t\t\t\t\t\t")),
- json_string(JSON_TEXT("\t\t\t\t\t\t\t\t\t")),
- json_string(JSON_TEXT("\t\t\t\t\t\t\t\t\t\t")),
- json_string(JSON_TEXT("\t\t\t\t\t\t\t\t\t\t\t")),
- json_string(JSON_TEXT("\t\t\t\t\t\t\t\t\t\t\t\t")),
- json_string(JSON_TEXT("\t\t\t\t\t\t\t\t\t\t\t\t\t")),
- json_string(JSON_TEXT("\t\t\t\t\t\t\t\t\t\t\t\t\t\t")),
- json_string(JSON_TEXT("\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t"))
- };
- return cache[amount - 8];
- }
- #if JSON_WRITE_PRIORITY == HIGH
- if (json_likely(amount < 24)){
- static const json_string cache[] = {
- json_string(JSON_TEXT("\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t")),
- json_string(JSON_TEXT("\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t")),
- json_string(JSON_TEXT("\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t")),
- json_string(JSON_TEXT("\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t")),
- json_string(JSON_TEXT("\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t")),
- json_string(JSON_TEXT("\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t")),
- json_string(JSON_TEXT("\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t")),
- json_string(JSON_TEXT("\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t"))
- };
- return cache[amount - 16];
- }
- #endif
- #endif
- return json_string(amount, JSON_TEXT('\t'));
- }
- #endif
- void internalJSONNode::WriteName(bool formatted, bool arrayChild, json_string & output) const json_nothrow {
- if (!arrayChild){
- output += JSON_TEXT("\"");
- JSONWorker::UnfixString(_name, _name_encoded, output);
- output += ((formatted) ? JSON_TEXT("\" : ") : JSON_TEXT("\":"));
- }
- }
- void internalJSONNode::WriteChildren(unsigned int indent, json_string & output) const json_nothrow {
- //Iterate through the children and write them
- if (json_likely(CHILDREN -> empty())) return;
- json_string indent_plus_one;
- //handle whether or not it's formatted JSON
- if (indent != 0xFFFFFFFF){ //it's formatted, make the indentation strings
- indent_plus_one = json_global(NEW_LINE) + makeIndent(++indent);
- }
- //else it's not formatted, leave the indentation strings empty
- const size_t size_minus_one = CHILDREN -> size() - 1;
- size_t i = 0;
- JSONNode ** it = CHILDREN -> begin();
- for(JSONNode ** it_end = CHILDREN -> end(); it != it_end; ++it, ++i){
- output += indent_plus_one;
- (*it) -> internal -> Write(indent, type() == JSON_ARRAY, output);
- if (json_likely(i < size_minus_one)) output += JSON_TEXT(','); //the last one does not get a comma, but all of the others do
- }
- if (indent != 0xFFFFFFFF){
- output += json_global(NEW_LINE);
- output += makeIndent(indent - 1);
- }
- }
- #ifdef JSON_ARRAY_SIZE_ON_ONE_LINE
- void internalJSONNode::WriteChildrenOneLine(unsigned int indent, json_string & output) const json_nothrow {
- //Iterate through the children and write them
- if (json_likely(CHILDREN -> empty())) return;
- if ((*CHILDREN -> begin()) -> internal -> isContainer()) return WriteChildren(indent, output);
- json_string comma(JSON_TEXT(","));
- if (indent != 0xFFFFFFFF){
- comma += JSON_TEXT(' ');
- }
- //else it's not formatted, leave the indentation strings empty
- const size_t size_minus_one = CHILDREN -> size() - 1;
- size_t i = 0;
- JSONNode ** it = CHILDREN -> begin();
- for(JSONNode ** it_end = CHILDREN -> end(); it != it_end; ++it, ++i){
- (*it) -> internal -> Write(indent, type() == JSON_ARRAY, output);
- if (json_likely(i < size_minus_one)) output += comma; //the last one does not get a comma, but all of the others do
- }
- }
- #endif
- #ifdef JSON_COMMENTS
- void internalJSONNode::WriteComment(unsigned int indent, json_string & output) const json_nothrow {
- if (indent == 0xFFFFFFFF) return;
- if (json_likely(_comment.empty())) return;
- size_t pos = _comment.find(JSON_TEXT('\n'));
-
- const json_string current_indent(json_global(NEW_LINE) + makeIndent(indent));
-
- if (json_likely(pos == json_string::npos)){ //Single line comment
- output += current_indent;
- output += json_global(SINGLELINE_COMMENT);
- output.append(_comment.begin(), _comment.end());
- output += current_indent;
- return;
- }
- /*
- Multiline comments
- */
- output += current_indent;
- #if !(defined(JSON_WRITE_BASH_COMMENTS) || defined(JSON_WRITE_SINGLE_LINE_COMMENTS))
- const json_string current_indent_plus_one(json_global(NEW_LINE) + makeIndent(indent + 1));
- output += JSON_TEXT("/*");
- output += current_indent_plus_one;
- #endif
- size_t old = 0;
- while(pos != json_string::npos){
- if (json_unlikely(pos && _comment[pos - 1] == JSON_TEXT('\r'))) --pos;
- #if defined(JSON_WRITE_BASH_COMMENTS) || defined(JSON_WRITE_SINGLE_LINE_COMMENTS)
- output += json_global(SINGLELINE_COMMENT);
- #endif
- output.append(_comment.begin() + old, _comment.begin() + pos);
-
- #if defined(JSON_WRITE_BASH_COMMENTS) || defined(JSON_WRITE_SINGLE_LINE_COMMENTS)
- output += current_indent;
- #else
- output += current_indent_plus_one;
- #endif
- old = (_comment[pos] == JSON_TEXT('\r')) ? pos + 2 : pos + 1;
- pos = _comment.find(JSON_TEXT('\n'), old);
- }
- #if defined(JSON_WRITE_BASH_COMMENTS) || defined(JSON_WRITE_SINGLE_LINE_COMMENTS)
- output += json_global(SINGLELINE_COMMENT);
- #endif
- output.append(_comment.begin() + old, _comment.end());
- output += current_indent;
- #if !(defined(JSON_WRITE_BASH_COMMENTS) || defined(JSON_WRITE_SINGLE_LINE_COMMENTS))
- output += JSON_TEXT("*/");
- output += current_indent;
- #endif
- }
- #else
- inline void internalJSONNode::WriteComment(unsigned int, json_string &) const json_nothrow {}
- #endif
- void internalJSONNode::DumpRawString(json_string & output) const json_nothrow {
- //first remove the \1 characters
- if (used_ascii_one){ //if it hasn't been used yet, don't bother checking
- json_string result(_string.begin(), _string.end());
- for(json_string::iterator beg = result.begin(), en = result.end(); beg != en; ++beg){
- if (*beg == JSON_TEXT('\1')) *beg = JSON_TEXT('\"');
- }
- output += result;
- return;
- } else {
- output.append(_string.begin(), _string.end());
- }
- }
- void internalJSONNode::Write(unsigned int indent, bool arrayChild, json_string & output) const json_nothrow {
- const bool formatted = indent != 0xFFFFFFFF;
- WriteComment(indent, output);
-
- #if !defined(JSON_PREPARSE) && defined(JSON_READ_PRIORITY)
- if (!(formatted || fetched)){ //It's not formatted or fetched, just do a raw dump
- WriteName(false, arrayChild, output);
- //first remove the \1 characters
- DumpRawString(output);
- return;
- }
- #endif
- WriteName(formatted, arrayChild, output);
- //It's either formatted or fetched
- switch (_type){
- case JSON_NODE: //got members, write the members
- Fetch();
- output += JSON_TEXT("{");
- WriteChildren(indent, output);
- output += JSON_TEXT("}");
- return;
- case JSON_ARRAY: //write out the child nodes int he array
- Fetch();
- output += JSON_TEXT("[");
- #ifdef JSON_ARRAY_SIZE_ON_ONE_LINE
- if (size() <= JSON_ARRAY_SIZE_ON_ONE_LINE){
- WriteChildrenOneLine(indent, output);
- } else {
- #endif
- WriteChildren(indent, output);
- #ifdef JSON_ARRAY_SIZE_ON_ONE_LINE
- }
- #endif
- output += JSON_TEXT("]");
- return;
- case JSON_NUMBER: //write out a literal, without quotes
- case JSON_NULL:
- case JSON_BOOL:
- output.append(_string.begin(), _string.end());
- return;
- }
- JSON_ASSERT(_type == JSON_STRING, JSON_TEXT("Unknown json node type"));
- //If it go here, then it's a json_string
- #if !defined(JSON_PREPARSE) && defined(JSON_READ_PRIORITY)
- if (json_likely(fetched)){
- #endif
- output += JSON_TEXT("\"");
- JSONWorker::UnfixString(_string, _string_encoded, output); //It's already been fetched, meaning that it's unescaped
- output += JSON_TEXT("\"");
- #if !defined(JSON_PREPARSE) && defined(JSON_READ_PRIORITY)
- } else {
- DumpRawString(output); //it hasn't yet been fetched, so it's already unescaped, just do a dump
- }
- #endif
- }
- #endif
|