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