win64 compile error fix for BinaryPropertyList.cpp
[WebKit-https.git] / Source / WebCore / platform / cf / BinaryPropertyList.cpp
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:
58     IntegerArray() : m_integers(0), m_size(0) { }
59     IntegerArray(const int* integers, size_t size) : m_integers(integers), m_size(size) { ASSERT(integers); ASSERT(size); }
60
61     void markDeleted() { m_integers = 0; m_size = deletedValueSize(); }
62     bool isDeletedValue() const { return m_size == deletedValueSize(); }
63
64     const int* integers() const { ASSERT(!isDeletedValue()); return m_integers; }
65     size_t size() const { ASSERT(!isDeletedValue()); return m_size; }
66
67 private:
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
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;
83     static void constructDeletedValue(IntegerArray& slot) { slot.markDeleted(); }
84     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
93 unsigned IntegerArrayHash::hash(const IntegerArray& array)
94 {
95     return StringHasher::hashMemory(array.integers(), array.size() * sizeof(int));
96 }
97
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
122     ObjectReference objectCount() const { return m_currentObjectReference; }
123
124     ObjectReference byteCount() const { return m_byteCount; }
125     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
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
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
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
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
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).isNewEntry)
208             return;
209     }
210     ++m_currentObjectReference;
211     m_byteCount += integerByteCount(integer);
212 }
213
214 void BinaryPropertyListPlan::writeString(const String& string)
215 {
216     ++m_currentAggregateSize;
217     if (!m_strings.add(string, m_currentObjectReference).isNewEntry)
218         return;
219     ++m_currentObjectReference;
220     writeStringObject(string);
221 }
222
223 void BinaryPropertyListPlan::writeIntegerArray(const int* integers, size_t size)
224 {
225     size_t savedAggregateSize = ++m_currentAggregateSize;
226     ASSERT(size);
227     IntegerArrayMap::AddResult addResult = m_integerArrays.add(IntegerArray(integers, size), 0);
228     if (!addResult.isNewEntry)
229         return;
230     for (size_t i = 0; i < size; ++i)
231         writeInteger(integers[i]);
232     addResult.iterator->second = m_currentObjectReference++;
233     writeArrayObject(size);
234     m_currentAggregateSize = savedAggregateSize;
235 }
236
237 void BinaryPropertyListPlan::writeUniqueString(const String& string)
238 {
239     ++m_currentAggregateSize;
240     ++m_currentObjectReference;
241     writeStringObject(string);
242 }
243
244 void BinaryPropertyListPlan::writeUniqueString(const char* string)
245 {
246     ++m_currentAggregateSize;
247     ++m_currentObjectReference;
248     writeStringObject(string);
249 }
250
251 size_t BinaryPropertyListPlan::writeArrayStart()
252 {
253     size_t savedAggregateSize = m_currentAggregateSize;
254     m_currentAggregateSize = 0;
255     return savedAggregateSize;
256 }
257
258 void BinaryPropertyListPlan::writeArrayEnd(size_t savedAggregateSize)
259 {
260     ++m_currentObjectReference;
261     writeArrayObject(m_currentAggregateSize);
262     m_currentAggregateSize = savedAggregateSize + 1;
263 }
264
265 size_t BinaryPropertyListPlan::writeDictionaryStart()
266 {
267     size_t savedAggregateSize = m_currentAggregateSize;
268     m_currentAggregateSize = 0;
269     return savedAggregateSize;
270 }
271
272 void BinaryPropertyListPlan::writeDictionaryEnd(size_t savedAggregateSize)
273 {
274     ++m_currentObjectReference;
275     writeDictionaryObject(m_currentAggregateSize);
276     m_currentAggregateSize = savedAggregateSize + 1;
277 }
278
279 static size_t markerPlusLengthByteCount(size_t length)
280 {
281     if (length <= maxLengthInMarkerByte)
282         return 1;
283     return 1 + integerByteCount(length);
284 }
285
286 void BinaryPropertyListPlan::writeStringObject(const String& string)
287 {
288     unsigned length = string.length();
289     m_byteCount += markerPlusLengthByteCount(length) + length;
290     if (!string.containsOnlyASCII())
291         m_byteCount += length;
292 }
293
294 void BinaryPropertyListPlan::writeStringObject(const char* string)
295 {
296     unsigned length = strlen(string);
297     m_byteCount += markerPlusLengthByteCount(length) + length;
298 }
299
300 void BinaryPropertyListPlan::writeArrayObject(size_t size)
301 {
302     ASSERT(size);
303     m_byteCount += markerPlusLengthByteCount(size);
304     m_objectReferenceCount += size;
305 }
306
307 void BinaryPropertyListPlan::writeDictionaryObject(size_t size)
308 {
309     ASSERT(size);
310     ASSERT(!(size & 1));
311     m_byteCount += markerPlusLengthByteCount(size / 2);
312     m_objectReferenceCount += size;
313 }
314
315 ObjectReference BinaryPropertyListPlan::booleanTrueObjectReference() const
316 {
317     ASSERT(m_booleanTrueObjectReference != invalidObjectReference());
318     return m_booleanTrueObjectReference;
319 }
320
321 ObjectReference BinaryPropertyListPlan::integerObjectReference(int integer) const
322 {
323     ASSERT(integer >= 0);
324     if (!integer) {
325         ASSERT(m_integerZeroObjectReference != invalidObjectReference());
326         return m_integerZeroObjectReference;
327     }
328     ASSERT(m_integers.contains(integer));
329     return m_integers.get(integer);
330 }
331
332 ObjectReference BinaryPropertyListPlan::stringObjectReference(const String& string) const
333 {
334     ASSERT(m_strings.contains(string));
335     return m_strings.get(string);
336 }
337
338 ObjectReference BinaryPropertyListPlan::integerArrayObjectReference(const int* integers, size_t size) const
339 {
340     ASSERT(m_integerArrays.contains(IntegerArray(integers, size)));
341     return m_integerArrays.get(IntegerArray(integers, size));
342 }
343
344 class BinaryPropertyListSerializer : private BinaryPropertyListObjectStream {
345 public:
346     BinaryPropertyListSerializer(BinaryPropertyListWriter&);
347
348 private:
349     virtual void writeBooleanTrue();
350     virtual void writeInteger(int);
351     virtual void writeString(const String&);
352     virtual void writeIntegerArray(const int*, size_t);
353     virtual void writeUniqueString(const String&);
354     virtual void writeUniqueString(const char*);
355     virtual size_t writeArrayStart();
356     virtual void writeArrayEnd(size_t);
357     virtual size_t writeDictionaryStart();
358     virtual void writeDictionaryEnd(size_t);
359
360     ObjectReference writeIntegerWithoutAddingAggregateObjectReference(int);
361
362     void appendIntegerObject(int);
363     void appendStringObject(const String&);
364     void appendStringObject(const char*);
365     void appendIntegerArrayObject(const int*, size_t);
366
367     void appendByte(unsigned char);
368     void appendByte(unsigned);
369     void appendByte(unsigned long);
370     void appendByte(int);
371
372     void appendInteger(size_t);
373
374     void appendObjectReference(ObjectReference);
375
376     void addAggregateObjectReference(ObjectReference);
377
378     void startObject();
379
380     const BinaryPropertyListPlan m_plan;
381     const int m_objectReferenceSize;
382     const size_t m_offsetTableStart;
383     const int m_offsetSize;
384     const size_t m_bufferSize;
385     UInt8* const m_buffer;
386
387     UInt8* m_currentByte;
388     ObjectReference m_currentObjectReference;
389     UInt8* m_currentAggregateBufferByte;
390 };
391
392 inline void BinaryPropertyListSerializer::appendByte(unsigned char byte)
393 {
394     *m_currentByte++ = byte;
395     ASSERT(m_currentByte <= m_currentAggregateBufferByte);
396 }
397
398 inline void BinaryPropertyListSerializer::appendByte(unsigned byte)
399 {
400     *m_currentByte++ = byte;
401     ASSERT(m_currentByte <= m_currentAggregateBufferByte);
402 }
403
404 inline void BinaryPropertyListSerializer::appendByte(unsigned long byte)
405 {
406     *m_currentByte++ = byte;
407     ASSERT(m_currentByte <= m_currentAggregateBufferByte);
408 }
409
410 inline void BinaryPropertyListSerializer::appendByte(int byte)
411 {
412     *m_currentByte++ = byte;
413     ASSERT(m_currentByte <= m_currentAggregateBufferByte);
414 }
415
416 static int bytesNeeded(size_t count)
417 {
418     ASSERT(count);
419     int bytesNeeded = 1;
420     for (size_t mask = numeric_limits<size_t>::max() << 8; count & mask; mask <<= 8)
421         ++bytesNeeded;
422     return bytesNeeded;
423 }
424
425 static inline void storeLength(UInt8* destination, size_t length)
426 {
427 #ifdef __LP64__
428     destination[0] = length >> 56;
429     destination[1] = length >> 48;
430     destination[2] = length >> 40;
431     destination[3] = length >> 32;
432 #else
433     destination[0] = 0;
434     destination[1] = 0;
435     destination[2] = 0;
436     destination[3] = 0;
437 #endif
438     destination[4] = length >> 24;
439     destination[5] = length >> 16;
440     destination[6] = length >> 8;
441     destination[7] = length;
442 }
443
444 // Like memmove, but reverses the bytes.
445 static void moveAndReverseBytes(UInt8* destination, const UInt8* source, size_t length)
446 {
447     ASSERT(length);
448     memmove(destination, source, length);
449     UInt8* start = destination;
450     UInt8* end = destination + length;
451     while (end - start > 1)
452         std::swap(*start++, *--end);
453 }
454
455 // The serializer uses a single buffer for the property list.
456 // The buffer contains:
457 //
458 //    8-byte header
459 //    object data
460 //    offset table
461 //    32-byte trailer
462 //
463 // While serializing object, the offset table entry for each object is written just before
464 // the object data for that object is written. Aggregates, arrays and dictionaries, are a
465 // special case. The objects that go into an aggregate are written before the aggregate is.
466 // As each object is written, the object reference is put in the aggregate buffer. Then,
467 // when the aggregate is written, the aggregate buffer is copied into place in the object
468 // data. Finally, the header and trailer are written.
469 //
470 // The aggregate buffer shares space with the object data, like this:
471 //
472 //    8-byte header
473 //    object data
474 //    >>> aggregate buffer <<<
475 //    offset table
476 //    32-byte trailer
477 //
478 // To make it easy to build it incrementally, the buffer starts at the end of the object
479 // data space, and grows backwards. We're guaranteed the aggregate buffer will never collide
480 // with the object data pointer because we know that the object data is correctly sized
481 // based on our plan, and all the data in the aggregate buffer will be used to create the
482 // actual aggregate objects; in the worst case the aggregate buffer will already be in
483 // exactly the right place, but backwards.
484
485 BinaryPropertyListSerializer::BinaryPropertyListSerializer(BinaryPropertyListWriter& client)
486     : m_plan(client)
487     , m_objectReferenceSize(bytesNeeded(m_plan.objectCount()))
488     , m_offsetTableStart(headerSize + m_plan.byteCount() + m_plan.objectReferenceCount() * m_objectReferenceSize)
489     , m_offsetSize(bytesNeeded(m_offsetTableStart))
490     , m_bufferSize(m_offsetTableStart + m_plan.objectCount() * m_offsetSize + trailerSize)
491     , m_buffer(client.buffer(m_bufferSize))
492     , m_currentObjectReference(0)
493 {
494     ASSERT(m_objectReferenceSize > 0);
495     ASSERT(m_offsetSize > 0);
496
497 #ifdef __LP64__
498     ASSERT(m_objectReferenceSize <= 8);
499     ASSERT(m_offsetSize <= 8);
500 #else
501     ASSERT(m_objectReferenceSize <= 4);
502     ASSERT(m_offsetSize <= 4);
503 #endif
504
505     if (!m_buffer)
506         return;
507
508     // Write objects and offset table.
509     m_currentByte = m_buffer + headerSize;
510     m_currentAggregateBufferByte = m_buffer + m_offsetTableStart;
511     client.writeObjects(*this);
512     ASSERT(m_currentObjectReference == m_plan.objectCount());
513     ASSERT(m_currentAggregateBufferByte == m_buffer + m_offsetTableStart);
514     ASSERT(m_currentByte == m_buffer + m_offsetTableStart);
515
516     // Write header.
517     memcpy(m_buffer, "bplist00", headerSize);
518
519     // Write trailer.
520     UInt8* trailer = m_buffer + m_bufferSize - trailerSize;
521     memset(trailer, 0, 6);
522     trailer[6] = m_offsetSize;
523     trailer[7] = m_objectReferenceSize;
524     storeLength(trailer + 8, m_plan.objectCount());
525     storeLength(trailer + 16, m_plan.objectCount() - 1);
526     storeLength(trailer + 24, m_offsetTableStart);
527 }
528
529 void BinaryPropertyListSerializer::writeBooleanTrue()
530 {
531     ObjectReference reference = m_plan.booleanTrueObjectReference();
532     if (m_currentObjectReference != reference)
533         ASSERT(reference < m_currentObjectReference);
534     else {
535         startObject();
536         appendByte(booleanTrueMarkerByte);
537     }
538     addAggregateObjectReference(reference);
539 }
540
541 inline ObjectReference BinaryPropertyListSerializer::writeIntegerWithoutAddingAggregateObjectReference(int integer)
542 {
543     ObjectReference reference = m_plan.integerObjectReference(integer);
544     if (m_currentObjectReference != reference)
545         ASSERT(reference < m_currentObjectReference);
546     else
547         appendIntegerObject(integer);
548     return reference;
549 }
550
551 void BinaryPropertyListSerializer::writeInteger(int integer)
552 {
553     addAggregateObjectReference(writeIntegerWithoutAddingAggregateObjectReference(integer));
554 }
555
556 void BinaryPropertyListSerializer::writeString(const String& string)
557 {
558     ObjectReference reference = m_plan.stringObjectReference(string);
559     if (m_currentObjectReference != reference)
560         ASSERT(reference < m_currentObjectReference);
561     else
562         appendStringObject(string);
563     addAggregateObjectReference(reference);
564 }
565
566 void BinaryPropertyListSerializer::writeIntegerArray(const int* integers, size_t size)
567 {
568     ObjectReference reference = m_plan.integerArrayObjectReference(integers, size);
569     for (size_t i = 0; i < size; ++i)
570         writeIntegerWithoutAddingAggregateObjectReference(integers[i]);
571     if (m_currentObjectReference != reference)
572         ASSERT(reference < m_currentObjectReference);
573     else
574         appendIntegerArrayObject(integers, size);
575     addAggregateObjectReference(reference);
576 }
577
578 void BinaryPropertyListSerializer::writeUniqueString(const char* string)
579 {
580     addAggregateObjectReference(m_currentObjectReference);
581     appendStringObject(string);
582 }
583
584 void BinaryPropertyListSerializer::writeUniqueString(const String& string)
585 {
586     addAggregateObjectReference(m_currentObjectReference);
587     appendStringObject(string);
588 }
589
590 size_t BinaryPropertyListSerializer::writeArrayStart()
591 {
592     return m_currentAggregateBufferByte - m_buffer;
593 }
594
595 void BinaryPropertyListSerializer::writeArrayEnd(size_t savedAggregateBufferOffset)
596 {
597     ObjectReference reference = m_currentObjectReference;
598     startObject();
599     size_t aggregateBufferByteCount = savedAggregateBufferOffset - (m_currentAggregateBufferByte - m_buffer);
600     ASSERT(aggregateBufferByteCount);
601     ASSERT(!(aggregateBufferByteCount % m_objectReferenceSize));
602     size_t size = aggregateBufferByteCount / m_objectReferenceSize;
603     if (size <= maxLengthInMarkerByte)
604         appendByte(arrayMarkerByte | size);
605     else {
606         appendByte(arrayWithSeparateLengthMarkerByte);
607         appendInteger(size);
608     }
609     m_currentAggregateBufferByte = m_buffer + savedAggregateBufferOffset;
610     ASSERT(m_currentByte <= m_currentAggregateBufferByte);
611     moveAndReverseBytes(m_currentByte, m_currentAggregateBufferByte - aggregateBufferByteCount, aggregateBufferByteCount);
612     m_currentByte += aggregateBufferByteCount;
613     ASSERT(m_currentByte <= m_currentAggregateBufferByte);
614     if (m_currentObjectReference < m_plan.objectCount())
615         addAggregateObjectReference(reference);
616     else
617         ASSERT(m_currentObjectReference == m_plan.objectCount());
618 }
619
620 size_t BinaryPropertyListSerializer::writeDictionaryStart()
621 {
622     return m_currentAggregateBufferByte - m_buffer;
623 }
624
625 void BinaryPropertyListSerializer::writeDictionaryEnd(size_t savedAggregateBufferOffset)
626 {
627     ObjectReference reference = m_currentObjectReference;
628     startObject();
629     size_t aggregateBufferByteCount = savedAggregateBufferOffset - (m_currentAggregateBufferByte - m_buffer);
630     ASSERT(aggregateBufferByteCount);
631     ASSERT(!(aggregateBufferByteCount % (m_objectReferenceSize * 2)));
632     size_t size = aggregateBufferByteCount / (m_objectReferenceSize * 2);
633     if (size <= maxLengthInMarkerByte)
634         appendByte(dictionaryMarkerByte | size);
635     else {
636         appendByte(dictionaryWithSeparateLengthMarkerByte);
637         appendInteger(size);
638     }
639     m_currentAggregateBufferByte = m_buffer + savedAggregateBufferOffset;
640     ASSERT(m_currentByte <= m_currentAggregateBufferByte);
641     moveAndReverseBytes(m_currentByte, m_currentAggregateBufferByte - aggregateBufferByteCount, aggregateBufferByteCount);
642     m_currentByte += aggregateBufferByteCount;
643     ASSERT(m_currentByte <= m_currentAggregateBufferByte);
644     if (m_currentObjectReference != m_plan.objectCount())
645         addAggregateObjectReference(reference);
646     else
647         ASSERT(m_currentObjectReference == m_plan.objectCount());
648 }
649
650 void BinaryPropertyListSerializer::appendIntegerObject(int integer)
651 {
652     startObject();
653     ASSERT(integer >= 0);
654     appendInteger(integer);
655 }
656
657 void BinaryPropertyListSerializer::appendInteger(size_t integer)
658 {
659     if (integer <= 0xFF) {
660         appendByte(oneByteIntegerMarkerByte);
661         appendByte(integer);
662         return;
663     }
664     if (integer <= 0xFFFF) {
665         appendByte(twoByteIntegerMarkerByte);
666         appendByte(integer >> 8);
667         appendByte(integer);
668         return;
669     }
670 #ifdef __LP64__
671     if (integer <= 0xFFFFFFFFULL) {
672 #endif
673         appendByte(fourByteIntegerMarkerByte);
674         appendByte(integer >> 24);
675         appendByte(integer >> 16);
676         appendByte(integer >> 8);
677         appendByte(integer);
678 #ifdef __LP64__
679         return;
680     }
681     appendByte(eightByteIntegerMarkerByte);
682     appendByte(integer >> 56);
683     appendByte(integer >> 48);
684     appendByte(integer >> 40);
685     appendByte(integer >> 32);
686     appendByte(integer >> 24);
687     appendByte(integer >> 16);
688     appendByte(integer >> 8);
689     appendByte(integer);
690 #endif
691 }
692
693 void BinaryPropertyListSerializer::appendStringObject(const String& string)
694 {
695     startObject();
696     const UChar* characters = string.characters();
697     unsigned length = string.length();
698     if (charactersAreAllASCII(characters, length)) {
699         if (length <= maxLengthInMarkerByte)
700             appendByte(static_cast<unsigned char>(asciiStringMarkerByte | length));
701         else {
702             appendByte(asciiStringWithSeparateLengthMarkerByte);
703             appendInteger(length);
704         }
705         for (unsigned i = 0; i < length; ++i)
706             appendByte(characters[i]);
707     } else {
708         if (length <= maxLengthInMarkerByte)
709             appendByte(static_cast<unsigned char>(unicodeStringMarkerByte | length));
710         else {
711             appendByte(unicodeStringWithSeparateLengthMarkerByte);
712             appendInteger(length);
713         }
714         for (unsigned i = 0; i < length; ++i) {
715             appendByte(characters[i] >> 8);
716             appendByte(characters[i]);
717         }
718     }
719 }
720
721 void BinaryPropertyListSerializer::appendStringObject(const char* string)
722 {
723     startObject();
724     unsigned length = strlen(string);
725     if (length <= maxLengthInMarkerByte)
726         appendByte(static_cast<unsigned char>(asciiStringMarkerByte | length));
727     else {
728         appendByte(asciiStringWithSeparateLengthMarkerByte);
729         appendInteger(length);
730     }
731     for (unsigned i = 0; i < length; ++i)
732         appendByte(string[i]);
733 }
734
735 void BinaryPropertyListSerializer::appendIntegerArrayObject(const int* integers, size_t size)
736 {
737     startObject();
738     if (size <= maxLengthInMarkerByte)
739         appendByte(arrayMarkerByte | size);
740     else {
741         appendByte(arrayWithSeparateLengthMarkerByte);
742         appendInteger(size);
743     }
744     for (unsigned i = 0; i < size; ++i)
745         appendObjectReference(m_plan.integerObjectReference(integers[i]));
746 }
747
748 void BinaryPropertyListSerializer::appendObjectReference(ObjectReference reference)
749 {
750     switch (m_objectReferenceSize) {
751 #ifdef __LP64__
752         case 8:
753             appendByte(reference >> 56);
754         case 7:
755             appendByte(reference >> 48);
756         case 6:
757             appendByte(reference >> 40);
758         case 5:
759             appendByte(reference >> 32);
760 #endif
761         case 4:
762             appendByte(reference >> 24);
763         case 3:
764             appendByte(reference >> 16);
765         case 2:
766             appendByte(reference >> 8);
767         case 1:
768             appendByte(reference);
769     }
770 }
771
772 void BinaryPropertyListSerializer::startObject()
773 {
774     ObjectReference reference = m_currentObjectReference++;
775
776     size_t offset = m_currentByte - m_buffer;
777
778     UInt8* offsetTableEntry = m_buffer + m_offsetTableStart + reference * m_offsetSize + m_offsetSize;
779     switch (m_offsetSize) {
780 #ifdef __LP64__
781         case 8:
782             offsetTableEntry[-8] = offset >> 56;
783         case 7:
784             offsetTableEntry[-7] = offset >> 48;
785         case 6:
786             offsetTableEntry[-6] = offset >> 40;
787         case 5:
788             offsetTableEntry[-5] = offset >> 32;
789 #endif
790         case 4:
791             offsetTableEntry[-4] = offset >> 24;
792         case 3:
793             offsetTableEntry[-3] = offset >> 16;
794         case 2:
795             offsetTableEntry[-2] = offset >> 8;
796         case 1:
797             offsetTableEntry[-1] = offset;
798     }
799 }
800
801 void BinaryPropertyListSerializer::addAggregateObjectReference(ObjectReference reference)
802 {
803     switch (m_objectReferenceSize) {
804 #ifdef __LP64__
805         case 8:
806             *--m_currentAggregateBufferByte = reference >> 56;
807         case 7:
808             *--m_currentAggregateBufferByte = reference >> 48;
809         case 6:
810             *--m_currentAggregateBufferByte = reference >> 40;
811         case 5:
812             *--m_currentAggregateBufferByte = reference >> 32;
813 #endif
814         case 4:
815             *--m_currentAggregateBufferByte = reference >> 24;
816         case 3:
817             *--m_currentAggregateBufferByte = reference >> 16;
818         case 2:
819             *--m_currentAggregateBufferByte = reference >> 8;
820         case 1:
821             *--m_currentAggregateBufferByte = reference;
822     }
823     ASSERT(m_currentByte <= m_currentAggregateBufferByte);
824 }
825
826 void BinaryPropertyListWriter::writePropertyList()
827 {
828     BinaryPropertyListSerializer serializer(*this);
829 }
830
831 }