blob: 5c785dc45fe05979076ce7ae4776e2c4e03ede2e [file] [log] [blame]
// 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.
// mcpack2pb - Make protobuf be front-end of mcpack/compack
// Date: Mon Oct 19 17:17:36 CST 2015
#include "mcpack2pb/parser.h"
namespace mcpack2pb {
// Binary head before fixed-size types.
class FieldFixedHead {
public:
void set_type(uint8_t type) { _type = type; }
uint8_t type() const { return _type; }
size_t name_offset() const { return sizeof(FieldFixedHead); }
size_t name_size() const { return _name_size; }
void set_name_size(size_t name_size) { _name_size = name_size; }
size_t value_offset() const { return name_offset() + name_size(); }
size_t value_size() const { return (_type & FIELD_FIXED_MASK); }
size_t full_size() const { return value_offset() + value_size(); }
private:
uint8_t _type; // FieldType
uint8_t _name_size;
} __attribute__((__packed__));
// Binary head before string<=254 or raw<=255
class FieldShortHead {
public:
void set_type(uint8_t type) { _type = type; }
uint8_t type() const { return _type; }
size_t name_offset() const { return sizeof(FieldShortHead); }
size_t name_size() const { return _name_size; }
void set_name_size(size_t name_size) { _name_size = name_size; }
size_t value_offset() const { return name_offset() + name_size(); }
size_t value_size() const { return _value_size; }
void set_value_size(size_t value_size) { _value_size = value_size; }
size_t full_size() const { return value_offset() + value_size(); }
private:
uint8_t _type;
uint8_t _name_size;
uint8_t _value_size;
} __attribute__((__packed__));
// Binary head before variable-size fields.
class FieldLongHead {
public:
void set_type(uint8_t type) { _type = type; }
uint8_t type() const { return _type; }
size_t name_offset() const { return sizeof(FieldLongHead); }
size_t name_size() const { return _name_size; }
void set_name_size(size_t name_size) { _name_size = name_size; }
size_t value_offset() const { return name_offset() + name_size(); }
size_t value_size() const { return _value_size; }
void set_value_size(size_t value_size) { _value_size = value_size; }
size_t full_size() const { return value_offset() + value_size(); }
private:
uint8_t _type;
uint8_t _name_size;
uint32_t _value_size;
} __attribute__((__packed__));
// Assert type sizes:
BAIDU_CASSERT(sizeof(FieldFixedHead) == 2, size_assert);
BAIDU_CASSERT(sizeof(FieldShortHead) == 3, size_assert);
BAIDU_CASSERT(sizeof(FieldLongHead) == 6, size_assert);
BAIDU_CASSERT(sizeof(ItemsHead) == 4, size_assert);
BAIDU_CASSERT(sizeof(IsoItemsHead) == 1, size_assert);
void ObjectIterator::operator++() {
if (_stream->popped_bytes() != _expected_popped_bytes) {
if (_stream->popped_bytes() + _current_field.value.size() ==
_expected_popped_bytes) {
// skipping untouched values is acceptible.
_stream->popn(_current_field.value.size());
} else if (_stream->popped_bytes() < _expected_popped_bytes) {
CHECK(false) << "value of name=" << _current_field.name
<< " is not fully consumed, expected="
<< _expected_popped_bytes << " actually="
<< _stream->popped_bytes();
return set_bad();
} else {
CHECK(false) << "Over popped in value of name=" << _current_field.name
<< " expected=" << _expected_popped_bytes << " actually="
<< _stream->popped_bytes();
return set_bad();
}
}
if (_expected_popped_bytes >= _expected_popped_end) {
return set_end();
}
const uint8_t first_byte = _stream->peek1();
if (first_byte & FIELD_FIXED_MASK) {
FieldFixedHead head;
if (_stream->cut_packed_pod(&head) != sizeof(FieldFixedHead) ||
left_size() < head.full_size()) {
CHECK(false) << "buffer(size=" << left_size() << ") is not enough";
return set_bad();
}
_expected_popped_bytes = _stream->popped_bytes() + head.full_size()
- sizeof(FieldFixedHead);
if (!(head.type() & FIELD_NON_DELETED_MASK)) {
_stream->popn(head.full_size() - sizeof(FieldFixedHead));
return operator++(); // tailr
}
_current_field.name = _stream->ref_cut(&_name_backup_string, head.name_size());
if (!_current_field.name.empty()) {
_current_field.name.remove_suffix(1);
}
_current_field.value.set((FieldType)head.type(), _stream, head.value_size());
} else if (first_byte & FIELD_SHORT_MASK) {
FieldShortHead head;
if (_stream->cut_packed_pod(&head) != sizeof(FieldShortHead) ||
left_size() < head.full_size()) {
CHECK(false) << "buffer(size=" << left_size() << ") is not enough";
return set_bad();
}
_expected_popped_bytes = _stream->popped_bytes() + head.full_size()
- sizeof(FieldShortHead);
if (!(head.type() & FIELD_NON_DELETED_MASK)) {
// Skip deleted field.
_stream->popn(head.full_size() - sizeof(FieldShortHead));
return operator++(); // tailr
}
// Remove FIELD_SHORT_MASK.
FieldType type = (FieldType)(head.type() & ~FIELD_SHORT_MASK);
_current_field.name = _stream->ref_cut(&_name_backup_string, head.name_size());
if (!_current_field.name.empty()) {
_current_field.name.remove_suffix(1);
}
_current_field.value.set(type, _stream, head.value_size());
} else {
FieldLongHead head;
if (_stream->cut_packed_pod(&head) != sizeof(FieldLongHead) ||
left_size() < head.full_size()) {
CHECK(false) << "buffer(size=" << left_size() << ") is not enough";
return set_bad();
}
_expected_popped_bytes = _stream->popped_bytes() + head.full_size()
- sizeof(FieldLongHead);
if (!(head.type() & FIELD_NON_DELETED_MASK)) {
// Skip deleted field.
_stream->popn(head.full_size() - sizeof(FieldLongHead));
return operator++(); // tailr
}
_current_field.name = _stream->ref_cut(&_name_backup_string, head.name_size());
if (!_current_field.name.empty()) {
_current_field.name.remove_suffix(1);
}
_current_field.value.set((FieldType)head.type(), _stream, head.value_size());
}
}
void ArrayIterator::operator++() {
if (_stream->popped_bytes() != _expected_popped_bytes) {
if (_stream->popped_bytes() + _current_field.size() ==
_expected_popped_bytes) {
// skipping untouched values is acceptible.
_stream->popn(_current_field.size());
} else if (_stream->popped_bytes() < _expected_popped_bytes) {
CHECK(false) << "previous value is not fully consumed, expected="
<< _expected_popped_bytes << " actually="
<< _stream->popped_bytes();
return set_bad();
} else {
CHECK(false) << "Over popped in previous value, expected="
<< _expected_popped_bytes << " actually="
<< _stream->popped_bytes();
return set_bad();
}
}
if (_expected_popped_bytes >= _expected_popped_end) {
return set_end();
}
const uint8_t first_byte = _stream->peek1();
if (first_byte & FIELD_FIXED_MASK) {
FieldFixedHead head;
if (_stream->cut_packed_pod(&head) != sizeof(FieldFixedHead) ||
left_size() < head.full_size()) {
CHECK(false) << "buffer(size=" << left_size() << ") is not enough";
return set_bad();
}
_expected_popped_bytes = _stream->popped_bytes() + head.full_size()
- sizeof(FieldFixedHead);
if (!(head.type() & FIELD_NON_DELETED_MASK)) {
// Skip deleted fields.
_stream->popn(head.full_size() - sizeof(FieldFixedHead));
return operator++(); // tailr
}
const uint32_t name_size = head.name_size();
if (name_size) {
_stream->popn(name_size);
}
_current_field.set((FieldType)head.type(), _stream, head.value_size());
} else if (first_byte & FIELD_SHORT_MASK) {
FieldShortHead head;
if (_stream->cut_packed_pod(&head) != sizeof(FieldShortHead) ||
left_size() < head.full_size()) {
CHECK(false) << "buffer(size=" << left_size() << ") is not enough";
return set_bad();
}
_expected_popped_bytes = _stream->popped_bytes() + head.full_size()
- sizeof(FieldShortHead);
if (!(head.type() & FIELD_NON_DELETED_MASK)) {
// Skip deleted field.
_stream->popn(head.full_size() - sizeof(FieldShortHead));
return operator++(); // tailr
}
// Remove FIELD_SHORT_MASK.
const FieldType type = (FieldType)(head.type() & ~FIELD_SHORT_MASK);
const uint32_t name_size = head.name_size();
if (name_size) {
_stream->popn(name_size);
}
_current_field.set(type, _stream, head.value_size());
} else {
FieldLongHead head;
if (_stream->cut_packed_pod(&head) != sizeof(FieldLongHead) ||
left_size() < head.full_size()) {
CHECK(false) << "buffer(size=" << left_size() << ") is not enough";
return set_bad();
}
_expected_popped_bytes = _stream->popped_bytes() + head.full_size()
- sizeof(FieldLongHead);
if (!(head.type() & FIELD_NON_DELETED_MASK)) {
// Skip deleted field.
_stream->popn(head.full_size() - sizeof(FieldLongHead));
return operator++(); // tailr
}
const uint32_t name_size = head.name_size();
if (name_size) {
_stream->popn(name_size);
}
_current_field.set((FieldType)head.type(), _stream, head.value_size());
}
}
size_t unbox(InputStream* stream) {
FieldLongHead head;
if (stream->cut_packed_pod(&head) != sizeof(FieldLongHead)) {
CHECK(false) << "Input buffer is not enough";
return 0;
}
if (head.type() != FIELD_OBJECT) {
CHECK(false) << "type=" << type2str(head.type()) << " is not object";
return 0;
}
if (!(head.type() & FIELD_NON_DELETED_MASK)) {
CHECK(false) << "The item is deleted";
return 0;
}
if (head.name_size() != 0) {
CHECK(false) << "The object should not have name";
return 0;
}
return head.value_size();
}
std::ostream& operator<<(std::ostream& os, const UnparsedValue& value) {
// TODO(gejun): More info.
return os << type2str(value.type());
}
// NOTE: following functions are too big to be inlined. Actually non-inlining
// them perform better in tests.
int64_t UnparsedValue::as_int64(const char* var) {
switch ((PrimitiveFieldType)_type) {
case PRIMITIVE_FIELD_INT8:
return _stream->cut_packed_pod<int8_t>();
case PRIMITIVE_FIELD_INT16:
return _stream->cut_packed_pod<int16_t>();
case PRIMITIVE_FIELD_INT32:
return _stream->cut_packed_pod<int32_t>();
case PRIMITIVE_FIELD_INT64:
return _stream->cut_packed_pod<int64_t>();
case PRIMITIVE_FIELD_UINT8:
return _stream->cut_packed_pod<uint8_t>();
case PRIMITIVE_FIELD_UINT16:
return _stream->cut_packed_pod<uint16_t>();
case PRIMITIVE_FIELD_UINT32:
return _stream->cut_packed_pod<uint32_t>();
case PRIMITIVE_FIELD_UINT64: {
const uint64_t value = _stream->cut_packed_pod<uint64_t>();
if (value <= (uint64_t)std::numeric_limits<int64_t>::max()) {
return (int64_t)value;
}
CHECK(false) << "uint64=" << value << " to " << var << " overflows";
_stream->set_bad();
return std::numeric_limits<int64_t>::max();
}
case PRIMITIVE_FIELD_BOOL:
return _stream->cut_packed_pod<bool>();
case PRIMITIVE_FIELD_FLOAT:
CHECK(false) << "Can't set float=" << _stream->cut_packed_pod<float>()
<< " to " << var;
_stream->set_bad();
return 0;
case PRIMITIVE_FIELD_DOUBLE:
CHECK(false) << "Can't set double=" << _stream->cut_packed_pod<double>()
<< " to " << var;
_stream->set_bad();
return 0;
}
CHECK(false) << "Can't set type=" << type2str(_type) << " to " << var;
_stream->set_bad();
return 0;
}
uint64_t UnparsedValue::as_uint64(const char* var) {
switch ((PrimitiveFieldType)_type) {
case PRIMITIVE_FIELD_INT8: {
const int8_t value = _stream->cut_packed_pod<int8_t>();
if (value >= 0) {
return (uint64_t)value;
}
CHECK(false) << "Can't set int8=" << value << " to " << var;
_stream->set_bad();
return 0;
}
case PRIMITIVE_FIELD_INT16: {
const int16_t value = _stream->cut_packed_pod<int16_t>();
if (value >= 0) {
return (uint64_t)value;
}
CHECK(false) << "Can't set int16=" << value << " to " << var;
_stream->set_bad();
return 0;
}
case PRIMITIVE_FIELD_INT32: {
const int32_t value = _stream->cut_packed_pod<int32_t>();
if (value >= 0) {
return (uint64_t)value;
}
CHECK(false) << "Can't set int32=" << value << " to " << var;
_stream->set_bad();
return 0;
}
case PRIMITIVE_FIELD_INT64: {
const int64_t value = _stream->cut_packed_pod<int64_t>();
if (value >= 0) {
return (uint64_t)value;
}
CHECK(false) << "Can't set int64=" << value << " to " << var;
_stream->set_bad();
return 0;
}
case PRIMITIVE_FIELD_UINT8:
return _stream->cut_packed_pod<uint8_t>();
case PRIMITIVE_FIELD_UINT16:
return _stream->cut_packed_pod<uint16_t>();
case PRIMITIVE_FIELD_UINT32:
return _stream->cut_packed_pod<uint32_t>();
case PRIMITIVE_FIELD_UINT64:
return _stream->cut_packed_pod<uint64_t>();
case PRIMITIVE_FIELD_BOOL:
return _stream->cut_packed_pod<bool>();
case PRIMITIVE_FIELD_FLOAT:
CHECK(false) << "Can't set float=" << _stream->cut_packed_pod<float>()
<< " to " << var;
_stream->set_bad();
return 0;
case PRIMITIVE_FIELD_DOUBLE:
CHECK(false) << "Can't set double=" << _stream->cut_packed_pod<double>()
<< " to " << var;
_stream->set_bad();
return 0;
}
CHECK(false) << "Can't set type=" << type2str(_type) << " to " << var;
_stream->set_bad();
return 0;
}
int32_t UnparsedValue::as_int32(const char* var) {
switch ((PrimitiveFieldType)_type) {
case PRIMITIVE_FIELD_INT8:
return _stream->cut_packed_pod<int8_t>();
case PRIMITIVE_FIELD_INT16:
return _stream->cut_packed_pod<int16_t>();
case PRIMITIVE_FIELD_INT32:
return _stream->cut_packed_pod<int32_t>();
case PRIMITIVE_FIELD_INT64: {
const int64_t value = _stream->cut_packed_pod<int64_t>();
if (value > std::numeric_limits<int32_t>::max()) {
CHECK(false) << "int64=" << value << " to " << var << " overflows";
_stream->set_bad();
return std::numeric_limits<int32_t>::max();
} else if (value < std::numeric_limits<int32_t>::min()) {
CHECK(false) << "int64=" << value << " to " << var << " underflows";
_stream->set_bad();
return std::numeric_limits<int32_t>::min();
}
return (int32_t)value;
}
case PRIMITIVE_FIELD_UINT8:
return _stream->cut_packed_pod<uint8_t>();
case PRIMITIVE_FIELD_UINT16:
return _stream->cut_packed_pod<uint16_t>();
case PRIMITIVE_FIELD_UINT32: {
const uint32_t value = _stream->cut_packed_pod<uint32_t>();
if (value <= (uint32_t)std::numeric_limits<int32_t>::max()) {
return (int32_t)value;
}
CHECK(false) << "uint32=" << value << " to " << var << " overflows";
_stream->set_bad();
return std::numeric_limits<int32_t>::max();
}
case PRIMITIVE_FIELD_UINT64: {
const uint64_t value = _stream->cut_packed_pod<uint64_t>();
if (value <= (uint64_t)std::numeric_limits<int32_t>::max()) {
return (int32_t)value;
}
CHECK(false) << "uint64=" << value << " to " << var << " overflows";
_stream->set_bad();
return std::numeric_limits<int32_t>::max();
}
case PRIMITIVE_FIELD_BOOL:
return _stream->cut_packed_pod<bool>();
case PRIMITIVE_FIELD_FLOAT:
CHECK(false) << "Can't set float=" << _stream->cut_packed_pod<float>()
<< " to " << var;
_stream->set_bad();
return 0;
case PRIMITIVE_FIELD_DOUBLE:
CHECK(false) << "Can't set double=" << _stream->cut_packed_pod<double>()
<< " to " << var;
_stream->set_bad();
return 0;
}
CHECK(false) << "Can't set type=" << type2str(_type) << " to " << var;
_stream->set_bad();
return 0;
}
uint32_t UnparsedValue::as_uint32(const char* var) {
switch ((PrimitiveFieldType)_type) {
case PRIMITIVE_FIELD_INT8: {
const int8_t value = _stream->cut_packed_pod<int8_t>();
if (value >= 0) {
return (uint32_t)value;
}
CHECK(false) << "Can't set int8=" << value << " to " << var;
_stream->set_bad();
return 0;
}
case PRIMITIVE_FIELD_INT16: {
const int16_t value = _stream->cut_packed_pod<int16_t>();
if (value >= 0) {
return (uint32_t)value;
}
CHECK(false) << "Can't set int16=" << value << " to " << var;
_stream->set_bad();
return 0;
}
case PRIMITIVE_FIELD_INT32: {
const int32_t value = _stream->cut_packed_pod<int32_t>();
if (value >= 0) {
return (uint32_t)value;
}
CHECK(false) << "Can't set int32=" << value << " to " << var;
_stream->set_bad();
return 0;
}
case PRIMITIVE_FIELD_INT64: {
const int64_t value = _stream->cut_packed_pod<int64_t>();
if (value >= 0 &&
value <= (int64_t)std::numeric_limits<uint32_t>::max()) {
return (uint32_t)value;
}
CHECK(false) << "Can't set int64=" << value << " to " << var;
_stream->set_bad();
return 0;
}
case PRIMITIVE_FIELD_UINT8:
return _stream->cut_packed_pod<uint8_t>();
case PRIMITIVE_FIELD_UINT16:
return _stream->cut_packed_pod<uint16_t>();
case PRIMITIVE_FIELD_UINT32:
return _stream->cut_packed_pod<uint32_t>();
case PRIMITIVE_FIELD_UINT64: {
const uint64_t value = _stream->cut_packed_pod<uint64_t>();
if (value <= std::numeric_limits<uint32_t>::max()) {
return (uint32_t)value;
}
CHECK(false) << "uint64=" << value << " to " << var << " overflows";
_stream->set_bad();
return std::numeric_limits<uint32_t>::max();
}
case PRIMITIVE_FIELD_BOOL:
return _stream->cut_packed_pod<bool>();
case PRIMITIVE_FIELD_FLOAT:
CHECK(false) << "Can't set float=" << _stream->cut_packed_pod<float>()
<< " to " << var;
_stream->set_bad();
return 0;
case PRIMITIVE_FIELD_DOUBLE:
CHECK(false) << "Can't set double=" << _stream->cut_packed_pod<double>()
<< " to " << var;
_stream->set_bad();
return 0;
}
CHECK(false) << "Can't set type=" << type2str(_type) << " to " << var;
_stream->set_bad();
return 0;
}
bool UnparsedValue::as_bool(const char* var) {
switch ((PrimitiveFieldType)_type) {
case PRIMITIVE_FIELD_INT8:
return _stream->cut_packed_pod<int8_t>();
case PRIMITIVE_FIELD_INT16:
return _stream->cut_packed_pod<int16_t>();
case PRIMITIVE_FIELD_INT32:
return _stream->cut_packed_pod<int32_t>();
case PRIMITIVE_FIELD_INT64:
return _stream->cut_packed_pod<int64_t>();
case PRIMITIVE_FIELD_UINT8:
return _stream->cut_packed_pod<uint8_t>();
case PRIMITIVE_FIELD_UINT16:
return _stream->cut_packed_pod<uint16_t>();
case PRIMITIVE_FIELD_UINT32:
return _stream->cut_packed_pod<uint32_t>();
case PRIMITIVE_FIELD_UINT64:
return _stream->cut_packed_pod<uint64_t>();
case PRIMITIVE_FIELD_BOOL:
return _stream->cut_packed_pod<bool>();
case PRIMITIVE_FIELD_FLOAT:
CHECK(false) << "Can't set float=" << _stream->cut_packed_pod<float>()
<< " to " << var;
_stream->set_bad();
return false;
case PRIMITIVE_FIELD_DOUBLE:
CHECK(false) << "Can't set double=" << _stream->cut_packed_pod<double>()
<< " to " << var;
_stream->set_bad();
return false;
}
CHECK(false) << "Can't set type=" << type2str(_type) << " to " << var;
_stream->set_bad();
return false;
}
float UnparsedValue::as_float(const char* var) {
if (_type == FIELD_DOUBLE) {
return (float)_stream->cut_packed_pod<double>();
} else if (_type == FIELD_FLOAT) {
return _stream->cut_packed_pod<float>();
}
CHECK(false) << "Can't set type=" << type2str(_type) << " to " << var;
_stream->set_bad();
return 0;
}
double UnparsedValue::as_double(const char* var) {
if (_type == FIELD_DOUBLE) {
return _stream->cut_packed_pod<double>();
} else if (_type == FIELD_FLOAT) {
return _stream->cut_packed_pod<float>();
}
CHECK(false) << "Can't set type=" << type2str(_type) << " to " << var;
_stream->set_bad();
return 0;
}
void UnparsedValue::as_string(std::string* out, const char* var) {
out->resize(_size - 1);
if (_stream->cutn(&(*out)[0], _size - 1) != _size - 1) {
CHECK(false) << "Not enough data for " << var;
return;
}
_stream->popn(1);
}
std::string UnparsedValue::as_string(const char* var) {
std::string result;
as_string(&result, var);
return result;
}
void UnparsedValue::as_binary(std::string* out, const char* var) {
out->resize(_size);
if (_stream->cutn(&(*out)[0], _size) != _size) {
CHECK(false) << "Not enough data for " << var;
return;
}
}
std::string UnparsedValue::as_binary(const char* var) {
std::string result;
as_binary(&result, var);
return result;
}
} // namespace mcpack2pb