Forgot a .h file.
[chromium-blink-merge.git] / base / pickle.cc
blobf6ed4cc4c7f3550a190c4918c5fc7030916c3033
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.
5 #include "base/pickle.h"
7 #include <stdlib.h>
9 #include <limits>
10 #include <string>
12 //------------------------------------------------------------------------------
14 // static
15 const int Pickle::kPayloadUnit = 64;
17 // We mark a read only pickle with a special capacity_.
18 static const size_t kCapacityReadOnly = std::numeric_limits<size_t>::max();
20 // Payload is uint32 aligned.
22 Pickle::Pickle()
23 : header_(NULL),
24 header_size_(sizeof(Header)),
25 capacity_(0),
26 variable_buffer_offset_(0) {
27 Resize(kPayloadUnit);
28 header_->payload_size = 0;
31 Pickle::Pickle(int header_size)
32 : header_(NULL),
33 header_size_(AlignInt(header_size, sizeof(uint32))),
34 capacity_(0),
35 variable_buffer_offset_(0) {
36 DCHECK(static_cast<size_t>(header_size) >= sizeof(Header));
37 DCHECK(header_size <= kPayloadUnit);
38 Resize(kPayloadUnit);
39 header_->payload_size = 0;
42 Pickle::Pickle(const char* data, int data_len)
43 : header_(reinterpret_cast<Header*>(const_cast<char*>(data))),
44 header_size_(data_len - header_->payload_size),
45 capacity_(kCapacityReadOnly),
46 variable_buffer_offset_(0) {
47 DCHECK(header_size_ >= sizeof(Header));
48 DCHECK(header_size_ == AlignInt(header_size_, sizeof(uint32)));
51 Pickle::Pickle(const Pickle& other)
52 : header_(NULL),
53 header_size_(other.header_size_),
54 capacity_(0),
55 variable_buffer_offset_(other.variable_buffer_offset_) {
56 size_t payload_size = header_size_ + other.header_->payload_size;
57 bool resized = Resize(payload_size);
58 CHECK(resized); // Realloc failed.
59 memcpy(header_, other.header_, payload_size);
62 Pickle::~Pickle() {
63 if (capacity_ != kCapacityReadOnly)
64 free(header_);
67 Pickle& Pickle::operator=(const Pickle& other) {
68 if (header_size_ != other.header_size_ && capacity_ != kCapacityReadOnly) {
69 free(header_);
70 header_ = NULL;
71 header_size_ = other.header_size_;
73 bool resized = Resize(other.header_size_ + other.header_->payload_size);
74 CHECK(resized); // Realloc failed.
75 memcpy(header_, other.header_, header_size_ + other.header_->payload_size);
76 variable_buffer_offset_ = other.variable_buffer_offset_;
77 return *this;
80 bool Pickle::ReadBool(void** iter, bool* result) const {
81 DCHECK(iter);
83 int tmp;
84 if (!ReadInt(iter, &tmp))
85 return false;
86 DCHECK(0 == tmp || 1 == tmp);
87 *result = tmp ? true : false;
88 return true;
91 bool Pickle::ReadInt(void** iter, int* result) const {
92 DCHECK(iter);
93 if (!*iter)
94 *iter = const_cast<char*>(payload());
96 if (!IteratorHasRoomFor(*iter, sizeof(*result)))
97 return false;
99 // TODO(jar) bug 1129285: Pickle should be cleaned up, and not dependent on
100 // alignment.
101 // Next line is otherwise the same as: memcpy(result, *iter, sizeof(*result));
102 *result = *reinterpret_cast<int*>(*iter);
104 UpdateIter(iter, sizeof(*result));
105 return true;
108 bool Pickle::ReadLong(void** iter, long* result) const {
109 DCHECK(iter);
110 if (!*iter)
111 *iter = const_cast<char*>(payload());
113 if (!IteratorHasRoomFor(*iter, sizeof(*result)))
114 return false;
116 // TODO(jar) bug 1129285: Pickle should be cleaned up, and not dependent on
117 // alignment.
118 memcpy(result, *iter, sizeof(*result));
120 UpdateIter(iter, sizeof(*result));
121 return true;
124 bool Pickle::ReadLength(void** iter, int* result) const {
125 if (!ReadInt(iter, result))
126 return false;
127 return ((*result) >= 0);
130 bool Pickle::ReadSize(void** iter, size_t* result) const {
131 DCHECK(iter);
132 if (!*iter)
133 *iter = const_cast<char*>(payload());
135 if (!IteratorHasRoomFor(*iter, sizeof(*result)))
136 return false;
138 // TODO(jar) bug 1129285: Pickle should be cleaned up, and not dependent on
139 // alignment.
140 // Next line is otherwise the same as: memcpy(result, *iter, sizeof(*result));
141 *result = *reinterpret_cast<size_t*>(*iter);
143 UpdateIter(iter, sizeof(*result));
144 return true;
147 bool Pickle::ReadInt64(void** iter, int64* result) const {
148 DCHECK(iter);
149 if (!*iter)
150 *iter = const_cast<char*>(payload());
152 if (!IteratorHasRoomFor(*iter, sizeof(*result)))
153 return false;
155 memcpy(result, *iter, sizeof(*result));
157 UpdateIter(iter, sizeof(*result));
158 return true;
161 bool Pickle::ReadIntPtr(void** iter, intptr_t* result) const {
162 DCHECK(iter);
163 if (!*iter)
164 *iter = const_cast<char*>(payload());
166 if (!IteratorHasRoomFor(*iter, sizeof(*result)))
167 return false;
169 memcpy(result, *iter, sizeof(*result));
171 UpdateIter(iter, sizeof(*result));
172 return true;
175 bool Pickle::ReadString(void** iter, std::string* result) const {
176 DCHECK(iter);
178 int len;
179 if (!ReadLength(iter, &len))
180 return false;
181 if (!IteratorHasRoomFor(*iter, len))
182 return false;
184 char* chars = reinterpret_cast<char*>(*iter);
185 result->assign(chars, len);
187 UpdateIter(iter, len);
188 return true;
191 bool Pickle::ReadWString(void** iter, std::wstring* result) const {
192 DCHECK(iter);
194 int len;
195 if (!ReadLength(iter, &len))
196 return false;
197 if (!IteratorHasRoomFor(*iter, len * sizeof(wchar_t)))
198 return false;
200 wchar_t* chars = reinterpret_cast<wchar_t*>(*iter);
201 result->assign(chars, len);
203 UpdateIter(iter, len * sizeof(wchar_t));
204 return true;
207 bool Pickle::ReadBytes(void** iter, const char** data, int length) const {
208 DCHECK(iter);
209 DCHECK(data);
211 if (!IteratorHasRoomFor(*iter, length))
212 return false;
214 *data = reinterpret_cast<const char*>(*iter);
216 UpdateIter(iter, length);
217 return true;
220 bool Pickle::ReadData(void** iter, const char** data, int* length) const {
221 DCHECK(iter);
222 DCHECK(data);
223 DCHECK(length);
225 if (!ReadLength(iter, length))
226 return false;
228 return ReadBytes(iter, data, *length);
231 char* Pickle::BeginWrite(size_t length) {
232 // write at a uint32-aligned offset from the beginning of the header
233 size_t offset = AlignInt(header_->payload_size, sizeof(uint32));
235 size_t new_size = offset + length;
236 if (header_size_ + new_size > capacity_ && !Resize(header_size_ + new_size))
237 return NULL;
239 #ifdef ARCH_CPU_64_BITS
240 DCHECK_LE(length, std::numeric_limits<uint32>::max());
241 #endif
243 header_->payload_size = static_cast<uint32>(new_size);
244 return payload() + offset;
247 void Pickle::EndWrite(char* dest, int length) {
248 // Zero-pad to keep tools like purify from complaining about uninitialized
249 // memory.
250 if (length % sizeof(uint32))
251 memset(dest + length, 0, sizeof(uint32) - (length % sizeof(uint32)));
254 bool Pickle::WriteBytes(const void* data, int data_len) {
255 DCHECK(capacity_ != kCapacityReadOnly) << "oops: pickle is readonly";
257 char* dest = BeginWrite(data_len);
258 if (!dest)
259 return false;
261 memcpy(dest, data, data_len);
263 EndWrite(dest, data_len);
264 return true;
267 bool Pickle::WriteString(const std::string& value) {
268 if (!WriteInt(static_cast<int>(value.size())))
269 return false;
271 return WriteBytes(value.data(), static_cast<int>(value.size()));
274 bool Pickle::WriteWString(const std::wstring& value) {
275 if (!WriteInt(static_cast<int>(value.size())))
276 return false;
278 return WriteBytes(value.data(),
279 static_cast<int>(value.size() * sizeof(value.data()[0])));
282 bool Pickle::WriteData(const char* data, int length) {
283 return WriteInt(length) && WriteBytes(data, length);
286 char* Pickle::BeginWriteData(int length) {
287 DCHECK_EQ(variable_buffer_offset_, 0U) <<
288 "There can only be one variable buffer in a Pickle";
290 if (!WriteInt(length))
291 return false;
293 char *data_ptr = BeginWrite(length);
294 if (!data_ptr)
295 return NULL;
297 variable_buffer_offset_ =
298 data_ptr - reinterpret_cast<char*>(header_) - sizeof(int);
300 // EndWrite doesn't necessarily have to be called after the write operation,
301 // so we call it here to pad out what the caller will eventually write.
302 EndWrite(data_ptr, length);
303 return data_ptr;
306 void Pickle::TrimWriteData(int new_length) {
307 DCHECK(variable_buffer_offset_ != 0);
309 // Fetch the the variable buffer size
310 int* cur_length = reinterpret_cast<int*>(
311 reinterpret_cast<char*>(header_) + variable_buffer_offset_);
313 if (new_length < 0 || new_length > *cur_length) {
314 NOTREACHED() << "Invalid length in TrimWriteData.";
315 return;
318 // Update the payload size and variable buffer size
319 header_->payload_size -= (*cur_length - new_length);
320 *cur_length = new_length;
323 bool Pickle::Resize(size_t new_capacity) {
324 new_capacity = AlignInt(new_capacity, kPayloadUnit);
326 void* p = realloc(header_, new_capacity);
327 if (!p)
328 return false;
330 header_ = reinterpret_cast<Header*>(p);
331 capacity_ = new_capacity;
332 return true;
335 // static
336 const char* Pickle::FindNext(size_t header_size,
337 const char* start,
338 const char* end) {
339 DCHECK(header_size == AlignInt(header_size, sizeof(uint32)));
340 DCHECK(header_size <= static_cast<size_t>(kPayloadUnit));
342 const Header* hdr = reinterpret_cast<const Header*>(start);
343 const char* payload_base = start + header_size;
344 const char* payload_end = payload_base + hdr->payload_size;
345 if (payload_end < payload_base)
346 return NULL;
348 return (payload_end > end) ? NULL : payload_end;