1 : // Copyright 2014 Google Inc. All Rights Reserved.
2 : //
3 : // Licensed under the Apache License, Version 2.0 (the "License");
4 : // you may not use this file except in compliance with the License.
5 : // You may obtain a copy of the License at
6 : //
7 : // http://www.apache.org/licenses/LICENSE-2.0
8 : //
9 : // Unless required by applicable law or agreed to in writing, software
10 : // distributed under the License is distributed on an "AS IS" BASIS,
11 : // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 : // See the License for the specific language governing permissions and
13 : // limitations under the License.
14 : //
15 : // A utility class for safe and easy parsing of binary buffers.
16 :
17 : #ifndef SYZYGY_COMMON_BUFFER_PARSER_H_
18 : #define SYZYGY_COMMON_BUFFER_PARSER_H_
19 :
20 : #include "base/basictypes.h"
21 :
22 : namespace common {
23 :
24 : // A binary buffer parser
25 : class BinaryBufferParser {
26 : public:
27 : // This object is allowed to have copy constructors.
28 :
29 : BinaryBufferParser();
30 : BinaryBufferParser(const void* data, size_t data_len);
31 :
32 : // Sets the data associated to be parsed. Allows initializing this object
33 : // after construction.
34 : //
35 : // @param data the data to be parsed.
36 : // @param data_len the length of the data.
37 : void SetData(const void* data, size_t data_len);
38 :
39 : // Accessors.
40 E : const void* data() const { return data_; }
41 E : size_t data_len() const { return data_len_; }
42 :
43 : // Check whether the buffer contains the range of data from @p pos to
44 : // @p pos + @p data_len.
45 : // @param pos the byte position of the start of the data range.
46 : // @param data_len the byte length of the data range.
47 : // @returns true iff the range of bytes from @p pos to @p pos + @p data_len.
48 : bool Contains(size_t pos, size_t data_len) const;
49 :
50 : // Retrieve a pointer into the buffer if the requested data is contained
51 : // in our buffer.
52 : // @param pos the position to get a pointer to.
53 : // @param data_len the amount of data expected behind @p pos.
54 : // @param data_ptr on success will contain a pointer to @p pos in data.
55 : // @returns true iff Contains(pos, data_len).
56 : // @note No alignment constraints are checked.
57 : bool GetAt(size_t pos, size_t data_len, const void** data_ptr) const;
58 :
59 : // Retrieve a typed pointer into the buffer if the requested data
60 : // is contained in our buffer.
61 : // @param pos the position to get a pointer to.
62 : // @param data_len the amount of data expected behind @p pos.
63 : // @param data_ptr on success will contain a pointer to @p pos in data.
64 : // @returns true on success, false otherwise.
65 : // @note The basic version of the function checks @p pos for alignment,
66 : // whereas the IgnoreAlignment version ignores it.
67 : template <class DataType>
68 E : bool GetAt(size_t pos, size_t data_len, const DataType** data_ptr) const {
69 E : return GetAtImplicitAlignment(pos, data_len, data_ptr);
70 E : }
71 : template <class DataType>
72 : bool GetAtIgnoreAlignment(
73 : size_t pos, size_t data_len, const DataType** data_ptr) const {
74 : return GetAtExplicitAlignment(pos, data_len, 1, data_ptr);
75 : }
76 :
77 : // Retrieve a typed pointer into the buffer if the requested structure
78 : // fits into our buffer at position @pos.
79 : // @param pos the position to get a pointer to.
80 : // @param data_ptr on success will contain a pointer to @p pos in data.
81 : // @returns true on success, false otherwise.
82 : // @note The basic version of the function checks @p pos for alignment,
83 : // whereas the IgnoreAlignment version ignores it.
84 : template <class DataType>
85 E : bool GetAt(size_t pos, const DataType** data_ptr) const {
86 E : return GetAtImplicitAlignment(pos, sizeof(DataType), data_ptr);
87 E : }
88 : template <class DataType>
89 E : bool GetAtIgnoreAlignment(size_t pos, const DataType** data_ptr) const {
90 E : return GetAtExplicitAlignment(pos, sizeof(DataType), 1, data_ptr);
91 E : }
92 :
93 : // Retrieve a typed pointer to an array if the requested array fits into
94 : // the buffer at the given position.
95 : // @param pos the position to get a pointer to.
96 : // @param count the number of elements to retrieve.
97 : // @param data_ptr on success will contain a pointer to @p pos in data.
98 : // @returns true on success, false otherwise.
99 : // @note The basic version of the function checks @p pos for alignment,
100 : // whereas the IgnoreAlignment version ignores it.
101 : template <class DataType>
102 E : bool GetCountAt(size_t pos, size_t count, const DataType** data_ptr) const {
103 E : return GetAtImplicitAlignment(pos, sizeof(DataType) * count, data_ptr);
104 E : }
105 : template <class DataType>
106 : bool GetCountAtIgnoreAlignment(
107 E : size_t pos, size_t count, const DataType** data_ptr) const {
108 E : return GetAtExplicitAlignment(pos, sizeof(DataType) * count, 1, data_ptr);
109 E : }
110 :
111 : // Get a zero terminated string starting at the byte offset @p pos.
112 : // @param pos the byte offset where the string starts.
113 : // @param ptr on success returns the string pointer.
114 : // @param len on success returns the string character length.
115 : // @returns true on success, e.g. there's a zero termiator in the buffer
116 : // after @p pos, or false on failure, when @p pos is outside the buffer
117 : // or there is no zero terminator in the buffer after @p pos.
118 : // @note this function does not check @pos for appropriate alignment.
119 : // @note The basic version of the function checks @p pos for alignment,
120 : // whereas the IgnoreAlignment version ignores it.
121 : bool GetStringAt(size_t pos, const char** ptr, size_t* len) const;
122 : bool GetStringAt(size_t pos, const wchar_t** ptr, size_t* len) const;
123 : bool GetStringAtIgnoreAlignment(
124 : size_t pos, const wchar_t** ptr, size_t* len) const;
125 :
126 : protected:
127 : template <class DataType>
128 : bool GetAtImplicitAlignment(
129 : size_t pos, size_t size, const DataType** data_ptr) const;
130 :
131 : template <class DataType>
132 : bool GetAtExplicitAlignment(
133 : size_t pos, size_t size, size_t align, const DataType** data_ptr) const;
134 :
135 : const int8* data_;
136 : size_t data_len_;
137 : };
138 :
139 : // A binary buffer reader allows reading sequentially from a binary buffer,
140 : // as well as peeking at the current position without moving it.
141 : class BinaryBufferReader {
142 : public:
143 : BinaryBufferReader(const void* data, size_t data_len);
144 :
145 : // Accessors.
146 E : size_t pos() const { return pos_; }
147 E : void set_pos(size_t pos) { pos_ = pos; }
148 :
149 : // Calculate the number of bytes remaining in the buffer.
150 : // @returns the number of bytes remaining in the buffer.
151 : size_t RemainingBytes() const;
152 : // Advance the read position by @p bytes.
153 : // @param bytes the number of bytes to advance the read position.
154 : // @returns true iff the new position is in our buffer.
155 : bool Consume(size_t bytes);
156 :
157 : // Align the read position to the next even multiple of @p bytes.
158 : // @param bytes the byte alignment, must be a power of two.
159 : // @returns true iff the new position is in our buffer.
160 : bool Align(size_t bytes);
161 :
162 : // Check whether the read position is aligned to bytes.
163 : // @param bytes the byte alignment to check, must be a power of two.
164 : // @returns true iff the current position is an integer multiple of @p bytes.
165 : bool IsAligned(size_t bytes);
166 :
167 : // Retrieve a pointer into our buffer, without moving the read position.
168 : bool Peek(size_t data_len, const void** data);
169 : template <class DataType>
170 : bool Peek(size_t data_len, const DataType** data_ptr) {
171 : return Peek(data_len, reinterpret_cast<const void**>(data_ptr));
172 : }
173 : template <class DataType>
174 : bool Peek(const DataType** data_ptr) {
175 : return Peek(sizeof(**data_ptr), data_ptr);
176 : }
177 :
178 : // Retrieve a pointer into our buffer and advance the read position.
179 : bool Read(size_t data_len, const void** data);
180 : template <class DataType>
181 E : bool Read(size_t data_len, const DataType** data_ptr) {
182 E : return Read(data_len, reinterpret_cast<const void**>(data_ptr));
183 E : }
184 : template <class DataType>
185 E : bool Read(const DataType** data_ptr) {
186 E : return Read(sizeof(**data_ptr), data_ptr);
187 E : }
188 :
189 : // Retrieve a zero-terminated string from our buffer without
190 : // advancing the read position.
191 : bool PeekString(const char** str, size_t* str_len);
192 : bool PeekString(const wchar_t** str, size_t* str_len);
193 :
194 : // Retrieve a zero-terminated string from our buffer and
195 : // advance the read position.
196 : bool ReadString(const char** str, size_t* str_len);
197 : bool ReadString(const wchar_t** str, size_t* str_len);
198 :
199 : private:
200 : // The buffer we read from.
201 : BinaryBufferParser parser_;
202 : // Current position.
203 : size_t pos_;
204 : };
205 :
206 : } // namespace common
207 :
208 : #include "syzygy/common/buffer_parser_impl.h"
209 :
210 : #endif // SYZYGY_COMMON_BUFFER_PARSER_H_
|