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