blob: 86e5e285bac1cd47cc22374cc0e8cb16861e122a [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>
David Reiss4e7530d2007-09-04 21:49:53 +000092#include "TDenseProtocol.h"
93#include "TReflectionLocal.h"
94
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);
248 buf[pos] = (vlq | 0x80);
249 vlq >>= 7;
250 pos--;
251 }
252
253 // Back up one step before writing.
254 pos++;
255
256 trans_->write(buf+pos, sizeof(buf) - pos);
257 return sizeof(buf) - pos;
258}
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) {
466 uint32_t size = str.size();
467 uint32_t xfer = subWriteI32((int32_t)size);
468 if (size > 0) {
469 trans_->write((uint8_t*)str.data(), size);
470 }
471 return xfer + size;
472}
473
David Reisse67c0e62007-09-07 01:34:12 +0000474
David Reisse67c0e62007-09-07 01:34:12 +0000475
David Reissce161a92007-09-11 22:09:42 +0000476/*
David Reiss4e7530d2007-09-04 21:49:53 +0000477 * Reading functions
David Reissce161a92007-09-11 22:09:42 +0000478 *
479 * These have a lot of the same logic as the writing functions, so if
480 * something is confusing, look for comments in the corresponding writer.
David Reiss4e7530d2007-09-04 21:49:53 +0000481 */
482
483uint32_t TDenseProtocol::readMessageBegin(std::string& name,
484 TMessageType& messageType,
485 int32_t& seqid) {
David Reissac110e42010-03-09 05:20:07 +0000486 throw TException("TDenseProtocol doesn't work with messages (yet).");
David Reisse67c0e62007-09-07 01:34:12 +0000487
David Reiss4e7530d2007-09-04 21:49:53 +0000488 uint32_t xfer = 0;
489 int32_t sz;
490 xfer += subReadI32(sz);
491
492 if (sz < 0) {
493 // Check for correct version number
494 int32_t version = sz & VERSION_MASK;
495 if (version != VERSION_2) {
496 throw TProtocolException(TProtocolException::BAD_VERSION, "Bad version identifier");
497 }
498 messageType = (TMessageType)(sz & 0x000000ff);
499 xfer += subReadString(name);
500 xfer += subReadI32(seqid);
501 } else {
502 throw TProtocolException(TProtocolException::BAD_VERSION, "No version identifier... old protocol client in strict mode?");
503 }
504 return xfer;
505}
506
507uint32_t TDenseProtocol::readMessageEnd() {
508 return 0;
509}
510
511uint32_t TDenseProtocol::readStructBegin(string& name) {
Roger Meier3b771a12010-11-17 22:11:26 +0000512 (void) name;
David Reissce161a92007-09-11 22:09:42 +0000513 uint32_t xfer = 0;
514
515 if (ts_stack_.empty()) {
516 assert(standalone_);
517
518 if (type_spec_ == NULL) {
519 resetState();
David Reissac110e42010-03-09 05:20:07 +0000520 throw TException("TDenseProtocol: No type specified.");
David Reissce161a92007-09-11 22:09:42 +0000521 } else {
522 assert(type_spec_->ttype == T_STRUCT);
523 ts_stack_.push_back(type_spec_);
524
525 // Check the fingerprint prefix.
526 uint8_t buf[FP_PREFIX_LEN];
527 xfer += trans_->read(buf, FP_PREFIX_LEN);
528 if (std::memcmp(buf, type_spec_->fp_prefix, FP_PREFIX_LEN) != 0) {
529 resetState();
530 throw TProtocolException(TProtocolException::INVALID_DATA,
531 "Fingerprint in data does not match type_spec.");
532 }
533 }
534 }
535
536 // We need a new field index for this structure.
537 idx_stack_.push_back(0);
538 return 0;
David Reiss4e7530d2007-09-04 21:49:53 +0000539}
540
541uint32_t TDenseProtocol::readStructEnd() {
542 idx_stack_.pop_back();
543 stateTransition();
544 return 0;
545}
546
547uint32_t TDenseProtocol::readFieldBegin(string& name,
548 TType& fieldType,
549 int16_t& fieldId) {
Roger Meier3b771a12010-11-17 22:11:26 +0000550 (void) name;
David Reiss4e7530d2007-09-04 21:49:53 +0000551 uint32_t xfer = 0;
552
David Reissce161a92007-09-11 22:09:42 +0000553 // For optional fields, check to see if they are there.
David Reiss4e7530d2007-09-04 21:49:53 +0000554 while (FMT.is_optional) {
555 bool is_present;
556 xfer += subReadBool(is_present);
557 if (is_present) {
558 break;
559 }
560 IDX++;
561 }
562
David Reissce161a92007-09-11 22:09:42 +0000563 // Once we hit a mandatory field, or an optional field that is present,
564 // we know that FMT and FTS point to the appropriate field.
565
David Reiss4e7530d2007-09-04 21:49:53 +0000566 fieldId = FMT.tag;
567 fieldType = FTS->ttype;
568
David Reissce161a92007-09-11 22:09:42 +0000569 // Normally, we push the TypeSpec that we are about to read,
570 // but no reading is done for T_STOP.
David Reiss4e7530d2007-09-04 21:49:53 +0000571 if (FTS->ttype != T_STOP) {
572 ts_stack_.push_back(FTS);
573 }
574 return xfer;
575}
576
577uint32_t TDenseProtocol::readFieldEnd() {
578 IDX++;
579 return 0;
580}
581
582uint32_t TDenseProtocol::readMapBegin(TType& keyType,
583 TType& valType,
584 uint32_t& size) {
585 checkTType(T_MAP);
586
587 uint32_t xfer = 0;
588 int32_t sizei;
589 xfer += subReadI32(sizei);
590 if (sizei < 0) {
David Reissce161a92007-09-11 22:09:42 +0000591 resetState();
David Reiss4e7530d2007-09-04 21:49:53 +0000592 throw TProtocolException(TProtocolException::NEGATIVE_SIZE);
593 } else if (container_limit_ && sizei > container_limit_) {
David Reissce161a92007-09-11 22:09:42 +0000594 resetState();
David Reiss4e7530d2007-09-04 21:49:53 +0000595 throw TProtocolException(TProtocolException::SIZE_LIMIT);
596 }
597 size = (uint32_t)sizei;
598
599 keyType = ST1->ttype;
600 valType = ST2->ttype;
601
602 ts_stack_.push_back(ST1);
603 mkv_stack_.push_back(true);
604
605 return xfer;
606}
607
608uint32_t TDenseProtocol::readMapEnd() {
609 ts_stack_.pop_back();
610 mkv_stack_.pop_back();
611 stateTransition();
612 return 0;
613}
614
615uint32_t TDenseProtocol::readListBegin(TType& elemType,
616 uint32_t& size) {
617 checkTType(T_LIST);
618
619 uint32_t xfer = 0;
620 int32_t sizei;
621 xfer += subReadI32(sizei);
622 if (sizei < 0) {
David Reissce161a92007-09-11 22:09:42 +0000623 resetState();
David Reiss4e7530d2007-09-04 21:49:53 +0000624 throw TProtocolException(TProtocolException::NEGATIVE_SIZE);
625 } else if (container_limit_ && sizei > container_limit_) {
David Reissce161a92007-09-11 22:09:42 +0000626 resetState();
David Reiss4e7530d2007-09-04 21:49:53 +0000627 throw TProtocolException(TProtocolException::SIZE_LIMIT);
628 }
629 size = (uint32_t)sizei;
630
631 elemType = ST1->ttype;
632
633 ts_stack_.push_back(ST1);
634
635 return xfer;
636}
637
638uint32_t TDenseProtocol::readListEnd() {
639 ts_stack_.pop_back();
640 stateTransition();
641 return 0;
642}
643
644uint32_t TDenseProtocol::readSetBegin(TType& elemType,
645 uint32_t& size) {
646 checkTType(T_SET);
647
648 uint32_t xfer = 0;
649 int32_t sizei;
650 xfer += subReadI32(sizei);
651 if (sizei < 0) {
David Reissce161a92007-09-11 22:09:42 +0000652 resetState();
David Reiss4e7530d2007-09-04 21:49:53 +0000653 throw TProtocolException(TProtocolException::NEGATIVE_SIZE);
654 } else if (container_limit_ && sizei > container_limit_) {
David Reissce161a92007-09-11 22:09:42 +0000655 resetState();
David Reiss4e7530d2007-09-04 21:49:53 +0000656 throw TProtocolException(TProtocolException::SIZE_LIMIT);
657 }
658 size = (uint32_t)sizei;
659
660 elemType = ST1->ttype;
661
662 ts_stack_.push_back(ST1);
663
664 return xfer;
665}
666
667uint32_t TDenseProtocol::readSetEnd() {
668 ts_stack_.pop_back();
669 stateTransition();
670 return 0;
671}
672
673uint32_t TDenseProtocol::readBool(bool& value) {
674 checkTType(T_BOOL);
675 stateTransition();
676 return TBinaryProtocol::readBool(value);
677}
678
679uint32_t TDenseProtocol::readByte(int8_t& byte) {
680 checkTType(T_BYTE);
681 stateTransition();
682 return TBinaryProtocol::readByte(byte);
683}
684
685uint32_t TDenseProtocol::readI16(int16_t& i16) {
686 checkTType(T_I16);
687 stateTransition();
David Reisse67c0e62007-09-07 01:34:12 +0000688 uint64_t u64;
David Reissce161a92007-09-11 22:09:42 +0000689 uint32_t rv = vlqRead(u64);
David Reisse67c0e62007-09-07 01:34:12 +0000690 int64_t val = (int64_t)u64;
691 if (UNLIKELY(val > INT16_MAX || val < INT16_MIN)) {
David Reissce161a92007-09-11 22:09:42 +0000692 resetState();
David Reisse67c0e62007-09-07 01:34:12 +0000693 throw TProtocolException(TProtocolException::INVALID_DATA,
694 "i16 out of range.");
695 }
696 i16 = (int16_t)val;
697 return rv;
David Reiss4e7530d2007-09-04 21:49:53 +0000698}
699
700uint32_t TDenseProtocol::readI32(int32_t& i32) {
701 checkTType(T_I32);
702 stateTransition();
David Reisse67c0e62007-09-07 01:34:12 +0000703 uint64_t u64;
David Reissce161a92007-09-11 22:09:42 +0000704 uint32_t rv = vlqRead(u64);
David Reisse67c0e62007-09-07 01:34:12 +0000705 int64_t val = (int64_t)u64;
706 if (UNLIKELY(val > INT32_MAX || val < INT32_MIN)) {
David Reissce161a92007-09-11 22:09:42 +0000707 resetState();
David Reisse67c0e62007-09-07 01:34:12 +0000708 throw TProtocolException(TProtocolException::INVALID_DATA,
709 "i32 out of range.");
710 }
711 i32 = (int32_t)val;
712 return rv;
David Reiss4e7530d2007-09-04 21:49:53 +0000713}
714
715uint32_t TDenseProtocol::readI64(int64_t& i64) {
716 checkTType(T_I64);
717 stateTransition();
David Reisse67c0e62007-09-07 01:34:12 +0000718 uint64_t u64;
David Reissce161a92007-09-11 22:09:42 +0000719 uint32_t rv = vlqRead(u64);
David Reisse67c0e62007-09-07 01:34:12 +0000720 int64_t val = (int64_t)u64;
721 if (UNLIKELY(val > INT64_MAX || val < INT64_MIN)) {
David Reissce161a92007-09-11 22:09:42 +0000722 resetState();
David Reisse67c0e62007-09-07 01:34:12 +0000723 throw TProtocolException(TProtocolException::INVALID_DATA,
724 "i64 out of range.");
725 }
726 i64 = (int64_t)val;
727 return rv;
David Reiss4e7530d2007-09-04 21:49:53 +0000728}
729
730uint32_t TDenseProtocol::readDouble(double& dub) {
731 checkTType(T_DOUBLE);
732 stateTransition();
733 return TBinaryProtocol::readDouble(dub);
734}
735
736uint32_t TDenseProtocol::readString(std::string& str) {
737 checkTType(T_STRING);
738 stateTransition();
739 return subReadString(str);
740}
741
David Reissc005b1b2008-02-15 01:38:18 +0000742uint32_t TDenseProtocol::readBinary(std::string& str) {
743 return TDenseProtocol::readString(str);
744}
745
David Reisse67c0e62007-09-07 01:34:12 +0000746uint32_t TDenseProtocol::subReadI32(int32_t& i32) {
747 uint64_t u64;
David Reissce161a92007-09-11 22:09:42 +0000748 uint32_t rv = vlqRead(u64);
David Reisse67c0e62007-09-07 01:34:12 +0000749 int64_t val = (int64_t)u64;
750 if (UNLIKELY(val > INT32_MAX || val < INT32_MIN)) {
David Reissce161a92007-09-11 22:09:42 +0000751 resetState();
David Reisse67c0e62007-09-07 01:34:12 +0000752 throw TProtocolException(TProtocolException::INVALID_DATA,
753 "i32 out of range.");
754 }
755 i32 = (int32_t)val;
756 return rv;
757}
758
759uint32_t TDenseProtocol::subReadString(std::string& str) {
760 uint32_t xfer;
761 int32_t size;
762 xfer = subReadI32(size);
763 return xfer + readStringBody(str, size);
764}
765
T Jake Lucianib5e62212009-01-31 22:36:20 +0000766}}} // apache::thrift::protocol