[go: nahoru, domu]

blob: e66c5baca11bb382cea40489f7335f44b27254fd [file] [log] [blame]
jbates@chromium.orgce208f872012-03-07 20:42:561// Copyright (c) 2012 The Chromium Authors. All rights reserved.
license.botbf09a502008-08-24 00:55:552// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
initial.commitd7cae122008-07-26 21:49:384
initial.commitd7cae122008-07-26 21:49:385#include "base/pickle.h"
maruel@google.comc9046af2008-08-06 20:35:176
7#include <stdlib.h>
8
thestig@chromium.orgb7a5d992009-10-28 04:21:019#include <algorithm> // for max()
initial.commitd7cae122008-07-26 21:49:3810
11//------------------------------------------------------------------------------
12
brettw@chromium.org476dafb2013-12-03 00:39:2613using base::char16;
14using base::string16;
15
initial.commitd7cae122008-07-26 21:49:3816// static
17const int Pickle::kPayloadUnit = 64;
18
thestig@chromium.org9193d2f2011-10-10 22:20:3319static const size_t kCapacityReadOnly = static_cast<size_t>(-1);
jbates@chromium.orgce208f872012-03-07 20:42:5620
21PickleIterator::PickleIterator(const Pickle& pickle)
halyavin@google.coma15016f2014-06-02 23:23:4922 : payload_(pickle.payload()),
23 read_index_(0),
24 end_index_(pickle.payload_size()) {
jbates@chromium.orgce208f872012-03-07 20:42:5625}
26
27template <typename Type>
28inline bool PickleIterator::ReadBuiltinType(Type* result) {
29 const char* read_from = GetReadPointerAndAdvance<Type>();
30 if (!read_from)
31 return false;
32 if (sizeof(Type) > sizeof(uint32))
33 memcpy(result, read_from, sizeof(*result));
34 else
35 *result = *reinterpret_cast<const Type*>(read_from);
36 return true;
37}
38
halyavin@google.coma15016f2014-06-02 23:23:4939inline void PickleIterator::Advance(size_t size) {
40 size_t aligned_size = AlignInt(size, sizeof(uint32_t));
41 if (end_index_ - read_index_ < aligned_size) {
42 read_index_ = end_index_;
43 } else {
44 read_index_ += aligned_size;
45 }
46}
47
jbates@chromium.orgce208f872012-03-07 20:42:5648template<typename Type>
49inline const char* PickleIterator::GetReadPointerAndAdvance() {
halyavin@google.coma15016f2014-06-02 23:23:4950 if (sizeof(Type) > end_index_ - read_index_) {
51 read_index_ = end_index_;
jbates@chromium.orgce208f872012-03-07 20:42:5652 return NULL;
halyavin@google.coma15016f2014-06-02 23:23:4953 }
54 const char* current_read_ptr = payload_ + read_index_;
55 Advance(sizeof(Type));
jbates@chromium.orgce208f872012-03-07 20:42:5656 return current_read_ptr;
57}
58
59const char* PickleIterator::GetReadPointerAndAdvance(int num_bytes) {
halyavin@google.coma15016f2014-06-02 23:23:4960 if (num_bytes < 0 ||
61 end_index_ - read_index_ < static_cast<size_t>(num_bytes)) {
62 read_index_ = end_index_;
glider@chromium.org2d936052012-03-13 17:17:5663 return NULL;
halyavin@google.coma15016f2014-06-02 23:23:4964 }
65 const char* current_read_ptr = payload_ + read_index_;
66 Advance(num_bytes);
jbates@chromium.orgce208f872012-03-07 20:42:5667 return current_read_ptr;
68}
69
halyavin@google.coma15016f2014-06-02 23:23:4970inline const char* PickleIterator::GetReadPointerAndAdvance(
71 int num_elements,
72 size_t size_element) {
jbates@chromium.orgce208f872012-03-07 20:42:5673 // 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))
77 return NULL;
78 return GetReadPointerAndAdvance(num_bytes32);
79}
80
81bool PickleIterator::ReadBool(bool* result) {
82 return ReadBuiltinType(result);
83}
84
85bool PickleIterator::ReadInt(int* result) {
86 return ReadBuiltinType(result);
87}
88
89bool PickleIterator::ReadLong(long* result) {
90 return ReadBuiltinType(result);
91}
92
jbates@chromium.orgce208f872012-03-07 20:42:5693bool PickleIterator::ReadUInt16(uint16* result) {
94 return ReadBuiltinType(result);
95}
96
97bool PickleIterator::ReadUInt32(uint32* result) {
98 return ReadBuiltinType(result);
99}
100
101bool PickleIterator::ReadInt64(int64* result) {
102 return ReadBuiltinType(result);
103}
104
105bool PickleIterator::ReadUInt64(uint64* result) {
106 return ReadBuiltinType(result);
107}
108
pkasting89a19f12014-10-02 03:01:04109bool 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);
117}
118
rbyers@chromium.orgb1f61b032012-11-28 15:40:58119bool PickleIterator::ReadFloat(float* result) {
piman@chromium.org522fbea2013-11-18 00:50:25120 // crbug.com/315213
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
123 // into the result.
124 const char* read_from = GetReadPointerAndAdvance<float>();
125 if (!read_from)
126 return false;
127 memcpy(result, read_from, sizeof(*result));
128 return true;
rbyers@chromium.orgb1f61b032012-11-28 15:40:58129}
130
mostynb@opera.com915cc7d2014-07-14 22:50:32131bool PickleIterator::ReadDouble(double* result) {
132 // crbug.com/315213
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
135 // into the result.
136 const char* read_from = GetReadPointerAndAdvance<double>();
137 if (!read_from)
138 return false;
139 memcpy(result, read_from, sizeof(*result));
140 return true;
141}
142
jbates@chromium.orgce208f872012-03-07 20:42:56143bool PickleIterator::ReadString(std::string* result) {
144 int len;
145 if (!ReadInt(&len))
146 return false;
147 const char* read_from = GetReadPointerAndAdvance(len);
148 if (!read_from)
149 return false;
150
151 result->assign(read_from, len);
152 return true;
153}
154
brucedawsoneaa38962015-03-10 01:46:50155bool PickleIterator::ReadStringPiece(base::StringPiece* result) {
156 int len;
157 if (!ReadInt(&len))
158 return false;
159 const char* read_from = GetReadPointerAndAdvance(len);
160 if (!read_from)
161 return false;
162
163 *result = base::StringPiece(read_from, len);
164 return true;
165}
166
jbates@chromium.orgce208f872012-03-07 20:42:56167bool PickleIterator::ReadWString(std::wstring* result) {
168 int len;
169 if (!ReadInt(&len))
170 return false;
171 const char* read_from = GetReadPointerAndAdvance(len, sizeof(wchar_t));
172 if (!read_from)
173 return false;
174
175 result->assign(reinterpret_cast<const wchar_t*>(read_from), len);
176 return true;
177}
178
179bool PickleIterator::ReadString16(string16* result) {
180 int len;
181 if (!ReadInt(&len))
182 return false;
183 const char* read_from = GetReadPointerAndAdvance(len, sizeof(char16));
184 if (!read_from)
185 return false;
186
187 result->assign(reinterpret_cast<const char16*>(read_from), len);
brucedawsoneaa38962015-03-10 01:46:50188 return true;
189}
190
191bool PickleIterator::ReadStringPiece16(base::StringPiece16* result) {
192 int len;
193 if (!ReadInt(&len))
194 return false;
195 const char* read_from = GetReadPointerAndAdvance(len, sizeof(char16));
196 if (!read_from)
197 return false;
198
199 *result = base::StringPiece16(reinterpret_cast<const char16*>(read_from),
200 len);
jbates@chromium.orgce208f872012-03-07 20:42:56201 return true;
202}
203
204bool PickleIterator::ReadData(const char** data, int* length) {
205 *length = 0;
206 *data = 0;
207
208 if (!ReadInt(length))
209 return false;
210
211 return ReadBytes(data, *length);
212}
213
214bool PickleIterator::ReadBytes(const char** data, int length) {
215 const char* read_from = GetReadPointerAndAdvance(length);
216 if (!read_from)
217 return false;
218 *data = read_from;
219 return true;
220}
deanm@google.com836061b2008-08-13 14:57:51221
initial.commitd7cae122008-07-26 21:49:38222// Payload is uint32 aligned.
223
224Pickle::Pickle()
225 : header_(NULL),
226 header_size_(sizeof(Header)),
piman@chromium.orgd1b319fc2013-10-31 04:03:02227 capacity_after_header_(0),
228 write_offset_(0) {
initial.commitd7cae122008-07-26 21:49:38229 Resize(kPayloadUnit);
230 header_->payload_size = 0;
231}
232
233Pickle::Pickle(int header_size)
234 : header_(NULL),
235 header_size_(AlignInt(header_size, sizeof(uint32))),
piman@chromium.orgd1b319fc2013-10-31 04:03:02236 capacity_after_header_(0),
237 write_offset_(0) {
pkasting@chromium.org8e03fec2011-03-31 20:34:25238 DCHECK_GE(static_cast<size_t>(header_size), sizeof(Header));
kushi.p@gmail.comd7a93ad2011-04-22 13:13:07239 DCHECK_LE(header_size, kPayloadUnit);
initial.commitd7cae122008-07-26 21:49:38240 Resize(kPayloadUnit);
241 header_->payload_size = 0;
242}
243
bbudge@chromium.org753bb252013-11-04 22:28:12244Pickle::Pickle(const char* data, int data_len)
initial.commitd7cae122008-07-26 21:49:38245 : header_(reinterpret_cast<Header*>(const_cast<char*>(data))),
rvargas@google.comd87f8e62010-11-15 19:31:23246 header_size_(0),
piman@chromium.orgd1b319fc2013-10-31 04:03:02247 capacity_after_header_(kCapacityReadOnly),
248 write_offset_(0) {
bbudge@chromium.org753bb252013-11-04 22:28:12249 if (data_len >= static_cast<int>(sizeof(Header)))
rvargas@google.comd87f8e62010-11-15 19:31:23250 header_size_ = data_len - header_->payload_size;
251
bbudge@chromium.org753bb252013-11-04 22:28:12252 if (header_size_ > static_cast<unsigned int>(data_len))
rvargas@google.comd87f8e62010-11-15 19:31:23253 header_size_ = 0;
254
255 if (header_size_ != AlignInt(header_size_, sizeof(uint32)))
256 header_size_ = 0;
257
258 // If there is anything wrong with the data, we're not going to use it.
259 if (!header_size_)
260 header_ = NULL;
initial.commitd7cae122008-07-26 21:49:38261}
262
263Pickle::Pickle(const Pickle& other)
264 : header_(NULL),
265 header_size_(other.header_size_),
piman@chromium.orgd1b319fc2013-10-31 04:03:02266 capacity_after_header_(0),
267 write_offset_(other.write_offset_) {
initial.commitd7cae122008-07-26 21:49:38268 size_t payload_size = header_size_ + other.header_->payload_size;
piman@chromium.orgd1b319fc2013-10-31 04:03:02269 Resize(payload_size);
initial.commitd7cae122008-07-26 21:49:38270 memcpy(header_, other.header_, payload_size);
271}
272
273Pickle::~Pickle() {
piman@chromium.orgd1b319fc2013-10-31 04:03:02274 if (capacity_after_header_ != kCapacityReadOnly)
initial.commitd7cae122008-07-26 21:49:38275 free(header_);
276}
277
278Pickle& Pickle::operator=(const Pickle& other) {
jar@chromium.orgb944f612009-08-07 23:13:35279 if (this == &other) {
280 NOTREACHED();
281 return *this;
282 }
piman@chromium.orgd1b319fc2013-10-31 04:03:02283 if (capacity_after_header_ == kCapacityReadOnly) {
jar@chromium.orgfb6ec9992009-08-03 07:01:47284 header_ = NULL;
piman@chromium.orgd1b319fc2013-10-31 04:03:02285 capacity_after_header_ = 0;
jar@chromium.orgfb6ec9992009-08-03 07:01:47286 }
287 if (header_size_ != other.header_size_) {
initial.commitd7cae122008-07-26 21:49:38288 free(header_);
289 header_ = NULL;
290 header_size_ = other.header_size_;
291 }
piman@chromium.orgd1b319fc2013-10-31 04:03:02292 Resize(other.header_->payload_size);
jar@chromium.orgb944f612009-08-07 23:13:35293 memcpy(header_, other.header_,
294 other.header_size_ + other.header_->payload_size);
piman@chromium.orgd1b319fc2013-10-31 04:03:02295 write_offset_ = other.write_offset_;
initial.commitd7cae122008-07-26 21:49:38296 return *this;
initial.commitd7cae122008-07-26 21:49:38297}
298
brucedawsoneaa38962015-03-10 01:46:50299bool Pickle::WriteString(const base::StringPiece& value) {
initial.commitd7cae122008-07-26 21:49:38300 if (!WriteInt(static_cast<int>(value.size())))
301 return false;
302
303 return WriteBytes(value.data(), static_cast<int>(value.size()));
304}
305
306bool Pickle::WriteWString(const std::wstring& value) {
307 if (!WriteInt(static_cast<int>(value.size())))
308 return false;
309
310 return WriteBytes(value.data(),
estade@chromium.org3a2a5d22009-03-04 03:36:36311 static_cast<int>(value.size() * sizeof(wchar_t)));
312}
313
brucedawsoneaa38962015-03-10 01:46:50314bool Pickle::WriteString16(const base::StringPiece16& value) {
estade@chromium.org3a2a5d22009-03-04 03:36:36315 if (!WriteInt(static_cast<int>(value.size())))
316 return false;
317
318 return WriteBytes(value.data(),
319 static_cast<int>(value.size()) * sizeof(char16));
initial.commitd7cae122008-07-26 21:49:38320}
321
322bool Pickle::WriteData(const char* data, int length) {
wtc@chromium.orge64ff5e2009-07-28 21:00:03323 return length >= 0 && WriteInt(length) && WriteBytes(data, length);
erg@google.com9989c9bb2011-01-07 20:23:43324}
325
piman@chromium.orgd1b319fc2013-10-31 04:03:02326bool Pickle::WriteBytes(const void* data, int length) {
327 WriteBytesCommon(data, length);
erg@google.com9989c9bb2011-01-07 20:23:43328 return true;
initial.commitd7cae122008-07-26 21:49:38329}
330
piman@chromium.orgd1b319fc2013-10-31 04:03:02331void Pickle::Reserve(size_t length) {
332 size_t data_len = AlignInt(length, sizeof(uint32));
333 DCHECK_GE(data_len, length);
erg@google.com9989c9bb2011-01-07 20:23:43334#ifdef ARCH_CPU_64_BITS
piman@chromium.orgd1b319fc2013-10-31 04:03:02335 DCHECK_LE(data_len, kuint32max);
erg@google.com9989c9bb2011-01-07 20:23:43336#endif
piman@chromium.orgd1b319fc2013-10-31 04:03:02337 DCHECK_LE(write_offset_, kuint32max - data_len);
338 size_t new_size = write_offset_ + data_len;
339 if (new_size > capacity_after_header_)
340 Resize(capacity_after_header_ * 2 + new_size);
erg@google.com9989c9bb2011-01-07 20:23:43341}
342
piman@chromium.orgd1b319fc2013-10-31 04:03:02343void Pickle::Resize(size_t new_capacity) {
initial.commitd7cae122008-07-26 21:49:38344 new_capacity = AlignInt(new_capacity, kPayloadUnit);
345
piman@chromium.orgd1b319fc2013-10-31 04:03:02346 CHECK_NE(capacity_after_header_, kCapacityReadOnly);
347 void* p = realloc(header_, header_size_ + new_capacity);
348 CHECK(p);
initial.commitd7cae122008-07-26 21:49:38349 header_ = reinterpret_cast<Header*>(p);
piman@chromium.orgd1b319fc2013-10-31 04:03:02350 capacity_after_header_ = new_capacity;
initial.commitd7cae122008-07-26 21:49:38351}
352
353// static
354const char* Pickle::FindNext(size_t header_size,
355 const char* start,
356 const char* end) {
kushi.p@gmail.comd7a93ad2011-04-22 13:13:07357 DCHECK_EQ(header_size, AlignInt(header_size, sizeof(uint32)));
358 DCHECK_LE(header_size, static_cast<size_t>(kPayloadUnit));
initial.commitd7cae122008-07-26 21:49:38359
halyavin@google.com33a38dd2013-11-01 09:06:26360 size_t length = static_cast<size_t>(end - start);
361 if (length < sizeof(Header))
glider@chromium.org137d2372011-01-26 13:02:27362 return NULL;
363
initial.commitd7cae122008-07-26 21:49:38364 const Header* hdr = reinterpret_cast<const Header*>(start);
halyavin@google.com33a38dd2013-11-01 09:06:26365 if (length < header_size || length - header_size < hdr->payload_size)
initial.commitd7cae122008-07-26 21:49:38366 return NULL;
halyavin@google.com33a38dd2013-11-01 09:06:26367 return start + header_size + hdr->payload_size;
initial.commitd7cae122008-07-26 21:49:38368}
piman@chromium.orgd1b319fc2013-10-31 04:03:02369
370template <size_t length> void Pickle::WriteBytesStatic(const void* data) {
371 WriteBytesCommon(data, length);
372}
373
374template void Pickle::WriteBytesStatic<2>(const void* data);
375template void Pickle::WriteBytesStatic<4>(const void* data);
376template void Pickle::WriteBytesStatic<8>(const void* data);
377
378inline void Pickle::WriteBytesCommon(const void* data, size_t length) {
379 DCHECK_NE(kCapacityReadOnly, capacity_after_header_)
380 << "oops: pickle is readonly";
381 size_t data_len = AlignInt(length, sizeof(uint32));
382 DCHECK_GE(data_len, length);
383#ifdef ARCH_CPU_64_BITS
384 DCHECK_LE(data_len, kuint32max);
385#endif
386 DCHECK_LE(write_offset_, kuint32max - data_len);
387 size_t new_size = write_offset_ + data_len;
388 if (new_size > capacity_after_header_) {
389 Resize(std::max(capacity_after_header_ * 2, new_size));
390 }
391
392 char* write = mutable_payload() + write_offset_;
393 memcpy(write, data, length);
394 memset(write + length, 0, data_len - length);
halyavin@google.coma15016f2014-06-02 23:23:49395 header_->payload_size = static_cast<uint32>(new_size);
piman@chromium.orgd1b319fc2013-10-31 04:03:02396 write_offset_ = new_size;
397}