1 // Copyright (c) 2011 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"
9 #include <algorithm> // for max()
12 //------------------------------------------------------------------------------
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.
24 header_size_(sizeof(Header
)),
26 variable_buffer_offset_(0) {
28 header_
->payload_size
= 0;
31 Pickle::Pickle(int header_size
)
33 header_size_(AlignInt(header_size
, sizeof(uint32
))),
35 variable_buffer_offset_(0) {
36 DCHECK_GE(static_cast<size_t>(header_size
), sizeof(Header
));
37 DCHECK_LE(header_size
, kPayloadUnit
);
39 header_
->payload_size
= 0;
42 Pickle::Pickle(const char* data
, int data_len
)
43 : header_(reinterpret_cast<Header
*>(const_cast<char*>(data
))),
45 capacity_(kCapacityReadOnly
),
46 variable_buffer_offset_(0) {
47 if (data_len
>= static_cast<int>(sizeof(Header
)))
48 header_size_
= data_len
- header_
->payload_size
;
50 if (header_size_
> static_cast<unsigned int>(data_len
))
53 if (header_size_
!= AlignInt(header_size_
, sizeof(uint32
)))
56 // If there is anything wrong with the data, we're not going to use it.
61 Pickle::Pickle(const Pickle
& other
)
63 header_size_(other
.header_size_
),
65 variable_buffer_offset_(other
.variable_buffer_offset_
) {
66 size_t payload_size
= header_size_
+ other
.header_
->payload_size
;
67 bool resized
= Resize(payload_size
);
68 CHECK(resized
); // Realloc failed.
69 memcpy(header_
, other
.header_
, payload_size
);
73 if (capacity_
!= kCapacityReadOnly
)
77 Pickle
& Pickle::operator=(const Pickle
& other
) {
82 if (capacity_
== kCapacityReadOnly
) {
86 if (header_size_
!= other
.header_size_
) {
89 header_size_
= other
.header_size_
;
91 bool resized
= Resize(other
.header_size_
+ other
.header_
->payload_size
);
92 CHECK(resized
); // Realloc failed.
93 memcpy(header_
, other
.header_
,
94 other
.header_size_
+ other
.header_
->payload_size
);
95 variable_buffer_offset_
= other
.variable_buffer_offset_
;
99 bool Pickle::ReadBool(void** iter
, bool* result
) const {
103 if (!ReadInt(iter
, &tmp
))
105 DCHECK(0 == tmp
|| 1 == tmp
);
106 *result
= tmp
? true : false;
110 bool Pickle::ReadInt(void** iter
, int* result
) const {
113 *iter
= const_cast<char*>(payload());
115 if (!IteratorHasRoomFor(*iter
, sizeof(*result
)))
118 // TODO(jar): http://crbug.com/13108 Pickle should be cleaned up, and not
119 // dependent on alignment.
120 // Next line is otherwise the same as: memcpy(result, *iter, sizeof(*result));
121 *result
= *reinterpret_cast<int*>(*iter
);
123 UpdateIter(iter
, sizeof(*result
));
127 bool Pickle::ReadLong(void** iter
, long* result
) const {
130 *iter
= const_cast<char*>(payload());
132 if (!IteratorHasRoomFor(*iter
, sizeof(*result
)))
135 // TODO(jar): http://crbug.com/13108 Pickle should be cleaned up, and not
136 // dependent on alignment.
137 memcpy(result
, *iter
, sizeof(*result
));
139 UpdateIter(iter
, sizeof(*result
));
143 bool Pickle::ReadSize(void** iter
, size_t* result
) const {
146 *iter
= const_cast<char*>(payload());
148 if (!IteratorHasRoomFor(*iter
, sizeof(*result
)))
151 // TODO(jar): http://crbug.com/13108 Pickle should be cleaned up, and not
152 // dependent on alignment.
153 // Next line is otherwise the same as: memcpy(result, *iter, sizeof(*result));
154 *result
= *reinterpret_cast<size_t*>(*iter
);
156 UpdateIter(iter
, sizeof(*result
));
160 bool Pickle::ReadUInt16(void** iter
, uint16
* result
) const {
163 *iter
= const_cast<char*>(payload());
165 if (!IteratorHasRoomFor(*iter
, sizeof(*result
)))
168 memcpy(result
, *iter
, sizeof(*result
));
170 UpdateIter(iter
, sizeof(*result
));
174 bool Pickle::ReadUInt32(void** iter
, uint32
* result
) const {
177 *iter
= const_cast<char*>(payload());
179 if (!IteratorHasRoomFor(*iter
, sizeof(*result
)))
182 memcpy(result
, *iter
, sizeof(*result
));
184 UpdateIter(iter
, sizeof(*result
));
188 bool Pickle::ReadInt64(void** iter
, int64
* result
) const {
191 *iter
= const_cast<char*>(payload());
193 if (!IteratorHasRoomFor(*iter
, sizeof(*result
)))
196 memcpy(result
, *iter
, sizeof(*result
));
198 UpdateIter(iter
, sizeof(*result
));
202 bool Pickle::ReadUInt64(void** iter
, uint64
* result
) const {
205 *iter
= const_cast<char*>(payload());
207 if (!IteratorHasRoomFor(*iter
, sizeof(*result
)))
210 memcpy(result
, *iter
, sizeof(*result
));
212 UpdateIter(iter
, sizeof(*result
));
216 bool Pickle::ReadString(void** iter
, std::string
* result
) const {
220 if (!ReadLength(iter
, &len
))
222 if (!IteratorHasRoomFor(*iter
, len
))
225 char* chars
= reinterpret_cast<char*>(*iter
);
226 result
->assign(chars
, len
);
228 UpdateIter(iter
, len
);
232 bool Pickle::ReadWString(void** iter
, std::wstring
* result
) const {
236 if (!ReadLength(iter
, &len
))
238 // Avoid integer overflow.
239 if (len
> INT_MAX
/ static_cast<int>(sizeof(wchar_t)))
241 if (!IteratorHasRoomFor(*iter
, len
* sizeof(wchar_t)))
244 wchar_t* chars
= reinterpret_cast<wchar_t*>(*iter
);
245 result
->assign(chars
, len
);
247 UpdateIter(iter
, len
* sizeof(wchar_t));
251 bool Pickle::ReadString16(void** iter
, string16
* result
) const {
255 if (!ReadLength(iter
, &len
))
257 if (!IteratorHasRoomFor(*iter
, len
* sizeof(char16
)))
260 char16
* chars
= reinterpret_cast<char16
*>(*iter
);
261 result
->assign(chars
, len
);
263 UpdateIter(iter
, len
* sizeof(char16
));
267 bool Pickle::ReadData(void** iter
, const char** data
, int* length
) const {
274 if (!ReadLength(iter
, length
))
277 return ReadBytes(iter
, data
, *length
);
280 bool Pickle::ReadBytes(void** iter
, const char** data
, int length
) const {
285 *iter
= const_cast<char*>(payload());
287 if (!IteratorHasRoomFor(*iter
, length
))
290 *data
= reinterpret_cast<const char*>(*iter
);
292 UpdateIter(iter
, length
);
296 bool Pickle::ReadLength(void** iter
, int* result
) const {
297 if (!ReadInt(iter
, result
))
299 return ((*result
) >= 0);
302 bool Pickle::WriteString(const std::string
& value
) {
303 if (!WriteInt(static_cast<int>(value
.size())))
306 return WriteBytes(value
.data(), static_cast<int>(value
.size()));
309 bool Pickle::WriteWString(const std::wstring
& value
) {
310 if (!WriteInt(static_cast<int>(value
.size())))
313 return WriteBytes(value
.data(),
314 static_cast<int>(value
.size() * sizeof(wchar_t)));
317 bool Pickle::WriteString16(const string16
& value
) {
318 if (!WriteInt(static_cast<int>(value
.size())))
321 return WriteBytes(value
.data(),
322 static_cast<int>(value
.size()) * sizeof(char16
));
325 bool Pickle::WriteData(const char* data
, int length
) {
326 return length
>= 0 && WriteInt(length
) && WriteBytes(data
, length
);
329 bool Pickle::WriteBytes(const void* data
, int data_len
) {
330 DCHECK_NE(kCapacityReadOnly
, capacity_
) << "oops: pickle is readonly";
332 char* dest
= BeginWrite(data_len
);
336 memcpy(dest
, data
, data_len
);
338 EndWrite(dest
, data_len
);
342 char* Pickle::BeginWriteData(int length
) {
343 DCHECK_EQ(variable_buffer_offset_
, 0U) <<
344 "There can only be one variable buffer in a Pickle";
346 if (length
< 0 || !WriteInt(length
))
349 char *data_ptr
= BeginWrite(length
);
353 variable_buffer_offset_
=
354 data_ptr
- reinterpret_cast<char*>(header_
) - sizeof(int);
356 // EndWrite doesn't necessarily have to be called after the write operation,
357 // so we call it here to pad out what the caller will eventually write.
358 EndWrite(data_ptr
, length
);
362 void Pickle::TrimWriteData(int new_length
) {
363 DCHECK_NE(variable_buffer_offset_
, 0U);
365 // Fetch the the variable buffer size
366 int* cur_length
= reinterpret_cast<int*>(
367 reinterpret_cast<char*>(header_
) + variable_buffer_offset_
);
369 if (new_length
< 0 || new_length
> *cur_length
) {
370 NOTREACHED() << "Invalid length in TrimWriteData.";
374 // Update the payload size and variable buffer size
375 header_
->payload_size
-= (*cur_length
- new_length
);
376 *cur_length
= new_length
;
379 char* Pickle::BeginWrite(size_t length
) {
380 // write at a uint32-aligned offset from the beginning of the header
381 size_t offset
= AlignInt(header_
->payload_size
, sizeof(uint32
));
383 size_t new_size
= offset
+ length
;
384 size_t needed_size
= header_size_
+ new_size
;
385 if (needed_size
> capacity_
&& !Resize(std::max(capacity_
* 2, needed_size
)))
388 #ifdef ARCH_CPU_64_BITS
389 DCHECK_LE(length
, std::numeric_limits
<uint32
>::max());
392 header_
->payload_size
= static_cast<uint32
>(new_size
);
393 return payload() + offset
;
396 void Pickle::EndWrite(char* dest
, int length
) {
397 // Zero-pad to keep tools like purify from complaining about uninitialized
399 if (length
% sizeof(uint32
))
400 memset(dest
+ length
, 0, sizeof(uint32
) - (length
% sizeof(uint32
)));
403 bool Pickle::Resize(size_t new_capacity
) {
404 new_capacity
= AlignInt(new_capacity
, kPayloadUnit
);
406 CHECK_NE(capacity_
, kCapacityReadOnly
);
407 void* p
= realloc(header_
, new_capacity
);
411 header_
= reinterpret_cast<Header
*>(p
);
412 capacity_
= new_capacity
;
417 const char* Pickle::FindNext(size_t header_size
,
420 DCHECK_EQ(header_size
, AlignInt(header_size
, sizeof(uint32
)));
421 DCHECK_LE(header_size
, static_cast<size_t>(kPayloadUnit
));
423 if (static_cast<size_t>(end
- start
) < sizeof(Header
))
426 const Header
* hdr
= reinterpret_cast<const Header
*>(start
);
427 const char* payload_base
= start
+ header_size
;
428 const char* payload_end
= payload_base
+ hdr
->payload_size
;
429 if (payload_end
< payload_base
)
432 return (payload_end
> end
) ? NULL
: payload_end
;