1 // Copyright (c) 2012 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()
11 //------------------------------------------------------------------------------
17 const int Pickle::kPayloadUnit
= 64;
19 static const size_t kCapacityReadOnly
= static_cast<size_t>(-1);
21 PickleIterator::PickleIterator(const Pickle
& pickle
)
22 : read_ptr_(pickle
.payload()),
23 read_end_ptr_(pickle
.end_of_payload()) {
26 template <typename Type
>
27 inline bool PickleIterator::ReadBuiltinType(Type
* result
) {
28 const char* read_from
= GetReadPointerAndAdvance
<Type
>();
31 if (sizeof(Type
) > sizeof(uint32
))
32 memcpy(result
, read_from
, sizeof(*result
));
34 *result
= *reinterpret_cast<const Type
*>(read_from
);
38 template<typename Type
>
39 inline const char* PickleIterator::GetReadPointerAndAdvance() {
40 const char* current_read_ptr
= read_ptr_
;
41 if (read_ptr_
+ sizeof(Type
) > read_end_ptr_
)
43 if (sizeof(Type
) < sizeof(uint32
))
44 read_ptr_
+= AlignInt(sizeof(Type
), sizeof(uint32
));
46 read_ptr_
+= sizeof(Type
);
47 return current_read_ptr
;
50 const char* PickleIterator::GetReadPointerAndAdvance(int num_bytes
) {
51 if (num_bytes
< 0 || read_end_ptr_
- read_ptr_
< num_bytes
)
53 const char* current_read_ptr
= read_ptr_
;
54 read_ptr_
+= AlignInt(num_bytes
, sizeof(uint32
));
55 return current_read_ptr
;
58 inline const char* PickleIterator::GetReadPointerAndAdvance(int num_elements
,
59 size_t size_element
) {
60 // Check for int32 overflow.
61 int64 num_bytes
= static_cast<int64
>(num_elements
) * size_element
;
62 int num_bytes32
= static_cast<int>(num_bytes
);
63 if (num_bytes
!= static_cast<int64
>(num_bytes32
))
65 return GetReadPointerAndAdvance(num_bytes32
);
68 bool PickleIterator::ReadBool(bool* result
) {
69 return ReadBuiltinType(result
);
72 bool PickleIterator::ReadInt(int* result
) {
73 return ReadBuiltinType(result
);
76 bool PickleIterator::ReadLong(long* result
) {
77 return ReadBuiltinType(result
);
80 bool PickleIterator::ReadUInt16(uint16
* result
) {
81 return ReadBuiltinType(result
);
84 bool PickleIterator::ReadUInt32(uint32
* result
) {
85 return ReadBuiltinType(result
);
88 bool PickleIterator::ReadInt64(int64
* result
) {
89 return ReadBuiltinType(result
);
92 bool PickleIterator::ReadUInt64(uint64
* result
) {
93 return ReadBuiltinType(result
);
96 bool PickleIterator::ReadFloat(float* result
) {
98 // The source data may not be properly aligned, and unaligned float reads
99 // cause SIGBUS on some ARM platforms, so force using memcpy to copy the data
101 const char* read_from
= GetReadPointerAndAdvance
<float>();
104 memcpy(result
, read_from
, sizeof(*result
));
108 bool PickleIterator::ReadString(std::string
* result
) {
112 const char* read_from
= GetReadPointerAndAdvance(len
);
116 result
->assign(read_from
, len
);
120 bool PickleIterator::ReadWString(std::wstring
* result
) {
124 const char* read_from
= GetReadPointerAndAdvance(len
, sizeof(wchar_t));
128 result
->assign(reinterpret_cast<const wchar_t*>(read_from
), len
);
132 bool PickleIterator::ReadString16(string16
* result
) {
136 const char* read_from
= GetReadPointerAndAdvance(len
, sizeof(char16
));
140 result
->assign(reinterpret_cast<const char16
*>(read_from
), len
);
144 bool PickleIterator::ReadData(const char** data
, int* length
) {
148 if (!ReadInt(length
))
151 return ReadBytes(data
, *length
);
154 bool PickleIterator::ReadBytes(const char** data
, int length
) {
155 const char* read_from
= GetReadPointerAndAdvance(length
);
162 // Payload is uint32 aligned.
166 header_size_(sizeof(Header
)),
167 capacity_after_header_(0),
169 Resize(kPayloadUnit
);
170 header_
->payload_size
= 0;
173 Pickle::Pickle(int header_size
)
175 header_size_(AlignInt(header_size
, sizeof(uint32
))),
176 capacity_after_header_(0),
178 DCHECK_GE(static_cast<size_t>(header_size
), sizeof(Header
));
179 DCHECK_LE(header_size
, kPayloadUnit
);
180 Resize(kPayloadUnit
);
181 header_
->payload_size
= 0;
184 Pickle::Pickle(const char* data
, int data_len
)
185 : header_(reinterpret_cast<Header
*>(const_cast<char*>(data
))),
187 capacity_after_header_(kCapacityReadOnly
),
189 if (data_len
>= static_cast<int>(sizeof(Header
)))
190 header_size_
= data_len
- header_
->payload_size
;
192 if (header_size_
> static_cast<unsigned int>(data_len
))
195 if (header_size_
!= AlignInt(header_size_
, sizeof(uint32
)))
198 // If there is anything wrong with the data, we're not going to use it.
203 Pickle::Pickle(const Pickle
& other
)
205 header_size_(other
.header_size_
),
206 capacity_after_header_(0),
207 write_offset_(other
.write_offset_
) {
208 size_t payload_size
= header_size_
+ other
.header_
->payload_size
;
209 Resize(payload_size
);
210 memcpy(header_
, other
.header_
, payload_size
);
214 if (capacity_after_header_
!= kCapacityReadOnly
)
218 Pickle
& Pickle::operator=(const Pickle
& other
) {
219 if (this == &other
) {
223 if (capacity_after_header_
== kCapacityReadOnly
) {
225 capacity_after_header_
= 0;
227 if (header_size_
!= other
.header_size_
) {
230 header_size_
= other
.header_size_
;
232 Resize(other
.header_
->payload_size
);
233 memcpy(header_
, other
.header_
,
234 other
.header_size_
+ other
.header_
->payload_size
);
235 write_offset_
= other
.write_offset_
;
239 bool Pickle::WriteString(const std::string
& value
) {
240 if (!WriteInt(static_cast<int>(value
.size())))
243 return WriteBytes(value
.data(), static_cast<int>(value
.size()));
246 bool Pickle::WriteWString(const std::wstring
& value
) {
247 if (!WriteInt(static_cast<int>(value
.size())))
250 return WriteBytes(value
.data(),
251 static_cast<int>(value
.size() * sizeof(wchar_t)));
254 bool Pickle::WriteString16(const string16
& value
) {
255 if (!WriteInt(static_cast<int>(value
.size())))
258 return WriteBytes(value
.data(),
259 static_cast<int>(value
.size()) * sizeof(char16
));
262 bool Pickle::WriteData(const char* data
, int length
) {
263 return length
>= 0 && WriteInt(length
) && WriteBytes(data
, length
);
266 bool Pickle::WriteBytes(const void* data
, int length
) {
267 WriteBytesCommon(data
, length
);
271 void Pickle::Reserve(size_t length
) {
272 size_t data_len
= AlignInt(length
, sizeof(uint32
));
273 DCHECK_GE(data_len
, length
);
274 #ifdef ARCH_CPU_64_BITS
275 DCHECK_LE(data_len
, kuint32max
);
277 DCHECK_LE(write_offset_
, kuint32max
- data_len
);
278 size_t new_size
= write_offset_
+ data_len
;
279 if (new_size
> capacity_after_header_
)
280 Resize(capacity_after_header_
* 2 + new_size
);
283 void Pickle::Resize(size_t new_capacity
) {
284 new_capacity
= AlignInt(new_capacity
, kPayloadUnit
);
286 CHECK_NE(capacity_after_header_
, kCapacityReadOnly
);
287 void* p
= realloc(header_
, header_size_
+ new_capacity
);
289 header_
= reinterpret_cast<Header
*>(p
);
290 capacity_after_header_
= new_capacity
;
294 const char* Pickle::FindNext(size_t header_size
,
297 DCHECK_EQ(header_size
, AlignInt(header_size
, sizeof(uint32
)));
298 DCHECK_LE(header_size
, static_cast<size_t>(kPayloadUnit
));
300 size_t length
= static_cast<size_t>(end
- start
);
301 if (length
< sizeof(Header
))
304 const Header
* hdr
= reinterpret_cast<const Header
*>(start
);
305 if (length
< header_size
|| length
- header_size
< hdr
->payload_size
)
307 return start
+ header_size
+ hdr
->payload_size
;
310 template <size_t length
> void Pickle::WriteBytesStatic(const void* data
) {
311 WriteBytesCommon(data
, length
);
314 template void Pickle::WriteBytesStatic
<2>(const void* data
);
315 template void Pickle::WriteBytesStatic
<4>(const void* data
);
316 template void Pickle::WriteBytesStatic
<8>(const void* data
);
318 inline void Pickle::WriteBytesCommon(const void* data
, size_t length
) {
319 DCHECK_NE(kCapacityReadOnly
, capacity_after_header_
)
320 << "oops: pickle is readonly";
321 size_t data_len
= AlignInt(length
, sizeof(uint32
));
322 DCHECK_GE(data_len
, length
);
323 #ifdef ARCH_CPU_64_BITS
324 DCHECK_LE(data_len
, kuint32max
);
326 DCHECK_LE(write_offset_
, kuint32max
- data_len
);
327 size_t new_size
= write_offset_
+ data_len
;
328 if (new_size
> capacity_after_header_
) {
329 Resize(std::max(capacity_after_header_
* 2, new_size
));
332 char* write
= mutable_payload() + write_offset_
;
333 memcpy(write
, data
, length
);
334 memset(write
+ length
, 0, data_len
- length
);
335 header_
->payload_size
= static_cast<uint32
>(write_offset_
+ length
);
336 write_offset_
= new_size
;