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"
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(static_cast<size_t>(header_size
) >= sizeof(Header
));
37 DCHECK(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
))),
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
)
53 header_size_(other
.header_size_
),
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
);
63 if (capacity_
!= kCapacityReadOnly
)
67 Pickle
& Pickle::operator=(const Pickle
& other
) {
68 if (header_size_
!= other
.header_size_
&& capacity_
!= kCapacityReadOnly
) {
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_
;
80 bool Pickle::ReadBool(void** iter
, bool* result
) const {
84 if (!ReadInt(iter
, &tmp
))
86 DCHECK(0 == tmp
|| 1 == tmp
);
87 *result
= tmp
? true : false;
91 bool Pickle::ReadInt(void** iter
, int* result
) const {
94 *iter
= const_cast<char*>(payload());
96 if (!IteratorHasRoomFor(*iter
, sizeof(*result
)))
99 // TODO(jar) bug 1129285: Pickle should be cleaned up, and not dependent on
101 // Next line is otherwise the same as: memcpy(result, *iter, sizeof(*result));
102 *result
= *reinterpret_cast<int*>(*iter
);
104 UpdateIter(iter
, sizeof(*result
));
108 bool Pickle::ReadLong(void** iter
, long* result
) const {
111 *iter
= const_cast<char*>(payload());
113 if (!IteratorHasRoomFor(*iter
, sizeof(*result
)))
116 // TODO(jar) bug 1129285: Pickle should be cleaned up, and not dependent on
118 memcpy(result
, *iter
, sizeof(*result
));
120 UpdateIter(iter
, sizeof(*result
));
124 bool Pickle::ReadLength(void** iter
, int* result
) const {
125 if (!ReadInt(iter
, result
))
127 return ((*result
) >= 0);
130 bool Pickle::ReadSize(void** iter
, size_t* result
) const {
133 *iter
= const_cast<char*>(payload());
135 if (!IteratorHasRoomFor(*iter
, sizeof(*result
)))
138 // TODO(jar) bug 1129285: Pickle should be cleaned up, and not dependent on
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
));
147 bool Pickle::ReadInt64(void** iter
, int64
* result
) const {
150 *iter
= const_cast<char*>(payload());
152 if (!IteratorHasRoomFor(*iter
, sizeof(*result
)))
155 memcpy(result
, *iter
, sizeof(*result
));
157 UpdateIter(iter
, sizeof(*result
));
161 bool Pickle::ReadIntPtr(void** iter
, intptr_t* result
) const {
164 *iter
= const_cast<char*>(payload());
166 if (!IteratorHasRoomFor(*iter
, sizeof(*result
)))
169 memcpy(result
, *iter
, sizeof(*result
));
171 UpdateIter(iter
, sizeof(*result
));
175 bool Pickle::ReadString(void** iter
, std::string
* result
) const {
179 if (!ReadLength(iter
, &len
))
181 if (!IteratorHasRoomFor(*iter
, len
))
184 char* chars
= reinterpret_cast<char*>(*iter
);
185 result
->assign(chars
, len
);
187 UpdateIter(iter
, len
);
191 bool Pickle::ReadWString(void** iter
, std::wstring
* result
) const {
195 if (!ReadLength(iter
, &len
))
197 if (!IteratorHasRoomFor(*iter
, len
* sizeof(wchar_t)))
200 wchar_t* chars
= reinterpret_cast<wchar_t*>(*iter
);
201 result
->assign(chars
, len
);
203 UpdateIter(iter
, len
* sizeof(wchar_t));
207 bool Pickle::ReadBytes(void** iter
, const char** data
, int length
) const {
211 if (!IteratorHasRoomFor(*iter
, length
))
214 *data
= reinterpret_cast<const char*>(*iter
);
216 UpdateIter(iter
, length
);
220 bool Pickle::ReadData(void** iter
, const char** data
, int* length
) const {
225 if (!ReadLength(iter
, length
))
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
))
239 #ifdef ARCH_CPU_64_BITS
240 DCHECK_LE(length
, std::numeric_limits
<uint32
>::max());
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
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
);
261 memcpy(dest
, data
, data_len
);
263 EndWrite(dest
, data_len
);
267 bool Pickle::WriteString(const std::string
& value
) {
268 if (!WriteInt(static_cast<int>(value
.size())))
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())))
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
))
293 char *data_ptr
= BeginWrite(length
);
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
);
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.";
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
);
330 header_
= reinterpret_cast<Header
*>(p
);
331 capacity_
= new_capacity
;
336 const char* Pickle::FindNext(size_t header_size
,
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
)
348 return (payload_end
> end
) ? NULL
: payload_end
;