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