1 /*
2 * Copyright (C) 2009 Apple Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26 #include "config.h"
27 #include "BinaryPropertyList.h"
28
29 #include <wtf/HashMap.h>
30 #include <wtf/HashSet.h>
31 #include <wtf/text/StringHash.h>
32 #include <limits>
33
34 using namespace std;
35
36 namespace WebCore {
37
38 static const size_t headerSize = 8;
39 static const size_t trailerSize = 32;
40
41 static const UInt8 booleanTrueMarkerByte = 0x09;
42 static const UInt8 oneByteIntegerMarkerByte = 0x10;
43 static const UInt8 twoByteIntegerMarkerByte = 0x11;
44 static const UInt8 fourByteIntegerMarkerByte = 0x12;
45 static const UInt8 eightByteIntegerMarkerByte = 0x13;
46 static const UInt8 asciiStringMarkerByte = 0x50;
47 static const UInt8 asciiStringWithSeparateLengthMarkerByte = 0x5F;
48 static const UInt8 unicodeStringMarkerByte = 0x60;
49 static const UInt8 unicodeStringWithSeparateLengthMarkerByte = 0x6F;
50 static const UInt8 arrayMarkerByte = 0xA0;
51 static const UInt8 arrayWithSeparateLengthMarkerByte = 0xAF;
52 static const UInt8 dictionaryMarkerByte = 0xD0;
53 static const UInt8 dictionaryWithSeparateLengthMarkerByte = 0xDF;
54 static const size_t maxLengthInMarkerByte = 0xE;
55
56 class IntegerArray {
57 public:
IntegerArray()58 IntegerArray() : m_integers(0), m_size(0) { }
IntegerArray(const int * integers,size_t size)59 IntegerArray(const int* integers, size_t size) : m_integers(integers), m_size(size) { ASSERT(integers); ASSERT(size); }
60
markDeleted()61 void markDeleted() { m_integers = 0; m_size = deletedValueSize(); }
isDeletedValue() const62 bool isDeletedValue() const { return m_size == deletedValueSize(); }
63
integers() const64 const int* integers() const { ASSERT(!isDeletedValue()); return m_integers; }
size() const65 size_t size() const { ASSERT(!isDeletedValue()); return m_size; }
66
67 private:
deletedValueSize()68 static size_t deletedValueSize() { return numeric_limits<size_t>::max(); }
69
70 friend bool operator==(const IntegerArray&, const IntegerArray&);
71
72 const int* m_integers;
73 size_t m_size;
74 };
75
operator ==(const IntegerArray & a,const IntegerArray & b)76 inline bool operator==(const IntegerArray& a, const IntegerArray& b)
77 {
78 return a.m_integers == b.m_integers && a.m_size == b.m_size;
79 }
80
81 struct IntegerArrayHashTraits : WTF::GenericHashTraits<IntegerArray> {
82 static const bool needsDestruction = false;
constructDeletedValueWebCore::IntegerArrayHashTraits83 static void constructDeletedValue(IntegerArray& slot) { slot.markDeleted(); }
isDeletedValueWebCore::IntegerArrayHashTraits84 static bool isDeletedValue(const IntegerArray& array) { return array.isDeletedValue(); }
85 };
86
87 struct IntegerArrayHash {
88 static unsigned hash(const IntegerArray&);
89 static bool equal(const IntegerArray&, const IntegerArray&);
90 static const bool safeToCompareToEmptyOrDeleted = true;
91 };
92
hash(const IntegerArray & array)93 unsigned IntegerArrayHash::hash(const IntegerArray& array)
94 {
95 return StringHasher::hashMemory(array.integers(), array.size() * sizeof(int));
96 }
97
equal(const IntegerArray & a,const IntegerArray & b)98 bool IntegerArrayHash::equal(const IntegerArray& a, const IntegerArray& b)
99 {
100 if (a.isDeletedValue() || b.isDeletedValue())
101 return a.isDeletedValue() == b.isDeletedValue();
102 if (a.size() != b.size())
103 return false;
104 for (size_t i = 0; i < a.size(); ++i) {
105 if (a.integers()[i] != b.integers()[i])
106 return false;
107 }
108 return true;
109 }
110
111 typedef size_t ObjectReference;
112
113 class BinaryPropertyListPlan : private BinaryPropertyListObjectStream {
114 public:
115 BinaryPropertyListPlan(BinaryPropertyListWriter&);
116
117 ObjectReference booleanTrueObjectReference() const;
118 ObjectReference integerObjectReference(int) const;
119 ObjectReference stringObjectReference(const String&) const;
120 ObjectReference integerArrayObjectReference(const int*, size_t) const;
121
objectCount() const122 ObjectReference objectCount() const { return m_currentObjectReference; }
123
byteCount() const124 ObjectReference byteCount() const { return m_byteCount; }
objectReferenceCount() const125 ObjectReference objectReferenceCount() const { return m_objectReferenceCount; }
126
127 private:
128 virtual void writeBooleanTrue();
129 virtual void writeInteger(int);
130 virtual void writeString(const String&);
131 virtual void writeIntegerArray(const int*, size_t);
132 virtual void writeUniqueString(const String&);
133 virtual void writeUniqueString(const char*);
134 virtual size_t writeArrayStart();
135 virtual void writeArrayEnd(size_t);
136 virtual size_t writeDictionaryStart();
137 virtual void writeDictionaryEnd(size_t);
138
139 void writeArrayObject(size_t);
140 void writeDictionaryObject(size_t);
141 void writeStringObject(const String&);
142 void writeStringObject(const char*);
143
invalidObjectReference()144 static ObjectReference invalidObjectReference() { return numeric_limits<ObjectReference>::max(); }
145
146 typedef HashMap<IntegerArray, ObjectReference, IntegerArrayHash, IntegerArrayHashTraits> IntegerArrayMap;
147
148 ObjectReference m_booleanTrueObjectReference;
149 ObjectReference m_integerZeroObjectReference;
150 HashMap<int, ObjectReference> m_integers;
151 HashMap<String, ObjectReference> m_strings;
152 IntegerArrayMap m_integerArrays;
153
154 ObjectReference m_currentObjectReference;
155
156 size_t m_currentAggregateSize;
157
158 size_t m_byteCount;
159 size_t m_objectReferenceCount;
160 };
161
BinaryPropertyListPlan(BinaryPropertyListWriter & client)162 BinaryPropertyListPlan::BinaryPropertyListPlan(BinaryPropertyListWriter& client)
163 : m_booleanTrueObjectReference(invalidObjectReference())
164 , m_integerZeroObjectReference(invalidObjectReference())
165 , m_currentObjectReference(0)
166 , m_currentAggregateSize(0)
167 , m_byteCount(0)
168 , m_objectReferenceCount(0)
169 {
170 client.writeObjects(*this);
171 ASSERT(m_currentAggregateSize == 1);
172 }
173
writeBooleanTrue()174 void BinaryPropertyListPlan::writeBooleanTrue()
175 {
176 ++m_currentAggregateSize;
177 if (m_booleanTrueObjectReference != invalidObjectReference())
178 return;
179 m_booleanTrueObjectReference = m_currentObjectReference++;
180 ++m_byteCount;
181 }
182
integerByteCount(size_t integer)183 static inline int integerByteCount(size_t integer)
184 {
185 if (integer <= 0xFF)
186 return 2;
187 if (integer <= 0xFFFF)
188 return 3;
189 #ifdef __LP64__
190 if (integer <= 0xFFFFFFFFULL)
191 return 5;
192 return 9;
193 #else
194 return 5;
195 #endif
196 }
197
writeInteger(int integer)198 void BinaryPropertyListPlan::writeInteger(int integer)
199 {
200 ASSERT(integer >= 0);
201 ++m_currentAggregateSize;
202 if (!integer) {
203 if (m_integerZeroObjectReference != invalidObjectReference())
204 return;
205 m_integerZeroObjectReference = m_currentObjectReference;
206 } else {
207 if (!m_integers.add(integer, m_currentObjectReference).second)
208 return;
209 }
210 ++m_currentObjectReference;
211 m_byteCount += integerByteCount(integer);
212 }
213
writeString(const String & string)214 void BinaryPropertyListPlan::writeString(const String& string)
215 {
216 ++m_currentAggregateSize;
217 if (!m_strings.add(string, m_currentObjectReference).second)
218 return;
219 ++m_currentObjectReference;
220 writeStringObject(string);
221 }
222
writeIntegerArray(const int * integers,size_t size)223 void BinaryPropertyListPlan::writeIntegerArray(const int* integers, size_t size)
224 {
225 size_t savedAggregateSize = ++m_currentAggregateSize;
226 ASSERT(size);
227 pair<IntegerArrayMap::iterator, bool> addResult = m_integerArrays.add(IntegerArray(integers, size), 0);
228 if (!addResult.second)
229 return;
230 for (size_t i = 0; i < size; ++i)
231 writeInteger(integers[i]);
232 addResult.first->second = m_currentObjectReference++;
233 writeArrayObject(size);
234 m_currentAggregateSize = savedAggregateSize;
235 }
236
writeUniqueString(const String & string)237 void BinaryPropertyListPlan::writeUniqueString(const String& string)
238 {
239 ++m_currentAggregateSize;
240 ++m_currentObjectReference;
241 writeStringObject(string);
242 }
243
writeUniqueString(const char * string)244 void BinaryPropertyListPlan::writeUniqueString(const char* string)
245 {
246 ++m_currentAggregateSize;
247 ++m_currentObjectReference;
248 writeStringObject(string);
249 }
250
writeArrayStart()251 size_t BinaryPropertyListPlan::writeArrayStart()
252 {
253 size_t savedAggregateSize = m_currentAggregateSize;
254 m_currentAggregateSize = 0;
255 return savedAggregateSize;
256 }
257
writeArrayEnd(size_t savedAggregateSize)258 void BinaryPropertyListPlan::writeArrayEnd(size_t savedAggregateSize)
259 {
260 ++m_currentObjectReference;
261 writeArrayObject(m_currentAggregateSize);
262 m_currentAggregateSize = savedAggregateSize + 1;
263 }
264
writeDictionaryStart()265 size_t BinaryPropertyListPlan::writeDictionaryStart()
266 {
267 size_t savedAggregateSize = m_currentAggregateSize;
268 m_currentAggregateSize = 0;
269 return savedAggregateSize;
270 }
271
writeDictionaryEnd(size_t savedAggregateSize)272 void BinaryPropertyListPlan::writeDictionaryEnd(size_t savedAggregateSize)
273 {
274 ++m_currentObjectReference;
275 writeDictionaryObject(m_currentAggregateSize);
276 m_currentAggregateSize = savedAggregateSize + 1;
277 }
278
markerPlusLengthByteCount(size_t length)279 static size_t markerPlusLengthByteCount(size_t length)
280 {
281 if (length <= maxLengthInMarkerByte)
282 return 1;
283 return 1 + integerByteCount(length);
284 }
285
writeStringObject(const String & string)286 void BinaryPropertyListPlan::writeStringObject(const String& string)
287 {
288 const UChar* characters = string.characters();
289 unsigned length = string.length();
290 m_byteCount += markerPlusLengthByteCount(length) + length;
291 if (!charactersAreAllASCII(characters, length))
292 m_byteCount += length;
293 }
294
writeStringObject(const char * string)295 void BinaryPropertyListPlan::writeStringObject(const char* string)
296 {
297 unsigned length = strlen(string);
298 m_byteCount += markerPlusLengthByteCount(length) + length;
299 }
300
writeArrayObject(size_t size)301 void BinaryPropertyListPlan::writeArrayObject(size_t size)
302 {
303 ASSERT(size);
304 m_byteCount += markerPlusLengthByteCount(size);
305 m_objectReferenceCount += size;
306 }
307
writeDictionaryObject(size_t size)308 void BinaryPropertyListPlan::writeDictionaryObject(size_t size)
309 {
310 ASSERT(size);
311 ASSERT(!(size & 1));
312 m_byteCount += markerPlusLengthByteCount(size / 2);
313 m_objectReferenceCount += size;
314 }
315
booleanTrueObjectReference() const316 ObjectReference BinaryPropertyListPlan::booleanTrueObjectReference() const
317 {
318 ASSERT(m_booleanTrueObjectReference != invalidObjectReference());
319 return m_booleanTrueObjectReference;
320 }
321
integerObjectReference(int integer) const322 ObjectReference BinaryPropertyListPlan::integerObjectReference(int integer) const
323 {
324 ASSERT(integer >= 0);
325 if (!integer) {
326 ASSERT(m_integerZeroObjectReference != invalidObjectReference());
327 return m_integerZeroObjectReference;
328 }
329 ASSERT(m_integers.contains(integer));
330 return m_integers.get(integer);
331 }
332
stringObjectReference(const String & string) const333 ObjectReference BinaryPropertyListPlan::stringObjectReference(const String& string) const
334 {
335 ASSERT(m_strings.contains(string));
336 return m_strings.get(string);
337 }
338
integerArrayObjectReference(const int * integers,size_t size) const339 ObjectReference BinaryPropertyListPlan::integerArrayObjectReference(const int* integers, size_t size) const
340 {
341 ASSERT(m_integerArrays.contains(IntegerArray(integers, size)));
342 return m_integerArrays.get(IntegerArray(integers, size));
343 }
344
345 class BinaryPropertyListSerializer : private BinaryPropertyListObjectStream {
346 public:
347 BinaryPropertyListSerializer(BinaryPropertyListWriter&);
348
349 private:
350 virtual void writeBooleanTrue();
351 virtual void writeInteger(int);
352 virtual void writeString(const String&);
353 virtual void writeIntegerArray(const int*, size_t);
354 virtual void writeUniqueString(const String&);
355 virtual void writeUniqueString(const char*);
356 virtual size_t writeArrayStart();
357 virtual void writeArrayEnd(size_t);
358 virtual size_t writeDictionaryStart();
359 virtual void writeDictionaryEnd(size_t);
360
361 ObjectReference writeIntegerWithoutAddingAggregateObjectReference(int);
362
363 void appendIntegerObject(int);
364 void appendStringObject(const String&);
365 void appendStringObject(const char*);
366 void appendIntegerArrayObject(const int*, size_t);
367
368 void appendByte(unsigned char);
369 void appendByte(unsigned);
370 void appendByte(unsigned long);
371 void appendByte(int);
372
373 void appendInteger(size_t);
374
375 void appendObjectReference(ObjectReference);
376
377 void addAggregateObjectReference(ObjectReference);
378
379 void startObject();
380
381 const BinaryPropertyListPlan m_plan;
382 const int m_objectReferenceSize;
383 const size_t m_offsetTableStart;
384 const int m_offsetSize;
385 const size_t m_bufferSize;
386 UInt8* const m_buffer;
387
388 UInt8* m_currentByte;
389 ObjectReference m_currentObjectReference;
390 UInt8* m_currentAggregateBufferByte;
391 };
392
appendByte(unsigned char byte)393 inline void BinaryPropertyListSerializer::appendByte(unsigned char byte)
394 {
395 *m_currentByte++ = byte;
396 ASSERT(m_currentByte <= m_currentAggregateBufferByte);
397 }
398
appendByte(unsigned byte)399 inline void BinaryPropertyListSerializer::appendByte(unsigned byte)
400 {
401 *m_currentByte++ = byte;
402 ASSERT(m_currentByte <= m_currentAggregateBufferByte);
403 }
404
appendByte(unsigned long byte)405 inline void BinaryPropertyListSerializer::appendByte(unsigned long byte)
406 {
407 *m_currentByte++ = byte;
408 ASSERT(m_currentByte <= m_currentAggregateBufferByte);
409 }
410
appendByte(int byte)411 inline void BinaryPropertyListSerializer::appendByte(int byte)
412 {
413 *m_currentByte++ = byte;
414 ASSERT(m_currentByte <= m_currentAggregateBufferByte);
415 }
416
bytesNeeded(size_t count)417 static int bytesNeeded(size_t count)
418 {
419 ASSERT(count);
420 int bytesNeeded = 1;
421 for (size_t mask = numeric_limits<size_t>::max() << 8; count & mask; mask <<= 8)
422 ++bytesNeeded;
423 return bytesNeeded;
424 }
425
storeLength(UInt8 * destination,size_t length)426 static inline void storeLength(UInt8* destination, size_t length)
427 {
428 #ifdef __LP64__
429 destination[0] = length >> 56;
430 destination[1] = length >> 48;
431 destination[2] = length >> 40;
432 destination[3] = length >> 32;
433 #else
434 destination[0] = 0;
435 destination[1] = 0;
436 destination[2] = 0;
437 destination[3] = 0;
438 #endif
439 destination[4] = length >> 24;
440 destination[5] = length >> 16;
441 destination[6] = length >> 8;
442 destination[7] = length;
443 }
444
445 // Like memmove, but reverses the bytes.
moveAndReverseBytes(UInt8 * destination,const UInt8 * source,size_t length)446 static void moveAndReverseBytes(UInt8* destination, const UInt8* source, size_t length)
447 {
448 ASSERT(length);
449 memmove(destination, source, length);
450 UInt8* start = destination;
451 UInt8* end = destination + length;
452 while (end - start > 1)
453 std::swap(*start++, *--end);
454 }
455
456 // The serializer uses a single buffer for the property list.
457 // The buffer contains:
458 //
459 // 8-byte header
460 // object data
461 // offset table
462 // 32-byte trailer
463 //
464 // While serializing object, the offset table entry for each object is written just before
465 // the object data for that object is written. Aggregates, arrays and dictionaries, are a
466 // special case. The objects that go into an aggregate are written before the aggregate is.
467 // As each object is written, the object reference is put in the aggregate buffer. Then,
468 // when the aggregate is written, the aggregate buffer is copied into place in the object
469 // data. Finally, the header and trailer are written.
470 //
471 // The aggregate buffer shares space with the object data, like this:
472 //
473 // 8-byte header
474 // object data
475 // >>> aggregate buffer <<<
476 // offset table
477 // 32-byte trailer
478 //
479 // To make it easy to build it incrementally, the buffer starts at the end of the object
480 // data space, and grows backwards. We're guaranteed the aggregate buffer will never collide
481 // with the object data pointer because we know that the object data is correctly sized
482 // based on our plan, and all the data in the aggregate buffer will be used to create the
483 // actual aggregate objects; in the worst case the aggregate buffer will already be in
484 // exactly the right place, but backwards.
485
BinaryPropertyListSerializer(BinaryPropertyListWriter & client)486 BinaryPropertyListSerializer::BinaryPropertyListSerializer(BinaryPropertyListWriter& client)
487 : m_plan(client)
488 , m_objectReferenceSize(bytesNeeded(m_plan.objectCount()))
489 , m_offsetTableStart(headerSize + m_plan.byteCount() + m_plan.objectReferenceCount() * m_objectReferenceSize)
490 , m_offsetSize(bytesNeeded(m_offsetTableStart))
491 , m_bufferSize(m_offsetTableStart + m_plan.objectCount() * m_offsetSize + trailerSize)
492 , m_buffer(client.buffer(m_bufferSize))
493 , m_currentObjectReference(0)
494 {
495 ASSERT(m_objectReferenceSize > 0);
496 ASSERT(m_offsetSize > 0);
497
498 #ifdef __LP64__
499 ASSERT(m_objectReferenceSize <= 8);
500 ASSERT(m_offsetSize <= 8);
501 #else
502 ASSERT(m_objectReferenceSize <= 4);
503 ASSERT(m_offsetSize <= 4);
504 #endif
505
506 if (!m_buffer)
507 return;
508
509 // Write objects and offset table.
510 m_currentByte = m_buffer + headerSize;
511 m_currentAggregateBufferByte = m_buffer + m_offsetTableStart;
512 client.writeObjects(*this);
513 ASSERT(m_currentObjectReference == m_plan.objectCount());
514 ASSERT(m_currentAggregateBufferByte == m_buffer + m_offsetTableStart);
515 ASSERT(m_currentByte == m_buffer + m_offsetTableStart);
516
517 // Write header.
518 memcpy(m_buffer, "bplist00", headerSize);
519
520 // Write trailer.
521 UInt8* trailer = m_buffer + m_bufferSize - trailerSize;
522 memset(trailer, 0, 6);
523 trailer[6] = m_offsetSize;
524 trailer[7] = m_objectReferenceSize;
525 storeLength(trailer + 8, m_plan.objectCount());
526 storeLength(trailer + 16, m_plan.objectCount() - 1);
527 storeLength(trailer + 24, m_offsetTableStart);
528 }
529
writeBooleanTrue()530 void BinaryPropertyListSerializer::writeBooleanTrue()
531 {
532 ObjectReference reference = m_plan.booleanTrueObjectReference();
533 if (m_currentObjectReference != reference)
534 ASSERT(reference < m_currentObjectReference);
535 else {
536 startObject();
537 appendByte(booleanTrueMarkerByte);
538 }
539 addAggregateObjectReference(reference);
540 }
541
writeIntegerWithoutAddingAggregateObjectReference(int integer)542 inline ObjectReference BinaryPropertyListSerializer::writeIntegerWithoutAddingAggregateObjectReference(int integer)
543 {
544 ObjectReference reference = m_plan.integerObjectReference(integer);
545 if (m_currentObjectReference != reference)
546 ASSERT(reference < m_currentObjectReference);
547 else
548 appendIntegerObject(integer);
549 return reference;
550 }
551
writeInteger(int integer)552 void BinaryPropertyListSerializer::writeInteger(int integer)
553 {
554 addAggregateObjectReference(writeIntegerWithoutAddingAggregateObjectReference(integer));
555 }
556
writeString(const String & string)557 void BinaryPropertyListSerializer::writeString(const String& string)
558 {
559 ObjectReference reference = m_plan.stringObjectReference(string);
560 if (m_currentObjectReference != reference)
561 ASSERT(reference < m_currentObjectReference);
562 else
563 appendStringObject(string);
564 addAggregateObjectReference(reference);
565 }
566
writeIntegerArray(const int * integers,size_t size)567 void BinaryPropertyListSerializer::writeIntegerArray(const int* integers, size_t size)
568 {
569 ObjectReference reference = m_plan.integerArrayObjectReference(integers, size);
570 for (size_t i = 0; i < size; ++i)
571 writeIntegerWithoutAddingAggregateObjectReference(integers[i]);
572 if (m_currentObjectReference != reference)
573 ASSERT(reference < m_currentObjectReference);
574 else
575 appendIntegerArrayObject(integers, size);
576 addAggregateObjectReference(reference);
577 }
578
writeUniqueString(const char * string)579 void BinaryPropertyListSerializer::writeUniqueString(const char* string)
580 {
581 addAggregateObjectReference(m_currentObjectReference);
582 appendStringObject(string);
583 }
584
writeUniqueString(const String & string)585 void BinaryPropertyListSerializer::writeUniqueString(const String& string)
586 {
587 addAggregateObjectReference(m_currentObjectReference);
588 appendStringObject(string);
589 }
590
writeArrayStart()591 size_t BinaryPropertyListSerializer::writeArrayStart()
592 {
593 return m_currentAggregateBufferByte - m_buffer;
594 }
595
writeArrayEnd(size_t savedAggregateBufferOffset)596 void BinaryPropertyListSerializer::writeArrayEnd(size_t savedAggregateBufferOffset)
597 {
598 ObjectReference reference = m_currentObjectReference;
599 startObject();
600 size_t aggregateBufferByteCount = savedAggregateBufferOffset - (m_currentAggregateBufferByte - m_buffer);
601 ASSERT(aggregateBufferByteCount);
602 ASSERT(!(aggregateBufferByteCount % m_objectReferenceSize));
603 size_t size = aggregateBufferByteCount / m_objectReferenceSize;
604 if (size <= maxLengthInMarkerByte)
605 appendByte(arrayMarkerByte | size);
606 else {
607 appendByte(arrayWithSeparateLengthMarkerByte);
608 appendInteger(size);
609 }
610 m_currentAggregateBufferByte = m_buffer + savedAggregateBufferOffset;
611 ASSERT(m_currentByte <= m_currentAggregateBufferByte);
612 moveAndReverseBytes(m_currentByte, m_currentAggregateBufferByte - aggregateBufferByteCount, aggregateBufferByteCount);
613 m_currentByte += aggregateBufferByteCount;
614 ASSERT(m_currentByte <= m_currentAggregateBufferByte);
615 if (m_currentObjectReference < m_plan.objectCount())
616 addAggregateObjectReference(reference);
617 else
618 ASSERT(m_currentObjectReference == m_plan.objectCount());
619 }
620
writeDictionaryStart()621 size_t BinaryPropertyListSerializer::writeDictionaryStart()
622 {
623 return m_currentAggregateBufferByte - m_buffer;
624 }
625
writeDictionaryEnd(size_t savedAggregateBufferOffset)626 void BinaryPropertyListSerializer::writeDictionaryEnd(size_t savedAggregateBufferOffset)
627 {
628 ObjectReference reference = m_currentObjectReference;
629 startObject();
630 size_t aggregateBufferByteCount = savedAggregateBufferOffset - (m_currentAggregateBufferByte - m_buffer);
631 ASSERT(aggregateBufferByteCount);
632 ASSERT(!(aggregateBufferByteCount % (m_objectReferenceSize * 2)));
633 size_t size = aggregateBufferByteCount / (m_objectReferenceSize * 2);
634 if (size <= maxLengthInMarkerByte)
635 appendByte(dictionaryMarkerByte | size);
636 else {
637 appendByte(dictionaryWithSeparateLengthMarkerByte);
638 appendInteger(size);
639 }
640 m_currentAggregateBufferByte = m_buffer + savedAggregateBufferOffset;
641 ASSERT(m_currentByte <= m_currentAggregateBufferByte);
642 moveAndReverseBytes(m_currentByte, m_currentAggregateBufferByte - aggregateBufferByteCount, aggregateBufferByteCount);
643 m_currentByte += aggregateBufferByteCount;
644 ASSERT(m_currentByte <= m_currentAggregateBufferByte);
645 if (m_currentObjectReference != m_plan.objectCount())
646 addAggregateObjectReference(reference);
647 else
648 ASSERT(m_currentObjectReference == m_plan.objectCount());
649 }
650
appendIntegerObject(int integer)651 void BinaryPropertyListSerializer::appendIntegerObject(int integer)
652 {
653 startObject();
654 ASSERT(integer >= 0);
655 appendInteger(integer);
656 }
657
appendInteger(size_t integer)658 void BinaryPropertyListSerializer::appendInteger(size_t integer)
659 {
660 if (integer <= 0xFF) {
661 appendByte(oneByteIntegerMarkerByte);
662 appendByte(integer);
663 return;
664 }
665 if (integer <= 0xFFFF) {
666 appendByte(twoByteIntegerMarkerByte);
667 appendByte(integer >> 8);
668 appendByte(integer);
669 return;
670 }
671 #ifdef __LP64__
672 if (integer <= 0xFFFFFFFFULL) {
673 #endif
674 appendByte(fourByteIntegerMarkerByte);
675 appendByte(integer >> 24);
676 appendByte(integer >> 16);
677 appendByte(integer >> 8);
678 appendByte(integer);
679 #ifdef __LP64__
680 return;
681 }
682 appendByte(eightByteIntegerMarkerByte);
683 appendByte(integer >> 56);
684 appendByte(integer >> 48);
685 appendByte(integer >> 40);
686 appendByte(integer >> 32);
687 appendByte(integer >> 24);
688 appendByte(integer >> 16);
689 appendByte(integer >> 8);
690 appendByte(integer);
691 #endif
692 }
693
appendStringObject(const String & string)694 void BinaryPropertyListSerializer::appendStringObject(const String& string)
695 {
696 startObject();
697 const UChar* characters = string.characters();
698 unsigned length = string.length();
699 if (charactersAreAllASCII(characters, length)) {
700 if (length <= maxLengthInMarkerByte)
701 appendByte(asciiStringMarkerByte | length);
702 else {
703 appendByte(asciiStringWithSeparateLengthMarkerByte);
704 appendInteger(length);
705 }
706 for (unsigned i = 0; i < length; ++i)
707 appendByte(characters[i]);
708 } else {
709 if (length <= maxLengthInMarkerByte)
710 appendByte(unicodeStringMarkerByte | length);
711 else {
712 appendByte(unicodeStringWithSeparateLengthMarkerByte);
713 appendInteger(length);
714 }
715 for (unsigned i = 0; i < length; ++i) {
716 appendByte(characters[i] >> 8);
717 appendByte(characters[i]);
718 }
719 }
720 }
721
appendStringObject(const char * string)722 void BinaryPropertyListSerializer::appendStringObject(const char* string)
723 {
724 startObject();
725 unsigned length = strlen(string);
726 if (length <= maxLengthInMarkerByte)
727 appendByte(asciiStringMarkerByte | length);
728 else {
729 appendByte(asciiStringWithSeparateLengthMarkerByte);
730 appendInteger(length);
731 }
732 for (unsigned i = 0; i < length; ++i)
733 appendByte(string[i]);
734 }
735
appendIntegerArrayObject(const int * integers,size_t size)736 void BinaryPropertyListSerializer::appendIntegerArrayObject(const int* integers, size_t size)
737 {
738 startObject();
739 if (size <= maxLengthInMarkerByte)
740 appendByte(arrayMarkerByte | size);
741 else {
742 appendByte(arrayWithSeparateLengthMarkerByte);
743 appendInteger(size);
744 }
745 for (unsigned i = 0; i < size; ++i)
746 appendObjectReference(m_plan.integerObjectReference(integers[i]));
747 }
748
appendObjectReference(ObjectReference reference)749 void BinaryPropertyListSerializer::appendObjectReference(ObjectReference reference)
750 {
751 switch (m_objectReferenceSize) {
752 #ifdef __LP64__
753 case 8:
754 appendByte(reference >> 56);
755 case 7:
756 appendByte(reference >> 48);
757 case 6:
758 appendByte(reference >> 40);
759 case 5:
760 appendByte(reference >> 32);
761 #endif
762 case 4:
763 appendByte(reference >> 24);
764 case 3:
765 appendByte(reference >> 16);
766 case 2:
767 appendByte(reference >> 8);
768 case 1:
769 appendByte(reference);
770 }
771 }
772
startObject()773 void BinaryPropertyListSerializer::startObject()
774 {
775 ObjectReference reference = m_currentObjectReference++;
776
777 size_t offset = m_currentByte - m_buffer;
778
779 UInt8* offsetTableEntry = m_buffer + m_offsetTableStart + reference * m_offsetSize + m_offsetSize;
780 switch (m_offsetSize) {
781 #ifdef __LP64__
782 case 8:
783 offsetTableEntry[-8] = offset >> 56;
784 case 7:
785 offsetTableEntry[-7] = offset >> 48;
786 case 6:
787 offsetTableEntry[-6] = offset >> 40;
788 case 5:
789 offsetTableEntry[-5] = offset >> 32;
790 #endif
791 case 4:
792 offsetTableEntry[-4] = offset >> 24;
793 case 3:
794 offsetTableEntry[-3] = offset >> 16;
795 case 2:
796 offsetTableEntry[-2] = offset >> 8;
797 case 1:
798 offsetTableEntry[-1] = offset;
799 }
800 }
801
addAggregateObjectReference(ObjectReference reference)802 void BinaryPropertyListSerializer::addAggregateObjectReference(ObjectReference reference)
803 {
804 switch (m_objectReferenceSize) {
805 #ifdef __LP64__
806 case 8:
807 *--m_currentAggregateBufferByte = reference >> 56;
808 case 7:
809 *--m_currentAggregateBufferByte = reference >> 48;
810 case 6:
811 *--m_currentAggregateBufferByte = reference >> 40;
812 case 5:
813 *--m_currentAggregateBufferByte = reference >> 32;
814 #endif
815 case 4:
816 *--m_currentAggregateBufferByte = reference >> 24;
817 case 3:
818 *--m_currentAggregateBufferByte = reference >> 16;
819 case 2:
820 *--m_currentAggregateBufferByte = reference >> 8;
821 case 1:
822 *--m_currentAggregateBufferByte = reference;
823 }
824 ASSERT(m_currentByte <= m_currentAggregateBufferByte);
825 }
826
writePropertyList()827 void BinaryPropertyListWriter::writePropertyList()
828 {
829 BinaryPropertyListSerializer(*this);
830 }
831
832 }
833