steffen: server/kolab-horde-framework/kolab-horde-framework/XML_WBXML/WBXML ContentHandler.php, NONE, 1.1 DTD.php, NONE, 1.1 DTDManager.php, NONE, 1.1 Decoder.php, NONE, 1.1 Encoder.php, NONE, 1.1

cvs at intevation.de cvs at intevation.de
Fri Oct 14 16:33:17 CEST 2005


Author: steffen

Update of /kolabrepository/server/kolab-horde-framework/kolab-horde-framework/XML_WBXML/WBXML
In directory doto:/tmp/cvs-serv28903/kolab-horde-framework/kolab-horde-framework/XML_WBXML/WBXML

Added Files:
	ContentHandler.php DTD.php DTDManager.php Decoder.php 
	Encoder.php 
Log Message:
Separated Horde Framework from kolab-resource-handlers

--- NEW FILE: ContentHandler.php ---
<?php
/**
 * $Horde: framework/XML_WBXML/WBXML/ContentHandler.php,v 1.8 2004/01/20 02:21:54 chuck Exp $
 *
 * Copyright 2003-2004 Anthony Mills <amills at pyramid6.com>
 *
 * See the enclosed file COPYING for license information (LGPL).  If you
 * did not receive this file, see http://www.fsf.org/copyleft/lgpl.html.
 *
 * From Binary XML Content Format Specification Version 1.3, 25 July
 * 2001 found at http://www.wapforum.org
 *
 * @package XML_WBXML
 */
class XML_WBXML_ContentHandler {

    var $_currentUri;
    var $_indent = 0;
    var $_output = '';

    var $_opaqueHandler;

    /**
     * Charset.
     */
    var $_charset = 'UTF-8';

    /**
     * WBXML Version.
     * 1, 2, or 3 supported
     */
    var $_wbxmlVersion = 2;

    function XML_WBXML_ContentHandler()
    {
        $this->_currentUri = &new XML_WBXML_LifoQueue();
    }

    function raiseError($error)
    {
        include_once 'PEAR.php';
        return PEAR::raiseError($error);
    }

    function getCharsetStr()
    {
        return $this->_charset;
    }

    function setCharset($cs)
    {
        $this->_charset = $cs;
    }

    function getVersion()
    {
        return $this->_wbxmlVersion;
    }

    function setVersion($v)
    {
        $this->_wbxmlVersion = 2;
    }

    function getOutput()
    {
        return $this->_output;
    }

    function startElement($uri, $element, $attrs)
    {
        $this->_padspaces();
        $this->_output .= '<' . $element;

        $currentUri = $this->_currentUri->top();

        if ((!$currentUri) || ($currentUri != $uri)) {
            $this->_output .= ' xmlns="' . $uri . '"';
        }

        $this->_currentUri->push($uri);

        foreach ($attrs as $attr) {
            $this->_output .= ' ' . $attr['attiribute'] . '="' . $attr['value'] . '"';
        }

        $this->_output .= ">\n";

        $this->_indent++;
    }

    function endElement($uri, $element)
    {
        $this->_indent--;

        $this->_padspaces();
        $this->_output .= '</' . $element . ">\n";

        $this->_currentUri->pop();
    }

    function characters($str)
    {
        $this->_padspaces();
        $this->_output .= $str . "\n";
    }

    function opaque($o)
    {
        //I can check the first chanracter and see if it is WBXML
        if (ord($o[0]) < 10) {
            //should decode this, I really need a call back function

        } else {
            $this->_output .= $o . "\n";
        }
    }

    /**
     * Padding to make it easier to read.
     */
    function _padspaces()
    {
        if ($this->_indent > 0) {
            $this->_output .= str_repeat(' ', $this->_indent);
        }
    }


    function setOpaqueHandler($opaqueHandler)
    {
        $this->_opaqueHandler = $opaqueHandler;
    }

    function removeOpaqueHandler()
    {
        unset($this->_opaqueHandler);
    }

}

class XML_WBXML_LifoQueue {

    var $_queue = array();

    function XML_WBXML_LifoQueue()
    {
    }

    function push($obj)
    {
        array_push($this->_queue, $obj);
    }

    function pop()
    {
        if (count($this->_queue)) {
            return array_pop($this->_queue);
        } else {
            return null;
        }
    }

    function top()
    {
        if ($count = count($this->_queue)) {
            return $this->_queue[$count - 1];
        } else {
            return null;
        }
    }

}

--- NEW FILE: DTD.php ---
<?php
/**
 * $Horde: framework/XML_WBXML/WBXML/DTD.php,v 1.6 2004/01/01 15:14:45 jan Exp $
 *
 * From Binary XML Content Format Specification Version 1.3, 25 July 2001
 * found at http://www.wapforum.org
 *
 * Copyright 2003-2004 Anthony Mills <amills at pyramid6.com>
 *
 * See the enclosed file COPYING for license information (LGPL).  If you
 * did not receive this file, see http://www.fsf.org/copyleft/lgpl.html.
 *
 * @package XML_WBXML
 */
class XML_WBXML_DTD {

    var $version;
    var $intTags;
    var $intAttributes;
    var $strTags;
    var $strAttributes;
    var $intCodePages;
    var $strCodePages;
    var $strCodePagesURI;
    var $URI;
    var $XMLNS;
    var $DPI;

