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 : #include "base/pickle.h"
6 :
7 : #include <stdlib.h>
8 :
9 : #include <limits>
10 : #include <string>
11 :
12 : //------------------------------------------------------------------------------
13 :
14 : // static
15 : const int Pickle::kPayloadUnit = 64;
16 :
17 : // We mark a read only pickle with a special capacity_.
18 : static const uint32 kCapacityReadOnly = (uint32) -1;
19 :
20 : // Payload is uint32 aligned.
21 :
22 2 : Pickle::Pickle()
23 : : header_(NULL),
24 : header_size_(sizeof(Header)),
25 : capacity_(0),
26 2 : variable_buffer_offset_(0) {
27 2 : Resize(kPayloadUnit);
28 2 : header_->payload_size = 0;
29 2 : }
30 :
31 2 : Pickle::Pickle(int header_size)
32 : : header_(NULL),
33 2 : header_size_(AlignInt(header_size, sizeof(uint32))),
34 : capacity_(0),
35 4 : variable_buffer_offset_(0) {
36 2 : DCHECK(static_cast<uint32>(header_size) >= sizeof(Header));
37 2 : DCHECK(header_size <= kPayloadUnit);
38 2 : Resize(kPayloadUnit);
39 2 : header_->payload_size = 0;
40 2 : }
41 :
42 2 : 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 2 : variable_buffer_offset_(0) {
47 2 : DCHECK(header_size_ >= sizeof(Header));
48 2 : DCHECK(header_size_ == AlignInt(header_size_, sizeof(uint32)));
49 2 : }
50 :
51 0 : Pickle::Pickle(const Pickle& other)
52 : : header_(NULL),
53 : header_size_(other.header_size_),
54 : capacity_(0),
55 0 : variable_buffer_offset_(other.variable_buffer_offset_) {
56 0 : uint32 payload_size = header_size_ + other.header_->payload_size;
57 0 : bool resized = Resize(payload_size);
58 0 : CHECK(resized); // Realloc failed.
59 0 : memcpy(header_, other.header_, payload_size);
60 0 : }
61 :
62 4 : Pickle::~Pickle() {
63 4 : if (capacity_ != kCapacityReadOnly)
64 2 : free(header_);
65 4 : }
66 :
67 0 : Pickle& Pickle::operator=(const Pickle& other) {
68 0 : if (header_size_ != other.header_size_ && capacity_ != kCapacityReadOnly) {
69 0 : free(header_);
70 0 : header_ = NULL;
71 0 : header_size_ = other.header_size_;
72 : }
73 0 : bool resized = Resize(other.header_size_ + other.header_->payload_size);
74 0 : CHECK(resized); // Realloc failed.
75 0 : memcpy(header_, other.header_, header_size_ + other.header_->payload_size);
76 0 : variable_buffer_offset_ = other.variable_buffer_offset_;
77 0 : return *this;
78 : }
79 :
80 0 : bool Pickle::ReadBool(void** iter, bool* result) const {
81 0 : DCHECK(iter);
82 :
83 : int tmp;
84 0 : if (!ReadInt(iter, &tmp))
85 0 : return false;
86 0 : DCHECK(0 == tmp || 1 == tmp);
87 0 : *result = tmp ? true : false;
88 0 : return true;
89 : }
90 :
91 0 : bool Pickle::ReadInt16(void** iter, int16* result) const {
92 0 : DCHECK(iter);
93 0 : if (!*iter)
94 0 : *iter = const_cast<char*>(payload());
95 :
96 0 : if (!IteratorHasRoomFor(*iter, sizeof(*result)))
97 0 : return false;
98 :
99 0 : memcpy(result, *iter, sizeof(*result));
100 :
101 0 : UpdateIter(iter, sizeof(*result));
102 0 : return true;
103 : }
104 :
105 0 : bool Pickle::ReadUInt16(void** iter, uint16* result) const {
106 0 : DCHECK(iter);
107 0 : if (!*iter)
108 0 : *iter = const_cast<char*>(payload());
109 :
110 0 : if (!IteratorHasRoomFor(*iter, sizeof(*result)))
111 0 : return false;
112 :
113 0 : memcpy(result, *iter, sizeof(*result));
114 :
115 0 : UpdateIter(iter, sizeof(*result));
116 0 : return true;
117 : }
118 :
119 41885 : bool Pickle::ReadInt(void** iter, int* result) const {
120 41885 : DCHECK(iter);
121 41885 : if (!*iter)
122 0 : *iter = const_cast<char*>(payload());
123 :
124 41885 : if (!IteratorHasRoomFor(*iter, sizeof(*result)))
125 0 : return false;
126 :
127 : // TODO(jar) bug 1129285: Pickle should be cleaned up, and not dependent on
128 : // alignment.
129 : // Next line is otherwise the same as: memcpy(result, *iter, sizeof(*result));
130 41885 : *result = *reinterpret_cast<int*>(*iter);
131 :
132 41885 : UpdateIter(iter, sizeof(*result));
133 41885 : return true;
134 : }
135 :
136 : // Always written as a 64-bit value since the size for this type can
137 : // differ between architectures.
138 0 : bool Pickle::ReadLong(void** iter, long* result) const {
139 0 : DCHECK(iter);
140 0 : if (!*iter)
141 0 : *iter = const_cast<char*>(payload());
142 :
143 0 : int64 bigResult = 0;
144 0 : if (!IteratorHasRoomFor(*iter, sizeof(bigResult)))
145 0 : return false;
146 :
147 : // TODO(jar) bug 1129285: Pickle should be cleaned up, and not dependent on
148 : // alignment.
149 0 : memcpy(&bigResult, *iter, sizeof(bigResult));
150 0 : DCHECK(bigResult <= LONG_MAX && bigResult >= LONG_MIN);
151 0 : *result = static_cast<long>(bigResult);
152 :
153 0 : UpdateIter(iter, sizeof(bigResult));
154 0 : return true;
155 : }
156 :
157 : // Always written as a 64-bit value since the size for this type can
158 : // differ between architectures.
159 0 : bool Pickle::ReadULong(void** iter, unsigned long* result) const {
160 0 : DCHECK(iter);
161 0 : if (!*iter)
162 0 : *iter = const_cast<char*>(payload());
163 :
164 0 : uint64 bigResult = 0;
165 0 : if (!IteratorHasRoomFor(*iter, sizeof(bigResult)))
166 0 : return false;
167 :
168 : // TODO(jar) bug 1129285: Pickle should be cleaned up, and not dependent on
169 : // alignment.
170 0 : memcpy(&bigResult, *iter, sizeof(bigResult));
171 0 : DCHECK(bigResult <= ULONG_MAX);
172 0 : *result = static_cast<unsigned long>(bigResult);
173 :
174 0 : UpdateIter(iter, sizeof(bigResult));
175 0 : return true;
176 : }
177 :
178 76 : bool Pickle::ReadLength(void** iter, int* result) const {
179 76 : if (!ReadInt(iter, result))
180 0 : return false;
181 76 : return ((*result) >= 0);
182 : }
183 :
184 : // Always written as a 64-bit value since the size for this type can
185 : // differ between architectures.
186 74 : bool Pickle::ReadSize(void** iter, size_t* result) const {
187 74 : DCHECK(iter);
188 74 : if (!*iter)
189 0 : *iter = const_cast<char*>(payload());
190 :
191 74 : uint64 bigResult = 0;
192 74 : if (!IteratorHasRoomFor(*iter, sizeof(bigResult)))
193 0 : return false;
194 :
195 : // TODO(jar) bug 1129285: Pickle should be cleaned up, and not dependent on
196 : // alignment.
197 74 : memcpy(&bigResult, *iter, sizeof(bigResult));
198 74 : DCHECK(bigResult <= std::numeric_limits<size_t>::max());
199 74 : *result = static_cast<size_t>(bigResult);
200 :
201 74 : UpdateIter(iter, sizeof(bigResult));
202 74 : return true;
203 : }
204 :
205 0 : bool Pickle::ReadInt32(void** iter, int32* result) const {
206 0 : DCHECK(iter);
207 0 : if (!*iter)
208 0 : *iter = const_cast<char*>(payload());
209 :
210 0 : if (!IteratorHasRoomFor(*iter, sizeof(*result)))
211 0 : return false;
212 :
213 0 : memcpy(result, *iter, sizeof(*result));
214 :
215 0 : UpdateIter(iter, sizeof(*result));
216 0 : return true;
217 : }
218 :
219 4 : bool Pickle::ReadUInt32(void** iter, uint32* result) const {
220 4 : DCHECK(iter);
221 4 : if (!*iter)
222 2 : *iter = const_cast<char*>(payload());
223 :
224 4 : if (!IteratorHasRoomFor(*iter, sizeof(*result)))
225 0 : return false;
226 :
227 4 : memcpy(result, *iter, sizeof(*result));
228 :
229 4 : UpdateIter(iter, sizeof(*result));
230 4 : return true;
231 : }
232 :
233 148 : bool Pickle::ReadInt64(void** iter, int64* result) const {
234 148 : DCHECK(iter);
235 148 : if (!*iter)
236 0 : *iter = const_cast<char*>(payload());
237 :
238 148 : if (!IteratorHasRoomFor(*iter, sizeof(*result)))
239 0 : return false;
240 :
241 148 : memcpy(result, *iter, sizeof(*result));
242 :
243 148 : UpdateIter(iter, sizeof(*result));
244 148 : return true;
245 : }
246 :
247 0 : bool Pickle::ReadUInt64(void** iter, uint64* result) const {
248 0 : DCHECK(iter);
249 0 : if (!*iter)
250 0 : *iter = const_cast<char*>(payload());
251 :
252 0 : if (!IteratorHasRoomFor(*iter, sizeof(*result)))
253 0 : return false;
254 :
255 0 : memcpy(result, *iter, sizeof(*result));
256 :
257 0 : UpdateIter(iter, sizeof(*result));
258 0 : return true;
259 : }
260 :
261 0 : bool Pickle::ReadDouble(void** iter, double* result) const {
262 0 : DCHECK(iter);
263 0 : if (!*iter)
264 0 : *iter = const_cast<char*>(payload());
265 :
266 0 : if (!IteratorHasRoomFor(*iter, sizeof(*result)))
267 0 : return false;
268 :
269 0 : memcpy(result, *iter, sizeof(*result));
270 :
271 0 : UpdateIter(iter, sizeof(*result));
272 0 : return true;
273 : }
274 :
275 : // Always written as a 64-bit value since the size for this type can
276 : // differ between architectures.
277 0 : bool Pickle::ReadIntPtr(void** iter, intptr_t* result) const {
278 0 : DCHECK(iter);
279 0 : if (!*iter)
280 0 : *iter = const_cast<char*>(payload());
281 :
282 0 : int64 bigResult = 0;
283 0 : if (!IteratorHasRoomFor(*iter, sizeof(bigResult)))
284 0 : return false;
285 :
286 0 : memcpy(&bigResult, *iter, sizeof(bigResult));
287 0 : DCHECK(bigResult <= std::numeric_limits<intptr_t>::max() && bigResult >= std::numeric_limits<intptr_t>::min());
288 0 : *result = static_cast<intptr_t>(bigResult);
289 :
290 0 : UpdateIter(iter, sizeof(bigResult));
291 0 : return true;
292 : }
293 :
294 0 : bool Pickle::ReadUnsignedChar(void** iter, unsigned char* result) const {
295 0 : DCHECK(iter);
296 0 : if (!*iter)
297 0 : *iter = const_cast<char*>(payload());
298 :
299 0 : if (!IteratorHasRoomFor(*iter, sizeof(*result)))
300 0 : return false;
301 :
302 0 : memcpy(result, *iter, sizeof(*result));
303 :
304 0 : UpdateIter(iter, sizeof(*result));
305 0 : return true;
306 : }
307 :
308 0 : bool Pickle::ReadString(void** iter, std::string* result) const {
309 0 : DCHECK(iter);
310 0 : if (!*iter)
311 0 : *iter = const_cast<char*>(payload());
312 :
313 : int len;
314 0 : if (!ReadLength(iter, &len))
315 0 : return false;
316 0 : if (!IteratorHasRoomFor(*iter, len))
317 0 : return false;
318 :
319 0 : char* chars = reinterpret_cast<char*>(*iter);
320 0 : result->assign(chars, len);
321 :
322 0 : UpdateIter(iter, len);
323 0 : return true;
324 : }
325 :
326 0 : bool Pickle::ReadWString(void** iter, std::wstring* result) const {
327 0 : DCHECK(iter);
328 0 : if (!*iter)
329 0 : *iter = const_cast<char*>(payload());
330 :
331 : int len;
332 0 : if (!ReadLength(iter, &len))
333 0 : return false;
334 0 : if (!IteratorHasRoomFor(*iter, len * sizeof(wchar_t)))
335 0 : return false;
336 :
337 0 : wchar_t* chars = reinterpret_cast<wchar_t*>(*iter);
338 0 : result->assign(chars, len);
339 :
340 0 : UpdateIter(iter, len * sizeof(wchar_t));
341 0 : return true;
342 : }
343 :
344 0 : bool Pickle::ReadString16(void** iter, string16* result) const {
345 0 : DCHECK(iter);
346 0 : if (!*iter)
347 0 : *iter = const_cast<char*>(payload());
348 :
349 : int len;
350 0 : if (!ReadLength(iter, &len))
351 0 : return false;
352 0 : if (!IteratorHasRoomFor(*iter, len))
353 0 : return false;
354 :
355 0 : char16* chars = reinterpret_cast<char16*>(*iter);
356 0 : result->assign(chars, len);
357 :
358 0 : UpdateIter(iter, len * sizeof(char16));
359 0 : return true;
360 : }
361 :
362 76 : bool Pickle::ReadBytes(void** iter, const char** data, int length) const {
363 76 : DCHECK(iter);
364 76 : DCHECK(data);
365 76 : if (!*iter)
366 0 : *iter = const_cast<char*>(payload());
367 :
368 76 : if (!IteratorHasRoomFor(*iter, length))
369 0 : return false;
370 :
371 76 : *data = reinterpret_cast<const char*>(*iter);
372 :
373 76 : UpdateIter(iter, length);
374 76 : return true;
375 : }
376 :
377 76 : bool Pickle::ReadData(void** iter, const char** data, int* length) const {
378 76 : DCHECK(iter);
379 76 : DCHECK(data);
380 76 : DCHECK(length);
381 76 : if (!*iter)
382 0 : *iter = const_cast<char*>(payload());
383 :
384 76 : if (!ReadLength(iter, length))
385 0 : return false;
386 :
387 76 : return ReadBytes(iter, data, *length);
388 : }
389 :
390 42188 : char* Pickle::BeginWrite(uint32 length) {
391 : // write at a uint32-aligned offset from the beginning of the header
392 42188 : uint32 offset = AlignInt(header_->payload_size, sizeof(uint32));
393 42188 : uint32 new_size = offset + AlignInt(length, sizeof(uint32));
394 42188 : uint32 needed_size = header_size_ + new_size;
395 :
396 42188 : if (needed_size > capacity_ && !Resize(std::max(capacity_ * 2, needed_size)))
397 0 : return NULL;
398 :
399 : #ifdef ARCH_CPU_64_BITS
400 : DCHECK_LE(length, std::numeric_limits<uint32>::max());
401 : #endif
402 :
403 42188 : header_->payload_size = static_cast<uint32>(new_size);
404 42188 : return payload() + offset;
405 : }
406 :
407 42188 : void Pickle::EndWrite(char* dest, int length) {
408 : // Zero-pad to keep tools like purify from complaining about uninitialized
409 : // memory.
410 42188 : if (length % sizeof(uint32))
411 54 : memset(dest + length, 0, sizeof(uint32) - (length % sizeof(uint32)));
412 42188 : }
413 :
414 42188 : bool Pickle::WriteBytes(const void* data, int data_len) {
415 42188 : DCHECK(capacity_ != kCapacityReadOnly) << "oops: pickle is readonly";
416 :
417 42188 : char* dest = BeginWrite(data_len);
418 42188 : if (!dest)
419 0 : return false;
420 :
421 42188 : memcpy(dest, data, data_len);
422 :
423 42188 : EndWrite(dest, data_len);
424 42188 : return true;
425 : }
426 :
427 0 : bool Pickle::WriteString(const std::string& value) {
428 0 : if (!WriteInt(static_cast<int>(value.size())))
429 0 : return false;
430 :
431 0 : return WriteBytes(value.data(), static_cast<int>(value.size()));
432 : }
433 :
434 0 : bool Pickle::WriteWString(const std::wstring& value) {
435 0 : if (!WriteInt(static_cast<int>(value.size())))
436 0 : return false;
437 :
438 0 : return WriteBytes(value.data(),
439 0 : static_cast<int>(value.size() * sizeof(wchar_t)));
440 : }
441 :
442 0 : bool Pickle::WriteString16(const string16& value) {
443 0 : if (!WriteInt(static_cast<int>(value.size())))
444 0 : return false;
445 :
446 0 : return WriteBytes(value.data(),
447 0 : static_cast<int>(value.size()) * sizeof(char16));
448 : }
449 :
450 76 : bool Pickle::WriteData(const char* data, int length) {
451 76 : return WriteInt(length) && WriteBytes(data, length);
452 : }
453 :
454 0 : char* Pickle::BeginWriteData(int length) {
455 0 : DCHECK_EQ(variable_buffer_offset_, 0U) <<
456 0 : "There can only be one variable buffer in a Pickle";
457 :
458 0 : if (!WriteInt(length))
459 0 : return false;
460 :
461 0 : char *data_ptr = BeginWrite(length);
462 0 : if (!data_ptr)
463 0 : return NULL;
464 :
465 : variable_buffer_offset_ =
466 0 : data_ptr - reinterpret_cast<char*>(header_) - sizeof(int);
467 :
468 : // EndWrite doesn't necessarily have to be called after the write operation,
469 : // so we call it here to pad out what the caller will eventually write.
470 0 : EndWrite(data_ptr, length);
471 0 : return data_ptr;
472 : }
473 :
474 0 : void Pickle::TrimWriteData(int new_length) {
475 0 : DCHECK(variable_buffer_offset_ != 0);
476 :
477 : // Fetch the the variable buffer size
478 : int* cur_length = reinterpret_cast<int*>(
479 0 : reinterpret_cast<char*>(header_) + variable_buffer_offset_);
480 :
481 0 : if (new_length < 0 || new_length > *cur_length) {
482 0 : NOTREACHED() << "Invalid length in TrimWriteData.";
483 0 : return;
484 : }
485 :
486 : // Update the payload size and variable buffer size
487 0 : header_->payload_size -= (*cur_length - new_length);
488 0 : *cur_length = new_length;
489 : }
490 :
491 20 : bool Pickle::Resize(uint32 new_capacity) {
492 20 : new_capacity = AlignInt(new_capacity, kPayloadUnit);
493 :
494 20 : void* p = realloc(header_, new_capacity);
495 20 : if (!p)
496 0 : return false;
497 :
498 20 : header_ = reinterpret_cast<Header*>(p);
499 20 : capacity_ = new_capacity;
500 20 : return true;
501 : }
502 :
503 : // static
504 0 : const char* Pickle::FindNext(uint32 header_size,
505 : const char* start,
506 : const char* end) {
507 0 : DCHECK(header_size == AlignInt(header_size, sizeof(uint32)));
508 0 : DCHECK(header_size <= static_cast<uint32>(kPayloadUnit));
509 :
510 0 : const Header* hdr = reinterpret_cast<const Header*>(start);
511 0 : const char* payload_base = start + header_size;
512 0 : const char* payload_end = payload_base + hdr->payload_size;
513 0 : if (payload_end < payload_base)
514 0 : return NULL;
515 :
516 0 : return (payload_end > end) ? NULL : payload_end;
517 : }
|