~ubuntu-branches/ubuntu/trusty/cajun/trusty

« back to all changes in this revision

Viewing changes to .pc/0001-Fix-for-embedded-unicode.patch/json/reader.inl

  • Committer: Package Import Robot
  • Author(s): Daniel Pocock
  • Date: 2013-09-26 14:03:24 UTC
  • mfrom: (1.1.1)
  • Revision ID: package-import@ubuntu.com-20130926140324-m8cerngq0ct7rfoj
Tags: 2.0.3-1
* New upstream release
* Upstream now includes UTF-8 fix, local patch removed

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/******************************************************************************
2
 
 
3
 
Copyright (c) 2009-2010, Terry Caton
4
 
All rights reserved.
5
 
 
6
 
Redistribution and use in source and binary forms, with or without
7
 
modification, are permitted provided that the following conditions are met:
8
 
    * Redistributions of source code must retain the above copyright 
9
 
      notice, this list of conditions and the following disclaimer.
10
 
    * Redistributions in binary form must reproduce the above copyright
11
 
      notice, this list of conditions and the following disclaimer in the
12
 
      documentation and/or other materials provided with the distribution.
13
 
    * Neither the name of the projecct nor the names of its contributors 
14
 
      may be used to endorse or promote products derived from this software 
15
 
      without specific prior written permission.
16
 
 
17
 
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
18
 
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19
 
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 
20
 
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
21
 
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22
 
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23
 
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
24
 
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 
25
 
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
26
 
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
 
 
28
 
******************************************************************************/
29
 
 
30
 
#include <cassert>
31
 
#include <set>
32
 
#include <sstream>
33
 
 
34
 
/*  
35
 
 
36
 
TODO:
37
 
* better documentation
38
 
* unicode character decoding
39
 
 
40
 
*/
41
 
 
42
 
namespace json
43
 
{
44
 
 
45
 
inline std::istream& operator >> (std::istream& istr, UnknownElement& elementRoot) {
46
 
   Reader::Read(elementRoot, istr);
47
 
   return istr;
48
 
}
49
 
 
50
 
inline Reader::Location::Location() :
51
 
   m_nLine(0),
52
 
   m_nLineOffset(0),
53
 
   m_nDocOffset(0)
54
 
{}
55
 
 
56
 
 
57
 
//////////////////////
58
 
// Reader::InputStream
59
 
 
60
 
class Reader::InputStream // would be cool if we could inherit from std::istream & override "get"
61
 
{
62
 
public:
63
 
   InputStream(std::istream& iStr) :
64
 
      m_iStr(iStr) {}
65
 
 
66
 
   // protect access to the input stream, so we can keeep track of document/line offsets
67
 
   char Get(); // big, define outside
68
 
   char Peek() {
69
 
      assert(m_iStr.eof() == false); // enforce reading of only valid stream data 
70
 
      return m_iStr.peek();
71
 
   }
72
 
 
73
 
   bool EOS() {
74
 
      m_iStr.peek(); // apparently eof flag isn't set until a character read is attempted. whatever.
75
 
      return m_iStr.eof();
76
 
   }
77
 
 
78
 
   const Location& GetLocation() const { return m_Location; }
79
 
 
80
 
private:
81
 
   std::istream& m_iStr;
82
 
   Location m_Location;
83
 
};
84
 
 
85
 
 
86
 
inline char Reader::InputStream::Get()
87
 
{
88
 
   assert(m_iStr.eof() == false); // enforce reading of only valid stream data 
89
 
   char c = m_iStr.get();
90
 
   
91
 
   ++m_Location.m_nDocOffset;
92
 
   if (c == '\n') {
93
 
      ++m_Location.m_nLine;
94
 
      m_Location.m_nLineOffset = 0;
95
 
   }
96
 
   else {
97
 
      ++m_Location.m_nLineOffset;
98
 
   }
99
 
 
100
 
   return c;
101
 
}
102
 
 
103
 
 
104
 
 
105
 
//////////////////////
106
 
// Reader::TokenStream
107
 
 
108
 
class Reader::TokenStream
109
 
{
110
 
public:
111
 
   TokenStream(const Tokens& tokens);
112
 
 
113
 
   const Token& Peek();
114
 
   const Token& Get();
115
 
 
116
 
   bool EOS() const;
117
 
 
118
 
private:
119
 
   const Tokens& m_Tokens;
120
 
   Tokens::const_iterator m_itCurrent;
121
 
};
122
 
 
123
 
 
124
 
inline Reader::TokenStream::TokenStream(const Tokens& tokens) :
125
 
   m_Tokens(tokens),
126
 
   m_itCurrent(tokens.begin())
127
 
{}
128
 
 
129
 
inline const Reader::Token& Reader::TokenStream::Peek() {
130
 
   if (EOS())
131
 
   {
132
 
      const Token& lastToken = *m_Tokens.rbegin();
133
 
      std::string sMessage = "Unexpected end of token stream";
134
 
      throw ParseException(sMessage, lastToken.locBegin, lastToken.locEnd); // nowhere to point to
135
 
   }
136
 
   return *(m_itCurrent); 
137
 
}
138
 
 
139
 
inline const Reader::Token& Reader::TokenStream::Get() {
140
 
   const Token& token = Peek();
141
 
   ++m_itCurrent;
142
 
   return token;
143
 
}
144
 
 
145
 
inline bool Reader::TokenStream::EOS() const {
146
 
   return m_itCurrent == m_Tokens.end(); 
147
 
}
148
 
 
149
 
///////////////////
150
 
// Reader (finally)
151
 
 
152
 
 
153
 
inline void Reader::Read(Object& object, std::istream& istr)                { Read_i(object, istr); }
154
 
inline void Reader::Read(Array& array, std::istream& istr)                  { Read_i(array, istr); }
155
 
inline void Reader::Read(String& string, std::istream& istr)                { Read_i(string, istr); }
156
 
inline void Reader::Read(Number& number, std::istream& istr)                { Read_i(number, istr); }
157
 
inline void Reader::Read(Boolean& boolean, std::istream& istr)              { Read_i(boolean, istr); }
158
 
inline void Reader::Read(Null& null, std::istream& istr)                    { Read_i(null, istr); }
159
 
inline void Reader::Read(UnknownElement& unknown, std::istream& istr)       { Read_i(unknown, istr); }
160
 
 
161
 
 
162
 
template <typename ElementTypeT>   
163
 
void Reader::Read_i(ElementTypeT& element, std::istream& istr)
164
 
{
165
 
   Reader reader;
166
 
 
167
 
   Tokens tokens;
168
 
   InputStream inputStream(istr);
169
 
   reader.Scan(tokens, inputStream);
170
 
 
171
 
   TokenStream tokenStream(tokens);
172
 
   reader.Parse(element, tokenStream);
173
 
 
174
 
   if (tokenStream.EOS() == false)
175
 
   {
176
 
      const Token& token = tokenStream.Peek();
177
 
      std::string sMessage = std::string("Expected End of token stream; found ") + token.sValue;
178
 
      throw ParseException(sMessage, token.locBegin, token.locEnd);
179
 
   }
180
 
}
181
 
 
182
 
 
183
 
inline void Reader::Scan(Tokens& tokens, InputStream& inputStream)
184
 
{
185
 
   while (EatWhiteSpace(inputStream),              // ignore any leading white space...
186
 
          inputStream.EOS() == false) // ...before checking for EOS
187
 
   {
188
 
      // if all goes well, we'll create a token each pass
189
 
      Token token;
190
 
      token.locBegin = inputStream.GetLocation();
191
 
 
192
 
      // gives us null-terminated string
193
 
      char sChar = inputStream.Peek();
194
 
      switch (sChar)
195
 
      {
196
 
         case '{':
197
 
            token.sValue = MatchExpectedString(inputStream, "{");
198
 
            token.nType = Token::TOKEN_OBJECT_BEGIN;
199
 
            break;
200
 
 
201
 
         case '}':
202
 
            token.sValue = MatchExpectedString(inputStream, "}");
203
 
            token.nType = Token::TOKEN_OBJECT_END;
204
 
            break;
205
 
 
206
 
         case '[':
207
 
            token.sValue = MatchExpectedString(inputStream, "[");
208
 
            token.nType = Token::TOKEN_ARRAY_BEGIN;
209
 
            break;
210
 
 
211
 
         case ']':
212
 
            token.sValue = MatchExpectedString(inputStream, "]");
213
 
            token.nType = Token::TOKEN_ARRAY_END;
214
 
            break;
215
 
 
216
 
         case ',':
217
 
            token.sValue = MatchExpectedString(inputStream, ",");
218
 
            token.nType = Token::TOKEN_NEXT_ELEMENT;
219
 
            break;
220
 
 
221
 
         case ':':
222
 
            token.sValue = MatchExpectedString(inputStream, ":");
223
 
            token.nType = Token::TOKEN_MEMBER_ASSIGN;
224
 
            break;
225
 
 
226
 
         case '"':
227
 
            token.sValue = MatchString(inputStream);
228
 
            token.nType = Token::TOKEN_STRING;
229
 
            break;
230
 
 
231
 
         case '-':
232
 
         case '0':
233
 
         case '1':
234
 
         case '2':
235
 
         case '3':
236
 
         case '4':
237
 
         case '5':
238
 
         case '6':
239
 
         case '7':
240
 
         case '8':
241
 
         case '9':
242
 
            token.sValue = MatchNumber(inputStream);
243
 
            token.nType = Token::TOKEN_NUMBER;
244
 
            break;
245
 
 
246
 
         case 't':
247
 
            token.sValue = MatchExpectedString(inputStream, "true");
248
 
            token.nType = Token::TOKEN_BOOLEAN;
249
 
            break;
250
 
 
251
 
         case 'f':
252
 
            token.sValue = MatchExpectedString(inputStream, "false");
253
 
            token.nType = Token::TOKEN_BOOLEAN;
254
 
            break;
255
 
 
256
 
         case 'n':
257
 
            token.sValue = MatchExpectedString(inputStream, "null");
258
 
            token.nType = Token::TOKEN_NULL;
259
 
            break;
260
 
 
261
 
         default:
262
 
         {
263
 
            std::string sErrorMessage = std::string("Unexpected character in stream: ") + sChar;
264
 
            throw ScanException(sErrorMessage, inputStream.GetLocation());
265
 
         }
266
 
      }
267
 
 
268
 
      token.locEnd = inputStream.GetLocation();
269
 
      tokens.push_back(token);
270
 
   }
271
 
}
272
 
 
273
 
 
274
 
inline void Reader::EatWhiteSpace(InputStream& inputStream)
275
 
{
276
 
   while (inputStream.EOS() == false && 
277
 
          ::isspace(inputStream.Peek()))
278
 
      inputStream.Get();
279
 
}
280
 
 
281
 
inline std::string Reader::MatchExpectedString(InputStream& inputStream, const std::string& sExpected)
282
 
{
283
 
   std::string::const_iterator it(sExpected.begin()),
284
 
                               itEnd(sExpected.end());
285
 
   for ( ; it != itEnd; ++it) {
286
 
      if (inputStream.EOS() ||      // did we reach the end before finding what we're looking for...
287
 
          inputStream.Get() != *it) // ...or did we find something different?
288
 
      {
289
 
         std::string sMessage = std::string("Expected string: ") + sExpected;
290
 
         throw ScanException(sMessage, inputStream.GetLocation());
291
 
      }
292
 
   }
293
 
 
294
 
   // all's well if we made it here
295
 
   return sExpected;
296
 
}
297
 
 
298
 
 
299
 
inline std::string Reader::MatchString(InputStream& inputStream)
300
 
{
301
 
   MatchExpectedString(inputStream, "\"");
302
 
 
303
 
   std::string string;
304
 
   while (inputStream.EOS() == false &&
305
 
          inputStream.Peek() != '"')
306
 
   {
307
 
      char c = inputStream.Get();
308
 
 
309
 
      // escape?
310
 
      if (c == '\\' &&
311
 
          inputStream.EOS() == false) // shouldn't have reached the end yet
312
 
      {
313
 
         c = inputStream.Get();
314
 
         switch (c) {
315
 
            case '/':      string.push_back('/');     break;
316
 
            case '"':      string.push_back('"');     break;
317
 
            case '\\':     string.push_back('\\');    break;
318
 
            case 'b':      string.push_back('\b');    break;
319
 
            case 'f':      string.push_back('\f');    break;
320
 
            case 'n':      string.push_back('\n');    break;
321
 
            case 'r':      string.push_back('\r');    break;
322
 
            case 't':      string.push_back('\t');    break;
323
 
            case 'u':      string.push_back('\u');    break; // TODO: what do we do with this?
324
 
            default: {
325
 
               std::string sMessage = std::string("Unrecognized escape sequence found in string: \\") + c;
326
 
               throw ScanException(sMessage, inputStream.GetLocation());
327
 
            }
328
 
         }
329
 
      }
330
 
      else {
331
 
         string.push_back(c);
332
 
      }
333
 
   }
334
 
 
335
 
   // eat the last '"' that we just peeked
336
 
   MatchExpectedString(inputStream, "\"");
337
 
 
338
 
   // all's well if we made it here
339
 
   return string;
340
 
}
341
 
 
342
 
 
343
 
inline std::string Reader::MatchNumber(InputStream& inputStream)
344
 
{
345
 
   const char sNumericChars[] = "0123456789.eE-+";
346
 
   std::set<char> numericChars;
347
 
   numericChars.insert(sNumericChars, sNumericChars + sizeof(sNumericChars));
348
 
 
349
 
   std::string sNumber;
350
 
   while (inputStream.EOS() == false &&
351
 
          numericChars.find(inputStream.Peek()) != numericChars.end())
352
 
   {
353
 
      sNumber.push_back(inputStream.Get());   
354
 
   }
355
 
 
356
 
   return sNumber;
357
 
}
358
 
 
359
 
 
360
 
inline void Reader::Parse(UnknownElement& element, Reader::TokenStream& tokenStream) 
361
 
{
362
 
   const Token& token = tokenStream.Peek();
363
 
   switch (token.nType) {
364
 
      case Token::TOKEN_OBJECT_BEGIN:
365
 
      {
366
 
         // implicit non-const cast will perform conversion for us (if necessary)
367
 
         Object& object = element;
368
 
         Parse(object, tokenStream);
369
 
         break;
370
 
      }
371
 
 
372
 
      case Token::TOKEN_ARRAY_BEGIN:
373
 
      {
374
 
         Array& array = element;
375
 
         Parse(array, tokenStream);
376
 
         break;
377
 
      }
378
 
 
379
 
      case Token::TOKEN_STRING:
380
 
      {
381
 
         String& string = element;
382
 
         Parse(string, tokenStream);
383
 
         break;
384
 
      }
385
 
 
386
 
      case Token::TOKEN_NUMBER:
387
 
      {
388
 
         Number& number = element;
389
 
         Parse(number, tokenStream);
390
 
         break;
391
 
      }
392
 
 
393
 
      case Token::TOKEN_BOOLEAN:
394
 
      {
395
 
         Boolean& boolean = element;
396
 
         Parse(boolean, tokenStream);
397
 
         break;
398
 
      }
399
 
 
400
 
      case Token::TOKEN_NULL:
401
 
      {
402
 
         Null& null = element;
403
 
         Parse(null, tokenStream);
404
 
         break;
405
 
      }
406
 
 
407
 
      default:
408
 
      {
409
 
         std::string sMessage = std::string("Unexpected token: ") + token.sValue;
410
 
         throw ParseException(sMessage, token.locBegin, token.locEnd);
411
 
      }
412
 
   }
413
 
}
414
 
 
415
 
 
416
 
inline void Reader::Parse(Object& object, Reader::TokenStream& tokenStream)
417
 
{
418
 
   MatchExpectedToken(Token::TOKEN_OBJECT_BEGIN, tokenStream);
419
 
 
420
 
   bool bContinue = (tokenStream.EOS() == false &&
421
 
                     tokenStream.Peek().nType != Token::TOKEN_OBJECT_END);
422
 
   while (bContinue)
423
 
   {
424
 
      Object::Member member;
425
 
 
426
 
      // first the member name. save the token in case we have to throw an exception
427
 
      const Token& tokenName = tokenStream.Peek();
428
 
      member.name = MatchExpectedToken(Token::TOKEN_STRING, tokenStream);
429
 
 
430
 
      // ...then the key/value separator...
431
 
      MatchExpectedToken(Token::TOKEN_MEMBER_ASSIGN, tokenStream);
432
 
 
433
 
      // ...then the value itself (can be anything).
434
 
      Parse(member.element, tokenStream);
435
 
 
436
 
      // try adding it to the object (this could throw)
437
 
      try
438
 
      {
439
 
         object.Insert(member);
440
 
      }
441
 
      catch (Exception&)
442
 
      {
443
 
         // must be a duplicate name
444
 
         std::string sMessage = std::string("Duplicate object member token: ") + member.name; 
445
 
         throw ParseException(sMessage, tokenName.locBegin, tokenName.locEnd);
446
 
      }
447
 
 
448
 
      bContinue = (tokenStream.EOS() == false &&
449
 
                   tokenStream.Peek().nType == Token::TOKEN_NEXT_ELEMENT);
450
 
      if (bContinue)
451
 
         MatchExpectedToken(Token::TOKEN_NEXT_ELEMENT, tokenStream);
452
 
   }
453
 
 
454
 
   MatchExpectedToken(Token::TOKEN_OBJECT_END, tokenStream);
455
 
}
456
 
 
457
 
 
458
 
inline void Reader::Parse(Array& array, Reader::TokenStream& tokenStream)
459
 
{
460
 
   MatchExpectedToken(Token::TOKEN_ARRAY_BEGIN, tokenStream);
461
 
 
462
 
   bool bContinue = (tokenStream.EOS() == false &&
463
 
                     tokenStream.Peek().nType != Token::TOKEN_ARRAY_END);
464
 
   while (bContinue)
465
 
   {
466
 
      // ...what's next? could be anything
467
 
      Array::iterator itElement = array.Insert(UnknownElement());
468
 
      UnknownElement& element = *itElement;
469
 
      Parse(element, tokenStream);
470
 
 
471
 
      bContinue = (tokenStream.EOS() == false &&
472
 
                   tokenStream.Peek().nType == Token::TOKEN_NEXT_ELEMENT);
473
 
      if (bContinue)
474
 
         MatchExpectedToken(Token::TOKEN_NEXT_ELEMENT, tokenStream);
475
 
   }
476
 
 
477
 
   MatchExpectedToken(Token::TOKEN_ARRAY_END, tokenStream);
478
 
}
479
 
 
480
 
 
481
 
inline void Reader::Parse(String& string, Reader::TokenStream& tokenStream)
482
 
{
483
 
   string = MatchExpectedToken(Token::TOKEN_STRING, tokenStream);
484
 
}
485
 
 
486
 
 
487
 
inline void Reader::Parse(Number& number, Reader::TokenStream& tokenStream)
488
 
{
489
 
   const Token& currentToken = tokenStream.Peek(); // might need this later for throwing exception
490
 
   const std::string& sValue = MatchExpectedToken(Token::TOKEN_NUMBER, tokenStream);
491
 
 
492
 
   std::istringstream iStr(sValue);
493
 
   double dValue;
494
 
   iStr >> dValue;
495
 
 
496
 
   // did we consume all characters in the token?
497
 
   if (iStr.eof() == false)
498
 
   {
499
 
      char c = iStr.peek();
500
 
      std::string sMessage = std::string("Unexpected character in NUMBER token: ") + c;
501
 
      throw ParseException(sMessage, currentToken.locBegin, currentToken.locEnd);
502
 
   }
503
 
 
504
 
   number = dValue;
505
 
}
506
 
 
507
 
 
508
 
inline void Reader::Parse(Boolean& boolean, Reader::TokenStream& tokenStream)
509
 
{
510
 
   const std::string& sValue = MatchExpectedToken(Token::TOKEN_BOOLEAN, tokenStream);
511
 
   boolean = (sValue == "true" ? true : false);
512
 
}
513
 
 
514
 
 
515
 
inline void Reader::Parse(Null&, Reader::TokenStream& tokenStream)
516
 
{
517
 
   MatchExpectedToken(Token::TOKEN_NULL, tokenStream);
518
 
}
519
 
 
520
 
 
521
 
inline const std::string& Reader::MatchExpectedToken(Token::Type nExpected, Reader::TokenStream& tokenStream)
522
 
{
523
 
   const Token& token = tokenStream.Get();
524
 
   if (token.nType != nExpected)
525
 
   {
526
 
      std::string sMessage = std::string("Unexpected token: ") + token.sValue;
527
 
      throw ParseException(sMessage, token.locBegin, token.locEnd);
528
 
   }
529
 
 
530
 
   return token.sValue;
531
 
}
532
 
 
533
 
} // End namespace