[go: nahoru, domu]

blob: 17fb83d1c2bc544cfd4d2ae4881bb316093ff72a [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
13// static
14const int Pickle::kPayloadUnit = 64;
15
thestig@chromium.org9193d2f2011-10-10 22:20:3316static const size_t kCapacityReadOnly = static_cast<size_t>(-1);
jbates@chromium.orgce208f872012-03-07 20:42:5617
18PickleIterator::PickleIterator(const Pickle& pickle)
19 : read_ptr_(pickle.payload()),
20 read_end_ptr_(pickle.end_of_payload()) {
21}
22
23template <typename Type>
24inline bool PickleIterator::ReadBuiltinType(Type* result) {
25 const char* read_from = GetReadPointerAndAdvance<Type>();
26 if (!read_from)
27 return false;
28 if (sizeof(Type) > sizeof(uint32))
29 memcpy(result, read_from, sizeof(*result));
30 else
31 *result = *reinterpret_cast<const Type*>(read_from);
32 return true;
33}
34
35template<typename Type>
36inline const char* PickleIterator::GetReadPointerAndAdvance() {
37 const char* current_read_ptr = read_ptr_;
38 if (read_ptr_ + sizeof(Type) > read_end_ptr_)
39 return NULL;
40 if (sizeof(Type) < sizeof(uint32))
41 read_ptr_ += AlignInt(sizeof(Type), sizeof(uint32));
42 else
43 read_ptr_ += sizeof(Type);
44 return current_read_ptr;
45}
46
47const char* PickleIterator::GetReadPointerAndAdvance(int num_bytes) {
glider@chromium.org2d936052012-03-13 17:17:5648 if (num_bytes < 0 || read_end_ptr_ - read_ptr_ < num_bytes)
49 return NULL;
jbates@chromium.orgce208f872012-03-07 20:42:5650 const char* current_read_ptr = read_ptr_;
jbates@chromium.orgce208f872012-03-07 20:42:5651 read_ptr_ += AlignInt(num_bytes, sizeof(uint32));
52 return current_read_ptr;
53}
54
55inline 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))
61 return NULL;
62 return GetReadPointerAndAdvance(num_bytes32);
63}
64
65bool PickleIterator::ReadBool(bool* result) {
66 return ReadBuiltinType(result);
67}
68
69bool PickleIterator::ReadInt(int* result) {
70 return ReadBuiltinType(result);
71}
72
73bool PickleIterator::ReadLong(long* result) {
74 return ReadBuiltinType(result);
75}
76
jbates@chromium.orgce208f872012-03-07 20:42:5677bool PickleIterator::ReadUInt16(uint16* result) {
78 return ReadBuiltinType(result);
79}
80
81bool PickleIterator::ReadUInt32(uint32* result) {
82 return ReadBuiltinType(result);
83}
84
85bool PickleIterator::ReadInt64(int64* result) {
86 return ReadBuiltinType(result);
87}
88
89bool PickleIterator::ReadUInt64(uint64* result) {
90 return ReadBuiltinType(result);
91}
92
rbyers@chromium.orgb1f61b032012-11-28 15:40:5893bool PickleIterator::ReadFloat(float* result) {
94 return ReadBuiltinType(result);
95}
96
jbates@chromium.orgce208f872012-03-07 20:42:5697bool PickleIterator::ReadString(std::string* result) {
98 int len;
99 if (!ReadInt(&len))
100 return false;
101 const char* read_from = GetReadPointerAndAdvance(len);
102 if (!read_from)
103 return false;
104
105 result->assign(read_from, len);
106 return true;
107}
108
109bool PickleIterator::ReadWString(std::wstring* result) {
110 int len;
111 if (!ReadInt(&len))
112 return false;
113 const char* read_from = GetReadPointerAndAdvance(len, sizeof(wchar_t));
114 if (!read_from)
115 return false;
116
117 result->assign(reinterpret_cast<const wchar_t*>(read_from), len);
118 return true;
119}
120
121bool PickleIterator::ReadString16(string16* result) {
122 int len;
123 if (!ReadInt(&len))
124 return false;
125 const char* read_from = GetReadPointerAndAdvance(len, sizeof(char16));
126 if (!read_from)
127 return false;
128
129 result->assign(reinterpret_cast<const char16*>(read_from), len);
130 return true;
131}
132
133bool PickleIterator::ReadData(const char** data, int* length) {
134 *length = 0;
135 *data = 0;
136
137 if (!ReadInt(length))
138 return false;
139
140 return ReadBytes(data, *length);
141}
142
143bool PickleIterator::ReadBytes(const char** data, int length) {
144 const char* read_from = GetReadPointerAndAdvance(length);
145 if (!read_from)
146 return false;
147 *data = read_from;
148 return true;
149}
deanm@google.com836061b2008-08-13 14:57:51150
initial.commitd7cae122008-07-26 21:49:38151// Payload is uint32 aligned.
152
153Pickle::Pickle()
154 : header_(NULL),
155 header_size_(sizeof(Header)),
piman@chromium.orgd1b319fc2013-10-31 04:03:02156 capacity_after_header_(0),
157 write_offset_(0) {
initial.commitd7cae122008-07-26 21:49:38158 Resize(kPayloadUnit);
159 header_->payload_size = 0;
160}
161
162Pickle::Pickle(int header_size)
163 : header_(NULL),
164 header_size_(AlignInt(header_size, sizeof(uint32))),
piman@chromium.orgd1b319fc2013-10-31 04:03:02165 capacity_after_header_(0),
166 write_offset_(0) {
pkasting@chromium.org8e03fec2011-03-31 20:34:25167 DCHECK_GE(static_cast<size_t>(header_size), sizeof(Header));
kushi.p@gmail.comd7a93ad2011-04-22 13:13:07168 DCHECK_LE(header_size, kPayloadUnit);
initial.commitd7cae122008-07-26 21:49:38169 Resize(kPayloadUnit);
170 header_->payload_size = 0;
171}
172
bbudge@chromium.org9ea0ecd2013-10-28 15:30:04173Pickle::Pickle(const char* data, size_t data_len)
initial.commitd7cae122008-07-26 21:49:38174 : header_(reinterpret_cast<Header*>(const_cast<char*>(data))),
rvargas@google.comd87f8e62010-11-15 19:31:23175 header_size_(0),
piman@chromium.orgd1b319fc2013-10-31 04:03:02176 capacity_after_header_(kCapacityReadOnly),
177 write_offset_(0) {
bbudge@chromium.org9ea0ecd2013-10-28 15:30:04178 if (data_len >= sizeof(Header))
rvargas@google.comd87f8e62010-11-15 19:31:23179 header_size_ = data_len - header_->payload_size;
180
bbudge@chromium.org9ea0ecd2013-10-28 15:30:04181 if (header_size_ > data_len)
rvargas@google.comd87f8e62010-11-15 19:31:23182 header_size_ = 0;
183
184 if (header_size_ != AlignInt(header_size_, sizeof(uint32)))
185 header_size_ = 0;
186
187 // If there is anything wrong with the data, we're not going to use it.
188 if (!header_size_)
189 header_ = NULL;
initial.commitd7cae122008-07-26 21:49:38190}
191
192Pickle::Pickle(const Pickle& other)
193 : header_(NULL),
194 header_size_(other.header_size_),
piman@chromium.orgd1b319fc2013-10-31 04:03:02195 capacity_after_header_(0),
196 write_offset_(other.write_offset_) {
initial.commitd7cae122008-07-26 21:49:38197 size_t payload_size = header_size_ + other.header_->payload_size;
piman@chromium.orgd1b319fc2013-10-31 04:03:02198 Resize(payload_size);
initial.commitd7cae122008-07-26 21:49:38199 memcpy(header_, other.header_, payload_size);
200}
201
202Pickle::~Pickle() {
piman@chromium.orgd1b319fc2013-10-31 04:03:02203 if (capacity_after_header_ != kCapacityReadOnly)
initial.commitd7cae122008-07-26 21:49:38204 free(header_);
205}
206
207Pickle& Pickle::operator=(const Pickle& other) {
jar@chromium.orgb944f612009-08-07 23:13:35208 if (this == &other) {
209 NOTREACHED();
210 return *this;
211 }
piman@chromium.orgd1b319fc2013-10-31 04:03:02212 if (capacity_after_header_ == kCapacityReadOnly) {
jar@chromium.orgfb6ec9992009-08-03 07:01:47213 header_ = NULL;
piman@chromium.orgd1b319fc2013-10-31 04:03:02214 capacity_after_header_ = 0;
jar@chromium.orgfb6ec9992009-08-03 07:01:47215 }
216 if (header_size_ != other.header_size_) {
initial.commitd7cae122008-07-26 21:49:38217 free(header_);
218 header_ = NULL;
219 header_size_ = other.header_size_;
220 }
piman@chromium.orgd1b319fc2013-10-31 04:03:02221 Resize(other.header_->payload_size);
jar@chromium.orgb944f612009-08-07 23:13:35222 memcpy(header_, other.header_,
223 other.header_size_ + other.header_->payload_size);
piman@chromium.orgd1b319fc2013-10-31 04:03:02224 write_offset_ = other.write_offset_;
initial.commitd7cae122008-07-26 21:49:38225 return *this;
initial.commitd7cae122008-07-26 21:49:38226}
227
228bool Pickle::WriteString(const std::string& value) {
229 if (!WriteInt(static_cast<int>(value.size())))
230 return false;
231
232 return WriteBytes(value.data(), static_cast<int>(value.size()));
233}
234
235bool Pickle::WriteWString(const std::wstring& value) {
236 if (!WriteInt(static_cast<int>(value.size())))
237 return false;
238
239 return WriteBytes(value.data(),
estade@chromium.org3a2a5d22009-03-04 03:36:36240 static_cast<int>(value.size() * sizeof(wchar_t)));
241}
242
243bool Pickle::WriteString16(const string16& value) {
244 if (!WriteInt(static_cast<int>(value.size())))
245 return false;
246
247 return WriteBytes(value.data(),
248 static_cast<int>(value.size()) * sizeof(char16));
initial.commitd7cae122008-07-26 21:49:38249}
250
251bool Pickle::WriteData(const char* data, int length) {
wtc@chromium.orge64ff5e2009-07-28 21:00:03252 return length >= 0 && WriteInt(length) && WriteBytes(data, length);
erg@google.com9989c9bb2011-01-07 20:23:43253}
254
piman@chromium.orgd1b319fc2013-10-31 04:03:02255bool Pickle::WriteBytes(const void* data, int length) {
256 WriteBytesCommon(data, length);
erg@google.com9989c9bb2011-01-07 20:23:43257 return true;
initial.commitd7cae122008-07-26 21:49:38258}
259
piman@chromium.orgd1b319fc2013-10-31 04:03:02260void Pickle::Reserve(size_t length) {
261 size_t data_len = AlignInt(length, sizeof(uint32));
262 DCHECK_GE(data_len, length);
erg@google.com9989c9bb2011-01-07 20:23:43263#ifdef ARCH_CPU_64_BITS
piman@chromium.orgd1b319fc2013-10-31 04:03:02264 DCHECK_LE(data_len, kuint32max);
erg@google.com9989c9bb2011-01-07 20:23:43265#endif
piman@chromium.orgd1b319fc2013-10-31 04:03:02266 DCHECK_LE(write_offset_, kuint32max - data_len);
267 size_t new_size = write_offset_ + data_len;
268 if (new_size > capacity_after_header_)
269 Resize(capacity_after_header_ * 2 + new_size);
erg@google.com9989c9bb2011-01-07 20:23:43270}
271
piman@chromium.orgd1b319fc2013-10-31 04:03:02272void Pickle::Resize(size_t new_capacity) {
initial.commitd7cae122008-07-26 21:49:38273 new_capacity = AlignInt(new_capacity, kPayloadUnit);
274
piman@chromium.orgd1b319fc2013-10-31 04:03:02275 CHECK_NE(capacity_after_header_, kCapacityReadOnly);
276 void* p = realloc(header_, header_size_ + new_capacity);
277 CHECK(p);
initial.commitd7cae122008-07-26 21:49:38278 header_ = reinterpret_cast<Header*>(p);
piman@chromium.orgd1b319fc2013-10-31 04:03:02279 capacity_after_header_ = new_capacity;
initial.commitd7cae122008-07-26 21:49:38280}
281
282// static
283const char* Pickle::FindNext(size_t header_size,
284 const char* start,
285 const char* end) {
kushi.p@gmail.comd7a93ad2011-04-22 13:13:07286 DCHECK_EQ(header_size, AlignInt(header_size, sizeof(uint32)));
287 DCHECK_LE(header_size, static_cast<size_t>(kPayloadUnit));
initial.commitd7cae122008-07-26 21:49:38288
halyavin@google.com33a38dd2013-11-01 09:06:26289 size_t length = static_cast<size_t>(end - start);
290 if (length < sizeof(Header))
glider@chromium.org137d2372011-01-26 13:02:27291 return NULL;
292
initial.commitd7cae122008-07-26 21:49:38293 const Header* hdr = reinterpret_cast<const Header*>(start);
halyavin@google.com33a38dd2013-11-01 09:06:26294 if (length < header_size || length - header_size < hdr->payload_size)
initial.commitd7cae122008-07-26 21:49:38295 return NULL;
halyavin@google.com33a38dd2013-11-01 09:06:26296 return start + header_size + hdr->payload_size;
initial.commitd7cae122008-07-26 21:49:38297}
piman@chromium.orgd1b319fc2013-10-31 04:03:02298
299template <size_t length> void Pickle::WriteBytesStatic(const void* data) {
300 WriteBytesCommon(data, length);
301}
302
303template void Pickle::WriteBytesStatic<2>(const void* data);
304template void Pickle::WriteBytesStatic<4>(const void* data);
305template void Pickle::WriteBytesStatic<8>(const void* data);
306
307inline void Pickle::WriteBytesCommon(const void* data, size_t length) {
308 DCHECK_NE(kCapacityReadOnly, capacity_after_header_)
309 << "oops: pickle is readonly";
310 size_t data_len = AlignInt(length, sizeof(uint32));
311 DCHECK_GE(data_len, length);
312#ifdef ARCH_CPU_64_BITS
313 DCHECK_LE(data_len, kuint32max);
314#endif
315 DCHECK_LE(write_offset_, kuint32max - data_len);
316 size_t new_size = write_offset_ + data_len;
317 if (new_size > capacity_after_header_) {
318 Resize(std::max(capacity_after_header_ * 2, new_size));
319 }
320
321 char* write = mutable_payload() + write_offset_;
322 memcpy(write, data, length);
323 memset(write + length, 0, data_len - length);
324 header_->payload_size = static_cast<uint32>(write_offset_ + length);
325 write_offset_ = new_size;
326}