    function XML_WBXML_DTD($v)
    {
        $this->version = $v;
        $this->init();
    }

    function init()
    {
    }

    function setAttribute($intAttribute, $strAttribute)
    {
        $this->strAttributes[$strAttribute] = $intAttribute;
        $this->intAttributes[$intAttribute] = $strAttribute;
    }

    function setTag($intTag, $strTag)
    {
        $this->strTags[$strTag] = $intTag;
        $this->intTags[$intTag] = $strTag;
    }

    function setCodePage($intCodePage, $strCodePage, $strCodePageURI)
    {
        $this->strCodePagesURI[$strCodePageURI] = $intCodePage;
        $this->strCodePages[$strCodePage] = $intCodePage;
        $this->intCodePages[$intCodePage] = $strCodePage;
    }

    function toTagStr($tag)
    {
        return isset($this->intTags[$tag]) ? $this->intTags[$tag] : false;
    }

    function toAttributeStr($attribute)
    {
        return isset($this->intTags[$attribute]) ? $this->intTags[$attribute] : false;
    }

    function toCodePageStr($codePage)
    {
        return isset($this->intCodePages[$codePage]) ? $this->intCodePages[$codePage] : false;
    }

    function toTagInt($tag)
    {
        return isset($this->strTags[$tag]) ? $this->strTags[$tag] : false;
    }

    function toAttributeInt($attribute)
    {
        return isset($this->strAttributes[$attribute]) ? $this->strAttributes[$attribute] : false;
    }

    function toCodePageInt($codePage)
    {
        return isset($this->strCodePages[$codePage]) ? $this->strCodePages[$codePage] : false;
    }

    function toCodePageURI($uri)
    {
        $uri = strtolower($uri);
        $ret = isset($this->strCodePagesURI[$uri]) ? $this->strCodePagesURI[$uri] : false;

        return $ret;
    }

    /**
     * Getter for property version.
     * @return Value of property version.
     */
    function getVersion()
    {
        return $this->version;
    }

    /**
     * Setter for property version.
     * @param integer $v  New value of property version.
     */
    function setVersion($v)
    {
        $this->version = $v;
    }

    /**
     * Getter for property URI.
     * @return Value of property URI.
     */
    function getURI()
    {
        return $this->URI;
    }

    /**
     * Setter for property URI.
     * @param string $u  New value of property URI.
     */
    function setURI($u)
    {
        $this->URI = $u;
    }

    /**
     * Getter for property DPI.
     * @return Value of property DPI.
     */
    function getDPI()
    {
        return $this->DPI;
    }

    /**
     * Setter for property DPI.
     * @param DPI New value of property DPI.
     */
    function setDPI($d)
    {
        $this->DPI = $d;
    }

}

--- NEW FILE: DTDManager.php ---
<?php

include_once 'XML/WBXML/DTD/SyncML.php';
include_once 'XML/WBXML/DTD/SyncMLMetInf.php';
include_once 'XML/WBXML/DTD/SyncMLDevInf.php';

/**
 * $Horde: framework/XML_WBXML/WBXML/DTDManager.php,v 1.3 2004/01/01 15:14:45 jan Exp $
 *
 * Copyright 2003-2004 Anthony Mills <amills at pyramid6.com>
 *
 * See the enclosed file COPYING for license information (LGPL).  If you
 * did not receive this file, see http://www.fsf.org/copyleft/lgpl.html.
 *
 * From Binary XML Content Format Specification Version 1.3, 25 July
 * 2001 found at http://www.wapforum.org
 *
 * @package XML_WBXML
 */
class XML_WBXML_DTDManager {

    var $_strDTD = array();
    var $_strDTDURI = array();

    function XML_WBXML_DTDManager()
    {
        $this->registerDTD('-//SYNCML//DTD SyncML 1.0//EN', 'syncml:syncml', new XML_WBXML_DTD_SyncML(0));
        $this->registerDTD('-//SYNCML//DTD SyncML 1.1//EN', 'syncml:syncml1.1', new XML_WBXML_DTD_SyncML(1));

        $this->registerDTD('-//SYNCML//DTD MetInf 1.0//EN', 'syncml:metinf', new XML_WBXML_DTD_SyncMLMetInf(0));
        $this->registerDTD('-//SYNCML//DTD MetInf 1.1//EN', 'syncml:metinf1.1', new XML_WBXML_DTD_SyncMLMetInf(1));

        $this->registerDTD('-//SYNCML//DTD DevInf 1.0//EN', 'syncml:devinf', new XML_WBXML_DTD_SyncMLDevInf(0));
        $this->registerDTD('-//SYNCML//DTD DevInf 1.1//EN', 'syncml:devinf1.1', new XML_WBXML_DTD_SyncMLDevInf(1));
    }

    function getInstance($publicIdentifier)
    {
        return isset($this->_strDTD[$publicIdentifier]) ? $this->_strDTD[$publicIdentifier] : null;
    }

    function getInstanceURI($uri)
    {
        $uri = strtolower($uri);
        return isset($this->_strDTDURI[$uri]) ? $this->_strDTDURI[$uri] : null;
    }

