/src/brpc/src/mcpack2pb/parser.h
Line | Count | Source (jump to first uncovered line) |
1 | | // Licensed to the Apache Software Foundation (ASF) under one |
2 | | // or more contributor license agreements. See the NOTICE file |
3 | | // distributed with this work for additional information |
4 | | // regarding copyright ownership. The ASF licenses this file |
5 | | // to you under the Apache License, Version 2.0 (the |
6 | | // "License"); you may not use this file except in compliance |
7 | | // with the License. You may obtain a copy of the License at |
8 | | // |
9 | | // http://www.apache.org/licenses/LICENSE-2.0 |
10 | | // |
11 | | // Unless required by applicable law or agreed to in writing, |
12 | | // software distributed under the License is distributed on an |
13 | | // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
14 | | // KIND, either express or implied. See the License for the |
15 | | // specific language governing permissions and limitations |
16 | | // under the License. |
17 | | |
18 | | // mcpack2pb - Make protobuf be front-end of mcpack/compack |
19 | | |
20 | | // Date: Mon Oct 19 17:17:36 CST 2015 |
21 | | |
22 | | #ifndef MCPACK2PB_MCPACK_PARSER_H |
23 | | #define MCPACK2PB_MCPACK_PARSER_H |
24 | | |
25 | | #include <limits> // std::numeric_limits |
26 | | #include <google/protobuf/io/zero_copy_stream.h> |
27 | | #include "butil/logging.h" |
28 | | #include "butil/strings/string_piece.h" |
29 | | #include "mcpack2pb/field_type.h" |
30 | | |
31 | | // CAUTION: Methods in this header is not intended to be public to users of |
32 | | // brpc, and subject to change at any future time. |
33 | | |
34 | | namespace mcpack2pb { |
35 | | |
36 | | // Read bytes from ZeroCopyInputStream |
37 | | class InputStream { |
38 | | public: |
39 | | InputStream(google::protobuf::io::ZeroCopyInputStream* stream) |
40 | | : _good(true) |
41 | | , _size(0) |
42 | | , _data(NULL) |
43 | | , _zc_stream(stream) |
44 | | , _popped_bytes(0) |
45 | 0 | {} |
46 | | |
47 | 0 | ~InputStream() { } |
48 | | |
49 | | // Pop at-most n bytes from front side. |
50 | | // Returns bytes popped. |
51 | | size_t popn(size_t n); |
52 | | |
53 | | // Cut off at-most n bytes from front side and copy to `out'. |
54 | | // Returns bytes cut. |
55 | | size_t cutn(void* out, size_t n); |
56 | | |
57 | | template <typename T> size_t cut_packed_pod(T* packed_pod); |
58 | | template <typename T> T cut_packed_pod(); |
59 | | |
60 | | // Cut off at-most n bytes from front side. If the data is stored in |
61 | | // continuous memory, return the reference directly, otherwise copy |
62 | | // the data into `aux' and return reference of `aux'. |
63 | | // Returns a StringPiece referencing the cut-off data. |
64 | | butil::StringPiece ref_cut(std::string* aux, size_t n); |
65 | | |
66 | | // Peek at the first character. If the stream is empty, 0 is returned. |
67 | | uint8_t peek1(); |
68 | | |
69 | | // Returns bytes popped and cut since creation of this stream. |
70 | 0 | size_t popped_bytes() const { return _popped_bytes; } |
71 | | |
72 | | // Returns false if error occurred in other consuming functions. |
73 | 0 | bool good() const { return _good; } |
74 | | |
75 | | // If the error prevents parsing from going on, call this method. |
76 | | // This method is also called in other functions in this class. |
77 | 0 | void set_bad() { _good = false; } |
78 | | |
79 | | private: |
80 | | bool _good; |
81 | | int _size; |
82 | | const void* _data; |
83 | | google::protobuf::io::ZeroCopyInputStream* _zc_stream; |
84 | | size_t _popped_bytes; |
85 | | }; |
86 | | |
87 | | class ObjectIterator; |
88 | | class ArrayIterator; |
89 | | class ISOArrayIterator; |
90 | | |
91 | | // Represent a piece of unparsed(and unread) data of InputStream. |
92 | | struct UnparsedValue { |
93 | | UnparsedValue() |
94 | 0 | : _type(FIELD_UNKNOWN), _stream(NULL), _size(0) {} |
95 | | UnparsedValue(FieldType type, InputStream* stream, size_t size) |
96 | 0 | : _type(type), _stream(stream), _size(size) {} |
97 | 0 | void set(FieldType type, InputStream* stream, size_t size) { |
98 | 0 | _type = type; |
99 | 0 | _stream = stream; |
100 | 0 | _size = size; |
101 | 0 | } |
102 | | |
103 | 0 | FieldType type() const { return _type; } |
104 | 0 | InputStream* stream() { return _stream; } |
105 | 0 | const InputStream* stream() const { return _stream; } |
106 | 0 | size_t size() const { return _size; } |
107 | | |
108 | | // Convert to concrete value. These functions can only be called once! |
109 | | ObjectIterator as_object(); |
110 | | ArrayIterator as_array(); |
111 | | ISOArrayIterator as_iso_array(); |
112 | | // `var' in following methods should be a description of the field being |
113 | | // parsed, for better error reporting. It has nothing to do with the result. |
114 | | int64_t as_int64(const char* var); |
115 | | uint64_t as_uint64(const char* var); |
116 | | int32_t as_int32(const char* var); |
117 | | uint32_t as_uint32(const char* var); |
118 | | bool as_bool(const char* var); |
119 | | float as_float(const char* var); |
120 | | double as_double(const char* var); |
121 | | void as_string(std::string* out, const char* var); |
122 | | std::string as_string(const char* var); |
123 | | void as_binary(std::string* out, const char* var); |
124 | | std::string as_binary(const char* var); |
125 | | |
126 | | private: |
127 | | friend class ObjectIterator; |
128 | | friend class ArrayIterator; |
129 | 0 | void set_end() { _type = FIELD_UNKNOWN; } |
130 | | |
131 | | FieldType _type; |
132 | | InputStream* _stream; |
133 | | size_t _size; |
134 | | }; |
135 | | |
136 | | std::ostream& operator<<(std::ostream& os, const UnparsedValue& value); |
137 | | |
138 | | // Remove the header of the wrapping object. |
139 | | // Returns the value size. |
140 | | size_t unbox(InputStream* stream); |
141 | | |
142 | | // Iterator all fields in an object which should be created like this: |
143 | | // ObjectIterator it(unparsed_value); |
144 | | // for (; it != NULL; ++it) { |
145 | | // std::cout << "name=" << it->name << " value=" << it->value << std::endl; |
146 | | // } |
147 | | class ObjectIterator { |
148 | | public: |
149 | | struct Field { |
150 | | butil::StringPiece name; |
151 | | UnparsedValue value; |
152 | | }; |
153 | | |
154 | | // Parse `n' bytes from `stream' as fields of an object. |
155 | 0 | ObjectIterator(InputStream* stream, size_t n) { init(stream, n); } |
156 | | explicit ObjectIterator(UnparsedValue& value) |
157 | 0 | { init(value.stream(), value.size()); } |
158 | 0 | ~ObjectIterator() {} |
159 | | |
160 | 0 | Field* operator->() { return &_current_field; } |
161 | 0 | Field& operator*() { return _current_field; } |
162 | | void operator++(); |
163 | 0 | operator void*() const { return (void*)_current_field.value.type(); } |
164 | | |
165 | | // Number of fields in the object. |
166 | 0 | uint32_t field_count() const { return _field_count; } |
167 | | |
168 | | private: |
169 | | void init(InputStream* stream, size_t n); |
170 | 0 | void set_bad() { |
171 | 0 | set_end(); |
172 | 0 | _stream->set_bad(); |
173 | 0 | } |
174 | 0 | void set_end() { _current_field.value._type = FIELD_UNKNOWN; } |
175 | | size_t left_size() const |
176 | 0 | { return _expected_popped_end - _expected_popped_bytes; } |
177 | | |
178 | | Field _current_field; |
179 | | uint32_t _field_count; |
180 | | std::string _name_backup_string; |
181 | | InputStream* _stream; |
182 | | size_t _expected_popped_bytes; |
183 | | size_t _expected_popped_end; |
184 | | }; |
185 | | |
186 | | // Iterator all items in a (mcpack) array which should be created like this: |
187 | | // ArrayIterator it(unparsed_value); |
188 | | // for (; it != NULL; ++it) { |
189 | | // std::cout << " item=" << *it << std::endl; |
190 | | // } |
191 | | class ArrayIterator { |
192 | | public: |
193 | | typedef UnparsedValue Field; |
194 | | |
195 | 0 | ArrayIterator(InputStream* stream, size_t size) { init(stream, size); } |
196 | | explicit ArrayIterator(UnparsedValue& value) |
197 | 0 | { init(value.stream(), value.size()); } |
198 | 0 | ~ArrayIterator() {} |
199 | | |
200 | 0 | Field* operator->() { return &_current_field; } |
201 | 0 | Field& operator*() { return _current_field; } |
202 | | void operator++(); |
203 | 0 | operator void*() const { return (void*)_current_field.type(); } |
204 | | |
205 | | // Number of items in the array. |
206 | 0 | uint32_t item_count() const { return _item_count; } |
207 | | |
208 | | private: |
209 | | void init(InputStream* stream, size_t n); |
210 | 0 | void set_bad() { |
211 | 0 | set_end(); |
212 | 0 | _stream->set_bad(); |
213 | 0 | } |
214 | 0 | void set_end() { _current_field._type = FIELD_UNKNOWN; } |
215 | | size_t left_size() const |
216 | 0 | { return _expected_popped_end - _expected_popped_bytes; } |
217 | | |
218 | | Field _current_field; |
219 | | uint32_t _item_count; |
220 | | InputStream* _stream; |
221 | | size_t _expected_popped_bytes; |
222 | | size_t _expected_popped_end; |
223 | | }; |
224 | | |
225 | | // Iterator all items in an isomorphic array which should be created like this: |
226 | | // ISOArrayIterator it(unparsed_value); |
227 | | class ISOArrayIterator { |
228 | | public: |
229 | 0 | ISOArrayIterator(InputStream* stream, size_t size) { init(stream, size); } |
230 | | explicit ISOArrayIterator(UnparsedValue& value) |
231 | 0 | { init(value.stream(), value.size()); } |
232 | 0 | ~ISOArrayIterator() {} |
233 | | void operator++(); |
234 | 0 | operator void*() const { return (void*)(uintptr_t)_item_type; } |
235 | | |
236 | | template <typename T> T as_integer() const; |
237 | | template <typename T> T as_fp() const; |
238 | 0 | int64_t as_int64() const { return as_integer<int64_t>(); } |
239 | 0 | uint64_t as_uint64() const { return as_integer<uint64_t>(); } |
240 | 0 | int32_t as_int32() const { return as_integer<int32_t>(); } |
241 | 0 | uint32_t as_uint32() const { return as_integer<uint32_t>(); } |
242 | 0 | bool as_bool() const { return as_integer<bool>(); } |
243 | 0 | float as_float() const { return as_fp<float>(); } |
244 | 0 | double as_double() const { return as_fp<double>(); } |
245 | | |
246 | 0 | PrimitiveFieldType item_type() const { return _item_type; } |
247 | | |
248 | | // Number of items in the array. |
249 | 0 | uint32_t item_count() const { return _item_count; } |
250 | | |
251 | | private: |
252 | | void init(InputStream* stream, size_t n); |
253 | 0 | void set_bad() { |
254 | 0 | set_end(); |
255 | 0 | _stream->set_bad(); |
256 | 0 | } |
257 | 0 | void set_end() { _item_type = (PrimitiveFieldType)0; } |
258 | | |
259 | | int _buf_index; |
260 | | int _buf_count; |
261 | | InputStream* _stream; |
262 | | PrimitiveFieldType _item_type; |
263 | | uint32_t _item_size; |
264 | | uint32_t _item_count; |
265 | | uint32_t _left_item_count; |
266 | | char _item_buf[1024]; |
267 | | }; |
268 | | |
269 | | } // namespace mcpack2pb |
270 | | |
271 | | #include "mcpack2pb/parser-inl.h" |
272 | | |
273 | | #endif // MCPACK2PB_MCPACK_PARSER_H |