Coverage Report

Created: 2023-11-19 06:38

/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