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. 4 5#include "base/pickle.h" 6 7#include <stdlib.h> 8 9#include <algorithm> // for max() 10 11//------------------------------------------------------------------------------ 12 13using base::char16; 14using base::string16; 15 16// static 17const int Pickle::kPayloadUnit = 64; 18 19static const size_t kCapacityReadOnly = static_cast<size_t>(-1); 20 21PickleIterator::PickleIterator(const Pickle& pickle) 22 : read_ptr_(pickle.payload()), 23 read_end_ptr_(pickle.end_of_payload()) { 24} 25 26template <typename Type> 27inline bool PickleIterator::ReadBuiltinType(Type* result) { 28 const char* read_from = GetReadPointerAndAdvance<Type>(); 29 if (!read_from) 30 return false; 31 if (sizeof(Type) > sizeof(uint32)) 32 memcpy(result, read_from, sizeof(*result)); 33 else 34 *result = *reinterpret_cast<const Type*>(read_from); 35 return true; 36} 37 38template<typename Type> 39inline const char* PickleIterator::GetReadPointerAndAdvance() { 40 const char* current_read_ptr = read_ptr_; 41 if (read_ptr_ + sizeof(Type) > read_end_ptr_) 42 return NULL; 43 if (sizeof(Type) < sizeof(uint32)) 44 read_ptr_ += AlignInt(sizeof(Type), sizeof(uint32)); 45 else 46 read_ptr_ += sizeof(Type); 47 return current_read_ptr; 48} 49 50const char* PickleIterator::GetReadPointerAndAdvance(int num_bytes) { 51 if (num_bytes < 0 || read_end_ptr_ - read_ptr_ < num_bytes) 52 return NULL; 53 const char* current_read_ptr = read_ptr_; 54 read_ptr_ += AlignInt(num_bytes, sizeof(uint32)); 55 return current_read_ptr; 56} 57 58inline const char* PickleIterator::GetReadPointerAndAdvance(int num_elements, 59 size_t size_element) { 60 // Check for int32 overflow. 61 int64 num_bytes = static_cast<int64>(num_elements) * size_element; 62 int num_bytes32 = static_cast<int>(num_bytes); 63 if (num_bytes != static_cast<int64>(num_bytes32)) 64 return NULL; 65 return GetReadPointerAndAdvance(num_bytes32); 66} 67 68bool PickleIterator::ReadBool(bool* result) { 69 return ReadBuiltinType(result); 70} 71 72bool PickleIterator::ReadInt(int* result) { 73 return ReadBuiltinType(result); 74} 75 76bool PickleIterator::ReadLong(long* result) { 77 return ReadBuiltinType(result); 78} 79 80bool PickleIterator::ReadUInt16(uint16* result) { 81 return ReadBuiltinType(result); 82} 83 84bool PickleIterator::ReadUInt32(uint32* result) { 85 return ReadBuiltinType(result); 86} 87 88bool PickleIterator::ReadInt64(int64* result) { 89 return ReadBuiltinType(result); 90} 91 92bool PickleIterator::ReadUInt64(uint64* result) { 93 return ReadBuiltinType(result); 94} 95 96bool PickleIterator::ReadFloat(float* result) { 97 // crbug.com/315213 98 // The source data may not be properly aligned, and unaligned float reads 99 // cause SIGBUS on some ARM platforms, so force using memcpy to copy the data 100 // into the result. 101 const char* read_from = GetReadPointerAndAdvance<float>(); 102 if (!read_from) 103 return false; 104 memcpy(result, read_from, sizeof(*result)); 105 return true; 106} 107 108bool PickleIterator::ReadString(std::string* result) { 109 int len; 110 if (!ReadInt(&len)) 111 return false; 112 const char* read_from = GetReadPointerAndAdvance(len); 113 if (!read_from) 114 return false; 115 116 result->assign(read_from, len); 117 return true; 118} 119 120bool PickleIterator::ReadWString(std::wstring* result) { 121 int len; 122 if (!ReadInt(&len)) 123 return false; 124 const char* read_from = GetReadPointerAndAdvance(len, sizeof(wchar_t)); 125 if (!read_from) 126 return false; 127 128 result->assign(reinterpret_cast<const wchar_t*>(read_from), len); 129 return true; 130} 131 132bool PickleIterator::ReadString16(string16* result) { 133 int len; 134 if (!ReadInt(&len)) 135 return false; 136 const char* read_from = GetReadPointerAndAdvance(len, sizeof(char16)); 137 if (!read_from) 138 return false; 139 140 result->assign(reinterpret_cast<const char16*>(read_from), len); 141 return true; 142} 143 144bool PickleIterator::ReadData(const char** data, int* length) { 145 *length = 0; 146 *data = 0; 147 148 if (!ReadInt(length)) 149 return false; 150 151 return ReadBytes(data, *length); 152} 153 154bool PickleIterator::ReadBytes(const char** data, int length) { 155 const char* read_from = GetReadPointerAndAdvance(length); 156 if (!read_from) 157 return false; 158 *data = read_from; 159 return true; 160} 161 162// Payload is uint32 aligned. 163 164Pickle::Pickle() 165 : header_(NULL), 166 header_size_(sizeof(Header)), 167 capacity_after_header_(0), 168 write_offset_(0) { 169 Resize(kPayloadUnit); 170 header_->payload_size = 0; 171} 172 173Pickle::Pickle(int header_size) 174 : header_(NULL), 175 header_size_(AlignInt(header_size, sizeof(uint32))), 176 capacity_after_header_(0), 177 write_offset_(0) { 178 DCHECK_GE(static_cast<size_t>(header_size), sizeof(Header)); 179 DCHECK_LE(header_size, kPayloadUnit); 180 Resize(kPayloadUnit); 181 header_->payload_size = 0; 182} 183 184Pickle::Pickle(const char* data, int data_len) 185 : header_(reinterpret_cast<Header*>(const_cast<char*>(data))), 186 header_size_(0), 187 capacity_after_header_(kCapacityReadOnly), 188 write_offset_(0) { 189 if (data_len >= static_cast<int>(sizeof(Header))) 190 header_size_ = data_len - header_->payload_size; 191 192 if (header_size_ > static_cast<unsigned int>(data_len)) 193 header_size_ = 0; 194 195 if (header_size_ != AlignInt(header_size_, sizeof(uint32))) 196 header_size_ = 0; 197 198 // If there is anything wrong with the data, we're not going to use it. 199 if (!header_size_) 200 header_ = NULL; 201} 202 203Pickle::Pickle(const Pickle& other) 204 : header_(NULL), 205 header_size_(other.header_size_), 206 capacity_after_header_(0), 207 write_offset_(other.write_offset_) { 208 size_t payload_size = header_size_ + other.header_->payload_size; 209 Resize(payload_size); 210 memcpy(header_, other.header_, payload_size); 211} 212 213Pickle::~Pickle() { 214 if (capacity_after_header_ != kCapacityReadOnly) 215 free(header_); 216} 217 218Pickle& Pickle::operator=(const Pickle& other) { 219 if (this == &other) { 220 NOTREACHED(); 221 return *this; 222 } 223 if (capacity_after_header_ == kCapacityReadOnly) { 224 header_ = NULL; 225 capacity_after_header_ = 0; 226 } 227 if (header_size_ != other.header_size_) { 228 free(header_); 229 header_ = NULL; 230 header_size_ = other.header_size_; 231 } 232 Resize(other.header_->payload_size); 233 memcpy(header_, other.header_, 234 other.header_size_ + other.header_->payload_size); 235 write_offset_ = other.write_offset_; 236 return *this; 237} 238 239bool Pickle::WriteString(const std::string& value) { 240 if (!WriteInt(static_cast<int>(value.size()))) 241 return false; 242 243 return WriteBytes(value.data(), static_cast<int>(value.size())); 244} 245 246bool Pickle::WriteWString(const std::wstring& value) { 247 if (!WriteInt(static_cast<int>(value.size()))) 248 return false; 249 250 return WriteBytes(value.data(), 251 static_cast<int>(value.size() * sizeof(wchar_t))); 252} 253 254bool Pickle::WriteString16(const string16& value) { 255 if (!WriteInt(static_cast<int>(value.size()))) 256 return false; 257 258 return WriteBytes(value.data(), 259 static_cast<int>(value.size()) * sizeof(char16)); 260} 261 262bool Pickle::WriteData(const char* data, int length) { 263 return length >= 0 && WriteInt(length) && WriteBytes(data, length); 264} 265 266bool Pickle::WriteBytes(const void* data, int length) { 267 WriteBytesCommon(data, length); 268 return true; 269} 270 271void Pickle::Reserve(size_t length) { 272 size_t data_len = AlignInt(length, sizeof(uint32)); 273 DCHECK_GE(data_len, length); 274#ifdef ARCH_CPU_64_BITS 275 DCHECK_LE(data_len, kuint32max); 276#endif 277 DCHECK_LE(write_offset_, kuint32max - data_len); 278 size_t new_size = write_offset_ + data_len; 279 if (new_size > capacity_after_header_) 280 Resize(capacity_after_header_ * 2 + new_size); 281} 282 283void Pickle::Resize(size_t new_capacity) { 284 new_capacity = AlignInt(new_capacity, kPayloadUnit); 285 286 CHECK_NE(capacity_after_header_, kCapacityReadOnly); 287 void* p = realloc(header_, header_size_ + new_capacity); 288 CHECK(p); 289 header_ = reinterpret_cast<Header*>(p); 290 capacity_after_header_ = new_capacity; 291} 292 293// static 294const char* Pickle::FindNext(size_t header_size, 295 const char* start, 296 const char* end) { 297 DCHECK_EQ(header_size, AlignInt(header_size, sizeof(uint32))); 298 DCHECK_LE(header_size, static_cast<size_t>(kPayloadUnit)); 299 300 size_t length = static_cast<size_t>(end - start); 301 if (length < sizeof(Header)) 302 return NULL; 303 304 const Header* hdr = reinterpret_cast<const Header*>(start); 305 if (length < header_size || length - header_size < hdr->payload_size) 306 return NULL; 307 return start + header_size + hdr->payload_size; 308} 309 310template <size_t length> void Pickle::WriteBytesStatic(const void* data) { 311 WriteBytesCommon(data, length); 312} 313 314template void Pickle::WriteBytesStatic<2>(const void* data); 315template void Pickle::WriteBytesStatic<4>(const void* data); 316template void Pickle::WriteBytesStatic<8>(const void* data); 317 318inline void Pickle::WriteBytesCommon(const void* data, size_t length) { 319 DCHECK_NE(kCapacityReadOnly, capacity_after_header_) 320 << "oops: pickle is readonly"; 321 size_t data_len = AlignInt(length, sizeof(uint32)); 322 DCHECK_GE(data_len, length); 323#ifdef ARCH_CPU_64_BITS 324 DCHECK_LE(data_len, kuint32max); 325#endif 326 DCHECK_LE(write_offset_, kuint32max - data_len); 327 size_t new_size = write_offset_ + data_len; 328 if (new_size > capacity_after_header_) { 329 Resize(std::max(capacity_after_header_ * 2, new_size)); 330 } 331 332 char* write = mutable_payload() + write_offset_; 333 memcpy(write, data, length); 334 memset(write + length, 0, data_len - length); 335 header_->payload_size = static_cast<uint32>(write_offset_ + length); 336 write_offset_ = new_size; 337} 338