| David Reiss | ea2cba8 | 2009-03-30 21:35:00 +0000 | [diff] [blame] | 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 |  */ | 
| David Reiss | db0ea15 | 2008-02-18 01:49:37 +0000 | [diff] [blame] | 19 |  | 
 | 20 | #include "TJSONProtocol.h" | 
 | 21 |  | 
 | 22 | #include <math.h> | 
| David Reiss | a177109 | 2008-04-11 22:36:31 +0000 | [diff] [blame] | 23 | #include <boost/lexical_cast.hpp> | 
| David Reiss | db0ea15 | 2008-02-18 01:49:37 +0000 | [diff] [blame] | 24 | #include "TBase64Utils.h" | 
 | 25 | #include <transport/TTransportException.h> | 
 | 26 |  | 
| T Jake Luciani | b5e6221 | 2009-01-31 22:36:20 +0000 | [diff] [blame] | 27 | using namespace apache::thrift::transport; | 
| David Reiss | db0ea15 | 2008-02-18 01:49:37 +0000 | [diff] [blame] | 28 |  | 
| T Jake Luciani | b5e6221 | 2009-01-31 22:36:20 +0000 | [diff] [blame] | 29 | namespace apache { namespace thrift { namespace protocol { | 
| David Reiss | db0ea15 | 2008-02-18 01:49:37 +0000 | [diff] [blame] | 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 |  | 
| David Reiss | 6713e1b | 2009-01-15 23:56:19 +0000 | [diff] [blame] | 48 | static const uint32_t kThriftVersion1 = 1; | 
| David Reiss | db0ea15 | 2008-02-18 01:49:37 +0000 | [diff] [blame] | 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 | 
| David Reiss | 2c9824c | 2008-03-02 00:20:47 +0000 | [diff] [blame] | 98 |   if (name.length() > 1) { | 
| David Reiss | 1e62ab4 | 2008-02-21 22:37:45 +0000 | [diff] [blame] | 99 |     switch (name[0]) { | 
 | 100 |     case 'd': | 
 | 101 |       result = T_DOUBLE; | 
| David Reiss | db0ea15 | 2008-02-18 01:49:37 +0000 | [diff] [blame] | 102 |       break; | 
| David Reiss | 1e62ab4 | 2008-02-21 22:37:45 +0000 | [diff] [blame] | 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 |       } | 
| David Reiss | db0ea15 | 2008-02-18 01:49:37 +0000 | [diff] [blame] | 118 |       break; | 
| David Reiss | 1e62ab4 | 2008-02-21 22:37:45 +0000 | [diff] [blame] | 119 |     case 'l': | 
 | 120 |       result = T_LIST; | 
| David Reiss | db0ea15 | 2008-02-18 01:49:37 +0000 | [diff] [blame] | 121 |       break; | 
| David Reiss | 1e62ab4 | 2008-02-21 22:37:45 +0000 | [diff] [blame] | 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; | 
| David Reiss | db0ea15 | 2008-02-18 01:49:37 +0000 | [diff] [blame] | 138 |       break; | 
 | 139 |     } | 
| David Reiss | db0ea15 | 2008-02-18 01:49:37 +0000 | [diff] [blame] | 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. | 
| David Reiss | 1e62ab4 | 2008-02-21 22:37:45 +0000 | [diff] [blame] | 178 | static uint32_t readSyntaxChar(TJSONProtocol::LookaheadReader &reader, | 
 | 179 |                                uint8_t ch) { | 
 | 180 |   uint8_t ch2 = reader.read(); | 
 | 181 |   if (ch2 != ch) { | 
| David Reiss | db0ea15 | 2008-02-18 01:49:37 +0000 | [diff] [blame] | 182 |     throw TProtocolException(TProtocolException::INVALID_DATA, | 
 | 183 |                              "Expected \'" + std::string((char *)&ch, 1) + | 
| David Reiss | 1e62ab4 | 2008-02-21 22:37:45 +0000 | [diff] [blame] | 184 |                              "\'; got \'" + std::string((char *)&ch2, 1) + | 
| David Reiss | db0ea15 | 2008-02-18 01:49:37 +0000 | [diff] [blame] | 185 |                              "\'."); | 
 | 186 |   } | 
 | 187 |   return 1; | 
 | 188 | } | 
 | 189 |  | 
| David Reiss | db0ea15 | 2008-02-18 01:49:37 +0000 | [diff] [blame] | 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')) { | 
| Bryan Duxbury | 4a2bc1b | 2010-11-03 17:57:38 +0000 | [diff] [blame] | 197 |     return ch - 'a' + 10; | 
| David Reiss | db0ea15 | 2008-02-18 01:49:37 +0000 | [diff] [blame] | 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 { | 
| Bryan Duxbury | 4a2bc1b | 2010-11-03 17:57:38 +0000 | [diff] [blame] | 214 |     return val - 10 + 'a'; | 
| David Reiss | db0ea15 | 2008-02-18 01:49:37 +0000 | [diff] [blame] | 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 | /** | 
| David Reiss | 1e62ab4 | 2008-02-21 22:37:45 +0000 | [diff] [blame] | 243 |  * Class to serve as base JSON context and as base class for other context | 
| David Reiss | db0ea15 | 2008-02-18 01:49:37 +0000 | [diff] [blame] | 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) { | 
| Roger Meier | 3b771a1 | 2010-11-17 22:11:26 +0000 | [diff] [blame] | 258 |     (void) trans; | 
| David Reiss | db0ea15 | 2008-02-18 01:49:37 +0000 | [diff] [blame] | 259 |     return 0; | 
 | 260 |   }; | 
 | 261 |  | 
 | 262 |   /** | 
 | 263 |    * Read context data from the transport. Default is to do nothing. | 
 | 264 |    */ | 
| David Reiss | 1e62ab4 | 2008-02-21 22:37:45 +0000 | [diff] [blame] | 265 |   virtual uint32_t read(TJSONProtocol::LookaheadReader &reader) { | 
| Roger Meier | 3b771a1 | 2010-11-17 22:11:26 +0000 | [diff] [blame] | 266 |     (void) reader; | 
| David Reiss | db0ea15 | 2008-02-18 01:49:37 +0000 | [diff] [blame] | 267 |     return 0; | 
 | 268 |   }; | 
 | 269 |  | 
 | 270 |   /** | 
 | 271 |    * Return true if numbers need to be escaped as strings in this context. | 
 | 272 |    * Default behavior is to return false. | 
 | 273 |    */ | 
 | 274 |   virtual bool escapeNum() { | 
 | 275 |     return false; | 
 | 276 |   } | 
 | 277 | }; | 
 | 278 |  | 
 | 279 | // Context class for object member key-value pairs | 
 | 280 | class JSONPairContext : public TJSONContext { | 
 | 281 |  | 
 | 282 | public: | 
 | 283 |  | 
 | 284 |   JSONPairContext() : | 
 | 285 |     first_(true), | 
 | 286 |     colon_(true) { | 
 | 287 |   } | 
 | 288 |  | 
 | 289 |   uint32_t write(TTransport &trans) { | 
 | 290 |     if (first_) { | 
 | 291 |       first_ = false; | 
 | 292 |       colon_ = true; | 
 | 293 |       return 0; | 
 | 294 |     } | 
 | 295 |     else { | 
 | 296 |       trans.write(colon_ ? &kJSONPairSeparator : &kJSONElemSeparator, 1); | 
 | 297 |       colon_ = !colon_; | 
 | 298 |       return 1; | 
 | 299 |     } | 
 | 300 |   } | 
 | 301 |  | 
| David Reiss | 1e62ab4 | 2008-02-21 22:37:45 +0000 | [diff] [blame] | 302 |   uint32_t read(TJSONProtocol::LookaheadReader &reader) { | 
| David Reiss | db0ea15 | 2008-02-18 01:49:37 +0000 | [diff] [blame] | 303 |     if (first_) { | 
 | 304 |       first_ = false; | 
 | 305 |       colon_ = true; | 
 | 306 |       return 0; | 
 | 307 |     } | 
 | 308 |     else { | 
 | 309 |       uint8_t ch = (colon_ ? kJSONPairSeparator : kJSONElemSeparator); | 
 | 310 |       colon_ = !colon_; | 
| David Reiss | 1e62ab4 | 2008-02-21 22:37:45 +0000 | [diff] [blame] | 311 |       return readSyntaxChar(reader, ch); | 
| David Reiss | db0ea15 | 2008-02-18 01:49:37 +0000 | [diff] [blame] | 312 |     } | 
 | 313 |   } | 
 | 314 |  | 
 | 315 |   // Numbers must be turned into strings if they are the key part of a pair | 
 | 316 |   virtual bool escapeNum() { | 
 | 317 |     return colon_; | 
 | 318 |   } | 
 | 319 |  | 
 | 320 |   private: | 
 | 321 |  | 
 | 322 |     bool first_; | 
 | 323 |     bool colon_; | 
 | 324 | }; | 
 | 325 |  | 
 | 326 | // Context class for lists | 
 | 327 | class JSONListContext : public TJSONContext { | 
 | 328 |  | 
 | 329 | public: | 
 | 330 |  | 
 | 331 |   JSONListContext() : | 
 | 332 |     first_(true) { | 
 | 333 |   } | 
 | 334 |  | 
 | 335 |   uint32_t write(TTransport &trans) { | 
 | 336 |     if (first_) { | 
 | 337 |       first_ = false; | 
 | 338 |       return 0; | 
 | 339 |     } | 
 | 340 |     else { | 
 | 341 |       trans.write(&kJSONElemSeparator, 1); | 
 | 342 |       return 1; | 
 | 343 |     } | 
 | 344 |   } | 
 | 345 |  | 
| David Reiss | 1e62ab4 | 2008-02-21 22:37:45 +0000 | [diff] [blame] | 346 |   uint32_t read(TJSONProtocol::LookaheadReader &reader) { | 
| David Reiss | db0ea15 | 2008-02-18 01:49:37 +0000 | [diff] [blame] | 347 |     if (first_) { | 
 | 348 |       first_ = false; | 
 | 349 |       return 0; | 
 | 350 |     } | 
 | 351 |     else { | 
| David Reiss | 1e62ab4 | 2008-02-21 22:37:45 +0000 | [diff] [blame] | 352 |       return readSyntaxChar(reader, kJSONElemSeparator); | 
| David Reiss | db0ea15 | 2008-02-18 01:49:37 +0000 | [diff] [blame] | 353 |     } | 
 | 354 |   } | 
 | 355 |  | 
 | 356 |   private: | 
 | 357 |     bool first_; | 
 | 358 | }; | 
 | 359 |  | 
 | 360 |  | 
 | 361 | TJSONProtocol::TJSONProtocol(boost::shared_ptr<TTransport> ptrans) : | 
| David Reiss | 6806fb8 | 2010-10-06 17:09:52 +0000 | [diff] [blame] | 362 |   TVirtualProtocol<TJSONProtocol>(ptrans), | 
| David Reiss | e71115b | 2010-10-06 17:09:56 +0000 | [diff] [blame] | 363 |   trans_(ptrans.get()), | 
| David Reiss | 1e62ab4 | 2008-02-21 22:37:45 +0000 | [diff] [blame] | 364 |   context_(new TJSONContext()), | 
 | 365 |   reader_(*ptrans) { | 
| David Reiss | db0ea15 | 2008-02-18 01:49:37 +0000 | [diff] [blame] | 366 | } | 
 | 367 |  | 
 | 368 | TJSONProtocol::~TJSONProtocol() {} | 
 | 369 |  | 
 | 370 | void TJSONProtocol::pushContext(boost::shared_ptr<TJSONContext> c) { | 
 | 371 |   contexts_.push(context_); | 
 | 372 |   context_ = c; | 
 | 373 | } | 
 | 374 |  | 
 | 375 | void TJSONProtocol::popContext() { | 
 | 376 |   context_ = contexts_.top(); | 
 | 377 |   contexts_.pop(); | 
 | 378 | } | 
 | 379 |  | 
 | 380 | // Write the character ch as a JSON escape sequence ("\u00xx") | 
 | 381 | uint32_t TJSONProtocol::writeJSONEscapeChar(uint8_t ch) { | 
 | 382 |   trans_->write((const uint8_t *)kJSONEscapePrefix.c_str(), | 
 | 383 |                 kJSONEscapePrefix.length()); | 
 | 384 |   uint8_t outCh = hexChar(ch >> 4); | 
 | 385 |   trans_->write(&outCh, 1); | 
 | 386 |   outCh = hexChar(ch); | 
 | 387 |   trans_->write(&outCh, 1); | 
 | 388 |   return 6; | 
 | 389 | } | 
 | 390 |  | 
 | 391 | // Write the character ch as part of a JSON string, escaping as appropriate. | 
 | 392 | uint32_t TJSONProtocol::writeJSONChar(uint8_t ch) { | 
 | 393 |   if (ch >= 0x30) { | 
 | 394 |     if (ch == kJSONBackslash) { // Only special character >= 0x30 is '\' | 
 | 395 |       trans_->write(&kJSONBackslash, 1); | 
 | 396 |       trans_->write(&kJSONBackslash, 1); | 
 | 397 |       return 2; | 
 | 398 |     } | 
 | 399 |     else { | 
 | 400 |       trans_->write(&ch, 1); | 
 | 401 |       return 1; | 
 | 402 |     } | 
 | 403 |   } | 
 | 404 |   else { | 
 | 405 |     uint8_t outCh = kJSONCharTable[ch]; | 
 | 406 |     // Check if regular character, backslash escaped, or JSON escaped | 
 | 407 |     if (outCh == 1) { | 
 | 408 |       trans_->write(&ch, 1); | 
 | 409 |       return 1; | 
 | 410 |     } | 
 | 411 |     else if (outCh > 1) { | 
 | 412 |       trans_->write(&kJSONBackslash, 1); | 
 | 413 |       trans_->write(&outCh, 1); | 
 | 414 |       return 2; | 
 | 415 |     } | 
 | 416 |     else { | 
 | 417 |       return writeJSONEscapeChar(ch); | 
 | 418 |     } | 
 | 419 |   } | 
 | 420 | } | 
 | 421 |  | 
 | 422 | // Write out the contents of the string str as a JSON string, escaping | 
 | 423 | // characters as appropriate. | 
 | 424 | uint32_t TJSONProtocol::writeJSONString(const std::string &str) { | 
 | 425 |   uint32_t result = context_->write(*trans_); | 
 | 426 |   result += 2; // For quotes | 
 | 427 |   trans_->write(&kJSONStringDelimiter, 1); | 
 | 428 |   std::string::const_iterator iter(str.begin()); | 
 | 429 |   std::string::const_iterator end(str.end()); | 
 | 430 |   while (iter != end) { | 
 | 431 |     result += writeJSONChar(*iter++); | 
 | 432 |   } | 
 | 433 |   trans_->write(&kJSONStringDelimiter, 1); | 
 | 434 |   return result; | 
 | 435 | } | 
 | 436 |  | 
 | 437 | // Write out the contents of the string as JSON string, base64-encoding | 
 | 438 | // the string's contents, and escaping as appropriate | 
 | 439 | uint32_t TJSONProtocol::writeJSONBase64(const std::string &str) { | 
 | 440 |   uint32_t result = context_->write(*trans_); | 
 | 441 |   result += 2; // For quotes | 
 | 442 |   trans_->write(&kJSONStringDelimiter, 1); | 
 | 443 |   uint8_t b[4]; | 
 | 444 |   const uint8_t *bytes = (const uint8_t *)str.c_str(); | 
 | 445 |   uint32_t len = str.length(); | 
 | 446 |   while (len >= 3) { | 
 | 447 |     // Encode 3 bytes at a time | 
 | 448 |     base64_encode(bytes, 3, b); | 
 | 449 |     trans_->write(b, 4); | 
 | 450 |     result += 4; | 
 | 451 |     bytes += 3; | 
 | 452 |     len -=3; | 
 | 453 |   } | 
 | 454 |   if (len) { // Handle remainder | 
 | 455 |     base64_encode(bytes, len, b); | 
 | 456 |     trans_->write(b, len + 1); | 
 | 457 |     result += len + 1; | 
 | 458 |   } | 
 | 459 |   trans_->write(&kJSONStringDelimiter, 1); | 
 | 460 |   return result; | 
 | 461 | } | 
 | 462 |  | 
 | 463 | // Convert the given integer type to a JSON number, or a string | 
 | 464 | // if the context requires it (eg: key in a map pair). | 
 | 465 | template <typename NumberType> | 
 | 466 | uint32_t TJSONProtocol::writeJSONInteger(NumberType num) { | 
 | 467 |   uint32_t result = context_->write(*trans_); | 
 | 468 |   std::string val(boost::lexical_cast<std::string>(num)); | 
 | 469 |   bool escapeNum = context_->escapeNum(); | 
 | 470 |   if (escapeNum) { | 
 | 471 |     trans_->write(&kJSONStringDelimiter, 1); | 
 | 472 |     result += 1; | 
 | 473 |   } | 
 | 474 |   trans_->write((const uint8_t *)val.c_str(), val.length()); | 
 | 475 |   result += val.length(); | 
 | 476 |   if (escapeNum) { | 
 | 477 |     trans_->write(&kJSONStringDelimiter, 1); | 
 | 478 |     result += 1; | 
 | 479 |   } | 
 | 480 |   return result; | 
 | 481 | } | 
 | 482 |  | 
 | 483 | // Convert the given double to a JSON string, which is either the number, | 
 | 484 | // "NaN" or "Infinity" or "-Infinity". | 
 | 485 | uint32_t TJSONProtocol::writeJSONDouble(double num) { | 
 | 486 |   uint32_t result = context_->write(*trans_); | 
 | 487 |   std::string val(boost::lexical_cast<std::string>(num)); | 
 | 488 |  | 
 | 489 |   // Normalize output of boost::lexical_cast for NaNs and Infinities | 
 | 490 |   bool special = false; | 
 | 491 |   switch (val[0]) { | 
 | 492 |   case 'N': | 
 | 493 |   case 'n': | 
 | 494 |     val = kThriftNan; | 
 | 495 |     special = true; | 
 | 496 |     break; | 
 | 497 |   case 'I': | 
 | 498 |   case 'i': | 
 | 499 |     val = kThriftInfinity; | 
 | 500 |     special = true; | 
 | 501 |     break; | 
 | 502 |   case '-': | 
 | 503 |     if ((val[1] == 'I') || (val[1] == 'i')) { | 
 | 504 |       val = kThriftNegativeInfinity; | 
 | 505 |       special = true; | 
 | 506 |     } | 
 | 507 |     break; | 
 | 508 |   } | 
 | 509 |  | 
 | 510 |   bool escapeNum = special || context_->escapeNum(); | 
 | 511 |   if (escapeNum) { | 
 | 512 |     trans_->write(&kJSONStringDelimiter, 1); | 
 | 513 |     result += 1; | 
 | 514 |   } | 
 | 515 |   trans_->write((const uint8_t *)val.c_str(), val.length()); | 
 | 516 |   result += val.length(); | 
 | 517 |   if (escapeNum) { | 
 | 518 |     trans_->write(&kJSONStringDelimiter, 1); | 
 | 519 |     result += 1; | 
 | 520 |   } | 
 | 521 |   return result; | 
 | 522 | } | 
 | 523 |  | 
 | 524 | uint32_t TJSONProtocol::writeJSONObjectStart() { | 
 | 525 |   uint32_t result = context_->write(*trans_); | 
 | 526 |   trans_->write(&kJSONObjectStart, 1); | 
 | 527 |   pushContext(boost::shared_ptr<TJSONContext>(new JSONPairContext())); | 
 | 528 |   return result + 1; | 
 | 529 | } | 
 | 530 |  | 
 | 531 | uint32_t TJSONProtocol::writeJSONObjectEnd() { | 
 | 532 |   popContext(); | 
 | 533 |   trans_->write(&kJSONObjectEnd, 1); | 
 | 534 |   return 1; | 
 | 535 | } | 
 | 536 |  | 
 | 537 | uint32_t TJSONProtocol::writeJSONArrayStart() { | 
 | 538 |   uint32_t result = context_->write(*trans_); | 
 | 539 |   trans_->write(&kJSONArrayStart, 1); | 
 | 540 |   pushContext(boost::shared_ptr<TJSONContext>(new JSONListContext())); | 
 | 541 |   return result + 1; | 
 | 542 | } | 
 | 543 |  | 
 | 544 | uint32_t TJSONProtocol::writeJSONArrayEnd() { | 
 | 545 |   popContext(); | 
 | 546 |   trans_->write(&kJSONArrayEnd, 1); | 
 | 547 |   return 1; | 
 | 548 | } | 
 | 549 |  | 
 | 550 | uint32_t TJSONProtocol::writeMessageBegin(const std::string& name, | 
 | 551 |                                           const TMessageType messageType, | 
 | 552 |                                           const int32_t seqid) { | 
 | 553 |   uint32_t result = writeJSONArrayStart(); | 
 | 554 |   result += writeJSONInteger(kThriftVersion1); | 
 | 555 |   result += writeJSONString(name); | 
 | 556 |   result += writeJSONInteger(messageType); | 
 | 557 |   result += writeJSONInteger(seqid); | 
 | 558 |   return result; | 
 | 559 | } | 
 | 560 |  | 
 | 561 | uint32_t TJSONProtocol::writeMessageEnd() { | 
 | 562 |   return writeJSONArrayEnd(); | 
 | 563 | } | 
 | 564 |  | 
| David Reiss | 6412000 | 2008-04-29 23:12:24 +0000 | [diff] [blame] | 565 | uint32_t TJSONProtocol::writeStructBegin(const char* name) { | 
| Roger Meier | 3b771a1 | 2010-11-17 22:11:26 +0000 | [diff] [blame] | 566 |   (void) name; | 
| David Reiss | db0ea15 | 2008-02-18 01:49:37 +0000 | [diff] [blame] | 567 |   return writeJSONObjectStart(); | 
 | 568 | } | 
 | 569 |  | 
 | 570 | uint32_t TJSONProtocol::writeStructEnd() { | 
 | 571 |   return writeJSONObjectEnd(); | 
 | 572 | } | 
 | 573 |  | 
| David Reiss | 6412000 | 2008-04-29 23:12:24 +0000 | [diff] [blame] | 574 | uint32_t TJSONProtocol::writeFieldBegin(const char* name, | 
| David Reiss | db0ea15 | 2008-02-18 01:49:37 +0000 | [diff] [blame] | 575 |                                         const TType fieldType, | 
 | 576 |                                         const int16_t fieldId) { | 
| Roger Meier | 3b771a1 | 2010-11-17 22:11:26 +0000 | [diff] [blame] | 577 |   (void) name; | 
| David Reiss | db0ea15 | 2008-02-18 01:49:37 +0000 | [diff] [blame] | 578 |   uint32_t result = writeJSONInteger(fieldId); | 
 | 579 |   result += writeJSONObjectStart(); | 
 | 580 |   result += writeJSONString(getTypeNameForTypeID(fieldType)); | 
 | 581 |   return result; | 
 | 582 | } | 
 | 583 |  | 
 | 584 | uint32_t TJSONProtocol::writeFieldEnd() { | 
 | 585 |   return writeJSONObjectEnd(); | 
 | 586 | } | 
 | 587 |  | 
 | 588 | uint32_t TJSONProtocol::writeFieldStop() { | 
 | 589 |   return 0; | 
 | 590 | } | 
 | 591 |  | 
 | 592 | uint32_t TJSONProtocol::writeMapBegin(const TType keyType, | 
 | 593 |                                       const TType valType, | 
 | 594 |                                       const uint32_t size) { | 
 | 595 |   uint32_t result = writeJSONArrayStart(); | 
 | 596 |   result += writeJSONString(getTypeNameForTypeID(keyType)); | 
 | 597 |   result += writeJSONString(getTypeNameForTypeID(valType)); | 
 | 598 |   result += writeJSONInteger((int64_t)size); | 
 | 599 |   result += writeJSONObjectStart(); | 
 | 600 |   return result; | 
 | 601 | } | 
 | 602 |  | 
 | 603 | uint32_t TJSONProtocol::writeMapEnd() { | 
 | 604 |   return writeJSONObjectEnd() + writeJSONArrayEnd(); | 
 | 605 | } | 
 | 606 |  | 
 | 607 | uint32_t TJSONProtocol::writeListBegin(const TType elemType, | 
 | 608 |                                        const uint32_t size) { | 
 | 609 |   uint32_t result = writeJSONArrayStart(); | 
 | 610 |   result += writeJSONString(getTypeNameForTypeID(elemType)); | 
 | 611 |   result += writeJSONInteger((int64_t)size); | 
 | 612 |   return result; | 
 | 613 | } | 
 | 614 |  | 
 | 615 | uint32_t TJSONProtocol::writeListEnd() { | 
 | 616 |   return writeJSONArrayEnd(); | 
 | 617 | } | 
 | 618 |  | 
 | 619 | uint32_t TJSONProtocol::writeSetBegin(const TType elemType, | 
 | 620 |                                       const uint32_t size) { | 
 | 621 |   uint32_t result = writeJSONArrayStart(); | 
 | 622 |   result += writeJSONString(getTypeNameForTypeID(elemType)); | 
 | 623 |   result += writeJSONInteger((int64_t)size); | 
 | 624 |   return result; | 
 | 625 | } | 
 | 626 |  | 
 | 627 | uint32_t TJSONProtocol::writeSetEnd() { | 
 | 628 |   return writeJSONArrayEnd(); | 
 | 629 | } | 
 | 630 |  | 
 | 631 | uint32_t TJSONProtocol::writeBool(const bool value) { | 
 | 632 |   return writeJSONInteger(value); | 
 | 633 | } | 
 | 634 |  | 
 | 635 | uint32_t TJSONProtocol::writeByte(const int8_t byte) { | 
| David Reiss | 1e62ab4 | 2008-02-21 22:37:45 +0000 | [diff] [blame] | 636 |   // writeByte() must be handled specially becuase boost::lexical cast sees | 
| David Reiss | db0ea15 | 2008-02-18 01:49:37 +0000 | [diff] [blame] | 637 |   // int8_t as a text type instead of an integer type | 
 | 638 |   return writeJSONInteger((int16_t)byte); | 
 | 639 | } | 
 | 640 |  | 
 | 641 | uint32_t TJSONProtocol::writeI16(const int16_t i16) { | 
 | 642 |   return writeJSONInteger(i16); | 
 | 643 | } | 
 | 644 |  | 
 | 645 | uint32_t TJSONProtocol::writeI32(const int32_t i32) { | 
 | 646 |   return writeJSONInteger(i32); | 
 | 647 | } | 
 | 648 |  | 
 | 649 | uint32_t TJSONProtocol::writeI64(const int64_t i64) { | 
 | 650 |   return writeJSONInteger(i64); | 
 | 651 | } | 
 | 652 |  | 
 | 653 | uint32_t TJSONProtocol::writeDouble(const double dub) { | 
 | 654 |   return writeJSONDouble(dub); | 
 | 655 | } | 
 | 656 |  | 
 | 657 | uint32_t TJSONProtocol::writeString(const std::string& str) { | 
 | 658 |   return writeJSONString(str); | 
 | 659 | } | 
 | 660 |  | 
 | 661 | uint32_t TJSONProtocol::writeBinary(const std::string& str) { | 
 | 662 |   return writeJSONBase64(str); | 
 | 663 | } | 
 | 664 |  | 
 | 665 |   /** | 
 | 666 |    * Reading functions | 
 | 667 |    */ | 
 | 668 |  | 
| David Reiss | 1e62ab4 | 2008-02-21 22:37:45 +0000 | [diff] [blame] | 669 | // Reads 1 byte and verifies that it matches ch. | 
| David Reiss | db0ea15 | 2008-02-18 01:49:37 +0000 | [diff] [blame] | 670 | uint32_t TJSONProtocol::readJSONSyntaxChar(uint8_t ch) { | 
| David Reiss | 1e62ab4 | 2008-02-21 22:37:45 +0000 | [diff] [blame] | 671 |   return readSyntaxChar(reader_, ch); | 
| David Reiss | db0ea15 | 2008-02-18 01:49:37 +0000 | [diff] [blame] | 672 | } | 
 | 673 |  | 
 | 674 | // Decodes the four hex parts of a JSON escaped string character and returns | 
 | 675 | // the character via out. The first two characters must be "00". | 
 | 676 | uint32_t TJSONProtocol::readJSONEscapeChar(uint8_t *out) { | 
 | 677 |   uint8_t b[2]; | 
 | 678 |   readJSONSyntaxChar(kJSONZeroChar); | 
 | 679 |   readJSONSyntaxChar(kJSONZeroChar); | 
| David Reiss | 1e62ab4 | 2008-02-21 22:37:45 +0000 | [diff] [blame] | 680 |   b[0] = reader_.read(); | 
 | 681 |   b[1] = reader_.read(); | 
| David Reiss | db0ea15 | 2008-02-18 01:49:37 +0000 | [diff] [blame] | 682 |   *out = (hexVal(b[0]) << 4) + hexVal(b[1]); | 
 | 683 |   return 4; | 
 | 684 | } | 
 | 685 |  | 
 | 686 | // Decodes a JSON string, including unescaping, and returns the string via str | 
 | 687 | uint32_t TJSONProtocol::readJSONString(std::string &str, bool skipContext) { | 
| David Reiss | 1e62ab4 | 2008-02-21 22:37:45 +0000 | [diff] [blame] | 688 |   uint32_t result = (skipContext ? 0 : context_->read(reader_)); | 
| David Reiss | db0ea15 | 2008-02-18 01:49:37 +0000 | [diff] [blame] | 689 |   result += readJSONSyntaxChar(kJSONStringDelimiter); | 
| David Reiss | 1e62ab4 | 2008-02-21 22:37:45 +0000 | [diff] [blame] | 690 |   uint8_t ch; | 
| David Reiss | 9163073 | 2008-02-28 21:11:39 +0000 | [diff] [blame] | 691 |   str.clear(); | 
| David Reiss | db0ea15 | 2008-02-18 01:49:37 +0000 | [diff] [blame] | 692 |   while (true) { | 
| David Reiss | 1e62ab4 | 2008-02-21 22:37:45 +0000 | [diff] [blame] | 693 |     ch = reader_.read(); | 
 | 694 |     ++result; | 
 | 695 |     if (ch == kJSONStringDelimiter) { | 
| David Reiss | db0ea15 | 2008-02-18 01:49:37 +0000 | [diff] [blame] | 696 |       break; | 
 | 697 |     } | 
| David Reiss | 1e62ab4 | 2008-02-21 22:37:45 +0000 | [diff] [blame] | 698 |     if (ch == kJSONBackslash) { | 
 | 699 |       ch = reader_.read(); | 
 | 700 |       ++result; | 
 | 701 |       if (ch == kJSONEscapeChar) { | 
 | 702 |         result += readJSONEscapeChar(&ch); | 
| David Reiss | db0ea15 | 2008-02-18 01:49:37 +0000 | [diff] [blame] | 703 |       } | 
 | 704 |       else { | 
| David Reiss | 1e62ab4 | 2008-02-21 22:37:45 +0000 | [diff] [blame] | 705 |         size_t pos = kEscapeChars.find(ch); | 
| David Reiss | db0ea15 | 2008-02-18 01:49:37 +0000 | [diff] [blame] | 706 |         if (pos == std::string::npos) { | 
 | 707 |           throw TProtocolException(TProtocolException::INVALID_DATA, | 
 | 708 |                                    "Expected control char, got '" + | 
| David Reiss | 1e62ab4 | 2008-02-21 22:37:45 +0000 | [diff] [blame] | 709 |                                    std::string((const char *)&ch, 1)  + "'."); | 
| David Reiss | db0ea15 | 2008-02-18 01:49:37 +0000 | [diff] [blame] | 710 |         } | 
| David Reiss | 1e62ab4 | 2008-02-21 22:37:45 +0000 | [diff] [blame] | 711 |         ch = kEscapeCharVals[pos]; | 
| David Reiss | db0ea15 | 2008-02-18 01:49:37 +0000 | [diff] [blame] | 712 |       } | 
 | 713 |     } | 
| David Reiss | 1e62ab4 | 2008-02-21 22:37:45 +0000 | [diff] [blame] | 714 |     str += ch; | 
| David Reiss | db0ea15 | 2008-02-18 01:49:37 +0000 | [diff] [blame] | 715 |   } | 
 | 716 |   return result; | 
 | 717 | } | 
 | 718 |  | 
 | 719 | // Reads a block of base64 characters, decoding it, and returns via str | 
 | 720 | uint32_t TJSONProtocol::readJSONBase64(std::string &str) { | 
 | 721 |   std::string tmp; | 
 | 722 |   uint32_t result = readJSONString(tmp); | 
 | 723 |   uint8_t *b = (uint8_t *)tmp.c_str(); | 
 | 724 |   uint32_t len = tmp.length(); | 
| David Reiss | 9163073 | 2008-02-28 21:11:39 +0000 | [diff] [blame] | 725 |   str.clear(); | 
| David Reiss | db0ea15 | 2008-02-18 01:49:37 +0000 | [diff] [blame] | 726 |   while (len >= 4) { | 
 | 727 |     base64_decode(b, 4); | 
 | 728 |     str.append((const char *)b, 3); | 
 | 729 |     b += 4; | 
 | 730 |     len -= 4; | 
 | 731 |   } | 
 | 732 |   // Don't decode if we hit the end or got a single leftover byte (invalid | 
 | 733 |   // base64 but legal for skip of regular string type) | 
 | 734 |   if (len > 1) { | 
 | 735 |     base64_decode(b, len); | 
 | 736 |     str.append((const char *)b, len - 1); | 
 | 737 |   } | 
 | 738 |   return result; | 
 | 739 | } | 
 | 740 |  | 
 | 741 | // Reads a sequence of characters, stopping at the first one that is not | 
 | 742 | // a valid JSON numeric character. | 
 | 743 | uint32_t TJSONProtocol::readJSONNumericChars(std::string &str) { | 
 | 744 |   uint32_t result = 0; | 
| David Reiss | 9163073 | 2008-02-28 21:11:39 +0000 | [diff] [blame] | 745 |   str.clear(); | 
| David Reiss | db0ea15 | 2008-02-18 01:49:37 +0000 | [diff] [blame] | 746 |   while (true) { | 
| David Reiss | 1e62ab4 | 2008-02-21 22:37:45 +0000 | [diff] [blame] | 747 |     uint8_t ch = reader_.peek(); | 
| David Reiss | db0ea15 | 2008-02-18 01:49:37 +0000 | [diff] [blame] | 748 |     if (!isJSONNumeric(ch)) { | 
 | 749 |       break; | 
 | 750 |     } | 
| David Reiss | 1e62ab4 | 2008-02-21 22:37:45 +0000 | [diff] [blame] | 751 |     reader_.read(); | 
| David Reiss | db0ea15 | 2008-02-18 01:49:37 +0000 | [diff] [blame] | 752 |     str += ch; | 
 | 753 |     ++result; | 
 | 754 |   } | 
 | 755 |   return result; | 
 | 756 | } | 
 | 757 |  | 
 | 758 | // Reads a sequence of characters and assembles them into a number, | 
 | 759 | // returning them via num | 
 | 760 | template <typename NumberType> | 
 | 761 | uint32_t TJSONProtocol::readJSONInteger(NumberType &num) { | 
| David Reiss | 1e62ab4 | 2008-02-21 22:37:45 +0000 | [diff] [blame] | 762 |   uint32_t result = context_->read(reader_); | 
| David Reiss | db0ea15 | 2008-02-18 01:49:37 +0000 | [diff] [blame] | 763 |   if (context_->escapeNum()) { | 
 | 764 |     result += readJSONSyntaxChar(kJSONStringDelimiter); | 
 | 765 |   } | 
 | 766 |   std::string str; | 
 | 767 |   result += readJSONNumericChars(str); | 
 | 768 |   try { | 
 | 769 |     num = boost::lexical_cast<NumberType>(str); | 
 | 770 |   } | 
 | 771 |   catch (boost::bad_lexical_cast e) { | 
 | 772 |     throw new TProtocolException(TProtocolException::INVALID_DATA, | 
 | 773 |                                  "Expected numeric value; got \"" + str + | 
 | 774 |                                   "\""); | 
 | 775 |   } | 
 | 776 |   if (context_->escapeNum()) { | 
 | 777 |     result += readJSONSyntaxChar(kJSONStringDelimiter); | 
 | 778 |   } | 
 | 779 |   return result; | 
 | 780 | } | 
 | 781 |  | 
 | 782 | // Reads a JSON number or string and interprets it as a double. | 
 | 783 | uint32_t TJSONProtocol::readJSONDouble(double &num) { | 
| David Reiss | 1e62ab4 | 2008-02-21 22:37:45 +0000 | [diff] [blame] | 784 |   uint32_t result = context_->read(reader_); | 
| David Reiss | db0ea15 | 2008-02-18 01:49:37 +0000 | [diff] [blame] | 785 |   std::string str; | 
| David Reiss | 1e62ab4 | 2008-02-21 22:37:45 +0000 | [diff] [blame] | 786 |   if (reader_.peek() == kJSONStringDelimiter) { | 
| David Reiss | db0ea15 | 2008-02-18 01:49:37 +0000 | [diff] [blame] | 787 |     result += readJSONString(str, true); | 
 | 788 |     // Check for NaN, Infinity and -Infinity | 
 | 789 |     if (str == kThriftNan) { | 
 | 790 |       num = HUGE_VAL/HUGE_VAL; // generates NaN | 
 | 791 |     } | 
 | 792 |     else if (str == kThriftInfinity) { | 
 | 793 |       num = HUGE_VAL; | 
 | 794 |     } | 
 | 795 |     else if (str == kThriftNegativeInfinity) { | 
 | 796 |       num = -HUGE_VAL; | 
 | 797 |     } | 
 | 798 |     else { | 
 | 799 |       if (!context_->escapeNum()) { | 
 | 800 |         // Throw exception -- we should not be in a string in this case | 
 | 801 |         throw new TProtocolException(TProtocolException::INVALID_DATA, | 
 | 802 |                                      "Numeric data unexpectedly quoted"); | 
 | 803 |       } | 
 | 804 |       try { | 
 | 805 |         num = boost::lexical_cast<double>(str); | 
 | 806 |       } | 
 | 807 |       catch (boost::bad_lexical_cast e) { | 
 | 808 |         throw new TProtocolException(TProtocolException::INVALID_DATA, | 
 | 809 |                                      "Expected numeric value; got \"" + str + | 
 | 810 |                                      "\""); | 
 | 811 |       } | 
 | 812 |     } | 
 | 813 |   } | 
 | 814 |   else { | 
 | 815 |     if (context_->escapeNum()) { | 
 | 816 |       // This will throw - we should have had a quote if escapeNum == true | 
 | 817 |       readJSONSyntaxChar(kJSONStringDelimiter); | 
 | 818 |     } | 
 | 819 |     result += readJSONNumericChars(str); | 
 | 820 |     try { | 
 | 821 |       num = boost::lexical_cast<double>(str); | 
 | 822 |     } | 
 | 823 |     catch (boost::bad_lexical_cast e) { | 
 | 824 |       throw new TProtocolException(TProtocolException::INVALID_DATA, | 
 | 825 |                                    "Expected numeric value; got \"" + str + | 
 | 826 |                                    "\""); | 
 | 827 |     } | 
 | 828 |   } | 
 | 829 |   return result; | 
 | 830 | } | 
 | 831 |  | 
 | 832 | uint32_t TJSONProtocol::readJSONObjectStart() { | 
| David Reiss | 1e62ab4 | 2008-02-21 22:37:45 +0000 | [diff] [blame] | 833 |   uint32_t result = context_->read(reader_); | 
| David Reiss | db0ea15 | 2008-02-18 01:49:37 +0000 | [diff] [blame] | 834 |   result += readJSONSyntaxChar(kJSONObjectStart); | 
 | 835 |   pushContext(boost::shared_ptr<TJSONContext>(new JSONPairContext())); | 
 | 836 |   return result; | 
 | 837 | } | 
 | 838 |  | 
 | 839 | uint32_t TJSONProtocol::readJSONObjectEnd() { | 
 | 840 |   uint32_t result = readJSONSyntaxChar(kJSONObjectEnd); | 
 | 841 |   popContext(); | 
 | 842 |   return result; | 
 | 843 | } | 
 | 844 |  | 
 | 845 | uint32_t TJSONProtocol::readJSONArrayStart() { | 
| David Reiss | 1e62ab4 | 2008-02-21 22:37:45 +0000 | [diff] [blame] | 846 |   uint32_t result = context_->read(reader_); | 
| David Reiss | db0ea15 | 2008-02-18 01:49:37 +0000 | [diff] [blame] | 847 |   result += readJSONSyntaxChar(kJSONArrayStart); | 
 | 848 |   pushContext(boost::shared_ptr<TJSONContext>(new JSONListContext())); | 
 | 849 |   return result; | 
 | 850 | } | 
 | 851 |  | 
 | 852 | uint32_t TJSONProtocol::readJSONArrayEnd() { | 
 | 853 |   uint32_t result = readJSONSyntaxChar(kJSONArrayEnd); | 
 | 854 |   popContext(); | 
 | 855 |   return result; | 
 | 856 | } | 
 | 857 |  | 
 | 858 | uint32_t TJSONProtocol::readMessageBegin(std::string& name, | 
 | 859 |                                          TMessageType& messageType, | 
 | 860 |                                          int32_t& seqid) { | 
 | 861 |   uint32_t result = readJSONArrayStart(); | 
| David Reiss | db0ea15 | 2008-02-18 01:49:37 +0000 | [diff] [blame] | 862 |   uint64_t tmpVal = 0; | 
 | 863 |   result += readJSONInteger(tmpVal); | 
 | 864 |   if (tmpVal != kThriftVersion1) { | 
 | 865 |     throw TProtocolException(TProtocolException::BAD_VERSION, | 
 | 866 |                              "Message contained bad version."); | 
 | 867 |   } | 
 | 868 |   result += readJSONString(name); | 
 | 869 |   result += readJSONInteger(tmpVal); | 
 | 870 |   messageType = (TMessageType)tmpVal; | 
 | 871 |   result += readJSONInteger(tmpVal); | 
 | 872 |   seqid = tmpVal; | 
 | 873 |   return result; | 
 | 874 | } | 
 | 875 |  | 
 | 876 | uint32_t TJSONProtocol::readMessageEnd() { | 
 | 877 |   return readJSONArrayEnd(); | 
 | 878 | } | 
 | 879 |  | 
 | 880 | uint32_t TJSONProtocol::readStructBegin(std::string& name) { | 
| Roger Meier | 3b771a1 | 2010-11-17 22:11:26 +0000 | [diff] [blame] | 881 |   (void) name; | 
| David Reiss | db0ea15 | 2008-02-18 01:49:37 +0000 | [diff] [blame] | 882 |   return readJSONObjectStart(); | 
 | 883 | } | 
 | 884 |  | 
 | 885 | uint32_t TJSONProtocol::readStructEnd() { | 
 | 886 |   return readJSONObjectEnd(); | 
 | 887 | } | 
 | 888 |  | 
 | 889 | uint32_t TJSONProtocol::readFieldBegin(std::string& name, | 
 | 890 |                                        TType& fieldType, | 
 | 891 |                                        int16_t& fieldId) { | 
| Roger Meier | 3b771a1 | 2010-11-17 22:11:26 +0000 | [diff] [blame] | 892 |   (void) name; | 
| David Reiss | db0ea15 | 2008-02-18 01:49:37 +0000 | [diff] [blame] | 893 |   uint32_t result = 0; | 
| David Reiss | 1e62ab4 | 2008-02-21 22:37:45 +0000 | [diff] [blame] | 894 |   // Check if we hit the end of the list | 
 | 895 |   uint8_t ch = reader_.peek(); | 
 | 896 |   if (ch == kJSONObjectEnd) { | 
| T Jake Luciani | b5e6221 | 2009-01-31 22:36:20 +0000 | [diff] [blame] | 897 |     fieldType = apache::thrift::protocol::T_STOP; | 
| David Reiss | db0ea15 | 2008-02-18 01:49:37 +0000 | [diff] [blame] | 898 |   } | 
 | 899 |   else { | 
 | 900 |     uint64_t tmpVal = 0; | 
 | 901 |     std::string tmpStr; | 
 | 902 |     result += readJSONInteger(tmpVal); | 
 | 903 |     fieldId = tmpVal; | 
 | 904 |     result += readJSONObjectStart(); | 
 | 905 |     result += readJSONString(tmpStr); | 
 | 906 |     fieldType = getTypeIDForTypeName(tmpStr); | 
 | 907 |   } | 
 | 908 |   return result; | 
 | 909 | } | 
 | 910 |  | 
 | 911 | uint32_t TJSONProtocol::readFieldEnd() { | 
 | 912 |   return readJSONObjectEnd(); | 
 | 913 | } | 
 | 914 |  | 
 | 915 | uint32_t TJSONProtocol::readMapBegin(TType& keyType, | 
 | 916 |                                      TType& valType, | 
 | 917 |                                      uint32_t& size) { | 
 | 918 |   uint64_t tmpVal = 0; | 
 | 919 |   std::string tmpStr; | 
 | 920 |   uint32_t result = readJSONArrayStart(); | 
 | 921 |   result += readJSONString(tmpStr); | 
 | 922 |   keyType = getTypeIDForTypeName(tmpStr); | 
 | 923 |   result += readJSONString(tmpStr); | 
 | 924 |   valType = getTypeIDForTypeName(tmpStr); | 
 | 925 |   result += readJSONInteger(tmpVal); | 
 | 926 |   size = tmpVal; | 
 | 927 |   result += readJSONObjectStart(); | 
 | 928 |   return result; | 
 | 929 | } | 
 | 930 |  | 
 | 931 | uint32_t TJSONProtocol::readMapEnd() { | 
 | 932 |   return readJSONObjectEnd() + readJSONArrayEnd(); | 
 | 933 | } | 
 | 934 |  | 
 | 935 | uint32_t TJSONProtocol::readListBegin(TType& elemType, | 
 | 936 |                                       uint32_t& size) { | 
 | 937 |   uint64_t tmpVal = 0; | 
 | 938 |   std::string tmpStr; | 
 | 939 |   uint32_t result = readJSONArrayStart(); | 
 | 940 |   result += readJSONString(tmpStr); | 
 | 941 |   elemType = getTypeIDForTypeName(tmpStr); | 
 | 942 |   result += readJSONInteger(tmpVal); | 
 | 943 |   size = tmpVal; | 
 | 944 |   return result; | 
 | 945 | } | 
 | 946 |  | 
 | 947 | uint32_t TJSONProtocol::readListEnd() { | 
 | 948 |   return readJSONArrayEnd(); | 
 | 949 | } | 
 | 950 |  | 
 | 951 | uint32_t TJSONProtocol::readSetBegin(TType& elemType, | 
 | 952 |                                      uint32_t& size) { | 
 | 953 |   uint64_t tmpVal = 0; | 
 | 954 |   std::string tmpStr; | 
 | 955 |   uint32_t result = readJSONArrayStart(); | 
 | 956 |   result += readJSONString(tmpStr); | 
 | 957 |   elemType = getTypeIDForTypeName(tmpStr); | 
 | 958 |   result += readJSONInteger(tmpVal); | 
 | 959 |   size = tmpVal; | 
 | 960 |   return result; | 
 | 961 | } | 
 | 962 |  | 
 | 963 | uint32_t TJSONProtocol::readSetEnd() { | 
 | 964 |   return readJSONArrayEnd(); | 
 | 965 | } | 
 | 966 |  | 
 | 967 | uint32_t TJSONProtocol::readBool(bool& value) { | 
 | 968 |   return readJSONInteger(value); | 
 | 969 | } | 
 | 970 |  | 
 | 971 | // readByte() must be handled properly becuase boost::lexical cast sees int8_t | 
 | 972 | // as a text type instead of an integer type | 
 | 973 | uint32_t TJSONProtocol::readByte(int8_t& byte) { | 
 | 974 |   int16_t tmp = (int16_t) byte; | 
 | 975 |   uint32_t result =  readJSONInteger(tmp); | 
 | 976 |   assert(tmp < 256); | 
 | 977 |   byte = (int8_t)tmp; | 
 | 978 |   return result; | 
 | 979 | } | 
 | 980 |  | 
 | 981 | uint32_t TJSONProtocol::readI16(int16_t& i16) { | 
 | 982 |   return readJSONInteger(i16); | 
 | 983 | } | 
 | 984 |  | 
 | 985 | uint32_t TJSONProtocol::readI32(int32_t& i32) { | 
 | 986 |   return readJSONInteger(i32); | 
 | 987 | } | 
 | 988 |  | 
 | 989 | uint32_t TJSONProtocol::readI64(int64_t& i64) { | 
 | 990 |   return readJSONInteger(i64); | 
 | 991 | } | 
 | 992 |  | 
 | 993 | uint32_t TJSONProtocol::readDouble(double& dub) { | 
 | 994 |   return readJSONDouble(dub); | 
 | 995 | } | 
 | 996 |  | 
 | 997 | uint32_t TJSONProtocol::readString(std::string &str) { | 
 | 998 |   return readJSONString(str); | 
 | 999 | } | 
 | 1000 |  | 
 | 1001 | uint32_t TJSONProtocol::readBinary(std::string &str) { | 
 | 1002 |   return readJSONBase64(str); | 
 | 1003 | } | 
 | 1004 |  | 
| T Jake Luciani | b5e6221 | 2009-01-31 22:36:20 +0000 | [diff] [blame] | 1005 | }}} // apache::thrift::protocol |