public function testDecode() { if (!is_executable('/usr/bin/wbxml2xml')) { $this->markTestSkipped('/usr/bin/wbxml2xml is required for comparison tests.'); } $decoder = new Horde_Xml_Wbxml_Decoder(); foreach (glob(__DIR__ . '/../../../../doc/Horde/Xml/Wbxml/examples/*.wbxml') as $file) { $xml_ref = shell_exec('/usr/bin/wbxml2xml' . ' -m 0 -o - "' . $file . '" 2>/dev/null'); $xml_ref = preg_replace(array('/<\\?xml version=\\"1\\.0\\"\\?><!DOCTYPE [^>]*>/', '|<([^>]+)/>|'), array('', '<$1></$1>'), $xml_ref); $xml = $decoder->decodeToString(file_get_contents($file)); if (is_string($xml)) { // Ignore <?xml and <!DOCTYPE stuff. $xml = preg_replace('/<\\?xml version=\\"1\\.0\\"\\?><!DOCTYPE [^>]*>/', '', $xml); // Handle different mimetypes. $xml = str_replace('application/vnd.syncml-devinf+wbxml', 'application/vnd.syncml-devinf+xml', $xml); } $this->assertEquals(Horde_String::lower($xml_ref), Horde_String::lower($xml)); } }
protected function _decode($input) { $token = $this->getByte($input); $str = ''; // print "position: " . $this->_strpos . " token: " . $token . " str10: " . substr($input, $this->_strpos, 10) . "\n"; // @todo: remove debug output switch ($token) { case Horde_Xml_Wbxml::GLOBAL_TOKEN_STR_I: // Section 5.8.4.1 $str = $this->termstr($input); $this->_ch->characters($str); // print "str:$str\n"; // @TODO Remove debug code break; case Horde_Xml_Wbxml::GLOBAL_TOKEN_STR_T: // Section 5.8.4.1 $x = Horde_Xml_Wbxml::MBUInt32ToInt($input, $this->_strpos); $str = $this->getStringTableEntry($x); $this->_ch->characters($str); break; case Horde_Xml_Wbxml::GLOBAL_TOKEN_EXT_I_0: case Horde_Xml_Wbxml::GLOBAL_TOKEN_EXT_I_1: case Horde_Xml_Wbxml::GLOBAL_TOKEN_EXT_I_2: // Section 5.8.4.2 $str = $this->termstr($input); $this->_ch->characters($str); break; case Horde_Xml_Wbxml::GLOBAL_TOKEN_EXT_T_0: case Horde_Xml_Wbxml::GLOBAL_TOKEN_EXT_T_1: case Horde_Xml_Wbxml::GLOBAL_TOKEN_EXT_T_2: // Section 5.8.4.2 $str = $this->getStringTableEnty(Horde_Xml_Wbxml::MBUInt32ToInt($input, $this->_strpos)); $this->_ch->characters($str); break; case Horde_Xml_Wbxml::GLOBAL_TOKEN_EXT_0: case Horde_Xml_Wbxml::GLOBAL_TOKEN_EXT_1: case Horde_Xml_Wbxml::GLOBAL_TOKEN_EXT_2: // Section 5.8.4.2 $extension = $this->getByte($input); $this->_ch->characters($extension); break; case Horde_Xml_Wbxml::GLOBAL_TOKEN_ENTITY: // Section 5.8.4.3 // UCS-4 chracter encoding? $entity = $this->entity(Horde_Xml_Wbxml::MBUInt32ToInt($input, $this->_strpos)); $this->_ch->characters('&#' . $entity . ';'); break; case Horde_Xml_Wbxml::GLOBAL_TOKEN_PI: // Section 5.8.4.4 throw new Horde_Xml_Wbxml_Exception('WBXML global token processing instruction is unsupported'); case Horde_Xml_Wbxml::GLOBAL_TOKEN_LITERAL: // Section 5.8.4.5 $str = $this->getStringTableEntry(Horde_Xml_Wbxml::MBUInt32ToInt($input, $this->_strpos)); $this->parseTag($input, $str, false, false); break; case Horde_Xml_Wbxml::GLOBAL_TOKEN_LITERAL_A: // Section 5.8.4.5 $str = $this->getStringTableEntry(Horde_Xml_Wbxml::MBUInt32ToInt($input, $this->_strpos)); $this->parseTag($input, $str, true, false); break; case Horde_Xml_Wbxml::GLOBAL_TOKEN_LITERAL_AC: // Section 5.8.4.5 $str = $this->getStringTableEntry(Horde_Xml_Wbxml::MBUInt32ToInt($input, $this->_strpos)); $this->parseTag($input, $string, true, true); break; case Horde_Xml_Wbxml::GLOBAL_TOKEN_LITERAL_C: // Section 5.8.4.5 $str = $this->getStringTableEntry(Horde_Xml_Wbxml::MBUInt32ToInt($input, $this->_strpos)); $this->parseTag($input, $str, false, true); break; case Horde_Xml_Wbxml::GLOBAL_TOKEN_OPAQUE: // Section 5.8.4.6 $size = Horde_Xml_Wbxml::MBUInt32ToInt($input, $this->_strpos); if ($size > 0) { $b = substr($input, $this->_strpos, $size); // print "opaque of size $size: ($b)\n"; // @todo remove debug $this->_strpos += $size; // opaque data inside a <data> element may or may not be // a nested wbxml document (for example devinf data). // We find out by checking the first byte of the data: if it's // 1, 2 or 3 we expect it to be the version number of a wbxml // document and thus start a new wbxml decoder instance on it. if ($size > 0 && $this->_isData && ord($b) <= 10) { $decoder = new Horde_Xml_Wbxml_Decoder(); $decoder->setContentHandler($this->_ch); $decoder->decode($b); // /* // @todo: FIXME currently we can't decode Nokia // DevInf data. So ignore error for the time beeing. // */ // $this->_ch->characters($s); } else { /* normal opaque behaviour: just copy the raw data: */ // print "opaque handled as string=$b\n"; // @todo remove debug $this->_ch->characters($b); } } // old approach to deal with opaque data inside ContentHandler: // FIXME Opaque is used by SYNCML. Opaque data that depends on the context // if (contentHandler instanceof OpaqueContentHandler) { // ((OpaqueContentHandler)contentHandler).opaque(b); // } else { // String str = new String(b, 0, size, charset); // char[] chars = str.toCharArray(); // contentHandler.characters(chars, 0, chars.length); // } break; case Horde_Xml_Wbxml::GLOBAL_TOKEN_END: // Section 5.8.4.7.1 $str = $this->endTag(); break; case Horde_Xml_Wbxml::GLOBAL_TOKEN_SWITCH_PAGE: // Section 5.8.4.7.2 $codePage = $this->getByte($input); // print "switch to codepage $codePage\n"; // @todo: remove debug code $this->switchElementCodePage($codePage); break; default: // Section 5.8.2 // Section 5.8.3 $hasAttributes = ($token & 0x80) != 0; $hasContent = ($token & 0x40) != 0; $realToken = $token & 0x3f; $str = $this->getTag($realToken); // print "element:$str\n"; // @TODO Remove debug code $this->parseTag($input, $str, $hasAttributes, $hasContent); if ($realToken == 0xf) { // store if we're inside a Data tag. This may contain // an additional enclosed wbxml document on which we have // to run a seperate encoder $this->_isData = true; } else { $this->_isData = false; } break; } }