    function registerDTD($publicIdentifier, $uri, &$dtd)
    {
        $dtd->setDPI($publicIdentifier);

        $this->_strDTD[$publicIdentifier] = $dtd;
        $this->_strDTDURI[$uri] = $dtd;
    }

}

--- NEW FILE: Decoder.php ---
<?php

include_once 'XML/WBXML.php';
include_once 'XML/WBXML/DTDManager.php';
include_once 'XML/WBXML/ContentHandler.php';

/**
 * $Horde: framework/XML_WBXML/WBXML/Decoder.php,v 1.18 2004/04/07 17:43:43 chuck Exp $
 *
 * Copyright 2003-2004 Anthony Mills <amills at pyramid6.com>
 *
 * See the enclosed file COPYING for license information (LGPL).  If you
 * did not receive this file, see http://www.fsf.org/copyleft/lgpl.html.
 *
 * From Binary XML Content Format Specification Version 1.3, 25 July
 * 2001 found at http://www.wapforum.org
 *
 * @package XML_WBXML
 */
class XML_WBXML_Decoder extends XML_WBXML_ContentHandler {

    /**
     * Document Public Identifier type
     * 1 mb_u_int32 well known type
     * 2 string table
     * from spec but converted into a string.
     *
     * Document Public Identifier
     * Used with dpiType.
     */
    var $_dpi;

    /**
     * String table as defined in 5.7
     */
    var $_stringTable = array();

    /**
     * Content handler.
     * Currently just outputs raw XML.
     */
    var $_ch;

    var $_tagDTD;

    var $_prevAttributeDTD;

    var $_attributeDTD;

    /**
     * State variables.
     */
    var $_tagStack = array();
    var $_isAttribute;
    var $_isData = false;

    /**
     * The DTD Manager.
     * @var object XML_WBXML_DTDManager $dtdManager
     */
    var $_dtdManager;


    /**
     * The string position.
     * @var integer string position
     */
    var $_strpos;

    /**
     * Use wbxml2xml from libwbxml.
     * @var String
     */
    var $_wbxml2xml = '/usr/bin/wbxml2xml -o ';

    /**
     * Constructor.
     */
    function XML_WBXML_Decoder()
    {
        $this->_dtdManager = &new XML_WBXML_DTDManager();
    }

    /**
     * Return one byte from the input stream.
     */
    function getByte($input)
    {
        return ord($input[$this->_strpos++]);
    }

    function decode($input)
    {
        if (isset($this->_wbxml2xml)) {
            $tmp_id = mt_rand();
            $tmp_file = '/tmp/wbxml_decoder_' . $tmp_id;

            $fp = fopen($tmp_file . '.wbxml', 'wb');
            fwrite($fp, $input);
            fclose($fp);

            exec($this->_wbxml2xml . $tmp_file . '.xml ' . $tmp_file . '.wbxml');

            $ret = file_get_contents($tmp_file . '.xml');
            unlink($tmp_file . '.xml');
            unlink($tmp_file . '.wbxml');
            return $ret;
        } else {
            $this->_strpos = 0;
            // Get Version Number from Section 5.4
            // version = u_int8
            // currently 1, 2 or 3
            $this->_wbxmlVersion = $this->getVersionNumber($input);

            // Get Document Public Idetifier from Section 5.5
            // publicid = mb_u_int32 | (zero index)
            // zero = u_int8
            // Containing the value zero (0)
            // The actual DPI is determined after the String Table is read.
            $dpiStruct = $this->getDocumentPublicIdentifier($input);

            // Get Charset from 5.6
            // charset = mb_u_int32
            $this->_charset = $this->getCharset($input);

            // Get String Table from 5.7
            // strb1 = length *byte
            $this->_stringTable = $this->getStringTable($input, $this->_charset);

            // Get Document Public Idetifier from Section 5.5.
            $this->_dpi = $this->getDocumentPublicIdentifierImpl($dpiStruct['dpiType'],
                                                                 $dpiStruct['dpiNumber'],
                                                                 $this->_stringTable);

            // Now the real fun begins.
            // from Sections 5.2 and 5.8

            // Default content handler.
            $this->_ch = &new XML_WBXML_ContentHandler();

            // Default content handler.
            $this->_dtdManager = &new XML_WBXML_DTDManager();

            // Get the starting DTD.
            $this->_tagDTD = $this->_dtdManager->getInstance($this->_dpi);
            if (!$this->_tagDTD) {
                return $this->raiseError('No DTD found for ' . $this->_dpi);
            }

            $this->_attributeDTD = $this->_tagDTD;

            while ($this->_strpos < strlen($input)) {
                $this->_decode($input);
            }

            return $this->_ch->getOutput();
        }

    }

    function getVersionNumber($input)
    {
        return $this->getByte($input);
    }

    function getDocumentPublicIdentifier($input)
    {
        // 'dpiType' 'dpiNumber'
        $dpistruct = array();

        $i = XML_WBXML::MBUInt32ToInt($input, $this->_strpos);

        if ($i == 0) {
            $dpiStruct['dpiType'] = 2;
            $dpiStruct['dpiNumber'] = $this->getByte($input);
        } else {
            $dpiStruct['dpiType'] = 1;
            $dpiStruct['dpiNumber'] = $i;
        }

        return $dpiStruct;
    }

