blob: 4fbfc1338cf63206c870fdfe90f9b8f7f477615c [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 Reiss4e7530d2007-09-04 21:49:53 +000019
David Reissce161a92007-09-11 22:09:42 +000020/*
21
22IMPLEMENTATION DETAILS
23
24TDenseProtocol was designed to have a smaller serialized form than
25TBinaryProtocol. This is accomplished using two techniques. The first is
26variable-length integer encoding. We use the same technique that the Standard
27MIDI File format uses for "variable-length quantities"
28(http://en.wikipedia.org/wiki/Variable-length_quantity).
29All integers (including i16, but not byte) are first cast to uint64_t,
30then written out as variable-length quantities. This has the unfortunate side
31effect that all negative numbers require 10 bytes, but negative numbers tend
32to be far less common than positive ones.
33
34The second technique eliminating the field ids used by TBinaryProtocol. This
35decision required support from the Thrift compiler and also sacrifices some of
36the backward and forward compatibility of TBinaryProtocol.
37
38We considered implementing this technique by generating separate readers and
39writers for the dense protocol (this is how Pillar, Thrift's predecessor,
40worked), but this idea had a few problems:
41- Our abstractions go out the window.
42- We would have to maintain a second code generator.
43- Preserving compatibility with old versions of the structures would be a
44 nightmare.
45
46Therefore, we chose an alternate implementation that stored the description of
47the data neither in the data itself (like TBinaryProtocol) nor in the
48serialization code (like Pillar), but instead in a separate data structure,
49called a TypeSpec. TypeSpecs are generated by the Thrift compiler
50(specifically in the t_cpp_generator), and their structure should be
51documented there (TODO(dreiss): s/should be/is/).
52
53We maintain a stack of TypeSpecs within the protocol so it knows where the
54generated code is in the reading/writing process. For example, if we are
55writing an i32 contained in a struct bar, contained in a struct foo, then the
56stack would look like: TOP , i32 , struct bar , struct foo , BOTTOM.
57The following invariant: whenever we are about to read/write an object
58(structBegin, containerBegin, or a scalar), the TypeSpec on the top of the
59stack must match the type being read/written. The main reasons that this
60invariant must be maintained is that if we ever start reading a structure, we
61must have its exact TypeSpec in order to pass the right tags to the
62deserializer.
63
64We use the following strategies for maintaining this invariant:
65
66- For structures, we have a separate stack of indexes, one for each structure
67 on the TypeSpec stack. These are indexes into the list of fields in the
68 structure's TypeSpec. When we {read,write}FieldBegin, we push on the
69 TypeSpec for the field.
70- When we begin writing a list or set, we push on the TypeSpec for the
71 element type.
72- For maps, we have a separate stack of booleans, one for each map on the
73 TypeSpec stack. The boolean is true if we are writing the key for that
74 map, and false if we are writing the value. Maps are the trickiest case
75 because the generated code does not call any protocol method between
76 the key and the value. As a result, we potentially have to switch
77 between map key state and map value state after reading/writing any object.
78- This job is handled by the stateTransition method. It is called after
79 reading/writing every object. It pops the current TypeSpec off the stack,
80 then optionally pushes a new one on, depending on what the next TypeSpec is.
81 If it is a struct, the job is left to the next writeFieldBegin. If it is a
82 set or list, the just-popped typespec is pushed back on. If it is a map,
83 the top of the key/value stack is toggled, and the appropriate TypeSpec
84 is pushed.
85
86Optional fields are a little tricky also. We write a zero byte if they are
87absent and prefix them with an 0x01 byte if they are present
88*/
89
David Reisse67c0e62007-09-07 01:34:12 +000090#define __STDC_LIMIT_MACROS
91#include <stdint.h>
Roger Meier2badac72012-04-14 11:03:43 +000092#include <thrift/protocol/TDenseProtocol.h>
93#include <thrift/TReflectionLocal.h>
David Reiss4e7530d2007-09-04 21:49:53 +000094
David Reissce161a92007-09-11 22:09:42 +000095// Leaving this on for now. Disabling it will turn off asserts, which should
96// give a performance boost. When we have *really* thorough test cases,
97// we should drop this.
David Reiss4e7530d2007-09-04 21:49:53 +000098#define DEBUG_TDENSEPROTOCOL
99
David Reissce161a92007-09-11 22:09:42 +0000100// NOTE: Assertions should *only* be used to detect bugs in code,
101// either in TDenseProtocol itself, or in code using it.
102// (For example, using the wrong TypeSpec.)
103// Invalid data should NEVER cause an assertion failure,
104// no matter how grossly corrupted, nor how ingeniously crafted.
David Reiss4e7530d2007-09-04 21:49:53 +0000105#ifdef DEBUG_TDENSEPROTOCOL
106#undef NDEBUG
David Reissce161a92007-09-11 22:09:42 +0000107#else
108#define NDEBUG
David Reiss4e7530d2007-09-04 21:49:53 +0000109#endif
110#include <cassert>
111
112using std::string;
113
David Reisse67c0e62007-09-07 01:34:12 +0000114#ifdef __GNUC__
115#define UNLIKELY(val) (__builtin_expect((val), 0))
116#else
117#define UNLIKELY(val) (val)
118#endif
119
T Jake Lucianib5e62212009-01-31 22:36:20 +0000120namespace apache { namespace thrift { namespace protocol {
David Reiss4e7530d2007-09-04 21:49:53 +0000121
David Reissce161a92007-09-11 22:09:42 +0000122const int TDenseProtocol::FP_PREFIX_LEN =
T Jake Lucianib5e62212009-01-31 22:36:20 +0000123 apache::thrift::reflection::local::FP_PREFIX_LEN;
David Reissce161a92007-09-11 22:09:42 +0000124
David Reiss4e7530d2007-09-04 21:49:53 +0000125// Top TypeSpec. TypeSpec of the structure being encoded.
126#define TTS (ts_stack_.back()) // type = TypeSpec*
127// InDeX. Index into TTS of the current/next field to encode.
128#define IDX (idx_stack_.back()) // type = int
129// Field TypeSpec. TypeSpec of the current/next field to encode.
130#define FTS (TTS->tstruct.specs[IDX]) // type = TypeSpec*
131// Field MeTa. Metadata of the current/next field to encode.
132#define FMT (TTS->tstruct.metas[IDX]) // type = FieldMeta
133// SubType 1/2. TypeSpec of the first/second subtype of this container.
134#define ST1 (TTS->tcontainer.subtype1)
135#define ST2 (TTS->tcontainer.subtype2)
136
137
David Reissce161a92007-09-11 22:09:42 +0000138/**
139 * Checks that @c ttype is indeed the ttype that we should be writing,
140 * according to our typespec. Aborts if the test fails and debugging in on.
141 */
David Reiss4e7530d2007-09-04 21:49:53 +0000142inline void TDenseProtocol::checkTType(const TType ttype) {
143 assert(!ts_stack_.empty());
144 assert(TTS->ttype == ttype);
145}
146
David Reissce161a92007-09-11 22:09:42 +0000147/**
148 * Makes sure that the TypeSpec stack is correct for the next object.
149 * See top-of-file comments.
150 */
David Reiss4e7530d2007-09-04 21:49:53 +0000151inline void TDenseProtocol::stateTransition() {
152 TypeSpec* old_tts = ts_stack_.back();
153 ts_stack_.pop_back();
154
David Reissce161a92007-09-11 22:09:42 +0000155 // If this is the end of the top-level write, we should have just popped
156 // the TypeSpec passed to the constructor.
David Reiss4e7530d2007-09-04 21:49:53 +0000157 if (ts_stack_.empty()) {
158 assert(old_tts = type_spec_);
159 return;
160 }
161
162 switch (TTS->ttype) {
163
164 case T_STRUCT:
165 assert(old_tts == FTS);
166 break;
167
168 case T_LIST:
169 case T_SET:
170 assert(old_tts == ST1);
171 ts_stack_.push_back(old_tts);
172 break;
173
174 case T_MAP:
175 assert(old_tts == (mkv_stack_.back() ? ST1 : ST2));
176 mkv_stack_.back() = !mkv_stack_.back();
177 ts_stack_.push_back(mkv_stack_.back() ? ST1 : ST2);
178 break;
179
180 default:
181 assert(!"Invalid TType in stateTransition.");
182 break;
183
184 }
185}
186
David Reissce161a92007-09-11 22:09:42 +0000187
188/*
189 * Variable-length quantity functions.
190 */
191
192inline uint32_t TDenseProtocol::vlqRead(uint64_t& vlq) {
193 uint32_t used = 0;
194 uint64_t val = 0;
195 uint8_t buf[10]; // 64 bits / (7 bits/byte) = 10 bytes.
David Reissd46eb092008-02-02 00:54:48 +0000196 uint32_t buf_size = sizeof(buf);
197 const uint8_t* borrowed = trans_->borrow(buf, &buf_size);
David Reissce161a92007-09-11 22:09:42 +0000198
199 // Fast path. TODO(dreiss): Make it faster.
David Reissd46eb092008-02-02 00:54:48 +0000200 if (borrowed != NULL) {
David Reissce161a92007-09-11 22:09:42 +0000201 while (true) {
David Reissd46eb092008-02-02 00:54:48 +0000202 uint8_t byte = borrowed[used];
David Reissce161a92007-09-11 22:09:42 +0000203 used++;
204 val = (val << 7) | (byte & 0x7f);
205 if (!(byte & 0x80)) {
206 vlq = val;
207 trans_->consume(used);
208 return used;
209 }
210 // Have to check for invalid data so we don't crash.
211 if (UNLIKELY(used == sizeof(buf))) {
212 resetState();
213 throw TProtocolException(TProtocolException::INVALID_DATA, "Variable-length int over 10 bytes.");
214 }
215 }
216 }
217
218 // Slow path.
219 else {
220 while (true) {
221 uint8_t byte;
222 used += trans_->readAll(&byte, 1);
223 val = (val << 7) | (byte & 0x7f);
224 if (!(byte & 0x80)) {
225 vlq = val;
226 return used;
227 }
228 // Might as well check for invalid data on the slow path too.
229 if (UNLIKELY(used >= sizeof(buf))) {
230 resetState();
231 throw TProtocolException(TProtocolException::INVALID_DATA, "Variable-length int over 10 bytes.");
232 }
233 }
234 }
235}
236
237inline uint32_t TDenseProtocol::vlqWrite(uint64_t vlq) {
238 uint8_t buf[10]; // 64 bits / (7 bits/byte) = 10 bytes.
239 int32_t pos = sizeof(buf) - 1;
240
241 // Write the thing from back to front.
242 buf[pos] = vlq & 0x7f;
243 vlq >>= 7;
244 pos--;
245
246 while (vlq > 0) {
247 assert(pos >= 0);
Roger Meierb69d24d2012-10-04 18:02:15 +0000248 buf[pos] = static_cast<uint8_t>(vlq | 0x80);
David Reissce161a92007-09-11 22:09:42 +0000249 vlq >>= 7;
250 pos--;
251 }
252
253 // Back up one step before writing.
254 pos++;
255
Roger Meier82525772012-11-16 00:38:27 +0000256 trans_->write(buf+pos, static_cast<uint32_t>(sizeof(buf) - pos));
257 return static_cast<uint32_t>(sizeof(buf) - pos);
David Reissce161a92007-09-11 22:09:42 +0000258}
259
260
261
262/*
263 * Writing functions.
264 */
265
David Reiss4e7530d2007-09-04 21:49:53 +0000266uint32_t TDenseProtocol::writeMessageBegin(const std::string& name,
267 const TMessageType messageType,
268 const int32_t seqid) {
David Reissac110e42010-03-09 05:20:07 +0000269 throw TException("TDenseProtocol doesn't work with messages (yet).");
David Reisse67c0e62007-09-07 01:34:12 +0000270
David Reiss4e7530d2007-09-04 21:49:53 +0000271 int32_t version = (VERSION_2) | ((int32_t)messageType);
272 uint32_t wsize = 0;
273 wsize += subWriteI32(version);
274 wsize += subWriteString(name);
275 wsize += subWriteI32(seqid);
276 return wsize;
277}
278
279uint32_t TDenseProtocol::writeMessageEnd() {
280 return 0;
281}
282
David Reiss64120002008-04-29 23:12:24 +0000283uint32_t TDenseProtocol::writeStructBegin(const char* name) {
Roger Meier3b771a12010-11-17 22:11:26 +0000284 (void) name;
David Reissce161a92007-09-11 22:09:42 +0000285 uint32_t xfer = 0;
286
287 // The TypeSpec stack should be empty if this is the top-level read/write.
288 // If it is, we push the TypeSpec passed to the constructor.
David Reiss4e7530d2007-09-04 21:49:53 +0000289 if (ts_stack_.empty()) {
David Reissce161a92007-09-11 22:09:42 +0000290 assert(standalone_);
291
David Reiss4e7530d2007-09-04 21:49:53 +0000292 if (type_spec_ == NULL) {
David Reissce161a92007-09-11 22:09:42 +0000293 resetState();
David Reissac110e42010-03-09 05:20:07 +0000294 throw TException("TDenseProtocol: No type specified.");
David Reiss4e7530d2007-09-04 21:49:53 +0000295 } else {
David Reissce161a92007-09-11 22:09:42 +0000296 assert(type_spec_->ttype == T_STRUCT);
David Reiss4e7530d2007-09-04 21:49:53 +0000297 ts_stack_.push_back(type_spec_);
David Reissce161a92007-09-11 22:09:42 +0000298 // Write out a prefix of the structure fingerprint.
299 trans_->write(type_spec_->fp_prefix, FP_PREFIX_LEN);
300 xfer += FP_PREFIX_LEN;
David Reiss4e7530d2007-09-04 21:49:53 +0000301 }
302 }
303
David Reissce161a92007-09-11 22:09:42 +0000304 // We need a new field index for this structure.
David Reiss4e7530d2007-09-04 21:49:53 +0000305 idx_stack_.push_back(0);
306 return 0;
307}
308
309uint32_t TDenseProtocol::writeStructEnd() {
310 idx_stack_.pop_back();
311 stateTransition();
312 return 0;
313}
314
David Reiss64120002008-04-29 23:12:24 +0000315uint32_t TDenseProtocol::writeFieldBegin(const char* name,
David Reiss4e7530d2007-09-04 21:49:53 +0000316 const TType fieldType,
317 const int16_t fieldId) {
Roger Meier3b771a12010-11-17 22:11:26 +0000318 (void) name;
David Reiss4e7530d2007-09-04 21:49:53 +0000319 uint32_t xfer = 0;
320
David Reissce161a92007-09-11 22:09:42 +0000321 // Skip over optional fields.
David Reiss4e7530d2007-09-04 21:49:53 +0000322 while (FMT.tag != fieldId) {
323 // TODO(dreiss): Old meta here.
324 assert(FTS->ttype != T_STOP);
325 assert(FMT.is_optional);
David Reissce161a92007-09-11 22:09:42 +0000326 // Write a zero byte so the reader can skip it.
David Reiss4e7530d2007-09-04 21:49:53 +0000327 xfer += subWriteBool(false);
David Reissce161a92007-09-11 22:09:42 +0000328 // And advance to the next field.
David Reiss4e7530d2007-09-04 21:49:53 +0000329 IDX++;
330 }
331
332 // TODO(dreiss): give a better exception.
333 assert(FTS->ttype == fieldType);
334
335 if (FMT.is_optional) {
336 subWriteBool(true);
337 xfer += 1;
338 }
339
David Reissce161a92007-09-11 22:09:42 +0000340 // writeFieldStop shares all lot of logic up to this point.
341 // Instead of replicating it all, we just call this method from that one
342 // and use a gross special case here.
343 if (UNLIKELY(FTS->ttype != T_STOP)) {
344 // For normal fields, push the TypeSpec that we're about to use.
David Reiss4e7530d2007-09-04 21:49:53 +0000345 ts_stack_.push_back(FTS);
346 }
347 return xfer;
348}
349
350uint32_t TDenseProtocol::writeFieldEnd() {
David Reissce161a92007-09-11 22:09:42 +0000351 // Just move on to the next field.
David Reiss4e7530d2007-09-04 21:49:53 +0000352 IDX++;
353 return 0;
354}
355
356uint32_t TDenseProtocol::writeFieldStop() {
David Reissce161a92007-09-11 22:09:42 +0000357 return TDenseProtocol::writeFieldBegin("", T_STOP, 0);
David Reiss4e7530d2007-09-04 21:49:53 +0000358}
359
360uint32_t TDenseProtocol::writeMapBegin(const TType keyType,
361 const TType valType,
362 const uint32_t size) {
363 checkTType(T_MAP);
364
365 assert(keyType == ST1->ttype);
366 assert(valType == ST2->ttype);
367
368 ts_stack_.push_back(ST1);
369 mkv_stack_.push_back(true);
370
371 return subWriteI32((int32_t)size);
372}
373
374uint32_t TDenseProtocol::writeMapEnd() {
David Reissce161a92007-09-11 22:09:42 +0000375 // Pop off the value type, as well as our entry in the map key/value stack.
376 // stateTransition takes care of popping off our TypeSpec.
David Reiss4e7530d2007-09-04 21:49:53 +0000377 ts_stack_.pop_back();
378 mkv_stack_.pop_back();
379 stateTransition();
380 return 0;
381}
382
383uint32_t TDenseProtocol::writeListBegin(const TType elemType,
384 const uint32_t size) {
385 checkTType(T_LIST);
386
387 assert(elemType == ST1->ttype);
388 ts_stack_.push_back(ST1);
389 return subWriteI32((int32_t)size);
390}
391
392uint32_t TDenseProtocol::writeListEnd() {
David Reissce161a92007-09-11 22:09:42 +0000393 // Pop off the element type. stateTransition takes care of popping off ours.
David Reiss4e7530d2007-09-04 21:49:53 +0000394 ts_stack_.pop_back();
395 stateTransition();
396 return 0;
397}
398
399uint32_t TDenseProtocol::writeSetBegin(const TType elemType,
400 const uint32_t size) {
401 checkTType(T_SET);
402
403 assert(elemType == ST1->ttype);
404 ts_stack_.push_back(ST1);
405 return subWriteI32((int32_t)size);
406}
407
408uint32_t TDenseProtocol::writeSetEnd() {
David Reissce161a92007-09-11 22:09:42 +0000409 // Pop off the element type. stateTransition takes care of popping off ours.
David Reiss4e7530d2007-09-04 21:49:53 +0000410 ts_stack_.pop_back();
411 stateTransition();
412 return 0;
413}
414
415uint32_t TDenseProtocol::writeBool(const bool value) {
416 checkTType(T_BOOL);
417 stateTransition();
418 return TBinaryProtocol::writeBool(value);
419}
420
421uint32_t TDenseProtocol::writeByte(const int8_t byte) {
422 checkTType(T_BYTE);
423 stateTransition();
424 return TBinaryProtocol::writeByte(byte);
425}
426
David Reiss4e7530d2007-09-04 21:49:53 +0000427uint32_t TDenseProtocol::writeI16(const int16_t i16) {
David Reiss4e7530d2007-09-04 21:49:53 +0000428 checkTType(T_I16);
429 stateTransition();
David Reissce161a92007-09-11 22:09:42 +0000430 return vlqWrite(i16);
David Reiss4e7530d2007-09-04 21:49:53 +0000431}
432
433uint32_t TDenseProtocol::writeI32(const int32_t i32) {
David Reiss4e7530d2007-09-04 21:49:53 +0000434 checkTType(T_I32);
435 stateTransition();
David Reissce161a92007-09-11 22:09:42 +0000436 return vlqWrite(i32);
David Reiss4e7530d2007-09-04 21:49:53 +0000437}
438
439uint32_t TDenseProtocol::writeI64(const int64_t i64) {
David Reiss4e7530d2007-09-04 21:49:53 +0000440 checkTType(T_I64);
441 stateTransition();
David Reissce161a92007-09-11 22:09:42 +0000442 return vlqWrite(i64);
David Reiss4e7530d2007-09-04 21:49:53 +0000443}
444
445uint32_t TDenseProtocol::writeDouble(const double dub) {
446 checkTType(T_DOUBLE);
447 stateTransition();
448 return TBinaryProtocol::writeDouble(dub);
449}
450
451uint32_t TDenseProtocol::writeString(const std::string& str) {
452 checkTType(T_STRING);
453 stateTransition();
454 return subWriteString(str);
455}
456
David Reissc005b1b2008-02-15 01:38:18 +0000457uint32_t TDenseProtocol::writeBinary(const std::string& str) {
458 return TDenseProtocol::writeString(str);
459}
460
David Reiss4e7530d2007-09-04 21:49:53 +0000461inline uint32_t TDenseProtocol::subWriteI32(const int32_t i32) {
David Reissce161a92007-09-11 22:09:42 +0000462 return vlqWrite(i32);
David Reiss4e7530d2007-09-04 21:49:53 +0000463}
464
David Reiss4e7530d2007-09-04 21:49:53 +0000465uint32_t TDenseProtocol::subWriteString(const std::string& str) {
Roger Meierb69d24d2012-10-04 18:02:15 +0000466 if(str.size() > static_cast<size_t>((std::numeric_limits<int32_t>::max)()))
467 throw TProtocolException(TProtocolException::SIZE_LIMIT);
468 uint32_t size = static_cast<uint32_t>(str.size());
David Reiss4e7530d2007-09-04 21:49:53 +0000469 uint32_t xfer = subWriteI32((int32_t)size);
470 if (size > 0) {
471 trans_->write((uint8_t*)str.data(), size);
472 }
473 return xfer + size;
474}
475
David Reisse67c0e62007-09-07 01:34:12 +0000476
David Reisse67c0e62007-09-07 01:34:12 +0000477
David Reissce161a92007-09-11 22:09:42 +0000478/*
David Reiss4e7530d2007-09-04 21:49:53 +0000479 * Reading functions
David Reissce161a92007-09-11 22:09:42 +0000480 *
481 * These have a lot of the same logic as the writing functions, so if
482 * something is confusing, look for comments in the corresponding writer.
David Reiss4e7530d2007-09-04 21:49:53 +0000483 */
484
485uint32_t TDenseProtocol::readMessageBegin(std::string& name,
486 TMessageType& messageType,
487 int32_t& seqid) {
David Reissac110e42010-03-09 05:20:07 +0000488 throw TException("TDenseProtocol doesn't work with messages (yet).");
David Reisse67c0e62007-09-07 01:34:12 +0000489
David Reiss4e7530d2007-09-04 21:49:53 +0000490 uint32_t xfer = 0;
491 int32_t sz;
492 xfer += subReadI32(sz);
493
494 if (sz < 0) {
495 // Check for correct version number
496 int32_t version = sz & VERSION_MASK;
497 if (version != VERSION_2) {
498 throw TProtocolException(TProtocolException::BAD_VERSION, "Bad version identifier");
499 }
500 messageType = (TMessageType)(sz & 0x000000ff);
501 xfer += subReadString(name);
502 xfer += subReadI32(seqid);
503 } else {
504 throw TProtocolException(TProtocolException::BAD_VERSION, "No version identifier... old protocol client in strict mode?");
505 }
506 return xfer;
507}
508
509uint32_t TDenseProtocol::readMessageEnd() {
510 return 0;
511}
512
513uint32_t TDenseProtocol::readStructBegin(string& name) {
Roger Meier3b771a12010-11-17 22:11:26 +0000514 (void) name;
David Reissce161a92007-09-11 22:09:42 +0000515 uint32_t xfer = 0;
516
517 if (ts_stack_.empty()) {
518 assert(standalone_);
519
520 if (type_spec_ == NULL) {
521 resetState();
David Reissac110e42010-03-09 05:20:07 +0000522 throw TException("TDenseProtocol: No type specified.");
David Reissce161a92007-09-11 22:09:42 +0000523 } else {
524 assert(type_spec_->ttype == T_STRUCT);
525 ts_stack_.push_back(type_spec_);
526
527 // Check the fingerprint prefix.
528 uint8_t buf[FP_PREFIX_LEN];
529 xfer += trans_->read(buf, FP_PREFIX_LEN);
530 if (std::memcmp(buf, type_spec_->fp_prefix, FP_PREFIX_LEN) != 0) {
531 resetState();
532 throw TProtocolException(TProtocolException::INVALID_DATA,
533 "Fingerprint in data does not match type_spec.");
534 }
535 }
536 }
537
538 // We need a new field index for this structure.
539 idx_stack_.push_back(0);
540 return 0;
David Reiss4e7530d2007-09-04 21:49:53 +0000541}
542
543uint32_t TDenseProtocol::readStructEnd() {
544 idx_stack_.pop_back();
545 stateTransition();
546 return 0;
547}
548
549uint32_t TDenseProtocol::readFieldBegin(string& name,
550 TType& fieldType,
551 int16_t& fieldId) {
Roger Meier3b771a12010-11-17 22:11:26 +0000552 (void) name;
David Reiss4e7530d2007-09-04 21:49:53 +0000553 uint32_t xfer = 0;
554
David Reissce161a92007-09-11 22:09:42 +0000555 // For optional fields, check to see if they are there.
David Reiss4e7530d2007-09-04 21:49:53 +0000556 while (FMT.is_optional) {
557 bool is_present;
558 xfer += subReadBool(is_present);
559 if (is_present) {
560 break;
561 }
562 IDX++;
563 }
564
David Reissce161a92007-09-11 22:09:42 +0000565 // Once we hit a mandatory field, or an optional field that is present,
566 // we know that FMT and FTS point to the appropriate field.
567
David Reiss4e7530d2007-09-04 21:49:53 +0000568 fieldId = FMT.tag;
569 fieldType = FTS->ttype;
570
David Reissce161a92007-09-11 22:09:42 +0000571 // Normally, we push the TypeSpec that we are about to read,
572 // but no reading is done for T_STOP.
David Reiss4e7530d2007-09-04 21:49:53 +0000573 if (FTS->ttype != T_STOP) {
574 ts_stack_.push_back(FTS);
575 }
576 return xfer;
577}
578
579uint32_t TDenseProtocol::readFieldEnd() {
580 IDX++;
581 return 0;
582}
583
584uint32_t TDenseProtocol::readMapBegin(TType& keyType,
585 TType& valType,
586 uint32_t& size) {
587 checkTType(T_MAP);
588
589 uint32_t xfer = 0;
590 int32_t sizei;
591 xfer += subReadI32(sizei);
592 if (sizei < 0) {
David Reissce161a92007-09-11 22:09:42 +0000593 resetState();
David Reiss4e7530d2007-09-04 21:49:53 +0000594 throw TProtocolException(TProtocolException::NEGATIVE_SIZE);
595 } else if (container_limit_ && sizei > container_limit_) {
David Reissce161a92007-09-11 22:09:42 +0000596 resetState();
David Reiss4e7530d2007-09-04 21:49:53 +0000597 throw TProtocolException(TProtocolException::SIZE_LIMIT);
598 }
599 size = (uint32_t)sizei;
600
601 keyType = ST1->ttype;
602 valType = ST2->ttype;
603
604 ts_stack_.push_back(ST1);
605 mkv_stack_.push_back(true);
606
607 return xfer;
608}
609
610uint32_t TDenseProtocol::readMapEnd() {
611 ts_stack_.pop_back();
612 mkv_stack_.pop_back();
613 stateTransition();
614 return 0;
615}
616
617uint32_t TDenseProtocol::readListBegin(TType& elemType,
618 uint32_t& size) {
619 checkTType(T_LIST);
620
621 uint32_t xfer = 0;
622 int32_t sizei;
623 xfer += subReadI32(sizei);
624 if (sizei < 0) {
David Reissce161a92007-09-11 22:09:42 +0000625 resetState();
David Reiss4e7530d2007-09-04 21:49:53 +0000626 throw TProtocolException(TProtocolException::NEGATIVE_SIZE);
627 } else if (container_limit_ && sizei > container_limit_) {
David Reissce161a92007-09-11 22:09:42 +0000628 resetState();
David Reiss4e7530d2007-09-04 21:49:53 +0000629 throw TProtocolException(TProtocolException::SIZE_LIMIT);
630 }
631 size = (uint32_t)sizei;
632
633 elemType = ST1->ttype;
634
635 ts_stack_.push_back(ST1);
636
637 return xfer;
638}
639
640uint32_t TDenseProtocol::readListEnd() {
641 ts_stack_.pop_back();
642 stateTransition();
643 return 0;
644}
645
646uint32_t TDenseProtocol::readSetBegin(TType& elemType,
647 uint32_t& size) {
648 checkTType(T_SET);
649
650 uint32_t xfer = 0;
651 int32_t sizei;
652 xfer += subReadI32(sizei);
653 if (sizei < 0) {
David Reissce161a92007-09-11 22:09:42 +0000654 resetState();
David Reiss4e7530d2007-09-04 21:49:53 +0000655 throw TProtocolException(TProtocolException::NEGATIVE_SIZE);
656 } else if (container_limit_ && sizei > container_limit_) {
David Reissce161a92007-09-11 22:09:42 +0000657 resetState();
David Reiss4e7530d2007-09-04 21:49:53 +0000658 throw TProtocolException(TProtocolException::SIZE_LIMIT);
659 }
660 size = (uint32_t)sizei;
661
662 elemType = ST1->ttype;
663
664 ts_stack_.push_back(ST1);
665
666 return xfer;
667}
668
669uint32_t TDenseProtocol::readSetEnd() {
670 ts_stack_.pop_back();
671 stateTransition();
672 return 0;
673}
674
675uint32_t TDenseProtocol::readBool(bool& value) {
676 checkTType(T_BOOL);
677 stateTransition();
678 return TBinaryProtocol::readBool(value);
679}
680
681uint32_t TDenseProtocol::readByte(int8_t& byte) {
682 checkTType(T_BYTE);
683 stateTransition();
684 return TBinaryProtocol::readByte(byte);
685}
686
687uint32_t TDenseProtocol::readI16(int16_t& i16) {
688 checkTType(T_I16);
689 stateTransition();
David Reisse67c0e62007-09-07 01:34:12 +0000690 uint64_t u64;
David Reissce161a92007-09-11 22:09:42 +0000691 uint32_t rv = vlqRead(u64);
David Reisse67c0e62007-09-07 01:34:12 +0000692 int64_t val = (int64_t)u64;
693 if (UNLIKELY(val > INT16_MAX || val < INT16_MIN)) {
David Reissce161a92007-09-11 22:09:42 +0000694 resetState();
David Reisse67c0e62007-09-07 01:34:12 +0000695 throw TProtocolException(TProtocolException::INVALID_DATA,
696 "i16 out of range.");
697 }
698 i16 = (int16_t)val;
699 return rv;
David Reiss4e7530d2007-09-04 21:49:53 +0000700}
701
702uint32_t TDenseProtocol::readI32(int32_t& i32) {
703 checkTType(T_I32);
704 stateTransition();
David Reisse67c0e62007-09-07 01:34:12 +0000705 uint64_t u64;
David Reissce161a92007-09-11 22:09:42 +0000706 uint32_t rv = vlqRead(u64);
David Reisse67c0e62007-09-07 01:34:12 +0000707 int64_t val = (int64_t)u64;
708 if (UNLIKELY(val > INT32_MAX || val < INT32_MIN)) {
David Reissce161a92007-09-11 22:09:42 +0000709 resetState();
David Reisse67c0e62007-09-07 01:34:12 +0000710 throw TProtocolException(TProtocolException::INVALID_DATA,
711 "i32 out of range.");
712 }
713 i32 = (int32_t)val;
714 return rv;
David Reiss4e7530d2007-09-04 21:49:53 +0000715}
716
717uint32_t TDenseProtocol::readI64(int64_t& i64) {
718 checkTType(T_I64);
719 stateTransition();
David Reisse67c0e62007-09-07 01:34:12 +0000720 uint64_t u64;
David Reissce161a92007-09-11 22:09:42 +0000721 uint32_t rv = vlqRead(u64);
David Reisse67c0e62007-09-07 01:34:12 +0000722 int64_t val = (int64_t)u64;
723 if (UNLIKELY(val > INT64_MAX || val < INT64_MIN)) {
David Reissce161a92007-09-11 22:09:42 +0000724 resetState();
David Reisse67c0e62007-09-07 01:34:12 +0000725 throw TProtocolException(TProtocolException::INVALID_DATA,
726 "i64 out of range.");
727 }
728 i64 = (int64_t)val;
729 return rv;
David Reiss4e7530d2007-09-04 21:49:53 +0000730}
731
732uint32_t TDenseProtocol::readDouble(double& dub) {
733 checkTType(T_DOUBLE);
734 stateTransition();
735 return TBinaryProtocol::readDouble(dub);
736}
737
738uint32_t TDenseProtocol::readString(std::string& str) {
739 checkTType(T_STRING);
740 stateTransition();
741 return subReadString(str);
742}
743
David Reissc005b1b2008-02-15 01:38:18 +0000744uint32_t TDenseProtocol::readBinary(std::string& str) {
745 return TDenseProtocol::readString(str);
746}
747
David Reisse67c0e62007-09-07 01:34:12 +0000748uint32_t TDenseProtocol::subReadI32(int32_t& i32) {
749 uint64_t u64;
David Reissce161a92007-09-11 22:09:42 +0000750 uint32_t rv = vlqRead(u64);
David Reisse67c0e62007-09-07 01:34:12 +0000751 int64_t val = (int64_t)u64;
752 if (UNLIKELY(val > INT32_MAX || val < INT32_MIN)) {
David Reissce161a92007-09-11 22:09:42 +0000753 resetState();
David Reisse67c0e62007-09-07 01:34:12 +0000754 throw TProtocolException(TProtocolException::INVALID_DATA,
755 "i32 out of range.");
756 }
757 i32 = (int32_t)val;
758 return rv;
759}
760
761uint32_t TDenseProtocol::subReadString(std::string& str) {
762 uint32_t xfer;
763 int32_t size;
764 xfer = subReadI32(size);
765 return xfer + readStringBody(str, size);
766}
767
T Jake Lucianib5e62212009-01-31 22:36:20 +0000768}}} // apache::thrift::protocol