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 "StringHash.h" 30 #include <wtf/HashMap.h> 31 #include <wtf/HashSet.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 StringImpl::computeHash(reinterpret_cast<const UChar*>(array.integers()), array.size() / (sizeof(int) / sizeof(UChar))); 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