blob: 8f72b0925963f4418959080298545515e9d1cbcb [file] [log] [blame]
Nobuaki Sukegawa6525f6a2016-02-11 13:58:39 +09001/*
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_PY_COMPACT_H
21#define THRIFT_PY_COMPACT_H
22
23#include <Python.h>
24#include "ext/protocol.h"
25#include "ext/endian.h"
26#include <stdint.h>
27#include <stack>
28
29namespace apache {
30namespace thrift {
31namespace py {
32
33class CompactProtocol : public ProtocolBase<CompactProtocol> {
34public:
35 CompactProtocol() { readBool_.exists = false; }
36
37 virtual ~CompactProtocol() {}
38
39 void writeI8(int8_t val) { writeBuffer(reinterpret_cast<char*>(&val), 1); }
40
41 void writeI16(int16_t val) { writeVarint(toZigZag(val)); }
42
43 int writeI32(int32_t val) { return writeVarint(toZigZag(val)); }
44
45 void writeI64(int64_t val) { writeVarint64(toZigZag64(val)); }
46
47 void writeDouble(double dub) {
48 union {
49 double f;
50 int64_t t;
51 } transfer;
George Koehler1e17c932023-02-06 18:08:05 -050052 transfer.f = dub;
53 transfer.t = htolell(transfer.t);
Nobuaki Sukegawa6525f6a2016-02-11 13:58:39 +090054 writeBuffer(reinterpret_cast<char*>(&transfer.t), sizeof(int64_t));
55 }
56
57 void writeBool(int v) { writeByte(static_cast<uint8_t>(v ? CT_BOOLEAN_TRUE : CT_BOOLEAN_FALSE)); }
58
59 void writeString(PyObject* value, int32_t len) {
60 writeVarint(len);
61 writeBuffer(PyBytes_AS_STRING(value), len);
62 }
63
64 bool writeListBegin(PyObject* value, const SetListTypeArgs& args, int32_t len) {
65 int ctype = toCompactType(args.element_type);
66 if (len <= 14) {
67 writeByte(static_cast<uint8_t>(len << 4 | ctype));
68 } else {
69 writeByte(0xf0 | ctype);
70 writeVarint(len);
71 }
72 return true;
73 }
74
75 bool writeMapBegin(PyObject* value, const MapTypeArgs& args, int32_t len) {
76 if (len == 0) {
77 writeByte(0);
78 return true;
79 }
80 int ctype = toCompactType(args.ktag) << 4 | toCompactType(args.vtag);
81 writeVarint(len);
82 writeByte(ctype);
83 return true;
84 }
85
86 bool writeStructBegin() {
87 writeTags_.push(0);
88 return true;
89 }
90 bool writeStructEnd() {
91 writeTags_.pop();
92 return true;
93 }
94
95 bool writeField(PyObject* value, const StructItemSpec& spec) {
96 if (spec.type == T_BOOL) {
97 doWriteFieldBegin(spec, PyObject_IsTrue(value) ? CT_BOOLEAN_TRUE : CT_BOOLEAN_FALSE);
98 return true;
99 } else {
100 doWriteFieldBegin(spec, toCompactType(spec.type));
101 return encodeValue(value, spec.type, spec.typeargs);
102 }
103 }
104
105 void writeFieldStop() { writeByte(0); }
106
107 bool readBool(bool& val) {
108 if (readBool_.exists) {
109 readBool_.exists = false;
110 val = readBool_.value;
111 return true;
112 }
113 char* buf;
114 if (!readBytes(&buf, 1)) {
115 return false;
116 }
117 val = buf[0] == CT_BOOLEAN_TRUE;
118 return true;
119 }
120 bool readI8(int8_t& val) {
121 char* buf;
122 if (!readBytes(&buf, 1)) {
123 return false;
124 }
125 val = buf[0];
126 return true;
127 }
128
129 bool readI16(int16_t& val) {
130 uint16_t uval;
131 if (readVarint<uint16_t, 3>(uval)) {
132 val = fromZigZag<int16_t, uint16_t>(uval);
133 return true;
134 }
135 return false;
136 }
137
138 bool readI32(int32_t& val) {
139 uint32_t uval;
140 if (readVarint<uint32_t, 5>(uval)) {
141 val = fromZigZag<int32_t, uint32_t>(uval);
142 return true;
143 }
144 return false;
145 }
146
147 bool readI64(int64_t& val) {
148 uint64_t uval;
149 if (readVarint<uint64_t, 10>(uval)) {
150 val = fromZigZag<int64_t, uint64_t>(uval);
151 return true;
152 }
153 return false;
154 }
155
156 bool readDouble(double& val) {
157 union {
158 int64_t f;
159 double t;
160 } transfer;
161
162 char* buf;
163 if (!readBytes(&buf, 8)) {
164 return false;
165 }
James E. King, III0ad20bd2017-09-30 15:44:16 -0700166 memcpy(&transfer.f, buf, sizeof(int64_t));
167 transfer.f = letohll(transfer.f);
Nobuaki Sukegawa6525f6a2016-02-11 13:58:39 +0900168 val = transfer.t;
169 return true;
170 }
171
172 int32_t readString(char** buf) {
173 uint32_t len;
174 if (!readVarint<uint32_t, 5>(len) || !checkLengthLimit(len, stringLimit())) {
175 return -1;
176 }
177 if (len == 0) {
178 return 0;
179 }
180 if (!readBytes(buf, len)) {
181 return -1;
182 }
183 return len;
184 }
185
186 int32_t readListBegin(TType& etype) {
187 uint8_t b;
188 if (!readByte(b)) {
189 return -1;
190 }
191 etype = getTType(b & 0xf);
192 if (etype == -1) {
193 return -1;
194 }
195 uint32_t len = (b >> 4) & 0xf;
196 if (len == 15 && !readVarint<uint32_t, 5>(len)) {
197 return -1;
198 }
199 if (!checkLengthLimit(len, containerLimit())) {
200 return -1;
201 }
202 return len;
203 }
204
205 int32_t readMapBegin(TType& ktype, TType& vtype) {
206 uint32_t len;
207 if (!readVarint<uint32_t, 5>(len) || !checkLengthLimit(len, containerLimit())) {
208 return -1;
209 }
210 if (len != 0) {
211 uint8_t kvType;
212 if (!readByte(kvType)) {
213 return -1;
214 }
215 ktype = getTType(kvType >> 4);
216 vtype = getTType(kvType & 0xf);
217 if (ktype == -1 || vtype == -1) {
218 return -1;
219 }
220 }
221 return len;
222 }
223
224 bool readStructBegin() {
225 readTags_.push(0);
226 return true;
227 }
228 bool readStructEnd() {
229 readTags_.pop();
230 return true;
231 }
232 bool readFieldBegin(TType& type, int16_t& tag);
233
234 bool skipBool() {
235 bool val;
236 return readBool(val);
237 }
238#define SKIPBYTES(n) \
239 do { \
240 if (!readBytes(&dummy_buf_, (n))) { \
241 return false; \
242 } \
243 return true; \
244 } while (0)
245 bool skipByte() { SKIPBYTES(1); }
246 bool skipDouble() { SKIPBYTES(8); }
247 bool skipI16() {
248 int16_t val;
249 return readI16(val);
250 }
251 bool skipI32() {
252 int32_t val;
253 return readI32(val);
254 }
255 bool skipI64() {
256 int64_t val;
257 return readI64(val);
258 }
259 bool skipString() {
260 uint32_t len;
261 if (!readVarint<uint32_t, 5>(len)) {
262 return false;
263 }
264 SKIPBYTES(len);
265 }
266#undef SKIPBYTES
267
268private:
269 enum Types {
270 CT_STOP = 0x00,
271 CT_BOOLEAN_TRUE = 0x01,
272 CT_BOOLEAN_FALSE = 0x02,
273 CT_BYTE = 0x03,
274 CT_I16 = 0x04,
275 CT_I32 = 0x05,
276 CT_I64 = 0x06,
277 CT_DOUBLE = 0x07,
278 CT_BINARY = 0x08,
279 CT_LIST = 0x09,
280 CT_SET = 0x0A,
281 CT_MAP = 0x0B,
282 CT_STRUCT = 0x0C
283 };
284
285 static const uint8_t TTypeToCType[];
286
287 TType getTType(uint8_t type);
288
289 int toCompactType(TType type) {
290 int i = static_cast<int>(type);
291 return i < 16 ? TTypeToCType[i] : -1;
292 }
293
294 uint32_t toZigZag(int32_t val) { return (val >> 31) ^ (val << 1); }
295
296 uint64_t toZigZag64(int64_t val) { return (val >> 63) ^ (val << 1); }
297
298 int writeVarint(uint32_t val) {
299 int cnt = 1;
300 while (val & ~0x7fU) {
301 writeByte(static_cast<char>((val & 0x7fU) | 0x80U));
302 val >>= 7;
303 ++cnt;
304 }
305 writeByte(static_cast<char>(val));
306 return cnt;
307 }
308
309 int writeVarint64(uint64_t val) {
310 int cnt = 1;
311 while (val & ~0x7fULL) {
312 writeByte(static_cast<char>((val & 0x7fULL) | 0x80ULL));
313 val >>= 7;
314 ++cnt;
315 }
316 writeByte(static_cast<char>(val));
317 return cnt;
318 }
319
320 template <typename T, int Max>
321 bool readVarint(T& result) {
322 uint8_t b;
323 T val = 0;
324 int shift = 0;
325 for (int i = 0; i < Max; ++i) {
326 if (!readByte(b)) {
327 return false;
328 }
329 if (b & 0x80) {
330 val |= static_cast<T>(b & 0x7f) << shift;
331 } else {
332 val |= static_cast<T>(b) << shift;
333 result = val;
334 return true;
335 }
336 shift += 7;
337 }
338 PyErr_Format(PyExc_OverflowError, "varint exceeded %d bytes", Max);
339 return false;
340 }
341
342 template <typename S, typename U>
343 S fromZigZag(U val) {
344 return (val >> 1) ^ static_cast<U>(-static_cast<S>(val & 1));
345 }
346
347 void doWriteFieldBegin(const StructItemSpec& spec, int ctype) {
348 int diff = spec.tag - writeTags_.top();
349 if (diff > 0 && diff <= 15) {
350 writeByte(static_cast<uint8_t>(diff << 4 | ctype));
351 } else {
352 writeByte(static_cast<uint8_t>(ctype));
353 writeI16(spec.tag);
354 }
355 writeTags_.top() = spec.tag;
356 }
357
358 std::stack<int> writeTags_;
359 std::stack<int> readTags_;
360 struct {
361 bool exists;
362 bool value;
363 } readBool_;
364 char* dummy_buf_;
365};
366}
367}
368}
369#endif // THRIFT_PY_COMPACT_H