1 : // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
2 : // Use of this source code is governed by a BSD-style license that can be
3 : // found in the LICENSE file.
4 :
5 : #ifndef BASE_PICKLE_H__
6 : #define BASE_PICKLE_H__
7 :
8 : #include <string>
9 :
10 : #include "base/basictypes.h"
11 : #include "base/logging.h"
12 : #include "base/string16.h"
13 : #include "testing/gtest/include/gtest/gtest_prod.h"
14 :
15 : // This class provides facilities for basic binary value packing and unpacking.
16 : //
17 : // The Pickle class supports appending primitive values (ints, strings, etc.)
18 : // to a pickle instance. The Pickle instance grows its internal memory buffer
19 : // dynamically to hold the sequence of primitive values. The internal memory
20 : // buffer is exposed as the "data" of the Pickle. This "data" can be passed
21 : // to a Pickle object to initialize it for reading.
22 : //
23 : // When reading from a Pickle object, it is important for the consumer to know
24 : // what value types to read and in what order to read them as the Pickle does
25 : // not keep track of the type of data written to it.
26 : //
27 : // The Pickle's data has a header which contains the size of the Pickle's
28 : // payload. It can optionally support additional space in the header. That
29 : // space is controlled by the header_size parameter passed to the Pickle
30 : // constructor.
31 : //
32 : class Pickle {
33 : public:
34 : ~Pickle();
35 :
36 : // Initialize a Pickle object using the default header size.
37 : Pickle();
38 :
39 : // Initialize a Pickle object with the specified header size in bytes, which
40 : // must be greater-than-or-equal-to sizeof(Pickle::Header). The header size
41 : // will be rounded up to ensure that the header size is 32bit-aligned.
42 : explicit Pickle(int header_size);
43 :
44 : // Initializes a Pickle from a const block of data. The data is not copied;
45 : // instead the data is merely referenced by this Pickle. Only const methods
46 : // should be used on the Pickle when initialized this way. The header
47 : // padding size is deduced from the data length.
48 : Pickle(const char* data, int data_len);
49 :
50 : // Initializes a Pickle as a deep copy of another Pickle.
51 : Pickle(const Pickle& other);
52 :
53 : // Performs a deep copy.
54 : Pickle& operator=(const Pickle& other);
55 :
56 : // Returns the size of the Pickle's data.
57 4 : int size() const { return static_cast<int>(header_size_ +
58 4 : header_->payload_size); }
59 :
60 : // Returns the data for this Pickle.
61 2 : const void* data() const { return header_; }
62 :
63 : // Methods for reading the payload of the Pickle. To read from the start of
64 : // the Pickle, initialize *iter to NULL. If successful, these methods return
65 : // true. Otherwise, false is returned to indicate that the result could not
66 : // be extracted.
67 : bool ReadBool(void** iter, bool* result) const;
68 : bool ReadInt16(void** iter, int16* result) const;
69 : bool ReadUInt16(void** iter, uint16* result) const;
70 : bool ReadShort(void** iter, short* result) const;
71 : bool ReadInt(void** iter, int* result) const;
72 : bool ReadLong(void** iter, long* result) const;
73 : bool ReadULong(void** iter, unsigned long* result) const;
74 : bool ReadSize(void** iter, size_t* result) const;
75 : bool ReadInt32(void** iter, int32* result) const;
76 : bool ReadUInt32(void** iter, uint32* result) const;
77 : bool ReadInt64(void** iter, int64* result) const;
78 : bool ReadUInt64(void** iter, uint64* result) const;
79 : bool ReadDouble(void** iter, double* result) const;
80 : bool ReadIntPtr(void** iter, intptr_t* result) const;
81 : bool ReadUnsignedChar(void** iter, unsigned char* result) const;
82 : bool ReadString(void** iter, std::string* result) const;
83 : bool ReadWString(void** iter, std::wstring* result) const;
84 : bool ReadString16(void** iter, string16* result) const;
85 : bool ReadData(void** iter, const char** data, int* length) const;
86 : bool ReadBytes(void** iter, const char** data, int length) const;
87 :
88 : // Safer version of ReadInt() checks for the result not being negative.
89 : // Use it for reading the object sizes.
90 : bool ReadLength(void** iter, int* result) const;
91 :
92 : // Methods for adding to the payload of the Pickle. These values are
93 : // appended to the end of the Pickle's payload. When reading values from a
94 : // Pickle, it is important to read them in the order in which they were added
95 : // to the Pickle.
96 0 : bool WriteBool(bool value) {
97 0 : return WriteInt(value ? 1 : 0);
98 : }
99 0 : bool WriteInt16(int16 value) {
100 0 : return WriteBytes(&value, sizeof(value));
101 : }
102 : bool WriteUInt16(uint16 value) {
103 : return WriteBytes(&value, sizeof(value));
104 : }
105 41886 : bool WriteInt(int value) {
106 41886 : return WriteBytes(&value, sizeof(value));
107 : }
108 0 : bool WriteLong(long value) {
109 : // Always written as a 64-bit value since the size for this type can
110 : // differ between architectures.
111 0 : return WriteInt64(int64(value));
112 : }
113 0 : bool WriteULong(unsigned long value) {
114 : // Always written as a 64-bit value since the size for this type can
115 : // differ between architectures.
116 0 : return WriteUInt64(uint64(value));
117 : }
118 74 : bool WriteSize(size_t value) {
119 : // Always written as a 64-bit value since the size for this type can
120 : // differ between architectures.
121 74 : return WriteUInt64(uint64(value));
122 : }
123 : bool WriteInt32(int32 value) {
124 : return WriteBytes(&value, sizeof(value));
125 : }
126 4 : bool WriteUInt32(uint32 value) {
127 4 : return WriteBytes(&value, sizeof(value));
128 : }
129 148 : bool WriteInt64(int64 value) {
130 148 : return WriteBytes(&value, sizeof(value));
131 : }
132 74 : bool WriteUInt64(uint64 value) {
133 74 : return WriteBytes(&value, sizeof(value));
134 : }
135 : bool WriteDouble(double value) {
136 : return WriteBytes(&value, sizeof(value));
137 : }
138 : bool WriteIntPtr(intptr_t value) {
139 : // Always written as a 64-bit value since the size for this type can
140 : // differ between architectures.
141 : return WriteInt64(int64(value));
142 : }
143 : bool WriteUnsignedChar(unsigned char value) {
144 : return WriteBytes(&value, sizeof(value));
145 : }
146 : bool WriteString(const std::string& value);
147 : bool WriteWString(const std::wstring& value);
148 : bool WriteString16(const string16& value);
149 : bool WriteData(const char* data, int length);
150 : bool WriteBytes(const void* data, int data_len);
151 :
152 : // Same as WriteData, but allows the caller to write directly into the
153 : // Pickle. This saves a copy in cases where the data is not already
154 : // available in a buffer. The caller should take care to not write more
155 : // than the length it declares it will. Use ReadData to get the data.
156 : // Returns NULL on failure.
157 : //
158 : // The returned pointer will only be valid until the next write operation
159 : // on this Pickle.
160 : char* BeginWriteData(int length);
161 :
162 : // For Pickles which contain variable length buffers (e.g. those created
163 : // with BeginWriteData), the Pickle can
164 : // be 'trimmed' if the amount of data required is less than originally
165 : // requested. For example, you may have created a buffer with 10K of data,
166 : // but decided to only fill 10 bytes of that data. Use this function
167 : // to trim the buffer so that we don't send 9990 bytes of unused data.
168 : // You cannot increase the size of the variable buffer; only shrink it.
169 : // This function assumes that the length of the variable buffer has
170 : // not been changed.
171 : void TrimWriteData(int length);
172 :
173 0 : void EndRead(void* iter) const {
174 0 : DCHECK(iter == end_of_payload());
175 0 : }
176 :
177 : // Payload follows after allocation of Header (header size is customizable).
178 : struct Header {
179 : uint32 payload_size; // Specifies the size of the payload.
180 : };
181 :
182 : // Returns the header, cast to a user-specified type T. The type T must be a
183 : // subclass of Header and its size must correspond to the header_size passed
184 : // to the Pickle constructor.
185 : template <class T>
186 13 : T* headerT() {
187 13 : DCHECK(sizeof(T) == header_size_);
188 13 : return static_cast<T*>(header_);
189 : }
190 : template <class T>
191 0 : const T* headerT() const {
192 0 : DCHECK(sizeof(T) == header_size_);
193 0 : return static_cast<const T*>(header_);
194 : }
195 :
196 : // Returns true if the given iterator could point to data with the given
197 : // length. If there is no room for the given data before the end of the
198 : // payload, returns false.
199 42187 : bool IteratorHasRoomFor(const void* iter, int len) const {
200 42187 : if ((len < 0) || (iter < header_) || iter > end_of_payload())
201 0 : return false;
202 42187 : const char* end_of_region = reinterpret_cast<const char*>(iter) + len;
203 : // Watch out for overflow in pointer calculation, which wraps.
204 42187 : return (iter <= end_of_region) && (end_of_region <= end_of_payload());
205 : }
206 :
207 : protected:
208 84374 : uint32 payload_size() const { return header_->payload_size; }
209 :
210 42188 : char* payload() {
211 42188 : return reinterpret_cast<char*>(header_) + header_size_;
212 : }
213 84376 : const char* payload() const {
214 84376 : return reinterpret_cast<const char*>(header_) + header_size_;
215 : }
216 :
217 : // Returns the address of the byte immediately following the currently valid
218 : // header + payload.
219 : char* end_of_payload() {
220 : return payload() + payload_size();
221 : }
222 84374 : const char* end_of_payload() const {
223 84374 : return payload() + payload_size();
224 : }
225 :
226 : uint32 capacity() const {
227 : return capacity_;
228 : }
229 :
230 : // Resizes the buffer for use when writing the specified amount of data. The
231 : // location that the data should be written at is returned, or NULL if there
232 : // was an error. Call EndWrite with the returned offset and the given length
233 : // to pad out for the next write.
234 : char* BeginWrite(uint32 length);
235 :
236 : // Completes the write operation by padding the data with NULL bytes until it
237 : // is padded. Should be paired with BeginWrite, but it does not necessarily
238 : // have to be called after the data is written.
239 : void EndWrite(char* dest, int length);
240 :
241 : // Resize the capacity, note that the input value should include the size of
242 : // the header: new_capacity = sizeof(Header) + desired_payload_capacity.
243 : // A realloc() failure will cause a Resize failure... and caller should check
244 : // the return result for true (i.e., successful resizing).
245 : bool Resize(uint32 new_capacity);
246 :
247 : // Aligns 'i' by rounding it up to the next multiple of 'alignment'
248 126587 : static uint32 AlignInt(uint32 i, int alignment) {
249 126587 : return i + (alignment - (i % alignment)) % alignment;
250 : }
251 :
252 : // Moves the iterator by the given number of bytes, making sure it is aligned.
253 : // Pointer (iterator) is NOT aligned, but the change in the pointer
254 : // is guaranteed to be a multiple of sizeof(uint32).
255 42187 : static void UpdateIter(void** iter, int bytes) {
256 42187 : *iter = static_cast<char*>(*iter) + AlignInt(bytes, sizeof(uint32));
257 42187 : }
258 :
259 : // Find the end of the pickled data that starts at range_start. Returns NULL
260 : // if the entire Pickle is not found in the given data range.
261 : static const char* FindNext(uint32 header_size,
262 : const char* range_start,
263 : const char* range_end);
264 :
265 : // The allocation granularity of the payload.
266 : static const int kPayloadUnit;
267 :
268 : private:
269 : Header* header_;
270 : uint32 header_size_;
271 : uint32 capacity_;
272 : uint32 variable_buffer_offset_;
273 : FRIEND_TEST(PickleTest, Resize);
274 : FRIEND_TEST(PickleTest, FindNext);
275 : FRIEND_TEST(PickleTest, IteratorHasRoom);
276 : };
277 :
278 : #endif // BASE_PICKLE_H__
|