pickle.cc revision 21d179b334e59e9a3bfcaed4c4430bef1bc5759d
1// Copyright (c) 2006-2008 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#include <limits> 11 12//------------------------------------------------------------------------------ 13 14// static 15const int Pickle::kPayloadUnit = 64; 16 17// We mark a read only pickle with a special capacity_. 18static const size_t kCapacityReadOnly = std::numeric_limits<size_t>::max(); 19 20// Payload is uint32 aligned. 21 22Pickle::Pickle() 23 : header_(NULL), 24 header_size_(sizeof(Header)), 25 capacity_(0), 26 variable_buffer_offset_(0) { 27 Resize(kPayloadUnit); 28 header_->payload_size = 0; 29} 30 31Pickle::Pickle(int header_size) 32 : header_(NULL), 33 header_size_(AlignInt(header_size, sizeof(uint32))), 34 capacity_(0), 35 variable_buffer_offset_(0) { 36 DCHECK(static_cast<size_t>(header_size) >= sizeof(Header)); 37 DCHECK(header_size <= kPayloadUnit); 38 Resize(kPayloadUnit); 39 header_->payload_size = 0; 40} 41 42Pickle::Pickle(const char* data, int data_len) 43 : header_(reinterpret_cast<Header*>(const_cast<char*>(data))), 44 header_size_(0), 45 capacity_(kCapacityReadOnly), 46 variable_buffer_offset_(0) { 47 if (data_len >= static_cast<int>(sizeof(Header))) 48 header_size_ = data_len - header_->payload_size; 49 50 if (header_size_ > static_cast<unsigned int>(data_len)) 51 header_size_ = 0; 52 53 if (header_size_ != AlignInt(header_size_, sizeof(uint32))) 54 header_size_ = 0; 55 56 // If there is anything wrong with the data, we're not going to use it. 57 if (!header_size_) 58 header_ = NULL; 59} 60 61Pickle::Pickle(const Pickle& other) 62 : header_(NULL), 63 header_size_(other.header_size_), 64 capacity_(0), 65 variable_buffer_offset_(other.variable_buffer_offset_) { 66 size_t payload_size = header_size_ + other.header_->payload_size; 67 bool resized = Resize(payload_size); 68 CHECK(resized); // Realloc failed. 69 memcpy(header_, other.header_, payload_size); 70} 71 72Pickle::~Pickle() { 73 if (capacity_ != kCapacityReadOnly) 74 free(header_); 75} 76 77Pickle& Pickle::operator=(const Pickle& other) { 78 if (this == &other) { 79 NOTREACHED(); 80 return *this; 81 } 82 if (capacity_ == kCapacityReadOnly) { 83 header_ = NULL; 84 capacity_ = 0; 85 } 86 if (header_size_ != other.header_size_) { 87 free(header_); 88 header_ = NULL; 89 header_size_ = other.header_size_; 90 } 91 bool resized = Resize(other.header_size_ + other.header_->payload_size); 92 CHECK(resized); // Realloc failed. 93 memcpy(header_, other.header_, 94 other.header_size_ + other.header_->payload_size); 95 variable_buffer_offset_ = other.variable_buffer_offset_; 96 return *this; 97} 98 99bool Pickle::ReadBool(void** iter, bool* result) const { 100 DCHECK(iter); 101 102 int tmp; 103 if (!ReadInt(iter, &tmp)) 104 return false; 105 DCHECK(0 == tmp || 1 == tmp); 106 *result = tmp ? true : false; 107 return true; 108} 109 110bool Pickle::ReadInt(void** iter, int* result) const { 111 DCHECK(iter); 112 if (!*iter) 113 *iter = const_cast<char*>(payload()); 114 115 if (!IteratorHasRoomFor(*iter, sizeof(*result))) 116 return false; 117 118 // TODO(jar): http://crbug.com/13108 Pickle should be cleaned up, and not 119 // dependent on alignment. 120 // Next line is otherwise the same as: memcpy(result, *iter, sizeof(*result)); 121 *result = *reinterpret_cast<int*>(*iter); 122 123 UpdateIter(iter, sizeof(*result)); 124 return true; 125} 126 127bool Pickle::ReadLong(void** iter, long* result) const { 128 DCHECK(iter); 129 if (!*iter) 130 *iter = const_cast<char*>(payload()); 131 132 if (!IteratorHasRoomFor(*iter, sizeof(*result))) 133 return false; 134 135 // TODO(jar): http://crbug.com/13108 Pickle should be cleaned up, and not 136 // dependent on alignment. 137 memcpy(result, *iter, sizeof(*result)); 138 139 UpdateIter(iter, sizeof(*result)); 140 return true; 141} 142 143bool Pickle::ReadLength(void** iter, int* result) const { 144 if (!ReadInt(iter, result)) 145 return false; 146 return ((*result) >= 0); 147} 148 149bool Pickle::ReadSize(void** iter, size_t* result) const { 150 DCHECK(iter); 151 if (!*iter) 152 *iter = const_cast<char*>(payload()); 153 154 if (!IteratorHasRoomFor(*iter, sizeof(*result))) 155 return false; 156 157 // TODO(jar): http://crbug.com/13108 Pickle should be cleaned up, and not 158 // dependent on alignment. 159 // Next line is otherwise the same as: memcpy(result, *iter, sizeof(*result)); 160 *result = *reinterpret_cast<size_t*>(*iter); 161 162 UpdateIter(iter, sizeof(*result)); 163 return true; 164} 165 166bool Pickle::ReadUInt32(void** iter, uint32* result) const { 167 DCHECK(iter); 168 if (!*iter) 169 *iter = const_cast<char*>(payload()); 170 171 if (!IteratorHasRoomFor(*iter, sizeof(*result))) 172 return false; 173 174 memcpy(result, *iter, sizeof(*result)); 175 176 UpdateIter(iter, sizeof(*result)); 177 return true; 178} 179 180bool Pickle::ReadInt64(void** iter, int64* result) const { 181 DCHECK(iter); 182 if (!*iter) 183 *iter = const_cast<char*>(payload()); 184 185 if (!IteratorHasRoomFor(*iter, sizeof(*result))) 186 return false; 187 188 memcpy(result, *iter, sizeof(*result)); 189 190 UpdateIter(iter, sizeof(*result)); 191 return true; 192} 193 194bool Pickle::ReadUInt64(void** iter, uint64* result) const { 195 DCHECK(iter); 196 if (!*iter) 197 *iter = const_cast<char*>(payload()); 198 199 if (!IteratorHasRoomFor(*iter, sizeof(*result))) 200 return false; 201 202 memcpy(result, *iter, sizeof(*result)); 203 204 UpdateIter(iter, sizeof(*result)); 205 return true; 206} 207 208bool Pickle::ReadString(void** iter, std::string* result) const { 209 DCHECK(iter); 210 211 int len; 212 if (!ReadLength(iter, &len)) 213 return false; 214 if (!IteratorHasRoomFor(*iter, len)) 215 return false; 216 217 char* chars = reinterpret_cast<char*>(*iter); 218 result->assign(chars, len); 219 220 UpdateIter(iter, len); 221 return true; 222} 223 224bool Pickle::ReadWString(void** iter, std::wstring* result) const { 225 DCHECK(iter); 226 227 int len; 228 if (!ReadLength(iter, &len)) 229 return false; 230 // Avoid integer overflow. 231 if (len > INT_MAX / static_cast<int>(sizeof(wchar_t))) 232 return false; 233 if (!IteratorHasRoomFor(*iter, len * sizeof(wchar_t))) 234 return false; 235 236 wchar_t* chars = reinterpret_cast<wchar_t*>(*iter); 237 result->assign(chars, len); 238 239 UpdateIter(iter, len * sizeof(wchar_t)); 240 return true; 241} 242 243bool Pickle::ReadString16(void** iter, string16* result) const { 244 DCHECK(iter); 245 246 int len; 247 if (!ReadLength(iter, &len)) 248 return false; 249 if (!IteratorHasRoomFor(*iter, len * sizeof(char16))) 250 return false; 251 252 char16* chars = reinterpret_cast<char16*>(*iter); 253 result->assign(chars, len); 254 255 UpdateIter(iter, len * sizeof(char16)); 256 return true; 257} 258 259bool Pickle::ReadBytes(void** iter, const char** data, int length) const { 260 DCHECK(iter); 261 DCHECK(data); 262 *data = 0; 263 if (!*iter) 264 *iter = const_cast<char*>(payload()); 265 266 if (!IteratorHasRoomFor(*iter, length)) 267 return false; 268 269 *data = reinterpret_cast<const char*>(*iter); 270 271 UpdateIter(iter, length); 272 return true; 273} 274 275bool Pickle::ReadData(void** iter, const char** data, int* length) const { 276 DCHECK(iter); 277 DCHECK(data); 278 DCHECK(length); 279 *length = 0; 280 *data = 0; 281 282 if (!ReadLength(iter, length)) 283 return false; 284 285 return ReadBytes(iter, data, *length); 286} 287 288char* Pickle::BeginWrite(size_t length) { 289 // write at a uint32-aligned offset from the beginning of the header 290 size_t offset = AlignInt(header_->payload_size, sizeof(uint32)); 291 292 size_t new_size = offset + length; 293 size_t needed_size = header_size_ + new_size; 294 if (needed_size > capacity_ && !Resize(std::max(capacity_ * 2, needed_size))) 295 return NULL; 296 297#ifdef ARCH_CPU_64_BITS 298 DCHECK_LE(length, std::numeric_limits<uint32>::max()); 299#endif 300 301 header_->payload_size = static_cast<uint32>(new_size); 302 return payload() + offset; 303} 304 305void Pickle::EndWrite(char* dest, int length) { 306 // Zero-pad to keep tools like purify from complaining about uninitialized 307 // memory. 308 if (length % sizeof(uint32)) 309 memset(dest + length, 0, sizeof(uint32) - (length % sizeof(uint32))); 310} 311 312bool Pickle::WriteBytes(const void* data, int data_len) { 313 DCHECK(capacity_ != kCapacityReadOnly) << "oops: pickle is readonly"; 314 315 char* dest = BeginWrite(data_len); 316 if (!dest) 317 return false; 318 319 memcpy(dest, data, data_len); 320 321 EndWrite(dest, data_len); 322 return true; 323} 324 325bool Pickle::WriteString(const std::string& value) { 326 if (!WriteInt(static_cast<int>(value.size()))) 327 return false; 328 329 return WriteBytes(value.data(), static_cast<int>(value.size())); 330} 331 332bool Pickle::WriteWString(const std::wstring& value) { 333 if (!WriteInt(static_cast<int>(value.size()))) 334 return false; 335 336 return WriteBytes(value.data(), 337 static_cast<int>(value.size() * sizeof(wchar_t))); 338} 339 340bool Pickle::WriteString16(const string16& value) { 341 if (!WriteInt(static_cast<int>(value.size()))) 342 return false; 343 344 return WriteBytes(value.data(), 345 static_cast<int>(value.size()) * sizeof(char16)); 346} 347 348bool Pickle::WriteData(const char* data, int length) { 349 return length >= 0 && WriteInt(length) && WriteBytes(data, length); 350} 351 352char* Pickle::BeginWriteData(int length) { 353 DCHECK_EQ(variable_buffer_offset_, 0U) << 354 "There can only be one variable buffer in a Pickle"; 355 356 if (length < 0 || !WriteInt(length)) 357 return NULL; 358 359 char *data_ptr = BeginWrite(length); 360 if (!data_ptr) 361 return NULL; 362 363 variable_buffer_offset_ = 364 data_ptr - reinterpret_cast<char*>(header_) - sizeof(int); 365 366 // EndWrite doesn't necessarily have to be called after the write operation, 367 // so we call it here to pad out what the caller will eventually write. 368 EndWrite(data_ptr, length); 369 return data_ptr; 370} 371 372void Pickle::TrimWriteData(int new_length) { 373 DCHECK_NE(variable_buffer_offset_, 0U); 374 375 // Fetch the the variable buffer size 376 int* cur_length = reinterpret_cast<int*>( 377 reinterpret_cast<char*>(header_) + variable_buffer_offset_); 378 379 if (new_length < 0 || new_length > *cur_length) { 380 NOTREACHED() << "Invalid length in TrimWriteData."; 381 return; 382 } 383 384 // Update the payload size and variable buffer size 385 header_->payload_size -= (*cur_length - new_length); 386 *cur_length = new_length; 387} 388 389bool Pickle::Resize(size_t new_capacity) { 390 new_capacity = AlignInt(new_capacity, kPayloadUnit); 391 392 CHECK_NE(capacity_, kCapacityReadOnly); 393 void* p = realloc(header_, new_capacity); 394 if (!p) 395 return false; 396 397 header_ = reinterpret_cast<Header*>(p); 398 capacity_ = new_capacity; 399 return true; 400} 401 402// static 403const char* Pickle::FindNext(size_t header_size, 404 const char* start, 405 const char* end) { 406 DCHECK(header_size == AlignInt(header_size, sizeof(uint32))); 407 DCHECK(header_size <= static_cast<size_t>(kPayloadUnit)); 408 409 const Header* hdr = reinterpret_cast<const Header*>(start); 410 const char* payload_base = start + header_size; 411 const char* payload_end = payload_base + hdr->payload_size; 412 if (payload_end < payload_base) 413 return NULL; 414 415 return (payload_end > end) ? NULL : payload_end; 416} 417