Jamoma API  0.6.0.a19
JSONStream.cpp
1 #include "JSONStream.h"
2 
3 #ifdef JSON_STREAM
4 #include "JSONWorker.h"
5 #include "JSONValidator.h"
6 
7 
8 JSONStream::JSONStream(json_stream_callback_t call_p, json_stream_e_callback_t call_e, void * callbackIdentifier) json_nothrow : state(true), call(call_p), err_call(call_e), buffer(), callback_identifier(callbackIdentifier) {
9  LIBJSON_CTOR;
10 }
11 
12 JSONStream::JSONStream(const JSONStream & orig) json_nothrow : state(orig.state), call(orig.call), err_call(orig.err_call), buffer(orig.buffer), callback_identifier(orig.callback_identifier){
13  LIBJSON_COPY_CTOR;
14 }
15 
16 JSONStream & JSONStream::operator =(const JSONStream & orig) json_nothrow {
17  LIBJSON_ASSIGNMENT;
18  err_call = orig.err_call;
19  call = orig.call;
20  state = orig.state;
21  buffer = orig.buffer;
22  callback_identifier = orig.callback_identifier;
23  return *this;
24 }
25 
26 #ifdef JSON_LIBRARY
27  JSONStream & JSONStream::operator << (const json_char * str) json_nothrow {
28 #else
29  JSONStream & JSONStream::operator << (const json_string & str) json_nothrow {
30 #endif
31  if (state){
32  buffer += str;
33  parse();
34  }
35  return *this;
36 }
37 
38 
39 #define QUOTECASE_STREAM()\
40  case JSON_TEXT('\"'):\
41  while (*(++p) != JSON_TEXT('\"')){\
42  if (json_unlikely(*p == JSON_TEXT('\0'))) return json_string::npos;\
43  }\
44  break;
45 
46 
47 #define NULLCASE_STREAM()\
48  case JSON_TEXT('\0'):\
49  return json_string::npos;\
50 
51 
52 #define BRACKET_STREAM(left, right)\
53  case left: {\
54  size_t brac = 1;\
55  while (brac){\
56  switch (*(++p)){\
57  case right:\
58  --brac;\
59  break;\
60  case left:\
61  ++brac;\
62  break;\
63  QUOTECASE_STREAM()\
64  NULLCASE_STREAM()\
65  }\
66  }\
67  break;}\
68  case right:\
69  return json_string::npos;
70 
71 #if (JSON_READ_PRIORITY == HIGH) && (!(defined(JSON_LESS_MEMORY)))
72  #define STREAM_FIND_NEXT_RELEVANT(ch, vt, po) FindNextRelevant<ch>(vt, po)
73  template<json_char ch>
74  size_t JSONStream::FindNextRelevant(const json_string & value_t, const size_t pos) json_nothrow {
75 #else
76  #define STREAM_FIND_NEXT_RELEVANT(ch, vt, po) FindNextRelevant(ch, vt, po)
77  size_t JSONStream::FindNextRelevant(json_char ch, const json_string & value_t, const size_t pos) json_nothrow {
78 #endif
79  const json_char * start = value_t.c_str();
80  for (const json_char * p = start + pos; *p; ++p){
81  if (json_unlikely(*p == ch)) return p - start;
82  switch (*p){
83  BRACKET_STREAM(JSON_TEXT('['), JSON_TEXT(']'))
84  BRACKET_STREAM(JSON_TEXT('{'), JSON_TEXT('}'))
85  QUOTECASE_STREAM()
86  }
87  };
88  return json_string::npos;
89 }
90 
91 void JSONStream::parse(void) json_nothrow {
92  #ifdef JSON_SECURITY_MAX_STREAM_OBJECTS
93  size_t objects = 0;
94  #endif
95  for(;;){
96  size_t pos = buffer.find_first_of(JSON_TEXT("{["));
97  if (json_likely(pos != json_string::npos)){
98  size_t end = (buffer[pos] == JSON_TEXT('[')) ? STREAM_FIND_NEXT_RELEVANT(JSON_TEXT(']'), buffer, pos + 1) : STREAM_FIND_NEXT_RELEVANT(JSON_TEXT('}'), buffer, pos + 1);
99  if (end != json_string::npos){
100  #ifdef JSON_SECURITY_MAX_STREAM_OBJECTS
101  if (++objects > JSON_SECURITY_MAX_STREAM_OBJECTS){
102  JSON_FAIL(JSON_TEXT("Maximum number of json objects for a stream at once has been reached"));
103  if (err_call) err_call(getIdentifier());
104  state = false;
105  return;
106  }
107  #endif
108  START_MEM_SCOPE
109  JSONNode temp(JSONWorker::parse(buffer.substr(pos, end - pos + 1)));
110  #ifndef JSON_LIBRARY
111  call(temp, getIdentifier());
112  #else
113  call(&temp, getIdentifier());
114  #endif
115  END_MEM_SCOPE
116  json_string::iterator beginning = buffer.begin();
117  buffer.erase(beginning, beginning + end);
118  continue; //parse(); //parse the next object too
119  }
120  #ifdef JSON_SAFE
121  else {
122  //verify that what's in there is at least valid so far
123  #ifndef JSON_VALIDATE
124  #error In order to use safe mode and streams, JSON_VALIDATE needs to be defined
125  #endif
126 
127  json_auto<json_char> s;
128  size_t len;
129  s.set(JSONWorker::RemoveWhiteSpace(json_string(buffer.c_str() + pos), len, false));
130 
131 
132  if (!JSONValidator::isValidPartialRoot(s.ptr)){
133  if (err_call) err_call(getIdentifier());
134  state = false;
135  }
136  }
137  #endif
138  }
139  break;
140  }
141 }
142 
143 #endif