1 : // Copyright 2012 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 : #ifndef SYZYGY_PDB_PDB_STREAM_H_
16 : #define SYZYGY_PDB_PDB_STREAM_H_
17 :
18 : #include <stdio.h>
19 : #include <vector>
20 :
21 : #include "base/basictypes.h"
22 : #include "base/logging.h"
23 : #include "base/memory/ref_counted.h"
24 : #include "syzygy/common/buffer_writer.h"
25 :
26 : namespace pdb {
27 :
28 : // Forward declaration.
29 : class WritablePdbStream;
30 :
31 : // This class represents a PDB stream. It has a stream-like interface that
32 : // allows invoking successive reads through the stream and seeking.
33 : class PdbStream : public base::RefCounted<PdbStream> {
34 : public:
35 : explicit PdbStream(size_t length);
36 :
37 : // Reads @p count chunks of size sizeof(ItemType) into the destination buffer.
38 : // The caller is responsible for ensuring that the destination buffer has
39 : // enough space to receive the data. Returns the number of items successfully
40 : // read via @p items_read.
41 : //
42 : // @tparam ItemType the type of item to coerce the data to.
43 : // @param dest the destination array.
44 : // @param count the number of elements to read.
45 : // @param items_read pointer to receive the number of items successfully read.
46 : // @returns true on success.
47 : template <typename ItemType>
48 : bool Read(ItemType* dest, size_t count, size_t* items_read);
49 :
50 : // Reads @p count chunks of size sizeof(ItemType) into the destination buffer.
51 : // The caller is responsible for ensuring that the destination buffer has
52 : // enough space to receive the data.
53 : //
54 : // @tparam ItemType the type of item to coerce the data to.
55 : // @param dest the destination array.
56 : // @param count the number of elements to read.
57 : // @returns true on success.
58 : template <typename ItemType>
59 : bool Read(ItemType* dest, size_t count);
60 :
61 : // Reads @p count elements of size sizeof(ItemType) into the provided
62 : // vector of elements. Resizes @p dest to the number of elements that were
63 : // successfully read.
64 : //
65 : // @tparam ItemType the type of item to coerce the data to.
66 : // @param dest the destination vector.
67 : // @param count the number of elements to read.
68 : // @returns true if @p dest was populated with @p count elements, false
69 : // otherwise. The number of elements actually read is indicated by the
70 : // length of @p dest.
71 : template <typename ItemType>
72 : bool Read(std::vector<ItemType>* dest, size_t count);
73 :
74 : // Fills the provided vector with elements read from this stream. The bytes
75 : // remaining in the stream must be an even multiple of sizeof(ItemType).
76 : // Resizes @p dest to the number of elements read.
77 : //
78 : // @tparam ItemType the type of item to coerce the data to.
79 : // @param dest the destination vector.
80 : // @returns true if the remaining bytes in the stream were read into the
81 : // provided vector, false otherwise. The number of elements actually read
82 : // is indicated by the length of @p dest.
83 : template <typename ItemType>
84 : bool Read(std::vector<ItemType>* dest);
85 :
86 : // Reads @p count bytes of data into the destination buffer. The caller is
87 : // responsible for ensuring that the destination buffer has enough space to
88 : // receive the data. @p bytes_read will hold the number of bytes read. If
89 : // there was insufficient data but some bytes were read, returns false and
90 : // returns the number of bytes read via @p bytes_read.
91 : //
92 : // @param dest the buffer to receive the data.
93 : // @param count the number of bytes to read.
94 : // @param bytes_read pointer that will receive the number of bytes read.
95 : // @returns true if all @p count bytes are read, false otherwise.
96 : virtual bool ReadBytes(void* dest, size_t count, size_t* bytes_read) = 0;
97 :
98 : // Returns a pointer to a WritablePdbStream if the underlying object supports
99 : // this interface. If this returns non-NULL, it is up to the user to ensure
100 : // thread safety; each writer should be used exclusively of any other writer,
101 : // and no reader should be used while a writer is in use. Each of the reader
102 : // and writer maintains its own cursor, but their view of the data (and its
103 : // length) will remain in sync.
104 : //
105 : // NOTE: This function should act as a factory, with each call returning a
106 : // heap allocated reference counted writer. However, since each
107 : // WritablePdbStream is currently implemented using a BufferWriter, and
108 : // the BufferWriter maintains its own state internally rather than a
109 : // shared state, its possible that one writer causing a resize could
110 : // invalidate the internal data pointer held by another writer. As a
111 : // workaround, there is only a single writer allowed to be allocated
112 : // right now.
113 : //
114 : // TODO(chrisha): Clean this up to return an interface, which can be wrapped
115 : // in some common stream-writer functionality, reusing BufferWriter.
116 : //
117 : // @returns a pointer to a WritablePdbStream.
118 E : virtual scoped_refptr<WritablePdbStream> GetWritablePdbStream() {
119 E : return scoped_refptr<WritablePdbStream>();
120 E : }
121 :
122 : // Sets the current read position.
123 : bool Seek(size_t pos);
124 :
125 : // Gets the stream's length.
126 : // @returns the total number of bytes in the stream.
127 E : size_t length() const { return length_; }
128 :
129 : // Gets the stream's read position.
130 : // @returns the number of bytes already read.
131 E : size_t pos() const { return pos_; }
132 :
133 : // Gets the number of bytes left to read in the stream.
134 : // @returns the number of bytes left.
135 E : size_t bytes_left() const { return length_ - pos_; }
136 :
137 : protected:
138 : friend base::RefCounted<PdbStream>;
139 :
140 : // Protected to enforce use of ref-counted pointers at compile time.
141 : virtual ~PdbStream();
142 :
143 : // Sets the stream's length.
144 E : void set_length(size_t length) { length_ = length; }
145 :
146 : private:
147 : // The length of the stream.
148 : size_t length_;
149 :
150 : // The read position within the stream.
151 : size_t pos_;
152 :
153 : DISALLOW_COPY_AND_ASSIGN(PdbStream);
154 : };
155 :
156 : // Represents a writable PDB stream.
157 : // TODO(chrisha): For now, this inherits from common::BufferWriter, but a far
158 : // cleaner approach would be to hoist a basic WritableStreamInterface, and
159 : // make BufferWriter accept a pointer to said interface. The same thing
160 : // could be done to the sawbuck BufferParser/BufferReader and PdbStream
161 : // hierarchy.
162 : class WritablePdbStream : public base::RefCounted<WritablePdbStream>,
163 : public common::BufferWriter {
164 : public:
165 : // Constructor.
166 E : WritablePdbStream() : common::BufferWriter(NULL, 0) { }
167 :
168 : protected:
169 : friend base::RefCounted<WritablePdbStream>;
170 :
171 : // Destructor. Protected to enforce use of ref-counted pointers at compile
172 : // time.
173 E : virtual ~WritablePdbStream() { }
174 :
175 : // Forwarded from common::BufferWriter.
176 : virtual uint8* GrowBuffer(size_t size) = 0;
177 : };
178 :
179 : template <typename ItemType>
180 E : bool PdbStream::Read(ItemType* dest, size_t count, size_t* items_read) {
181 E : DCHECK(dest != NULL);
182 E : DCHECK(items_read != NULL);
183 :
184 E : size_t byte_size = sizeof(ItemType) * count;
185 E : if (byte_size > bytes_left())
186 E : return false;
187 :
188 E : size_t bytes_read = 0;
189 E : bool result = ReadBytes(dest, byte_size, &bytes_read);
190 E : *items_read = bytes_read / sizeof(ItemType);
191 E : return result && *items_read == count;
192 E : }
193 :
194 : template <typename ItemType>
195 E : bool PdbStream::Read(ItemType* dest, size_t count) {
196 E : DCHECK(dest != NULL);
197 E : size_t items_read = 0;
198 E : return Read(dest, count, &items_read) && items_read == count;
199 E : }
200 :
201 : template <typename ItemType>
202 E : bool PdbStream::Read(std::vector<ItemType>* dest, size_t count) {
203 E : DCHECK(dest != NULL);
204 E : dest->clear();
205 E : if (sizeof(ItemType) * count > bytes_left())
206 E : return false;
207 E : dest->resize(count);
208 :
209 E : if (count == 0)
210 E : return true;
211 :
212 E : size_t items_read = 0;
213 E : bool result = Read(&dest->at(0), count, &items_read);
214 E : dest->resize(items_read);
215 E : return result;
216 E : }
217 :
218 : template <typename ItemType>
219 E : bool PdbStream::Read(std::vector<ItemType>* dest) {
220 E : DCHECK(dest != NULL);
221 E : dest->clear();
222 E : if ((bytes_left() % sizeof(ItemType)) != 0)
223 E : return false;
224 E : return Read(dest, bytes_left() / sizeof(ItemType));
225 E : }
226 :
227 : } // namespace pdb
228 :
229 : #endif // SYZYGY_PDB_PDB_STREAM_H_
|