blob: f6ed4cc4c7f3550a190c4918c5fc7030916c3033 [file] [log] [blame]
license.botf003cfe2008-08-24 09:55:55 +09001// 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.
initial.commit3f4a7322008-07-27 06:49:38 +09004
initial.commit3f4a7322008-07-27 06:49:38 +09005#include "base/pickle.h"
6
maruel@google.com825f8792008-08-07 05:35:17 +09007#include <stdlib.h>
8
9#include <limits>
10#include <string>
11
initial.commit3f4a7322008-07-27 06:49:38 +090012//------------------------------------------------------------------------------
13
14// static
15const int Pickle::kPayloadUnit = 64;
16
deanm@google.com19650de2008-08-13 23:57:51 +090017// We mark a read only pickle with a special capacity_.
18static const size_t kCapacityReadOnly = std::numeric_limits<size_t>::max();
19
initial.commit3f4a7322008-07-27 06:49:38 +090020// Payload is uint32 aligned.
21
22Pickle::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;
29}
30
31Pickle::Pickle(int header_size)
32 : header_(NULL),
33 header_size_(AlignInt(header_size, sizeof(uint32))),
34 capacity_(0),
35 variable_buffer_offset_(0) {
darin@google.comcf7eff42008-08-15 10:05:11 +090036 DCHECK(static_cast<size_t>(header_size) >= sizeof(Header));
initial.commit3f4a7322008-07-27 06:49:38 +090037 DCHECK(header_size <= kPayloadUnit);
38 Resize(kPayloadUnit);
39 header_->payload_size = 0;
40}
41
42Pickle::Pickle(const char* data, int data_len)
43 : header_(reinterpret_cast<Header*>(const_cast<char*>(data))),
44 header_size_(data_len - header_->payload_size),
deanm@google.com19650de2008-08-13 23:57:51 +090045 capacity_(kCapacityReadOnly),
initial.commit3f4a7322008-07-27 06:49:38 +090046 variable_buffer_offset_(0) {
47 DCHECK(header_size_ >= sizeof(Header));
48 DCHECK(header_size_ == AlignInt(header_size_, sizeof(uint32)));
49}
50
51Pickle::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);
60}
61
62Pickle::~Pickle() {
deanm@google.com19650de2008-08-13 23:57:51 +090063 if (capacity_ != kCapacityReadOnly)
initial.commit3f4a7322008-07-27 06:49:38 +090064 free(header_);
65}
66
67Pickle& Pickle::operator=(const Pickle& other) {
deanm@google.com19650de2008-08-13 23:57:51 +090068 if (header_size_ != other.header_size_ && capacity_ != kCapacityReadOnly) {
initial.commit3f4a7322008-07-27 06:49:38 +090069 free(header_);
70 header_ = NULL;
71 header_size_ = other.header_size_;
72 }
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;
78}
79
80bool Pickle::ReadBool(void** iter, bool* result) const {
81 DCHECK(iter);
82
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;
89}
90
91bool Pickle::ReadInt(void** iter, int* result) const {
92 DCHECK(iter);
93 if (!*iter)
94 *iter = const_cast<char*>(payload());
95
96 if (!IteratorHasRoomFor(*iter, sizeof(*result)))
97 return false;
98
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);
103
104 UpdateIter(iter, sizeof(*result));
105 return true;
106}
107
klink@google.comd7f60032008-08-23 08:24:54 +0900108bool Pickle::ReadLong(void** iter, long* result) const {
109 DCHECK(iter);
110 if (!*iter)
111 *iter = const_cast<char*>(payload());
112
113 if (!IteratorHasRoomFor(*iter, sizeof(*result)))
114 return false;
115
116 // TODO(jar) bug 1129285: Pickle should be cleaned up, and not dependent on
117 // alignment.
118 memcpy(result, *iter, sizeof(*result));
119
120 UpdateIter(iter, sizeof(*result));
121 return true;
122}
123
initial.commit3f4a7322008-07-27 06:49:38 +0900124bool Pickle::ReadLength(void** iter, int* result) const {
125 if (!ReadInt(iter, result))
126 return false;
127 return ((*result) >= 0);
128}
129
130bool Pickle::ReadSize(void** iter, size_t* result) const {
131 DCHECK(iter);
132 if (!*iter)
133 *iter = const_cast<char*>(payload());
134
135 if (!IteratorHasRoomFor(*iter, sizeof(*result)))
136 return false;
137
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);
142
143 UpdateIter(iter, sizeof(*result));
144 return true;
145}
146
147bool Pickle::ReadInt64(void** iter, int64* result) const {
148 DCHECK(iter);
149 if (!*iter)
150 *iter = const_cast<char*>(payload());
151
152 if (!IteratorHasRoomFor(*iter, sizeof(*result)))
153 return false;
154
155 memcpy(result, *iter, sizeof(*result));
156
157 UpdateIter(iter, sizeof(*result));
158 return true;
159}
160
161bool Pickle::ReadIntPtr(void** iter, intptr_t* result) const {
162 DCHECK(iter);
163 if (!*iter)
164 *iter = const_cast<char*>(payload());
165
166 if (!IteratorHasRoomFor(*iter, sizeof(*result)))
167 return false;
168
169 memcpy(result, *iter, sizeof(*result));
170
171 UpdateIter(iter, sizeof(*result));
172 return true;
173}
174
175bool Pickle::ReadString(void** iter, std::string* result) const {
176 DCHECK(iter);
177
178 int len;
179 if (!ReadLength(iter, &len))
180 return false;
181 if (!IteratorHasRoomFor(*iter, len))
182 return false;
183
184 char* chars = reinterpret_cast<char*>(*iter);
185 result->assign(chars, len);
186
187 UpdateIter(iter, len);
188 return true;
189}
190
191bool Pickle::ReadWString(void** iter, std::wstring* result) const {
192 DCHECK(iter);
193
194 int len;
195 if (!ReadLength(iter, &len))
196 return false;
197 if (!IteratorHasRoomFor(*iter, len * sizeof(wchar_t)))
198 return false;
199
200 wchar_t* chars = reinterpret_cast<wchar_t*>(*iter);
201 result->assign(chars, len);
202
203 UpdateIter(iter, len * sizeof(wchar_t));
204 return true;
205}
206
207bool Pickle::ReadBytes(void** iter, const char** data, int length) const {
208 DCHECK(iter);
209 DCHECK(data);
210
211 if (!IteratorHasRoomFor(*iter, length))
212 return false;
213
214 *data = reinterpret_cast<const char*>(*iter);
215
216 UpdateIter(iter, length);
217 return true;
218}
219
220bool Pickle::ReadData(void** iter, const char** data, int* length) const {
221 DCHECK(iter);
222 DCHECK(data);
223 DCHECK(length);
224
225 if (!ReadLength(iter, length))
226 return false;
227
228 return ReadBytes(iter, data, *length);
229}
230
231char* 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));
234
235 size_t new_size = offset + length;
236 if (header_size_ + new_size > capacity_ && !Resize(header_size_ + new_size))
237 return NULL;
238
maruel@google.com825f8792008-08-07 05:35:17 +0900239#ifdef ARCH_CPU_64_BITS
240 DCHECK_LE(length, std::numeric_limits<uint32>::max());
241#endif
242
243 header_->payload_size = static_cast<uint32>(new_size);
initial.commit3f4a7322008-07-27 06:49:38 +0900244 return payload() + offset;
245}
246
247void 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)));
252}
253
254bool Pickle::WriteBytes(const void* data, int data_len) {
deanm@google.com19650de2008-08-13 23:57:51 +0900255 DCHECK(capacity_ != kCapacityReadOnly) << "oops: pickle is readonly";
initial.commit3f4a7322008-07-27 06:49:38 +0900256
257 char* dest = BeginWrite(data_len);
258 if (!dest)
259 return false;
260
261 memcpy(dest, data, data_len);
262
263 EndWrite(dest, data_len);
264 return true;
265}
266
267bool Pickle::WriteString(const std::string& value) {
268 if (!WriteInt(static_cast<int>(value.size())))
269 return false;
270
271 return WriteBytes(value.data(), static_cast<int>(value.size()));
272}
273
274bool Pickle::WriteWString(const std::wstring& value) {
275 if (!WriteInt(static_cast<int>(value.size())))
276 return false;
277
278 return WriteBytes(value.data(),
279 static_cast<int>(value.size() * sizeof(value.data()[0])));
280}
281
282bool Pickle::WriteData(const char* data, int length) {
283 return WriteInt(length) && WriteBytes(data, length);
284}
285
286char* Pickle::BeginWriteData(int length) {
darin@google.comcf7eff42008-08-15 10:05:11 +0900287 DCHECK_EQ(variable_buffer_offset_, 0U) <<
initial.commit3f4a7322008-07-27 06:49:38 +0900288 "There can only be one variable buffer in a Pickle";
289
290 if (!WriteInt(length))
291 return false;
292
293 char *data_ptr = BeginWrite(length);
294 if (!data_ptr)
295 return NULL;
296
297 variable_buffer_offset_ =
298 data_ptr - reinterpret_cast<char*>(header_) - sizeof(int);
299
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;
304}
305
maruel@google.coma01bb102008-08-08 02:04:23 +0900306void Pickle::TrimWriteData(int new_length) {
initial.commit3f4a7322008-07-27 06:49:38 +0900307 DCHECK(variable_buffer_offset_ != 0);
308
maruel@google.coma01bb102008-08-08 02:04:23 +0900309 // Fetch the the variable buffer size
310 int* cur_length = reinterpret_cast<int*>(
initial.commit3f4a7322008-07-27 06:49:38 +0900311 reinterpret_cast<char*>(header_) + variable_buffer_offset_);
312
maruel@google.coma01bb102008-08-08 02:04:23 +0900313 if (new_length < 0 || new_length > *cur_length) {
314 NOTREACHED() << "Invalid length in TrimWriteData.";
315 return;
deanm@google.com8ba9dfb2008-08-08 00:18:20 +0900316 }
maruel@google.coma01bb102008-08-08 02:04:23 +0900317
318 // Update the payload size and variable buffer size
319 header_->payload_size -= (*cur_length - new_length);
320 *cur_length = new_length;
initial.commit3f4a7322008-07-27 06:49:38 +0900321}
322
323bool Pickle::Resize(size_t new_capacity) {
324 new_capacity = AlignInt(new_capacity, kPayloadUnit);
325
326 void* p = realloc(header_, new_capacity);
327 if (!p)
328 return false;
329
330 header_ = reinterpret_cast<Header*>(p);
331 capacity_ = new_capacity;
332 return true;
333}
334
335// static
336const char* Pickle::FindNext(size_t header_size,
337 const char* start,
338 const char* end) {
339 DCHECK(header_size == AlignInt(header_size, sizeof(uint32)));
darin@google.comcf7eff42008-08-15 10:05:11 +0900340 DCHECK(header_size <= static_cast<size_t>(kPayloadUnit));
initial.commit3f4a7322008-07-27 06:49:38 +0900341
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;
347
348 return (payload_end > end) ? NULL : payload_end;
349}
license.botf003cfe2008-08-24 09:55:55 +0900350