pickle.cc revision 3f50c38dc070f4bb515c1b64450dae14f316474e
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::ReadSize(void** iter, size_t* result) const { 144 DCHECK(iter); 145 if (!*iter) 146 *iter = const_cast<char*>(payload()); 147 148 if (!IteratorHasRoomFor(*iter, sizeof(*result))) 149 return false; 150 151 // TODO(jar): http://crbug.com/13108 Pickle should be cleaned up, and not 152 // dependent on alignment. 153 // Next line is otherwise the same as: memcpy(result, *iter, sizeof(*result)); 154 *result = *reinterpret_cast<size_t*>(*iter); 155 156 UpdateIter(iter, sizeof(*result)); 157 return true; 158} 159 160bool Pickle::ReadUInt32(void** iter, uint32* result) const { 161 DCHECK(iter); 162 if (!*iter) 163 *iter = const_cast<char*>(payload()); 164 165 if (!IteratorHasRoomFor(*iter, sizeof(*result))) 166 return false; 167 168 memcpy(result, *iter, sizeof(*result)); 169 170 UpdateIter(iter, sizeof(*result)); 171 return true; 172} 173 174bool Pickle::ReadInt64(void** iter, int64* result) const { 175 DCHECK(iter); 176 if (!*iter) 177 *iter = const_cast<char*>(payload()); 178 179 if (!IteratorHasRoomFor(*iter, sizeof(*result))) 180 return false; 181 182 memcpy(result, *iter, sizeof(*result)); 183 184 UpdateIter(iter, sizeof(*result)); 185 return true; 186} 187 188bool Pickle::ReadUInt64(void** iter, uint64* result) const { 189 DCHECK(iter); 190 if (!*iter) 191 *iter = const_cast<char*>(payload()); 192 193 if (!IteratorHasRoomFor(*iter, sizeof(*result))) 194 return false; 195 196 memcpy(result, *iter, sizeof(*result)); 197 198 UpdateIter(iter, sizeof(*result)); 199 return true; 200} 201 202bool Pickle::ReadString(void** iter, std::string* result) const { 203 DCHECK(iter); 204 205 int len; 206 if (!ReadLength(iter, &len)) 207 return false; 208 if (!IteratorHasRoomFor(*iter, len)) 209 return false; 210 211 char* chars = reinterpret_cast<char*>(*iter); 212 result->assign(chars, len); 213 214 UpdateIter(iter, len); 215 return true; 216} 217 218bool Pickle::ReadWString(void** iter, std::wstring* result) const { 219 DCHECK(iter); 220 221 int len; 222 if (!ReadLength(iter, &len)) 223 return false; 224 // Avoid integer overflow. 225 if (len > INT_MAX / static_cast<int>(sizeof(wchar_t))) 226 return false; 227 if (!IteratorHasRoomFor(*iter, len * sizeof(wchar_t))) 228 return false; 229 230 wchar_t* chars = reinterpret_cast<wchar_t*>(*iter); 231 result->assign(chars, len); 232 233 UpdateIter(iter, len * sizeof(wchar_t)); 234 return true; 235} 236 237bool Pickle::ReadString16(void** iter, string16* result) const { 238 DCHECK(iter); 239 240 int len; 241 if (!ReadLength(iter, &len)) 242 return false; 243 if (!IteratorHasRoomFor(*iter, len * sizeof(char16))) 244 return false; 245 246 char16* chars = reinterpret_cast<char16*>(*iter); 247 result->assign(chars, len); 248 249 UpdateIter(iter, len * sizeof(char16)); 250 return true; 251} 252 253bool Pickle::ReadData(void** iter, const char** data, int* length) const { 254 DCHECK(iter); 255 DCHECK(data); 256 DCHECK(length); 257 *length = 0; 258 *data = 0; 259 260 if (!ReadLength(iter, length)) 261 return false; 262 263 return ReadBytes(iter, data, *length); 264} 265 266bool Pickle::ReadBytes(void** iter, const char** data, int length) const { 267 DCHECK(iter); 268 DCHECK(data); 269 *data = 0; 270 if (!*iter) 271 *iter = const_cast<char*>(payload()); 272 273 if (!IteratorHasRoomFor(*iter, length)) 274 return false; 275 276 *data = reinterpret_cast<const char*>(*iter); 277 278 UpdateIter(iter, length); 279 return true; 280} 281 282bool Pickle::ReadLength(void** iter, int* result) const { 283 if (!ReadInt(iter, result)) 284 return false; 285 return ((*result) >= 0); 286} 287 288bool Pickle::WriteString(const std::string& value) { 289 if (!WriteInt(static_cast<int>(value.size()))) 290 return false; 291 292 return WriteBytes(value.data(), static_cast<int>(value.size())); 293} 294 295bool Pickle::WriteWString(const std::wstring& value) { 296 if (!WriteInt(static_cast<int>(value.size()))) 297 return false; 298 299 return WriteBytes(value.data(), 300 static_cast<int>(value.size() * sizeof(wchar_t))); 301} 302 303bool Pickle::WriteString16(const string16& value) { 304 if (!WriteInt(static_cast<int>(value.size()))) 305 return false; 306 307 return WriteBytes(value.data(), 308 static_cast<int>(value.size()) * sizeof(char16)); 309} 310 311bool Pickle::WriteData(const char* data, int length) { 312 return length >= 0 && WriteInt(length) && WriteBytes(data, length); 313} 314 315bool Pickle::WriteBytes(const void* data, int data_len) { 316 DCHECK(capacity_ != kCapacityReadOnly) << "oops: pickle is readonly"; 317 318 char* dest = BeginWrite(data_len); 319 if (!dest) 320 return false; 321 322 memcpy(dest, data, data_len); 323 324 EndWrite(dest, data_len); 325 return true; 326} 327 328char* Pickle::BeginWriteData(int length) { 329 DCHECK_EQ(variable_buffer_offset_, 0U) << 330 "There can only be one variable buffer in a Pickle"; 331 332 if (length < 0 || !WriteInt(length)) 333 return NULL; 334 335 char *data_ptr = BeginWrite(length); 336 if (!data_ptr) 337 return NULL; 338 339 variable_buffer_offset_ = 340 data_ptr - reinterpret_cast<char*>(header_) - sizeof(int); 341 342 // EndWrite doesn't necessarily have to be called after the write operation, 343 // so we call it here to pad out what the caller will eventually write. 344 EndWrite(data_ptr, length); 345 return data_ptr; 346} 347 348void Pickle::TrimWriteData(int new_length) { 349 DCHECK_NE(variable_buffer_offset_, 0U); 350 351 // Fetch the the variable buffer size 352 int* cur_length = reinterpret_cast<int*>( 353 reinterpret_cast<char*>(header_) + variable_buffer_offset_); 354 355 if (new_length < 0 || new_length > *cur_length) { 356 NOTREACHED() << "Invalid length in TrimWriteData."; 357 return; 358 } 359 360 // Update the payload size and variable buffer size 361 header_->payload_size -= (*cur_length - new_length); 362 *cur_length = new_length; 363} 364 365char* Pickle::BeginWrite(size_t length) { 366 // write at a uint32-aligned offset from the beginning of the header 367 size_t offset = AlignInt(header_->payload_size, sizeof(uint32)); 368 369 size_t new_size = offset + length; 370 size_t needed_size = header_size_ + new_size; 371 if (needed_size > capacity_ && !Resize(std::max(capacity_ * 2, needed_size))) 372 return NULL; 373 374#ifdef ARCH_CPU_64_BITS 375 DCHECK_LE(length, std::numeric_limits<uint32>::max()); 376#endif 377 378 header_->payload_size = static_cast<uint32>(new_size); 379 return payload() + offset; 380} 381 382void Pickle::EndWrite(char* dest, int length) { 383 // Zero-pad to keep tools like purify from complaining about uninitialized 384 // memory. 385 if (length % sizeof(uint32)) 386 memset(dest + length, 0, sizeof(uint32) - (length % sizeof(uint32))); 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