• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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