The R Project SVN R-packages

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
7747 ripley 1
#include "JSONNode.h"
2
#ifdef JSON_WRITE_PRIORITY
3
#include "JSONWorker.h"
4
#include "JSONGlobals.h"
5
 
6
extern bool used_ascii_one;
7
 
8
#ifdef JSON_INDENT
9
    inline json_string makeIndent(unsigned int amount) json_nothrow json_write_priority;
10
    inline json_string makeIndent(unsigned int amount) json_nothrow {
11
	   if (amount == 0xFFFFFFFF) return json_global(EMPTY_JSON_STRING);
12
	   json_string result;
13
	   result.reserve(amount * json_global(INDENT).length());
14
	   for(unsigned int i = 0; i < amount; ++i){
15
		  result += json_global(INDENT);
16
	   }
17
	   JSON_ASSERT(result.capacity() == amount * json_global(INDENT).length(), JSON_TEXT("makeIndent made a string too big"));
18
	   return result;
19
    }
20
#else
21
    inline json_string makeIndent(unsigned int amount) json_nothrow {
22
		if (amount == 0xFFFFFFFF) return json_global(EMPTY_JSON_STRING);
23
		if (json_likely(amount < 8)){
24
			static const json_string cache[] = {
25
				json_string(),
26
				json_string(JSON_TEXT("\t")),
27
				json_string(JSON_TEXT("\t\t")),
28
				json_string(JSON_TEXT("\t\t\t")),
29
				json_string(JSON_TEXT("\t\t\t\t")),
30
				json_string(JSON_TEXT("\t\t\t\t\t")),
31
				json_string(JSON_TEXT("\t\t\t\t\t\t")),
32
				json_string(JSON_TEXT("\t\t\t\t\t\t\t"))
33
			};
34
			return cache[amount];
35
		}
36
		#ifndef JSON_LESS_MEMORY
37
			if (json_likely(amount < 16)){
38
				static const json_string cache[] = {
39
					json_string(JSON_TEXT("\t\t\t\t\t\t\t\t")),
40
					json_string(JSON_TEXT("\t\t\t\t\t\t\t\t\t")),
41
					json_string(JSON_TEXT("\t\t\t\t\t\t\t\t\t\t")),
42
					json_string(JSON_TEXT("\t\t\t\t\t\t\t\t\t\t\t")),
43
					json_string(JSON_TEXT("\t\t\t\t\t\t\t\t\t\t\t\t")),
44
					json_string(JSON_TEXT("\t\t\t\t\t\t\t\t\t\t\t\t\t")),
45
					json_string(JSON_TEXT("\t\t\t\t\t\t\t\t\t\t\t\t\t\t")),
46
					json_string(JSON_TEXT("\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t"))
47
				};
48
				return cache[amount - 8];
49
			}
50
			#if JSON_WRITE_PRIORITY == HIGH
51
				if (json_likely(amount < 24)){
52
					static const json_string cache[] = {
53
						json_string(JSON_TEXT("\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t")),
54
						json_string(JSON_TEXT("\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t")),
55
						json_string(JSON_TEXT("\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t")),
56
						json_string(JSON_TEXT("\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t")),
57
						json_string(JSON_TEXT("\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t")),
58
						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")),
59
						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")),
60
						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"))
61
					};
62
					return cache[amount - 16];
63
				}
64
			#endif
65
		#endif
66
		return json_string(amount, JSON_TEXT('\t'));
67
    }
68
#endif
69
 
70
void internalJSONNode::WriteName(bool formatted, bool arrayChild, json_string & output) const json_nothrow {
71
    if (!arrayChild){
72
		output += JSON_TEXT("\"");
73
		JSONWorker::UnfixString(_name, _name_encoded, output);
74
		output += ((formatted) ? JSON_TEXT("\" : ") : JSON_TEXT("\":"));
75
    }
76
}
77
 
