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 //------------------------------------------------------------------------------
14 const int Pickle::kPayloadUnit
= 64;
16 static const size_t kCapacityReadOnly
= static_cast<size_t>(-1);
18 PickleIterator::PickleIterator(const Pickle
& pickle
)
19 : read_ptr_(pickle
.payload()),
20 read_end_ptr_(pickle
.end_of_payload()) {
23 template <typename Type
>
24 inline bool PickleIterator::ReadBuiltinType(Type
* result
) {
25 const char* read_from
= GetReadPointerAndAdvance
<Type
>();
28 if (sizeof(Type
) > sizeof(uint32
))
29 memcpy(result
, read_from
, sizeof(*result
));
31 *result
= *reinterpret_cast<const Type
*>(read_from
);
35 template<typename Type
>
36 inline const char* PickleIterator::GetReadPointerAndAdvance() {
37 const char* current_read_ptr
= read_ptr_
;
38 if (read_ptr_
+ sizeof(Type
) > read_end_ptr_
)
40 if (sizeof(Type
) < sizeof(uint32
))
41 read_ptr_
+= AlignInt(sizeof(Type
), sizeof(uint32
));
43 read_ptr_
+= sizeof(Type
);
44 return current_read_ptr
;
47 const char* PickleIterator::GetReadPointerAndAdvance(int num_bytes
) {
48 if (num_bytes
< 0 || read_end_ptr_
- read_ptr_
< num_bytes
)
50 const char* current_read_ptr
= read_ptr_
;
51 read_ptr_
+= AlignInt(num_bytes
, sizeof(uint32
));
52 return current_read_ptr
;
55 inline const char* PickleIterator::GetReadPointerAndAdvance(int num_elements
,
56 size_t size_element
) {
57 // Check for int32 overflow.
58 int64 num_bytes
= static_cast<int64
>(num_elements
) * size_element
;
59 int num_bytes32
= static_cast<int>(num_bytes
);
60 if (num_bytes
!= static_cast<int64
>(num_bytes32
))
62 return GetReadPointerAndAdvance(num_bytes32
);
65 bool PickleIterator::ReadBool(bool* result
) {
66 return ReadBuiltinType(result
);
69 bool PickleIterator::ReadInt(int* result
) {
70 return ReadBuiltinType(result
);
73 bool PickleIterator::ReadLong(long* result
) {
74 return ReadBuiltinType(result
);
77 bool PickleIterator::ReadUInt16(uint16
* result
) {
78 return ReadBuiltinType(result
);
81 bool PickleIterator::ReadUInt32(uint32
* result
) {
82 return ReadBuiltinType(result
);
85 bool PickleIterator::ReadInt64(int64
* result
) {
86 return ReadBuiltinType(result
);
89 bool PickleIterator::ReadUInt64(uint64
* result
) {
90 return ReadBuiltinType(result
);
93 bool PickleIterator::ReadFloat(float* result
) {
94 return ReadBuiltinType(result
);
97 bool PickleIterator::ReadString(std::string
* result
) {
101 const char* read_from
= GetReadPointerAndAdvance(len
);
105 result
->assign(read_from
, len
);
109 bool PickleIterator::ReadWString(std::wstring
* result
) {
113 const char* read_from
= GetReadPointerAndAdvance(len
, sizeof(wchar_t));
117 result
->assign(reinterpret_cast<const wchar_t*>(read_from
), len
);
121 bool PickleIterator::ReadString16(string16
* result
) {
125 const char* read_from
= GetReadPointerAndAdvance(len
, sizeof(char16
));
129 result
->assign(reinterpret_cast<const char16
*>(read_from
), len
);
133 bool PickleIterator::ReadData(const char** data
, int* length
) {
137 if (!ReadInt(length
))
140 return ReadBytes(data
, *length
);
143 bool PickleIterator::ReadBytes(const char** data
, int length
) {
144 const char* read_from
= GetReadPointerAndAdvance(length
);
151 // Payload is uint32 aligned.
155 header_size_(sizeof(Header
)),
157 variable_buffer_offset_(0) {
158 Resize(kPayloadUnit
);
159 header_
->payload_size
= 0;
162 Pickle::Pickle(int header_size
)
164 header_size_(AlignInt(header_size
, sizeof(uint32
))),
166 variable_buffer_offset_(0) {
167 DCHECK_GE(static_cast<size_t>(header_size
), sizeof(Header
));
168 DCHECK_LE(header_size
, kPayloadUnit
);
169 Resize(kPayloadUnit
);
170 header_
->payload_size
= 0;
173 Pickle::Pickle(const char* data
, int data_len
)
174 : header_(reinterpret_cast<Header
*>(const_cast<char*>(data
))),
176 capacity_(kCapacityReadOnly
),
177 variable_buffer_offset_(0) {
178 if (data_len
>= static_cast<int>(sizeof(Header
)))
179 header_size_
= data_len
- header_
->payload_size
;
181 if (header_size_
> static_cast<unsigned int>(data_len
))
184 if (header_size_
!= AlignInt(header_size_
, sizeof(uint32
)))
187 // If there is anything wrong with the data, we're not going to use it.
192 Pickle::Pickle(const Pickle
& other
)
194 header_size_(other
.header_size_
),
196 variable_buffer_offset_(other
.variable_buffer_offset_
) {
197 size_t payload_size
= header_size_
+ other
.header_
->payload_size
;
198 bool resized
= Resize(payload_size
);
199 CHECK(resized
); // Realloc failed.
200 memcpy(header_
, other
.header_
, payload_size
);
204 if (capacity_
!= kCapacityReadOnly
)
208 Pickle
& Pickle::operator=(const Pickle
& other
) {
209 if (this == &other
) {
213 if (capacity_
== kCapacityReadOnly
) {
217 if (header_size_
!= other
.header_size_
) {
220 header_size_
= other
.header_size_
;
222 bool resized
= Resize(other
.header_size_
+ other
.header_
->payload_size
);
223 CHECK(resized
); // Realloc failed.
224 memcpy(header_
, other
.header_
,
225 other
.header_size_
+ other
.header_
->payload_size
);
226 variable_buffer_offset_
= other
.variable_buffer_offset_
;
230 bool Pickle::WriteString(const std::string
& value
) {
231 if (!WriteInt(static_cast<int>(value
.size())))
234 return WriteBytes(value
.data(), static_cast<int>(value
.size()));
237 bool Pickle::WriteWString(const std::wstring
& value
) {
238 if (!WriteInt(static_cast<int>(value
.size())))
241 return WriteBytes(value
.data(),
242 static_cast<int>(value
.size() * sizeof(wchar_t)));
245 bool Pickle::WriteString16(const string16
& value
) {
246 if (!WriteInt(static_cast<int>(value
.size())))
249 return WriteBytes(value
.data(),
250 static_cast<int>(value
.size()) * sizeof(char16
));
253 bool Pickle::WriteData(const char* data
, int length
) {
254 return length
>= 0 && WriteInt(length
) && WriteBytes(data
, length
);
257 bool Pickle::WriteBytes(const void* data
, int data_len
) {
258 DCHECK_NE(kCapacityReadOnly
, capacity_
) << "oops: pickle is readonly";
260 char* dest
= BeginWrite(data_len
);
264 memcpy(dest
, data
, data_len
);
266 EndWrite(dest
, data_len
);
270 char* Pickle::BeginWriteData(int length
) {
271 DCHECK_EQ(variable_buffer_offset_
, 0U) <<
272 "There can only be one variable buffer in a Pickle";
274 if (length
< 0 || !WriteInt(length
))
277 char *data_ptr
= BeginWrite(length
);
281 variable_buffer_offset_
=
282 data_ptr
- reinterpret_cast<char*>(header_
) - sizeof(int);
284 // EndWrite doesn't necessarily have to be called after the write operation,
285 // so we call it here to pad out what the caller will eventually write.
286 EndWrite(data_ptr
, length
);
290 void Pickle::TrimWriteData(int new_length
) {
291 DCHECK_NE(variable_buffer_offset_
, 0U);
293 // Fetch the the variable buffer size
294 int* cur_length
= reinterpret_cast<int*>(
295 reinterpret_cast<char*>(header_
) + variable_buffer_offset_
);
297 if (new_length
< 0 || new_length
> *cur_length
) {
298 NOTREACHED() << "Invalid length in TrimWriteData.";
302 // Update the payload size and variable buffer size
303 header_
->payload_size
-= (*cur_length
- new_length
);
304 *cur_length
= new_length
;
307 char* Pickle::BeginWrite(size_t length
) {
308 // write at a uint32-aligned offset from the beginning of the header
309 size_t offset
= AlignInt(header_
->payload_size
, sizeof(uint32
));
311 size_t new_size
= offset
+ length
;
312 size_t needed_size
= header_size_
+ new_size
;
313 if (needed_size
> capacity_
&& !Resize(std::max(capacity_
* 2, needed_size
)))
316 #ifdef ARCH_CPU_64_BITS
317 DCHECK_LE(length
, kuint32max
);
320 header_
->payload_size
= static_cast<uint32
>(new_size
);
321 return mutable_payload() + offset
;
324 void Pickle::EndWrite(char* dest
, int length
) {
325 // Zero-pad to keep tools like valgrind from complaining about uninitialized
327 if (length
% sizeof(uint32
))
328 memset(dest
+ length
, 0, sizeof(uint32
) - (length
% sizeof(uint32
)));
331 bool Pickle::Resize(size_t new_capacity
) {
332 new_capacity
= AlignInt(new_capacity
, kPayloadUnit
);
334 CHECK_NE(capacity_
, kCapacityReadOnly
);
335 void* p
= realloc(header_
, new_capacity
);
339 header_
= reinterpret_cast<Header
*>(p
);
340 capacity_
= new_capacity
;
345 const char* Pickle::FindNext(size_t header_size
,
348 DCHECK_EQ(header_size
, AlignInt(header_size
, sizeof(uint32
)));
349 DCHECK_LE(header_size
, static_cast<size_t>(kPayloadUnit
));
351 if (static_cast<size_t>(end
- start
) < sizeof(Header
))
354 const Header
* hdr
= reinterpret_cast<const Header
*>(start
);
355 const char* payload_base
= start
+ header_size
;
356 const char* payload_end
= payload_base
+ hdr
->payload_size
;
357 if (payload_end
< payload_base
)
360 return (payload_end
> end
) ? NULL
: payload_end
;