    function getDocumentPublicIdentifierImpl($dpiType, $dpiNumber, $st)
    {
        if ($dpiType == 1) {
            return XML_WBXML::getDPIString($dpiNumber);
        } else {
            return isset($st[$dpiNumber]) ? $st[$dpiNumber] : null;
        }
    }

    /**
     * Returns the character encoding. Only default character
     * encodings from J2SE are supported.  From
     * http://www.iana.org/assignments/character-sets and
     * http://java.sun.com/j2se/1.4.2/docs/api/java/nio/charset/Charset.html
     */
    function getCharset($input)
    {
        $cs = XML_WBXML::MBUInt32ToInt($input, $this->_strpos);
        return $charset = XML_WBXML::getCharsetString($cs);
    }

    /**
     * @TODO needs to be fixed. Does this still really need to be
     * fixed?
     */
    function getStringTable($input, $cs)
    {
        $stringTable = array();
        $size = XML_WBXML::MBUInt32ToInt($input, $this->_strpos);

        // A hack to make it work with arrays.
        // How/why is this necessary?
        $str = 'j';

        $numstr = 0;
        $start = 0;
        $j = 0;
        for ($i = 0; $i < $size; $i++ ) {
            /* May need to fix the null detector for more than single
             * byte charsets like ASCII, UTF-8, etc. */
            $ch = $input[$this->_strpos++];
            if (ord($ch) == 0) {
                $stringTable[$numstr++] = $str;
                $str = '#';
                $start = $i + 1;
            } else {
                $str[$j++] = $ch;
            }
        }

        if ($start < $size) {
            $stringTable[$numstr++] = $str;
        }

        return $stringTable;
    }

