Commit f0039677 authored by Etienne CHAMPETIER's avatar Etienne CHAMPETIER

ZP-797 WBXMLDecoder is handling ActiveSync WBXML, which is only a subset of WBXML.

Released under the Affero GNU General Public License (AGPL) version 3.

let's cleanup and remove some (non working) code
for exemple we do not handle attributes
see also:
http://msdn.microsoft.com/en-us/library/hh475626%28v=exchg.80%29.aspx
http://www.w3.org/1999/06/NOTE-wbxml-19990624/
https://android.googlesource.com/platform/packages/apps/Exchange/+/master/src/com/android/exchange/adapter/Parser.java
parent 650d633d
......@@ -45,19 +45,12 @@
class WBXMLDecoder extends WBXMLDefs {
private $in;
private $version;
private $publicid;
private $publicstringid;
private $charsetid;
private $stringtable;
private $inLog;
private $tagcp = 0;
private $attrcp = 0;
private $ungetbuffer;
private $log = false;
private $logStack = array();
private $inputBuffer = "";
private $isWBXML = true;
......@@ -104,30 +97,35 @@ class WBXMLDecoder extends WBXMLDefs {
/**
* WBXML Decode Constructor
* We only handle ActiveSync WBXML, which is a subset of WBXML
*
* @param stream $input the incoming data stream
*
* @access public
*/
public function WBXMLDecoder($input) {
// make sure WBXML_DEBUG is defined. It should be at this point
if (!defined('WBXML_DEBUG')) define('WBXML_DEBUG', false);
$this->log = defined('WBXML_DEBUG') && WBXML_DEBUG;
$this->in = $input;
$this->readVersion();
if (isset($this->version) && $this->version != self::VERSION) {
$version = $this->getByte();
if($version != self::VERSION) {
$this->inputBuffer .= chr($version);
$this->isWBXML = false;
return;
}
$this->publicid = $this->getMBUInt();
if($this->publicid == 0) {
$this->publicstringid = $this->getMBUInt();
}
$publicid = $this->getMBUInt();
if($publicid !== 1)
throw new WBXMLException("Wrong publicid : ".$publicid);
$this->charsetid = $this->getMBUInt();
$this->stringtable = $this->getStringTable();
$charsetid = $this->getMBUInt();
if ($charsetid !== 106)
throw new WBXMLException("Wrong charset : ".$charsetid);
$stringtablesize = $this->getMBUInt();
if ($stringtablesize !== 0)
throw new WBXMLException("Wrong string table size : ".$stringtablesize);
}
/**
......@@ -306,7 +304,8 @@ class WBXMLDecoder extends WBXMLDefs {
}
$el = $this->_getToken();
$this->logToken($el);
if($this->log)
$this->logToken($el);
return $el;
}
......@@ -320,9 +319,6 @@ class WBXMLDecoder extends WBXMLDefs {
* @return
*/
private function logToken($el) {
if(!WBXML_DEBUG)
return;
$spaces = str_repeat(" ", count($this->logStack));
switch($el[EN_TYPE]) {
......@@ -370,203 +366,46 @@ class WBXMLDecoder extends WBXMLDefs {
$element[EN_TYPE] = EN_TYPE_ENDTAG;
return $element;
case self::WBXML_ENTITY:
$entity = $this->getMBUInt();
$element[EN_TYPE] = EN_TYPE_CONTENT;
$element[EN_CONTENT] = $this->entityToCharset($entity);
return $element;
case self::WBXML_STR_I:
$element[EN_TYPE] = EN_TYPE_CONTENT;
$element[EN_CONTENT] = $this->getTermStr();
return $element;
case self::WBXML_LITERAL:
$element[EN_TYPE] = EN_TYPE_STARTTAG;
$element[EN_TAG] = $this->getStringTableEntry($this->getMBUInt());
$element[EN_FLAGS] = 0;
return $element;
case self::WBXML_EXT_I_0:
case self::WBXML_EXT_I_1:
case self::WBXML_EXT_I_2:
$this->getTermStr();
// Ignore extensions
continue;
case self::WBXML_PI:
// Ignore PI
$this->getAttributes();
continue;
case self::WBXML_LITERAL_C:
$element[EN_TYPE] = EN_TYPE_STARTTAG;
$element[EN_TAG] = $this->getStringTableEntry($this->getMBUInt());
$element[EN_FLAGS] = EN_FLAGS_CONTENT;
return $element;
case self::WBXML_EXT_T_0:
case self::WBXML_EXT_T_1:
case self::WBXML_EXT_T_2:
$this->getMBUInt();
// Ingore extensions;
continue;
case self::WBXML_STR_T:
$element[EN_TYPE] = EN_TYPE_CONTENT;
$element[EN_CONTENT] = $this->getStringTableEntry($this->getMBUInt());
return $element;
case self::WBXML_LITERAL_A:
$element[EN_TYPE] = EN_TYPE_STARTTAG;
$element[EN_TAG] = $this->getStringTableEntry($this->getMBUInt());
$element[EN_ATTRIBUTES] = $this->getAttributes();
$element[EN_FLAGS] = EN_FLAGS_ATTRIBUTES;
return $element;
case self::WBXML_EXT_0:
case self::WBXML_EXT_1:
case self::WBXML_EXT_2:
continue;
case self::WBXML_OPAQUE:
$length = $this->getMBUInt();
$element[EN_TYPE] = EN_TYPE_CONTENT;
$element[EN_CONTENT] = $this->getOpaque($length);
return $element;
case self::WBXML_LITERAL_AC:
$element[EN_TYPE] = EN_TYPE_STARTTAG;
$element[EN_TAG] = $this->getStringTableEntry($this->getMBUInt());
$element[EN_ATTRIBUTES] = $this->getAttributes();
$element[EN_FLAGS] = EN_FLAGS_ATTRIBUTES | EN_FLAGS_CONTENT;
return $element;
default:
$element[EN_TYPE] = EN_TYPE_STARTTAG;
$element[EN_TAG] = $this->getMapping($this->tagcp, $byte & 0x3f);
$element[EN_FLAGS] = ($byte & 0x80 ? EN_FLAGS_ATTRIBUTES : 0) | ($byte & 0x40 ? EN_FLAGS_CONTENT : 0);
if($byte & 0x80)
$element[EN_ATTRIBUTES] = $this->getAttributes();
return $element;
}
}
}
/**
* Gets attributes
*
* @access private
* @return
*/
private function getAttributes() {
$attributes = array();
$attr = "";
WBXMLDecoder::ResetInWhile("decoderGetAttributes");
while(WBXMLDecoder::InWhile("decoderGetAttributes")) {
$byte = $this->getByte();
if(count($byte) == 0)
break;
switch($byte) {
case self::WBXML_SWITCH_PAGE:
$this->attrcp = $this->getByte();
break;
case self::WBXML_END:
if($attr != "")
$attributes += $this->splitAttribute($attr);
return $attributes;
case self::WBXML_ENTITY:
$entity = $this->getMBUInt();
$attr .= $this->entityToCharset($entity);
return $attr; /* fmbiete's contribution r1534, ZP-324 */
case self::WBXML_STR_I:
$attr .= $this->getTermStr();
return $attr; /* fmbiete's contribution r1534, ZP-324 */
case self::WBXML_LITERAL:
if($attr != "")
$attributes += $this->splitAttribute($attr);
$attr = $this->getStringTableEntry($this->getMBUInt());
return $attr; /* fmbiete's contribution r1534, ZP-324 */
case self::WBXML_EXT_I_0:
case self::WBXML_EXT_I_1:
case self::WBXML_EXT_I_2:
$this->getTermStr();
continue;
case self::WBXML_PI:
case self::WBXML_LITERAL_C:
// Invalid
return false;
case self::WBXML_EXT_T_0:
case self::WBXML_EXT_T_1:
case self::WBXML_EXT_T_2:
$this->getMBUInt();
continue;
case self::WBXML_STR_T:
$attr .= $this->getStringTableEntry($this->getMBUInt());
return $attr; /* fmbiete's contribution r1534, ZP-324 */
case self::WBXML_LITERAL_A:
return false;
case self::WBXML_EXT_0:
case self::WBXML_EXT_1:
case self::WBXML_EXT_2:
continue;
case self::WBXML_OPAQUE:
$length = $this->getMBUInt();
$attr .= $this->getOpaque($length);
return $attr; /* fmbiete's contribution r1534, ZP-324 */
case self::WBXML_LITERAL_AC:
return false;
throw new WBXMLException("Invalid token :".$byte);
default:
if($byte < 128) {
if($attr != "") {
$attributes += $this->splitAttribute($attr);
$attr = "";
}
}
$attr .= $this->getMapping($this->attrcp, $byte);
break;
if($byte & self::WBXML_WITH_ATTRIBUTES)
throw new WBXMLException("Attributes are not allowed :".$byte);
$element[EN_TYPE] = EN_TYPE_STARTTAG;
$element[EN_TAG] = $this->getMapping($this->tagcp, $byte & 0x3f);
$element[EN_FLAGS] = ($byte & self::WBXML_WITH_CONTENT ? EN_FLAGS_CONTENT : 0);
return $element;
}
}
}
/**
* Splits an attribute
*
* @param string $attr attribute to be splitted
*
* @access private
* @return array
*/
private function splitAttribute($attr) {
$attributes = array();
$pos = strpos($attr,chr(61)); // equals sign
if($pos)
$attributes[substr($attr, 0, $pos)] = substr($attr, $pos+1);
else
$attributes[$attr] = null;
return $attributes;
}
/**
* Reads from the stream until getting a string terminator
*
......@@ -637,22 +476,6 @@ class WBXMLDecoder extends WBXMLDefs {
return $uint;
}
/**
* Reads string table from the input stream
*
* @access private
* @return int
*/
private function getStringTable() {
$stringtable = "";
$length = $this->getMBUInt();
if($length > 0)
$stringtable = fread($this->in, $length);
return $stringtable;
}
/**
* Returns the mapping for a specified codepage and id
*
......@@ -672,19 +495,4 @@ class WBXMLDecoder extends WBXMLDefs {
return $this->dtd["codes"][$cp][$id];
}
}
/**
* Reads one byte from the input stream
*
* @access private
* @return void
*/
private function readVersion() {
$ch = $this->getByte();
if($ch != NULL) {
$this->inputBuffer .= chr($ch);
$this->version = $ch;
}
}
}
......@@ -61,24 +61,27 @@ class WBXMLDefs {
const WBXML_SWITCH_PAGE = 0x00;
const WBXML_END = 0x01;
const WBXML_ENTITY = 0x02;
const WBXML_ENTITY = 0x02; //not used in ActiveSync
const WBXML_STR_I = 0x03;
const WBXML_LITERAL = 0x04;
const WBXML_EXT_I_0 = 0x40;
const WBXML_EXT_I_1 = 0x41;
const WBXML_EXT_I_2 = 0x42;
const WBXML_PI = 0x43;
const WBXML_LITERAL_C = 0x44;
const WBXML_EXT_T_0 = 0x80;
const WBXML_EXT_T_1 = 0x81;
const WBXML_EXT_T_2 = 0x82;
const WBXML_STR_T = 0x83;
const WBXML_LITERAL_A = 0x84;
const WBXML_EXT_0 = 0xC0;
const WBXML_EXT_1 = 0xC1;
const WBXML_EXT_2 = 0xC2;
const WBXML_LITERAL = 0x04; //not used in ActiveSync
const WBXML_EXT_I_0 = 0x40; //not used in ActiveSync
const WBXML_EXT_I_1 = 0x41; //not used in ActiveSync
const WBXML_EXT_I_2 = 0x42; //not used in ActiveSync
const WBXML_PI = 0x43; //not used in ActiveSync
const WBXML_LITERAL_C = 0x44; //not used in ActiveSync
const WBXML_EXT_T_0 = 0x80; //not used in ActiveSync
const WBXML_EXT_T_1 = 0x81; //not used in ActiveSync
const WBXML_EXT_T_2 = 0x82; //not used in ActiveSync
const WBXML_STR_T = 0x83; //not used in ActiveSync
const WBXML_LITERAL_A = 0x84; //not used in ActiveSync
const WBXML_EXT_0 = 0xC0; //not used in ActiveSync
const WBXML_EXT_1 = 0xC1; //not used in ActiveSync
const WBXML_EXT_2 = 0xC2; //not used in ActiveSync
const WBXML_OPAQUE = 0xC3;
const WBXML_LITERAL_AC = 0xC4;
const WBXML_LITERAL_AC = 0xC4; //not used in ActiveSync
const WBXML_WITH_ATTRIBUTES = 0x80; //not used in ActiveSync
const WBXML_WITH_CONTENT = 0x40;
/**
* The WBXML DTDs
......
......@@ -46,9 +46,9 @@ class WBXMLEncoder extends WBXMLDefs {
private $_dtd;
private $_out;
private $_tagcp;
private $_attrcp;
private $_tagcp = 0;
private $log = false;
private $logStack = array();
// We use a delayed output mechanism in which we only output a tag when it actually has something
......@@ -63,14 +63,10 @@ class WBXMLEncoder extends WBXMLDefs {
private $bodyparts;
public function WBXMLEncoder($output, $multipart = false) {
// make sure WBXML_DEBUG is defined. It should be at this point
if (!defined('WBXML_DEBUG')) define('WBXML_DEBUG', false);
$this->log = @constant('WBXML_DEBUG') === true;
$this->_out = $output;
$this->_tagcp = 0;
$this->_attrcp = 0;
// reverse-map the DTD
foreach($this->dtd["namespaces"] as $nsid => $nsname) {
$this->_dtd["namespaces"][$nsname] = $nsid;
......@@ -124,7 +120,6 @@ class WBXMLEncoder extends WBXMLDefs {
if(!$nocontent) {
$stackelem['tag'] = $tag;
$stackelem['attributes'] = $attributes;
$stackelem['nocontent'] = $nocontent;
$stackelem['sent'] = false;
......@@ -134,7 +129,7 @@ class WBXMLEncoder extends WBXMLDefs {
// output of an empty tag, and we therefore output the stack here
} else {
$this->_outputStack();
$this->_startTag($tag, $attributes, $nocontent);
$this->_startTag($tag, $nocontent);
}
}
......@@ -252,7 +247,7 @@ class WBXMLEncoder extends WBXMLDefs {
private function _outputStack() {
for($i=0;$i<count($this->_stack);$i++) {
if(!$this->_stack[$i]['sent']) {
$this->_startTag($this->_stack[$i]['tag'], $this->_stack[$i]['attributes'], $this->_stack[$i]['nocontent']);
$this->_startTag($this->_stack[$i]['tag'], $this->_stack[$i]['nocontent']);
$this->_stack[$i]['sent'] = true;
}
}
......@@ -264,8 +259,9 @@ class WBXMLEncoder extends WBXMLDefs {
* @access private
* @return
*/
private function _startTag($tag, $attributes = false, $nocontent = false) {
$this->logStartTag($tag, $attributes, $nocontent);
private function _startTag($tag, $nocontent = false) {
if ($this->log)
$this->logStartTag($tag, $nocontent);
$mapping = $this->getMapping($tag);
......@@ -278,17 +274,11 @@ class WBXMLEncoder extends WBXMLDefs {
}
$code = $mapping["code"];
if(isset($attributes) && is_array($attributes) && count($attributes) > 0) {
$code |= 0x80;
}
if(!isset($nocontent) || !$nocontent)
$code |= 0x40;
$this->outByte($code);
if($code & 0x80)
$this->outAttributes($attributes);
}
/**
......@@ -299,7 +289,8 @@ class WBXMLEncoder extends WBXMLDefs {
* @return
*/
private function _content($content) {
$this->logContent($content);
if ($this->log)
$this->logContent($content);
$this->outByte(self::WBXML_STR_I);
$this->outTermStr($content);
}
......@@ -325,10 +316,11 @@ class WBXMLEncoder extends WBXMLDefs {
}
fwrite($this->_out, chr(0));
// data is out, do some logging
$stat = fstat($stream);
$logContent = sprintf("<<< written %d of %d bytes of %s data >>>", $written, $stat['size'], $asBase64 ? "base64 encoded":"plain");
$this->logContent($logContent);
if ($this->log) {
// data is out, do some logging
$stat = fstat($stream);
$this->logContent(sprintf("<<< written %d of %d bytes of %s data >>>", $written, $stat['size'], $asBase64 ? "base64 encoded":"plain"));
}
}
/**
......@@ -338,7 +330,8 @@ class WBXMLEncoder extends WBXMLDefs {
* @return
*/
private function _endTag() {
$this->logEndTag();
if ($this->log)
$this->logEndTag();
$this->outByte(self::WBXML_END);
}
......@@ -388,20 +381,6 @@ class WBXMLEncoder extends WBXMLDefs {
fwrite($this->_out, chr(0));
}
/**
* Output attributes
* We don't actually support this, because to do so, we would have
* to build a string table before sending the data (but we can't
* because we're streaming), so we'll just send an END, which just
* terminates the attribute list with 0 attributes.
*
* @access private
* @return
*/
private function outAttributes() {
$this->outByte(self::WBXML_END);
}
/**
* Switches the codepage
*
......@@ -475,16 +454,12 @@ class WBXMLEncoder extends WBXMLDefs {
* Logs a StartTag to ZLog
*
* @param $tag
* @param $attr
* @param $nocontent
*
* @access private
* @return
*/
private function logStartTag($tag, $attr, $nocontent) {
if(!WBXML_DEBUG)
return;
private function logStartTag($tag, $nocontent) {
$spaces = str_repeat(" ", count($this->logStack));
if($nocontent)
ZLog::Write(LOGLEVEL_WBXML,"O " . $spaces . " <$tag/>");
......@@ -501,9 +476,6 @@ class WBXMLEncoder extends WBXMLDefs {
* @return
*/
private function logEndTag() {
if(!WBXML_DEBUG)
return;
$spaces = str_repeat(" ", count($this->logStack));
$tag = array_pop($this->logStack);
ZLog::Write(LOGLEVEL_WBXML,"O " . $spaces . "</$tag>");
......@@ -518,9 +490,6 @@ class WBXMLEncoder extends WBXMLDefs {
* @return
*/
private function logContent($content) {
if(!WBXML_DEBUG)
return;
$spaces = str_repeat(" ", count($this->logStack));
ZLog::Write(LOGLEVEL_WBXML,"O " . $spaces . $content);
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment