blob: 7c4a007b5a7642e44547bf6935f5e2c17841a0f3 [file] [log] [blame]
initial.commitd7cae122008-07-26 21:49:381// Copyright 2008, Google Inc.
2// All rights reserved.
3//
4// Redistribution and use in source and binary forms, with or without
5// modification, are permitted provided that the following conditions are
6// met:
7//
8// * Redistributions of source code must retain the above copyright
9// notice, this list of conditions and the following disclaimer.
10// * Redistributions in binary form must reproduce the above
11// copyright notice, this list of conditions and the following disclaimer
12// in the documentation and/or other materials provided with the
13// distribution.
14// * Neither the name of Google Inc. nor the names of its
15// contributors may be used to endorse or promote products derived from
16// this software without specific prior written permission.
17//
18// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29
30#ifndef BASE_PICKLE_H__
31#define BASE_PICKLE_H__
32
33#include <string>
34
35#include "base/basictypes.h"
36#include "base/logging.h"
37#include "testing/gtest/include/gtest/gtest_prod.h"
38
39// This class provides facilities for basic binary value packing and unpacking.
40//
41// The Pickle class supports appending primitive values (ints, strings, etc.)
42// to a pickle instance. The Pickle instance grows its internal memory buffer
43// dynamically to hold the sequence of primitive values. The internal memory
44// buffer is exposed as the "data" of the Pickle. This "data" can be passed
45// to a Pickle object to initialize it for reading.
46//
47// When reading from a Pickle object, it is important for the consumer to know
48// what value types to read and in what order to read them as the Pickle does
49// not keep track of the type of data written to it.
50//
51// The Pickle's data has a header which contains the size of the Pickle's
52// payload. It can optionally support additional space in the header. That
53// space is controlled by the header_size parameter passed to the Pickle
54// constructor.
55//
56class Pickle {
57 public:
58 ~Pickle();
59
60 // Initialize a Pickle object using the default header size.
61 Pickle();
62
63 // Initialize a Pickle object with the specified header size in bytes, which
64 // must be greater-than-or-equal-to sizeof(Pickle::Header). The header size
65 // will be rounded up to ensure that the header size is 32bit-aligned.
66 explicit Pickle(int header_size);
67
68 // Initializes a Pickle from a const block of data. The data is not copied;
69 // instead the data is merely referenced by this Pickle. Only const methods
70 // should be used on the Pickle when initialized this way. The header
71 // padding size is deduced from the data length.
72 Pickle(const char* data, int data_len);
73
74 // Initializes a Pickle as a deep copy of another Pickle.
75 Pickle(const Pickle& other);
76
77 // Performs a deep copy.
78 Pickle& operator=(const Pickle& other);
79
80 // Returns the size of the Pickle's data.
81 int size() const { return static_cast<int>(header_size_ +
82 header_->payload_size); }
83
84 // Returns the data for this Pickle.
85 const void* data() const { return header_; }
86
87 // Methods for reading the payload of the Pickle. To read from the start of
88 // the Pickle, initialize *iter to NULL. If successful, these methods return
89 // true. Otherwise, false is returned to indicate that the result could not
90 // be extracted.
91 bool ReadBool(void** iter, bool* result) const;
92 bool ReadInt(void** iter, int* result) const;
93 bool ReadSize(void** iter, size_t* result) const;
94 bool ReadInt64(void** iter, int64* result) const;
95 bool ReadIntPtr(void** iter, intptr_t* result) const;
96 bool ReadString(void** iter, std::string* result) const;
97 bool ReadWString(void** iter, std::wstring* result) const;
98 bool ReadData(void** iter, const char** data, int* length) const;
99 bool ReadBytes(void** iter, const char** data, int length) const;
100
101 // Safer version of ReadInt() checks for the result not being negative.
102 // Use it for reading the object sizes.
103 bool Pickle::ReadLength(void** iter, int* result) const;
104
105 // Methods for adding to the payload of the Pickle. These values are
106 // appended to the end of the Pickle's payload. When reading values from a
107 // Pickle, it is important to read them in the order in which they were added
108 // to the Pickle.
109 bool WriteBool(bool value) {
110 return WriteInt(value ? 1 : 0);
111 }
112 bool WriteInt(int value) {
113 return WriteBytes(&value, sizeof(value));
114 }
115 bool WriteSize(size_t value) {
116 return WriteBytes(&value, sizeof(value));
117 }
118 bool WriteInt64(int64 value) {
119 return WriteBytes(&value, sizeof(value));
120 }
121 bool WriteIntPtr(intptr_t value) {
122 return WriteBytes(&value, sizeof(value));
123 }
124 bool WriteString(const std::string& value);
125 bool WriteWString(const std::wstring& value);
126 bool WriteData(const char* data, int length);
127 bool WriteBytes(const void* data, int data_len);
128
129 // Same as WriteData, but allows the caller to write directly into the
130 // Pickle. This saves a copy in cases where the data is not already
131 // available in a buffer. The caller should take care to not write more
132 // than the length it declares it will. Use ReadData to get the data.
133 // Returns NULL on failure.
134 //
135 // The returned pointer will only be valid until the next write operation
136 // on this Pickle.
137 char* BeginWriteData(int length);
138
139 // For Pickles which contain variable length buffers (e.g. those created
140 // with BeginWriteData), the Pickle can
141 // be 'trimmed' if the amount of data required is less than originally
142 // requested. For example, you may have created a buffer with 10K of data,
143 // but decided to only fill 10 bytes of that data. Use this function
144 // to trim the buffer so that we don't send 9990 bytes of unused data.
145 // You cannot increase the size of the variable buffer; only shrink it.
146 // This function assumes that the length of the variable buffer has
147 // not been changed.
148 void TrimWriteData(int length);
149
[email protected]c9046af2008-08-06 20:35:17150 // Payload follows after allocation of Header (header size is customizable).
initial.commitd7cae122008-07-26 21:49:38151 struct Header {
[email protected]c9046af2008-08-06 20:35:17152 uint32 payload_size; // Specifies the size of the payload.
initial.commitd7cae122008-07-26 21:49:38153 };
154
155 // Returns the header, cast to a user-specified type T. The type T must be a
156 // subclass of Header and its size must correspond to the header_size passed
157 // to the Pickle constructor.
158 template <class T>
159 T* headerT() {
160 DCHECK(sizeof(T) == header_size_);
161 return static_cast<T*>(header_);
162 }
163 template <class T>
164 const T* headerT() const {
165 DCHECK(sizeof(T) == header_size_);
166 return static_cast<const T*>(header_);
167 }
168
169 // Returns true if the given iterator could point to data with the given
170 // length. If there is no room for the given data before the end of the
171 // payload, returns false.
172 bool IteratorHasRoomFor(const void* iter, int len) const {
173 if ((len < 0) || (iter < header_) || iter > end_of_payload())
174 return false;
175 const char* end_of_region = reinterpret_cast<const char*>(iter) + len;
176 // Watch out for overflow in pointer calculation, which wraps.
177 return (iter <= end_of_region) && (end_of_region <= end_of_payload());
178 }
179
180 protected:
181 size_t payload_size() const { return header_->payload_size; }
182
183 char* payload() {
184 return reinterpret_cast<char*>(header_) + header_size_;
185 }
186 const char* payload() const {
187 return reinterpret_cast<const char*>(header_) + header_size_;
188 }
189
190 // Returns the address of the byte immediately following the currently valid
191 // header + payload.
192 char* end_of_payload() {
193 return payload() + payload_size();
194 }
195 const char* end_of_payload() const {
196 return payload() + payload_size();
197 }
198
199 size_t capacity() const {
200 return capacity_;
201 }
202
203 // Resizes the buffer for use when writing the specified amount of data. The
204 // location that the data should be written at is returned, or NULL if there
205 // was an error. Call EndWrite with the returned offset and the given length
206 // to pad out for the next write.
207 char* BeginWrite(size_t length);
208
209 // Completes the write operation by padding the data with NULL bytes until it
210 // is padded. Should be paired with BeginWrite, but it does not necessarily
211 // have to be called after the data is written.
212 void EndWrite(char* dest, int length);
213
214 // Resize the capacity, note that the input value should include the size of
215 // the header: new_capacity = sizeof(Header) + desired_payload_capacity.
216 // A realloc() failure will cause a Resize failure... and caller should check
217 // the return result for true (i.e., successful resizing).
218 bool Resize(size_t new_capacity);
219
220 // Aligns 'i' by rounding it up to the next multiple of 'alignment'
[email protected]c9046af2008-08-06 20:35:17221 static size_t AlignInt(size_t i, int alignment) {
initial.commitd7cae122008-07-26 21:49:38222 return i + (alignment - (i % alignment)) % alignment;
223 }
224
225 // Moves the iterator by the given number of bytes, making sure it is aligned.
226 // Pointer (iterator) is NOT aligned, but the change in the pointer
227 // is guaranteed to be a multiple of sizeof(uint32).
[email protected]c9046af2008-08-06 20:35:17228 static void UpdateIter(void** iter, int bytes) {
initial.commitd7cae122008-07-26 21:49:38229 *iter = static_cast<char*>(*iter) + AlignInt(bytes, sizeof(uint32));
230 }
231
232 // Find the end of the pickled data that starts at range_start. Returns NULL
233 // if the entire Pickle is not found in the given data range.
234 static const char* FindNext(size_t header_size,
235 const char* range_start,
236 const char* range_end);
237
238 // The allocation granularity of the payload.
239 static const int kPayloadUnit;
240
241 private:
242 // A buffer of variable length; used internally
243 struct VariableLengthBuffer {
244 int length;
245 char data; // This is variable length.
246 };
247
248 Header* header_;
249 size_t header_size_; // Supports extra data between header and payload.
250 // Allocation size of payload (or -1 if allocation is const).
251 size_t capacity_;
252 size_t variable_buffer_offset_; // IF non-zero, then offset to a buffer.
253
254 FRIEND_TEST(PickleTest, Resize);
255 FRIEND_TEST(PickleTest, FindNext);
256 FRIEND_TEST(PickleTest, IteratorHasRoom);
257};
258
259#endif // BASE_PICKLE_H__