    function _decode($input)
    {
        $token = $this->getByte($input);
        $str = '';

        switch ($token) {
        case XML_WBXML_GLOBAL_TOKEN_STR_I:
            // Section 5.8.4.1
            $str = $this->termstr($input);
            $this->_ch->characters($str);
            break;

        case XML_WBXML_GLOBAL_TOKEN_STR_T:
            // Section 5.8.4.1
            $str = $this->_stringTable[XML_WBXML::MBUInt32ToInt($intput)];
            $this->_ch->characters($str);
            break;

        case XML_WBXML_GLOBAL_TOKEN_EXT_I_0:
        case XML_WBXML_GLOBAL_TOKEN_EXT_I_1:
        case XML_WBXML_GLOBAL_TOKEN_EXT_I_2:
            // Section 5.8.4.2
            $str = $this->termstr($input);
            $this->_ch->characters($str);
            break;

        case XML_WBXML_GLOBAL_TOKEN_EXT_T_0:
        case XML_WBXML_GLOBAL_TOKEN_EXT_T_1:
        case XML_WBXML_GLOBAL_TOKEN_EXT_T_2:
            // Section 5.8.4.2
            $str = $this->_stringTable[XML_WBXML::MBUInt32ToInt($intput)];
            $this->_ch->characters($str);
            break;

        case XML_WBXML_GLOBAL_TOKEN_EXT_0:
        case XML_WBXML_GLOBAL_TOKEN_EXT_1:
        case XML_WBXML_GLOBAL_TOKEN_EXT_2:
            // Section 5.8.4.2
            $extension = $this->getByte($input);
            $this->_ch->characters($extension);
            break;

        case XML_WBXML_GLOBAL_TOKEN_ENTITY:
            // Section 5.8.4.3
            // UCS-4 chracter encoding?
            $entity = $this->entity(XML_WBXML::MBUInt32ToInt($input, $this->_strpos));

            $this->_ch->characters('&#' . $entity . ';');
            break;

        case XML_WBXML_GLOBAL_TOKEN_PI:
            // Section 5.8.4.4
            // throw new IOException("WBXML global token processing instruction(PI, " + token + ") is unsupported!");
            break;

        case XML_WBXML_GLOBAL_TOKEN_LITERAL:
            // Section 5.8.4.5
            $str = $this->_stringTable[XML_WBXML::MBUInt32ToInt($input, $this->_strpos)];
            $this->parseTag($input, $str, false, false);
            break;

        case XML_WBXML_GLOBAL_TOKEN_LITERAL_A:
            // Section 5.8.4.5
            $str = $this->_stringTable[XML_WBXML::MBUInt32ToInt($input, $this->_strpos)];
            $this->parseTag($input, $str, true, false);
            break;

        case XML_WBXML_GLOBAL_TOKEN_LITERAL_AC:
            // Section 5.8.4.5
            $str = $this->_stringTable[XML_WBXML::MBUInt32ToInt($input, $this->_strpos)];
            $this->parseTag($input, $string, true, true);
            break;

        case XML_WBXML_GLOBAL_TOKEN_LITERAL_C:
            // Section 5.8.4.5
            $str = $this->_stringTable[XML_WBXML::MBUInt32ToInt($input, $this->_strpos)];
            $this->parseTag($input, $str, false, true);
            break;

        case XML_WBXML_GLOBAL_TOKEN_OPAQUE:
            // Section 5.8.4.6
            $size = XML_WBXML::MBUInt32ToInt($input, $this->_strpos);
            $b = substr($input, $this->_strpos, $this->_strpos + $size);
            $this->_strpos += $size;
            $this->_ch->opaque($b);

            // 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);
            // }

            // This can cause some problems. We may have to use a
            // event based decoder.
            break;

        case XML_WBXML_GLOBAL_TOKEN_END:
            // Section 5.8.4.7.1
            $str = $this->endTag();
            break;

        case XML_WBXML_GLOBAL_TOKEN_SWITCH_PAGE:
            // Section 5.8.4.7.2
            $codePage = $this->getByte($input);
            $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);

            $this->parseTag($input, $str, $hasAttributes, $hasContent);

            if ($realToken == 0x0f) {
                // FIXME Don't remember this one.
                $this->_isData = true;
            }
            break;
        }
    }

    function parseTag($input, $tag, $hasAttributes, $hasContent)
    {
        $attrs = array();
        if ($hasAttributes) {
            $attrs = $this->getAttributes($input);
        }

        $this->_ch->startElement($this->getCurrentURI(), $tag, $attrs);

        if ($hasContent) {
            // FIXME I forgot what does this does. Not sure if this is
            // right?
            $this->_tagStack[] = $tag;
        } else {
            $this->_ch->endElement($this->getCurrentURI(), $tag);
        }
    }

    function endTag()
    {
        if (count($this->_tagStack)) {
            $tag = array_pop($this->_tagStack);
        } else {
            $tag = 'Unknown';
        }

        if ($tag == 'Data') {
            $this->_isData = false;
        }

        $this->_ch->endElement($this->getCurrentURI(), $tag);

        return $tag;
    }

    function getAttributes($input)
    {
        $this->startGetAttributes();
        $hasMoreAttributes = true;

        $attrs = array();
        $attr = null;
        $value = null;
        $token = null;

        while ($hasMoreAttributes) {
            $token = $this->getByte($input);

            switch ($token) {
            // Attribute specified.
            case XML_WBXML_GLOBAL_TOKEN_LITERAL:
                // Section 5.8.4.5
                if (isset($attr)) {
                    $attrs[] = array('attribute' => $attr,
                                     'value' => $value);
                }

                $attr = $this->_stringTable[XML_WBXML::MBUInt32ToInt($input, $this->_strpos)];
                break;

            // Value specified.
            case XML_WBXML_GLOBAL_TOKEN_EXT_I_0:
            case XML_WBXML_GLOBAL_TOKEN_EXT_I_1:
            case XML_WBXML_GLOBAL_TOKEN_EXT_I_2:
                // Section 5.8.4.2
                $value .= $this->termstr($input);
                break;

            case XML_WBXML_GLOBAL_TOKEN_EXT_T_0:
            case XML_WBXML_GLOBAL_TOKEN_EXT_T_1:
            case XML_WBXML_GLOBAL_TOKEN_EXT_T_2:
                // Section 5.8.4.2
                $value .= $this->_stringTable[XML_WBXML::MBUInt32ToInt($input, $this->_strpos)];
                break;

            case XML_WBXML_GLOBAL_TOKEN_EXT_0:
            case XML_WBXML_GLOBAL_TOKEN_EXT_1:
            case XML_WBXML_GLOBAL_TOKEN_EXT_2:
                // Section 5.8.4.2
                $value .= $input[$this->_strpos++];
                break;

            case XML_WBXML_GLOBAL_TOKEN_ENTITY:
                // Section 5.8.4.3
                $value .= $this->entity(XML_WBXML::MBUInt32ToInt($input, $this->_strpos));
                break;

            case XML_WBXML_GLOBAL_TOKEN_STR_I:
                // Section 5.8.4.1
                $value .= $this->termstr($input);
                break;

            case XML_WBXML_GLOBAL_TOKEN_STR_T:
                // Section 5.8.4.1
                $value .= $this->_stringTable[XML_WBXML::MBUInt32ToInt($input, $this->_strpos)];
                break;

            case XML_WBXML_GLOBAL_TOKEN_OPAQUE:
                // Section 5.8.4.6
                $size = XML_WBXML::MBUInt32ToInt($input, $this->_strpos);
                $b = substr($input, $this->_strpos, $this->_strpos + $size);
                $this->_strpos += $size;

                $value .= $b;
                break;

            case XML_WBXML_GLOBAL_TOKEN_END:
                // Section 5.8.4.7.1
                $hasMoreAttributes = false;
                if (isset($attr)) {
                    $attrs[] = array('attribute' => $attr,
                                     'value' => $value);
                }
                break;

            case XML_WBXML_GLOBAL_TOKEN_SWITCH_PAGE:
                // Section 5.8.4.7.2
                $codePage = $this->getByte($input);
                if (!$this->_prevAttributeDTD) {
                    $this->_prevAttributeDTD = $this->_attributeDTD;
                }

                $this->switchAttributeCodePage($codePage);
                break;

            default:
                if ($token > 128) {
                    if (isset($attr)) {
                        $attrs[] = array('attribute' => $attr,
                                         'value' => $value);
                    }
                    $attr = $this->_attributeDTD->toAttribute($token);
                } else {
                    // Value.
                    $value .= $this->_attributeDTD->toAttribute($token);
                }
                break;
            }
        }

        if (!$this->_prevAttributeDTD) {
            $this->_attributeDTD = $this->_prevAttributeDTD;
            $this->_prevAttributeDTD = false;
        }

        $this->stopGetAttributes();
    }

    function startGetAttributes()
    {
        $this->_isAttribute = true;
    }

    function stopGetAttributes()
    {
        $this->_isAttribute = false;
    }

    function getCurrentURI()
    {
        if ($this->_isAttribute) {
            return $this->_tagDTD->getURI();
        } else {
            return $this->_attributeDTD->getURI();
        }
    }

    function writeString($str)
    {
        $this->_ch->characters($str);
    }

    function getTag($tag)
    {
        // Should know which state it is in.
        return $this->_tagDTD->toTagStr($tag);
    }

    function getAttribute($attribute)
    {
        // Should know which state it is in.
        $this->_attributeDTD->toAttributeInt($attribute);
    }

    function switchElementCodePage($codePage)
    {
        $this->_tagDTD = &$this->_dtdManager->getInstance($this->_tagDTD->toCodePageStr($codePage));
        $this->switchAttributeCodePage($codePage);
    }

    function switchAttributeCodePage($codePage)
    {
        $this->_attributeDTD = &$this->_dtdManager->getInstance($this->_attributeDTD->toCodePageStr($codePage));
    }

    /**
     * Return the hex version of the base 10 $entity.
     */
    function entity($entity)
    {
        return dechex($entity);
    }

    /**
     * @TODO FIXME reads a null terminated string.
     */
    function termstr($input)
    {
        $str = '#';
        $i = 0;
        $ch = $input[$this->_strpos++];
        while (ord($ch) != 0) {
            $str[$i++] = $ch;
            $ch = $input[$this->_strpos++];
        }

        return $str;
    }

    /**
     * For debugging.
     */
    function dumpStringTable($st)
    {
        echo 'String Table: ';
        foreach ($st as $s) {
            echo $s . ', ';
        }
        echo "\n";
    }

}

