1 /*
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 */
19
20 #ifndef _THRIFT_PROTOCOL_TBINARYPROTOCOL_TCC_
21 #define _THRIFT_PROTOCOL_TBINARYPROTOCOL_TCC_ 1
22
23 #include <thrift/protocol/TBinaryProtocol.h>
24 #include <thrift/transport/TTransportException.h>
25
26 #include <limits>
27
28 namespace apache {
29 namespace thrift {
30 namespace protocol {
31
32 template <class Transport_, class ByteOrder_>
writeMessageBegin(const std::string & name,const TMessageType messageType,const int32_t seqid)33 uint32_t TBinaryProtocolT<Transport_, ByteOrder_>::writeMessageBegin(const std::string& name,
34 const TMessageType messageType,
35 const int32_t seqid) {
36 if (this->strict_write_) {
37 int32_t version = (VERSION_1) | ((int32_t)messageType);
38 uint32_t wsize = 0;
39 wsize += writeI32(version);
40 wsize += writeString(name);
41 wsize += writeI32(seqid);
42 return wsize;
43 } else {
44 uint32_t wsize = 0;
45 wsize += writeString(name);
46 wsize += writeByte((int8_t)messageType);
47 wsize += writeI32(seqid);
48 return wsize;
49 }
50 }
51
52 template <class Transport_, class ByteOrder_>
writeMessageEnd()53 uint32_t TBinaryProtocolT<Transport_, ByteOrder_>::writeMessageEnd() {
54 return 0;
55 }
56
57 template <class Transport_, class ByteOrder_>
writeStructBegin(const char * name)58 uint32_t TBinaryProtocolT<Transport_, ByteOrder_>::writeStructBegin(const char* name) {
59 (void)name;
60 return 0;
61 }
62
63 template <class Transport_, class ByteOrder_>
writeStructEnd()64 uint32_t TBinaryProtocolT<Transport_, ByteOrder_>::writeStructEnd() {
65 return 0;
66 }
67
68 template <class Transport_, class ByteOrder_>
writeFieldBegin(const char * name,const TType fieldType,const int16_t fieldId)69 uint32_t TBinaryProtocolT<Transport_, ByteOrder_>::writeFieldBegin(const char* name,
70 const TType fieldType,
71 const int16_t fieldId) {
72 (void)name;
73 uint32_t wsize = 0;
74 wsize += writeByte((int8_t)fieldType);
75 wsize += writeI16(fieldId);
76 return wsize;
77 }
78
79 template <class Transport_, class ByteOrder_>
writeFieldEnd()80 uint32_t TBinaryProtocolT<Transport_, ByteOrder_>::writeFieldEnd() {
81 return 0;
82 }
83
84 template <class Transport_, class ByteOrder_>
writeFieldStop()85 uint32_t TBinaryProtocolT<Transport_, ByteOrder_>::writeFieldStop() {
86 return writeByte((int8_t)T_STOP);
87 }
88
89 template <class Transport_, class ByteOrder_>
writeMapBegin(const TType keyType,const TType valType,const uint32_t size)90 uint32_t TBinaryProtocolT<Transport_, ByteOrder_>::writeMapBegin(const TType keyType,
91 const TType valType,
92 const uint32_t size) {
93 uint32_t wsize = 0;
94 wsize += writeByte((int8_t)keyType);
95 wsize += writeByte((int8_t)valType);
96 wsize += writeI32((int32_t)size);
97 return wsize;
98 }
99
100 template <class Transport_, class ByteOrder_>
writeMapEnd()101 uint32_t TBinaryProtocolT<Transport_, ByteOrder_>::writeMapEnd() {
102 return 0;
103 }
104
105 template <class Transport_, class ByteOrder_>
writeListBegin(const TType elemType,const uint32_t size)106 uint32_t TBinaryProtocolT<Transport_, ByteOrder_>::writeListBegin(const TType elemType,
107 const uint32_t size) {
108 uint32_t wsize = 0;
109 wsize += writeByte((int8_t)elemType);
110 wsize += writeI32((int32_t)size);
111 return wsize;
112 }
113
114 template <class Transport_, class ByteOrder_>
writeListEnd()115 uint32_t TBinaryProtocolT<Transport_, ByteOrder_>::writeListEnd() {
116 return 0;
117 }
118
119 template <class Transport_, class ByteOrder_>
writeSetBegin(const TType elemType,const uint32_t size)120 uint32_t TBinaryProtocolT<Transport_, ByteOrder_>::writeSetBegin(const TType elemType,
121 const uint32_t size) {
122 uint32_t wsize = 0;
123 wsize += writeByte((int8_t)elemType);
124 wsize += writeI32((int32_t)size);
125 return wsize;
126 }
127
128 template <class Transport_, class ByteOrder_>
writeSetEnd()129 uint32_t TBinaryProtocolT<Transport_, ByteOrder_>::writeSetEnd() {
130 return 0;
131 }
132
133 template <class Transport_, class ByteOrder_>
writeBool(const bool value)134 uint32_t TBinaryProtocolT<Transport_, ByteOrder_>::writeBool(const bool value) {
135 uint8_t tmp = value ? 1 : 0;
136 this->trans_->write(&tmp, 1);
137 return 1;
138 }
139
140 template <class Transport_, class ByteOrder_>
writeByte(const int8_t byte)141 uint32_t TBinaryProtocolT<Transport_, ByteOrder_>::writeByte(const int8_t byte) {
142 this->trans_->write((uint8_t*)&byte, 1);
143 return 1;
144 }
145
146 template <class Transport_, class ByteOrder_>
writeI16(const int16_t i16)147 uint32_t TBinaryProtocolT<Transport_, ByteOrder_>::writeI16(const int16_t i16) {
148 auto net = (int16_t)ByteOrder_::toWire16(i16);
149 this->trans_->write((uint8_t*)&net, 2);
150 return 2;
151 }
152
153 template <class Transport_, class ByteOrder_>
writeI32(const int32_t i32)154 uint32_t TBinaryProtocolT<Transport_, ByteOrder_>::writeI32(const int32_t i32) {
155 auto net = (int32_t)ByteOrder_::toWire32(i32);
156 this->trans_->write((uint8_t*)&net, 4);
157 return 4;
158 }
159
160 template <class Transport_, class ByteOrder_>
writeI64(const int64_t i64)161 uint32_t TBinaryProtocolT<Transport_, ByteOrder_>::writeI64(const int64_t i64) {
162 auto net = (int64_t)ByteOrder_::toWire64(i64);
163 this->trans_->write((uint8_t*)&net, 8);
164 return 8;
165 }
166
167 template <class Transport_, class ByteOrder_>
writeDouble(const double dub)168 uint32_t TBinaryProtocolT<Transport_, ByteOrder_>::writeDouble(const double dub) {
169 static_assert(sizeof(double) == sizeof(uint64_t), "sizeof(double) == sizeof(uint64_t)");
170 static_assert(std::numeric_limits<double>::is_iec559, "std::numeric_limits<double>::is_iec559");
171
172 auto bits = bitwise_cast<uint64_t>(dub);
173 bits = ByteOrder_::toWire64(bits);
174 this->trans_->write((uint8_t*)&bits, 8);
175 return 8;
176 }
177
178 template <class Transport_, class ByteOrder_>
179 template <typename StrType>
writeString(const StrType & str)180 uint32_t TBinaryProtocolT<Transport_, ByteOrder_>::writeString(const StrType& str) {
181 if (str.size() > static_cast<size_t>((std::numeric_limits<int32_t>::max)()))
182 throw TProtocolException(TProtocolException::SIZE_LIMIT);
183 auto size = static_cast<uint32_t>(str.size());
184 uint32_t result = writeI32((int32_t)size);
185 if (size > 0) {
186 this->trans_->write((uint8_t*)str.data(), size);
187 }
188 return result + size;
189 }
190
191 template <class Transport_, class ByteOrder_>
writeBinary(const std::string & str)192 uint32_t TBinaryProtocolT<Transport_, ByteOrder_>::writeBinary(const std::string& str) {
193 return TBinaryProtocolT<Transport_, ByteOrder_>::writeString(str);
194 }
195
196 /**
197 * Reading functions
198 */
199
200 template <class Transport_, class ByteOrder_>
readMessageBegin(std::string & name,TMessageType & messageType,int32_t & seqid)201 uint32_t TBinaryProtocolT<Transport_, ByteOrder_>::readMessageBegin(std::string& name,
202 TMessageType& messageType,
203 int32_t& seqid) {
204 uint32_t result = 0;
205 int32_t sz;
206 result += readI32(sz);
207
208 if (sz < 0) {
209 // Check for correct version number
210 int32_t version = sz & VERSION_MASK;
211 if (version != VERSION_1) {
212 throw TProtocolException(TProtocolException::BAD_VERSION, "Bad version identifier");
213 }
214 messageType = (TMessageType)(sz & 0x000000ff);
215 result += readString(name);
216 result += readI32(seqid);
217 } else {
218 if (this->strict_read_) {
219 throw TProtocolException(TProtocolException::BAD_VERSION,
220 "No version identifier... old protocol client in strict mode?");
221 } else {
222 // Handle pre-versioned input
223 int8_t type;
224 result += readStringBody(name, sz);
225 result += readByte(type);
226 messageType = (TMessageType)type;
227 result += readI32(seqid);
228 }
229 }
230 return result;
231 }
232
233 template <class Transport_, class ByteOrder_>
readMessageEnd()234 uint32_t TBinaryProtocolT<Transport_, ByteOrder_>::readMessageEnd() {
235 return 0;
236 }
237
238 template <class Transport_, class ByteOrder_>
readStructBegin(std::string & name)239 uint32_t TBinaryProtocolT<Transport_, ByteOrder_>::readStructBegin(std::string& name) {
240 name = "";
241 return 0;
242 }
243
244 template <class Transport_, class ByteOrder_>
readStructEnd()245 uint32_t TBinaryProtocolT<Transport_, ByteOrder_>::readStructEnd() {
246 return 0;
247 }
248
249 template <class Transport_, class ByteOrder_>
readFieldBegin(std::string & name,TType & fieldType,int16_t & fieldId)250 uint32_t TBinaryProtocolT<Transport_, ByteOrder_>::readFieldBegin(std::string& name,
251 TType& fieldType,
252 int16_t& fieldId) {
253 (void)name;
254 uint32_t result = 0;
255 int8_t type;
256 result += readByte(type);
257 fieldType = (TType)type;
258 if (fieldType == T_STOP) {
259 fieldId = 0;
260 return result;
261 }
262 result += readI16(fieldId);
263 return result;
264 }
265
266 template <class Transport_, class ByteOrder_>
readFieldEnd()267 uint32_t TBinaryProtocolT<Transport_, ByteOrder_>::readFieldEnd() {
268 return 0;
269 }
270
271 template <class Transport_, class ByteOrder_>
readMapBegin(TType & keyType,TType & valType,uint32_t & size)272 uint32_t TBinaryProtocolT<Transport_, ByteOrder_>::readMapBegin(TType& keyType,
273 TType& valType,
274 uint32_t& size) {
275 int8_t k, v;
276 uint32_t result = 0;
277 int32_t sizei;
278 result += readByte(k);
279 keyType = (TType)k;
280 result += readByte(v);
281 valType = (TType)v;
282 result += readI32(sizei);
283 if (sizei < 0) {
284 throw TProtocolException(TProtocolException::NEGATIVE_SIZE);
285 } else if (this->container_limit_ && sizei > this->container_limit_) {
286 throw TProtocolException(TProtocolException::SIZE_LIMIT);
287 }
288 size = (uint32_t)sizei;
289
290 TMap map(keyType, valType, size);
291 checkReadBytesAvailable(map);
292
293 return result;
294 }
295
296 template <class Transport_, class ByteOrder_>
readMapEnd()297 uint32_t TBinaryProtocolT<Transport_, ByteOrder_>::readMapEnd() {
298 return 0;
299 }
300
301 template <class Transport_, class ByteOrder_>
readListBegin(TType & elemType,uint32_t & size)302 uint32_t TBinaryProtocolT<Transport_, ByteOrder_>::readListBegin(TType& elemType, uint32_t& size) {
303 int8_t e;
304 uint32_t result = 0;
305 int32_t sizei;
306 result += readByte(e);
307 elemType = (TType)e;
308 result += readI32(sizei);
309 if (sizei < 0) {
310 throw TProtocolException(TProtocolException::NEGATIVE_SIZE);
311 } else if (this->container_limit_ && sizei > this->container_limit_) {
312 throw TProtocolException(TProtocolException::SIZE_LIMIT);
313 }
314 size = (uint32_t)sizei;
315
316 TList list(elemType, size);
317 checkReadBytesAvailable(list);
318
319 return result;
320 }
321
322 template <class Transport_, class ByteOrder_>
readListEnd()323 uint32_t TBinaryProtocolT<Transport_, ByteOrder_>::readListEnd() {
324 return 0;
325 }
326
327 template <class Transport_, class ByteOrder_>
readSetBegin(TType & elemType,uint32_t & size)328 uint32_t TBinaryProtocolT<Transport_, ByteOrder_>::readSetBegin(TType& elemType, uint32_t& size) {
329 int8_t e;
330 uint32_t result = 0;
331 int32_t sizei;
332 result += readByte(e);
333 elemType = (TType)e;
334 result += readI32(sizei);
335 if (sizei < 0) {
336 throw TProtocolException(TProtocolException::NEGATIVE_SIZE);
337 } else if (this->container_limit_ && sizei > this->container_limit_) {
338 throw TProtocolException(TProtocolException::SIZE_LIMIT);
339 }
340 size = (uint32_t)sizei;
341
342 TSet set(elemType, size);
343 checkReadBytesAvailable(set);
344
345 return result;
346 }
347
348 template <class Transport_, class ByteOrder_>
readSetEnd()349 uint32_t TBinaryProtocolT<Transport_, ByteOrder_>::readSetEnd() {
350 return 0;
351 }
352
353 template <class Transport_, class ByteOrder_>
readBool(bool & value)354 uint32_t TBinaryProtocolT<Transport_, ByteOrder_>::readBool(bool& value) {
355 uint8_t b[1];
356 this->trans_->readAll(b, 1);
357 value = *(int8_t*)b != 0;
358 return 1;
359 }
360
361 template <class Transport_, class ByteOrder_>
readByte(int8_t & byte)362 uint32_t TBinaryProtocolT<Transport_, ByteOrder_>::readByte(int8_t& byte) {
363 uint8_t b[1];
364 this->trans_->readAll(b, 1);
365 byte = *(int8_t*)b;
366 return 1;
367 }
368
369 template <class Transport_, class ByteOrder_>
readI16(int16_t & i16)370 uint32_t TBinaryProtocolT<Transport_, ByteOrder_>::readI16(int16_t& i16) {
371 union bytes {
372 uint8_t b[2];
373 int16_t all;
374 } theBytes;
375 this->trans_->readAll(theBytes.b, 2);
376 i16 = (int16_t)ByteOrder_::fromWire16(theBytes.all);
377 return 2;
378 }
379
380 template <class Transport_, class ByteOrder_>
readI32(int32_t & i32)381 uint32_t TBinaryProtocolT<Transport_, ByteOrder_>::readI32(int32_t& i32) {
382 union bytes {
383 uint8_t b[4];
384 int32_t all;
385 } theBytes;
386 this->trans_->readAll(theBytes.b, 4);
387 i32 = (int32_t)ByteOrder_::fromWire32(theBytes.all);
388 return 4;
389 }
390
391 template <class Transport_, class ByteOrder_>
readI64(int64_t & i64)392 uint32_t TBinaryProtocolT<Transport_, ByteOrder_>::readI64(int64_t& i64) {
393 union bytes {
394 uint8_t b[8];
395 int64_t all;
396 } theBytes;
397 this->trans_->readAll(theBytes.b, 8);
398 i64 = (int64_t)ByteOrder_::fromWire64(theBytes.all);
399 return 8;
400 }
401
402 template <class Transport_, class ByteOrder_>
readDouble(double & dub)403 uint32_t TBinaryProtocolT<Transport_, ByteOrder_>::readDouble(double& dub) {
404 static_assert(sizeof(double) == sizeof(uint64_t), "sizeof(double) == sizeof(uint64_t)");
405 static_assert(std::numeric_limits<double>::is_iec559, "std::numeric_limits<double>::is_iec559");
406
407 union bytes {
408 uint8_t b[8];
409 uint64_t all;
410 } theBytes;
411 this->trans_->readAll(theBytes.b, 8);
412 theBytes.all = ByteOrder_::fromWire64(theBytes.all);
413 dub = bitwise_cast<double>(theBytes.all);
414 return 8;
415 }
416
417 template <class Transport_, class ByteOrder_>
418 template <typename StrType>
readString(StrType & str)419 uint32_t TBinaryProtocolT<Transport_, ByteOrder_>::readString(StrType& str) {
420 uint32_t result;
421 int32_t size;
422 result = readI32(size);
423 return result + readStringBody(str, size);
424 }
425
426 template <class Transport_, class ByteOrder_>
readBinary(std::string & str)427 uint32_t TBinaryProtocolT<Transport_, ByteOrder_>::readBinary(std::string& str) {
428 return TBinaryProtocolT<Transport_, ByteOrder_>::readString(str);
429 }
430
431 template <class Transport_, class ByteOrder_>
432 template <typename StrType>
readStringBody(StrType & str,int32_t size)433 uint32_t TBinaryProtocolT<Transport_, ByteOrder_>::readStringBody(StrType& str, int32_t size) {
434 uint32_t result = 0;
435
436 // Catch error cases
437 if (size < 0) {
438 throw TProtocolException(TProtocolException::NEGATIVE_SIZE);
439 }
440 if (this->string_limit_ > 0 && size > this->string_limit_) {
441 throw TProtocolException(TProtocolException::SIZE_LIMIT);
442 }
443
444 // Catch empty string case
445 if (size == 0) {
446 str.clear();
447 return result;
448 }
449
450 // Try to borrow first
451 const uint8_t* borrow_buf;
452 uint32_t got = size;
453 if ((borrow_buf = this->trans_->borrow(nullptr, &got))) {
454 str.assign((const char*)borrow_buf, size);
455 this->trans_->consume(size);
456 return size;
457 }
458
459 str.resize(size);
460 this->trans_->readAll(reinterpret_cast<uint8_t*>(&str[0]), size);
461 return (uint32_t)size;
462 }
463
464 // Return the minimum number of bytes a type will consume on the wire
465 template <class Transport_, class ByteOrder_>
getMinSerializedSize(TType type)466 int TBinaryProtocolT<Transport_, ByteOrder_>::getMinSerializedSize(TType type)
467 {
468 switch (type)
469 {
470 case T_STOP: return 0;
471 case T_VOID: return 0;
472 case T_BOOL: return sizeof(int8_t);
473 case T_BYTE: return sizeof(int8_t);
474 case T_DOUBLE: return sizeof(double);
475 case T_I16: return sizeof(short);
476 case T_I32: return sizeof(int);
477 case T_I64: return sizeof(long);
478 case T_STRING: return sizeof(int); // string length
479 case T_STRUCT: return 0; // empty struct
480 case T_MAP: return sizeof(int); // element count
481 case T_SET: return sizeof(int); // element count
482 case T_LIST: return sizeof(int); // element count
483 default: throw TProtocolException(TProtocolException::UNKNOWN, "unrecognized type code");
484 }
485 }
486
487 }
488 }
489 } // apache::thrift::protocol
490
491 #endif // #ifndef _THRIFT_PROTOCOL_TBINARYPROTOCOL_TCC_
492