| // 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 |
| |
| #ifndef MCPACK2PB_MCPACK_PARSER_H |
| #define MCPACK2PB_MCPACK_PARSER_H |
| |
| #include <limits> // std::numeric_limits |
| #include <google/protobuf/io/zero_copy_stream.h> |
| #include "butil/logging.h" |
| #include "butil/strings/string_piece.h" |
| #include "mcpack2pb/field_type.h" |
| |
| // CAUTION: Methods in this header is not intended to be public to users of |
| // brpc, and subject to change at any future time. |
| |
| namespace mcpack2pb { |
| |
| // Read bytes from ZeroCopyInputStream |
| class InputStream { |
| public: |
| InputStream(google::protobuf::io::ZeroCopyInputStream* stream) |
| : _good(true) |
| , _size(0) |
| , _data(NULL) |
| , _zc_stream(stream) |
| , _popped_bytes(0) |
| {} |
| |
| ~InputStream() { } |
| |
| // Pop at-most n bytes from front side. |
| // Returns bytes popped. |
| size_t popn(size_t n); |
| |
| // Cut off at-most n bytes from front side and copy to `out'. |
| // Returns bytes cut. |
| size_t cutn(void* out, size_t n); |
| |
| template <typename T> size_t cut_packed_pod(T* packed_pod); |
| template <typename T> T cut_packed_pod(); |
| |
| // Cut off at-most n bytes from front side. If the data is stored in |
| // continuous memory, return the reference directly, otherwise copy |
| // the data into `aux' and return reference of `aux'. |
| // Returns a StringPiece referencing the cut-off data. |
| butil::StringPiece ref_cut(std::string* aux, size_t n); |
| |
| // Peek at the first character. If the stream is empty, 0 is returned. |
| uint8_t peek1(); |
| |
| // Returns bytes popped and cut since creation of this stream. |
| size_t popped_bytes() const { return _popped_bytes; } |
| |
| // Returns false if error occurred in other consuming functions. |
| bool good() const { return _good; } |
| |
| // If the error prevents parsing from going on, call this method. |
| // This method is also called in other functions in this class. |
| void set_bad() { _good = false; } |
| |
| private: |
| bool _good; |
| int _size; |
| const void* _data; |
| google::protobuf::io::ZeroCopyInputStream* _zc_stream; |
| size_t _popped_bytes; |
| }; |
| |
| class ObjectIterator; |
| class ArrayIterator; |
| class ISOArrayIterator; |
| |
| // Represent a piece of unparsed(and unread) data of InputStream. |
| struct UnparsedValue { |
| UnparsedValue() |
| : _type(FIELD_UNKNOWN), _stream(NULL), _size(0) {} |
| UnparsedValue(FieldType type, InputStream* stream, size_t size) |
| : _type(type), _stream(stream), _size(size) {} |
| void set(FieldType type, InputStream* stream, size_t size) { |
| _type = type; |
| _stream = stream; |
| _size = size; |
| } |
| |
| FieldType type() const { return _type; } |
| InputStream* stream() { return _stream; } |
| const InputStream* stream() const { return _stream; } |
| size_t size() const { return _size; } |
| |
| // Convert to concrete value. These functions can only be called once! |
| ObjectIterator as_object(); |
| ArrayIterator as_array(); |
| ISOArrayIterator as_iso_array(); |
| // `var' in following methods should be a description of the field being |
| // parsed, for better error reporting. It has nothing to do with the result. |
| int64_t as_int64(const char* var); |
| uint64_t as_uint64(const char* var); |
| int32_t as_int32(const char* var); |
| uint32_t as_uint32(const char* var); |
| bool as_bool(const char* var); |
| float as_float(const char* var); |
| double as_double(const char* var); |
| void as_string(std::string* out, const char* var); |
| std::string as_string(const char* var); |
| void as_binary(std::string* out, const char* var); |
| std::string as_binary(const char* var); |
| |
| private: |
| friend class ObjectIterator; |
| friend class ArrayIterator; |
| void set_end() { _type = FIELD_UNKNOWN; } |
| |
| FieldType _type; |
| InputStream* _stream; |
| size_t _size; |
| }; |
| |
| std::ostream& operator<<(std::ostream& os, const UnparsedValue& value); |
| |
| // Remove the header of the wrapping object. |
| // Returns the value size. |
| size_t unbox(InputStream* stream); |
| |
| // Iterator all fields in an object which should be created like this: |
| // ObjectIterator it(unparsed_value); |
| // for (; it != NULL; ++it) { |
| // std::cout << "name=" << it->name << " value=" << it->value << std::endl; |
| // } |
| class ObjectIterator { |
| public: |
| struct Field { |
| butil::StringPiece name; |
| UnparsedValue value; |
| }; |
| |
| // Parse `n' bytes from `stream' as fields of an object. |
| ObjectIterator(InputStream* stream, size_t n) { init(stream, n); } |
| explicit ObjectIterator(UnparsedValue& value) |
| { init(value.stream(), value.size()); } |
| ~ObjectIterator() {} |
| |
| Field* operator->() { return &_current_field; } |
| Field& operator*() { return _current_field; } |
| void operator++(); |
| operator void*() const { return (void*)_current_field.value.type(); } |
| |
| // Number of fields in the object. |
| uint32_t field_count() const { return _field_count; } |
| |
| private: |
| void init(InputStream* stream, size_t n); |
| void set_bad() { |
| set_end(); |
| _stream->set_bad(); |
| } |
| void set_end() { _current_field.value._type = FIELD_UNKNOWN; } |
| size_t left_size() const |
| { return _expected_popped_end - _expected_popped_bytes; } |
| |
| Field _current_field; |
| uint32_t _field_count; |
| std::string _name_backup_string; |
| InputStream* _stream; |
| size_t _expected_popped_bytes; |
| size_t _expected_popped_end; |
| }; |
| |
| // Iterator all items in a (mcpack) array which should be created like this: |
| // ArrayIterator it(unparsed_value); |
| // for (; it != NULL; ++it) { |
| // std::cout << " item=" << *it << std::endl; |
| // } |
| class ArrayIterator { |
| public: |
| typedef UnparsedValue Field; |
| |
| ArrayIterator(InputStream* stream, size_t size) { init(stream, size); } |
| explicit ArrayIterator(UnparsedValue& value) |
| { init(value.stream(), value.size()); } |
| ~ArrayIterator() {} |
| |
| Field* operator->() { return &_current_field; } |
| Field& operator*() { return _current_field; } |
| void operator++(); |
| operator void*() const { return (void*)_current_field.type(); } |
| |
| // Number of items in the array. |
| uint32_t item_count() const { return _item_count; } |
| |
| private: |
| void init(InputStream* stream, size_t n); |
| void set_bad() { |
| set_end(); |
| _stream->set_bad(); |
| } |
| void set_end() { _current_field._type = FIELD_UNKNOWN; } |
| size_t left_size() const |
| { return _expected_popped_end - _expected_popped_bytes; } |
| |
| Field _current_field; |
| uint32_t _item_count; |
| InputStream* _stream; |
| size_t _expected_popped_bytes; |
| size_t _expected_popped_end; |
| }; |
| |
| // Iterator all items in an isomorphic array which should be created like this: |
| // ISOArrayIterator it(unparsed_value); |
| class ISOArrayIterator { |
| public: |
| ISOArrayIterator(InputStream* stream, size_t size) { init(stream, size); } |
| explicit ISOArrayIterator(UnparsedValue& value) |
| { init(value.stream(), value.size()); } |
| ~ISOArrayIterator() {} |
| void operator++(); |
| operator void*() const { return (void*)(uintptr_t)_item_type; } |
| |
| template <typename T> T as_integer() const; |
| template <typename T> T as_fp() const; |
| int64_t as_int64() const { return as_integer<int64_t>(); } |
| uint64_t as_uint64() const { return as_integer<uint64_t>(); } |
| int32_t as_int32() const { return as_integer<int32_t>(); } |
| uint32_t as_uint32() const { return as_integer<uint32_t>(); } |
| bool as_bool() const { return as_integer<bool>(); } |
| float as_float() const { return as_fp<float>(); } |
| double as_double() const { return as_fp<double>(); } |
| |
| PrimitiveFieldType item_type() const { return _item_type; } |
| |
| // Number of items in the array. |
| uint32_t item_count() const { return _item_count; } |
| |
| private: |
| void init(InputStream* stream, size_t n); |
| void set_bad() { |
| set_end(); |
| _stream->set_bad(); |
| } |
| void set_end() { _item_type = (PrimitiveFieldType)0; } |
| |
| int _buf_index; |
| int _buf_count; |
| InputStream* _stream; |
| PrimitiveFieldType _item_type; |
| uint32_t _item_size; |
| uint32_t _item_count; |
| uint32_t _left_item_count; |
| char _item_buf[1024]; |
| }; |
| |
| } // namespace mcpack2pb |
| |
| #include "mcpack2pb/parser-inl.h" |
| |
| #endif // MCPACK2PB_MCPACK_PARSER_H |