--- NEW FILE: Encoder.php ---
<?php

include_once 'XML/WBXML.php';
include_once 'XML/WBXML/ContentHandler.php';
include_once 'XML/WBXML/DTDManager.php';
include_once 'Horde/String.php';

/**
 * $Horde: framework/XML_WBXML/WBXML/Encoder.php,v 1.22 2004/04/07 17:43:43 chuck Exp $
 *
 * Copyright 2003-2004 Anthony Mills <amills at pyramid6.com>
 *
 * See the enclosed file COPYING for license information (LGPL).  If you
 * did not receive this file, see http://www.fsf.org/copyleft/lgpl.html.
 *
 * From Binary XML Content Format Specification Version 1.3, 25 July
 * 2001 found at http://www.wapforum.org
 *
 * @package XML_WBXML
 */
class XML_WBXML_Encoder extends XML_WBXML_ContentHandler {

    var $_strings = array();

    var $_stringTable;

    var $_hasWrittenHeader = false;

    var $_dtd;

    var $_output;

    var $_uris = array();

    var $_uriNums = array();

    var $_currentURI;

    var $_subParser;
    var $_subParserStack;

    /**
     * These will store the startElement params to see if we should
     * call startElementImp or startEndElementImp.
     */
    var $_storeURI;
    var $_storeName;
    var $_storeAttributes;

    /**
     * The XML parser.
     * @var resource $_parser
     */
    var $_parser;

    /**
     * The DTD Manager.
     * @var object XML_WBXML_DTDManager $dtdManager
     */
    var $_dtdManager;

    var $_indent = 0;

    /**
     * Use wbxml2xml from libwbxml.
     * @var String
     */
    var $_xml2wbxml = '/usr/bin/xml2wbxml -n -v 1.2 -o ';

    /**
     * Constructor.
     */
    function XML_WBXML_Encoder()
    {
        $this->_stringTable = &new XML_WBXML_HashTable();
        $this->_dtdManager = &new XML_WBXML_DTDManager();
        $this->_hasWrittenHeader = false;

        $this->_subParser = null;
        $this->_subParserStack = 0;

        $this->_output = '';
    }

    /**
     * Take the input $xml and turn it into WBXML, which gets sent to
     * $this->_output.
     */
    function encode($xml)
    {
        if (isset($this->_xml2wbxml)) {
            $tmp_id = mt_rand();
            $tmp_file = '/tmp/wbxml_encoder_' . $tmp_id;

            $fp = fopen($tmp_file . '.xml', 'wb');
            fwrite($fp, $xml);
            fclose($fp);

            exec($this->_xml2wbxml . $tmp_file . '.wbxml ' . $tmp_file . '.xml');

            $ret = file_get_contents($tmp_file . '.wbxml');
            unlink($tmp_file . '.wbxml');
            unlink($tmp_file . '.xml');
            return $ret;
        } else {
            // Create the XML parser and set method references.
            $this->_parser = xml_parser_create_ns($this->_charset);
            xml_set_object($this->_parser, $this);
            xml_parser_set_option($this->_parser, XML_OPTION_CASE_FOLDING, false);
            xml_set_element_handler($this->_parser, '_startElement', '_endElement');
            xml_set_character_data_handler($this->_parser, '_characters');
            xml_set_default_handler($this->_parser, 'defaultHandler');
            xml_set_processing_instruction_handler($this->_parser, '');
            xml_set_external_entity_ref_handler($this->_parser, '');

            if (!xml_parse($this->_parser, $xml)) {
                return $this->raiseError(sprintf('XML error: %s at line %d',
                                                 xml_error_string(xml_get_error_code($this->_parser)),
                                                 xml_get_current_line_number($this->_parser)));
            }

            xml_parser_free($this->_parser);

            return $this->_output;
        }
    }

