pickle.cc revision 46d4c2bc3267f3f028f39e7e311b0f89aba2e4fd
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::ReadString(std::string* result) { 122 int len; 123 if (!ReadInt(&len)) 124 return false; 125 const char* read_from = GetReadPointerAndAdvance(len); 126 if (!read_from) 127 return false; 128 129 result->assign(read_from, len); 130 return true; 131} 132 133bool PickleIterator::ReadWString(std::wstring* result) { 134 int len; 135 if (!ReadInt(&len)) 136 return false; 137 const char* read_from = GetReadPointerAndAdvance(len, sizeof(wchar_t)); 138 if (!read_from) 139 return false; 140 141 result->assign(reinterpret_cast<const wchar_t*>(read_from), len); 142 return true; 143} 144 145bool PickleIterator::ReadString16(string16* result) { 146 int len; 147 if (!ReadInt(&len)) 148 return false; 149 const char* read_from = GetReadPointerAndAdvance(len, sizeof(char16)); 150 if (!read_from) 151 return false; 152 153 result->assign(reinterpret_cast<const char16*>(read_from), len); 154 return true; 155} 156 157bool PickleIterator::ReadData(const char** data, int* length) { 158 *length = 0; 159 *data = 0; 160 161 if (!ReadInt(length)) 162 return false; 163 164 return ReadBytes(data, *length); 165} 166 167bool PickleIterator::ReadBytes(const char** data, int length) { 168 const char* read_from = GetReadPointerAndAdvance(length); 169 if (!read_from) 170 return false; 171 *data = read_from; 172 return true; 173} 174 175// Payload is uint32 aligned. 176 177Pickle::Pickle() 178 : header_(NULL), 179 header_size_(sizeof(Header)), 180 capacity_after_header_(0), 181 write_offset_(0) { 182 Resize(kPayloadUnit); 183 header_->payload_size = 0; 184} 185 186Pickle::Pickle(int header_size) 187 : header_(NULL), 188 header_size_(AlignInt(header_size, sizeof(uint32))), 189 capacity_after_header_(0), 190 write_offset_(0) { 191 DCHECK_GE(static_cast<size_t>(header_size), sizeof(Header)); 192 DCHECK_LE(header_size, kPayloadUnit); 193 Resize(kPayloadUnit); 194 header_->payload_size = 0; 195} 196 197Pickle::Pickle(const char* data, int data_len) 198 : header_(reinterpret_cast<Header*>(const_cast<char*>(data))), 199 header_size_(0), 200 capacity_after_header_(kCapacityReadOnly), 201 write_offset_(0) { 202 if (data_len >= static_cast<int>(sizeof(Header))) 203 header_size_ = data_len - header_->payload_size; 204 205 if (header_size_ > static_cast<unsigned int>(data_len)) 206 header_size_ = 0; 207 208 if (header_size_ != AlignInt(header_size_, sizeof(uint32))) 209 header_size_ = 0; 210 211 // If there is anything wrong with the data, we're not going to use it. 212 if (!header_size_) 213 header_ = NULL; 214} 215 216Pickle::Pickle(const Pickle& other) 217 : header_(NULL), 218 header_size_(other.header_size_), 219 capacity_after_header_(0), 220 write_offset_(other.write_offset_) { 221 size_t payload_size = header_size_ + other.header_->payload_size; 222 Resize(payload_size); 223 memcpy(header_, other.header_, payload_size); 224} 225 226Pickle::~Pickle() { 227 if (capacity_after_header_ != kCapacityReadOnly) 228 free(header_); 229} 230 231Pickle& Pickle::operator=(const Pickle& other) { 232 if (this == &other) { 233 NOTREACHED(); 234 return *this; 235 } 236 if (capacity_after_header_ == kCapacityReadOnly) { 237 header_ = NULL; 238 capacity_after_header_ = 0; 239 } 240 if (header_size_ != other.header_size_) { 241 free(header_); 242 header_ = NULL; 243 header_size_ = other.header_size_; 244 } 245 Resize(other.header_->payload_size); 246 memcpy(header_, other.header_, 247 other.header_size_ + other.header_->payload_size); 248 write_offset_ = other.write_offset_; 249 return *this; 250} 251 252bool Pickle::WriteString(const std::string& value) { 253 if (!WriteInt(static_cast<int>(value.size()))) 254 return false; 255 256 return WriteBytes(value.data(), static_cast<int>(value.size())); 257} 258 259bool Pickle::WriteWString(const std::wstring& value) { 260 if (!WriteInt(static_cast<int>(value.size()))) 261 return false; 262 263 return WriteBytes(value.data(), 264 static_cast<int>(value.size() * sizeof(wchar_t))); 265} 266 267bool Pickle::WriteString16(const string16& value) { 268 if (!WriteInt(static_cast<int>(value.size()))) 269 return false; 270 271 return WriteBytes(value.data(), 272 static_cast<int>(value.size()) * sizeof(char16)); 273} 274 275bool Pickle::WriteData(const char* data, int length) { 276 return length >= 0 && WriteInt(length) && WriteBytes(data, length); 277} 278 279bool Pickle::WriteBytes(const void* data, int length) { 280 WriteBytesCommon(data, length); 281 return true; 282} 283 284void Pickle::Reserve(size_t length) { 285 size_t data_len = AlignInt(length, sizeof(uint32)); 286 DCHECK_GE(data_len, length); 287#ifdef ARCH_CPU_64_BITS 288 DCHECK_LE(data_len, kuint32max); 289#endif 290 DCHECK_LE(write_offset_, kuint32max - data_len); 291 size_t new_size = write_offset_ + data_len; 292 if (new_size > capacity_after_header_) 293 Resize(capacity_after_header_ * 2 + new_size); 294} 295 296void Pickle::Resize(size_t new_capacity) { 297 new_capacity = AlignInt(new_capacity, kPayloadUnit); 298 299 CHECK_NE(capacity_after_header_, kCapacityReadOnly); 300 void* p = realloc(header_, header_size_ + new_capacity); 301 CHECK(p); 302 header_ = reinterpret_cast<Header*>(p); 303 capacity_after_header_ = new_capacity; 304} 305 306// static 307const char* Pickle::FindNext(size_t header_size, 308 const char* start, 309 const char* end) { 310 DCHECK_EQ(header_size, AlignInt(header_size, sizeof(uint32))); 311 DCHECK_LE(header_size, static_cast<size_t>(kPayloadUnit)); 312 313 size_t length = static_cast<size_t>(end - start); 314 if (length < sizeof(Header)) 315 return NULL; 316 317 const Header* hdr = reinterpret_cast<const Header*>(start); 318 if (length < header_size || length - header_size < hdr->payload_size) 319 return NULL; 320 return start + header_size + hdr->payload_size; 321} 322 323template <size_t length> void Pickle::WriteBytesStatic(const void* data) { 324 WriteBytesCommon(data, length); 325} 326 327template void Pickle::WriteBytesStatic<2>(const void* data); 328template void Pickle::WriteBytesStatic<4>(const void* data); 329template void Pickle::WriteBytesStatic<8>(const void* data); 330 331inline void Pickle::WriteBytesCommon(const void* data, size_t length) { 332 DCHECK_NE(kCapacityReadOnly, capacity_after_header_) 333 << "oops: pickle is readonly"; 334 size_t data_len = AlignInt(length, sizeof(uint32)); 335 DCHECK_GE(data_len, length); 336#ifdef ARCH_CPU_64_BITS 337 DCHECK_LE(data_len, kuint32max); 338#endif 339 DCHECK_LE(write_offset_, kuint32max - data_len); 340 size_t new_size = write_offset_ + data_len; 341 if (new_size > capacity_after_header_) { 342 Resize(std::max(capacity_after_header_ * 2, new_size)); 343 } 344 345 char* write = mutable_payload() + write_offset_; 346 memcpy(write, data, length); 347 memset(write + length, 0, data_len - length); 348 header_->payload_size = static_cast<uint32>(new_size); 349 write_offset_ = new_size; 350} 351