78
void internalJSONNode::WriteChildren(unsigned int indent, json_string & output) const json_nothrow {
79
    //Iterate through the children and write them
80
    if (json_likely(CHILDREN -> empty())) return;
81
 
82
    json_string indent_plus_one;
83
    //handle whether or not it's formatted JSON
84
    if (indent != 0xFFFFFFFF){  //it's formatted, make the indentation strings
85
	   indent_plus_one = json_global(NEW_LINE) + makeIndent(++indent);
86
    }
87
 
88
    //else it's not formatted, leave the indentation strings empty
89
    const size_t size_minus_one = CHILDREN -> size() - 1;
90
    size_t i = 0;
91
    JSONNode ** it = CHILDREN -> begin();
92
    for(JSONNode ** it_end = CHILDREN -> end(); it != it_end; ++it, ++i){
93
 
94
		output += indent_plus_one;
95
		(*it) -> internal -> Write(indent, type() == JSON_ARRAY, output);
96
	    if (json_likely(i < size_minus_one)) output += JSON_TEXT(',');  //the last one does not get a comma, but all of the others do
97
    }
98
    if (indent != 0xFFFFFFFF){
99
		output += json_global(NEW_LINE);
100
		output += makeIndent(indent - 1);
101
    }
102
}
103
 
104
#ifdef JSON_ARRAY_SIZE_ON_ONE_LINE
105
    void internalJSONNode::WriteChildrenOneLine(unsigned int indent, json_string & output) const json_nothrow {
106
	   //Iterate through the children and write them
107
	   if (json_likely(CHILDREN -> empty())) return;
108
	   if ((*CHILDREN -> begin()) -> internal -> isContainer()) return WriteChildren(indent, output);
109
 
110
	   json_string comma(JSON_TEXT(","));
111
	   if (indent != 0xFFFFFFFF){
112
		  comma += JSON_TEXT(' ');
113
	   }
114
 
115
	   //else it's not formatted, leave the indentation strings empty
116
	   const size_t size_minus_one = CHILDREN -> size() - 1;
117
	   size_t i = 0;
118
	   JSONNode ** it = CHILDREN -> begin();
119
	   for(JSONNode ** it_end = CHILDREN -> end(); it != it_end; ++it, ++i){
120
		  (*it) -> internal -> Write(indent, type() == JSON_ARRAY, output);
121
		  if (json_likely(i < size_minus_one)) output += comma;  //the last one does not get a comma, but all of the others do
122
	   }
123
    }
124
#endif
125
 
126
#ifdef JSON_COMMENTS
127
    void internalJSONNode::WriteComment(unsigned int indent, json_string & output) const json_nothrow {
128
	   if (indent == 0xFFFFFFFF) return;
129
	   if (json_likely(_comment.empty())) return;
130
	   size_t pos = _comment.find(JSON_TEXT('\n'));
131
 
132
	   const json_string current_indent(json_global(NEW_LINE) + makeIndent(indent));
133
 
134
	   if (json_likely(pos == json_string::npos)){  //Single line comment
135
		   output += current_indent;
136
		   output += json_global(SINGLELINE_COMMENT);
137
		   output.append(_comment.begin(), _comment.end());
138
		   output += current_indent;
139
		   return;
140
	   }
141
 
142
	   /*
143
	    Multiline comments
144
	    */
145
		output += current_indent;
146
	   #if !(defined(JSON_WRITE_BASH_COMMENTS) || defined(JSON_WRITE_SINGLE_LINE_COMMENTS))
147
		  const json_string current_indent_plus_one(json_global(NEW_LINE) + makeIndent(indent + 1));
148
		  output += JSON_TEXT("/*");
149
		  output += current_indent_plus_one;
150
	   #endif
151
	   size_t old = 0;
152
	   while(pos != json_string::npos){
153
		  if (json_unlikely(pos && _comment[pos - 1] == JSON_TEXT('\r'))) --pos;
154
		  #if defined(JSON_WRITE_BASH_COMMENTS) || defined(JSON_WRITE_SINGLE_LINE_COMMENTS)
155
			 output += json_global(SINGLELINE_COMMENT);
156
		  #endif
157
		  output.append(_comment.begin() + old, _comment.begin() + pos);
158
 
159
		  #if defined(JSON_WRITE_BASH_COMMENTS) || defined(JSON_WRITE_SINGLE_LINE_COMMENTS)
160
			 output += current_indent;
161
		  #else
162
			 output += current_indent_plus_one;
163
		  #endif
164
		  old = (_comment[pos] == JSON_TEXT('\r')) ? pos + 2 : pos + 1;
165
		  pos = _comment.find(JSON_TEXT('\n'), old);
166
	   }
167
	   #if defined(JSON_WRITE_BASH_COMMENTS) || defined(JSON_WRITE_SINGLE_LINE_COMMENTS)
168
		  output += json_global(SINGLELINE_COMMENT);
169
	   #endif
170
	   output.append(_comment.begin() + old, _comment.end());
171
	   output += current_indent;
172
	   #if !(defined(JSON_WRITE_BASH_COMMENTS) || defined(JSON_WRITE_SINGLE_LINE_COMMENTS))
173
		  output += JSON_TEXT("*/");
174
		  output += current_indent;
175
	   #endif
176
    }