    /**
     * This will write the correct headers.
     */
    function writeHeader($uri)
    {
        $this->_dtd = &$this->_dtdManager->getInstanceURI($uri);

        $dpiString = $this->_dtd->getDPI();

        // Set Version Number from Section 5.4
        // version = u_int8
        // currently 1, 2 or 3
        $this->writeVersionNumber($this->_wbxmlVersion);

        // Set Document Public Idetifier from Section 5.5
        // publicid = mb_u_int32 | ( zero index )
        // zero = u_int8
        // containing the value zero (0)
        // The actual DPI is determined after the String Table is read.
        $this->writeDocumentPublicIdentifier($dpiString, $this->_strings);

        // Set Charset from 5.6
        // charset = mb_u_int32
        $this->writeCharset($this->_charset);

        // Set String Table from 5.7
        // strb1 = length *byte
        $this->writeStringTable($this->_strings, $this->_charset, $this->_stringTable);

        $this->_currentURI = $uri;

        $this->_hasWrittenHeader = true;
    }

    function writeVersionNumber($version)
    {
        $this->_output.= chr($version);
    }

    function writeDocumentPublicIdentifier($dpiString, &$strings)
    {
        $i = XML_WBXML::getDPIInt($dpiString);

        if ($i == 0) {
            $strings[0] = $dpiString;
            $this->_output .= chr(0);
            $this->_output .= chr(0);
        } else {
            XML_WBXML::intToMBUInt32($this->_output, $i);
        }
    }

    function writeCharset($charset)
    {
        $cs = XML_WBXML::getCharsetInt($charset);

        if ($cs == 0) {
            return $this->raiseError('Unsupported Charset: ' . $charset);
        } else {
            XML_WBXML::intToMBUInt32($this->_output, $cs);
        }
    }

    function writeStringTable($strings, $charset, $stringTable)
    {
        $stringBytes = array();
        $count = 0;
        foreach ($strings as $str) {
            $bytes = $this->_getBytes($str, $charset);
            $stringBytes = array_merge($stringBytes, $bytes);
            $nullLength = $this->_addNullByte($bytes);
            $this->_stringTable->set($str, $count);
            $count += count($bytes) + $nullLength;
        }

        XML_WBXML::intToMBUInt32($this->_output, count($stringBytes));
        $this->_output.= implode('', $stringBytes);
    }

    function writeString($str, $cs)
    {
        $bytes = $this->_getBytes($str, $cs);
        $this->_output.= implode('', $bytes);
        $this->writeNull($cs);
    }

    function writeNull($charset)
    {
        $this->_output.= chr(0);
        return 1;
    }

    function _addNullByte(&$bytes)
    {
        $bytes[] = chr(0);
        return 1;
    }

    function _getBytes($string, $cs)
    {
        $string = String::convertCharset($string, $cs, 'utf-8');
        $nbytes = strlen($string);

        $bytes = array();
        for ($i = 0; $i < $nbytes; $i++) {
            $bytes[] = $string{$i};
        }

        return $bytes;
    }

    function _splitURI($tag)
    {
        $parts = explode(':', $tag);
        $name = array_pop($parts);
        $uri = implode(':', $parts);
        return array($uri, $name);
    }

    /**
     * Has no content, 64.
     */
    function startEndElementImp($uri, $name, $attributes)
    {
        if (!$this->_hasWrittenHeader) {
            $this->writeHeader($uri);
        }

        $this->writeTag($name, $attributes, false, $this->_charset);
    }

    function startElementImp($uri, $name, $attributes)
    {
        if (!$this->_hasWrittenHeader) {
            $this->writeHeader($uri);
        }

        if ($this->_currentURI != $uri) {
            $this->changecodepage($uri);

            $this->_currentURI != $uri;
        }

        $this->writeTag($name, $attributes, true, $this->_charset);
    }

    function writeStartElement($isEnd)
    {
        if ($this->_storeName != null) {
            if ($isEnd) {
                $this->startEndElementImp($this->_storeURI, $this->_storeName, $this->_storeAttributes);
            } else {
                $this->startElementImp($this->_storeURI, $this->_storeName, $this->_storeAttributes);
            }

            $this->_storeURI = null;
            $this->_storeName = null;
            $this->_storeAttributes = null;
        }
    }

    function startElement($uri, $name, $attributes)
    {
        if ($this->_subParser == null) {
            $this->writeStartElement(false);
            $this->_storeURI = $uri;
            $this->_storeName = $name;
            $this->_storeAttributes = $attributes;
        } else {
            $this->_subParserStack++;
        }
    }

    function _startElement($parser, $tag, $attributes)
    {
        list($uri, $name) = $this->_splitURI($tag);

        $this->startElement($uri, $name, $attributes);
    }

