Subversion Repositories SmartDukaan

Rev

Rev 30 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
30 ashish 1
/*
2
 * Licensed to the Apache Software Foundation (ASF) under one
3
 * or more contributor license agreements. See the NOTICE file
4
 * distributed with this work for additional information
5
 * regarding copyright ownership. The ASF licenses this file
6
 * to you under the Apache License, Version 2.0 (the
7
 * "License"); you may not use this file except in compliance
8
 * with the License. You may obtain a copy of the License at
9
 *
10
 *   http://www.apache.org/licenses/LICENSE-2.0
11
 *
12
 * Unless required by applicable law or agreed to in writing,
13
 * software distributed under the License is distributed on an
14
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15
 * KIND, either express or implied. See the License for the
16
 * specific language governing permissions and limitations
17
 * under the License.
18
 */
19
 
20
#include "TJSONProtocol.h"
21
 
22
#include <math.h>
23
#include <boost/lexical_cast.hpp>
24
#include "TBase64Utils.h"
25
#include <transport/TTransportException.h>
26
 
27
using namespace apache::thrift::transport;
28
 
29
namespace apache { namespace thrift { namespace protocol {
30
 
31
 
32
// Static data
33
 
34
static const uint8_t kJSONObjectStart = '{';
35
static const uint8_t kJSONObjectEnd = '}';
36
static const uint8_t kJSONArrayStart = '[';
37
static const uint8_t kJSONArrayEnd = ']';
38
static const uint8_t kJSONNewline = '\n';
39
static const uint8_t kJSONPairSeparator = ':';
40
static const uint8_t kJSONElemSeparator = ',';
41
static const uint8_t kJSONBackslash = '\\';
42
static const uint8_t kJSONStringDelimiter = '"';
43
static const uint8_t kJSONZeroChar = '0';
44
static const uint8_t kJSONEscapeChar = 'u';
45
 
46
static const std::string kJSONEscapePrefix("\\u00");
47
 
48
static const uint32_t kThriftVersion1 = 1;
49
 
50
static const std::string kThriftNan("NaN");
51
static const std::string kThriftInfinity("Infinity");
52
static const std::string kThriftNegativeInfinity("-Infinity");
53
 
54
static const std::string kTypeNameBool("tf");
55
static const std::string kTypeNameByte("i8");
56
static const std::string kTypeNameI16("i16");
57
static const std::string kTypeNameI32("i32");
58
static const std::string kTypeNameI64("i64");
59
static const std::string kTypeNameDouble("dbl");
60
static const std::string kTypeNameStruct("rec");
61
static const std::string kTypeNameString("str");
62
static const std::string kTypeNameMap("map");
63
static const std::string kTypeNameList("lst");
64
static const std::string kTypeNameSet("set");
65
 
66
static const std::string &getTypeNameForTypeID(TType typeID) {
67
  switch (typeID) {
68
  case T_BOOL:
69
    return kTypeNameBool;
70
  case T_BYTE:
71
    return kTypeNameByte;
72
  case T_I16:
73
    return kTypeNameI16;
74
  case T_I32:
75
    return kTypeNameI32;
76
  case T_I64:
77
    return kTypeNameI64;
78
  case T_DOUBLE:
79
    return kTypeNameDouble;
80
  case T_STRING:
81
    return kTypeNameString;
82
  case T_STRUCT:
83
    return kTypeNameStruct;
84
  case T_MAP:
85
    return kTypeNameMap;
86
  case T_SET:
87
    return kTypeNameSet;
88
  case T_LIST:
89
    return kTypeNameList;
90
  default:
91
    throw TProtocolException(TProtocolException::NOT_IMPLEMENTED,
92
                             "Unrecognized type");
93
  }
94
}
95
 
96
static TType getTypeIDForTypeName(const std::string &name) {
97
  TType result = T_STOP; // Sentinel value
98
  if (name.length() > 1) {
99
    switch (name[0]) {
100
    case 'd':
101
      result = T_DOUBLE;
102
      break;
103
    case 'i':
104
      switch (name[1]) {
105
      case '8':
106
        result = T_BYTE;
107
        break;
108
      case '1':
109
        result = T_I16;
110
        break;
111
      case '3':
112
        result = T_I32;
113
        break;
114
      case '6':
115
        result = T_I64;
116
        break;
117
      }
118
      break;
119
    case 'l':
120
      result = T_LIST;
121
      break;
122
    case 'm':
123
      result = T_MAP;
124
      break;
125
    case 'r':
126
      result = T_STRUCT;
127
      break;
128
    case 's':
129
      if (name[1] == 't') {
130
        result = T_STRING;
131
      }
132
      else if (name[1] == 'e') {
133
        result = T_SET;
134
      }
135
      break;
136
    case 't':
137
      result = T_BOOL;
138
      break;
139
    }
140
  }
141
  if (result == T_STOP) {
142
    throw TProtocolException(TProtocolException::NOT_IMPLEMENTED,
143
                             "Unrecognized type");
144
  }
145
  return result;
146
}
147
 
148
 
149
// This table describes the handling for the first 0x30 characters
150
//  0 : escape using "\u00xx" notation
151
//  1 : just output index
152
// <other> : escape using "\<other>" notation
153
static const uint8_t kJSONCharTable[0x30] = {
154
//  0   1   2   3   4   5   6   7   8   9   A   B   C   D   E   F
155
    0,  0,  0,  0,  0,  0,  0,  0,'b','t','n',  0,'f','r',  0,  0, // 0
156
    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, // 1
157
    1,  1,'"',  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1, // 2
158
};
159
 
160
 
161
// This string's characters must match up with the elements in kEscapeCharVals.
162
// I don't have '/' on this list even though it appears on www.json.org --
163
// it is not in the RFC
164
const static std::string kEscapeChars("\"\\bfnrt");
165
 
166
// The elements of this array must match up with the sequence of characters in
167
// kEscapeChars
168
const static uint8_t kEscapeCharVals[7] = {
169
  '"', '\\', '\b', '\f', '\n', '\r', '\t',
170
};
171
 
172
 
173
// Static helper functions
174
 
175
// Read 1 character from the transport trans and verify that it is the
176
// expected character ch.
177
// Throw a protocol exception if it is not.
178
static uint32_t readSyntaxChar(TJSONProtocol::LookaheadReader &reader,
179
                               uint8_t ch) {
180
  uint8_t ch2 = reader.read();
181
  if (ch2 != ch) {
182
    throw TProtocolException(TProtocolException::INVALID_DATA,
183
                             "Expected \'" + std::string((char *)&ch, 1) +
184
                             "\'; got \'" + std::string((char *)&ch2, 1) +
185
                             "\'.");
186
  }
187
  return 1;
188
}
189
 
190
// Return the integer value of a hex character ch.
191
// Throw a protocol exception if the character is not [0-9a-f].
192
static uint8_t hexVal(uint8_t ch) {
193
  if ((ch >= '0') && (ch <= '9')) {
194
    return ch - '0';
195
  }
196
  else if ((ch >= 'a') && (ch <= 'f')) {
197
    return ch - 'a';
198
  }
199
  else {
200
    throw TProtocolException(TProtocolException::INVALID_DATA,
201
                             "Expected hex val ([0-9a-f]); got \'"
202
                               + std::string((char *)&ch, 1) + "\'.");
203
  }
204
}
205
 
206
// Return the hex character representing the integer val. The value is masked
207
// to make sure it is in the correct range.
208
static uint8_t hexChar(uint8_t val) {
209
  val &= 0x0F;
210
  if (val < 10) {
211
    return val + '0';
212
  }
213
  else {
214
    return val + 'a';
215
  }
216
}
217
 
218
// Return true if the character ch is in [-+0-9.Ee]; false otherwise
219
static bool isJSONNumeric(uint8_t ch) {
220
  switch (ch) {
221
  case '+':
222
  case '-':
223
  case '.':
224
  case '0':
225
  case '1':
226
  case '2':
227
  case '3':
228
  case '4':
229
  case '5':
230
  case '6':
231
  case '7':
232
  case '8':
233
  case '9':
234
  case 'E':
235
  case 'e':
236
    return true;
237
  }
238
  return false;
239
}
240
 
241
 
242
/**
243
 * Class to serve as base JSON context and as base class for other context
244
 * implementations
245
 */
246
class TJSONContext {
247
 
248
 public:
249
 
250
  TJSONContext() {};
251
 
252
  virtual ~TJSONContext() {};
253
 
254
  /**
255
   * Write context data to the transport. Default is to do nothing.
256
   */
257
  virtual uint32_t write(TTransport &trans) {
258
    return 0;
259
  };
260
 
261
  /**
262
   * Read context data from the transport. Default is to do nothing.
263
   */
264
  virtual uint32_t read(TJSONProtocol::LookaheadReader &reader) {
265
    return 0;
266
  };
267
 
268
  /**
269
   * Return true if numbers need to be escaped as strings in this context.
270
   * Default behavior is to return false.
271
   */
272
  virtual bool escapeNum() {
273
    return false;
274
  }
275
};
276
 
277
// Context class for object member key-value pairs
278
class JSONPairContext : public TJSONContext {
279
 
280
public:
281
 
282
  JSONPairContext() :
283
    first_(true),
284
    colon_(true) {
285
  }
286
 
287
  uint32_t write(TTransport &trans) {
288
    if (first_) {
289
      first_ = false;
290
      colon_ = true;
291
      return 0;
292
    }
293
    else {
294
      trans.write(colon_ ? &kJSONPairSeparator : &kJSONElemSeparator, 1);
295
      colon_ = !colon_;
296
      return 1;
297
    }
298
  }
299
 
300
  uint32_t read(TJSONProtocol::LookaheadReader &reader) {
301
    if (first_) {
302
      first_ = false;
303
      colon_ = true;
304
      return 0;
305
    }
306
    else {
307
      uint8_t ch = (colon_ ? kJSONPairSeparator : kJSONElemSeparator);
308
      colon_ = !colon_;
309
      return readSyntaxChar(reader, ch);
310
    }
311
  }
312
 
313
  // Numbers must be turned into strings if they are the key part of a pair
314
  virtual bool escapeNum() {
315
    return colon_;
316
  }
317
 
318
  private:
319
 
320
    bool first_;
321
    bool colon_;
322
};
323
 
324
// Context class for lists
325
class JSONListContext : public TJSONContext {
326
 
327
public:
328
 
329
  JSONListContext() :
330
    first_(true) {
331
  }
332
 
333
  uint32_t write(TTransport &trans) {
334
    if (first_) {
335
      first_ = false;
336
      return 0;
337
    }
338
    else {
339
      trans.write(&kJSONElemSeparator, 1);
340
      return 1;
341
    }
342
  }
343
 
344
  uint32_t read(TJSONProtocol::LookaheadReader &reader) {
345
    if (first_) {
346
      first_ = false;
347
      return 0;
348
    }
349
    else {
350
      return readSyntaxChar(reader, kJSONElemSeparator);
351
    }
352
  }
353
 
354
  private:
355
    bool first_;
356
};
357
 
358
 
359
TJSONProtocol::TJSONProtocol(boost::shared_ptr<TTransport> ptrans) :
360
  TProtocol(ptrans),
361
  context_(new TJSONContext()),
362
  reader_(*ptrans) {
363
}
364
 
365
TJSONProtocol::~TJSONProtocol() {}
366
 
367
void TJSONProtocol::pushContext(boost::shared_ptr<TJSONContext> c) {
368
  contexts_.push(context_);
369
  context_ = c;
370
}
371
 
372
void TJSONProtocol::popContext() {
373
  context_ = contexts_.top();
374
  contexts_.pop();
375
}
376
 
377
// Write the character ch as a JSON escape sequence ("\u00xx")
378
uint32_t TJSONProtocol::writeJSONEscapeChar(uint8_t ch) {
379
  trans_->write((const uint8_t *)kJSONEscapePrefix.c_str(),
380
                kJSONEscapePrefix.length());
381
  uint8_t outCh = hexChar(ch >> 4);
382
  trans_->write(&outCh, 1);
383
  outCh = hexChar(ch);
384
  trans_->write(&outCh, 1);
385
  return 6;
386
}
387
 
388
// Write the character ch as part of a JSON string, escaping as appropriate.
389
uint32_t TJSONProtocol::writeJSONChar(uint8_t ch) {
390
  if (ch >= 0x30) {
391
    if (ch == kJSONBackslash) { // Only special character >= 0x30 is '\'
392
      trans_->write(&kJSONBackslash, 1);
393
      trans_->write(&kJSONBackslash, 1);
394
      return 2;
395
    }
396
    else {
397
      trans_->write(&ch, 1);
398
      return 1;
399
    }
400
  }
401
  else {
402
    uint8_t outCh = kJSONCharTable[ch];
403
    // Check if regular character, backslash escaped, or JSON escaped
404
    if (outCh == 1) {
405
      trans_->write(&ch, 1);
406
      return 1;
407
    }
408
    else if (outCh > 1) {
409
      trans_->write(&kJSONBackslash, 1);
410
      trans_->write(&outCh, 1);
411
      return 2;
412
    }
413
    else {
414
      return writeJSONEscapeChar(ch);
415
    }
416
  }
417
}
418
 
419
// Write out the contents of the string str as a JSON string, escaping
420
// characters as appropriate.
421
uint32_t TJSONProtocol::writeJSONString(const std::string &str) {
422
  uint32_t result = context_->write(*trans_);
423
  result += 2; // For quotes
424
  trans_->write(&kJSONStringDelimiter, 1);
425
  std::string::const_iterator iter(str.begin());
426
  std::string::const_iterator end(str.end());
427
  while (iter != end) {
428
    result += writeJSONChar(*iter++);
429
  }
430
  trans_->write(&kJSONStringDelimiter, 1);
431
  return result;
432
}
433
 
434
// Write out the contents of the string as JSON string, base64-encoding
435
// the string's contents, and escaping as appropriate
436
uint32_t TJSONProtocol::writeJSONBase64(const std::string &str) {
437
  uint32_t result = context_->write(*trans_);
438
  result += 2; // For quotes
439
  trans_->write(&kJSONStringDelimiter, 1);
440
  uint8_t b[4];
441
  const uint8_t *bytes = (const uint8_t *)str.c_str();
442
  uint32_t len = str.length();
443
  while (len >= 3) {
444
    // Encode 3 bytes at a time
445
    base64_encode(bytes, 3, b);
446
    trans_->write(b, 4);
447
    result += 4;
448
    bytes += 3;
449
    len -=3;
450
  }
451
  if (len) { // Handle remainder
452
    base64_encode(bytes, len, b);
453
    trans_->write(b, len + 1);
454
    result += len + 1;
455
  }
456
  trans_->write(&kJSONStringDelimiter, 1);
457
  return result;
458
}
459
 
460
// Convert the given integer type to a JSON number, or a string
461
// if the context requires it (eg: key in a map pair).
462
template <typename NumberType>
463
uint32_t TJSONProtocol::writeJSONInteger(NumberType num) {
464
  uint32_t result = context_->write(*trans_);
465
  std::string val(boost::lexical_cast<std::string>(num));
466
  bool escapeNum = context_->escapeNum();
467
  if (escapeNum) {
468
    trans_->write(&kJSONStringDelimiter, 1);
469
    result += 1;
470
  }
471
  trans_->write((const uint8_t *)val.c_str(), val.length());
472
  result += val.length();
473
  if (escapeNum) {
474
    trans_->write(&kJSONStringDelimiter, 1);
475
    result += 1;
476
  }
477
  return result;
478
}
479
 
480
// Convert the given double to a JSON string, which is either the number,
481
// "NaN" or "Infinity" or "-Infinity".
482
uint32_t TJSONProtocol::writeJSONDouble(double num) {
483
  uint32_t result = context_->write(*trans_);
484
  std::string val(boost::lexical_cast<std::string>(num));
485
 
486
  // Normalize output of boost::lexical_cast for NaNs and Infinities
487
  bool special = false;
488
  switch (val[0]) {
489
  case 'N':
490
  case 'n':
491
    val = kThriftNan;
492
    special = true;
493
    break;
494
  case 'I':
495
  case 'i':
496
    val = kThriftInfinity;
497
    special = true;
498
    break;
499
  case '-':
500
    if ((val[1] == 'I') || (val[1] == 'i')) {
501
      val = kThriftNegativeInfinity;
502
      special = true;
503
    }
504
    break;
505
  }
506
 
507
  bool escapeNum = special || context_->escapeNum();
508
  if (escapeNum) {
509
    trans_->write(&kJSONStringDelimiter, 1);
510
    result += 1;
511
  }
512
  trans_->write((const uint8_t *)val.c_str(), val.length());
513
  result += val.length();
514
  if (escapeNum) {
515
    trans_->write(&kJSONStringDelimiter, 1);
516
    result += 1;
517
  }
518
  return result;
519
}
520
 
521
uint32_t TJSONProtocol::writeJSONObjectStart() {
522
  uint32_t result = context_->write(*trans_);
523
  trans_->write(&kJSONObjectStart, 1);
524
  pushContext(boost::shared_ptr<TJSONContext>(new JSONPairContext()));
525
  return result + 1;
526
}
527
 
528
uint32_t TJSONProtocol::writeJSONObjectEnd() {
529
  popContext();
530
  trans_->write(&kJSONObjectEnd, 1);
531
  return 1;
532
}
533
 
534
uint32_t TJSONProtocol::writeJSONArrayStart() {
535
  uint32_t result = context_->write(*trans_);
536
  trans_->write(&kJSONArrayStart, 1);
537
  pushContext(boost::shared_ptr<TJSONContext>(new JSONListContext()));
538
  return result + 1;
539
}
540
 
541
uint32_t TJSONProtocol::writeJSONArrayEnd() {
542
  popContext();
543
  trans_->write(&kJSONArrayEnd, 1);
544
  return 1;
545
}
546
 
547
uint32_t TJSONProtocol::writeMessageBegin(const std::string& name,
548
                                          const TMessageType messageType,
549
                                          const int32_t seqid) {
550
  uint32_t result = writeJSONArrayStart();
551
  result += writeJSONInteger(kThriftVersion1);
552
  result += writeJSONString(name);
553
  result += writeJSONInteger(messageType);
554
  result += writeJSONInteger(seqid);
555
  return result;
556
}
557
 
558
uint32_t TJSONProtocol::writeMessageEnd() {
559
  return writeJSONArrayEnd();
560
}
561
 
562
uint32_t TJSONProtocol::writeStructBegin(const char* name) {
563
  return writeJSONObjectStart();
564
}
565
 
566
uint32_t TJSONProtocol::writeStructEnd() {
567
  return writeJSONObjectEnd();
568
}
569
 
570
uint32_t TJSONProtocol::writeFieldBegin(const char* name,
571
                                        const TType fieldType,
572
                                        const int16_t fieldId) {
573
  uint32_t result = writeJSONInteger(fieldId);
574
  result += writeJSONObjectStart();
575
  result += writeJSONString(getTypeNameForTypeID(fieldType));
576
  return result;
577
}
578
 
579
uint32_t TJSONProtocol::writeFieldEnd() {
580
  return writeJSONObjectEnd();
581
}
582
 
583
uint32_t TJSONProtocol::writeFieldStop() {
584
  return 0;
585
}
586
 
587
uint32_t TJSONProtocol::writeMapBegin(const TType keyType,
588
                                      const TType valType,
589
                                      const uint32_t size) {
590
  uint32_t result = writeJSONArrayStart();
591
  result += writeJSONString(getTypeNameForTypeID(keyType));
592
  result += writeJSONString(getTypeNameForTypeID(valType));
593
  result += writeJSONInteger((int64_t)size);
594
  result += writeJSONObjectStart();
595
  return result;
596
}
597
 
598
uint32_t TJSONProtocol::writeMapEnd() {
599
  return writeJSONObjectEnd() + writeJSONArrayEnd();
600
}
601
 
602
uint32_t TJSONProtocol::writeListBegin(const TType elemType,
603
                                       const uint32_t size) {
604
  uint32_t result = writeJSONArrayStart();
605
  result += writeJSONString(getTypeNameForTypeID(elemType));
606
  result += writeJSONInteger((int64_t)size);
607
  return result;
608
}
609
 
610
uint32_t TJSONProtocol::writeListEnd() {
611
  return writeJSONArrayEnd();
612
}
613
 
614
uint32_t TJSONProtocol::writeSetBegin(const TType elemType,
615
                                      const uint32_t size) {
616
  uint32_t result = writeJSONArrayStart();
617
  result += writeJSONString(getTypeNameForTypeID(elemType));
618
  result += writeJSONInteger((int64_t)size);
619
  return result;
620
}
621
 
622
uint32_t TJSONProtocol::writeSetEnd() {
623
  return writeJSONArrayEnd();
624
}
625
 
626
uint32_t TJSONProtocol::writeBool(const bool value) {
627
  return writeJSONInteger(value);
628
}
629
 
630
uint32_t TJSONProtocol::writeByte(const int8_t byte) {
631
  // writeByte() must be handled specially becuase boost::lexical cast sees
632
  // int8_t as a text type instead of an integer type
633
  return writeJSONInteger((int16_t)byte);
634
}
635
 
636
uint32_t TJSONProtocol::writeI16(const int16_t i16) {
637
  return writeJSONInteger(i16);
638
}
639
 
640
uint32_t TJSONProtocol::writeI32(const int32_t i32) {
641
  return writeJSONInteger(i32);
642
}
643
 
644
uint32_t TJSONProtocol::writeI64(const int64_t i64) {
645
  return writeJSONInteger(i64);
646
}
647
 
648
uint32_t TJSONProtocol::writeDouble(const double dub) {
649
  return writeJSONDouble(dub);
650
}
651
 
652
uint32_t TJSONProtocol::writeString(const std::string& str) {
653
  return writeJSONString(str);
654
}
655
 
656
uint32_t TJSONProtocol::writeBinary(const std::string& str) {
657
  return writeJSONBase64(str);
658
}
659
 
660
  /**
661
   * Reading functions
662
   */
663
 
664
// Reads 1 byte and verifies that it matches ch.
665
uint32_t TJSONProtocol::readJSONSyntaxChar(uint8_t ch) {
666
  return readSyntaxChar(reader_, ch);
667
}
668
 
669
// Decodes the four hex parts of a JSON escaped string character and returns
670
// the character via out. The first two characters must be "00".
671
uint32_t TJSONProtocol::readJSONEscapeChar(uint8_t *out) {
672
  uint8_t b[2];
673
  readJSONSyntaxChar(kJSONZeroChar);
674
  readJSONSyntaxChar(kJSONZeroChar);
675
  b[0] = reader_.read();
676
  b[1] = reader_.read();
677
  *out = (hexVal(b[0]) << 4) + hexVal(b[1]);
678
  return 4;
679
}
680
 
681
// Decodes a JSON string, including unescaping, and returns the string via str
682
uint32_t TJSONProtocol::readJSONString(std::string &str, bool skipContext) {
683
  uint32_t result = (skipContext ? 0 : context_->read(reader_));
684
  result += readJSONSyntaxChar(kJSONStringDelimiter);
685
  uint8_t ch;
686
  str.clear();
687
  while (true) {
688
    ch = reader_.read();
689
    ++result;
690
    if (ch == kJSONStringDelimiter) {
691
      break;
692
    }
693
    if (ch == kJSONBackslash) {
694
      ch = reader_.read();
695
      ++result;
696
      if (ch == kJSONEscapeChar) {
697
        result += readJSONEscapeChar(&ch);
698
      }
699
      else {
700
        size_t pos = kEscapeChars.find(ch);
701
        if (pos == std::string::npos) {
702
          throw TProtocolException(TProtocolException::INVALID_DATA,
703
                                   "Expected control char, got '" +
704
                                   std::string((const char *)&ch, 1)  + "'.");
705
        }
706
        ch = kEscapeCharVals[pos];
707
      }
708
    }
709
    str += ch;
710
  }
711
  return result;
712
}
713
 
714
// Reads a block of base64 characters, decoding it, and returns via str
715
uint32_t TJSONProtocol::readJSONBase64(std::string &str) {
716
  std::string tmp;
717
  uint32_t result = readJSONString(tmp);
718
  uint8_t *b = (uint8_t *)tmp.c_str();
719
  uint32_t len = tmp.length();
720
  str.clear();
721
  while (len >= 4) {
722
    base64_decode(b, 4);
723
    str.append((const char *)b, 3);
724
    b += 4;
725
    len -= 4;
726
  }
727
  // Don't decode if we hit the end or got a single leftover byte (invalid
728
  // base64 but legal for skip of regular string type)
729
  if (len > 1) {
730
    base64_decode(b, len);
731
    str.append((const char *)b, len - 1);
732
  }
733
  return result;
734
}
735
 
736
// Reads a sequence of characters, stopping at the first one that is not
737
// a valid JSON numeric character.
738
uint32_t TJSONProtocol::readJSONNumericChars(std::string &str) {
739
  uint32_t result = 0;
740
  str.clear();
741
  while (true) {
742
    uint8_t ch = reader_.peek();
743
    if (!isJSONNumeric(ch)) {
744
      break;
745
    }
746
    reader_.read();
747
    str += ch;
748
    ++result;
749
  }
750
  return result;
751
}
752
 
753
// Reads a sequence of characters and assembles them into a number,
754
// returning them via num
755
template <typename NumberType>
756
uint32_t TJSONProtocol::readJSONInteger(NumberType &num) {
757
  uint32_t result = context_->read(reader_);
758
  if (context_->escapeNum()) {
759
    result += readJSONSyntaxChar(kJSONStringDelimiter);
760
  }
761
  std::string str;
762
  result += readJSONNumericChars(str);
763
  try {
764
    num = boost::lexical_cast<NumberType>(str);
765
  }
766
  catch (boost::bad_lexical_cast e) {
767
    throw new TProtocolException(TProtocolException::INVALID_DATA,
768
                                 "Expected numeric value; got \"" + str +
769
                                  "\"");
770
  }
771
  if (context_->escapeNum()) {
772
    result += readJSONSyntaxChar(kJSONStringDelimiter);
773
  }
774
  return result;
775
}
776
 
777
// Reads a JSON number or string and interprets it as a double.
778
uint32_t TJSONProtocol::readJSONDouble(double &num) {
779
  uint32_t result = context_->read(reader_);
780
  std::string str;
781
  if (reader_.peek() == kJSONStringDelimiter) {
782
    result += readJSONString(str, true);
783
    // Check for NaN, Infinity and -Infinity
784
    if (str == kThriftNan) {
785
      num = HUGE_VAL/HUGE_VAL; // generates NaN
786
    }
787
    else if (str == kThriftInfinity) {
788
      num = HUGE_VAL;
789
    }
790
    else if (str == kThriftNegativeInfinity) {
791
      num = -HUGE_VAL;
792
    }
793
    else {
794
      if (!context_->escapeNum()) {
795
        // Throw exception -- we should not be in a string in this case
796
        throw new TProtocolException(TProtocolException::INVALID_DATA,
797
                                     "Numeric data unexpectedly quoted");
798
      }
799
      try {
800
        num = boost::lexical_cast<double>(str);
801
      }
802
      catch (boost::bad_lexical_cast e) {
803
        throw new TProtocolException(TProtocolException::INVALID_DATA,
804
                                     "Expected numeric value; got \"" + str +
805
                                     "\"");
806
      }
807
    }
808
  }
809
  else {
810
    if (context_->escapeNum()) {
811
      // This will throw - we should have had a quote if escapeNum == true
812
      readJSONSyntaxChar(kJSONStringDelimiter);
813
    }
814
    result += readJSONNumericChars(str);
815
    try {
816
      num = boost::lexical_cast<double>(str);
817
    }
818
    catch (boost::bad_lexical_cast e) {
819
      throw new TProtocolException(TProtocolException::INVALID_DATA,
820
                                   "Expected numeric value; got \"" + str +
821
                                   "\"");
822
    }
823
  }
824
  return result;
825
}
826
 
827
uint32_t TJSONProtocol::readJSONObjectStart() {
828
  uint32_t result = context_->read(reader_);
829
  result += readJSONSyntaxChar(kJSONObjectStart);
830
  pushContext(boost::shared_ptr<TJSONContext>(new JSONPairContext()));
831
  return result;
832
}
833
 
834
uint32_t TJSONProtocol::readJSONObjectEnd() {
835
  uint32_t result = readJSONSyntaxChar(kJSONObjectEnd);
836
  popContext();
837
  return result;
838
}
839
 
840
uint32_t TJSONProtocol::readJSONArrayStart() {
841
  uint32_t result = context_->read(reader_);
842
  result += readJSONSyntaxChar(kJSONArrayStart);
843
  pushContext(boost::shared_ptr<TJSONContext>(new JSONListContext()));
844
  return result;
845
}
846
 
847
uint32_t TJSONProtocol::readJSONArrayEnd() {
848
  uint32_t result = readJSONSyntaxChar(kJSONArrayEnd);
849
  popContext();
850
  return result;
851
}
852
 
853
uint32_t TJSONProtocol::readMessageBegin(std::string& name,
854
                                         TMessageType& messageType,
855
                                         int32_t& seqid) {
856
  uint32_t result = readJSONArrayStart();
857
  uint64_t tmpVal = 0;
858
  result += readJSONInteger(tmpVal);
859
  if (tmpVal != kThriftVersion1) {
860
    throw TProtocolException(TProtocolException::BAD_VERSION,
861
                             "Message contained bad version.");
862
  }
863
  result += readJSONString(name);
864
  result += readJSONInteger(tmpVal);
865
  messageType = (TMessageType)tmpVal;
866
  result += readJSONInteger(tmpVal);
867
  seqid = tmpVal;
868
  return result;
869
}
870
 
871
uint32_t TJSONProtocol::readMessageEnd() {
872
  return readJSONArrayEnd();
873
}
874
 
875
uint32_t TJSONProtocol::readStructBegin(std::string& name) {
876
  return readJSONObjectStart();
877
}
878
 
879
uint32_t TJSONProtocol::readStructEnd() {
880
  return readJSONObjectEnd();
881
}
882
 
883
uint32_t TJSONProtocol::readFieldBegin(std::string& name,
884
                                       TType& fieldType,
885
                                       int16_t& fieldId) {
886
  uint32_t result = 0;
887
  // Check if we hit the end of the list
888
  uint8_t ch = reader_.peek();
889
  if (ch == kJSONObjectEnd) {
890
    fieldType = apache::thrift::protocol::T_STOP;
891
  }
892
  else {
893
    uint64_t tmpVal = 0;
894
    std::string tmpStr;
895
    result += readJSONInteger(tmpVal);
896
    fieldId = tmpVal;
897
    result += readJSONObjectStart();
898
    result += readJSONString(tmpStr);
899
    fieldType = getTypeIDForTypeName(tmpStr);
900
  }
901
  return result;
902
}
903
 
904
uint32_t TJSONProtocol::readFieldEnd() {
905
  return readJSONObjectEnd();
906
}
907
 
908
uint32_t TJSONProtocol::readMapBegin(TType& keyType,
909
                                     TType& valType,
910
                                     uint32_t& size) {
911
  uint64_t tmpVal = 0;
912
  std::string tmpStr;
913
  uint32_t result = readJSONArrayStart();
914
  result += readJSONString(tmpStr);
915
  keyType = getTypeIDForTypeName(tmpStr);
916
  result += readJSONString(tmpStr);
917
  valType = getTypeIDForTypeName(tmpStr);
918
  result += readJSONInteger(tmpVal);
919
  size = tmpVal;
920
  result += readJSONObjectStart();
921
  return result;
922
}
923
 
924
uint32_t TJSONProtocol::readMapEnd() {
925
  return readJSONObjectEnd() + readJSONArrayEnd();
926
}
927
 
928
uint32_t TJSONProtocol::readListBegin(TType& elemType,
929
                                      uint32_t& size) {
930
  uint64_t tmpVal = 0;
931
  std::string tmpStr;
932
  uint32_t result = readJSONArrayStart();
933
  result += readJSONString(tmpStr);
934
  elemType = getTypeIDForTypeName(tmpStr);
935
  result += readJSONInteger(tmpVal);
936
  size = tmpVal;
937
  return result;
938
}
939
 
940
uint32_t TJSONProtocol::readListEnd() {
941
  return readJSONArrayEnd();
942
}
943
 
944
uint32_t TJSONProtocol::readSetBegin(TType& elemType,
945
                                     uint32_t& size) {
946
  uint64_t tmpVal = 0;
947
  std::string tmpStr;
948
  uint32_t result = readJSONArrayStart();
949
  result += readJSONString(tmpStr);
950
  elemType = getTypeIDForTypeName(tmpStr);
951
  result += readJSONInteger(tmpVal);
952
  size = tmpVal;
953
  return result;
954
}
955
 
956
uint32_t TJSONProtocol::readSetEnd() {
957
  return readJSONArrayEnd();
958
}
959
 
960
uint32_t TJSONProtocol::readBool(bool& value) {
961
  return readJSONInteger(value);
962
}
963
 
964
// readByte() must be handled properly becuase boost::lexical cast sees int8_t
965
// as a text type instead of an integer type
966
uint32_t TJSONProtocol::readByte(int8_t& byte) {
967
  int16_t tmp = (int16_t) byte;
968
  uint32_t result =  readJSONInteger(tmp);
969
  assert(tmp < 256);
970
  byte = (int8_t)tmp;
971
  return result;
972
}
973
 
974
uint32_t TJSONProtocol::readI16(int16_t& i16) {
975
  return readJSONInteger(i16);
976
}
977
 
978
uint32_t TJSONProtocol::readI32(int32_t& i32) {
979
  return readJSONInteger(i32);
980
}
981
 
982
uint32_t TJSONProtocol::readI64(int64_t& i64) {
983
  return readJSONInteger(i64);
984
}
985
 
986
uint32_t TJSONProtocol::readDouble(double& dub) {
987
  return readJSONDouble(dub);
988
}
989
 
990
uint32_t TJSONProtocol::readString(std::string &str) {
991
  return readJSONString(str);
992
}
993
 
994
uint32_t TJSONProtocol::readBinary(std::string &str) {
995
  return readJSONBase64(str);
996
}
997
 
998
}}} // apache::thrift::protocol