[go: nahoru, domu]

blob: e491832ec618cab7ce0a3be757c78593f903c00e [file] [log] [blame]
license.botbf09a502008-08-24 00:55:551// 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.commitd7cae122008-07-26 21:49:384
initial.commitd7cae122008-07-26 21:49:385#include "base/pickle.h"
maruel@google.comc9046af2008-08-06 20:35:176
7#include <stdlib.h>
8
9#include <limits>
10#include <string>
initial.commitd7cae122008-07-26 21:49:3811
12//------------------------------------------------------------------------------
13
14// static
15const int Pickle::kPayloadUnit = 64;
16
deanm@google.com836061b2008-08-13 14:57:5117// We mark a read only pickle with a special capacity_.
18static const size_t kCapacityReadOnly = std::numeric_limits<size_t>::max();
19
initial.commitd7cae122008-07-26 21:49:3820// 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.com44a1cbfa2008-08-15 01:05:1136 DCHECK(static_cast<size_t>(header_size) >= sizeof(Header));
initial.commitd7cae122008-07-26 21:49:3837 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.com836061b2008-08-13 14:57:5145 capacity_(kCapacityReadOnly),
initial.commitd7cae122008-07-26 21:49:3846 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.com836061b2008-08-13 14:57:5163 if (capacity_ != kCapacityReadOnly)
initial.commitd7cae122008-07-26 21:49:3864 free(header_);
65}
66
67Pickle& Pickle::operator=(const Pickle& other) {
deanm@google.com836061b2008-08-13 14:57:5168 if (header_size_ != other.header_size_ && capacity_ != kCapacityReadOnly) {
initial.commitd7cae122008-07-26 21:49:3869 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
maruel@chromium.org390c4bf2009-06-01 20:26:4299 // TODO(jar): http://crbug.com/13108 Pickle should be cleaned up, and not
100 // dependent on alignment.
initial.commitd7cae122008-07-26 21:49:38101 // 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.com43beaef42008-08-22 23:24:54108bool 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
maruel@chromium.org390c4bf2009-06-01 20:26:42116 // TODO(jar): http://crbug.com/13108 Pickle should be cleaned up, and not
117 // dependent on alignment.
klink@google.com43beaef42008-08-22 23:24:54118 memcpy(result, *iter, sizeof(*result));
119
120 UpdateIter(iter, sizeof(*result));
121 return true;
122}
123
initial.commitd7cae122008-07-26 21:49:38124bool 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
maruel@chromium.org390c4bf2009-06-01 20:26:42138 // TODO(jar): http://crbug.com/13108 Pickle should be cleaned up, and not
139 // dependent on alignment.
initial.commitd7cae122008-07-26 21:49:38140 // 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
jeremy@chromium.org48ce616a2008-12-29 18:55:18147bool Pickle::ReadUInt32(void** iter, uint32* 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
initial.commitd7cae122008-07-26 21:49:38161bool Pickle::ReadInt64(void** iter, int64* 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::ReadIntPtr(void** iter, intptr_t* result) const {
176 DCHECK(iter);
177 if (!*iter)
178 *iter = const_cast<char*>(payload());
179
180 if (!IteratorHasRoomFor(*iter, sizeof(*result)))
181 return false;
182
183 memcpy(result, *iter, sizeof(*result));
184
185 UpdateIter(iter, sizeof(*result));
186 return true;
187}
188
189bool Pickle::ReadString(void** iter, std::string* result) const {
190 DCHECK(iter);
191
192 int len;
193 if (!ReadLength(iter, &len))
194 return false;
195 if (!IteratorHasRoomFor(*iter, len))
196 return false;
197
198 char* chars = reinterpret_cast<char*>(*iter);
199 result->assign(chars, len);
200
201 UpdateIter(iter, len);
202 return true;
203}
204
205bool Pickle::ReadWString(void** iter, std::wstring* result) const {
206 DCHECK(iter);
207
208 int len;
209 if (!ReadLength(iter, &len))
210 return false;
cevans@chromium.org87665562009-06-25 16:54:02211 // Avoid integer overflow.
212 if (len > INT_MAX / static_cast<int>(sizeof(wchar_t)))
213 return false;
initial.commitd7cae122008-07-26 21:49:38214 if (!IteratorHasRoomFor(*iter, len * sizeof(wchar_t)))
215 return false;
216
217 wchar_t* chars = reinterpret_cast<wchar_t*>(*iter);
218 result->assign(chars, len);
219
220 UpdateIter(iter, len * sizeof(wchar_t));
221 return true;
222}
223
estade@chromium.org3a2a5d22009-03-04 03:36:36224bool Pickle::ReadString16(void** iter, string16* result) const {
225 DCHECK(iter);
226
227 int len;
228 if (!ReadLength(iter, &len))
229 return false;
cevans@chromium.org87665562009-06-25 16:54:02230 if (!IteratorHasRoomFor(*iter, len * sizeof(char16)))
estade@chromium.org3a2a5d22009-03-04 03:36:36231 return false;
232
233 char16* chars = reinterpret_cast<char16*>(*iter);
234 result->assign(chars, len);
235
236 UpdateIter(iter, len * sizeof(char16));
237 return true;
238}
239
initial.commitd7cae122008-07-26 21:49:38240bool Pickle::ReadBytes(void** iter, const char** data, int length) const {
241 DCHECK(iter);
242 DCHECK(data);
243
244 if (!IteratorHasRoomFor(*iter, length))
245 return false;
246
247 *data = reinterpret_cast<const char*>(*iter);
248
249 UpdateIter(iter, length);
250 return true;
251}
252
253bool Pickle::ReadData(void** iter, const char** data, int* length) const {
254 DCHECK(iter);
255 DCHECK(data);
256 DCHECK(length);
257
258 if (!ReadLength(iter, length))
259 return false;
260
261 return ReadBytes(iter, data, *length);
262}
263
264char* Pickle::BeginWrite(size_t length) {
265 // write at a uint32-aligned offset from the beginning of the header
266 size_t offset = AlignInt(header_->payload_size, sizeof(uint32));
267
268 size_t new_size = offset + length;
mpcomplete@google.com2de46262009-03-16 20:21:57269 size_t needed_size = header_size_ + new_size;
270 if (needed_size > capacity_ && !Resize(std::max(capacity_ * 2, needed_size)))
initial.commitd7cae122008-07-26 21:49:38271 return NULL;
272
maruel@google.comc9046af2008-08-06 20:35:17273#ifdef ARCH_CPU_64_BITS
274 DCHECK_LE(length, std::numeric_limits<uint32>::max());
275#endif
276
277 header_->payload_size = static_cast<uint32>(new_size);
initial.commitd7cae122008-07-26 21:49:38278 return payload() + offset;
279}
280
281void Pickle::EndWrite(char* dest, int length) {
282 // Zero-pad to keep tools like purify from complaining about uninitialized
283 // memory.
284 if (length % sizeof(uint32))
285 memset(dest + length, 0, sizeof(uint32) - (length % sizeof(uint32)));
286}
287
288bool Pickle::WriteBytes(const void* data, int data_len) {
deanm@google.com836061b2008-08-13 14:57:51289 DCHECK(capacity_ != kCapacityReadOnly) << "oops: pickle is readonly";
initial.commitd7cae122008-07-26 21:49:38290
291 char* dest = BeginWrite(data_len);
292 if (!dest)
293 return false;
294
295 memcpy(dest, data, data_len);
296
297 EndWrite(dest, data_len);
298 return true;
299}
300
301bool Pickle::WriteString(const std::string& value) {
302 if (!WriteInt(static_cast<int>(value.size())))
303 return false;
304
305 return WriteBytes(value.data(), static_cast<int>(value.size()));
306}
307
308bool Pickle::WriteWString(const std::wstring& value) {
309 if (!WriteInt(static_cast<int>(value.size())))
310 return false;
311
312 return WriteBytes(value.data(),
estade@chromium.org3a2a5d22009-03-04 03:36:36313 static_cast<int>(value.size() * sizeof(wchar_t)));
314}
315
316bool Pickle::WriteString16(const string16& value) {
317 if (!WriteInt(static_cast<int>(value.size())))
318 return false;
319
320 return WriteBytes(value.data(),
321 static_cast<int>(value.size()) * sizeof(char16));
initial.commitd7cae122008-07-26 21:49:38322}
323
324bool Pickle::WriteData(const char* data, int length) {
wtc@chromium.orge64ff5e2009-07-28 21:00:03325 return length >= 0 && WriteInt(length) && WriteBytes(data, length);
initial.commitd7cae122008-07-26 21:49:38326}
327
328char* Pickle::BeginWriteData(int length) {
darin@google.com44a1cbfa2008-08-15 01:05:11329 DCHECK_EQ(variable_buffer_offset_, 0U) <<
initial.commitd7cae122008-07-26 21:49:38330 "There can only be one variable buffer in a Pickle";
331
wtc@chromium.orge64ff5e2009-07-28 21:00:03332 if (length < 0 || !WriteInt(length))
333 return NULL;
initial.commitd7cae122008-07-26 21:49:38334
335 char *data_ptr = BeginWrite(length);
336 if (!data_ptr)
337 return NULL;
338
339 variable_buffer_offset_ =
340 data_ptr - reinterpret_cast<char*>(header_) - sizeof(int);
341
342 // EndWrite doesn't necessarily have to be called after the write operation,
343 // so we call it here to pad out what the caller will eventually write.
344 EndWrite(data_ptr, length);
345 return data_ptr;
346}
347
maruel@google.com9f16de02008-08-07 17:04:23348void Pickle::TrimWriteData(int new_length) {
initial.commitd7cae122008-07-26 21:49:38349 DCHECK(variable_buffer_offset_ != 0);
350
maruel@google.com9f16de02008-08-07 17:04:23351 // Fetch the the variable buffer size
352 int* cur_length = reinterpret_cast<int*>(
initial.commitd7cae122008-07-26 21:49:38353 reinterpret_cast<char*>(header_) + variable_buffer_offset_);
354
maruel@google.com9f16de02008-08-07 17:04:23355 if (new_length < 0 || new_length > *cur_length) {
356 NOTREACHED() << "Invalid length in TrimWriteData.";
357 return;
deanm@google.com65b10942008-08-07 15:18:20358 }
maruel@google.com9f16de02008-08-07 17:04:23359
360 // Update the payload size and variable buffer size
361 header_->payload_size -= (*cur_length - new_length);
362 *cur_length = new_length;
initial.commitd7cae122008-07-26 21:49:38363}
364
365bool Pickle::Resize(size_t new_capacity) {
366 new_capacity = AlignInt(new_capacity, kPayloadUnit);
367
368 void* p = realloc(header_, new_capacity);
369 if (!p)
370 return false;
371
372 header_ = reinterpret_cast<Header*>(p);
373 capacity_ = new_capacity;
374 return true;
375}
376
377// static
378const char* Pickle::FindNext(size_t header_size,
379 const char* start,
380 const char* end) {
381 DCHECK(header_size == AlignInt(header_size, sizeof(uint32)));
darin@google.com44a1cbfa2008-08-15 01:05:11382 DCHECK(header_size <= static_cast<size_t>(kPayloadUnit));
initial.commitd7cae122008-07-26 21:49:38383
384 const Header* hdr = reinterpret_cast<const Header*>(start);
385 const char* payload_base = start + header_size;
386 const char* payload_end = payload_base + hdr->payload_size;
387 if (payload_end < payload_base)
388 return NULL;
389
390 return (payload_end > end) ? NULL : payload_end;
391}