blob: dbb2d4a40f720d33559881ded078723393ad93c5 [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 Reissce161a92007-09-11 22:09:42 +00007/*
8
9IMPLEMENTATION DETAILS
10
11TDenseProtocol was designed to have a smaller serialized form than
12TBinaryProtocol. This is accomplished using two techniques. The first is
13variable-length integer encoding. We use the same technique that the Standard
14MIDI File format uses for "variable-length quantities"
15(http://en.wikipedia.org/wiki/Variable-length_quantity).
16All integers (including i16, but not byte) are first cast to uint64_t,
17then written out as variable-length quantities. This has the unfortunate side
18effect that all negative numbers require 10 bytes, but negative numbers tend
19to be far less common than positive ones.
20
21The second technique eliminating the field ids used by TBinaryProtocol. This
22decision required support from the Thrift compiler and also sacrifices some of
23the backward and forward compatibility of TBinaryProtocol.
24
25We considered implementing this technique by generating separate readers and
26writers for the dense protocol (this is how Pillar, Thrift's predecessor,
27worked), but this idea had a few problems:
28- Our abstractions go out the window.
29- We would have to maintain a second code generator.
30- Preserving compatibility with old versions of the structures would be a
31 nightmare.
32
33Therefore, we chose an alternate implementation that stored the description of
34the data neither in the data itself (like TBinaryProtocol) nor in the
35serialization code (like Pillar), but instead in a separate data structure,
36called a TypeSpec. TypeSpecs are generated by the Thrift compiler
37(specifically in the t_cpp_generator), and their structure should be
38documented there (TODO(dreiss): s/should be/is/).
39
40We maintain a stack of TypeSpecs within the protocol so it knows where the
41generated code is in the reading/writing process. For example, if we are
42writing an i32 contained in a struct bar, contained in a struct foo, then the
43stack would look like: TOP , i32 , struct bar , struct foo , BOTTOM.
44The following invariant: whenever we are about to read/write an object
45(structBegin, containerBegin, or a scalar), the TypeSpec on the top of the
46stack must match the type being read/written. The main reasons that this
47invariant must be maintained is that if we ever start reading a structure, we
48must have its exact TypeSpec in order to pass the right tags to the
49deserializer.
50
51We use the following strategies for maintaining this invariant:
52
53- For structures, we have a separate stack of indexes, one for each structure
54 on the TypeSpec stack. These are indexes into the list of fields in the
55 structure's TypeSpec. When we {read,write}FieldBegin, we push on the
56 TypeSpec for the field.
57- When we begin writing a list or set, we push on the TypeSpec for the
58 element type.
59- For maps, we have a separate stack of booleans, one for each map on the
60 TypeSpec stack. The boolean is true if we are writing the key for that
61 map, and false if we are writing the value. Maps are the trickiest case
62 because the generated code does not call any protocol method between
63 the key and the value. As a result, we potentially have to switch
64 between map key state and map value state after reading/writing any object.
65- This job is handled by the stateTransition method. It is called after
66 reading/writing every object. It pops the current TypeSpec off the stack,
67 then optionally pushes a new one on, depending on what the next TypeSpec is.
68 If it is a struct, the job is left to the next writeFieldBegin. If it is a
69 set or list, the just-popped typespec is pushed back on. If it is a map,
70 the top of the key/value stack is toggled, and the appropriate TypeSpec
71 is pushed.
72
73Optional fields are a little tricky also. We write a zero byte if they are
74absent and prefix them with an 0x01 byte if they are present
75*/
76
David Reisse67c0e62007-09-07 01:34:12 +000077#define __STDC_LIMIT_MACROS
78#include <stdint.h>
David Reiss4e7530d2007-09-04 21:49:53 +000079#include "TDenseProtocol.h"
80#include "TReflectionLocal.h"
81
David Reissce161a92007-09-11 22:09:42 +000082// Leaving this on for now. Disabling it will turn off asserts, which should
83// give a performance boost. When we have *really* thorough test cases,
84// we should drop this.
David Reiss4e7530d2007-09-04 21:49:53 +000085#define DEBUG_TDENSEPROTOCOL
86
David Reissce161a92007-09-11 22:09:42 +000087// NOTE: Assertions should *only* be used to detect bugs in code,
88// either in TDenseProtocol itself, or in code using it.
89// (For example, using the wrong TypeSpec.)
90// Invalid data should NEVER cause an assertion failure,
91// no matter how grossly corrupted, nor how ingeniously crafted.
David Reiss4e7530d2007-09-04 21:49:53 +000092#ifdef DEBUG_TDENSEPROTOCOL
93#undef NDEBUG
David Reissce161a92007-09-11 22:09:42 +000094#else
95#define NDEBUG
David Reiss4e7530d2007-09-04 21:49:53 +000096#endif
97#include <cassert>
98
99using std::string;
100
David Reisse67c0e62007-09-07 01:34:12 +0000101#ifdef __GNUC__
102#define UNLIKELY(val) (__builtin_expect((val), 0))
103#else
104#define UNLIKELY(val) (val)
105#endif
106
David Reiss4e7530d2007-09-04 21:49:53 +0000107namespace facebook { namespace thrift { namespace protocol {
108
David Reissce161a92007-09-11 22:09:42 +0000109const int TDenseProtocol::FP_PREFIX_LEN =
110 facebook::thrift::reflection::local::FP_PREFIX_LEN;
111
David Reiss4e7530d2007-09-04 21:49:53 +0000112// Top TypeSpec. TypeSpec of the structure being encoded.
113#define TTS (ts_stack_.back()) // type = TypeSpec*
114// InDeX. Index into TTS of the current/next field to encode.
115#define IDX (idx_stack_.back()) // type = int
116// Field TypeSpec. TypeSpec of the current/next field to encode.
117#define FTS (TTS->tstruct.specs[IDX]) // type = TypeSpec*
118// Field MeTa. Metadata of the current/next field to encode.
119#define FMT (TTS->tstruct.metas[IDX]) // type = FieldMeta
120// SubType 1/2. TypeSpec of the first/second subtype of this container.
121#define ST1 (TTS->tcontainer.subtype1)
122#define ST2 (TTS->tcontainer.subtype2)
123
124
David Reissce161a92007-09-11 22:09:42 +0000125/**
126 * Checks that @c ttype is indeed the ttype that we should be writing,
127 * according to our typespec. Aborts if the test fails and debugging in on.
128 */
David Reiss4e7530d2007-09-04 21:49:53 +0000129inline void TDenseProtocol::checkTType(const TType ttype) {
130 assert(!ts_stack_.empty());
131 assert(TTS->ttype == ttype);
132}
133
David Reissce161a92007-09-11 22:09:42 +0000134/**
135 * Makes sure that the TypeSpec stack is correct for the next object.
136 * See top-of-file comments.
137 */
David Reiss4e7530d2007-09-04 21:49:53 +0000138inline void TDenseProtocol::stateTransition() {
139 TypeSpec* old_tts = ts_stack_.back();
140 ts_stack_.pop_back();
141
David Reissce161a92007-09-11 22:09:42 +0000142 // If this is the end of the top-level write, we should have just popped
143 // the TypeSpec passed to the constructor.
David Reiss4e7530d2007-09-04 21:49:53 +0000144 if (ts_stack_.empty()) {
145 assert(old_tts = type_spec_);
146 return;
147 }
148
149 switch (TTS->ttype) {
150
151 case T_STRUCT:
152 assert(old_tts == FTS);
153 break;
154
155 case T_LIST:
156 case T_SET:
157 assert(old_tts == ST1);
158 ts_stack_.push_back(old_tts);
159 break;
160
161 case T_MAP:
162 assert(old_tts == (mkv_stack_.back() ? ST1 : ST2));
163 mkv_stack_.back() = !mkv_stack_.back();
164 ts_stack_.push_back(mkv_stack_.back() ? ST1 : ST2);
165 break;
166
167 default:
168 assert(!"Invalid TType in stateTransition.");
169 break;
170
171 }
172}
173
David Reissce161a92007-09-11 22:09:42 +0000174
175/*
176 * Variable-length quantity functions.
177 */
178
179inline uint32_t TDenseProtocol::vlqRead(uint64_t& vlq) {
180 uint32_t used = 0;
181 uint64_t val = 0;
182 uint8_t buf[10]; // 64 bits / (7 bits/byte) = 10 bytes.
David Reissd46eb092008-02-02 00:54:48 +0000183 uint32_t buf_size = sizeof(buf);
184 const uint8_t* borrowed = trans_->borrow(buf, &buf_size);
David Reissce161a92007-09-11 22:09:42 +0000185
186 // Fast path. TODO(dreiss): Make it faster.
David Reissd46eb092008-02-02 00:54:48 +0000187 if (borrowed != NULL) {
David Reissce161a92007-09-11 22:09:42 +0000188 while (true) {
David Reissd46eb092008-02-02 00:54:48 +0000189 uint8_t byte = borrowed[used];
David Reissce161a92007-09-11 22:09:42 +0000190 used++;
191 val = (val << 7) | (byte & 0x7f);
192 if (!(byte & 0x80)) {
193 vlq = val;
194 trans_->consume(used);
195 return used;
196 }
197 // Have to check for invalid data so we don't crash.
198 if (UNLIKELY(used == sizeof(buf))) {
199 resetState();
200 throw TProtocolException(TProtocolException::INVALID_DATA, "Variable-length int over 10 bytes.");
201 }
202 }
203 }
204
205 // Slow path.
206 else {
207 while (true) {
208 uint8_t byte;
209 used += trans_->readAll(&byte, 1);
210 val = (val << 7) | (byte & 0x7f);
211 if (!(byte & 0x80)) {
212 vlq = val;
213 return used;
214 }
215 // Might as well check for invalid data on the slow path too.
216 if (UNLIKELY(used >= sizeof(buf))) {
217 resetState();
218 throw TProtocolException(TProtocolException::INVALID_DATA, "Variable-length int over 10 bytes.");
219 }
220 }
221 }
222}
223
224inline uint32_t TDenseProtocol::vlqWrite(uint64_t vlq) {
225 uint8_t buf[10]; // 64 bits / (7 bits/byte) = 10 bytes.
226 int32_t pos = sizeof(buf) - 1;
227
228 // Write the thing from back to front.
229 buf[pos] = vlq & 0x7f;
230 vlq >>= 7;
231 pos--;
232
233 while (vlq > 0) {
234 assert(pos >= 0);
235 buf[pos] = (vlq | 0x80);
236 vlq >>= 7;
237 pos--;
238 }
239
240 // Back up one step before writing.
241 pos++;
242
243 trans_->write(buf+pos, sizeof(buf) - pos);
244 return sizeof(buf) - pos;
245}
246
247
248
249/*
250 * Writing functions.
251 */
252
David Reiss4e7530d2007-09-04 21:49:53 +0000253uint32_t TDenseProtocol::writeMessageBegin(const std::string& name,
254 const TMessageType messageType,
255 const int32_t seqid) {
David Reisse67c0e62007-09-07 01:34:12 +0000256 throw TApplicationException("TDenseProtocol doesn't work with messages (yet).");
257
David Reiss4e7530d2007-09-04 21:49:53 +0000258 int32_t version = (VERSION_2) | ((int32_t)messageType);
259 uint32_t wsize = 0;
260 wsize += subWriteI32(version);
261 wsize += subWriteString(name);
262 wsize += subWriteI32(seqid);
263 return wsize;
264}
265
266uint32_t TDenseProtocol::writeMessageEnd() {
267 return 0;
268}
269
David Reiss4e7530d2007-09-04 21:49:53 +0000270uint32_t TDenseProtocol::writeStructBegin(const string& name) {
David Reissce161a92007-09-11 22:09:42 +0000271 uint32_t xfer = 0;
272
273 // The TypeSpec stack should be empty if this is the top-level read/write.
274 // If it is, we push the TypeSpec passed to the constructor.
David Reiss4e7530d2007-09-04 21:49:53 +0000275 if (ts_stack_.empty()) {
David Reissce161a92007-09-11 22:09:42 +0000276 assert(standalone_);
277
David Reiss4e7530d2007-09-04 21:49:53 +0000278 if (type_spec_ == NULL) {
David Reissce161a92007-09-11 22:09:42 +0000279 resetState();
David Reiss4e7530d2007-09-04 21:49:53 +0000280 throw TApplicationException("TDenseProtocol: No type specified.");
281 } else {
David Reissce161a92007-09-11 22:09:42 +0000282 assert(type_spec_->ttype == T_STRUCT);
David Reiss4e7530d2007-09-04 21:49:53 +0000283 ts_stack_.push_back(type_spec_);
David Reissce161a92007-09-11 22:09:42 +0000284 // Write out a prefix of the structure fingerprint.
285 trans_->write(type_spec_->fp_prefix, FP_PREFIX_LEN);
286 xfer += FP_PREFIX_LEN;
David Reiss4e7530d2007-09-04 21:49:53 +0000287 }
288 }
289
David Reissce161a92007-09-11 22:09:42 +0000290 // We need a new field index for this structure.
David Reiss4e7530d2007-09-04 21:49:53 +0000291 idx_stack_.push_back(0);
292 return 0;
293}
294
295uint32_t TDenseProtocol::writeStructEnd() {
296 idx_stack_.pop_back();
297 stateTransition();
298 return 0;
299}
300
301uint32_t TDenseProtocol::writeFieldBegin(const string& name,
302 const TType fieldType,
303 const int16_t fieldId) {
304 uint32_t xfer = 0;
305
David Reissce161a92007-09-11 22:09:42 +0000306 // Skip over optional fields.
David Reiss4e7530d2007-09-04 21:49:53 +0000307 while (FMT.tag != fieldId) {
308 // TODO(dreiss): Old meta here.
309 assert(FTS->ttype != T_STOP);
310 assert(FMT.is_optional);
David Reissce161a92007-09-11 22:09:42 +0000311 // Write a zero byte so the reader can skip it.
David Reiss4e7530d2007-09-04 21:49:53 +0000312 xfer += subWriteBool(false);
David Reissce161a92007-09-11 22:09:42 +0000313 // And advance to the next field.
David Reiss4e7530d2007-09-04 21:49:53 +0000314 IDX++;
315 }
316
317 // TODO(dreiss): give a better exception.
318 assert(FTS->ttype == fieldType);
319
320 if (FMT.is_optional) {
321 subWriteBool(true);
322 xfer += 1;
323 }
324
David Reissce161a92007-09-11 22:09:42 +0000325 // writeFieldStop shares all lot of logic up to this point.
326 // Instead of replicating it all, we just call this method from that one
327 // and use a gross special case here.
328 if (UNLIKELY(FTS->ttype != T_STOP)) {
329 // For normal fields, push the TypeSpec that we're about to use.
David Reiss4e7530d2007-09-04 21:49:53 +0000330 ts_stack_.push_back(FTS);
331 }
332 return xfer;
333}
334
335uint32_t TDenseProtocol::writeFieldEnd() {
David Reissce161a92007-09-11 22:09:42 +0000336 // Just move on to the next field.
David Reiss4e7530d2007-09-04 21:49:53 +0000337 IDX++;
338 return 0;
339}
340
341uint32_t TDenseProtocol::writeFieldStop() {
David Reissce161a92007-09-11 22:09:42 +0000342 return TDenseProtocol::writeFieldBegin("", T_STOP, 0);
David Reiss4e7530d2007-09-04 21:49:53 +0000343}
344
345uint32_t TDenseProtocol::writeMapBegin(const TType keyType,
346 const TType valType,
347 const uint32_t size) {
348 checkTType(T_MAP);
349
350 assert(keyType == ST1->ttype);
351 assert(valType == ST2->ttype);
352
353 ts_stack_.push_back(ST1);
354 mkv_stack_.push_back(true);
355
356 return subWriteI32((int32_t)size);
357}
358
359uint32_t TDenseProtocol::writeMapEnd() {
David Reissce161a92007-09-11 22:09:42 +0000360 // Pop off the value type, as well as our entry in the map key/value stack.
361 // stateTransition takes care of popping off our TypeSpec.
David Reiss4e7530d2007-09-04 21:49:53 +0000362 ts_stack_.pop_back();
363 mkv_stack_.pop_back();
364 stateTransition();
365 return 0;
366}
367
368uint32_t TDenseProtocol::writeListBegin(const TType elemType,
369 const uint32_t size) {
370 checkTType(T_LIST);
371
372 assert(elemType == ST1->ttype);
373 ts_stack_.push_back(ST1);
374 return subWriteI32((int32_t)size);
375}
376
377uint32_t TDenseProtocol::writeListEnd() {
David Reissce161a92007-09-11 22:09:42 +0000378 // Pop off the element type. stateTransition takes care of popping off ours.
David Reiss4e7530d2007-09-04 21:49:53 +0000379 ts_stack_.pop_back();
380 stateTransition();
381 return 0;
382}
383
384uint32_t TDenseProtocol::writeSetBegin(const TType elemType,
385 const uint32_t size) {
386 checkTType(T_SET);
387
388 assert(elemType == ST1->ttype);
389 ts_stack_.push_back(ST1);
390 return subWriteI32((int32_t)size);
391}
392
393uint32_t TDenseProtocol::writeSetEnd() {
David Reissce161a92007-09-11 22:09:42 +0000394 // Pop off the element type. stateTransition takes care of popping off ours.
David Reiss4e7530d2007-09-04 21:49:53 +0000395 ts_stack_.pop_back();
396 stateTransition();
397 return 0;
398}
399
400uint32_t TDenseProtocol::writeBool(const bool value) {
401 checkTType(T_BOOL);
402 stateTransition();
403 return TBinaryProtocol::writeBool(value);
404}
405
406uint32_t TDenseProtocol::writeByte(const int8_t byte) {
407 checkTType(T_BYTE);
408 stateTransition();
409 return TBinaryProtocol::writeByte(byte);
410}
411
David Reiss4e7530d2007-09-04 21:49:53 +0000412uint32_t TDenseProtocol::writeI16(const int16_t i16) {
David Reiss4e7530d2007-09-04 21:49:53 +0000413 checkTType(T_I16);
414 stateTransition();
David Reissce161a92007-09-11 22:09:42 +0000415 return vlqWrite(i16);
David Reiss4e7530d2007-09-04 21:49:53 +0000416}
417
418uint32_t TDenseProtocol::writeI32(const int32_t i32) {
David Reiss4e7530d2007-09-04 21:49:53 +0000419 checkTType(T_I32);
420 stateTransition();
David Reissce161a92007-09-11 22:09:42 +0000421 return vlqWrite(i32);
David Reiss4e7530d2007-09-04 21:49:53 +0000422}
423
424uint32_t TDenseProtocol::writeI64(const int64_t i64) {
David Reiss4e7530d2007-09-04 21:49:53 +0000425 checkTType(T_I64);
426 stateTransition();
David Reissce161a92007-09-11 22:09:42 +0000427 return vlqWrite(i64);
David Reiss4e7530d2007-09-04 21:49:53 +0000428}
429
430uint32_t TDenseProtocol::writeDouble(const double dub) {
431 checkTType(T_DOUBLE);
432 stateTransition();
433 return TBinaryProtocol::writeDouble(dub);
434}
435
436uint32_t TDenseProtocol::writeString(const std::string& str) {
437 checkTType(T_STRING);
438 stateTransition();
439 return subWriteString(str);
440}
441
David Reissc005b1b2008-02-15 01:38:18 +0000442uint32_t TDenseProtocol::writeBinary(const std::string& str) {
443 return TDenseProtocol::writeString(str);
444}
445
David Reiss4e7530d2007-09-04 21:49:53 +0000446inline uint32_t TDenseProtocol::subWriteI32(const int32_t i32) {
David Reissce161a92007-09-11 22:09:42 +0000447 return vlqWrite(i32);
David Reiss4e7530d2007-09-04 21:49:53 +0000448}
449
David Reiss4e7530d2007-09-04 21:49:53 +0000450uint32_t TDenseProtocol::subWriteString(const std::string& str) {
451 uint32_t size = str.size();
452 uint32_t xfer = subWriteI32((int32_t)size);
453 if (size > 0) {
454 trans_->write((uint8_t*)str.data(), size);
455 }
456 return xfer + size;
457}
458
David Reisse67c0e62007-09-07 01:34:12 +0000459
David Reisse67c0e62007-09-07 01:34:12 +0000460
David Reissce161a92007-09-11 22:09:42 +0000461/*
David Reiss4e7530d2007-09-04 21:49:53 +0000462 * Reading functions
David Reissce161a92007-09-11 22:09:42 +0000463 *
464 * These have a lot of the same logic as the writing functions, so if
465 * something is confusing, look for comments in the corresponding writer.
David Reiss4e7530d2007-09-04 21:49:53 +0000466 */
467
468uint32_t TDenseProtocol::readMessageBegin(std::string& name,
469 TMessageType& messageType,
470 int32_t& seqid) {
David Reisse67c0e62007-09-07 01:34:12 +0000471 throw TApplicationException("TDenseProtocol doesn't work with messages (yet).");
472
David Reiss4e7530d2007-09-04 21:49:53 +0000473 uint32_t xfer = 0;
474 int32_t sz;
475 xfer += subReadI32(sz);
476
477 if (sz < 0) {
478 // Check for correct version number
479 int32_t version = sz & VERSION_MASK;
480 if (version != VERSION_2) {
481 throw TProtocolException(TProtocolException::BAD_VERSION, "Bad version identifier");
482 }
483 messageType = (TMessageType)(sz & 0x000000ff);
484 xfer += subReadString(name);
485 xfer += subReadI32(seqid);
486 } else {
487 throw TProtocolException(TProtocolException::BAD_VERSION, "No version identifier... old protocol client in strict mode?");
488 }
489 return xfer;
490}
491
492uint32_t TDenseProtocol::readMessageEnd() {
493 return 0;
494}
495
496uint32_t TDenseProtocol::readStructBegin(string& name) {
David Reissce161a92007-09-11 22:09:42 +0000497 uint32_t xfer = 0;
498
499 if (ts_stack_.empty()) {
500 assert(standalone_);
501
502 if (type_spec_ == NULL) {
503 resetState();
504 throw TApplicationException("TDenseProtocol: No type specified.");
505 } else {
506 assert(type_spec_->ttype == T_STRUCT);
507 ts_stack_.push_back(type_spec_);
508
509 // Check the fingerprint prefix.
510 uint8_t buf[FP_PREFIX_LEN];
511 xfer += trans_->read(buf, FP_PREFIX_LEN);
512 if (std::memcmp(buf, type_spec_->fp_prefix, FP_PREFIX_LEN) != 0) {
513 resetState();
514 throw TProtocolException(TProtocolException::INVALID_DATA,
515 "Fingerprint in data does not match type_spec.");
516 }
517 }
518 }
519
520 // We need a new field index for this structure.
521 idx_stack_.push_back(0);
522 return 0;
David Reiss4e7530d2007-09-04 21:49:53 +0000523}
524
525uint32_t TDenseProtocol::readStructEnd() {
526 idx_stack_.pop_back();
527 stateTransition();
528 return 0;
529}
530
531uint32_t TDenseProtocol::readFieldBegin(string& name,
532 TType& fieldType,
533 int16_t& fieldId) {
534 uint32_t xfer = 0;
535
David Reissce161a92007-09-11 22:09:42 +0000536 // For optional fields, check to see if they are there.
David Reiss4e7530d2007-09-04 21:49:53 +0000537 while (FMT.is_optional) {
538 bool is_present;
539 xfer += subReadBool(is_present);
540 if (is_present) {
541 break;
542 }
543 IDX++;
544 }
545
David Reissce161a92007-09-11 22:09:42 +0000546 // Once we hit a mandatory field, or an optional field that is present,
547 // we know that FMT and FTS point to the appropriate field.
548
David Reiss4e7530d2007-09-04 21:49:53 +0000549 fieldId = FMT.tag;
550 fieldType = FTS->ttype;
551
David Reissce161a92007-09-11 22:09:42 +0000552 // Normally, we push the TypeSpec that we are about to read,
553 // but no reading is done for T_STOP.
David Reiss4e7530d2007-09-04 21:49:53 +0000554 if (FTS->ttype != T_STOP) {
555 ts_stack_.push_back(FTS);
556 }
557 return xfer;
558}
559
560uint32_t TDenseProtocol::readFieldEnd() {
561 IDX++;
562 return 0;
563}
564
565uint32_t TDenseProtocol::readMapBegin(TType& keyType,
566 TType& valType,
567 uint32_t& size) {
568 checkTType(T_MAP);
569
570 uint32_t xfer = 0;
571 int32_t sizei;
572 xfer += subReadI32(sizei);
573 if (sizei < 0) {
David Reissce161a92007-09-11 22:09:42 +0000574 resetState();
David Reiss4e7530d2007-09-04 21:49:53 +0000575 throw TProtocolException(TProtocolException::NEGATIVE_SIZE);
576 } else if (container_limit_ && sizei > container_limit_) {
David Reissce161a92007-09-11 22:09:42 +0000577 resetState();
David Reiss4e7530d2007-09-04 21:49:53 +0000578 throw TProtocolException(TProtocolException::SIZE_LIMIT);
579 }
580 size = (uint32_t)sizei;
581
582 keyType = ST1->ttype;
583 valType = ST2->ttype;
584
585 ts_stack_.push_back(ST1);
586 mkv_stack_.push_back(true);
587
588 return xfer;
589}
590
591uint32_t TDenseProtocol::readMapEnd() {
592 ts_stack_.pop_back();
593 mkv_stack_.pop_back();
594 stateTransition();
595 return 0;
596}
597
598uint32_t TDenseProtocol::readListBegin(TType& elemType,
599 uint32_t& size) {
600 checkTType(T_LIST);
601
602 uint32_t xfer = 0;
603 int32_t sizei;
604 xfer += subReadI32(sizei);
605 if (sizei < 0) {
David Reissce161a92007-09-11 22:09:42 +0000606 resetState();
David Reiss4e7530d2007-09-04 21:49:53 +0000607 throw TProtocolException(TProtocolException::NEGATIVE_SIZE);
608 } else if (container_limit_ && sizei > container_limit_) {
David Reissce161a92007-09-11 22:09:42 +0000609 resetState();
David Reiss4e7530d2007-09-04 21:49:53 +0000610 throw TProtocolException(TProtocolException::SIZE_LIMIT);
611 }
612 size = (uint32_t)sizei;
613
614 elemType = ST1->ttype;
615
616 ts_stack_.push_back(ST1);
617
618 return xfer;
619}
620
621uint32_t TDenseProtocol::readListEnd() {
622 ts_stack_.pop_back();
623 stateTransition();
624 return 0;
625}
626
627uint32_t TDenseProtocol::readSetBegin(TType& elemType,
628 uint32_t& size) {
629 checkTType(T_SET);
630
631 uint32_t xfer = 0;
632 int32_t sizei;
633 xfer += subReadI32(sizei);
634 if (sizei < 0) {
David Reissce161a92007-09-11 22:09:42 +0000635 resetState();
David Reiss4e7530d2007-09-04 21:49:53 +0000636 throw TProtocolException(TProtocolException::NEGATIVE_SIZE);
637 } else if (container_limit_ && sizei > container_limit_) {
David Reissce161a92007-09-11 22:09:42 +0000638 resetState();
David Reiss4e7530d2007-09-04 21:49:53 +0000639 throw TProtocolException(TProtocolException::SIZE_LIMIT);
640 }
641 size = (uint32_t)sizei;
642
643 elemType = ST1->ttype;
644
645 ts_stack_.push_back(ST1);
646
647 return xfer;
648}
649
650uint32_t TDenseProtocol::readSetEnd() {
651 ts_stack_.pop_back();
652 stateTransition();
653 return 0;
654}
655
656uint32_t TDenseProtocol::readBool(bool& value) {
657 checkTType(T_BOOL);
658 stateTransition();
659 return TBinaryProtocol::readBool(value);
660}
661
662uint32_t TDenseProtocol::readByte(int8_t& byte) {
663 checkTType(T_BYTE);
664 stateTransition();
665 return TBinaryProtocol::readByte(byte);
666}
667
668uint32_t TDenseProtocol::readI16(int16_t& i16) {
669 checkTType(T_I16);
670 stateTransition();
David Reisse67c0e62007-09-07 01:34:12 +0000671 uint64_t u64;
David Reissce161a92007-09-11 22:09:42 +0000672 uint32_t rv = vlqRead(u64);
David Reisse67c0e62007-09-07 01:34:12 +0000673 int64_t val = (int64_t)u64;
674 if (UNLIKELY(val > INT16_MAX || val < INT16_MIN)) {
David Reissce161a92007-09-11 22:09:42 +0000675 resetState();
David Reisse67c0e62007-09-07 01:34:12 +0000676 throw TProtocolException(TProtocolException::INVALID_DATA,
677 "i16 out of range.");
678 }
679 i16 = (int16_t)val;
680 return rv;
David Reiss4e7530d2007-09-04 21:49:53 +0000681}
682
683uint32_t TDenseProtocol::readI32(int32_t& i32) {
684 checkTType(T_I32);
685 stateTransition();
David Reisse67c0e62007-09-07 01:34:12 +0000686 uint64_t u64;
David Reissce161a92007-09-11 22:09:42 +0000687 uint32_t rv = vlqRead(u64);
David Reisse67c0e62007-09-07 01:34:12 +0000688 int64_t val = (int64_t)u64;
689 if (UNLIKELY(val > INT32_MAX || val < INT32_MIN)) {
David Reissce161a92007-09-11 22:09:42 +0000690 resetState();
David Reisse67c0e62007-09-07 01:34:12 +0000691 throw TProtocolException(TProtocolException::INVALID_DATA,
692 "i32 out of range.");
693 }
694 i32 = (int32_t)val;
695 return rv;
David Reiss4e7530d2007-09-04 21:49:53 +0000696}
697
698uint32_t TDenseProtocol::readI64(int64_t& i64) {
699 checkTType(T_I64);
700 stateTransition();
David Reisse67c0e62007-09-07 01:34:12 +0000701 uint64_t u64;
David Reissce161a92007-09-11 22:09:42 +0000702 uint32_t rv = vlqRead(u64);
David Reisse67c0e62007-09-07 01:34:12 +0000703 int64_t val = (int64_t)u64;
704 if (UNLIKELY(val > INT64_MAX || val < INT64_MIN)) {
David Reissce161a92007-09-11 22:09:42 +0000705 resetState();
David Reisse67c0e62007-09-07 01:34:12 +0000706 throw TProtocolException(TProtocolException::INVALID_DATA,
707 "i64 out of range.");
708 }
709 i64 = (int64_t)val;
710 return rv;
David Reiss4e7530d2007-09-04 21:49:53 +0000711}
712
713uint32_t TDenseProtocol::readDouble(double& dub) {
714 checkTType(T_DOUBLE);
715 stateTransition();
716 return TBinaryProtocol::readDouble(dub);
717}
718
719uint32_t TDenseProtocol::readString(std::string& str) {
720 checkTType(T_STRING);
721 stateTransition();
722 return subReadString(str);
723}
724
David Reissc005b1b2008-02-15 01:38:18 +0000725uint32_t TDenseProtocol::readBinary(std::string& str) {
726 return TDenseProtocol::readString(str);
727}
728
David Reisse67c0e62007-09-07 01:34:12 +0000729uint32_t TDenseProtocol::subReadI32(int32_t& i32) {
730 uint64_t u64;
David Reissce161a92007-09-11 22:09:42 +0000731 uint32_t rv = vlqRead(u64);
David Reisse67c0e62007-09-07 01:34:12 +0000732 int64_t val = (int64_t)u64;
733 if (UNLIKELY(val > INT32_MAX || val < INT32_MIN)) {
David Reissce161a92007-09-11 22:09:42 +0000734 resetState();
David Reisse67c0e62007-09-07 01:34:12 +0000735 throw TProtocolException(TProtocolException::INVALID_DATA,
736 "i32 out of range.");
737 }
738 i32 = (int32_t)val;
739 return rv;
740}
741
742uint32_t TDenseProtocol::subReadString(std::string& str) {
743 uint32_t xfer;
744 int32_t size;
745 xfer = subReadI32(size);
746 return xfer + readStringBody(str, size);
747}
748
David Reiss4e7530d2007-09-04 21:49:53 +0000749}}} // facebook::thrift::protocol