blob: c46cc142a57756798bad943f1482f57efaeb706f [file] [log] [blame]
David Reissea2cba82009-03-30 21:35:00 +00001/*
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 */
David Reissdb0ea152008-02-18 01:49:37 +000019
Roger Meier4285ba22013-06-10 21:17:23 +020020#include <thrift/protocol/TJSONProtocol.h>
David Reissdb0ea152008-02-18 01:49:37 +000021
Jim King1654fe92016-06-19 19:46:01 -040022#include <boost/lexical_cast.hpp>
23#include <boost/locale.hpp>
24#include <boost/math/special_functions/fpclassify.hpp>
25
26#include <cmath>
Konrad Grochowski12b06e42015-02-21 13:48:56 +010027#include <limits>
28#include <locale>
29#include <sstream>
Jim King1654fe92016-06-19 19:46:01 -040030#include <stdexcept>
Konrad Grochowski12b06e42015-02-21 13:48:56 +010031
Roger Meier4285ba22013-06-10 21:17:23 +020032#include <thrift/protocol/TBase64Utils.h>
Roger Meier49ff8b12012-04-13 09:12:31 +000033#include <thrift/transport/TTransportException.h>
David Reissdb0ea152008-02-18 01:49:37 +000034
T Jake Lucianib5e62212009-01-31 22:36:20 +000035using namespace apache::thrift::transport;
David Reissdb0ea152008-02-18 01:49:37 +000036
Konrad Grochowski16a23a62014-11-13 15:33:38 +010037namespace apache {
38namespace thrift {
39namespace protocol {
David Reissdb0ea152008-02-18 01:49:37 +000040
41// Static data
42
43static const uint8_t kJSONObjectStart = '{';
44static const uint8_t kJSONObjectEnd = '}';
45static const uint8_t kJSONArrayStart = '[';
46static const uint8_t kJSONArrayEnd = ']';
David Reissdb0ea152008-02-18 01:49:37 +000047static const uint8_t kJSONPairSeparator = ':';
48static const uint8_t kJSONElemSeparator = ',';
49static const uint8_t kJSONBackslash = '\\';
50static const uint8_t kJSONStringDelimiter = '"';
51static const uint8_t kJSONZeroChar = '0';
52static const uint8_t kJSONEscapeChar = 'u';
53
54static const std::string kJSONEscapePrefix("\\u00");
55
David Reiss6713e1b2009-01-15 23:56:19 +000056static const uint32_t kThriftVersion1 = 1;
David Reissdb0ea152008-02-18 01:49:37 +000057
58static const std::string kThriftNan("NaN");
59static const std::string kThriftInfinity("Infinity");
60static const std::string kThriftNegativeInfinity("-Infinity");
61
62static const std::string kTypeNameBool("tf");
63static const std::string kTypeNameByte("i8");
64static const std::string kTypeNameI16("i16");
65static const std::string kTypeNameI32("i32");
66static const std::string kTypeNameI64("i64");
67static const std::string kTypeNameDouble("dbl");
68static const std::string kTypeNameStruct("rec");
69static const std::string kTypeNameString("str");
70static const std::string kTypeNameMap("map");
71static const std::string kTypeNameList("lst");
72static const std::string kTypeNameSet("set");
73
Konrad Grochowski16a23a62014-11-13 15:33:38 +010074static const std::string& getTypeNameForTypeID(TType typeID) {
David Reissdb0ea152008-02-18 01:49:37 +000075 switch (typeID) {
76 case T_BOOL:
77 return kTypeNameBool;
78 case T_BYTE:
79 return kTypeNameByte;
80 case T_I16:
81 return kTypeNameI16;
82 case T_I32:
83 return kTypeNameI32;
84 case T_I64:
85 return kTypeNameI64;
86 case T_DOUBLE:
87 return kTypeNameDouble;
88 case T_STRING:
89 return kTypeNameString;
90 case T_STRUCT:
91 return kTypeNameStruct;
92 case T_MAP:
93 return kTypeNameMap;
94 case T_SET:
95 return kTypeNameSet;
96 case T_LIST:
97 return kTypeNameList;
98 default:
Konrad Grochowski16a23a62014-11-13 15:33:38 +010099 throw TProtocolException(TProtocolException::NOT_IMPLEMENTED, "Unrecognized type");
David Reissdb0ea152008-02-18 01:49:37 +0000100 }
101}
102
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100103static TType getTypeIDForTypeName(const std::string& name) {
David Reissdb0ea152008-02-18 01:49:37 +0000104 TType result = T_STOP; // Sentinel value
David Reiss2c9824c2008-03-02 00:20:47 +0000105 if (name.length() > 1) {
David Reiss1e62ab42008-02-21 22:37:45 +0000106 switch (name[0]) {
107 case 'd':
108 result = T_DOUBLE;
David Reissdb0ea152008-02-18 01:49:37 +0000109 break;
David Reiss1e62ab42008-02-21 22:37:45 +0000110 case 'i':
111 switch (name[1]) {
112 case '8':
113 result = T_BYTE;
114 break;
115 case '1':
116 result = T_I16;
117 break;
118 case '3':
119 result = T_I32;
120 break;
121 case '6':
122 result = T_I64;
123 break;
124 }
David Reissdb0ea152008-02-18 01:49:37 +0000125 break;
David Reiss1e62ab42008-02-21 22:37:45 +0000126 case 'l':
127 result = T_LIST;
David Reissdb0ea152008-02-18 01:49:37 +0000128 break;
David Reiss1e62ab42008-02-21 22:37:45 +0000129 case 'm':
130 result = T_MAP;
131 break;
132 case 'r':
133 result = T_STRUCT;
134 break;
135 case 's':
136 if (name[1] == 't') {
137 result = T_STRING;
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100138 } else if (name[1] == 'e') {
David Reiss1e62ab42008-02-21 22:37:45 +0000139 result = T_SET;
140 }
141 break;
142 case 't':
143 result = T_BOOL;
David Reissdb0ea152008-02-18 01:49:37 +0000144 break;
145 }
David Reissdb0ea152008-02-18 01:49:37 +0000146 }
147 if (result == T_STOP) {
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100148 throw TProtocolException(TProtocolException::NOT_IMPLEMENTED, "Unrecognized type");
David Reissdb0ea152008-02-18 01:49:37 +0000149 }
150 return result;
151}
152
David Reissdb0ea152008-02-18 01:49:37 +0000153// This table describes the handling for the first 0x30 characters
154// 0 : escape using "\u00xx" notation
155// 1 : just output index
156// <other> : escape using "\<other>" notation
157static const uint8_t kJSONCharTable[0x30] = {
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100158 // 0 1 2 3 4 5 6 7 8 9 A B C D E F
159 0,
160 0,
161 0,
162 0,
163 0,
164 0,
165 0,
166 0,
167 'b',
168 't',
169 'n',
170 0,
171 'f',
172 'r',
173 0,
174 0, // 0
175 0,
176 0,
177 0,
178 0,
179 0,
180 0,
181 0,
182 0,
183 0,
184 0,
185 0,
186 0,
187 0,
188 0,
189 0,
190 0, // 1
191 1,
192 1,
193 '"',
194 1,
195 1,
196 1,
197 1,
198 1,
199 1,
200 1,
201 1,
202 1,
203 1,
204 1,
205 1,
206 1, // 2
David Reissdb0ea152008-02-18 01:49:37 +0000207};
208
David Reissdb0ea152008-02-18 01:49:37 +0000209// This string's characters must match up with the elements in kEscapeCharVals.
210// I don't have '/' on this list even though it appears on www.json.org --
211// it is not in the RFC
212const static std::string kEscapeChars("\"\\bfnrt");
213
214// The elements of this array must match up with the sequence of characters in
215// kEscapeChars
216const static uint8_t kEscapeCharVals[7] = {
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100217 '"',
218 '\\',
219 '\b',
220 '\f',
221 '\n',
222 '\r',
223 '\t',
David Reissdb0ea152008-02-18 01:49:37 +0000224};
225
David Reissdb0ea152008-02-18 01:49:37 +0000226// Static helper functions
227
228// Read 1 character from the transport trans and verify that it is the
229// expected character ch.
230// Throw a protocol exception if it is not.
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100231static uint32_t readSyntaxChar(TJSONProtocol::LookaheadReader& reader, uint8_t ch) {
David Reiss1e62ab42008-02-21 22:37:45 +0000232 uint8_t ch2 = reader.read();
233 if (ch2 != ch) {
David Reissdb0ea152008-02-18 01:49:37 +0000234 throw TProtocolException(TProtocolException::INVALID_DATA,
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100235 "Expected \'" + std::string((char*)&ch, 1) + "\'; got \'"
236 + std::string((char*)&ch2, 1) + "\'.");
David Reissdb0ea152008-02-18 01:49:37 +0000237 }
238 return 1;
239}
240
David Reissdb0ea152008-02-18 01:49:37 +0000241// Return the integer value of a hex character ch.
242// Throw a protocol exception if the character is not [0-9a-f].
243static uint8_t hexVal(uint8_t ch) {
244 if ((ch >= '0') && (ch <= '9')) {
245 return ch - '0';
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100246 } else if ((ch >= 'a') && (ch <= 'f')) {
Bryan Duxbury4a2bc1b2010-11-03 17:57:38 +0000247 return ch - 'a' + 10;
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100248 } else {
David Reissdb0ea152008-02-18 01:49:37 +0000249 throw TProtocolException(TProtocolException::INVALID_DATA,
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100250 "Expected hex val ([0-9a-f]); got \'" + std::string((char*)&ch, 1)
251 + "\'.");
David Reissdb0ea152008-02-18 01:49:37 +0000252 }
253}
254
255// Return the hex character representing the integer val. The value is masked
256// to make sure it is in the correct range.
257static uint8_t hexChar(uint8_t val) {
258 val &= 0x0F;
259 if (val < 10) {
260 return val + '0';
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100261 } else {
Bryan Duxbury4a2bc1b2010-11-03 17:57:38 +0000262 return val - 10 + 'a';
David Reissdb0ea152008-02-18 01:49:37 +0000263 }
264}
265
266// Return true if the character ch is in [-+0-9.Ee]; false otherwise
267static bool isJSONNumeric(uint8_t ch) {
268 switch (ch) {
269 case '+':
270 case '-':
271 case '.':
272 case '0':
273 case '1':
274 case '2':
275 case '3':
276 case '4':
277 case '5':
278 case '6':
279 case '7':
280 case '8':
281 case '9':
282 case 'E':
283 case 'e':
284 return true;
285 }
286 return false;
287}
288
Konrad Grochowskia84e1392015-10-16 11:22:10 +0200289// Return true if the code unit is high surrogate
290static bool isHighSurrogate(uint16_t val) {
291 return val >= 0xD800 && val <= 0xDBFF;
292}
293
294// Return true if the code unit is low surrogate
295static bool isLowSurrogate(uint16_t val) {
296 return val >= 0xDC00 && val <= 0xDFFF;
297}
298
David Reissdb0ea152008-02-18 01:49:37 +0000299/**
David Reiss1e62ab42008-02-21 22:37:45 +0000300 * Class to serve as base JSON context and as base class for other context
David Reissdb0ea152008-02-18 01:49:37 +0000301 * implementations
302 */
303class TJSONContext {
304
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100305public:
306 TJSONContext(){};
David Reissdb0ea152008-02-18 01:49:37 +0000307
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100308 virtual ~TJSONContext(){};
David Reissdb0ea152008-02-18 01:49:37 +0000309
310 /**
311 * Write context data to the transport. Default is to do nothing.
312 */
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100313 virtual uint32_t write(TTransport& trans) {
314 (void)trans;
David Reissdb0ea152008-02-18 01:49:37 +0000315 return 0;
316 };
317
318 /**
319 * Read context data from the transport. Default is to do nothing.
320 */
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100321 virtual uint32_t read(TJSONProtocol::LookaheadReader& reader) {
322 (void)reader;
David Reissdb0ea152008-02-18 01:49:37 +0000323 return 0;
324 };
325
326 /**
327 * Return true if numbers need to be escaped as strings in this context.
328 * Default behavior is to return false.
329 */
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100330 virtual bool escapeNum() { return false; }
David Reissdb0ea152008-02-18 01:49:37 +0000331};
332
333// Context class for object member key-value pairs
334class JSONPairContext : public TJSONContext {
335
336public:
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100337 JSONPairContext() : first_(true), colon_(true) {}
David Reissdb0ea152008-02-18 01:49:37 +0000338
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100339 uint32_t write(TTransport& trans) {
David Reissdb0ea152008-02-18 01:49:37 +0000340 if (first_) {
341 first_ = false;
342 colon_ = true;
343 return 0;
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100344 } else {
David Reissdb0ea152008-02-18 01:49:37 +0000345 trans.write(colon_ ? &kJSONPairSeparator : &kJSONElemSeparator, 1);
346 colon_ = !colon_;
347 return 1;
348 }
349 }
350
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100351 uint32_t read(TJSONProtocol::LookaheadReader& reader) {
David Reissdb0ea152008-02-18 01:49:37 +0000352 if (first_) {
353 first_ = false;
354 colon_ = true;
355 return 0;
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100356 } else {
David Reissdb0ea152008-02-18 01:49:37 +0000357 uint8_t ch = (colon_ ? kJSONPairSeparator : kJSONElemSeparator);
358 colon_ = !colon_;
David Reiss1e62ab42008-02-21 22:37:45 +0000359 return readSyntaxChar(reader, ch);
David Reissdb0ea152008-02-18 01:49:37 +0000360 }
361 }
362
363 // Numbers must be turned into strings if they are the key part of a pair
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100364 virtual bool escapeNum() { return colon_; }
David Reissdb0ea152008-02-18 01:49:37 +0000365
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100366private:
367 bool first_;
368 bool colon_;
David Reissdb0ea152008-02-18 01:49:37 +0000369};
370
371// Context class for lists
372class JSONListContext : public TJSONContext {
373
374public:
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100375 JSONListContext() : first_(true) {}
David Reissdb0ea152008-02-18 01:49:37 +0000376
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100377 uint32_t write(TTransport& trans) {
David Reissdb0ea152008-02-18 01:49:37 +0000378 if (first_) {
379 first_ = false;
380 return 0;
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100381 } else {
David Reissdb0ea152008-02-18 01:49:37 +0000382 trans.write(&kJSONElemSeparator, 1);
383 return 1;
384 }
385 }
386
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100387 uint32_t read(TJSONProtocol::LookaheadReader& reader) {
David Reissdb0ea152008-02-18 01:49:37 +0000388 if (first_) {
389 first_ = false;
390 return 0;
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100391 } else {
David Reiss1e62ab42008-02-21 22:37:45 +0000392 return readSyntaxChar(reader, kJSONElemSeparator);
David Reissdb0ea152008-02-18 01:49:37 +0000393 }
394 }
395
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100396private:
397 bool first_;
David Reissdb0ea152008-02-18 01:49:37 +0000398};
399
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100400TJSONProtocol::TJSONProtocol(boost::shared_ptr<TTransport> ptrans)
401 : TVirtualProtocol<TJSONProtocol>(ptrans),
402 trans_(ptrans.get()),
403 context_(new TJSONContext()),
404 reader_(*ptrans) {
David Reissdb0ea152008-02-18 01:49:37 +0000405}
406
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100407TJSONProtocol::~TJSONProtocol() {
408}
David Reissdb0ea152008-02-18 01:49:37 +0000409
410void TJSONProtocol::pushContext(boost::shared_ptr<TJSONContext> c) {
411 contexts_.push(context_);
412 context_ = c;
413}
414
415void TJSONProtocol::popContext() {
416 context_ = contexts_.top();
417 contexts_.pop();
418}
419
420// Write the character ch as a JSON escape sequence ("\u00xx")
421uint32_t TJSONProtocol::writeJSONEscapeChar(uint8_t ch) {
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100422 trans_->write((const uint8_t*)kJSONEscapePrefix.c_str(),
Roger Meierb69d24d2012-10-04 18:02:15 +0000423 static_cast<uint32_t>(kJSONEscapePrefix.length()));
David Reissdb0ea152008-02-18 01:49:37 +0000424 uint8_t outCh = hexChar(ch >> 4);
425 trans_->write(&outCh, 1);
426 outCh = hexChar(ch);
427 trans_->write(&outCh, 1);
428 return 6;
429}
430
431// Write the character ch as part of a JSON string, escaping as appropriate.
432uint32_t TJSONProtocol::writeJSONChar(uint8_t ch) {
433 if (ch >= 0x30) {
434 if (ch == kJSONBackslash) { // Only special character >= 0x30 is '\'
435 trans_->write(&kJSONBackslash, 1);
436 trans_->write(&kJSONBackslash, 1);
437 return 2;
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100438 } else {
David Reissdb0ea152008-02-18 01:49:37 +0000439 trans_->write(&ch, 1);
440 return 1;
441 }
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100442 } else {
David Reissdb0ea152008-02-18 01:49:37 +0000443 uint8_t outCh = kJSONCharTable[ch];
444 // Check if regular character, backslash escaped, or JSON escaped
445 if (outCh == 1) {
446 trans_->write(&ch, 1);
447 return 1;
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100448 } else if (outCh > 1) {
David Reissdb0ea152008-02-18 01:49:37 +0000449 trans_->write(&kJSONBackslash, 1);
450 trans_->write(&outCh, 1);
451 return 2;
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100452 } else {
David Reissdb0ea152008-02-18 01:49:37 +0000453 return writeJSONEscapeChar(ch);
454 }
455 }
456}
457
458// Write out the contents of the string str as a JSON string, escaping
459// characters as appropriate.
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100460uint32_t TJSONProtocol::writeJSONString(const std::string& str) {
David Reissdb0ea152008-02-18 01:49:37 +0000461 uint32_t result = context_->write(*trans_);
462 result += 2; // For quotes
463 trans_->write(&kJSONStringDelimiter, 1);
464 std::string::const_iterator iter(str.begin());
465 std::string::const_iterator end(str.end());
466 while (iter != end) {
467 result += writeJSONChar(*iter++);
468 }
469 trans_->write(&kJSONStringDelimiter, 1);
470 return result;
471}
472
473// Write out the contents of the string as JSON string, base64-encoding
474// the string's contents, and escaping as appropriate
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100475uint32_t TJSONProtocol::writeJSONBase64(const std::string& str) {
David Reissdb0ea152008-02-18 01:49:37 +0000476 uint32_t result = context_->write(*trans_);
477 result += 2; // For quotes
478 trans_->write(&kJSONStringDelimiter, 1);
479 uint8_t b[4];
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100480 const uint8_t* bytes = (const uint8_t*)str.c_str();
481 if (str.length() > (std::numeric_limits<uint32_t>::max)())
Roger Meierb69d24d2012-10-04 18:02:15 +0000482 throw TProtocolException(TProtocolException::SIZE_LIMIT);
483 uint32_t len = static_cast<uint32_t>(str.length());
David Reissdb0ea152008-02-18 01:49:37 +0000484 while (len >= 3) {
485 // Encode 3 bytes at a time
486 base64_encode(bytes, 3, b);
487 trans_->write(b, 4);
488 result += 4;
489 bytes += 3;
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100490 len -= 3;
David Reissdb0ea152008-02-18 01:49:37 +0000491 }
492 if (len) { // Handle remainder
493 base64_encode(bytes, len, b);
494 trans_->write(b, len + 1);
495 result += len + 1;
496 }
497 trans_->write(&kJSONStringDelimiter, 1);
498 return result;
499}
500
501// Convert the given integer type to a JSON number, or a string
502// if the context requires it (eg: key in a map pair).
503template <typename NumberType>
504uint32_t TJSONProtocol::writeJSONInteger(NumberType num) {
505 uint32_t result = context_->write(*trans_);
506 std::string val(boost::lexical_cast<std::string>(num));
507 bool escapeNum = context_->escapeNum();
508 if (escapeNum) {
509 trans_->write(&kJSONStringDelimiter, 1);
510 result += 1;
511 }
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100512 if (val.length() > (std::numeric_limits<uint32_t>::max)())
Roger Meierb69d24d2012-10-04 18:02:15 +0000513 throw TProtocolException(TProtocolException::SIZE_LIMIT);
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100514 trans_->write((const uint8_t*)val.c_str(), static_cast<uint32_t>(val.length()));
Roger Meierb69d24d2012-10-04 18:02:15 +0000515 result += static_cast<uint32_t>(val.length());
David Reissdb0ea152008-02-18 01:49:37 +0000516 if (escapeNum) {
517 trans_->write(&kJSONStringDelimiter, 1);
518 result += 1;
519 }
520 return result;
521}
522
Konrad Grochowski1f6e3802015-05-18 18:10:06 +0200523namespace {
524std::string doubleToString(double d) {
Konrad Grochowski12b06e42015-02-21 13:48:56 +0100525 std::ostringstream str;
526 str.imbue(std::locale::classic());
Wang Yaofu0433d172016-02-15 10:43:09 +0800527 const double max_digits10 = 2 + std::numeric_limits<double>::digits10;
528 str.precision(max_digits10);
Konrad Grochowski12b06e42015-02-21 13:48:56 +0100529 str << d;
530 return str.str();
531}
532}
533
David Reissdb0ea152008-02-18 01:49:37 +0000534// Convert the given double to a JSON string, which is either the number,
535// "NaN" or "Infinity" or "-Infinity".
536uint32_t TJSONProtocol::writeJSONDouble(double num) {
537 uint32_t result = context_->write(*trans_);
Konrad Grochowski12b06e42015-02-21 13:48:56 +0100538 std::string val;
David Reissdb0ea152008-02-18 01:49:37 +0000539
David Reissdb0ea152008-02-18 01:49:37 +0000540 bool special = false;
Konrad Grochowski12b06e42015-02-21 13:48:56 +0100541 switch (boost::math::fpclassify(num)) {
542 case FP_INFINITE:
543 if (boost::math::signbit(num)) {
544 val = kThriftNegativeInfinity;
545 } else {
546 val = kThriftInfinity;
547 }
548 special = true;
549 break;
550 case FP_NAN:
David Reissdb0ea152008-02-18 01:49:37 +0000551 val = kThriftNan;
552 special = true;
553 break;
Konrad Grochowski12b06e42015-02-21 13:48:56 +0100554 default:
555 val = doubleToString(num);
David Reissdb0ea152008-02-18 01:49:37 +0000556 break;
557 }
558
559 bool escapeNum = special || context_->escapeNum();
560 if (escapeNum) {
561 trans_->write(&kJSONStringDelimiter, 1);
562 result += 1;
563 }
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100564 if (val.length() > (std::numeric_limits<uint32_t>::max)())
Roger Meierb69d24d2012-10-04 18:02:15 +0000565 throw TProtocolException(TProtocolException::SIZE_LIMIT);
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100566 trans_->write((const uint8_t*)val.c_str(), static_cast<uint32_t>(val.length()));
Roger Meierb69d24d2012-10-04 18:02:15 +0000567 result += static_cast<uint32_t>(val.length());
David Reissdb0ea152008-02-18 01:49:37 +0000568 if (escapeNum) {
569 trans_->write(&kJSONStringDelimiter, 1);
570 result += 1;
571 }
572 return result;
573}
574
575uint32_t TJSONProtocol::writeJSONObjectStart() {
576 uint32_t result = context_->write(*trans_);
577 trans_->write(&kJSONObjectStart, 1);
578 pushContext(boost::shared_ptr<TJSONContext>(new JSONPairContext()));
579 return result + 1;
580}
581
582uint32_t TJSONProtocol::writeJSONObjectEnd() {
583 popContext();
584 trans_->write(&kJSONObjectEnd, 1);
585 return 1;
586}
587
588uint32_t TJSONProtocol::writeJSONArrayStart() {
589 uint32_t result = context_->write(*trans_);
590 trans_->write(&kJSONArrayStart, 1);
591 pushContext(boost::shared_ptr<TJSONContext>(new JSONListContext()));
592 return result + 1;
593}
594
595uint32_t TJSONProtocol::writeJSONArrayEnd() {
596 popContext();
597 trans_->write(&kJSONArrayEnd, 1);
598 return 1;
599}
600
601uint32_t TJSONProtocol::writeMessageBegin(const std::string& name,
602 const TMessageType messageType,
603 const int32_t seqid) {
604 uint32_t result = writeJSONArrayStart();
605 result += writeJSONInteger(kThriftVersion1);
606 result += writeJSONString(name);
607 result += writeJSONInteger(messageType);
608 result += writeJSONInteger(seqid);
609 return result;
610}
611
612uint32_t TJSONProtocol::writeMessageEnd() {
613 return writeJSONArrayEnd();
614}
615
David Reiss64120002008-04-29 23:12:24 +0000616uint32_t TJSONProtocol::writeStructBegin(const char* name) {
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100617 (void)name;
David Reissdb0ea152008-02-18 01:49:37 +0000618 return writeJSONObjectStart();
619}
620
621uint32_t TJSONProtocol::writeStructEnd() {
622 return writeJSONObjectEnd();
623}
624
David Reiss64120002008-04-29 23:12:24 +0000625uint32_t TJSONProtocol::writeFieldBegin(const char* name,
David Reissdb0ea152008-02-18 01:49:37 +0000626 const TType fieldType,
627 const int16_t fieldId) {
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100628 (void)name;
David Reissdb0ea152008-02-18 01:49:37 +0000629 uint32_t result = writeJSONInteger(fieldId);
630 result += writeJSONObjectStart();
631 result += writeJSONString(getTypeNameForTypeID(fieldType));
632 return result;
633}
634
635uint32_t TJSONProtocol::writeFieldEnd() {
636 return writeJSONObjectEnd();
637}
638
639uint32_t TJSONProtocol::writeFieldStop() {
640 return 0;
641}
642
643uint32_t TJSONProtocol::writeMapBegin(const TType keyType,
644 const TType valType,
645 const uint32_t size) {
646 uint32_t result = writeJSONArrayStart();
647 result += writeJSONString(getTypeNameForTypeID(keyType));
648 result += writeJSONString(getTypeNameForTypeID(valType));
649 result += writeJSONInteger((int64_t)size);
650 result += writeJSONObjectStart();
651 return result;
652}
653
654uint32_t TJSONProtocol::writeMapEnd() {
dtmuller4300b722016-07-15 10:05:43 +0200655 uint32_t result = writeJSONObjectEnd();
656 result += writeJSONArrayEnd();
657 return result;
David Reissdb0ea152008-02-18 01:49:37 +0000658}
659
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100660uint32_t TJSONProtocol::writeListBegin(const TType elemType, const uint32_t size) {
David Reissdb0ea152008-02-18 01:49:37 +0000661 uint32_t result = writeJSONArrayStart();
662 result += writeJSONString(getTypeNameForTypeID(elemType));
663 result += writeJSONInteger((int64_t)size);
664 return result;
665}
666
667uint32_t TJSONProtocol::writeListEnd() {
668 return writeJSONArrayEnd();
669}
670
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100671uint32_t TJSONProtocol::writeSetBegin(const TType elemType, const uint32_t size) {
David Reissdb0ea152008-02-18 01:49:37 +0000672 uint32_t result = writeJSONArrayStart();
673 result += writeJSONString(getTypeNameForTypeID(elemType));
674 result += writeJSONInteger((int64_t)size);
675 return result;
676}
677
678uint32_t TJSONProtocol::writeSetEnd() {
679 return writeJSONArrayEnd();
680}
681
682uint32_t TJSONProtocol::writeBool(const bool value) {
683 return writeJSONInteger(value);
684}
685
686uint32_t TJSONProtocol::writeByte(const int8_t byte) {
Konrad Grochowski3b5dacb2014-11-24 10:55:31 +0100687 // writeByte() must be handled specially because boost::lexical cast sees
David Reissdb0ea152008-02-18 01:49:37 +0000688 // int8_t as a text type instead of an integer type
689 return writeJSONInteger((int16_t)byte);
690}
691
692uint32_t TJSONProtocol::writeI16(const int16_t i16) {
693 return writeJSONInteger(i16);
694}
695
696uint32_t TJSONProtocol::writeI32(const int32_t i32) {
697 return writeJSONInteger(i32);
698}
699
700uint32_t TJSONProtocol::writeI64(const int64_t i64) {
701 return writeJSONInteger(i64);
702}
703
704uint32_t TJSONProtocol::writeDouble(const double dub) {
705 return writeJSONDouble(dub);
706}
707
708uint32_t TJSONProtocol::writeString(const std::string& str) {
709 return writeJSONString(str);
710}
711
712uint32_t TJSONProtocol::writeBinary(const std::string& str) {
713 return writeJSONBase64(str);
714}
715
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100716/**
717 * Reading functions
718 */
David Reissdb0ea152008-02-18 01:49:37 +0000719
David Reiss1e62ab42008-02-21 22:37:45 +0000720// Reads 1 byte and verifies that it matches ch.
David Reissdb0ea152008-02-18 01:49:37 +0000721uint32_t TJSONProtocol::readJSONSyntaxChar(uint8_t ch) {
David Reiss1e62ab42008-02-21 22:37:45 +0000722 return readSyntaxChar(reader_, ch);
David Reissdb0ea152008-02-18 01:49:37 +0000723}
724
725// Decodes the four hex parts of a JSON escaped string character and returns
Konrad Grochowskia84e1392015-10-16 11:22:10 +0200726// the UTF-16 code unit via out.
727uint32_t TJSONProtocol::readJSONEscapeChar(uint16_t* out) {
728 uint8_t b[4];
David Reiss1e62ab42008-02-21 22:37:45 +0000729 b[0] = reader_.read();
730 b[1] = reader_.read();
Konrad Grochowskia84e1392015-10-16 11:22:10 +0200731 b[2] = reader_.read();
732 b[3] = reader_.read();
733
734 *out = (hexVal(b[0]) << 12)
735 + (hexVal(b[1]) << 8) + (hexVal(b[2]) << 4) + hexVal(b[3]);
736
David Reissdb0ea152008-02-18 01:49:37 +0000737 return 4;
738}
739
740// Decodes a JSON string, including unescaping, and returns the string via str
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100741uint32_t TJSONProtocol::readJSONString(std::string& str, bool skipContext) {
David Reiss1e62ab42008-02-21 22:37:45 +0000742 uint32_t result = (skipContext ? 0 : context_->read(reader_));
David Reissdb0ea152008-02-18 01:49:37 +0000743 result += readJSONSyntaxChar(kJSONStringDelimiter);
Konrad Grochowskia84e1392015-10-16 11:22:10 +0200744 std::vector<uint16_t> codeunits;
David Reiss1e62ab42008-02-21 22:37:45 +0000745 uint8_t ch;
David Reiss91630732008-02-28 21:11:39 +0000746 str.clear();
David Reissdb0ea152008-02-18 01:49:37 +0000747 while (true) {
David Reiss1e62ab42008-02-21 22:37:45 +0000748 ch = reader_.read();
749 ++result;
750 if (ch == kJSONStringDelimiter) {
David Reissdb0ea152008-02-18 01:49:37 +0000751 break;
752 }
David Reiss1e62ab42008-02-21 22:37:45 +0000753 if (ch == kJSONBackslash) {
754 ch = reader_.read();
755 ++result;
756 if (ch == kJSONEscapeChar) {
Konrad Grochowskia84e1392015-10-16 11:22:10 +0200757 uint16_t cp;
758 result += readJSONEscapeChar(&cp);
759 if (isHighSurrogate(cp)) {
760 codeunits.push_back(cp);
761 } else {
762 if (isLowSurrogate(cp)
763 && codeunits.empty()) {
764 throw TProtocolException(TProtocolException::INVALID_DATA,
765 "Missing UTF-16 high surrogate pair.");
766 }
767 codeunits.push_back(cp);
768 codeunits.push_back(0);
769 str += boost::locale::conv::utf_to_utf<char>(codeunits.data());
770 codeunits.clear();
771 }
772 continue;
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100773 } else {
David Reiss1e62ab42008-02-21 22:37:45 +0000774 size_t pos = kEscapeChars.find(ch);
David Reissdb0ea152008-02-18 01:49:37 +0000775 if (pos == std::string::npos) {
776 throw TProtocolException(TProtocolException::INVALID_DATA,
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100777 "Expected control char, got '" + std::string((const char*)&ch, 1)
778 + "'.");
David Reissdb0ea152008-02-18 01:49:37 +0000779 }
David Reiss1e62ab42008-02-21 22:37:45 +0000780 ch = kEscapeCharVals[pos];
David Reissdb0ea152008-02-18 01:49:37 +0000781 }
782 }
Konrad Grochowskia84e1392015-10-16 11:22:10 +0200783 if (!codeunits.empty()) {
784 throw TProtocolException(TProtocolException::INVALID_DATA,
785 "Missing UTF-16 low surrogate pair.");
786 }
David Reiss1e62ab42008-02-21 22:37:45 +0000787 str += ch;
David Reissdb0ea152008-02-18 01:49:37 +0000788 }
Konrad Grochowskia84e1392015-10-16 11:22:10 +0200789
790 if (!codeunits.empty()) {
791 throw TProtocolException(TProtocolException::INVALID_DATA,
792 "Missing UTF-16 low surrogate pair.");
793 }
David Reissdb0ea152008-02-18 01:49:37 +0000794 return result;
795}
796
797// Reads a block of base64 characters, decoding it, and returns via str
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100798uint32_t TJSONProtocol::readJSONBase64(std::string& str) {
David Reissdb0ea152008-02-18 01:49:37 +0000799 std::string tmp;
800 uint32_t result = readJSONString(tmp);
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100801 uint8_t* b = (uint8_t*)tmp.c_str();
802 if (tmp.length() > (std::numeric_limits<uint32_t>::max)())
Roger Meierb69d24d2012-10-04 18:02:15 +0000803 throw TProtocolException(TProtocolException::SIZE_LIMIT);
804 uint32_t len = static_cast<uint32_t>(tmp.length());
David Reiss91630732008-02-28 21:11:39 +0000805 str.clear();
Nobuaki Sukegawaa1754372015-10-10 10:44:07 +0900806 // Ignore padding
Nobuaki Sukegawadfb68962015-12-09 22:09:26 +0900807 if (len >= 2) {
808 uint32_t bound = len - 2;
809 for (uint32_t i = len - 1; i >= bound && b[i] == '='; --i) {
810 --len;
811 }
Nobuaki Sukegawaa1754372015-10-10 10:44:07 +0900812 }
David Reissdb0ea152008-02-18 01:49:37 +0000813 while (len >= 4) {
814 base64_decode(b, 4);
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100815 str.append((const char*)b, 3);
David Reissdb0ea152008-02-18 01:49:37 +0000816 b += 4;
817 len -= 4;
818 }
819 // Don't decode if we hit the end or got a single leftover byte (invalid
820 // base64 but legal for skip of regular string type)
821 if (len > 1) {
822 base64_decode(b, len);
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100823 str.append((const char*)b, len - 1);
David Reissdb0ea152008-02-18 01:49:37 +0000824 }
825 return result;
826}
827
828// Reads a sequence of characters, stopping at the first one that is not
829// a valid JSON numeric character.
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100830uint32_t TJSONProtocol::readJSONNumericChars(std::string& str) {
David Reissdb0ea152008-02-18 01:49:37 +0000831 uint32_t result = 0;
David Reiss91630732008-02-28 21:11:39 +0000832 str.clear();
David Reissdb0ea152008-02-18 01:49:37 +0000833 while (true) {
David Reiss1e62ab42008-02-21 22:37:45 +0000834 uint8_t ch = reader_.peek();
David Reissdb0ea152008-02-18 01:49:37 +0000835 if (!isJSONNumeric(ch)) {
836 break;
837 }
David Reiss1e62ab42008-02-21 22:37:45 +0000838 reader_.read();
David Reissdb0ea152008-02-18 01:49:37 +0000839 str += ch;
840 ++result;
841 }
842 return result;
843}
844
845// Reads a sequence of characters and assembles them into a number,
846// returning them via num
847template <typename NumberType>
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100848uint32_t TJSONProtocol::readJSONInteger(NumberType& num) {
David Reiss1e62ab42008-02-21 22:37:45 +0000849 uint32_t result = context_->read(reader_);
David Reissdb0ea152008-02-18 01:49:37 +0000850 if (context_->escapeNum()) {
851 result += readJSONSyntaxChar(kJSONStringDelimiter);
852 }
853 std::string str;
854 result += readJSONNumericChars(str);
855 try {
856 num = boost::lexical_cast<NumberType>(str);
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100857 } catch (boost::bad_lexical_cast e) {
Claudius Heine8f11f522015-07-01 10:35:38 +0200858 throw TProtocolException(TProtocolException::INVALID_DATA,
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100859 "Expected numeric value; got \"" + str + "\"");
David Reissdb0ea152008-02-18 01:49:37 +0000860 }
861 if (context_->escapeNum()) {
862 result += readJSONSyntaxChar(kJSONStringDelimiter);
863 }
864 return result;
865}
866
Konrad Grochowski1f6e3802015-05-18 18:10:06 +0200867namespace {
868double stringToDouble(const std::string& s) {
Konrad Grochowski12b06e42015-02-21 13:48:56 +0100869 double d;
870 std::istringstream str(s);
871 str.imbue(std::locale::classic());
872 str >> d;
873 if (str.bad() || !str.eof())
874 throw std::runtime_error(s);
875 return d;
876}
877}
878
David Reissdb0ea152008-02-18 01:49:37 +0000879// Reads a JSON number or string and interprets it as a double.
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100880uint32_t TJSONProtocol::readJSONDouble(double& num) {
David Reiss1e62ab42008-02-21 22:37:45 +0000881 uint32_t result = context_->read(reader_);
David Reissdb0ea152008-02-18 01:49:37 +0000882 std::string str;
David Reiss1e62ab42008-02-21 22:37:45 +0000883 if (reader_.peek() == kJSONStringDelimiter) {
David Reissdb0ea152008-02-18 01:49:37 +0000884 result += readJSONString(str, true);
885 // Check for NaN, Infinity and -Infinity
886 if (str == kThriftNan) {
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100887 num = HUGE_VAL / HUGE_VAL; // generates NaN
888 } else if (str == kThriftInfinity) {
David Reissdb0ea152008-02-18 01:49:37 +0000889 num = HUGE_VAL;
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100890 } else if (str == kThriftNegativeInfinity) {
David Reissdb0ea152008-02-18 01:49:37 +0000891 num = -HUGE_VAL;
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100892 } else {
David Reissdb0ea152008-02-18 01:49:37 +0000893 if (!context_->escapeNum()) {
894 // Throw exception -- we should not be in a string in this case
Claudius Heine8f11f522015-07-01 10:35:38 +0200895 throw TProtocolException(TProtocolException::INVALID_DATA,
David Reissdb0ea152008-02-18 01:49:37 +0000896 "Numeric data unexpectedly quoted");
897 }
898 try {
Konrad Grochowski12b06e42015-02-21 13:48:56 +0100899 num = stringToDouble(str);
900 } catch (std::runtime_error e) {
Claudius Heine8f11f522015-07-01 10:35:38 +0200901 throw TProtocolException(TProtocolException::INVALID_DATA,
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100902 "Expected numeric value; got \"" + str + "\"");
David Reissdb0ea152008-02-18 01:49:37 +0000903 }
904 }
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100905 } else {
David Reissdb0ea152008-02-18 01:49:37 +0000906 if (context_->escapeNum()) {
907 // This will throw - we should have had a quote if escapeNum == true
908 readJSONSyntaxChar(kJSONStringDelimiter);
909 }
910 result += readJSONNumericChars(str);
911 try {
Konrad Grochowski12b06e42015-02-21 13:48:56 +0100912 num = stringToDouble(str);
913 } catch (std::runtime_error e) {
Claudius Heine8f11f522015-07-01 10:35:38 +0200914 throw TProtocolException(TProtocolException::INVALID_DATA,
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100915 "Expected numeric value; got \"" + str + "\"");
David Reissdb0ea152008-02-18 01:49:37 +0000916 }
917 }
918 return result;
919}
920
921uint32_t TJSONProtocol::readJSONObjectStart() {
David Reiss1e62ab42008-02-21 22:37:45 +0000922 uint32_t result = context_->read(reader_);
David Reissdb0ea152008-02-18 01:49:37 +0000923 result += readJSONSyntaxChar(kJSONObjectStart);
924 pushContext(boost::shared_ptr<TJSONContext>(new JSONPairContext()));
925 return result;
926}
927
928uint32_t TJSONProtocol::readJSONObjectEnd() {
929 uint32_t result = readJSONSyntaxChar(kJSONObjectEnd);
930 popContext();
931 return result;
932}
933
934uint32_t TJSONProtocol::readJSONArrayStart() {
David Reiss1e62ab42008-02-21 22:37:45 +0000935 uint32_t result = context_->read(reader_);
David Reissdb0ea152008-02-18 01:49:37 +0000936 result += readJSONSyntaxChar(kJSONArrayStart);
937 pushContext(boost::shared_ptr<TJSONContext>(new JSONListContext()));
938 return result;
939}
940
941uint32_t TJSONProtocol::readJSONArrayEnd() {
942 uint32_t result = readJSONSyntaxChar(kJSONArrayEnd);
943 popContext();
944 return result;
945}
946
947uint32_t TJSONProtocol::readMessageBegin(std::string& name,
948 TMessageType& messageType,
949 int32_t& seqid) {
950 uint32_t result = readJSONArrayStart();
David Reissdb0ea152008-02-18 01:49:37 +0000951 uint64_t tmpVal = 0;
952 result += readJSONInteger(tmpVal);
953 if (tmpVal != kThriftVersion1) {
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100954 throw TProtocolException(TProtocolException::BAD_VERSION, "Message contained bad version.");
David Reissdb0ea152008-02-18 01:49:37 +0000955 }
956 result += readJSONString(name);
957 result += readJSONInteger(tmpVal);
958 messageType = (TMessageType)tmpVal;
959 result += readJSONInteger(tmpVal);
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100960 if (tmpVal > static_cast<uint64_t>((std::numeric_limits<int32_t>::max)()))
Roger Meierb69d24d2012-10-04 18:02:15 +0000961 throw TProtocolException(TProtocolException::SIZE_LIMIT);
962 seqid = static_cast<int32_t>(tmpVal);
David Reissdb0ea152008-02-18 01:49:37 +0000963 return result;
964}
965
966uint32_t TJSONProtocol::readMessageEnd() {
967 return readJSONArrayEnd();
968}
969
970uint32_t TJSONProtocol::readStructBegin(std::string& name) {
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100971 (void)name;
David Reissdb0ea152008-02-18 01:49:37 +0000972 return readJSONObjectStart();
973}
974
975uint32_t TJSONProtocol::readStructEnd() {
976 return readJSONObjectEnd();
977}
978
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100979uint32_t TJSONProtocol::readFieldBegin(std::string& name, TType& fieldType, int16_t& fieldId) {
980 (void)name;
David Reissdb0ea152008-02-18 01:49:37 +0000981 uint32_t result = 0;
David Reiss1e62ab42008-02-21 22:37:45 +0000982 // Check if we hit the end of the list
983 uint8_t ch = reader_.peek();
984 if (ch == kJSONObjectEnd) {
T Jake Lucianib5e62212009-01-31 22:36:20 +0000985 fieldType = apache::thrift::protocol::T_STOP;
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100986 } else {
David Reissdb0ea152008-02-18 01:49:37 +0000987 uint64_t tmpVal = 0;
988 std::string tmpStr;
989 result += readJSONInteger(tmpVal);
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100990 if (tmpVal > static_cast<uint32_t>((std::numeric_limits<int16_t>::max)()))
Roger Meierb69d24d2012-10-04 18:02:15 +0000991 throw TProtocolException(TProtocolException::SIZE_LIMIT);
992 fieldId = static_cast<int16_t>(tmpVal);
David Reissdb0ea152008-02-18 01:49:37 +0000993 result += readJSONObjectStart();
994 result += readJSONString(tmpStr);
995 fieldType = getTypeIDForTypeName(tmpStr);
996 }
997 return result;
998}
999
1000uint32_t TJSONProtocol::readFieldEnd() {
1001 return readJSONObjectEnd();
1002}
1003
Konrad Grochowski16a23a62014-11-13 15:33:38 +01001004uint32_t TJSONProtocol::readMapBegin(TType& keyType, TType& valType, uint32_t& size) {
David Reissdb0ea152008-02-18 01:49:37 +00001005 uint64_t tmpVal = 0;
1006 std::string tmpStr;
1007 uint32_t result = readJSONArrayStart();
1008 result += readJSONString(tmpStr);
1009 keyType = getTypeIDForTypeName(tmpStr);
1010 result += readJSONString(tmpStr);
1011 valType = getTypeIDForTypeName(tmpStr);
1012 result += readJSONInteger(tmpVal);
Konrad Grochowski16a23a62014-11-13 15:33:38 +01001013 if (tmpVal > (std::numeric_limits<uint32_t>::max)())
Roger Meierb69d24d2012-10-04 18:02:15 +00001014 throw TProtocolException(TProtocolException::SIZE_LIMIT);
1015 size = static_cast<uint32_t>(tmpVal);
David Reissdb0ea152008-02-18 01:49:37 +00001016 result += readJSONObjectStart();
1017 return result;
1018}
1019
1020uint32_t TJSONProtocol::readMapEnd() {
dtmuller4300b722016-07-15 10:05:43 +02001021 uint32_t result = readJSONObjectEnd();
1022 result += readJSONArrayEnd();
1023 return result;
David Reissdb0ea152008-02-18 01:49:37 +00001024}
1025
Konrad Grochowski16a23a62014-11-13 15:33:38 +01001026uint32_t TJSONProtocol::readListBegin(TType& elemType, uint32_t& size) {
David Reissdb0ea152008-02-18 01:49:37 +00001027 uint64_t tmpVal = 0;
1028 std::string tmpStr;
1029 uint32_t result = readJSONArrayStart();
1030 result += readJSONString(tmpStr);
1031 elemType = getTypeIDForTypeName(tmpStr);
1032 result += readJSONInteger(tmpVal);
Konrad Grochowski16a23a62014-11-13 15:33:38 +01001033 if (tmpVal > (std::numeric_limits<uint32_t>::max)())
Roger Meierb69d24d2012-10-04 18:02:15 +00001034 throw TProtocolException(TProtocolException::SIZE_LIMIT);
1035 size = static_cast<uint32_t>(tmpVal);
David Reissdb0ea152008-02-18 01:49:37 +00001036 return result;
1037}
1038
1039uint32_t TJSONProtocol::readListEnd() {
1040 return readJSONArrayEnd();
1041}
1042
Konrad Grochowski16a23a62014-11-13 15:33:38 +01001043uint32_t TJSONProtocol::readSetBegin(TType& elemType, uint32_t& size) {
David Reissdb0ea152008-02-18 01:49:37 +00001044 uint64_t tmpVal = 0;
1045 std::string tmpStr;
1046 uint32_t result = readJSONArrayStart();
1047 result += readJSONString(tmpStr);
1048 elemType = getTypeIDForTypeName(tmpStr);
1049 result += readJSONInteger(tmpVal);
Konrad Grochowski16a23a62014-11-13 15:33:38 +01001050 if (tmpVal > (std::numeric_limits<uint32_t>::max)())
Roger Meierb69d24d2012-10-04 18:02:15 +00001051 throw TProtocolException(TProtocolException::SIZE_LIMIT);
1052 size = static_cast<uint32_t>(tmpVal);
David Reissdb0ea152008-02-18 01:49:37 +00001053 return result;
1054}
1055
1056uint32_t TJSONProtocol::readSetEnd() {
1057 return readJSONArrayEnd();
1058}
1059
1060uint32_t TJSONProtocol::readBool(bool& value) {
1061 return readJSONInteger(value);
1062}
1063
Konrad Grochowski3b5dacb2014-11-24 10:55:31 +01001064// readByte() must be handled properly because boost::lexical cast sees int8_t
David Reissdb0ea152008-02-18 01:49:37 +00001065// as a text type instead of an integer type
1066uint32_t TJSONProtocol::readByte(int8_t& byte) {
Konrad Grochowski16a23a62014-11-13 15:33:38 +01001067 int16_t tmp = (int16_t)byte;
1068 uint32_t result = readJSONInteger(tmp);
David Reissdb0ea152008-02-18 01:49:37 +00001069 assert(tmp < 256);
1070 byte = (int8_t)tmp;
1071 return result;
1072}
1073
1074uint32_t TJSONProtocol::readI16(int16_t& i16) {
1075 return readJSONInteger(i16);
1076}
1077
1078uint32_t TJSONProtocol::readI32(int32_t& i32) {
1079 return readJSONInteger(i32);
1080}
1081
1082uint32_t TJSONProtocol::readI64(int64_t& i64) {
1083 return readJSONInteger(i64);
1084}
1085
1086uint32_t TJSONProtocol::readDouble(double& dub) {
1087 return readJSONDouble(dub);
1088}
1089
Konrad Grochowski16a23a62014-11-13 15:33:38 +01001090uint32_t TJSONProtocol::readString(std::string& str) {
David Reissdb0ea152008-02-18 01:49:37 +00001091 return readJSONString(str);
1092}
1093
Konrad Grochowski16a23a62014-11-13 15:33:38 +01001094uint32_t TJSONProtocol::readBinary(std::string& str) {
David Reissdb0ea152008-02-18 01:49:37 +00001095 return readJSONBase64(str);
1096}
Konrad Grochowski16a23a62014-11-13 15:33:38 +01001097}
1098}
1099} // apache::thrift::protocol