Home | History | Annotate | Download | only in cf
      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).second)
    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).second)
    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     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 
    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     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 
    295 void BinaryPropertyListPlan::writeStringObject(const char* string)
    296 {
    297     unsigned length = strlen(string);
    298     m_byteCount += markerPlusLengthByteCount(length) + length;
    299 }
    300 
    301 void BinaryPropertyListPlan::writeArrayObject(size_t size)
    302 {
    303     ASSERT(size);
    304     m_byteCount += markerPlusLengthByteCount(size);
    305     m_objectReferenceCount += size;
    306 }
    307 
    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 
    316 ObjectReference BinaryPropertyListPlan::booleanTrueObjectReference() const
    317 {
    318     ASSERT(m_booleanTrueObjectReference != invalidObjectReference());
    319     return m_booleanTrueObjectReference;
    320 }
    321 
    322 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 
    333 ObjectReference BinaryPropertyListPlan::stringObjectReference(const String& string) const
    334 {
    335     ASSERT(m_strings.contains(string));
    336     return m_strings.get(string);
    337 }
    338 
    339 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 
    393 inline void BinaryPropertyListSerializer::appendByte(unsigned char byte)
    394 {
    395     *m_currentByte++ = byte;
    396     ASSERT(m_currentByte <= m_currentAggregateBufferByte);
    397 }
    398 
    399 inline void BinaryPropertyListSerializer::appendByte(unsigned byte)
    400 {
    401     *m_currentByte++ = byte;
    402     ASSERT(m_currentByte <= m_currentAggregateBufferByte);
    403 }
    404 
    405 inline void BinaryPropertyListSerializer::appendByte(unsigned long byte)
    406 {
    407     *m_currentByte++ = byte;
    408     ASSERT(m_currentByte <= m_currentAggregateBufferByte);
    409 }
    410 
    411 inline void BinaryPropertyListSerializer::appendByte(int byte)
    412 {
    413     *m_currentByte++ = byte;
    414     ASSERT(m_currentByte <= m_currentAggregateBufferByte);
    415 }
    416 
    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 
    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.
    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 
    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 
    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 
    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 
    552 void BinaryPropertyListSerializer::writeInteger(int integer)
    553 {
    554     addAggregateObjectReference(writeIntegerWithoutAddingAggregateObjectReference(integer));
    555 }
    556 
    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 
    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 
    579 void BinaryPropertyListSerializer::writeUniqueString(const char* string)
    580 {
    581     addAggregateObjectReference(m_currentObjectReference);
    582     appendStringObject(string);
    583 }
    584 
    585 void BinaryPropertyListSerializer::writeUniqueString(const String& string)
    586 {
    587     addAggregateObjectReference(m_currentObjectReference);
    588     appendStringObject(string);
    589 }
    590 
    591 size_t BinaryPropertyListSerializer::writeArrayStart()
    592 {
    593     return m_currentAggregateBufferByte - m_buffer;
    594 }
    595 
    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 
    621 size_t BinaryPropertyListSerializer::writeDictionaryStart()
    622 {
    623     return m_currentAggregateBufferByte - m_buffer;
    624 }
    625 
    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 
    651 void BinaryPropertyListSerializer::appendIntegerObject(int integer)
    652 {
    653     startObject();
    654     ASSERT(integer >= 0);
    655     appendInteger(integer);
    656 }
    657 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    827 void BinaryPropertyListWriter::writePropertyList()
    828 {
    829     BinaryPropertyListSerializer(*this);
    830 }
    831 
    832 }
    833