pickle.cc revision 116680a4aac90f2aa7413d9095a592090648e557
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 : payload_(pickle.payload()), 23 read_index_(0), 24 end_index_(pickle.payload_size()) { 25} 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 39inline 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 48template<typename Type> 49inline const char* PickleIterator::GetReadPointerAndAdvance() { 50 if (sizeof(Type) > end_index_ - read_index_) { 51 read_index_ = end_index_; 52 return NULL; 53 } 54 const char* current_read_ptr = payload_ + read_index_; 55 Advance(sizeof(Type)); 56 return current_read_ptr; 57} 58 59const char* PickleIterator::GetReadPointerAndAdvance(int num_bytes) { 60 if (num_bytes < 0 || 61 end_index_ - read_index_ < static_cast<size_t>(num_bytes)) { 62 read_index_ = end_index_; 63 return NULL; 64 } 65 const char* current_read_ptr = payload_ + read_index_; 66 Advance(num_bytes); 67 return current_read_ptr; 68} 69 70inline const char* PickleIterator::GetReadPointerAndAdvance( 71 int num_elements, 72 size_t size_element) { 73 // 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 93bool 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 109bool PickleIterator::ReadFloat(float* result) { 110 // crbug.com/315213 111 // The source data may not be properly aligned, and unaligned float reads 112 // cause SIGBUS on some ARM platforms, so force using memcpy to copy the data 113 // into the result. 114 const char* read_from = GetReadPointerAndAdvance<float>(); 115 if (!read_from) 116 return false; 117 memcpy(result, read_from, sizeof(*result)); 118 return true; 119} 120 121bool PickleIterator::ReadDouble(double* result) { 122 // crbug.com/315213 123 // The source data may not be properly aligned, and unaligned double reads 124 // cause SIGBUS on some ARM platforms, so force using memcpy to copy the data 125 // into the result. 126 const char* read_from = GetReadPointerAndAdvance<double>(); 127 if (!read_from) 128 return false; 129 memcpy(result, read_from, sizeof(*result)); 130 return true; 131} 132 133bool PickleIterator::ReadString(std::string* result) { 134 int len; 135 if (!ReadInt(&len)) 136 return false; 137 const char* read_from = GetReadPointerAndAdvance(len); 138 if (!read_from) 139 return false; 140 141 result->assign(read_from, len); 142 return true; 143} 144 145bool PickleIterator::ReadWString(std::wstring* result) { 146 int len; 147 if (!ReadInt(&len)) 148 return false; 149 const char* read_from = GetReadPointerAndAdvance(len, sizeof(wchar_t)); 150 if (!read_from) 151 return false; 152 153 result->assign(reinterpret_cast<const wchar_t*>(read_from), len); 154 return true; 155} 156 157bool PickleIterator::ReadString16(string16* result) { 158 int len; 159 if (!ReadInt(&len)) 160 return false; 161 const char* read_from = GetReadPointerAndAdvance(len, sizeof(char16)); 162 if (!read_from) 163 return false; 164 165 result->assign(reinterpret_cast<const char16*>(read_from), len); 166 return true; 167} 168 169bool PickleIterator::ReadData(const char** data, int* length) { 170 *length = 0; 171 *data = 0; 172 173 if (!ReadInt(length)) 174 return false; 175 176 return ReadBytes(data, *length); 177} 178 179bool PickleIterator::ReadBytes(const char** data, int length) { 180 const char* read_from = GetReadPointerAndAdvance(length); 181 if (!read_from) 182 return false; 183 *data = read_from; 184 return true; 185} 186 187// Payload is uint32 aligned. 188 189Pickle::Pickle() 190 : header_(NULL), 191 header_size_(sizeof(Header)), 192 capacity_after_header_(0), 193 write_offset_(0) { 194 Resize(kPayloadUnit); 195 header_->payload_size = 0; 196} 197 198Pickle::Pickle(int header_size) 199 : header_(NULL), 200 header_size_(AlignInt(header_size, sizeof(uint32))), 201 capacity_after_header_(0), 202 write_offset_(0) { 203 DCHECK_GE(static_cast<size_t>(header_size), sizeof(Header)); 204 DCHECK_LE(header_size, kPayloadUnit); 205 Resize(kPayloadUnit); 206 header_->payload_size = 0; 207} 208 209Pickle::Pickle(const char* data, int data_len) 210 : header_(reinterpret_cast<Header*>(const_cast<char*>(data))), 211 header_size_(0), 212 capacity_after_header_(kCapacityReadOnly), 213 write_offset_(0) { 214 if (data_len >= static_cast<int>(sizeof(Header))) 215 header_size_ = data_len - header_->payload_size; 216 217 if (header_size_ > static_cast<unsigned int>(data_len)) 218 header_size_ = 0; 219 220 if (header_size_ != AlignInt(header_size_, sizeof(uint32))) 221 header_size_ = 0; 222 223 // If there is anything wrong with the data, we're not going to use it. 224 if (!header_size_) 225 header_ = NULL; 226} 227 228Pickle::Pickle(const Pickle& other) 229 : header_(NULL), 230 header_size_(other.header_size_), 231 capacity_after_header_(0), 232 write_offset_(other.write_offset_) { 233 size_t payload_size = header_size_ + other.header_->payload_size; 234 Resize(payload_size); 235 memcpy(header_, other.header_, payload_size); 236} 237 238Pickle::~Pickle() { 239 if (capacity_after_header_ != kCapacityReadOnly) 240 free(header_); 241} 242 243Pickle& Pickle::operator=(const Pickle& other) { 244 if (this == &other) { 245 NOTREACHED(); 246 return *this; 247 } 248 if (capacity_after_header_ == kCapacityReadOnly) { 249 header_ = NULL; 250 capacity_after_header_ = 0; 251 } 252 if (header_size_ != other.header_size_) { 253 free(header_); 254 header_ = NULL; 255 header_size_ = other.header_size_; 256 } 257 Resize(other.header_->payload_size); 258 memcpy(header_, other.header_, 259 other.header_size_ + other.header_->payload_size); 260 write_offset_ = other.write_offset_; 261 return *this; 262} 263 264bool Pickle::WriteString(const std::string& value) { 265 if (!WriteInt(static_cast<int>(value.size()))) 266 return false; 267 268 return WriteBytes(value.data(), static_cast<int>(value.size())); 269} 270 271bool Pickle::WriteWString(const std::wstring& value) { 272 if (!WriteInt(static_cast<int>(value.size()))) 273 return false; 274 275 return WriteBytes(value.data(), 276 static_cast<int>(value.size() * sizeof(wchar_t))); 277} 278 279bool Pickle::WriteString16(const string16& value) { 280 if (!WriteInt(static_cast<int>(value.size()))) 281 return false; 282 283 return WriteBytes(value.data(), 284 static_cast<int>(value.size()) * sizeof(char16)); 285} 286 287bool Pickle::WriteData(const char* data, int length) { 288 return length >= 0 && WriteInt(length) && WriteBytes(data, length); 289} 290 291bool Pickle::WriteBytes(const void* data, int length) { 292 WriteBytesCommon(data, length); 293 return true; 294} 295 296void Pickle::Reserve(size_t length) { 297 size_t data_len = AlignInt(length, sizeof(uint32)); 298 DCHECK_GE(data_len, length); 299#ifdef ARCH_CPU_64_BITS 300 DCHECK_LE(data_len, kuint32max); 301#endif 302 DCHECK_LE(write_offset_, kuint32max - data_len); 303 size_t new_size = write_offset_ + data_len; 304 if (new_size > capacity_after_header_) 305 Resize(capacity_after_header_ * 2 + new_size); 306} 307 308void Pickle::Resize(size_t new_capacity) { 309 new_capacity = AlignInt(new_capacity, kPayloadUnit); 310 311 CHECK_NE(capacity_after_header_, kCapacityReadOnly); 312 void* p = realloc(header_, header_size_ + new_capacity); 313 CHECK(p); 314 header_ = reinterpret_cast<Header*>(p); 315 capacity_after_header_ = new_capacity; 316} 317 318// static 319const char* Pickle::FindNext(size_t header_size, 320 const char* start, 321 const char* end) { 322 DCHECK_EQ(header_size, AlignInt(header_size, sizeof(uint32))); 323 DCHECK_LE(header_size, static_cast<size_t>(kPayloadUnit)); 324 325 size_t length = static_cast<size_t>(end - start); 326 if (length < sizeof(Header)) 327 return NULL; 328 329 const Header* hdr = reinterpret_cast<const Header*>(start); 330 if (length < header_size || length - header_size < hdr->payload_size) 331 return NULL; 332 return start + header_size + hdr->payload_size; 333} 334 335template <size_t length> void Pickle::WriteBytesStatic(const void* data) { 336 WriteBytesCommon(data, length); 337} 338 339template void Pickle::WriteBytesStatic<2>(const void* data); 340template void Pickle::WriteBytesStatic<4>(const void* data); 341template void Pickle::WriteBytesStatic<8>(const void* data); 342 343inline void Pickle::WriteBytesCommon(const void* data, size_t length) { 344 DCHECK_NE(kCapacityReadOnly, capacity_after_header_) 345 << "oops: pickle is readonly"; 346 size_t data_len = AlignInt(length, sizeof(uint32)); 347 DCHECK_GE(data_len, length); 348#ifdef ARCH_CPU_64_BITS 349 DCHECK_LE(data_len, kuint32max); 350#endif 351 DCHECK_LE(write_offset_, kuint32max - data_len); 352 size_t new_size = write_offset_ + data_len; 353 if (new_size > capacity_after_header_) { 354 Resize(std::max(capacity_after_header_ * 2, new_size)); 355 } 356 357 char* write = mutable_payload() + write_offset_; 358 memcpy(write, data, length); 359 memset(write + length, 0, data_len - length); 360 header_->payload_size = static_cast<uint32>(new_size); 361 write_offset_ = new_size; 362} 363