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 15 const int Pickle::kPayloadUnit = 64; 16 17 // We mark a read only pickle with a special capacity_. 18 static const size_t kCapacityReadOnly = std::numeric_limits<size_t>::max(); 19 20 // Payload is uint32 aligned. 21 22 Pickle::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 31 Pickle::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 42 Pickle::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 51 Pickle::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 62 Pickle::~Pickle() { 63 if (capacity_ != kCapacityReadOnly) 64 free(header_); 65 } 66 67 Pickle& 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 89 bool 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 100 bool 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 117 bool 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 133 bool Pickle::ReadLength(void** iter, int* result) const { 134 if (!ReadInt(iter, result)) 135 return false; 136 return ((*result) >= 0); 137 } 138 139 bool 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 156 bool 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 170 bool 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 184 bool 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 198 bool Pickle::ReadIntPtr(void** iter, intptr_t* result) const { 199 DCHECK(iter); 200 if (!*iter) 201 *iter = const_cast<char*>(payload()); 202 203 if (!IteratorHasRoomFor(*iter, sizeof(*result))) 204 return false; 205 206 memcpy(result, *iter, sizeof(*result)); 207 208 UpdateIter(iter, sizeof(*result)); 209 return true; 210 } 211 212 bool Pickle::ReadString(void** iter, std::string* result) const { 213 DCHECK(iter); 214 215 int len; 216 if (!ReadLength(iter, &len)) 217 return false; 218 if (!IteratorHasRoomFor(*iter, len)) 219 return false; 220 221 char* chars = reinterpret_cast<char*>(*iter); 222 result->assign(chars, len); 223 224 UpdateIter(iter, len); 225 return true; 226 } 227 228 bool Pickle::ReadWString(void** iter, std::wstring* result) const { 229 DCHECK(iter); 230 231 int len; 232 if (!ReadLength(iter, &len)) 233 return false; 234 // Avoid integer overflow. 235 if (len > INT_MAX / static_cast<int>(sizeof(wchar_t))) 236 return false; 237 if (!IteratorHasRoomFor(*iter, len * sizeof(wchar_t))) 238 return false; 239 240 wchar_t* chars = reinterpret_cast<wchar_t*>(*iter); 241 result->assign(chars, len); 242 243 UpdateIter(iter, len * sizeof(wchar_t)); 244 return true; 245 } 246 247 bool Pickle::ReadString16(void** iter, string16* result) const { 248 DCHECK(iter); 249 250 int len; 251 if (!ReadLength(iter, &len)) 252 return false; 253 if (!IteratorHasRoomFor(*iter, len * sizeof(char16))) 254 return false; 255 256 char16* chars = reinterpret_cast<char16*>(*iter); 257 result->assign(chars, len); 258 259 UpdateIter(iter, len * sizeof(char16)); 260 return true; 261 } 262 263 bool Pickle::ReadBytes(void** iter, const char** data, int length) const { 264 DCHECK(iter); 265 DCHECK(data); 266 *data = 0; 267 268 if (!IteratorHasRoomFor(*iter, length)) 269 return false; 270 271 *data = reinterpret_cast<const char*>(*iter); 272 273 UpdateIter(iter, length); 274 return true; 275 } 276 277 bool Pickle::ReadData(void** iter, const char** data, int* length) const { 278 DCHECK(iter); 279 DCHECK(data); 280 DCHECK(length); 281 *length = 0; 282 *data = 0; 283 284 if (!ReadLength(iter, length)) 285 return false; 286 287 return ReadBytes(iter, data, *length); 288 } 289 290 char* Pickle::BeginWrite(size_t length) { 291 // write at a uint32-aligned offset from the beginning of the header 292 size_t offset = AlignInt(header_->payload_size, sizeof(uint32)); 293 294 size_t new_size = offset + length; 295 size_t needed_size = header_size_ + new_size; 296 if (needed_size > capacity_ && !Resize(std::max(capacity_ * 2, needed_size))) 297 return NULL; 298 299 #ifdef ARCH_CPU_64_BITS 300 DCHECK_LE(length, std::numeric_limits<uint32>::max()); 301 #endif 302 303 header_->payload_size = static_cast<uint32>(new_size); 304 return payload() + offset; 305 } 306 307 void Pickle::EndWrite(char* dest, int length) { 308 // Zero-pad to keep tools like purify from complaining about uninitialized 309 // memory. 310 if (length % sizeof(uint32)) 311 memset(dest + length, 0, sizeof(uint32) - (length % sizeof(uint32))); 312 } 313 314 bool Pickle::WriteBytes(const void* data, int data_len) { 315 DCHECK(capacity_ != kCapacityReadOnly) << "oops: pickle is readonly"; 316 317 char* dest = BeginWrite(data_len); 318 if (!dest) 319 return false; 320 321 memcpy(dest, data, data_len); 322 323 EndWrite(dest, data_len); 324 return true; 325 } 326 327 bool Pickle::WriteString(const std::string& value) { 328 if (!WriteInt(static_cast<int>(value.size()))) 329 return false; 330 331 return WriteBytes(value.data(), static_cast<int>(value.size())); 332 } 333 334 bool Pickle::WriteWString(const std::wstring& value) { 335 if (!WriteInt(static_cast<int>(value.size()))) 336 return false; 337 338 return WriteBytes(value.data(), 339 static_cast<int>(value.size() * sizeof(wchar_t))); 340 } 341 342 bool Pickle::WriteString16(const string16& value) { 343 if (!WriteInt(static_cast<int>(value.size()))) 344 return false; 345 346 return WriteBytes(value.data(), 347 static_cast<int>(value.size()) * sizeof(char16)); 348 } 349 350 bool Pickle::WriteData(const char* data, int length) { 351 return length >= 0 && WriteInt(length) && WriteBytes(data, length); 352 } 353 354 char* Pickle::BeginWriteData(int length) { 355 DCHECK_EQ(variable_buffer_offset_, 0U) << 356 "There can only be one variable buffer in a Pickle"; 357 358 if (length < 0 || !WriteInt(length)) 359 return NULL; 360 361 char *data_ptr = BeginWrite(length); 362 if (!data_ptr) 363 return NULL; 364 365 variable_buffer_offset_ = 366 data_ptr - reinterpret_cast<char*>(header_) - sizeof(int); 367 368 // EndWrite doesn't necessarily have to be called after the write operation, 369 // so we call it here to pad out what the caller will eventually write. 370 EndWrite(data_ptr, length); 371 return data_ptr; 372 } 373 374 void Pickle::TrimWriteData(int new_length) { 375 DCHECK_NE(variable_buffer_offset_, 0U); 376 377 // Fetch the the variable buffer size 378 int* cur_length = reinterpret_cast<int*>( 379 reinterpret_cast<char*>(header_) + variable_buffer_offset_); 380 381 if (new_length < 0 || new_length > *cur_length) { 382 NOTREACHED() << "Invalid length in TrimWriteData."; 383 return; 384 } 385 386 // Update the payload size and variable buffer size 387 header_->payload_size -= (*cur_length - new_length); 388 *cur_length = new_length; 389 } 390 391 bool Pickle::Resize(size_t new_capacity) { 392 new_capacity = AlignInt(new_capacity, kPayloadUnit); 393 394 CHECK(capacity_ != kCapacityReadOnly); 395 void* p = realloc(header_, new_capacity); 396 if (!p) 397 return false; 398 399 header_ = reinterpret_cast<Header*>(p); 400 capacity_ = new_capacity; 401 return true; 402 } 403 404 // static 405 const char* Pickle::FindNext(size_t header_size, 406 const char* start, 407 const char* end) { 408 DCHECK(header_size == AlignInt(header_size, sizeof(uint32))); 409 DCHECK(header_size <= static_cast<size_t>(kPayloadUnit)); 410 411 const Header* hdr = reinterpret_cast<const Header*>(start); 412 const char* payload_base = start + header_size; 413 const char* payload_end = payload_base + hdr->payload_size; 414 if (payload_end < payload_base) 415 return NULL; 416 417 return (payload_end > end) ? NULL : payload_end; 418 } 419