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_TCOMPACTPROTOCOL_H_ |
21 | #define _THRIFT_PROTOCOL_TCOMPACTPROTOCOL_H_ 1 |
22 | |
23 | #include <thrift/protocol/TVirtualProtocol.h> |
24 | |
25 | #include <stack> |
26 | #include <memory> |
27 | |
28 | namespace apache { |
29 | namespace thrift { |
30 | namespace protocol { |
31 | |
32 | /** |
33 | * C++ Implementation of the Compact Protocol as described in THRIFT-110 |
34 | */ |
35 | template <class Transport_> |
36 | class TCompactProtocolT : public TVirtualProtocol<TCompactProtocolT<Transport_> > { |
37 | public: |
38 | static const int8_t PROTOCOL_ID = (int8_t)0x82u; |
39 | static const int8_t VERSION_N = 1; |
40 | static const int8_t VERSION_MASK = 0x1f; // 0001 1111 |
41 | |
42 | protected: |
43 | static const int8_t TYPE_MASK = (int8_t)0xE0u; // 1110 0000 |
44 | static const int8_t TYPE_BITS = 0x07; // 0000 0111 |
45 | static const int32_t TYPE_SHIFT_AMOUNT = 5; |
46 | |
47 | Transport_* trans_; |
48 | |
49 | /** |
50 | * (Writing) If we encounter a boolean field begin, save the TField here |
51 | * so it can have the value incorporated. |
52 | */ |
53 | struct { |
54 | const char* name; |
55 | TType fieldType; |
56 | int16_t fieldId; |
57 | } booleanField_; |
58 | |
59 | /** |
60 | * (Reading) If we read a field header, and it's a boolean field, save |
61 | * the boolean value here so that readBool can use it. |
62 | */ |
63 | struct { |
64 | bool hasBoolValue; |
65 | bool boolValue; |
66 | } boolValue_; |
67 | |
68 | /** |
69 | * Used to keep track of the last field for the current and previous structs, |
70 | * so we can do the delta stuff. |
71 | */ |
72 | |
73 | std::stack<int16_t> lastField_; |
74 | int16_t lastFieldId_; |
75 | |
76 | public: |
77 | TCompactProtocolT(std::shared_ptr<Transport_> trans) |
78 | : TVirtualProtocol<TCompactProtocolT<Transport_> >(trans), |
79 | trans_(trans.get()), |
80 | lastFieldId_(0), |
81 | string_limit_(0), |
82 | string_buf_(nullptr), |
83 | string_buf_size_(0), |
84 | container_limit_(0) { |
85 | booleanField_.name = nullptr; |
86 | boolValue_.hasBoolValue = false; |
87 | } |
88 | |
89 | TCompactProtocolT(std::shared_ptr<Transport_> trans, |
90 | int32_t string_limit, |
91 | int32_t container_limit) |
92 | : TVirtualProtocol<TCompactProtocolT<Transport_> >(trans), |
93 | trans_(trans.get()), |
94 | lastFieldId_(0), |
95 | string_limit_(string_limit), |
96 | string_buf_(nullptr), |
97 | string_buf_size_(0), |
98 | container_limit_(container_limit) { |
99 | booleanField_.name = nullptr; |
100 | boolValue_.hasBoolValue = false; |
101 | } |
102 | |
103 | ~TCompactProtocolT() override { free(string_buf_); } |
104 | |
105 | /** |
106 | * Writing functions |
107 | */ |
108 | |
109 | virtual uint32_t writeMessageBegin(const std::string& name, |
110 | const TMessageType messageType, |
111 | const int32_t seqid); |
112 | |
113 | uint32_t writeStructBegin(const char* name); |
114 | |
115 | uint32_t writeStructEnd(); |
116 | |
117 | uint32_t writeFieldBegin(const char* name, const TType fieldType, const int16_t fieldId); |
118 | |
119 | uint32_t writeFieldStop(); |
120 | |
121 | uint32_t writeListBegin(const TType elemType, const uint32_t size); |
122 | |
123 | uint32_t writeSetBegin(const TType elemType, const uint32_t size); |
124 | |
125 | virtual uint32_t writeMapBegin(const TType keyType, const TType valType, const uint32_t size); |
126 | |
127 | uint32_t writeBool(const bool value); |
128 | |
129 | uint32_t writeByte(const int8_t byte); |
130 | |
131 | uint32_t writeI16(const int16_t i16); |
132 | |
133 | uint32_t writeI32(const int32_t i32); |
134 | |
135 | uint32_t writeI64(const int64_t i64); |
136 | |
137 | uint32_t writeDouble(const double dub); |
138 | |
139 | uint32_t writeString(const std::string& str); |
140 | |
141 | uint32_t writeBinary(const std::string& str); |
142 | |
143 | /** |
144 | * These methods are called by structs, but don't actually have any wired |
145 | * output or purpose |
146 | */ |
147 | virtual uint32_t writeMessageEnd() { return 0; } |
148 | uint32_t writeMapEnd() { return 0; } |
149 | uint32_t writeListEnd() { return 0; } |
150 | uint32_t writeSetEnd() { return 0; } |
151 | uint32_t writeFieldEnd() { return 0; } |
152 | |
153 | protected: |
154 | int32_t writeFieldBeginInternal(const char* name, |
155 | const TType fieldType, |
156 | const int16_t fieldId, |
157 | int8_t typeOverride); |
158 | uint32_t writeCollectionBegin(const TType elemType, int32_t size); |
159 | uint32_t writeVarint32(uint32_t n); |
160 | uint32_t writeVarint64(uint64_t n); |
161 | uint64_t i64ToZigzag(const int64_t l); |
162 | uint32_t i32ToZigzag(const int32_t n); |
163 | inline int8_t getCompactType(const TType ttype); |
164 | |
165 | public: |
166 | uint32_t readMessageBegin(std::string& name, TMessageType& messageType, int32_t& seqid); |
167 | |
168 | uint32_t readStructBegin(std::string& name); |
169 | |
170 | uint32_t readStructEnd(); |
171 | |
172 | uint32_t readFieldBegin(std::string& name, TType& fieldType, int16_t& fieldId); |
173 | |
174 | uint32_t readMapBegin(TType& keyType, TType& valType, uint32_t& size); |
175 | |
176 | uint32_t readListBegin(TType& elemType, uint32_t& size); |
177 | |
178 | uint32_t readSetBegin(TType& elemType, uint32_t& size); |
179 | |
180 | uint32_t readBool(bool& value); |
181 | // Provide the default readBool() implementation for std::vector<bool> |
182 | using TVirtualProtocol<TCompactProtocolT<Transport_> >::readBool; |
183 | |
184 | uint32_t readByte(int8_t& byte); |
185 | |
186 | uint32_t readI16(int16_t& i16); |
187 | |
188 | uint32_t readI32(int32_t& i32); |
189 | |
190 | uint32_t readI64(int64_t& i64); |
191 | |
192 | uint32_t readDouble(double& dub); |
193 | |
194 | uint32_t readString(std::string& str); |
195 | |
196 | uint32_t readBinary(std::string& str); |
197 | |
198 | /* |
199 | *These methods are here for the struct to call, but don't have any wire |
200 | * encoding. |
201 | */ |
202 | uint32_t readMessageEnd() { return 0; } |
203 | uint32_t readFieldEnd() { return 0; } |
204 | uint32_t readMapEnd() { return 0; } |
205 | uint32_t readListEnd() { return 0; } |
206 | uint32_t readSetEnd() { return 0; } |
207 | |
208 | protected: |
209 | uint32_t readVarint32(int32_t& i32); |
210 | uint32_t readVarint64(int64_t& i64); |
211 | int32_t zigzagToI32(uint32_t n); |
212 | int64_t zigzagToI64(uint64_t n); |
213 | TType getTType(int8_t type); |
214 | |
215 | // Buffer for reading strings, save for the lifetime of the protocol to |
216 | // avoid memory churn allocating memory on every string read |
217 | int32_t string_limit_; |
218 | uint8_t* string_buf_; |
219 | int32_t string_buf_size_; |
220 | int32_t container_limit_; |
221 | }; |
222 | |
223 | typedef TCompactProtocolT<TTransport> TCompactProtocol; |
224 | |
225 | /** |
226 | * Constructs compact protocol handlers |
227 | */ |
228 | template <class Transport_> |
229 | class TCompactProtocolFactoryT : public TProtocolFactory { |
230 | public: |
231 | TCompactProtocolFactoryT() : string_limit_(0), container_limit_(0) {} |
232 | |
233 | TCompactProtocolFactoryT(int32_t string_limit, int32_t container_limit) |
234 | : string_limit_(string_limit), container_limit_(container_limit) {} |
235 | |
236 | ~TCompactProtocolFactoryT() override = default; |
237 | |
238 | void setStringSizeLimit(int32_t string_limit) { string_limit_ = string_limit; } |
239 | |
240 | void setContainerSizeLimit(int32_t container_limit) { container_limit_ = container_limit; } |
241 | |
242 | std::shared_ptr<TProtocol> getProtocol(std::shared_ptr<TTransport> trans) override { |
243 | std::shared_ptr<Transport_> specific_trans = std::dynamic_pointer_cast<Transport_>(trans); |
244 | TProtocol* prot; |
245 | if (specific_trans) { |
246 | prot = new TCompactProtocolT<Transport_>(specific_trans, string_limit_, container_limit_); |
247 | } else { |
248 | prot = new TCompactProtocol(trans, string_limit_, container_limit_); |
249 | } |
250 | |
251 | return std::shared_ptr<TProtocol>(prot); |
252 | } |
253 | |
254 | private: |
255 | int32_t string_limit_; |
256 | int32_t container_limit_; |
257 | }; |
258 | |
259 | typedef TCompactProtocolFactoryT<TTransport> TCompactProtocolFactory; |
260 | } |
261 | } |
262 | } // apache::thrift::protocol |
263 | |
264 | #include <thrift/protocol/TCompactProtocol.tcc> |
265 | |
266 | #endif |
267 | |