/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ #ifndef THRIFT_PY_COMPACT_H #define THRIFT_PY_COMPACT_H #include #include "ext/protocol.h" #include "ext/endian.h" #include #include namespace apache { namespace thrift { namespace py { class CompactProtocol : public ProtocolBase { public: CompactProtocol() { readBool_.exists = false; } virtual ~CompactProtocol() {} void writeI8(int8_t val) { writeBuffer(reinterpret_cast(&val), 1); } void writeI16(int16_t val) { writeVarint(toZigZag(val)); } int writeI32(int32_t val) { return writeVarint(toZigZag(val)); } void writeI64(int64_t val) { writeVarint64(toZigZag64(val)); } void writeDouble(double dub) { union { double f; int64_t t; } transfer; transfer.f = htolell(dub); writeBuffer(reinterpret_cast(&transfer.t), sizeof(int64_t)); } void writeBool(int v) { writeByte(static_cast(v ? CT_BOOLEAN_TRUE : CT_BOOLEAN_FALSE)); } void writeString(PyObject* value, int32_t len) { writeVarint(len); writeBuffer(PyBytes_AS_STRING(value), len); } bool writeListBegin(PyObject* value, const SetListTypeArgs& args, int32_t len) { int ctype = toCompactType(args.element_type); if (len <= 14) { writeByte(static_cast(len << 4 | ctype)); } else { writeByte(0xf0 | ctype); writeVarint(len); } return true; } bool writeMapBegin(PyObject* value, const MapTypeArgs& args, int32_t len) { if (len == 0) { writeByte(0); return true; } int ctype = toCompactType(args.ktag) << 4 | toCompactType(args.vtag); writeVarint(len); writeByte(ctype); return true; } bool writeStructBegin() { writeTags_.push(0); return true; } bool writeStructEnd() { writeTags_.pop(); return true; } bool writeField(PyObject* value, const StructItemSpec& spec) { if (spec.type == T_BOOL) { doWriteFieldBegin(spec, PyObject_IsTrue(value) ? CT_BOOLEAN_TRUE : CT_BOOLEAN_FALSE); return true; } else { doWriteFieldBegin(spec, toCompactType(spec.type)); return encodeValue(value, spec.type, spec.typeargs); } } void writeFieldStop() { writeByte(0); } bool readBool(bool& val) { if (readBool_.exists) { readBool_.exists = false; val = readBool_.value; return true; } char* buf; if (!readBytes(&buf, 1)) { return false; } val = buf[0] == CT_BOOLEAN_TRUE; return true; } bool readI8(int8_t& val) { char* buf; if (!readBytes(&buf, 1)) { return false; } val = buf[0]; return true; } bool readI16(int16_t& val) { uint16_t uval; if (readVarint(uval)) { val = fromZigZag(uval); return true; } return false; } bool readI32(int32_t& val) { uint32_t uval; if (readVarint(uval)) { val = fromZigZag(uval); return true; } return false; } bool readI64(int64_t& val) { uint64_t uval; if (readVarint(uval)) { val = fromZigZag(uval); return true; } return false; } bool readDouble(double& val) { union { int64_t f; double t; } transfer; char* buf; if (!readBytes(&buf, 8)) { return false; } memcpy(&transfer.f, buf, sizeof(int64_t)); transfer.f = letohll(transfer.f); val = transfer.t; return true; } int32_t readString(char** buf) { uint32_t len; if (!readVarint(len) || !checkLengthLimit(len, stringLimit())) { return -1; } if (len == 0) { return 0; } if (!readBytes(buf, len)) { return -1; } return len; } int32_t readListBegin(TType& etype) { uint8_t b; if (!readByte(b)) { return -1; } etype = getTType(b & 0xf); if (etype == -1) { return -1; } uint32_t len = (b >> 4) & 0xf; if (len == 15 && !readVarint(len)) { return -1; } if (!checkLengthLimit(len, containerLimit())) { return -1; } return len; } int32_t readMapBegin(TType& ktype, TType& vtype) { uint32_t len; if (!readVarint(len) || !checkLengthLimit(len, containerLimit())) { return -1; } if (len != 0) { uint8_t kvType; if (!readByte(kvType)) { return -1; } ktype = getTType(kvType >> 4); vtype = getTType(kvType & 0xf); if (ktype == -1 || vtype == -1) { return -1; } } return len; } bool readStructBegin() { readTags_.push(0); return true; } bool readStructEnd() { readTags_.pop(); return true; } bool readFieldBegin(TType& type, int16_t& tag); bool skipBool() { bool val; return readBool(val); } #define SKIPBYTES(n) \ do { \ if (!readBytes(&dummy_buf_, (n))) { \ return false; \ } \ return true; \ } while (0) bool skipByte() { SKIPBYTES(1); } bool skipDouble() { SKIPBYTES(8); } bool skipI16() { int16_t val; return readI16(val); } bool skipI32() { int32_t val; return readI32(val); } bool skipI64() { int64_t val; return readI64(val); } bool skipString() { uint32_t len; if (!readVarint(len)) { return false; } SKIPBYTES(len); } #undef SKIPBYTES private: enum Types { CT_STOP = 0x00, CT_BOOLEAN_TRUE = 0x01, CT_BOOLEAN_FALSE = 0x02, CT_BYTE = 0x03, CT_I16 = 0x04, CT_I32 = 0x05, CT_I64 = 0x06, CT_DOUBLE = 0x07, CT_BINARY = 0x08, CT_LIST = 0x09, CT_SET = 0x0A, CT_MAP = 0x0B, CT_STRUCT = 0x0C }; static const uint8_t TTypeToCType[]; TType getTType(uint8_t type); int toCompactType(TType type) { int i = static_cast(type); return i < 16 ? TTypeToCType[i] : -1; } uint32_t toZigZag(int32_t val) { return (val >> 31) ^ (val << 1); } uint64_t toZigZag64(int64_t val) { return (val >> 63) ^ (val << 1); } int writeVarint(uint32_t val) { int cnt = 1; while (val & ~0x7fU) { writeByte(static_cast((val & 0x7fU) | 0x80U)); val >>= 7; ++cnt; } writeByte(static_cast(val)); return cnt; } int writeVarint64(uint64_t val) { int cnt = 1; while (val & ~0x7fULL) { writeByte(static_cast((val & 0x7fULL) | 0x80ULL)); val >>= 7; ++cnt; } writeByte(static_cast(val)); return cnt; } template bool readVarint(T& result) { uint8_t b; T val = 0; int shift = 0; for (int i = 0; i < Max; ++i) { if (!readByte(b)) { return false; } if (b & 0x80) { val |= static_cast(b & 0x7f) << shift; } else { val |= static_cast(b) << shift; result = val; return true; } shift += 7; } PyErr_Format(PyExc_OverflowError, "varint exceeded %d bytes", Max); return false; } template S fromZigZag(U val) { return (val >> 1) ^ static_cast(-static_cast(val & 1)); } void doWriteFieldBegin(const StructItemSpec& spec, int ctype) { int diff = spec.tag - writeTags_.top(); if (diff > 0 && diff <= 15) { writeByte(static_cast(diff << 4 | ctype)); } else { writeByte(static_cast(ctype)); writeI16(spec.tag); } writeTags_.top() = spec.tag; } std::stack writeTags_; std::stack readTags_; struct { bool exists; bool value; } readBool_; char* dummy_buf_; }; } } } #endif // THRIFT_PY_COMPACT_H