177
#else
178
    inline void internalJSONNode::WriteComment(unsigned int, json_string &) const json_nothrow {}
179
#endif
180
 
181
void internalJSONNode::DumpRawString(json_string & output) const json_nothrow {
182
	//first remove the \1 characters
183
	if (used_ascii_one){  //if it hasn't been used yet, don't bother checking
184
		json_string result(_string.begin(), _string.end());
185
		for(json_string::iterator beg = result.begin(), en = result.end(); beg != en; ++beg){
186
			if (*beg == JSON_TEXT('\1')) *beg = JSON_TEXT('\"');
187
		}
188
		output += result;
189
		return;
190
	} else {
191
		output.append(_string.begin(), _string.end());
192
	}
193
}
194
 
195
void internalJSONNode::Write(unsigned int indent, bool arrayChild, json_string & output) const json_nothrow {
196
    const bool formatted = indent != 0xFFFFFFFF;
197
	WriteComment(indent, output);
198
 
199
    #if !defined(JSON_PREPARSE) && defined(JSON_READ_PRIORITY)
200
	   if (!(formatted || fetched)){  //It's not formatted or fetched, just do a raw dump
201
		   WriteName(false, arrayChild, output);
202
           //first remove the \1 characters
203
		   DumpRawString(output);
204
		   return;
205
	   }
206
    #endif
207
 
208
	WriteName(formatted, arrayChild, output);
209
    //It's either formatted or fetched
210
    switch (_type){
211
	   case JSON_NODE:   //got members, write the members
212
		  Fetch();
213
            output += JSON_TEXT("{");
214
			WriteChildren(indent, output);
215
			output += JSON_TEXT("}");
216
			return;
217
	   case JSON_ARRAY:	   //write out the child nodes int he array
218
		  Fetch();
219
		  output += JSON_TEXT("[");
220
		  #ifdef JSON_ARRAY_SIZE_ON_ONE_LINE
221
			 if (size() <= JSON_ARRAY_SIZE_ON_ONE_LINE){
222
				 WriteChildrenOneLine(indent, output);
223
			 } else {
224
		  #endif
225
				 WriteChildren(indent, output);
226
		  #ifdef JSON_ARRAY_SIZE_ON_ONE_LINE
227
			 }
228
		  #endif
229
            output += JSON_TEXT("]");
230
			return;
231
	   case JSON_NUMBER:   //write out a literal, without quotes
232
	   case JSON_NULL:
233
	   case JSON_BOOL:
234
            output.append(_string.begin(), _string.end());
235
			return;
236
    }
237
 
238
	JSON_ASSERT(_type == JSON_STRING, JSON_TEXT("Unknown json node type"));
239
    //If it go here, then it's a json_string
240
    #if !defined(JSON_PREPARSE) && defined(JSON_READ_PRIORITY)
241
		if (json_likely(fetched)){
242
	#endif
243
			output += JSON_TEXT("\"");
244
			JSONWorker::UnfixString(_string, _string_encoded, output);  //It's already been fetched, meaning that it's unescaped
245
			output += JSON_TEXT("\"");  
246
	#if !defined(JSON_PREPARSE) && defined(JSON_READ_PRIORITY)
247
		} else {
248
			DumpRawString(output);  //it hasn't yet been fetched, so it's already unescaped, just do a dump
249
		}
250
    #endif
251
}
252
#endif