io.h revision bb621b95ea636314c87b885107c8d5331992f9bb
1/*
2 * Copyright (C) 2016 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#ifndef NVRAM_MESSAGES_IO_H_
18#define NVRAM_MESSAGES_IO_H_
19
20extern "C" {
21#include <stddef.h>
22#include <stdint.h>
23}
24
25#include <nvram/messages/blob.h>
26#include <nvram/messages/compiler.h>
27
28namespace nvram {
29
30// Abstraction used by the protobuf decoder to read data. The idea here is that
31// |InputStreamBuffer| maintains a window of the data to be read. Access to the
32// contents of the current window is direct, i.e. doesn't need to go through
33// virtual dispatch to subclasses. Whenever the window is exhausted, the next
34// window must be set up. This latter operation is left for implementation of
35// the virtual |Advance()| member function in subclasses, which is entirely free
36// to pull its data from anywhere.
37class NVRAM_EXPORT InputStreamBuffer {
38 public:
39  InputStreamBuffer() = default;
40  InputStreamBuffer(const void* data, size_t size);
41  InputStreamBuffer(const void* start, const void* end);
42  virtual ~InputStreamBuffer() = default;
43
44  // Checks whether the stream is exhausted;
45  bool Done();
46
47  // Consume |size| bytes from the stream and store them in the provided |data|
48  // buffer. Returns false if insufficient bytes are available.
49  bool Read(void* data, size_t size);
50
51  // Consume a single byte and place it in |byte|. Returns true if successful,
52  // i.e. if there was a byte available.
53  bool ReadByte(uint8_t* byte);
54
55  // Discard |size| bytes from the stream. Returns false if there are fewer
56  // bytes available.
57  bool Skip(size_t size);
58
59 protected:
60  // Update the |pos_| and |end_| pointers for the next buffer window. Returns
61  // true if the window was successfully set up, false on I/O errors or stream
62  // exhaustion. The default implementation just returns false to signal
63  // immediate stream exhaustion. Subclasses should override this to pull in
64  // more data from the underlying data source.
65  virtual bool Advance();
66
67  // Pointers to the buffer to read from. |InputStreamBuffer| only advances
68  // |pos_| until reaching |end_|. At this point, |Advance| is called for the
69  // subclass to initialize the next buffer window and update the pointers.
70  const uint8_t* pos_ = nullptr;
71  const uint8_t* end_ = nullptr;
72
73  // Allow |NestedInputStreamBuffer| to mess with |pos_| and |end_|, also in its
74  // delegate, which isn't necessarily of type |NestedInputStreamBuffer|.
75  friend class NestedInputStreamBuffer;
76};
77
78// An |InputStreamBuffer| implementation that pulls its data from a delegate,
79// but only up to a predetermined limit of bytes.
80class NVRAM_EXPORT NestedInputStreamBuffer : public InputStreamBuffer {
81 public:
82  // Initialize a |NestedInputStreamBuffer| to provide at most |size| bytes from
83  // |delegate|. Note that |delegate| must remain valid throughout the life time
84  // of this |NestedInputStreamBuffer|.
85  NestedInputStreamBuffer(InputStreamBuffer* delegate, size_t size);
86  ~NestedInputStreamBuffer() override = default;
87
88 private:
89  // InputStreamBuffer:
90  bool Advance() override;
91
92  // Determine the input window end based on |delegate|'s current window and the
93  // requested |size| to read. If |size| can be satisfied from |delegate|'s
94  // current window, return an end pointer within that window. If size is larger
95  // than the remaining bytes available in |delegate|'s input window, return
96  // |delegate|'s |end_| pointer.
97  static const uint8_t* ClampEnd(InputStreamBuffer* delegate, size_t size);
98
99  InputStreamBuffer* delegate_;
100  size_t remaining_;
101};
102
103// Abstraction used by the protobuf decoder to output data. This class maintains
104// a current window of memory to write output to. Access to the current window's
105// bytes is direct and doesn't require virtual dispatch. Once the capacity of
106// the current window is exhausted, the virtual |Advance()| member function is
107// invoked to set up a new window. Subclasses are entirely free to implement
108// this operation as appropriate for their I/O mechanism, for example a
109// socket-based implementations might flush the buffer to the socket and reset
110// the window pointers to accept more output.
111class NVRAM_EXPORT OutputStreamBuffer {
112 public:
113  OutputStreamBuffer() = default;
114  OutputStreamBuffer(void* data, size_t size);
115  OutputStreamBuffer(void* data, void* end);
116  virtual ~OutputStreamBuffer() = default;
117
118  // Checks whether the stream is exhausted.
119  bool Done();
120
121  // Writes a blob of |size| bytes provided in |data| to the underlying buffer.
122  // Returns false if there is not enough space available.
123  bool Write(const void* data, size_t size);
124
125  // Writes |byte| to the underlying buffer. Returns false if there is not
126  // enough space available.
127  bool WriteByte(uint8_t byte);
128
129 protected:
130  // Set up the next data buffer window in |pos_| and |end_|. Returns true on
131  // success, false on I/O errors or stream exhaustion. The default
132  // implementation unconditionally returns false, i.e. signaling stream
133  // exhaustion after the initial window is filled. Subclasses should override
134  // this to flush buffers to the underlying data sink and set up a fresh buffer
135  // for more data as appropriate.
136  virtual bool Advance();
137
138  // The |pos_| and |end_| pointers define a window of writable buffer space for
139  // |OutputStreamBuffer| to place data in. |pos_| grows towards |end_| as
140  // writes occur. Once |pos_| hits |end_|, |OutputStreamBuffer| will call
141  // |Advance|, which subclasses can implement to provide a new buffer window in
142  // |pos_| and |end_|.
143  uint8_t* pos_ = nullptr;
144  uint8_t* end_ = nullptr;
145};
146
147// An |OutputStreamBuffer| backed by a single data buffer.
148class NVRAM_EXPORT ArrayOutputStreamBuffer : public OutputStreamBuffer {
149 public:
150  ArrayOutputStreamBuffer() = default;
151  ArrayOutputStreamBuffer(void* data, size_t size)
152      : OutputStreamBuffer(data, size), data_(pos_) {}
153  ArrayOutputStreamBuffer(void* data, void* end)
154      : OutputStreamBuffer(data, end), data_(pos_) {}
155  ~ArrayOutputStreamBuffer() override = default;
156
157  // Returns the number of bytes already written.
158  size_t bytes_written() const { return pos_ - data_; }
159
160 private:
161  uint8_t* data_ = nullptr;
162};
163
164// An |OutputStream| implementation that doesn't write anything, but just counts
165// the number of bytes written.
166class NVRAM_EXPORT CountingOutputStreamBuffer : public OutputStreamBuffer {
167 public:
168  CountingOutputStreamBuffer();
169  ~CountingOutputStreamBuffer() override = default;
170
171  size_t bytes_written() const {
172    return bytes_written_ + (pos_ - scratch_space_);
173  }
174
175 protected:
176  // OutputStreamBuffer:
177  bool Advance() override;
178
179 private:
180  // We share a single scratch buffer that all |CountingOutputStreamBuffer|
181  // instances use as the destination for writes. Its contents are pretty much
182  // unpredictable.
183  //
184  // TODO(mnissler): This adds a static 256 bytes memory allocation to each
185  // process linking to this code. If that becomes a problem, we might want to
186  // be smarter here and dynamically allocate a chunk of memory only when it's
187  // needed, or maybe even map some address space that's not even backed by
188  // actual memory (not sure that's possible).
189  static constexpr size_t kScratchSpaceSize = 256;
190  static uint8_t scratch_space_[kScratchSpaceSize];
191
192  // Number of bytes that had been written when the last |Advance()| call
193  // occurred.
194  size_t bytes_written_ = 0;
195};
196
197// An |OutputStreamBuffer| implementation that stores all data to a wrapped
198// |Blob|, growing it as necessary.
199class NVRAM_EXPORT BlobOutputStreamBuffer : public OutputStreamBuffer {
200 public:
201  // Construct a |BlobOutputStreamBuffer| that stores all written data to
202  // |blob|, which will get resized as necessary. Note that |blob| must remain
203  // valid for the life time of the |BlobOutputStreamBuffer| object.
204  explicit BlobOutputStreamBuffer(Blob* blob);
205  ~BlobOutputStreamBuffer() override = default;
206
207  // Truncate the blob to match the current output size.
208  bool Truncate();
209
210 protected:
211  // OutputStreamBuffer:
212  bool Advance() override;
213
214 private:
215  Blob* blob_;
216};
217
218// Protobuf wire types.
219enum class WireType : int8_t {
220  kVarint = 0,
221  kFixed64 = 1,
222  kLengthDelimited = 2,
223  kStartGroup = 3,
224  kEndGroup = 4,
225  kFixed32 = 5,
226};
227
228// A class implementing a parser for the low-level protobuf wire format. It
229// obtains raw data from a wrapped |InputStream| and offers member functions
230// that facilitate decoding the data according to the protobuf wire format.
231class NVRAM_EXPORT ProtoReader {
232 public:
233  // Construct a new |ProtoReader| that consumes data from |stream_buffer|.
234  // |stream_buffer| must remain valid throughout the life time of the
235  // |ProtoReader|.
236  explicit ProtoReader(InputStreamBuffer* stream_buffer);
237
238  // Access to the underlying stream buffer.
239  InputStreamBuffer* stream_buffer() { return stream_buffer_; }
240
241  // Wire type of the current field.
242  WireType wire_type() const { return static_cast<WireType>(wire_type_); }
243
244  // Field number of the current field.
245  uint64_t field_number() const { return field_number_; }
246
247  // Size of the field data, if known in advance.
248  size_t field_size() const { return field_size_; }
249
250  // Whether all data is consumed.
251  bool Done() const { return stream_buffer_->Done(); }
252
253  // Reads the next wire tag from the current position in the underlying
254  // |stream_buffer_| and initializes internal fields. Previous state is
255  // discarded silently.
256  bool ReadWireTag();
257
258  // Read a varint-encoded field and advances to the next field. Returns true if
259  // successful.
260  bool ReadVarint(uint64_t* value);
261
262  // Read field data. Checks that |size| matches |field_size()| and copies out
263  // the data to the provided |data| buffer. Advances to the next field and
264  // returns true if successful.
265  bool ReadLengthDelimited(void* data, size_t size);
266
267  // Skips over the current field data.
268  bool SkipField();
269
270 private:
271  static constexpr int8_t kInvalidWireType = -1;
272
273  InputStreamBuffer* stream_buffer_;
274
275  // Information about the current field. |wire_type == kInvalidWireType|
276  // indicates that there is no current field to be consumed.
277  int8_t wire_type_ = kInvalidWireType;
278  uint64_t field_number_ = 0;
279  size_t field_size_ = 0;
280};
281
282// |ProtoWriter| contains logic to write raw data according to the protobuf wire
283// format to an |OutputStreamBuffer|.
284class NVRAM_EXPORT ProtoWriter {
285 public:
286  // Construct a |ProtoWriter| which will send its output to |stream_buffer|.
287  // |stream_buffer| must remain valid for the life time of the |ProtoWriter|.
288  explicit ProtoWriter(OutputStreamBuffer* stream_buffer);
289
290  // Access to the underlying stream buffer.
291  OutputStreamBuffer* stream_buffer() { return stream_buffer_; }
292
293  // Sets the field number to use when emitting a tag.
294  void set_field_number(uint64_t field_number) { field_number_ = field_number; }
295
296  // Whether the writer has exhausted the underlying |OutputStream|'s capacity.
297  bool Done() const { return stream_buffer_->Done(); }
298
299  // Write |value| as a varint-encoded field. Returns true if successful, i.e.
300  // the data was successfully written to |stream_buffer_|.
301  bool WriteVarint(uint64_t value);
302
303  // Write |size| bytes stored at |data| to |stream_buffer_|. Returns true if
304  // successful, i.e. the data was successfully written to |stream_buffer_|.
305  bool WriteLengthDelimited(const void* data, size_t size);
306
307  // Writes a wire tag for a length-delimited field, followed by a length
308  // indication for |size| data bytes. It is up to the caller to emit exactly
309  // |size| bytes to |stream_buffer()|, otherwise the encoded data will be
310  // malformed.
311  bool WriteLengthHeader(size_t size);
312
313 private:
314  // A helper to write a wire tag using the current field number and the
315  // provided wire type.
316  bool WriteWireTag(WireType wire_type);
317
318  OutputStreamBuffer* stream_buffer_;
319  uint64_t field_number_ = 0;
320};
321
322}  // namespace nvram
323
324#endif  // NVRAM_MESSAGES_IO_H_
325