blob: b9a3d1fdedb52cdd54795eef9580cf41dde14105 [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) {
David Reissce161a92007-09-11 22:09:42 +0000284 uint32_t xfer = 0;
285
286 // The TypeSpec stack should be empty if this is the top-level read/write.
287 // If it is, we push the TypeSpec passed to the constructor.
David Reiss4e7530d2007-09-04 21:49:53 +0000288 if (ts_stack_.empty()) {
David Reissce161a92007-09-11 22:09:42 +0000289 assert(standalone_);
290
David Reiss4e7530d2007-09-04 21:49:53 +0000291 if (type_spec_ == NULL) {
David Reissce161a92007-09-11 22:09:42 +0000292 resetState();
David Reissac110e42010-03-09 05:20:07 +0000293 throw TException("TDenseProtocol: No type specified.");
David Reiss4e7530d2007-09-04 21:49:53 +0000294 } else {
David Reissce161a92007-09-11 22:09:42 +0000295 assert(type_spec_->ttype == T_STRUCT);
David Reiss4e7530d2007-09-04 21:49:53 +0000296 ts_stack_.push_back(type_spec_);
David Reissce161a92007-09-11 22:09:42 +0000297 // Write out a prefix of the structure fingerprint.
298 trans_->write(type_spec_->fp_prefix, FP_PREFIX_LEN);
299 xfer += FP_PREFIX_LEN;
David Reiss4e7530d2007-09-04 21:49:53 +0000300 }
301 }
302
David Reissce161a92007-09-11 22:09:42 +0000303 // We need a new field index for this structure.
David Reiss4e7530d2007-09-04 21:49:53 +0000304 idx_stack_.push_back(0);
305 return 0;
306}
307
308uint32_t TDenseProtocol::writeStructEnd() {
309 idx_stack_.pop_back();
310 stateTransition();
311 return 0;
312}
313
David Reiss64120002008-04-29 23:12:24 +0000314uint32_t TDenseProtocol::writeFieldBegin(const char* name,
David Reiss4e7530d2007-09-04 21:49:53 +0000315 const TType fieldType,
316 const int16_t fieldId) {
317 uint32_t xfer = 0;
318
David Reissce161a92007-09-11 22:09:42 +0000319 // Skip over optional fields.
David Reiss4e7530d2007-09-04 21:49:53 +0000320 while (FMT.tag != fieldId) {
321 // TODO(dreiss): Old meta here.
322 assert(FTS->ttype != T_STOP);
323 assert(FMT.is_optional);
David Reissce161a92007-09-11 22:09:42 +0000324 // Write a zero byte so the reader can skip it.
David Reiss4e7530d2007-09-04 21:49:53 +0000325 xfer += subWriteBool(false);
David Reissce161a92007-09-11 22:09:42 +0000326 // And advance to the next field.
David Reiss4e7530d2007-09-04 21:49:53 +0000327 IDX++;
328 }
329
330 // TODO(dreiss): give a better exception.
331 assert(FTS->ttype == fieldType);
332
333 if (FMT.is_optional) {
334 subWriteBool(true);
335 xfer += 1;
336 }
337
David Reissce161a92007-09-11 22:09:42 +0000338 // writeFieldStop shares all lot of logic up to this point.
339 // Instead of replicating it all, we just call this method from that one
340 // and use a gross special case here.
341 if (UNLIKELY(FTS->ttype != T_STOP)) {
342 // For normal fields, push the TypeSpec that we're about to use.
David Reiss4e7530d2007-09-04 21:49:53 +0000343 ts_stack_.push_back(FTS);
344 }
345 return xfer;
346}
347
348uint32_t TDenseProtocol::writeFieldEnd() {
David Reissce161a92007-09-11 22:09:42 +0000349 // Just move on to the next field.
David Reiss4e7530d2007-09-04 21:49:53 +0000350 IDX++;
351 return 0;
352}
353
354uint32_t TDenseProtocol::writeFieldStop() {
David Reissce161a92007-09-11 22:09:42 +0000355 return TDenseProtocol::writeFieldBegin("", T_STOP, 0);
David Reiss4e7530d2007-09-04 21:49:53 +0000356}
357
358uint32_t TDenseProtocol::writeMapBegin(const TType keyType,
359 const TType valType,
360 const uint32_t size) {
361 checkTType(T_MAP);
362
363 assert(keyType == ST1->ttype);
364 assert(valType == ST2->ttype);
365
366 ts_stack_.push_back(ST1);
367 mkv_stack_.push_back(true);
368
369 return subWriteI32((int32_t)size);
370}
371
372uint32_t TDenseProtocol::writeMapEnd() {
David Reissce161a92007-09-11 22:09:42 +0000373 // Pop off the value type, as well as our entry in the map key/value stack.
374 // stateTransition takes care of popping off our TypeSpec.
David Reiss4e7530d2007-09-04 21:49:53 +0000375 ts_stack_.pop_back();
376 mkv_stack_.pop_back();
377 stateTransition();
378 return 0;
379}
380
381uint32_t TDenseProtocol::writeListBegin(const TType elemType,
382 const uint32_t size) {
383 checkTType(T_LIST);
384
385 assert(elemType == ST1->ttype);
386 ts_stack_.push_back(ST1);
387 return subWriteI32((int32_t)size);
388}
389
390uint32_t TDenseProtocol::writeListEnd() {
David Reissce161a92007-09-11 22:09:42 +0000391 // Pop off the element type. stateTransition takes care of popping off ours.
David Reiss4e7530d2007-09-04 21:49:53 +0000392 ts_stack_.pop_back();
393 stateTransition();
394 return 0;
395}
396
397uint32_t TDenseProtocol::writeSetBegin(const TType elemType,
398 const uint32_t size) {
399 checkTType(T_SET);
400
401 assert(elemType == ST1->ttype);
402 ts_stack_.push_back(ST1);
403 return subWriteI32((int32_t)size);
404}
405
406uint32_t TDenseProtocol::writeSetEnd() {
David Reissce161a92007-09-11 22:09:42 +0000407 // Pop off the element type. stateTransition takes care of popping off ours.
David Reiss4e7530d2007-09-04 21:49:53 +0000408 ts_stack_.pop_back();
409 stateTransition();
410 return 0;
411}
412
413uint32_t TDenseProtocol::writeBool(const bool value) {
414 checkTType(T_BOOL);
415 stateTransition();
416 return TBinaryProtocol::writeBool(value);
417}
418
419uint32_t TDenseProtocol::writeByte(const int8_t byte) {
420 checkTType(T_BYTE);
421 stateTransition();
422 return TBinaryProtocol::writeByte(byte);
423}
424
David Reiss4e7530d2007-09-04 21:49:53 +0000425uint32_t TDenseProtocol::writeI16(const int16_t i16) {
David Reiss4e7530d2007-09-04 21:49:53 +0000426 checkTType(T_I16);
427 stateTransition();
David Reissce161a92007-09-11 22:09:42 +0000428 return vlqWrite(i16);
David Reiss4e7530d2007-09-04 21:49:53 +0000429}
430
431uint32_t TDenseProtocol::writeI32(const int32_t i32) {
David Reiss4e7530d2007-09-04 21:49:53 +0000432 checkTType(T_I32);
433 stateTransition();
David Reissce161a92007-09-11 22:09:42 +0000434 return vlqWrite(i32);
David Reiss4e7530d2007-09-04 21:49:53 +0000435}
436
437uint32_t TDenseProtocol::writeI64(const int64_t i64) {
David Reiss4e7530d2007-09-04 21:49:53 +0000438 checkTType(T_I64);
439 stateTransition();
David Reissce161a92007-09-11 22:09:42 +0000440 return vlqWrite(i64);
David Reiss4e7530d2007-09-04 21:49:53 +0000441}
442
443uint32_t TDenseProtocol::writeDouble(const double dub) {
444 checkTType(T_DOUBLE);
445 stateTransition();
446 return TBinaryProtocol::writeDouble(dub);
447}
448
449uint32_t TDenseProtocol::writeString(const std::string& str) {
450 checkTType(T_STRING);
451 stateTransition();
452 return subWriteString(str);
453}
454
David Reissc005b1b2008-02-15 01:38:18 +0000455uint32_t TDenseProtocol::writeBinary(const std::string& str) {
456 return TDenseProtocol::writeString(str);
457}
458
David Reiss4e7530d2007-09-04 21:49:53 +0000459inline uint32_t TDenseProtocol::subWriteI32(const int32_t i32) {
David Reissce161a92007-09-11 22:09:42 +0000460 return vlqWrite(i32);
David Reiss4e7530d2007-09-04 21:49:53 +0000461}
462
David Reiss4e7530d2007-09-04 21:49:53 +0000463uint32_t TDenseProtocol::subWriteString(const std::string& str) {
464 uint32_t size = str.size();
465 uint32_t xfer = subWriteI32((int32_t)size);
466 if (size > 0) {
467 trans_->write((uint8_t*)str.data(), size);
468 }
469 return xfer + size;
470}
471
David Reisse67c0e62007-09-07 01:34:12 +0000472
David Reisse67c0e62007-09-07 01:34:12 +0000473
David Reissce161a92007-09-11 22:09:42 +0000474/*
David Reiss4e7530d2007-09-04 21:49:53 +0000475 * Reading functions
David Reissce161a92007-09-11 22:09:42 +0000476 *
477 * These have a lot of the same logic as the writing functions, so if
478 * something is confusing, look for comments in the corresponding writer.
David Reiss4e7530d2007-09-04 21:49:53 +0000479 */
480
481uint32_t TDenseProtocol::readMessageBegin(std::string& name,
482 TMessageType& messageType,
483 int32_t& seqid) {
David Reissac110e42010-03-09 05:20:07 +0000484 throw TException("TDenseProtocol doesn't work with messages (yet).");
David Reisse67c0e62007-09-07 01:34:12 +0000485
David Reiss4e7530d2007-09-04 21:49:53 +0000486 uint32_t xfer = 0;
487 int32_t sz;
488 xfer += subReadI32(sz);
489
490 if (sz < 0) {
491 // Check for correct version number
492 int32_t version = sz & VERSION_MASK;
493 if (version != VERSION_2) {
494 throw TProtocolException(TProtocolException::BAD_VERSION, "Bad version identifier");
495 }
496 messageType = (TMessageType)(sz & 0x000000ff);
497 xfer += subReadString(name);
498 xfer += subReadI32(seqid);
499 } else {
500 throw TProtocolException(TProtocolException::BAD_VERSION, "No version identifier... old protocol client in strict mode?");
501 }
502 return xfer;
503}
504
505uint32_t TDenseProtocol::readMessageEnd() {
506 return 0;
507}
508
509uint32_t TDenseProtocol::readStructBegin(string& name) {
David Reissce161a92007-09-11 22:09:42 +0000510 uint32_t xfer = 0;
511
512 if (ts_stack_.empty()) {
513 assert(standalone_);
514
515 if (type_spec_ == NULL) {
516 resetState();
David Reissac110e42010-03-09 05:20:07 +0000517 throw TException("TDenseProtocol: No type specified.");
David Reissce161a92007-09-11 22:09:42 +0000518 } else {
519 assert(type_spec_->ttype == T_STRUCT);
520 ts_stack_.push_back(type_spec_);
521
522 // Check the fingerprint prefix.
523 uint8_t buf[FP_PREFIX_LEN];
524 xfer += trans_->read(buf, FP_PREFIX_LEN);
525 if (std::memcmp(buf, type_spec_->fp_prefix, FP_PREFIX_LEN) != 0) {
526 resetState();
527 throw TProtocolException(TProtocolException::INVALID_DATA,
528 "Fingerprint in data does not match type_spec.");
529 }
530 }
531 }
532
533 // We need a new field index for this structure.
534 idx_stack_.push_back(0);
535 return 0;
David Reiss4e7530d2007-09-04 21:49:53 +0000536}
537
538uint32_t TDenseProtocol::readStructEnd() {
539 idx_stack_.pop_back();
540 stateTransition();
541 return 0;
542}
543
544uint32_t TDenseProtocol::readFieldBegin(string& name,
545 TType& fieldType,
546 int16_t& fieldId) {
547 uint32_t xfer = 0;
548
David Reissce161a92007-09-11 22:09:42 +0000549 // For optional fields, check to see if they are there.
David Reiss4e7530d2007-09-04 21:49:53 +0000550 while (FMT.is_optional) {
551 bool is_present;
552 xfer += subReadBool(is_present);
553 if (is_present) {
554 break;
555 }
556 IDX++;
557 }
558
David Reissce161a92007-09-11 22:09:42 +0000559 // Once we hit a mandatory field, or an optional field that is present,
560 // we know that FMT and FTS point to the appropriate field.
561
David Reiss4e7530d2007-09-04 21:49:53 +0000562 fieldId = FMT.tag;
563 fieldType = FTS->ttype;
564
David Reissce161a92007-09-11 22:09:42 +0000565 // Normally, we push the TypeSpec that we are about to read,
566 // but no reading is done for T_STOP.
David Reiss4e7530d2007-09-04 21:49:53 +0000567 if (FTS->ttype != T_STOP) {
568 ts_stack_.push_back(FTS);
569 }
570 return xfer;
571}
572
573uint32_t TDenseProtocol::readFieldEnd() {
574 IDX++;
575 return 0;
576}
577
578uint32_t TDenseProtocol::readMapBegin(TType& keyType,
579 TType& valType,
580 uint32_t& size) {
581 checkTType(T_MAP);
582
583 uint32_t xfer = 0;
584 int32_t sizei;
585 xfer += subReadI32(sizei);
586 if (sizei < 0) {
David Reissce161a92007-09-11 22:09:42 +0000587 resetState();
David Reiss4e7530d2007-09-04 21:49:53 +0000588 throw TProtocolException(TProtocolException::NEGATIVE_SIZE);
589 } else if (container_limit_ && sizei > container_limit_) {
David Reissce161a92007-09-11 22:09:42 +0000590 resetState();
David Reiss4e7530d2007-09-04 21:49:53 +0000591 throw TProtocolException(TProtocolException::SIZE_LIMIT);
592 }
593 size = (uint32_t)sizei;
594
595 keyType = ST1->ttype;
596 valType = ST2->ttype;
597
598 ts_stack_.push_back(ST1);
599 mkv_stack_.push_back(true);
600
601 return xfer;
602}
603
604uint32_t TDenseProtocol::readMapEnd() {
605 ts_stack_.pop_back();
606 mkv_stack_.pop_back();
607 stateTransition();
608 return 0;
609}
610
611uint32_t TDenseProtocol::readListBegin(TType& elemType,
612 uint32_t& size) {
613 checkTType(T_LIST);
614
615 uint32_t xfer = 0;
616 int32_t sizei;
617 xfer += subReadI32(sizei);
618 if (sizei < 0) {
David Reissce161a92007-09-11 22:09:42 +0000619 resetState();
David Reiss4e7530d2007-09-04 21:49:53 +0000620 throw TProtocolException(TProtocolException::NEGATIVE_SIZE);
621 } else if (container_limit_ && sizei > container_limit_) {
David Reissce161a92007-09-11 22:09:42 +0000622 resetState();
David Reiss4e7530d2007-09-04 21:49:53 +0000623 throw TProtocolException(TProtocolException::SIZE_LIMIT);
624 }
625 size = (uint32_t)sizei;
626
627 elemType = ST1->ttype;
628
629 ts_stack_.push_back(ST1);
630
631 return xfer;
632}
633
634uint32_t TDenseProtocol::readListEnd() {
635 ts_stack_.pop_back();
636 stateTransition();
637 return 0;
638}
639
640uint32_t TDenseProtocol::readSetBegin(TType& elemType,
641 uint32_t& size) {
642 checkTType(T_SET);
643
644 uint32_t xfer = 0;
645 int32_t sizei;
646 xfer += subReadI32(sizei);
647 if (sizei < 0) {
David Reissce161a92007-09-11 22:09:42 +0000648 resetState();
David Reiss4e7530d2007-09-04 21:49:53 +0000649 throw TProtocolException(TProtocolException::NEGATIVE_SIZE);
650 } else if (container_limit_ && sizei > container_limit_) {
David Reissce161a92007-09-11 22:09:42 +0000651 resetState();
David Reiss4e7530d2007-09-04 21:49:53 +0000652 throw TProtocolException(TProtocolException::SIZE_LIMIT);
653 }
654 size = (uint32_t)sizei;
655
656 elemType = ST1->ttype;
657
658 ts_stack_.push_back(ST1);
659
660 return xfer;
661}
662
663uint32_t TDenseProtocol::readSetEnd() {
664 ts_stack_.pop_back();
665 stateTransition();
666 return 0;
667}
668
669uint32_t TDenseProtocol::readBool(bool& value) {
670 checkTType(T_BOOL);
671 stateTransition();
672 return TBinaryProtocol::readBool(value);
673}
674
675uint32_t TDenseProtocol::readByte(int8_t& byte) {
676 checkTType(T_BYTE);
677 stateTransition();
678 return TBinaryProtocol::readByte(byte);
679}
680
681uint32_t TDenseProtocol::readI16(int16_t& i16) {
682 checkTType(T_I16);
683 stateTransition();
David Reisse67c0e62007-09-07 01:34:12 +0000684 uint64_t u64;
David Reissce161a92007-09-11 22:09:42 +0000685 uint32_t rv = vlqRead(u64);
David Reisse67c0e62007-09-07 01:34:12 +0000686 int64_t val = (int64_t)u64;
687 if (UNLIKELY(val > INT16_MAX || val < INT16_MIN)) {
David Reissce161a92007-09-11 22:09:42 +0000688 resetState();
David Reisse67c0e62007-09-07 01:34:12 +0000689 throw TProtocolException(TProtocolException::INVALID_DATA,
690 "i16 out of range.");
691 }
692 i16 = (int16_t)val;
693 return rv;
David Reiss4e7530d2007-09-04 21:49:53 +0000694}
695
696uint32_t TDenseProtocol::readI32(int32_t& i32) {
697 checkTType(T_I32);
698 stateTransition();
David Reisse67c0e62007-09-07 01:34:12 +0000699 uint64_t u64;
David Reissce161a92007-09-11 22:09:42 +0000700 uint32_t rv = vlqRead(u64);
David Reisse67c0e62007-09-07 01:34:12 +0000701 int64_t val = (int64_t)u64;
702 if (UNLIKELY(val > INT32_MAX || val < INT32_MIN)) {
David Reissce161a92007-09-11 22:09:42 +0000703 resetState();
David Reisse67c0e62007-09-07 01:34:12 +0000704 throw TProtocolException(TProtocolException::INVALID_DATA,
705 "i32 out of range.");
706 }
707 i32 = (int32_t)val;
708 return rv;
David Reiss4e7530d2007-09-04 21:49:53 +0000709}
710
711uint32_t TDenseProtocol::readI64(int64_t& i64) {
712 checkTType(T_I64);
713 stateTransition();
David Reisse67c0e62007-09-07 01:34:12 +0000714 uint64_t u64;
David Reissce161a92007-09-11 22:09:42 +0000715 uint32_t rv = vlqRead(u64);
David Reisse67c0e62007-09-07 01:34:12 +0000716 int64_t val = (int64_t)u64;
717 if (UNLIKELY(val > INT64_MAX || val < INT64_MIN)) {
David Reissce161a92007-09-11 22:09:42 +0000718 resetState();
David Reisse67c0e62007-09-07 01:34:12 +0000719 throw TProtocolException(TProtocolException::INVALID_DATA,
720 "i64 out of range.");
721 }
722 i64 = (int64_t)val;
723 return rv;
David Reiss4e7530d2007-09-04 21:49:53 +0000724}
725
726uint32_t TDenseProtocol::readDouble(double& dub) {
727 checkTType(T_DOUBLE);
728 stateTransition();
729 return TBinaryProtocol::readDouble(dub);
730}
731
732uint32_t TDenseProtocol::readString(std::string& str) {
733 checkTType(T_STRING);
734 stateTransition();
735 return subReadString(str);
736}
737
David Reissc005b1b2008-02-15 01:38:18 +0000738uint32_t TDenseProtocol::readBinary(std::string& str) {
739 return TDenseProtocol::readString(str);
740}
741
David Reisse67c0e62007-09-07 01:34:12 +0000742uint32_t TDenseProtocol::subReadI32(int32_t& i32) {
743 uint64_t u64;
David Reissce161a92007-09-11 22:09:42 +0000744 uint32_t rv = vlqRead(u64);
David Reisse67c0e62007-09-07 01:34:12 +0000745 int64_t val = (int64_t)u64;
746 if (UNLIKELY(val > INT32_MAX || val < INT32_MIN)) {
David Reissce161a92007-09-11 22:09:42 +0000747 resetState();
David Reisse67c0e62007-09-07 01:34:12 +0000748 throw TProtocolException(TProtocolException::INVALID_DATA,
749 "i32 out of range.");
750 }
751 i32 = (int32_t)val;
752 return rv;
753}
754
755uint32_t TDenseProtocol::subReadString(std::string& str) {
756 uint32_t xfer;
757 int32_t size;
758 xfer = subReadI32(size);
759 return xfer + readStringBody(str, size);
760}
761
T Jake Lucianib5e62212009-01-31 22:36:20 +0000762}}} // apache::thrift::protocol