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