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 #include "base/bits.h"
12 #include "base/macros.h"
17 const int Pickle::kPayloadUnit
= 64;
19 static const size_t kCapacityReadOnly
= static_cast<size_t>(-1);
21 PickleIterator::PickleIterator(const Pickle
& pickle
)
22 : payload_(pickle
.payload()),
24 end_index_(pickle
.payload_size()) {
27 template <typename Type
>
28 inline bool PickleIterator::ReadBuiltinType(Type
* result
) {
29 const char* read_from
= GetReadPointerAndAdvance
<Type
>();
32 if (sizeof(Type
) > sizeof(uint32
))
33 memcpy(result
, read_from
, sizeof(*result
));
35 *result
= *reinterpret_cast<const Type
*>(read_from
);
39 inline void PickleIterator::Advance(size_t size
) {
40 size_t aligned_size
= bits::Align(size
, sizeof(uint32_t));
41 if (end_index_
- read_index_
< aligned_size
) {
42 read_index_
= end_index_
;
44 read_index_
+= aligned_size
;
48 template<typename Type
>
49 inline const char* PickleIterator::GetReadPointerAndAdvance() {
50 if (sizeof(Type
) > end_index_
- read_index_
) {
51 read_index_
= end_index_
;
54 const char* current_read_ptr
= payload_
+ read_index_
;
55 Advance(sizeof(Type
));
56 return current_read_ptr
;
59 const char* PickleIterator::GetReadPointerAndAdvance(int num_bytes
) {
61 end_index_
- read_index_
< static_cast<size_t>(num_bytes
)) {
62 read_index_
= end_index_
;
65 const char* current_read_ptr
= payload_
+ read_index_
;
67 return current_read_ptr
;
70 inline const char* PickleIterator::GetReadPointerAndAdvance(
72 size_t size_element
) {
73 // Check for int32 overflow.
74 int64 num_bytes
= static_cast<int64
>(num_elements
) * size_element
;
75 int num_bytes32
= static_cast<int>(num_bytes
);
76 if (num_bytes
!= static_cast<int64
>(num_bytes32
))
78 return GetReadPointerAndAdvance(num_bytes32
);
81 bool PickleIterator::ReadBool(bool* result
) {
82 return ReadBuiltinType(result
);
85 bool PickleIterator::ReadInt(int* result
) {
86 return ReadBuiltinType(result
);
89 bool PickleIterator::ReadLong(long* result
) {
90 return ReadBuiltinType(result
);
93 bool PickleIterator::ReadUInt16(uint16
* result
) {
94 return ReadBuiltinType(result
);
97 bool PickleIterator::ReadUInt32(uint32
* result
) {
98 return ReadBuiltinType(result
);
101 bool PickleIterator::ReadInt64(int64
* result
) {
102 return ReadBuiltinType(result
);
105 bool PickleIterator::ReadUInt64(uint64
* result
) {
106 return ReadBuiltinType(result
);
109 bool PickleIterator::ReadSizeT(size_t* result
) {
110 // Always read size_t as a 64-bit value to ensure compatibility between 32-bit
111 // and 64-bit processes.
112 uint64 result_uint64
= 0;
113 bool success
= ReadBuiltinType(&result_uint64
);
114 *result
= static_cast<size_t>(result_uint64
);
115 // Fail if the cast above truncates the value.
116 return success
&& (*result
== result_uint64
);
119 bool PickleIterator::ReadFloat(float* result
) {
121 // The source data may not be properly aligned, and unaligned float reads
122 // cause SIGBUS on some ARM platforms, so force using memcpy to copy the data
124 const char* read_from
= GetReadPointerAndAdvance
<float>();
127 memcpy(result
, read_from
, sizeof(*result
));
131 bool PickleIterator::ReadDouble(double* result
) {
133 // The source data may not be properly aligned, and unaligned double reads
134 // cause SIGBUS on some ARM platforms, so force using memcpy to copy the data
136 const char* read_from
= GetReadPointerAndAdvance
<double>();
139 memcpy(result
, read_from
, sizeof(*result
));
143 bool PickleIterator::ReadString(std::string
* result
) {
147 const char* read_from
= GetReadPointerAndAdvance(len
);
151 result
->assign(read_from
, len
);
155 bool PickleIterator::ReadStringPiece(StringPiece
* result
) {
159 const char* read_from
= GetReadPointerAndAdvance(len
);
163 *result
= StringPiece(read_from
, len
);
167 bool PickleIterator::ReadString16(string16
* result
) {
171 const char* read_from
= GetReadPointerAndAdvance(len
, sizeof(char16
));
175 result
->assign(reinterpret_cast<const char16
*>(read_from
), len
);
179 bool PickleIterator::ReadStringPiece16(StringPiece16
* result
) {
183 const char* read_from
= GetReadPointerAndAdvance(len
, sizeof(char16
));
187 *result
= StringPiece16(reinterpret_cast<const char16
*>(read_from
), len
);
191 bool PickleIterator::ReadData(const char** data
, int* length
) {
195 if (!ReadInt(length
))
198 return ReadBytes(data
, *length
);
201 bool PickleIterator::ReadBytes(const char** data
, int length
) {
202 const char* read_from
= GetReadPointerAndAdvance(length
);
209 // Payload is uint32 aligned.
213 header_size_(sizeof(Header
)),
214 capacity_after_header_(0),
216 static_assert((Pickle::kPayloadUnit
& (Pickle::kPayloadUnit
- 1)) == 0,
217 "Pickle::kPayloadUnit must be a power of two");
218 Resize(kPayloadUnit
);
219 header_
->payload_size
= 0;
222 Pickle::Pickle(int header_size
)
224 header_size_(bits::Align(header_size
, sizeof(uint32
))),
225 capacity_after_header_(0),
227 DCHECK_GE(static_cast<size_t>(header_size
), sizeof(Header
));
228 DCHECK_LE(header_size
, kPayloadUnit
);
229 Resize(kPayloadUnit
);
230 header_
->payload_size
= 0;
233 Pickle::Pickle(const char* data
, int data_len
)
234 : header_(reinterpret_cast<Header
*>(const_cast<char*>(data
))),
236 capacity_after_header_(kCapacityReadOnly
),
238 if (data_len
>= static_cast<int>(sizeof(Header
)))
239 header_size_
= data_len
- header_
->payload_size
;
241 if (header_size_
> static_cast<unsigned int>(data_len
))
244 if (header_size_
!= bits::Align(header_size_
, sizeof(uint32
)))
247 // If there is anything wrong with the data, we're not going to use it.
252 Pickle::Pickle(const Pickle
& other
)
254 header_size_(other
.header_size_
),
255 capacity_after_header_(0),
256 write_offset_(other
.write_offset_
) {
257 size_t payload_size
= header_size_
+ other
.header_
->payload_size
;
258 Resize(payload_size
);
259 memcpy(header_
, other
.header_
, payload_size
);
263 if (capacity_after_header_
!= kCapacityReadOnly
)
267 Pickle
& Pickle::operator=(const Pickle
& other
) {
268 if (this == &other
) {
272 if (capacity_after_header_
== kCapacityReadOnly
) {
274 capacity_after_header_
= 0;
276 if (header_size_
!= other
.header_size_
) {
279 header_size_
= other
.header_size_
;
281 Resize(other
.header_
->payload_size
);
282 memcpy(header_
, other
.header_
,
283 other
.header_size_
+ other
.header_
->payload_size
);
284 write_offset_
= other
.write_offset_
;
288 bool Pickle::WriteString(const StringPiece
& value
) {
289 if (!WriteInt(static_cast<int>(value
.size())))
292 return WriteBytes(value
.data(), static_cast<int>(value
.size()));
295 bool Pickle::WriteString16(const StringPiece16
& value
) {
296 if (!WriteInt(static_cast<int>(value
.size())))
299 return WriteBytes(value
.data(),
300 static_cast<int>(value
.size()) * sizeof(char16
));
303 bool Pickle::WriteData(const char* data
, int length
) {
304 return length
>= 0 && WriteInt(length
) && WriteBytes(data
, length
);
307 bool Pickle::WriteBytes(const void* data
, int length
) {
308 WriteBytesCommon(data
, length
);
312 void Pickle::Reserve(size_t length
) {
313 size_t data_len
= bits::Align(length
, sizeof(uint32
));
314 DCHECK_GE(data_len
, length
);
315 #ifdef ARCH_CPU_64_BITS
316 DCHECK_LE(data_len
, kuint32max
);
318 DCHECK_LE(write_offset_
, kuint32max
- data_len
);
319 size_t new_size
= write_offset_
+ data_len
;
320 if (new_size
> capacity_after_header_
)
321 Resize(capacity_after_header_
* 2 + new_size
);
324 void Pickle::Resize(size_t new_capacity
) {
325 CHECK_NE(capacity_after_header_
, kCapacityReadOnly
);
326 capacity_after_header_
= bits::Align(new_capacity
, kPayloadUnit
);
327 void* p
= realloc(header_
, GetTotalAllocatedSize());
329 header_
= reinterpret_cast<Header
*>(p
);
332 size_t Pickle::GetTotalAllocatedSize() const {
333 if (capacity_after_header_
== kCapacityReadOnly
)
335 return header_size_
+ capacity_after_header_
;
339 const char* Pickle::FindNext(size_t header_size
,
342 DCHECK_EQ(header_size
, bits::Align(header_size
, sizeof(uint32
)));
343 DCHECK_LE(header_size
, static_cast<size_t>(kPayloadUnit
));
345 size_t length
= static_cast<size_t>(end
- start
);
346 if (length
< sizeof(Header
))
349 const Header
* hdr
= reinterpret_cast<const Header
*>(start
);
350 if (length
< header_size
|| length
- header_size
< hdr
->payload_size
)
352 return start
+ header_size
+ hdr
->payload_size
;
355 template <size_t length
> void Pickle::WriteBytesStatic(const void* data
) {
356 WriteBytesCommon(data
, length
);
359 template void Pickle::WriteBytesStatic
<2>(const void* data
);
360 template void Pickle::WriteBytesStatic
<4>(const void* data
);
361 template void Pickle::WriteBytesStatic
<8>(const void* data
);
363 inline void Pickle::WriteBytesCommon(const void* data
, size_t length
) {
364 DCHECK_NE(kCapacityReadOnly
, capacity_after_header_
)
365 << "oops: pickle is readonly";
366 MSAN_CHECK_MEM_IS_INITIALIZED(data
, length
);
367 size_t data_len
= bits::Align(length
, sizeof(uint32
));
368 DCHECK_GE(data_len
, length
);
369 #ifdef ARCH_CPU_64_BITS
370 DCHECK_LE(data_len
, kuint32max
);
372 DCHECK_LE(write_offset_
, kuint32max
- data_len
);
373 size_t new_size
= write_offset_
+ data_len
;
374 if (new_size
> capacity_after_header_
) {
375 size_t new_capacity
= capacity_after_header_
* 2;
376 const size_t kPickleHeapAlign
= 4096;
377 if (new_capacity
> kPickleHeapAlign
)
378 new_capacity
= bits::Align(new_capacity
, kPickleHeapAlign
) - kPayloadUnit
;
379 Resize(std::max(new_capacity
, new_size
));
382 char* write
= mutable_payload() + write_offset_
;
383 memcpy(write
, data
, length
);
384 memset(write
+ length
, 0, data_len
- length
);
385 header_
->payload_size
= static_cast<uint32
>(new_size
);
386 write_offset_
= new_size
;