diff --git a/classes/CFPropertyList/CFBinaryPropertyList.php b/classes/CFPropertyList/CFBinaryPropertyList.php index e734088..34cb708 100644 --- a/classes/CFPropertyList/CFBinaryPropertyList.php +++ b/classes/CFPropertyList/CFBinaryPropertyList.php @@ -422,6 +422,10 @@ function readBinaryObject() { case '6': // unicode string (utf16be) $retval = $this->readBinaryUnicodeString($object_length); break; + case '8': + $num = $this->readBinaryInt($object_length); + $retval = new CFUid($num->getValue()); + break; case 'a': // array $retval = $this->readBinaryArray($object_length); break; @@ -892,6 +896,49 @@ protected function realToBinary($val) { return $bdata.strrev(pack("d", (float)$val)); } + public function uidToBinary($value) { + $saved_object_count = $this->writtenObjectCount++; + + $val = ""; + + $nbytes = 0; + if($value > 0xFF) $nbytes = 1; // 1 byte integer + if($value > 0xFFFF) $nbytes += 1; // 4 byte integer + if($value > 0xFFFFFFFF) $nbytes += 1; // 8 byte integer + if($value < 0) $nbytes = 3; // 8 byte integer, since signed + + $bdata = self::typeBytes("1000", $nbytes); // 1 is 0001, type indicator for integer + $buff = ""; + + if($nbytes < 3) { + if($nbytes == 0) $fmt = "C"; + elseif($nbytes == 1) $fmt = "n"; + else $fmt = "N"; + + $buff = pack($fmt, $value); + } + else { + if(PHP_INT_SIZE > 4) { + // 64 bit signed integer; we need the higher and the lower 32 bit of the value + $high_word = $value >> 32; + $low_word = $value & 0xFFFFFFFF; + } + else { + // since PHP can only handle 32bit signed, we can only get 32bit signed values at this point - values above 0x7FFFFFFF are + // floats. So we ignore the existance of 64bit on non-64bit-machines + if($value < 0) $high_word = 0xFFFFFFFF; + else $high_word = 0; + $low_word = $value; + } + $buff = pack("N", $high_word).pack("N", $low_word); + } + + $val = $bdata.$buff; + + $this->objectTable[$saved_object_count] = $val; + return $saved_object_count; + } + /** * Converts a numeric value to binary and adds it to the object table * @param numeric $value The numeric value diff --git a/classes/CFPropertyList/CFPropertyList.php b/classes/CFPropertyList/CFPropertyList.php index eff66fc..0e07b7c 100644 --- a/classes/CFPropertyList/CFPropertyList.php +++ b/classes/CFPropertyList/CFPropertyList.php @@ -319,6 +319,14 @@ protected function import(DOMNode $node, $parent) { case 'dict': $value = new $class(); $this->import($n, $value); + + if($value instanceof CFDictionary) { + $hsh = $value->getValue(); + if(isset($hsh['CF$UID']) && count($hsh) == 1) { + $value = new CFUid($hsh['CF$UID']->getValue()); + } + } + break; } diff --git a/classes/CFPropertyList/CFType.php b/classes/CFPropertyList/CFType.php index a00337b..ba2e57a 100644 --- a/classes/CFPropertyList/CFType.php +++ b/classes/CFPropertyList/CFType.php @@ -121,6 +121,19 @@ public function toBinary(CFBinaryPropertyList &$bplist) { } } +class CFUid extends CFType { + public + function toXML(DOMDocument $doc,$nodeName="") { + $obj = new CFDictionary(array('CF$UID' => new CFNumber($this->value))); + return $obj->toXml($doc); + } + + public + function toBinary(CFBinaryPropertyList &$bplist) { + return $bplist->uidToBinary($this->value); + } +} + /** * Number Type of CFPropertyList * @author Rodney Rehm diff --git a/tests/BinaryParseTest.php b/tests/BinaryParseTest.php index b24992d..d871716 100644 --- a/tests/BinaryParseTest.php +++ b/tests/BinaryParseTest.php @@ -11,6 +11,7 @@ if(!defined('TEST_BINARY_DATA_FILE')) { define('TEST_BINARY_DATA_FILE',__DIR__.'/binary-data.plist'); + define('TEST_UID_BPLIST', __DIR__ . '/uid-list.plist'); } require_once(LIBDIR.'/CFPropertyList.php'); @@ -107,6 +108,15 @@ public function testInvalidString() { $this->fail('No exception thrown for invalid string!'); } + public function testUidPlist() { + $plist = new CFPropertyList(TEST_UID_BPLIST); + $val = $plist->toArray(); + $this->assertEquals(array('test' => 1), $val); + + $v = $plist->getValue()->getValue(); + $this->assertTrue($v['test'] instanceof CFUid); + } + } # eof diff --git a/tests/ParseXMLTest.php b/tests/ParseXMLTest.php index 23649fc..4fde8db 100644 --- a/tests/ParseXMLTest.php +++ b/tests/ParseXMLTest.php @@ -11,6 +11,7 @@ if(!defined('TEST_XML_DATA_FILE')) { define('TEST_XML_DATA_FILE',__DIR__.'/xml-data.plist'); + define('TEST_UID_XML_PLIST', __DIR__ . '/uid-list.xml'); } require_once(LIBDIR.'/CFPropertyList.php'); @@ -113,6 +114,13 @@ public function testInvalidString() { $this->fail('No exception thrown for invalid string!'); } + public function testUidPlist() { + $plist = new CFPropertyList(TEST_UID_XML_PLIST); + $val = $plist->toArray(); + $this->assertEquals(array('test' => 1), $val); + $v = $plist->getValue()->getValue(); + $this->assertTrue($v['test'] instanceof CFUid); + } } # eof diff --git a/tests/WriteBinaryTest.php b/tests/WriteBinaryTest.php index 85cc2d7..473b6aa 100644 --- a/tests/WriteBinaryTest.php +++ b/tests/WriteBinaryTest.php @@ -11,6 +11,7 @@ if(!defined('WRITE_BINARY_DATA_FILE')) { define('WRITE_BINARY_DATA_FILE',__DIR__.'/binary.plist'); + define('TEST_UID_BPLIST', __DIR__ . '/uid-list.plist'); } require_once(LIBDIR.'/CFPropertyList.php'); @@ -71,6 +72,15 @@ public function testWriteString() { $plist->parse($content); } + public function testWriteUid() { + $plist = new CFPropertyList(); + $dict = new CFDictionary(); + $dict->add('test', new CFUid(1)); + $plist->add($dict); + + $plist1 = new CFPropertyList(TEST_UID_BPLIST); + $this->assertEquals($plist1->toBinary(), $plist->toBinary()); + } } diff --git a/tests/WriteXMLTest.php b/tests/WriteXMLTest.php index 782d29e..4029c6a 100644 --- a/tests/WriteXMLTest.php +++ b/tests/WriteXMLTest.php @@ -11,6 +11,7 @@ if(!defined('WRITE_XML_DATA_FILE')) { define('WRITE_XML_DATA_FILE',__DIR__.'/binary.plist'); + define('TEST_UID_XML_PLIST', __DIR__ . '/uid-list.xml'); } require_once(LIBDIR.'/CFPropertyList.php'); @@ -68,6 +69,16 @@ public function testWriteString() { $plist->parse($content); } + public + function testWriteUid() { + $plist = new CFPropertyList(); + $dict = new CFDictionary(); + $dict->add('test', new CFUid(1)); + $plist->add($dict); + + $plist1 = new CFPropertyList(TEST_UID_XML_PLIST); + $this->assertEquals($plist1->toXml(), $plist->toXml()); + } } diff --git a/tests/uid-list.plist b/tests/uid-list.plist new file mode 100644 index 0000000..4553e9f Binary files /dev/null and b/tests/uid-list.plist differ diff --git a/tests/uid-list.xml b/tests/uid-list.xml new file mode 100644 index 0000000..3dc6edc --- /dev/null +++ b/tests/uid-list.xml @@ -0,0 +1,11 @@ + + + + + test + + CF$UID + 1 + + +