ipc/chromium/src/base/pickle.cc

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

michael@0 1 // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
michael@0 2 // Use of this source code is governed by a BSD-style license that can be
michael@0 3 // found in the LICENSE file.
michael@0 4
michael@0 5 #include "base/pickle.h"
michael@0 6
michael@0 7 #include "mozilla/Alignment.h"
michael@0 8 #include "mozilla/Endian.h"
michael@0 9 #include "mozilla/TypeTraits.h"
michael@0 10
michael@0 11 #include <stdlib.h>
michael@0 12
michael@0 13 #include <limits>
michael@0 14 #include <string>
michael@0 15 #include <algorithm>
michael@0 16
michael@0 17 #include "nsDebug.h"
michael@0 18
michael@0 19 //------------------------------------------------------------------------------
michael@0 20
michael@0 21 static_assert(MOZ_ALIGNOF(Pickle::memberAlignmentType) >= MOZ_ALIGNOF(uint32_t),
michael@0 22 "Insufficient alignment");
michael@0 23
michael@0 24 // static
michael@0 25 const int Pickle::kPayloadUnit = 64;
michael@0 26
michael@0 27 // We mark a read only pickle with a special capacity_.
michael@0 28 static const uint32_t kCapacityReadOnly = (uint32_t) -1;
michael@0 29
michael@0 30 static const char kBytePaddingMarker = char(0xbf);
michael@0 31
michael@0 32 namespace {
michael@0 33
michael@0 34 // We want to copy data to our payload as efficiently as possible.
michael@0 35 // memcpy fits the bill for copying, but not all compilers or
michael@0 36 // architectures support inlining memcpy from void*, which has unknown
michael@0 37 // static alignment. However, we know that all the members of our
michael@0 38 // payload will be aligned on memberAlignmentType boundaries. We
michael@0 39 // therefore use that knowledge to construct a copier that will copy
michael@0 40 // efficiently (via standard C++ assignment mechanisms) if the datatype
michael@0 41 // needs that alignment or less, and memcpy otherwise. (The compiler
michael@0 42 // may still inline memcpy, of course.)
michael@0 43
michael@0 44 template<typename T, size_t size, bool hasSufficientAlignment>
michael@0 45 struct Copier
michael@0 46 {
michael@0 47 static void Copy(T* dest, void** iter) {
michael@0 48 memcpy(dest, *iter, sizeof(T));
michael@0 49 }
michael@0 50 };
michael@0 51
michael@0 52 // Copying 64-bit quantities happens often enough and can easily be made
michael@0 53 // worthwhile on 32-bit platforms, so handle it specially. Only do it
michael@0 54 // if 64-bit types aren't sufficiently aligned; the alignment
michael@0 55 // requirements for them vary between 32-bit platforms.
michael@0 56 #ifndef HAVE_64BIT_OS
michael@0 57 template<typename T>
michael@0 58 struct Copier<T, sizeof(uint64_t), false>
michael@0 59 {
michael@0 60 static void Copy(T* dest, void** iter) {
michael@0 61 #if MOZ_LITTLE_ENDIAN
michael@0 62 static const int loIndex = 0, hiIndex = 1;
michael@0 63 #else
michael@0 64 static const int loIndex = 1, hiIndex = 0;
michael@0 65 #endif
michael@0 66 static_assert(MOZ_ALIGNOF(uint32_t*) == MOZ_ALIGNOF(void*),
michael@0 67 "Pointers have different alignments");
michael@0 68 uint32_t* src = *reinterpret_cast<uint32_t**>(iter);
michael@0 69 uint32_t* uint32dest = reinterpret_cast<uint32_t*>(dest);
michael@0 70 uint32dest[loIndex] = src[loIndex];
michael@0 71 uint32dest[hiIndex] = src[hiIndex];
michael@0 72 }
michael@0 73 };
michael@0 74 #endif
michael@0 75
michael@0 76 template<typename T, size_t size>
michael@0 77 struct Copier<T, size, true>
michael@0 78 {
michael@0 79 static void Copy(T* dest, void** iter) {
michael@0 80 // The reinterpret_cast is only safe if two conditions hold:
michael@0 81 // (1) If the alignment of T* is the same as void*;
michael@0 82 // (2) The alignment of the data in *iter is at least as
michael@0 83 // big as MOZ_ALIGNOF(T).
michael@0 84 // Check the first condition, as the second condition is already
michael@0 85 // known to be true, or we wouldn't be here.
michael@0 86 static_assert(MOZ_ALIGNOF(T*) == MOZ_ALIGNOF(void*),
michael@0 87 "Pointers have different alignments");
michael@0 88 *dest = *(*reinterpret_cast<T**>(iter));
michael@0 89 }
michael@0 90 };
michael@0 91
michael@0 92 template<typename T>
michael@0 93 void CopyFromIter(T* dest, void** iter) {
michael@0 94 static_assert(mozilla::IsPod<T>::value, "Copied type must be a POD type");
michael@0 95 Copier<T, sizeof(T), (MOZ_ALIGNOF(T) <= sizeof(Pickle::memberAlignmentType))>::Copy(dest, iter);
michael@0 96 }
michael@0 97
michael@0 98 } // anonymous namespace
michael@0 99
michael@0 100 // Payload is sizeof(Pickle::memberAlignmentType) aligned.
michael@0 101
michael@0 102 Pickle::Pickle()
michael@0 103 : header_(NULL),
michael@0 104 header_size_(sizeof(Header)),
michael@0 105 capacity_(0),
michael@0 106 variable_buffer_offset_(0) {
michael@0 107 Resize(kPayloadUnit);
michael@0 108 header_->payload_size = 0;
michael@0 109 }
michael@0 110
michael@0 111 Pickle::Pickle(int header_size)
michael@0 112 : header_(NULL),
michael@0 113 header_size_(AlignInt(header_size)),
michael@0 114 capacity_(0),
michael@0 115 variable_buffer_offset_(0) {
michael@0 116 DCHECK(static_cast<memberAlignmentType>(header_size) >= sizeof(Header));
michael@0 117 DCHECK(header_size <= kPayloadUnit);
michael@0 118 Resize(kPayloadUnit);
michael@0 119 if (!header_) {
michael@0 120 NS_ABORT_OOM(kPayloadUnit);
michael@0 121 }
michael@0 122 header_->payload_size = 0;
michael@0 123 }
michael@0 124
michael@0 125 Pickle::Pickle(const char* data, int data_len)
michael@0 126 : header_(reinterpret_cast<Header*>(const_cast<char*>(data))),
michael@0 127 header_size_(data_len - header_->payload_size),
michael@0 128 capacity_(kCapacityReadOnly),
michael@0 129 variable_buffer_offset_(0) {
michael@0 130 DCHECK(header_size_ >= sizeof(Header));
michael@0 131 DCHECK(header_size_ == AlignInt(header_size_));
michael@0 132 }
michael@0 133
michael@0 134 Pickle::Pickle(const Pickle& other)
michael@0 135 : header_(NULL),
michael@0 136 header_size_(other.header_size_),
michael@0 137 capacity_(0),
michael@0 138 variable_buffer_offset_(other.variable_buffer_offset_) {
michael@0 139 uint32_t payload_size = header_size_ + other.header_->payload_size;
michael@0 140 bool resized = Resize(payload_size);
michael@0 141 if (!resized) {
michael@0 142 NS_ABORT_OOM(payload_size);
michael@0 143 }
michael@0 144 memcpy(header_, other.header_, payload_size);
michael@0 145 }
michael@0 146
michael@0 147 Pickle::~Pickle() {
michael@0 148 if (capacity_ != kCapacityReadOnly)
michael@0 149 free(header_);
michael@0 150 }
michael@0 151
michael@0 152 Pickle& Pickle::operator=(const Pickle& other) {
michael@0 153 if (header_size_ != other.header_size_ && capacity_ != kCapacityReadOnly) {
michael@0 154 free(header_);
michael@0 155 header_ = NULL;
michael@0 156 header_size_ = other.header_size_;
michael@0 157 }
michael@0 158 bool resized = Resize(other.header_size_ + other.header_->payload_size);
michael@0 159 if (!resized) {
michael@0 160 NS_ABORT_OOM(other.header_size_ + other.header_->payload_size);
michael@0 161 }
michael@0 162 memcpy(header_, other.header_, header_size_ + other.header_->payload_size);
michael@0 163 variable_buffer_offset_ = other.variable_buffer_offset_;
michael@0 164 return *this;
michael@0 165 }
michael@0 166
michael@0 167 bool Pickle::ReadBool(void** iter, bool* result) const {
michael@0 168 DCHECK(iter);
michael@0 169
michael@0 170 int tmp;
michael@0 171 if (!ReadInt(iter, &tmp))
michael@0 172 return false;
michael@0 173 DCHECK(0 == tmp || 1 == tmp);
michael@0 174 *result = tmp ? true : false;
michael@0 175 return true;
michael@0 176 }
michael@0 177
michael@0 178 bool Pickle::ReadInt16(void** iter, int16_t* result) const {
michael@0 179 DCHECK(iter);
michael@0 180 if (!*iter)
michael@0 181 *iter = const_cast<char*>(payload());
michael@0 182
michael@0 183 if (!IteratorHasRoomFor(*iter, sizeof(*result)))
michael@0 184 return false;
michael@0 185
michael@0 186 CopyFromIter(result, iter);
michael@0 187
michael@0 188 UpdateIter(iter, sizeof(*result));
michael@0 189 return true;
michael@0 190 }
michael@0 191
michael@0 192 bool Pickle::ReadUInt16(void** iter, uint16_t* result) const {
michael@0 193 DCHECK(iter);
michael@0 194 if (!*iter)
michael@0 195 *iter = const_cast<char*>(payload());
michael@0 196
michael@0 197 if (!IteratorHasRoomFor(*iter, sizeof(*result)))
michael@0 198 return false;
michael@0 199
michael@0 200 CopyFromIter(result, iter);
michael@0 201
michael@0 202 UpdateIter(iter, sizeof(*result));
michael@0 203 return true;
michael@0 204 }
michael@0 205
michael@0 206 bool Pickle::ReadInt(void** iter, int* result) const {
michael@0 207 DCHECK(iter);
michael@0 208 if (!*iter)
michael@0 209 *iter = const_cast<char*>(payload());
michael@0 210
michael@0 211 if (!IteratorHasRoomFor(*iter, sizeof(*result)))
michael@0 212 return false;
michael@0 213
michael@0 214 CopyFromIter(result, iter);
michael@0 215
michael@0 216 UpdateIter(iter, sizeof(*result));
michael@0 217 return true;
michael@0 218 }
michael@0 219
michael@0 220 // Always written as a 64-bit value since the size for this type can
michael@0 221 // differ between architectures.
michael@0 222 bool Pickle::ReadLong(void** iter, long* result) const {
michael@0 223 DCHECK(iter);
michael@0 224 if (!*iter)
michael@0 225 *iter = const_cast<char*>(payload());
michael@0 226
michael@0 227 int64_t bigResult = 0;
michael@0 228 if (!IteratorHasRoomFor(*iter, sizeof(bigResult)))
michael@0 229 return false;
michael@0 230
michael@0 231 CopyFromIter(&bigResult, iter);
michael@0 232 DCHECK(bigResult <= LONG_MAX && bigResult >= LONG_MIN);
michael@0 233 *result = static_cast<long>(bigResult);
michael@0 234
michael@0 235 UpdateIter(iter, sizeof(bigResult));
michael@0 236 return true;
michael@0 237 }
michael@0 238
michael@0 239 // Always written as a 64-bit value since the size for this type can
michael@0 240 // differ between architectures.
michael@0 241 bool Pickle::ReadULong(void** iter, unsigned long* result) const {
michael@0 242 DCHECK(iter);
michael@0 243 if (!*iter)
michael@0 244 *iter = const_cast<char*>(payload());
michael@0 245
michael@0 246 uint64_t bigResult = 0;
michael@0 247 if (!IteratorHasRoomFor(*iter, sizeof(bigResult)))
michael@0 248 return false;
michael@0 249
michael@0 250 CopyFromIter(&bigResult, iter);
michael@0 251 DCHECK(bigResult <= ULONG_MAX);
michael@0 252 *result = static_cast<unsigned long>(bigResult);
michael@0 253
michael@0 254 UpdateIter(iter, sizeof(bigResult));
michael@0 255 return true;
michael@0 256 }
michael@0 257
michael@0 258 bool Pickle::ReadLength(void** iter, int* result) const {
michael@0 259 if (!ReadInt(iter, result))
michael@0 260 return false;
michael@0 261 return ((*result) >= 0);
michael@0 262 }
michael@0 263
michael@0 264 // Always written as a 64-bit value since the size for this type can
michael@0 265 // differ between architectures.
michael@0 266 bool Pickle::ReadSize(void** iter, size_t* result) const {
michael@0 267 DCHECK(iter);
michael@0 268 if (!*iter)
michael@0 269 *iter = const_cast<char*>(payload());
michael@0 270
michael@0 271 uint64_t bigResult = 0;
michael@0 272 if (!IteratorHasRoomFor(*iter, sizeof(bigResult)))
michael@0 273 return false;
michael@0 274
michael@0 275 CopyFromIter(&bigResult, iter);
michael@0 276 DCHECK(bigResult <= std::numeric_limits<size_t>::max());
michael@0 277 *result = static_cast<size_t>(bigResult);
michael@0 278
michael@0 279 UpdateIter(iter, sizeof(bigResult));
michael@0 280 return true;
michael@0 281 }
michael@0 282
michael@0 283 bool Pickle::ReadInt32(void** iter, int32_t* result) const {
michael@0 284 DCHECK(iter);
michael@0 285 if (!*iter)
michael@0 286 *iter = const_cast<char*>(payload());
michael@0 287
michael@0 288 if (!IteratorHasRoomFor(*iter, sizeof(*result)))
michael@0 289 return false;
michael@0 290
michael@0 291 CopyFromIter(result, iter);
michael@0 292
michael@0 293 UpdateIter(iter, sizeof(*result));
michael@0 294 return true;
michael@0 295 }
michael@0 296
michael@0 297 bool Pickle::ReadUInt32(void** iter, uint32_t* result) const {
michael@0 298 DCHECK(iter);
michael@0 299 if (!*iter)
michael@0 300 *iter = const_cast<char*>(payload());
michael@0 301
michael@0 302 if (!IteratorHasRoomFor(*iter, sizeof(*result)))
michael@0 303 return false;
michael@0 304
michael@0 305 CopyFromIter(result, iter);
michael@0 306
michael@0 307 UpdateIter(iter, sizeof(*result));
michael@0 308 return true;
michael@0 309 }
michael@0 310
michael@0 311 bool Pickle::ReadInt64(void** iter, int64_t* result) const {
michael@0 312 DCHECK(iter);
michael@0 313 if (!*iter)
michael@0 314 *iter = const_cast<char*>(payload());
michael@0 315
michael@0 316 if (!IteratorHasRoomFor(*iter, sizeof(*result)))
michael@0 317 return false;
michael@0 318
michael@0 319 CopyFromIter(result, iter);
michael@0 320
michael@0 321 UpdateIter(iter, sizeof(*result));
michael@0 322 return true;
michael@0 323 }
michael@0 324
michael@0 325 bool Pickle::ReadUInt64(void** iter, uint64_t* result) const {
michael@0 326 DCHECK(iter);
michael@0 327 if (!*iter)
michael@0 328 *iter = const_cast<char*>(payload());
michael@0 329
michael@0 330 if (!IteratorHasRoomFor(*iter, sizeof(*result)))
michael@0 331 return false;
michael@0 332
michael@0 333 CopyFromIter(result, iter);
michael@0 334
michael@0 335 UpdateIter(iter, sizeof(*result));
michael@0 336 return true;
michael@0 337 }
michael@0 338
michael@0 339 bool Pickle::ReadDouble(void** iter, double* result) const {
michael@0 340 DCHECK(iter);
michael@0 341 if (!*iter)
michael@0 342 *iter = const_cast<char*>(payload());
michael@0 343
michael@0 344 if (!IteratorHasRoomFor(*iter, sizeof(*result)))
michael@0 345 return false;
michael@0 346
michael@0 347 CopyFromIter(result, iter);
michael@0 348
michael@0 349 UpdateIter(iter, sizeof(*result));
michael@0 350 return true;
michael@0 351 }
michael@0 352
michael@0 353 // Always written as a 64-bit value since the size for this type can
michael@0 354 // differ between architectures.
michael@0 355 bool Pickle::ReadIntPtr(void** iter, intptr_t* result) const {
michael@0 356 DCHECK(iter);
michael@0 357 if (!*iter)
michael@0 358 *iter = const_cast<char*>(payload());
michael@0 359
michael@0 360 int64_t bigResult = 0;
michael@0 361 if (!IteratorHasRoomFor(*iter, sizeof(bigResult)))
michael@0 362 return false;
michael@0 363
michael@0 364 CopyFromIter(&bigResult, iter);
michael@0 365 DCHECK(bigResult <= std::numeric_limits<intptr_t>::max() && bigResult >= std::numeric_limits<intptr_t>::min());
michael@0 366 *result = static_cast<intptr_t>(bigResult);
michael@0 367
michael@0 368 UpdateIter(iter, sizeof(bigResult));
michael@0 369 return true;
michael@0 370 }
michael@0 371
michael@0 372 bool Pickle::ReadUnsignedChar(void** iter, unsigned char* result) const {
michael@0 373 DCHECK(iter);
michael@0 374 if (!*iter)
michael@0 375 *iter = const_cast<char*>(payload());
michael@0 376
michael@0 377 if (!IteratorHasRoomFor(*iter, sizeof(*result)))
michael@0 378 return false;
michael@0 379
michael@0 380 CopyFromIter(result, iter);
michael@0 381
michael@0 382 UpdateIter(iter, sizeof(*result));
michael@0 383 return true;
michael@0 384 }
michael@0 385
michael@0 386 bool Pickle::ReadString(void** iter, std::string* result) const {
michael@0 387 DCHECK(iter);
michael@0 388 if (!*iter)
michael@0 389 *iter = const_cast<char*>(payload());
michael@0 390
michael@0 391 int len;
michael@0 392 if (!ReadLength(iter, &len))
michael@0 393 return false;
michael@0 394 if (!IteratorHasRoomFor(*iter, len))
michael@0 395 return false;
michael@0 396
michael@0 397 char* chars = reinterpret_cast<char*>(*iter);
michael@0 398 result->assign(chars, len);
michael@0 399
michael@0 400 UpdateIter(iter, len);
michael@0 401 return true;
michael@0 402 }
michael@0 403
michael@0 404 bool Pickle::ReadWString(void** iter, std::wstring* result) const {
michael@0 405 DCHECK(iter);
michael@0 406 if (!*iter)
michael@0 407 *iter = const_cast<char*>(payload());
michael@0 408
michael@0 409 int len;
michael@0 410 if (!ReadLength(iter, &len))
michael@0 411 return false;
michael@0 412 if (!IteratorHasRoomFor(*iter, len * sizeof(wchar_t)))
michael@0 413 return false;
michael@0 414
michael@0 415 wchar_t* chars = reinterpret_cast<wchar_t*>(*iter);
michael@0 416 result->assign(chars, len);
michael@0 417
michael@0 418 UpdateIter(iter, len * sizeof(wchar_t));
michael@0 419 return true;
michael@0 420 }
michael@0 421
michael@0 422 bool Pickle::ReadString16(void** iter, string16* result) const {
michael@0 423 DCHECK(iter);
michael@0 424 if (!*iter)
michael@0 425 *iter = const_cast<char*>(payload());
michael@0 426
michael@0 427 int len;
michael@0 428 if (!ReadLength(iter, &len))
michael@0 429 return false;
michael@0 430 if (!IteratorHasRoomFor(*iter, len))
michael@0 431 return false;
michael@0 432
michael@0 433 char16* chars = reinterpret_cast<char16*>(*iter);
michael@0 434 result->assign(chars, len);
michael@0 435
michael@0 436 UpdateIter(iter, len * sizeof(char16));
michael@0 437 return true;
michael@0 438 }
michael@0 439
michael@0 440 bool Pickle::ReadBytes(void** iter, const char** data, int length,
michael@0 441 uint32_t alignment) const {
michael@0 442 DCHECK(iter);
michael@0 443 DCHECK(data);
michael@0 444 DCHECK(alignment == 4 || alignment == 8);
michael@0 445 DCHECK(intptr_t(header_) % alignment == 0);
michael@0 446
michael@0 447 if (!*iter)
michael@0 448 *iter = const_cast<char*>(payload());
michael@0 449
michael@0 450 uint32_t paddingLen = intptr_t(*iter) % alignment;
michael@0 451 if (paddingLen) {
michael@0 452 #ifdef DEBUG
michael@0 453 {
michael@0 454 const char* padding = static_cast<const char*>(*iter);
michael@0 455 for (uint32_t i = 0; i < paddingLen; i++) {
michael@0 456 DCHECK(*(padding + i) == kBytePaddingMarker);
michael@0 457 }
michael@0 458 }
michael@0 459 #endif
michael@0 460 length += paddingLen;
michael@0 461 }
michael@0 462
michael@0 463 if (!IteratorHasRoomFor(*iter, length))
michael@0 464 return false;
michael@0 465
michael@0 466 *data = static_cast<const char*>(*iter) + paddingLen;
michael@0 467 DCHECK(intptr_t(*data) % alignment == 0);
michael@0 468
michael@0 469 UpdateIter(iter, length);
michael@0 470 return true;
michael@0 471 }
michael@0 472
michael@0 473 bool Pickle::ReadData(void** iter, const char** data, int* length) const {
michael@0 474 DCHECK(iter);
michael@0 475 DCHECK(data);
michael@0 476 DCHECK(length);
michael@0 477 if (!*iter)
michael@0 478 *iter = const_cast<char*>(payload());
michael@0 479
michael@0 480 if (!ReadLength(iter, length))
michael@0 481 return false;
michael@0 482
michael@0 483 return ReadBytes(iter, data, *length);
michael@0 484 }
michael@0 485
michael@0 486 char* Pickle::BeginWrite(uint32_t length, uint32_t alignment) {
michael@0 487 DCHECK(alignment % 4 == 0) << "Must be at least 32-bit aligned!";
michael@0 488
michael@0 489 // write at an alignment-aligned offset from the beginning of the header
michael@0 490 uint32_t offset = AlignInt(header_->payload_size);
michael@0 491 uint32_t padding = (header_size_ + offset) % alignment;
michael@0 492 uint32_t new_size = offset + padding + AlignInt(length);
michael@0 493 uint32_t needed_size = header_size_ + new_size;
michael@0 494
michael@0 495 if (needed_size > capacity_ && !Resize(std::max(capacity_ * 2, needed_size)))
michael@0 496 return NULL;
michael@0 497
michael@0 498 DCHECK(intptr_t(header_) % alignment == 0);
michael@0 499
michael@0 500 #ifdef ARCH_CPU_64_BITS
michael@0 501 DCHECK_LE(length, std::numeric_limits<uint32_t>::max());
michael@0 502 #endif
michael@0 503
michael@0 504 char* buffer = payload() + offset;
michael@0 505
michael@0 506 if (padding) {
michael@0 507 memset(buffer, kBytePaddingMarker, padding);
michael@0 508 buffer += padding;
michael@0 509 }
michael@0 510
michael@0 511 DCHECK(intptr_t(buffer) % alignment == 0);
michael@0 512
michael@0 513 header_->payload_size = new_size;
michael@0 514
michael@0 515 #ifdef MOZ_VALGRIND
michael@0 516 // pad the trailing end as well, so that valgrind
michael@0 517 // doesn't complain when we write the buffer
michael@0 518 padding = AlignInt(length) - length;
michael@0 519 if (padding) {
michael@0 520 memset(buffer + length, kBytePaddingMarker, padding);
michael@0 521 }
michael@0 522 #endif
michael@0 523
michael@0 524 return buffer;
michael@0 525 }
michael@0 526
michael@0 527 void Pickle::EndWrite(char* dest, int length) {
michael@0 528 // Zero-pad to keep tools like purify from complaining about uninitialized
michael@0 529 // memory.
michael@0 530 if (length % sizeof(memberAlignmentType))
michael@0 531 memset(dest + length, 0,
michael@0 532 sizeof(memberAlignmentType) - (length % sizeof(memberAlignmentType)));
michael@0 533 }
michael@0 534
michael@0 535 bool Pickle::WriteBytes(const void* data, int data_len, uint32_t alignment) {
michael@0 536 DCHECK(capacity_ != kCapacityReadOnly) << "oops: pickle is readonly";
michael@0 537 DCHECK(alignment == 4 || alignment == 8);
michael@0 538 DCHECK(intptr_t(header_) % alignment == 0);
michael@0 539
michael@0 540 char* dest = BeginWrite(data_len, alignment);
michael@0 541 if (!dest)
michael@0 542 return false;
michael@0 543
michael@0 544 memcpy(dest, data, data_len);
michael@0 545
michael@0 546 EndWrite(dest, data_len);
michael@0 547 return true;
michael@0 548 }
michael@0 549
michael@0 550 bool Pickle::WriteString(const std::string& value) {
michael@0 551 if (!WriteInt(static_cast<int>(value.size())))
michael@0 552 return false;
michael@0 553
michael@0 554 return WriteBytes(value.data(), static_cast<int>(value.size()));
michael@0 555 }
michael@0 556
michael@0 557 bool Pickle::WriteWString(const std::wstring& value) {
michael@0 558 if (!WriteInt(static_cast<int>(value.size())))
michael@0 559 return false;
michael@0 560
michael@0 561 return WriteBytes(value.data(),
michael@0 562 static_cast<int>(value.size() * sizeof(wchar_t)));
michael@0 563 }
michael@0 564
michael@0 565 bool Pickle::WriteString16(const string16& value) {
michael@0 566 if (!WriteInt(static_cast<int>(value.size())))
michael@0 567 return false;
michael@0 568
michael@0 569 return WriteBytes(value.data(),
michael@0 570 static_cast<int>(value.size()) * sizeof(char16));
michael@0 571 }
michael@0 572
michael@0 573 bool Pickle::WriteData(const char* data, int length) {
michael@0 574 return WriteInt(length) && WriteBytes(data, length);
michael@0 575 }
michael@0 576
michael@0 577 char* Pickle::BeginWriteData(int length) {
michael@0 578 DCHECK_EQ(variable_buffer_offset_, 0U) <<
michael@0 579 "There can only be one variable buffer in a Pickle";
michael@0 580
michael@0 581 if (!WriteInt(length))
michael@0 582 return NULL;
michael@0 583
michael@0 584 char *data_ptr = BeginWrite(length, sizeof(memberAlignmentType));
michael@0 585 if (!data_ptr)
michael@0 586 return NULL;
michael@0 587
michael@0 588 variable_buffer_offset_ =
michael@0 589 data_ptr - reinterpret_cast<char*>(header_) - sizeof(int);
michael@0 590
michael@0 591 // EndWrite doesn't necessarily have to be called after the write operation,
michael@0 592 // so we call it here to pad out what the caller will eventually write.
michael@0 593 EndWrite(data_ptr, length);
michael@0 594 return data_ptr;
michael@0 595 }
michael@0 596
michael@0 597 void Pickle::TrimWriteData(int new_length) {
michael@0 598 DCHECK(variable_buffer_offset_ != 0);
michael@0 599
michael@0 600 // Fetch the the variable buffer size
michael@0 601 int* cur_length = reinterpret_cast<int*>(
michael@0 602 reinterpret_cast<char*>(header_) + variable_buffer_offset_);
michael@0 603
michael@0 604 if (new_length < 0 || new_length > *cur_length) {
michael@0 605 NOTREACHED() << "Invalid length in TrimWriteData.";
michael@0 606 return;
michael@0 607 }
michael@0 608
michael@0 609 // Update the payload size and variable buffer size
michael@0 610 header_->payload_size -= (*cur_length - new_length);
michael@0 611 *cur_length = new_length;
michael@0 612 }
michael@0 613
michael@0 614 bool Pickle::Resize(uint32_t new_capacity) {
michael@0 615 new_capacity = ConstantAligner<kPayloadUnit>::align(new_capacity);
michael@0 616
michael@0 617 void* p = realloc(header_, new_capacity);
michael@0 618 if (!p)
michael@0 619 return false;
michael@0 620
michael@0 621 header_ = reinterpret_cast<Header*>(p);
michael@0 622 capacity_ = new_capacity;
michael@0 623 return true;
michael@0 624 }
michael@0 625
michael@0 626 // static
michael@0 627 const char* Pickle::FindNext(uint32_t header_size,
michael@0 628 const char* start,
michael@0 629 const char* end) {
michael@0 630 DCHECK(header_size == AlignInt(header_size));
michael@0 631 DCHECK(header_size <= static_cast<memberAlignmentType>(kPayloadUnit));
michael@0 632
michael@0 633 const Header* hdr = reinterpret_cast<const Header*>(start);
michael@0 634 const char* payload_base = start + header_size;
michael@0 635 const char* payload_end = payload_base + hdr->payload_size;
michael@0 636 if (payload_end < payload_base)
michael@0 637 return NULL;
michael@0 638
michael@0 639 return (payload_end > end) ? NULL : payload_end;
michael@0 640 }

mercurial