// mcpack2pb - Make protobuf be front-end of mcpack/compack // Copyright (c) 2015 Baidu, Inc. // // Licensed 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. // Author: Ge,Jun (gejun@baidu.com) // Date: Mon Oct 19 17:17:36 CST 2015 #ifndef MCPACK2PB_MCPACK_PARSER_INL_H #define MCPACK2PB_MCPACK_PARSER_INL_H namespace mcpack2pb { // Binary head before items of array/object except isomorphic array. struct ItemsHead { uint32_t item_count; } __attribute__((__packed__)); inline size_t InputStream::popn(size_t n) { const size_t saved_n = n; do { if (_size >= (int64_t)n) { _data = (const char*)_data + n; _size -= n; _popped_bytes += saved_n; return saved_n; } n -= _size; } while (_zc_stream->Next(&_data, &_size)); _data = NULL; _size = 0; _popped_bytes += saved_n - n; return saved_n - n; } inline size_t InputStream::cutn(void* out, size_t n) { const size_t saved_n = n; do { if (_size >= (int64_t)n) { memcpy(out, _data, n); _data = (const char*)_data + n; _size -= n; _popped_bytes += saved_n; return saved_n; } if (_size) { memcpy(out, _data, _size); out = (char*)out + _size; n -= _size; } } while (_zc_stream->Next(&_data, &_size)); _data = NULL; _size = 0; _popped_bytes += saved_n - n; return saved_n - n; } template <typename T> inline size_t InputStream::cut_packed_pod(T* packed_pod) { if (_size >= (int)sizeof(T)) { *packed_pod = *(T*)_data; _data = (const char*)_data + sizeof(T); _size -= sizeof(T); _popped_bytes += sizeof(T); return sizeof(T); } return cutn(packed_pod, sizeof(T)); } template <typename T> inline T InputStream::cut_packed_pod() { T packed_pod; if (_size >= (int)sizeof(T)) { packed_pod = *(T*)_data; _data = (const char*)_data + sizeof(T); _size -= sizeof(T); _popped_bytes += sizeof(T); return packed_pod; } cutn(&packed_pod, sizeof(T)); return packed_pod; } inline butil::StringPiece InputStream::ref_cut(std::string* aux, size_t n) { if (_size >= (int64_t)n) { butil::StringPiece ret((const char*)_data, n); _data = (const char*)_data + n; _size -= n; _popped_bytes += n; return ret; } aux->resize(n); size_t m = cutn(&(*aux)[0], n); if (m != n) { aux->resize(m); } return *aux; } inline uint8_t InputStream::peek1() { if (_size > 0) { return *(const uint8_t*)_data; } while (_zc_stream->Next(&_data, &_size)) { if (_size > 0) { return *(const uint8_t*)_data; } } return 0; } // Binary head before items of isomorphic array. struct IsoItemsHead { uint8_t type; } __attribute__((__packed__)); inline ObjectIterator UnparsedValue::as_object() { return ObjectIterator(_stream, _size); } inline ArrayIterator UnparsedValue::as_array() { return ArrayIterator(_stream, _size); } inline ISOArrayIterator UnparsedValue::as_iso_array() { return ISOArrayIterator(_stream, _size); } inline void ObjectIterator::init(InputStream* stream, size_t size) { _field_count = 0; _stream = stream; _expected_popped_bytes = _stream->popped_bytes() + sizeof(ItemsHead); _expected_popped_end = _stream->popped_bytes() + size; ItemsHead items_head; if (_stream->cut_packed_pod(&items_head) != sizeof(ItemsHead)) { CHECK(false) << "buffer(size=" << size << ") is not enough"; return set_bad(); } _field_count = items_head.item_count; operator++(); } inline void ArrayIterator::init(InputStream* stream, size_t size) { _item_count = 0; _stream = stream; _expected_popped_bytes = _stream->popped_bytes() + sizeof(ItemsHead); _expected_popped_end = _stream->popped_bytes() + size; ItemsHead items_head; if (_stream->cut_packed_pod(&items_head) != sizeof(ItemsHead)) { CHECK(false) << "buffer(size=" << size << ") is not enough"; return set_bad(); } _item_count = items_head.item_count; operator++(); } inline void ISOArrayIterator::init(InputStream* stream, size_t size) { _buf_index = 0; _buf_count = 0; _stream = stream; _item_type = (PrimitiveFieldType)0; _item_size = 0; _item_count = 0; _left_item_count = 0; IsoItemsHead items_head; if (_stream->cut_packed_pod(&items_head) != sizeof(IsoItemsHead)) { CHECK(false) << "Not enough data"; return set_bad(); } _item_type = (PrimitiveFieldType)items_head.type; _item_size = get_primitive_type_size(_item_type); if (!_item_size) { CHECK(false) << "type=" << type2str(_item_type) << " in primitive isoarray is not primitive"; return set_bad(); } const size_t items_full_size = size - sizeof(IsoItemsHead); _item_count = items_full_size / _item_size; if (_item_count * _item_size != items_full_size) { CHECK(false) << "inconsistent item_count(" << _item_count << ") and value_size(" << items_full_size << "), item_size=" << _item_size; return set_bad(); } _left_item_count = _item_count; operator++(); } inline void ISOArrayIterator::operator++() { if (_buf_index + 1 < _buf_count) { ++_buf_index; return; } // Iterate all items in isomorphic array. We have to do this // right here because the items are lacking of headings. // Call on_primitives in batch to reduce overhead. if (_left_item_count == 0) { set_end(); return; } _buf_count = std::min((uint32_t)sizeof(_item_buf) / _item_size, _left_item_count); _buf_index = 0; if (_stream->cutn(_item_buf, _buf_count * _item_size) != _buf_count * _item_size) { CHECK(false) << "Not enough data"; return set_bad(); } _left_item_count -= _buf_count; } template <typename T> inline T ISOArrayIterator::as_integer() const { const void* ptr = (_item_buf + _buf_index * _item_size); switch ((PrimitiveFieldType)_item_type) { case PRIMITIVE_FIELD_INT8: return *static_cast<const int8_t*>(ptr); case PRIMITIVE_FIELD_INT16: return *static_cast<const int16_t*>(ptr); case PRIMITIVE_FIELD_INT32: return *static_cast<const int32_t*>(ptr); case PRIMITIVE_FIELD_INT64: return *static_cast<const int64_t*>(ptr); case PRIMITIVE_FIELD_UINT8: return *static_cast<const uint8_t*>(ptr); case PRIMITIVE_FIELD_UINT16: return *static_cast<const uint16_t*>(ptr); case PRIMITIVE_FIELD_UINT32: return *static_cast<const uint32_t*>(ptr); case PRIMITIVE_FIELD_UINT64: return *static_cast<const uint64_t*>(ptr); case PRIMITIVE_FIELD_BOOL: return *static_cast<const bool*>(ptr); case PRIMITIVE_FIELD_FLOAT: return 0; case PRIMITIVE_FIELD_DOUBLE: return 0; } return 0; } template <typename T> inline T ISOArrayIterator::as_fp() const { const void* ptr = (_item_buf + _buf_index * _item_size); if (_item_type == PRIMITIVE_FIELD_FLOAT) { return *static_cast<const float*>(ptr); } else if (_item_type == PRIMITIVE_FIELD_DOUBLE) { return *static_cast<const double*>(ptr); } return T(); } } // namespace mcpack2pb #endif // MCPACK2PB_MCPACK_PARSER_INL_H