Open HTML files in Chrome by default.
[chromium-blink-merge.git] / base / pickle.cc
blob796fbc38beeb34867eea8a34cd528f46608b98f9
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"
7 #include <stdlib.h>
9 #include <algorithm> // for max()
11 //------------------------------------------------------------------------------
13 // static
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>();
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;
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_)
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;
47 const char* PickleIterator::GetReadPointerAndAdvance(int num_bytes) {
48 if (num_bytes < 0 || read_end_ptr_ - read_ptr_ < num_bytes)
49 return NULL;
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))
61 return NULL;
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 // crbug.com/315213
95 // The source data may not be properly aligned, and unaligned float reads
96 // cause SIGBUS on some ARM platforms, so force using memcpy to copy the data
97 // into the result.
98 const char* read_from = GetReadPointerAndAdvance<float>();
99 if (!read_from)
100 return false;
101 memcpy(result, read_from, sizeof(*result));
102 return true;
105 bool PickleIterator::ReadString(std::string* result) {
106 int len;
107 if (!ReadInt(&len))
108 return false;
109 const char* read_from = GetReadPointerAndAdvance(len);
110 if (!read_from)
111 return false;
113 result->assign(read_from, len);
114 return true;
117 bool PickleIterator::ReadWString(std::wstring* result) {
118 int len;
119 if (!ReadInt(&len))
120 return false;
121 const char* read_from = GetReadPointerAndAdvance(len, sizeof(wchar_t));
122 if (!read_from)
123 return false;
125 result->assign(reinterpret_cast<const wchar_t*>(read_from), len);
126 return true;
129 bool PickleIterator::ReadString16(string16* result) {
130 int len;
131 if (!ReadInt(&len))
132 return false;
133 const char* read_from = GetReadPointerAndAdvance(len, sizeof(char16));
134 if (!read_from)
135 return false;
137 result->assign(reinterpret_cast<const char16*>(read_from), len);
138 return true;
141 bool PickleIterator::ReadData(const char** data, int* length) {
142 *length = 0;
143 *data = 0;
145 if (!ReadInt(length))
146 return false;
148 return ReadBytes(data, *length);
151 bool PickleIterator::ReadBytes(const char** data, int length) {
152 const char* read_from = GetReadPointerAndAdvance(length);
153 if (!read_from)
154 return false;
155 *data = read_from;
156 return true;
159 // Payload is uint32 aligned.
161 Pickle::Pickle()
162 : header_(NULL),
163 header_size_(sizeof(Header)),
164 capacity_after_header_(0),
165 write_offset_(0) {
166 Resize(kPayloadUnit);
167 header_->payload_size = 0;
170 Pickle::Pickle(int header_size)
171 : header_(NULL),
172 header_size_(AlignInt(header_size, sizeof(uint32))),
173 capacity_after_header_(0),
174 write_offset_(0) {
175 DCHECK_GE(static_cast<size_t>(header_size), sizeof(Header));
176 DCHECK_LE(header_size, kPayloadUnit);
177 Resize(kPayloadUnit);
178 header_->payload_size = 0;
181 Pickle::Pickle(const char* data, int data_len)
182 : header_(reinterpret_cast<Header*>(const_cast<char*>(data))),
183 header_size_(0),
184 capacity_after_header_(kCapacityReadOnly),
185 write_offset_(0) {
186 if (data_len >= static_cast<int>(sizeof(Header)))
187 header_size_ = data_len - header_->payload_size;
189 if (header_size_ > static_cast<unsigned int>(data_len))
190 header_size_ = 0;
192 if (header_size_ != AlignInt(header_size_, sizeof(uint32)))
193 header_size_ = 0;
195 // If there is anything wrong with the data, we're not going to use it.
196 if (!header_size_)
197 header_ = NULL;
200 Pickle::Pickle(const Pickle& other)
201 : header_(NULL),
202 header_size_(other.header_size_),
203 capacity_after_header_(0),
204 write_offset_(other.write_offset_) {
205 size_t payload_size = header_size_ + other.header_->payload_size;
206 Resize(payload_size);
207 memcpy(header_, other.header_, payload_size);
210 Pickle::~Pickle() {
211 if (capacity_after_header_ != kCapacityReadOnly)
212 free(header_);
215 Pickle& Pickle::operator=(const Pickle& other) {
216 if (this == &other) {
217 NOTREACHED();
218 return *this;
220 if (capacity_after_header_ == kCapacityReadOnly) {
221 header_ = NULL;
222 capacity_after_header_ = 0;
224 if (header_size_ != other.header_size_) {
225 free(header_);
226 header_ = NULL;
227 header_size_ = other.header_size_;
229 Resize(other.header_->payload_size);
230 memcpy(header_, other.header_,
231 other.header_size_ + other.header_->payload_size);
232 write_offset_ = other.write_offset_;
233 return *this;
236 bool Pickle::WriteString(const std::string& value) {
237 if (!WriteInt(static_cast<int>(value.size())))
238 return false;
240 return WriteBytes(value.data(), static_cast<int>(value.size()));
243 bool Pickle::WriteWString(const std::wstring& value) {
244 if (!WriteInt(static_cast<int>(value.size())))
245 return false;
247 return WriteBytes(value.data(),
248 static_cast<int>(value.size() * sizeof(wchar_t)));
251 bool Pickle::WriteString16(const string16& value) {
252 if (!WriteInt(static_cast<int>(value.size())))
253 return false;
255 return WriteBytes(value.data(),
256 static_cast<int>(value.size()) * sizeof(char16));
259 bool Pickle::WriteData(const char* data, int length) {
260 return length >= 0 && WriteInt(length) && WriteBytes(data, length);
263 bool Pickle::WriteBytes(const void* data, int length) {
264 WriteBytesCommon(data, length);
265 return true;
268 void Pickle::Reserve(size_t length) {
269 size_t data_len = AlignInt(length, sizeof(uint32));
270 DCHECK_GE(data_len, length);
271 #ifdef ARCH_CPU_64_BITS
272 DCHECK_LE(data_len, kuint32max);
273 #endif
274 DCHECK_LE(write_offset_, kuint32max - data_len);
275 size_t new_size = write_offset_ + data_len;
276 if (new_size > capacity_after_header_)
277 Resize(capacity_after_header_ * 2 + new_size);
280 void Pickle::Resize(size_t new_capacity) {
281 new_capacity = AlignInt(new_capacity, kPayloadUnit);
283 CHECK_NE(capacity_after_header_, kCapacityReadOnly);
284 void* p = realloc(header_, header_size_ + new_capacity);
285 CHECK(p);
286 header_ = reinterpret_cast<Header*>(p);
287 capacity_after_header_ = new_capacity;
290 // static
291 const char* Pickle::FindNext(size_t header_size,
292 const char* start,
293 const char* end) {
294 DCHECK_EQ(header_size, AlignInt(header_size, sizeof(uint32)));
295 DCHECK_LE(header_size, static_cast<size_t>(kPayloadUnit));
297 size_t length = static_cast<size_t>(end - start);
298 if (length < sizeof(Header))
299 return NULL;
301 const Header* hdr = reinterpret_cast<const Header*>(start);
302 if (length < header_size || length - header_size < hdr->payload_size)
303 return NULL;
304 return start + header_size + hdr->payload_size;
307 template <size_t length> void Pickle::WriteBytesStatic(const void* data) {
308 WriteBytesCommon(data, length);
311 template void Pickle::WriteBytesStatic<2>(const void* data);
312 template void Pickle::WriteBytesStatic<4>(const void* data);
313 template void Pickle::WriteBytesStatic<8>(const void* data);
315 inline void Pickle::WriteBytesCommon(const void* data, size_t length) {
316 DCHECK_NE(kCapacityReadOnly, capacity_after_header_)
317 << "oops: pickle is readonly";
318 size_t data_len = AlignInt(length, sizeof(uint32));
319 DCHECK_GE(data_len, length);
320 #ifdef ARCH_CPU_64_BITS
321 DCHECK_LE(data_len, kuint32max);
322 #endif
323 DCHECK_LE(write_offset_, kuint32max - data_len);
324 size_t new_size = write_offset_ + data_len;
325 if (new_size > capacity_after_header_) {
326 Resize(std::max(capacity_after_header_ * 2, new_size));
329 char* write = mutable_payload() + write_offset_;
330 memcpy(write, data, length);
331 memset(write + length, 0, data_len - length);
332 header_->payload_size = static_cast<uint32>(write_offset_ + length);
333 write_offset_ = new_size;