    function opaque($bytes)
    {
        if ($this->_subParser == null) {
            $this->writeStartElement(false);

            $this->_output .= chr(XML_WBXML_GLOBAL_TOKEN_OPAQUE);
            XML_WBXML::intToMBUInt32($this->_output, count($bytes));
            $this->_output .= $bytes;
        }
    }

    function characters($chars)
    {
        $chars = trim($chars);

        if (strlen($chars)) {
            /* We definitely don't want any whitespace. */
            if ($this->_subParser == null) {
                $this->writeStartElement(false);

                $i = $this->_stringTable->get($chars);
                if ($i != null) {
                    $this->_output .= chr(XML_WBXML_GLOBAL_TOKEN_STR_T);
                    XML_WBXML::intToMBUInt32($this->_output, $i);
                } else {
                    $this->_output .= chr(XML_WBXML_GLOBAL_TOKEN_STR_I);
                    $this->writeString($chars, $this->_charset);
                }
            }
        }
    }

    function _characters($parser, $chars)
    {
        $this->characters($chars);
    }

    function defaultHandler($parser, $data)
    {
    }

    function writeTag($name, $attrs, $hasContent, $cs)
    {
        if ($attrs != null && !count($attrs)) {
            $attrs = null;
        }

        $t = $this->_dtd->toTagInt($name);
        if ($t == -1) {
            $i = $this->_stringTable->get($name);
            if ($i == null) {
                return $this->raiseError($name . ' is not found in String Table or DTD');
            } else {
                if ($attrs == null && !$hasContent) {
                    $this->_output.= chr(XML_WBXML_GLOBAL_TOKEN_LITERAL);
                } elseif ($attrs == null && $hasContent) {
                    $this->_output.= chr(XML_WBXML_GLOBAL_TOKEN_LITERAL_A);
                } elseif ($attrs != null && $hasContent) {
                    $this->_output.= chr(XML_WBXML_GLOBAL_TOKEN_LITERAL_C);
                } elseif ($attrs != null && !$hasContent) {
                    $this->_output.= chr(XML_WBXML_GLOBAL_TOKEN_LITERAL_AC);
                }

                XML_WBXML::intToMBUInt32($this->_output, $i);
            }
        } else {
            if ($attrs == null && !$hasContent) {
                $this->_output.= chr($t);
            } elseif ($attrs == null && $hasContent) {
                $this->_output.= chr($t | 64);
            } elseif ($attrs != null && $hasContent) {
                $this->_output.= chr($t | 128);
            } elseif ($attrs != null && !$hasContent) {
                $this->_output.= chr($t | 192);
            }
        }

        if ($attrs != null) {
            $this->writeAttributes($attrs, $cs);
        }
    }

    function writeAttributes($attrs, $cs)
    {
        foreach ($attrs as $name => $value) {
            $this->writeAttribute($name, $value, $cs);
        }

        $this->_output.= chr(XML_WBXML_GLOBAL_TOKEN_END);
    }

    function writeAttribute($name, $value, $cs)
    {
        $a = $this->_dtd->toAttribute($name);
        if ($a == -1) {
            $i = $this->_stringTable->get($name);
            if ($i == null) {
                return $this->raiseError($name . ' is not found in String Table or DTD');
            } else {
                $this->_output.= chr(XML_WBXML_GLOBAL_TOKEN_LITERAL);
                XML_WBXML::intToMBUInt32($this->_output, $i);
            }
        } else {
            $this->_output.= $a;
        }

        $i = $this->_stringTable->get($name);
        if ($i != null) {
            $this->_output.= chr(XML_WBXML_GLOBAL_TOKEN_STR_T);
            XML_WBXML::intToMBUInt32($this->_output, $i);
        } else {
            $this->_output.= chr(XML_WBXML_GLOBAL_TOKEN_STR_I);
            $this->writeString($value, $cs);
        }
    }

    function endElement($uri, $name)
    {
        if ($this->_subParser == null) {
            $this->writeStartElement(false);
            $this->_output .= chr(XML_WBXML_GLOBAL_TOKEN_END);
        } else {
            $this->_subParserStack--;
            if ($this->_subParserStack == 0) {
                unset($this->_subParser);
            }
        }
    }

    function _endElement($parser, $tag)
    {
        list($uri, $name) = $this->_splitURI($tag);
        $this->endElement($uri, $name);
    }

    function changecodepage($uri)
    {
        $cp = $this->_dtd->toCodePageURI($uri);

        if (strlen($cp)) {
            $this->_dtd = &$this->_dtdManager->getInstanceURI($uri);

            $this->_output .= chr(XML_WBXML_GLOBAL_TOKEN_SWITCH_PAGE);
            $this->_output .= chr($cp);
        } else {
            $this->_output .= chr(XML_WBXML_GLOBAL_TOKEN_OPAQUE);

            $this->_subParser = &new XML_WBXML_Encoder($this->_output);
            $this->startElement($this->_storeURI, $this->_storeName, $this->_storeAttributes);

            $this->_subParserStack = 2;

            $this->_storeURI = null;
            $this->_storeName = null;
            $this->_storeAttributes = null;
        }
    }

    /**
     * Getter for property output.
     */
    function getOutput($output)
    {
        return $this->_output;
    }

}





More information about the commits mailing list