blob: 99117d6479f5feefc1a566cf9a64b8a4cbe21984 [file] [log] [blame]
David Reiss4e7530d2007-09-04 21:49:53 +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
David Reisse67c0e62007-09-07 01:34:12 +00007#define __STDC_LIMIT_MACROS
8#include <stdint.h>
David Reiss4e7530d2007-09-04 21:49:53 +00009#include "TDenseProtocol.h"
10#include "TReflectionLocal.h"
11
12// XXX for debugging (duh)
13#define DEBUG_TDENSEPROTOCOL
14
David Reisse67c0e62007-09-07 01:34:12 +000015// XXX for development.
16#define TDENSE_PROTOCOL_MEASURE_VLI
17
David Reiss4e7530d2007-09-04 21:49:53 +000018// The XXX above does not apply to this.
19#ifdef DEBUG_TDENSEPROTOCOL
20#undef NDEBUG
21#endif
22#include <cassert>
23
24using std::string;
25
David Reisse67c0e62007-09-07 01:34:12 +000026#ifdef __GNUC__
27#define UNLIKELY(val) (__builtin_expect((val), 0))
28#else
29#define UNLIKELY(val) (val)
30#endif
31
David Reiss4e7530d2007-09-04 21:49:53 +000032namespace facebook { namespace thrift { namespace protocol {
33
34// Top TypeSpec. TypeSpec of the structure being encoded.
35#define TTS (ts_stack_.back()) // type = TypeSpec*
36// InDeX. Index into TTS of the current/next field to encode.
37#define IDX (idx_stack_.back()) // type = int
38// Field TypeSpec. TypeSpec of the current/next field to encode.
39#define FTS (TTS->tstruct.specs[IDX]) // type = TypeSpec*
40// Field MeTa. Metadata of the current/next field to encode.
41#define FMT (TTS->tstruct.metas[IDX]) // type = FieldMeta
42// SubType 1/2. TypeSpec of the first/second subtype of this container.
43#define ST1 (TTS->tcontainer.subtype1)
44#define ST2 (TTS->tcontainer.subtype2)
45
46
47inline void TDenseProtocol::checkTType(const TType ttype) {
48 assert(!ts_stack_.empty());
49 assert(TTS->ttype == ttype);
50}
51
52inline void TDenseProtocol::stateTransition() {
53 TypeSpec* old_tts = ts_stack_.back();
54 ts_stack_.pop_back();
55
56 if (ts_stack_.empty()) {
57 assert(old_tts = type_spec_);
58 return;
59 }
60
61 switch (TTS->ttype) {
62
63 case T_STRUCT:
64 assert(old_tts == FTS);
65 break;
66
67 case T_LIST:
68 case T_SET:
69 assert(old_tts == ST1);
70 ts_stack_.push_back(old_tts);
71 break;
72
73 case T_MAP:
74 assert(old_tts == (mkv_stack_.back() ? ST1 : ST2));
75 mkv_stack_.back() = !mkv_stack_.back();
76 ts_stack_.push_back(mkv_stack_.back() ? ST1 : ST2);
77 break;
78
79 default:
80 assert(!"Invalid TType in stateTransition.");
81 break;
82
83 }
84}
85
86uint32_t TDenseProtocol::writeMessageBegin(const std::string& name,
87 const TMessageType messageType,
88 const int32_t seqid) {
David Reisse67c0e62007-09-07 01:34:12 +000089 throw TApplicationException("TDenseProtocol doesn't work with messages (yet).");
90
David Reiss4e7530d2007-09-04 21:49:53 +000091 int32_t version = (VERSION_2) | ((int32_t)messageType);
92 uint32_t wsize = 0;
93 wsize += subWriteI32(version);
94 wsize += subWriteString(name);
95 wsize += subWriteI32(seqid);
96 return wsize;
97}
98
99uint32_t TDenseProtocol::writeMessageEnd() {
100 return 0;
101}
102
103// Also implements readStructBegin.
104uint32_t TDenseProtocol::writeStructBegin(const string& name) {
105 if (ts_stack_.empty()) {
106 if (type_spec_ == NULL) {
107 throw TApplicationException("TDenseProtocol: No type specified.");
108 } else {
109 ts_stack_.push_back(type_spec_);
110 }
111 }
112
113 idx_stack_.push_back(0);
114 return 0;
115}
116
117uint32_t TDenseProtocol::writeStructEnd() {
118 idx_stack_.pop_back();
119 stateTransition();
120 return 0;
121}
122
123uint32_t TDenseProtocol::writeFieldBegin(const string& name,
124 const TType fieldType,
125 const int16_t fieldId) {
126 uint32_t xfer = 0;
127
128 while (FMT.tag != fieldId) {
129 // TODO(dreiss): Old meta here.
130 assert(FTS->ttype != T_STOP);
131 assert(FMT.is_optional);
132 xfer += subWriteBool(false);
133 IDX++;
134 }
135
136 // TODO(dreiss): give a better exception.
137 assert(FTS->ttype == fieldType);
138
139 if (FMT.is_optional) {
140 subWriteBool(true);
141 xfer += 1;
142 }
143
144 // OMG I'm so gross. XXX
145 if (FTS->ttype != T_STOP) {
146 ts_stack_.push_back(FTS);
147 }
148 return xfer;
149}
150
151uint32_t TDenseProtocol::writeFieldEnd() {
152 IDX++;
153 return 0;
154}
155
156uint32_t TDenseProtocol::writeFieldStop() {
157 return writeFieldBegin("", T_STOP, 0);
158}
159
160uint32_t TDenseProtocol::writeMapBegin(const TType keyType,
161 const TType valType,
162 const uint32_t size) {
163 checkTType(T_MAP);
164
165 assert(keyType == ST1->ttype);
166 assert(valType == ST2->ttype);
167
168 ts_stack_.push_back(ST1);
169 mkv_stack_.push_back(true);
170
171 return subWriteI32((int32_t)size);
172}
173
174uint32_t TDenseProtocol::writeMapEnd() {
175 ts_stack_.pop_back();
176 mkv_stack_.pop_back();
177 stateTransition();
178 return 0;
179}
180
181uint32_t TDenseProtocol::writeListBegin(const TType elemType,
182 const uint32_t size) {
183 checkTType(T_LIST);
184
185 assert(elemType == ST1->ttype);
186 ts_stack_.push_back(ST1);
187 return subWriteI32((int32_t)size);
188}
189
190uint32_t TDenseProtocol::writeListEnd() {
191 ts_stack_.pop_back();
192 stateTransition();
193 return 0;
194}
195
196uint32_t TDenseProtocol::writeSetBegin(const TType elemType,
197 const uint32_t size) {
198 checkTType(T_SET);
199
200 assert(elemType == ST1->ttype);
201 ts_stack_.push_back(ST1);
202 return subWriteI32((int32_t)size);
203}
204
205uint32_t TDenseProtocol::writeSetEnd() {
206 ts_stack_.pop_back();
207 stateTransition();
208 return 0;
209}
210
211uint32_t TDenseProtocol::writeBool(const bool value) {
212 checkTType(T_BOOL);
213 stateTransition();
214 return TBinaryProtocol::writeBool(value);
215}
216
217uint32_t TDenseProtocol::writeByte(const int8_t byte) {
218 checkTType(T_BYTE);
219 stateTransition();
220 return TBinaryProtocol::writeByte(byte);
221}
222
David Reiss4e7530d2007-09-04 21:49:53 +0000223uint32_t TDenseProtocol::writeI16(const int16_t i16) {
David Reiss4e7530d2007-09-04 21:49:53 +0000224 checkTType(T_I16);
225 stateTransition();
David Reisse67c0e62007-09-07 01:34:12 +0000226
227 uint32_t rv = vliWrite(i16);
228#ifdef TDENSE_PROTOCOL_MEASURE_VLI
229 vli_save_16 += 2 - rv;
230 if (i16 < 0) {
231 negs++;
232 }
233#endif
234
235 return rv;
David Reiss4e7530d2007-09-04 21:49:53 +0000236}
237
238uint32_t TDenseProtocol::writeI32(const int32_t i32) {
David Reiss4e7530d2007-09-04 21:49:53 +0000239 checkTType(T_I32);
240 stateTransition();
David Reisse67c0e62007-09-07 01:34:12 +0000241
242 uint32_t rv = vliWrite(i32);
243#ifdef TDENSE_PROTOCOL_MEASURE_VLI
244 vli_save_32 += 4 - rv;
245 if (i32 < 0) {
246 negs++;
247 }
248#endif
249
250 return rv;
David Reiss4e7530d2007-09-04 21:49:53 +0000251}
252
253uint32_t TDenseProtocol::writeI64(const int64_t i64) {
David Reiss4e7530d2007-09-04 21:49:53 +0000254 checkTType(T_I64);
255 stateTransition();
David Reisse67c0e62007-09-07 01:34:12 +0000256
257 uint32_t rv = vliWrite(i64);
258#ifdef TDENSE_PROTOCOL_MEASURE_VLI
259 vli_save_64 += 8 - rv;
260 if (i64 < 0) {
261 negs++;
262 }
263#endif
264
265 return rv;
David Reiss4e7530d2007-09-04 21:49:53 +0000266}
267
268uint32_t TDenseProtocol::writeDouble(const double dub) {
269 checkTType(T_DOUBLE);
270 stateTransition();
271 return TBinaryProtocol::writeDouble(dub);
272}
273
274uint32_t TDenseProtocol::writeString(const std::string& str) {
275 checkTType(T_STRING);
276 stateTransition();
277 return subWriteString(str);
278}
279
David Reiss4e7530d2007-09-04 21:49:53 +0000280inline uint32_t TDenseProtocol::subWriteI32(const int32_t i32) {
David Reisse67c0e62007-09-07 01:34:12 +0000281 uint32_t rv = vliWrite(i32);
282#ifdef TDENSE_PROTOCOL_MEASURE_VLI
283 vli_save_sub += 4 - rv;
284 if (i32 < 0) {
285 negs++;
286 }
287#endif
288 return rv;
David Reiss4e7530d2007-09-04 21:49:53 +0000289}
290
David Reiss4e7530d2007-09-04 21:49:53 +0000291uint32_t TDenseProtocol::subWriteString(const std::string& str) {
292 uint32_t size = str.size();
293 uint32_t xfer = subWriteI32((int32_t)size);
294 if (size > 0) {
295 trans_->write((uint8_t*)str.data(), size);
296 }
297 return xfer + size;
298}
299
David Reisse67c0e62007-09-07 01:34:12 +0000300inline uint32_t TDenseProtocol::vliRead(uint64_t& vli) {
301 uint32_t used = 0;
302 uint64_t val = 0;
303 uint8_t buf[10]; // 64 bits / (7 bits/byte) = 10 bytes.
304 bool borrowed = trans_->borrow(buf, sizeof(buf));
305
306 // Fast path. TODO(dreiss): Make it faster.
307 if (borrowed) {
308 while (true) {
309 uint8_t byte = buf[used];
310 used++;
311 val = (val << 7) | (byte & 0x7f);
312 if (!(byte & 0x80)) {
313 vli = val;
314 trans_->consume(used);
315 return used;
316 }
317 // Have to check for invalid data so we don't crash.
318 if (UNLIKELY(used == sizeof(buf))) {
319 throw TProtocolException(TProtocolException::INVALID_DATA, "Variable-length int over 10 bytes.");
320 }
321 }
322 }
323
324 // Slow path.
325 else {
326 while (true) {
327 uint8_t byte;
328 used += trans_->readAll(&byte, 1);
329 val = (val << 7) | (byte & 0x7f);
330 if (!(byte & 0x80)) {
331 vli = val;
332 return used;
333 }
334 // Might as well check for invalid data on the slow path too.
335 if (UNLIKELY(used >= sizeof(buf))) {
336 throw TProtocolException(TProtocolException::INVALID_DATA, "Variable-length int over 10 bytes.");
337 }
338 }
339 }
340}
341
342inline uint32_t TDenseProtocol::vliWrite(uint64_t vli) {
343 uint8_t buf[10]; // 64 bits / (7 bits/byte) = 10 bytes.
344 int32_t pos = sizeof(buf) - 1;
345
346 // Write the thing from back to front.
347 buf[pos] = vli & 0x7f;
348 vli >>= 7;
349 pos--;
350
351 while (vli > 0) {
352 assert(pos >= 0);
353 buf[pos] = (vli | 0x80);
354 vli >>= 7;
355 pos--;
356 }
357
358 // Back up one step before writing.
359 pos++;
360
361 trans_->write(buf+pos, sizeof(buf) - pos);
362 return sizeof(buf) - pos;
363}
David Reiss4e7530d2007-09-04 21:49:53 +0000364
365/**
366 * Reading functions
367 */
368
369uint32_t TDenseProtocol::readMessageBegin(std::string& name,
370 TMessageType& messageType,
371 int32_t& seqid) {
David Reisse67c0e62007-09-07 01:34:12 +0000372 throw TApplicationException("TDenseProtocol doesn't work with messages (yet).");
373
David Reiss4e7530d2007-09-04 21:49:53 +0000374 uint32_t xfer = 0;
375 int32_t sz;
376 xfer += subReadI32(sz);
377
378 if (sz < 0) {
379 // Check for correct version number
380 int32_t version = sz & VERSION_MASK;
381 if (version != VERSION_2) {
382 throw TProtocolException(TProtocolException::BAD_VERSION, "Bad version identifier");
383 }
384 messageType = (TMessageType)(sz & 0x000000ff);
385 xfer += subReadString(name);
386 xfer += subReadI32(seqid);
387 } else {
388 throw TProtocolException(TProtocolException::BAD_VERSION, "No version identifier... old protocol client in strict mode?");
389 }
390 return xfer;
391}
392
393uint32_t TDenseProtocol::readMessageEnd() {
394 return 0;
395}
396
397uint32_t TDenseProtocol::readStructBegin(string& name) {
398 // TODO(dreiss): Any chance this gets inlined?
399 return TDenseProtocol::writeStructBegin(name);
400}
401
402uint32_t TDenseProtocol::readStructEnd() {
403 idx_stack_.pop_back();
404 stateTransition();
405 return 0;
406}
407
408uint32_t TDenseProtocol::readFieldBegin(string& name,
409 TType& fieldType,
410 int16_t& fieldId) {
411 uint32_t xfer = 0;
412
413 while (FMT.is_optional) {
414 bool is_present;
415 xfer += subReadBool(is_present);
416 if (is_present) {
417 break;
418 }
419 IDX++;
420 }
421
422 fieldId = FMT.tag;
423 fieldType = FTS->ttype;
424
425 // OMG I'm so gross. XXX
426 if (FTS->ttype != T_STOP) {
427 ts_stack_.push_back(FTS);
428 }
429 return xfer;
430}
431
432uint32_t TDenseProtocol::readFieldEnd() {
433 IDX++;
434 return 0;
435}
436
437uint32_t TDenseProtocol::readMapBegin(TType& keyType,
438 TType& valType,
439 uint32_t& size) {
440 checkTType(T_MAP);
441
442 uint32_t xfer = 0;
443 int32_t sizei;
444 xfer += subReadI32(sizei);
445 if (sizei < 0) {
446 throw TProtocolException(TProtocolException::NEGATIVE_SIZE);
447 } else if (container_limit_ && sizei > container_limit_) {
448 throw TProtocolException(TProtocolException::SIZE_LIMIT);
449 }
450 size = (uint32_t)sizei;
451
452 keyType = ST1->ttype;
453 valType = ST2->ttype;
454
455 ts_stack_.push_back(ST1);
456 mkv_stack_.push_back(true);
457
458 return xfer;
459}
460
461uint32_t TDenseProtocol::readMapEnd() {
462 ts_stack_.pop_back();
463 mkv_stack_.pop_back();
464 stateTransition();
465 return 0;
466}
467
468uint32_t TDenseProtocol::readListBegin(TType& elemType,
469 uint32_t& size) {
470 checkTType(T_LIST);
471
472 uint32_t xfer = 0;
473 int32_t sizei;
474 xfer += subReadI32(sizei);
475 if (sizei < 0) {
476 throw TProtocolException(TProtocolException::NEGATIVE_SIZE);
477 } else if (container_limit_ && sizei > container_limit_) {
478 throw TProtocolException(TProtocolException::SIZE_LIMIT);
479 }
480 size = (uint32_t)sizei;
481
482 elemType = ST1->ttype;
483
484 ts_stack_.push_back(ST1);
485
486 return xfer;
487}
488
489uint32_t TDenseProtocol::readListEnd() {
490 ts_stack_.pop_back();
491 stateTransition();
492 return 0;
493}
494
495uint32_t TDenseProtocol::readSetBegin(TType& elemType,
496 uint32_t& size) {
497 checkTType(T_SET);
498
499 uint32_t xfer = 0;
500 int32_t sizei;
501 xfer += subReadI32(sizei);
502 if (sizei < 0) {
503 throw TProtocolException(TProtocolException::NEGATIVE_SIZE);
504 } else if (container_limit_ && sizei > container_limit_) {
505 throw TProtocolException(TProtocolException::SIZE_LIMIT);
506 }
507 size = (uint32_t)sizei;
508
509 elemType = ST1->ttype;
510
511 ts_stack_.push_back(ST1);
512
513 return xfer;
514}
515
516uint32_t TDenseProtocol::readSetEnd() {
517 ts_stack_.pop_back();
518 stateTransition();
519 return 0;
520}
521
522uint32_t TDenseProtocol::readBool(bool& value) {
523 checkTType(T_BOOL);
524 stateTransition();
525 return TBinaryProtocol::readBool(value);
526}
527
528uint32_t TDenseProtocol::readByte(int8_t& byte) {
529 checkTType(T_BYTE);
530 stateTransition();
531 return TBinaryProtocol::readByte(byte);
532}
533
534uint32_t TDenseProtocol::readI16(int16_t& i16) {
535 checkTType(T_I16);
536 stateTransition();
David Reisse67c0e62007-09-07 01:34:12 +0000537 uint64_t u64;
538 uint32_t rv = vliRead(u64);
539 int64_t val = (int64_t)u64;
540 if (UNLIKELY(val > INT16_MAX || val < INT16_MIN)) {
541 throw TProtocolException(TProtocolException::INVALID_DATA,
542 "i16 out of range.");
543 }
544 i16 = (int16_t)val;
545 return rv;
David Reiss4e7530d2007-09-04 21:49:53 +0000546}
547
548uint32_t TDenseProtocol::readI32(int32_t& i32) {
549 checkTType(T_I32);
550 stateTransition();
David Reisse67c0e62007-09-07 01:34:12 +0000551 uint64_t u64;
552 uint32_t rv = vliRead(u64);
553 int64_t val = (int64_t)u64;
554 if (UNLIKELY(val > INT32_MAX || val < INT32_MIN)) {
555 throw TProtocolException(TProtocolException::INVALID_DATA,
556 "i32 out of range.");
557 }
558 i32 = (int32_t)val;
559 return rv;
David Reiss4e7530d2007-09-04 21:49:53 +0000560}
561
562uint32_t TDenseProtocol::readI64(int64_t& i64) {
563 checkTType(T_I64);
564 stateTransition();
David Reisse67c0e62007-09-07 01:34:12 +0000565 uint64_t u64;
566 uint32_t rv = vliRead(u64);
567 int64_t val = (int64_t)u64;
568 if (UNLIKELY(val > INT64_MAX || val < INT64_MIN)) {
569 throw TProtocolException(TProtocolException::INVALID_DATA,
570 "i64 out of range.");
571 }
572 i64 = (int64_t)val;
573 return rv;
David Reiss4e7530d2007-09-04 21:49:53 +0000574}
575
576uint32_t TDenseProtocol::readDouble(double& dub) {
577 checkTType(T_DOUBLE);
578 stateTransition();
579 return TBinaryProtocol::readDouble(dub);
580}
581
582uint32_t TDenseProtocol::readString(std::string& str) {
583 checkTType(T_STRING);
584 stateTransition();
585 return subReadString(str);
586}
587
David Reisse67c0e62007-09-07 01:34:12 +0000588uint32_t TDenseProtocol::subReadI32(int32_t& i32) {
589 uint64_t u64;
590 uint32_t rv = vliRead(u64);
591 int64_t val = (int64_t)u64;
592 if (UNLIKELY(val > INT32_MAX || val < INT32_MIN)) {
593 throw TProtocolException(TProtocolException::INVALID_DATA,
594 "i32 out of range.");
595 }
596 i32 = (int32_t)val;
597 return rv;
598}
599
600uint32_t TDenseProtocol::subReadString(std::string& str) {
601 uint32_t xfer;
602 int32_t size;
603 xfer = subReadI32(size);
604 return xfer + readStringBody(str, size);
605}
606
David Reiss4e7530d2007-09-04 21:49:53 +0000607}}} // facebook::thrift::protocol