1 // Copyright (c) 2011 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_GE(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_(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 61 Pickle::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 72 Pickle::~Pickle() { 73 if (capacity_ != kCapacityReadOnly) 74 free(header_); 75 } 76 77 Pickle& 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 99 bool 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 110 bool 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 127 bool 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 143 bool 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 160 bool Pickle::ReadUInt16(void** iter, uint16* 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 174 bool Pickle::ReadUInt32(void** iter, uint32* 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 188 bool Pickle::ReadInt64(void** iter, int64* 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 202 bool Pickle::ReadUInt64(void** iter, uint64* result) const { 203 DCHECK(iter); 204 if (!*iter) 205 *iter = const_cast<char*>(payload()); 206 207 if (!IteratorHasRoomFor(*iter, sizeof(*result))) 208 return false; 209 210 memcpy(result, *iter, sizeof(*result)); 211 212 UpdateIter(iter, sizeof(*result)); 213 return true; 214 } 215 216 bool Pickle::ReadString(void** iter, std::string* result) const { 217 DCHECK(iter); 218 219 int len; 220 if (!ReadLength(iter, &len)) 221 return false; 222 if (!IteratorHasRoomFor(*iter, len)) 223 return false; 224 225 char* chars = reinterpret_cast<char*>(*iter); 226 result->assign(chars, len); 227 228 UpdateIter(iter, len); 229 return true; 230 } 231 232 bool Pickle::ReadWString(void** iter, std::wstring* result) const { 233 DCHECK(iter); 234 235 int len; 236 if (!ReadLength(iter, &len)) 237 return false; 238 // Avoid integer overflow. 239 if (len > INT_MAX / static_cast<int>(sizeof(wchar_t))) 240 return false; 241 if (!IteratorHasRoomFor(*iter, len * sizeof(wchar_t))) 242 return false; 243 244 wchar_t* chars = reinterpret_cast<wchar_t*>(*iter); 245 result->assign(chars, len); 246 247 UpdateIter(iter, len * sizeof(wchar_t)); 248 return true; 249 } 250 251 bool Pickle::ReadString16(void** iter, string16* result) const { 252 DCHECK(iter); 253 254 int len; 255 if (!ReadLength(iter, &len)) 256 return false; 257 if (!IteratorHasRoomFor(*iter, len * sizeof(char16))) 258 return false; 259 260 char16* chars = reinterpret_cast<char16*>(*iter); 261 result->assign(chars, len); 262 263 UpdateIter(iter, len * sizeof(char16)); 264 return true; 265 } 266 267 bool Pickle::ReadData(void** iter, const char** data, int* length) const { 268 DCHECK(iter); 269 DCHECK(data); 270 DCHECK(length); 271 *length = 0; 272 *data = 0; 273 274 if (!ReadLength(iter, length)) 275 return false; 276 277 return ReadBytes(iter, data, *length); 278 } 279 280 bool Pickle::ReadBytes(void** iter, const char** data, int length) const { 281 DCHECK(iter); 282 DCHECK(data); 283 *data = 0; 284 if (!*iter) 285 *iter = const_cast<char*>(payload()); 286 287 if (!IteratorHasRoomFor(*iter, length)) 288 return false; 289 290 *data = reinterpret_cast<const char*>(*iter); 291 292 UpdateIter(iter, length); 293 return true; 294 } 295 296 bool Pickle::ReadLength(void** iter, int* result) const { 297 if (!ReadInt(iter, result)) 298 return false; 299 return ((*result) >= 0); 300 } 301 302 bool Pickle::WriteString(const std::string& value) { 303 if (!WriteInt(static_cast<int>(value.size()))) 304 return false; 305 306 return WriteBytes(value.data(), static_cast<int>(value.size())); 307 } 308 309 bool Pickle::WriteWString(const std::wstring& value) { 310 if (!WriteInt(static_cast<int>(value.size()))) 311 return false; 312 313 return WriteBytes(value.data(), 314 static_cast<int>(value.size() * sizeof(wchar_t))); 315 } 316 317 bool Pickle::WriteString16(const string16& value) { 318 if (!WriteInt(static_cast<int>(value.size()))) 319 return false; 320 321 return WriteBytes(value.data(), 322 static_cast<int>(value.size()) * sizeof(char16)); 323 } 324 325 bool Pickle::WriteData(const char* data, int length) { 326 return length >= 0 && WriteInt(length) && WriteBytes(data, length); 327 } 328 329 bool Pickle::WriteBytes(const void* data, int data_len) { 330 DCHECK(capacity_ != kCapacityReadOnly) << "oops: pickle is readonly"; 331 332 char* dest = BeginWrite(data_len); 333 if (!dest) 334 return false; 335 336 memcpy(dest, data, data_len); 337 338 EndWrite(dest, data_len); 339 return true; 340 } 341 342 char* 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 362 void 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 379 char* Pickle::BeginWrite(size_t length) { 380 // write at a uint32-aligned offset from the beginning of the header 381 size_t offset = AlignInt(header_->payload_size, sizeof(uint32)); 382 383 size_t new_size = offset + length; 384 size_t needed_size = header_size_ + new_size; 385 if (needed_size > capacity_ && !Resize(std::max(capacity_ * 2, needed_size))) 386 return NULL; 387 388 #ifdef ARCH_CPU_64_BITS 389 DCHECK_LE(length, std::numeric_limits<uint32>::max()); 390 #endif 391 392 header_->payload_size = static_cast<uint32>(new_size); 393 return payload() + offset; 394 } 395 396 void Pickle::EndWrite(char* dest, int length) { 397 // Zero-pad to keep tools like purify from complaining about uninitialized 398 // memory. 399 if (length % sizeof(uint32)) 400 memset(dest + length, 0, sizeof(uint32) - (length % sizeof(uint32))); 401 } 402 403 bool Pickle::Resize(size_t new_capacity) { 404 new_capacity = AlignInt(new_capacity, kPayloadUnit); 405 406 CHECK_NE(capacity_, kCapacityReadOnly); 407 void* p = realloc(header_, new_capacity); 408 if (!p) 409 return false; 410 411 header_ = reinterpret_cast<Header*>(p); 412 capacity_ = new_capacity; 413 return true; 414 } 415 416 // static 417 const char* Pickle::FindNext(size_t header_size, 418 const char* start, 419 const char* end) { 420 DCHECK(header_size == AlignInt(header_size, sizeof(uint32))); 421 DCHECK(header_size <= static_cast<size_t>(kPayloadUnit)); 422 423 if (static_cast<size_t>(end - start) < sizeof(Header)) 424 return NULL; 425 426 const Header* hdr = reinterpret_cast<const Header*>(start); 427 const char* payload_base = start + header_size; 428 const char* payload_end = payload_base + hdr->payload_size; 429 if (payload_end < payload_base) 430 return NULL; 431 432 return (payload_end > end) ? NULL : payload_end; 433 } 434