<? PHP /** * PropertyList class * Implements writing Apple Property List (. plist) XML and text files from an array. * * @ Author Jesus A. Alvarez <zydeco@namedfork.net> */ Function plist_encode_text ($ obj ){ $ Plist = new PropertyList ($ obj ); Return $ plist-> text (); } Function plist_encode_xml ($ obj ){ $ Plist = new PropertyList ($ obj ); Return $ plist-> xml (); } Class PropertyList { Private $ obj, $ xml, $ text; Public function _ construct ($ obj ){ $ This-> obj = $ obj; } Private static function is_assoc ($ array ){ Return (is_array ($ array) & 0! = Count (array_diff_key ($ array, array_keys ($ array ))))); } Public function xml (){ If (isset ($ this-> xml) return $ this-> xml; $ X = new XMLWriter (); $ X-> openMemory (); $ X-> setIndent (TRUE ); $ X-> startDocument ('1. 0', 'utf-8 '); $ X-> writeDTD ('plist', '-// Apple // DTD plist 1.0 // en', 'HTTP: // www.apple.com/DTDs/PropertyList-1.0.dtd '); $ X-> startElement ('plist '); $ X-> writeAttribute ('version', '1. 0 '); $ This-> xmlWriteValue ($ x, $ this-> obj ); $ X-> endElement (); // plist $ X-> endDocument (); $ This-> xml = $ x-> outputMemory (); Return $ this-> xml; } Public function text (){ If (isset ($ this-> text) return $ this-> text; $ Text = ''; $ This-> textWriteValue ($ text, $ this-> obj ); $ This-> text = $ text; Return $ this-> text; } Private function xmlWriteDict (XMLWriter $ x, & $ dict ){ $ X-> startElement ('dict '); Foreach ($ dict as $ k =>&$ v ){ $ X-> writeElement ('key', $ k ); $ This-> xmlWriteValue ($ x, $ v ); } $ X-> endElement (); // dict } Private function xmlWriteArray (XMLWriter $ x, & $ arr ){ $ X-> startElement ('array '); Foreach ($ arr as & $ v) $ This-> xmlWriteValue ($ x, $ v ); $ X-> endElement (); // array } Private function xmlWriteValue (XMLWriter $ x, & $ v ){ If (is_int ($ v) | is_long ($ v )) $ X-> writeElement ('integer', $ v ); Elseif (is_float ($ v) | is_real ($ v) | is_double ($ v )) $ X-> writeElement ('real', $ v ); Elseif (is_string ($ v )) $ X-> writeElement ('string', $ v ); Elseif (is_bool ($ v )) $ X-> writeElement ($ v? 'True': 'false '); Elseif (PropertyList: is_assoc ($ v )) $ This-> xmlWriteDict ($ x, $ v ); Elseif (is_array ($ v )) $ This-> xmlWriteArray ($ x, $ v ); Elseif (is_a ($ v, 'plistdata ')) $ X-> writeElement ('data', $ v-> base64EncodedData ()); Elseif (is_a ($ v, 'plistdate ')) $ X-> writeElement ('date', $ v-> encodedDate ()); Else { Trigger_error ("Unsupported data type in plist ($ v)", E_USER_WARNING ); $ X-> writeElement ('string', $ v ); } } Private function textWriteValue (& $ text, & $ v, $ indentLevel = 0 ){ If (is_int ($ v) | is_long ($ v )) $ Text. = sprintf ("% d", $ v ); Elseif (is_float ($ v) | is_real ($ v) | is_double ($ v )) $ Text. = sprintf ("% g", $ v ); Elseif (is_string ($ v )) $ This-> textWriteString ($ text, $ v ); Elseif (is_bool ($ v )) $ Text. = $ v? 'Yes': 'no '; Elseif (PropertyList: is_assoc ($ v )) $ This-> textWriteDict ($ text, $ v, $ indentLevel ); Elseif (is_array ($ v )) $ This-> textWriteArray ($ text, $ v, $ indentLevel ); Elseif (is_a ($ v, 'plistdata ')) $ Text. = '<'. $ v-> hexEncodedData (). '> '; Elseif (is_a ($ v, 'plistdate ')) $ Text. = '"'. $ v-> ISO8601Date ().'"'; Else { Trigger_error ("Unsupported data type in plist ($ v)", E_USER_WARNING ); $ This-> textWriteString ($ text, $ v ); } } Private function textWriteString (& $ text, & $ str ){ $ Oldlocale = setlocale (LC_CTYPE, "0 "); If (ctype_alnum ($ str) $ text. = $ str; Else $ text. = '"'. $ this-> textEncodeString ($ str ).'"'; Setlocale (LC_CTYPE, $ oldlocale ); } Private function textEncodeString (& $ str ){ $ Newstr = ''; $ I = 0; $ Len = strlen ($ str ); While ($ I <$ len ){ $ Ch = ord (substr ($ str, $ I, 1 )); If ($ ch = 0x22 | $ ch = 0x5C ){ // Escape double quote, backslash $ Newstr. = '\'. chr ($ ch ); $ I ++; } Else if ($ ch> = 0x07 & $ ch <= 0x0D ){ // Control characters with escape sequences $ Newstr. = '\'. substr ('abtnvfr ', $ ch-7, 1 ); $ I ++; } Else if ($ ch <32 ){ // Other non-printable characters escaped as unicode $ Newstr. = sprintf ('\ U % 04x', $ ch ); $ I ++; } Else if ($ ch <128 ){ // Ascii printable $ Newstr. = chr ($ ch ); $ I ++; } Else if ($ ch = 192 | $ ch = 193 ){ // Invalid encoding of ASCII characters $ I ++; } Else if ($ ch & 0xC0) = 0x80 ){ // Part of a lost multibyte sequence, skip $ I ++; } Else if ($ ch & 0xE0) = 0xC0 ){ // U + 0080-U + 07FF (2 bytes) $ U = ($ ch & 0x1F) <6) | (ord (substr ($ str, $ I + 1, 1) & 0x3F ); $ Newstr. = sprintf ('\ U % 04x', $ u ); $ I + = 2; } Else if ($ ch & 0xF0) = 0xE0 ){ // U + 0800-U + FFFF (3 bytes) $ U = ($ ch & 0x0F) <12) | (ord (substr ($ str, $ I + 1, 1) & 0x3F) <6) | (ord (substr ($ str, $ I + 2, 1) & 0x3F ); $ Newstr. = sprintf ('\ U % 04x', $ u ); $ I + = 3; } Else if ($ ch & 0xF8) = 0xF0 ){ // U + 10000-U + 3 FFFF (4 bytes) $ U = ($ ch & 0x07) <18) | (ord (substr ($ str, $ I + 1, 1) & 0x3F) <12) | (ord (substr ($ str, $ I + 2, 1) & 0x3F) <6) | (ord (substr ($ str, $ I + 3, 1) & 0x3F ); $ Newstr. = sprintf ('\ U % 04x', $ u ); $ I + = 4; } Else { // 5 and 6 byte sequences are not valid UTF-8 $ I ++; } } Return $ newstr; } Private function textWriteDict (& $ text, & $ dict, $ indentLevel ){ If (count ($ dict) = 0 ){ $ Text. = '{}'; Return; } $ Text. = "{\ n "; $ Indent = ''; $ IndentLevel ++; While (strlen ($ indent) <$ indentLevel) $ indent. = "\ t "; Foreach ($ dict as $ k =>&$ v ){ $ Text. = $ indent; $ This-> textWriteValue ($ text, $ k ); $ Text. = '; $ This-> textWriteValue ($ text, $ v, $ indentLevel ); $ Text. = "; \ n "; } $ Text. = substr ($ indent, 0,-1 ).'}'; } Private function textWriteArray (& $ text, & $ arr, $ indentLevel ){ If (count ($ arr) = 0 ){ $ Text. = '()'; Return; } $ Text. = "(\ n "; $ Indent = ''; $ IndentLevel ++; While (strlen ($ indent) <$ indentLevel) $ indent. = "\ t "; Foreach ($ arr as & $ v ){ $ Text. = $ indent; $ This-> textWriteValue ($ text, $ v, $ indentLevel ); $ Text. = ", \ n "; } $ Text. = substr ($ indent, 0,-1 ).')'; } } Class PlistData { Private $ data; Public function _ construct ($ str ){ $ This-> data = $ str; } Public function base64EncodedData (){ Return base64_encode ($ this-> data ); } Public function hexEncodedData (){ $ Len = strlen ($ this-> data ); $ Hexstr = ''; For ($ I = 0; $ I <$ len; $ I + = 4) $ Hexstr. = bin2hex (substr ($ this-> data, $ I, 4 )).''; Return substr ($ hexstr, 0,-1 ); } } Class PlistDate { Private $ dateval; Public function _ construct ($ init = NULL ){ If (is_int ($ init )) $ This-> dateval = $ init; Elseif (is_string ($ init )) $ This-> dateval = strtotime ($ init ); Elseif ($ init = NULL) $ This-> dateval = time (); } Public function ISO8601Date (){ Return gmdate ('Y-m-d \ TH: I: s \ Z', $ this-> dateval ); } } ?> |