* * * \**********************************************************/ require_once('HproseCommon.php'); require_once('HproseTags.php'); require_once('HproseClassManager.php'); class HproseRawReader { public $stream; function __construct(&$stream) { $this->stream = &$stream; } public function readRaw($ostream = NULL, $tag = NULL) { if (is_null($ostream)) { $ostream = new HproseStringStream(); } if (is_null($tag)) { $tag = $this->stream->getc(); } switch ($tag) { case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': case HproseTags::TagNull: case HproseTags::TagEmpty: case HproseTags::TagTrue: case HproseTags::TagFalse: case HproseTags::TagNaN: $ostream->write($tag); break; case HproseTags::TagInfinity: $ostream->write($tag); $ostream->write($this->stream->getc()); break; case HproseTags::TagInteger: case HproseTags::TagLong: case HproseTags::TagDouble: case HproseTags::TagRef: $this->readNumberRaw($ostream, $tag); break; case HproseTags::TagDate: case HproseTags::TagTime: $this->readDateTimeRaw($ostream, $tag); break; case HproseTags::TagUTF8Char: $this->readUTF8CharRaw($ostream, $tag); break; case HproseTags::TagBytes: $this->readBytesRaw($ostream, $tag); break; case HproseTags::TagString: $this->readStringRaw($ostream, $tag); break; case HproseTags::TagGuid: $this->readGuidRaw($ostream, $tag); break; case HproseTags::TagList: case HproseTags::TagMap: case HproseTags::TagObject: $this->readComplexRaw($ostream, $tag); break; case HproseTags::TagClass: $this->readComplexRaw($ostream, $tag); $this->readRaw($ostream); break; case HproseTags::TagError: $ostream->write($tag); $this->readRaw($ostream); break; case false: throw new HproseException("No byte found in stream"); default: throw new HproseException("Unexpected serialize tag '" + $tag + "' in stream"); } return $ostream; } private function readNumberRaw($ostream, $tag) { $s = $tag . $this->stream->readuntil(HproseTags::TagSemicolon) . HproseTags::TagSemicolon; $ostream->write($s); } private function readDateTimeRaw($ostream, $tag) { $s = $tag; do { $tag = $this->stream->getc(); $s .= $tag; } while ($tag != HproseTags::TagSemicolon && $tag != HproseTags::TagUTC); $ostream->write($s); } private function readUTF8CharRaw($ostream, $tag) { $s = $tag; $tag = $this->stream->getc(); $s .= $tag; $a = ord($tag); if (($a & 0xE0) == 0xC0) { $s .= $this->stream->getc(); } elseif (($a & 0xF0) == 0xE0) { $s .= $this->stream->read(2); } elseif ($a > 0x7F) { throw new HproseException("bad utf-8 encoding"); } $ostream->write($s); } private function readBytesRaw($ostream, $tag) { $len = $this->stream->readuntil(HproseTags::TagQuote); $s = $tag . $len . HproseTags::TagQuote . $this->stream->read((int)$len) . HproseTags::TagQuote; $this->stream->skip(1); $ostream->write($s); } private function readStringRaw($ostream, $tag) { $len = $this->stream->readuntil(HproseTags::TagQuote); $s = $tag . $len . HproseTags::TagQuote; $len = (int)$len; $this->stream->mark(); $utf8len = 0; for ($i = 0; $i < $len; ++$i) { switch (ord($this->stream->getc()) >> 4) { case 0: case 1: case 2: case 3: case 4: case 5: case 6: case 7: { // 0xxx xxxx $utf8len++; break; } case 12: case 13: { // 110x xxxx 10xx xxxx $this->stream->skip(1); $utf8len += 2; break; } case 14: { // 1110 xxxx 10xx xxxx 10xx xxxx $this->stream->skip(2); $utf8len += 3; break; } case 15: { // 1111 0xxx 10xx xxxx 10xx xxxx 10xx xxxx $this->stream->skip(3); $utf8len += 4; ++$i; break; } default: { throw new HproseException('bad utf-8 encoding'); } } } $this->stream->reset(); $this->stream->unmark(); $s .= $this->stream->read($utf8len) . HproseTags::TagQuote; $this->stream->skip(1); $ostream->write($s); } private function readGuidRaw($ostream, $tag) { $s = $tag . $this->stream->read(38); $ostream->write($s); } private function readComplexRaw($ostream, $tag) { $s = $tag . $this->stream->readuntil(HproseTags::TagOpenbrace) . HproseTags::TagOpenbrace; $ostream->write($s); while (($tag = $this->stream->getc()) != HproseTags::TagClosebrace) { $this->readRaw($ostream, $tag); } $ostream->write($tag); } } class HproseSimpleReader extends HproseRawReader { private $classref; function __construct(&$stream) { parent::__construct($stream); $this->classref = array(); } public function &unserialize($tag = NULL) { if (is_null($tag)) { $tag = $this->stream->getc(); } $result = NULL; switch ($tag) { case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': $result = (int)$tag; break; case HproseTags::TagInteger: $result = $this->readInteger(); break; case HproseTags::TagLong: $result = $this->readLong(); break; case HproseTags::TagDouble: $result = $this->readDouble(); break; case HproseTags::TagNull: break; case HproseTags::TagEmpty: $result = ''; break; case HproseTags::TagTrue: $result = true; break; case HproseTags::TagFalse: $result = false; break; case HproseTags::TagNaN: $result = log(-1); break; case HproseTags::TagInfinity: $result = $this->readInfinity(); break; case HproseTags::TagDate: $result = $this->readDate(); break; case HproseTags::TagTime: $result = $this->readTime(); break; case HproseTags::TagBytes: $result = $this->readBytes(); break; case HproseTags::TagUTF8Char: $result = $this->readUTF8Char(); break; case HproseTags::TagString: $result = $this->readString(); break; case HproseTags::TagGuid: $result = $this->readGuid(); break; case HproseTags::TagList: $result = &$this->readList(); break; case HproseTags::TagMap: $result = &$this->readMap(); break; case HproseTags::TagClass: $this->readClass(); $result = &$this->unserialize(); break; case HproseTags::TagObject: $result = $this->readObject(); break; case HproseTags::TagError: throw new HproseException($this->readString(true)); case false: throw new HproseException('No byte found in stream'); default: throw new HproseException("Unexpected serialize tag '$tag' in stream"); } return $result; } public function checkTag($expectTag, $tag = NULL) { if (is_null($tag)) $tag = $this->stream->getc(); if ($tag != $expectTag) { throw new HproseException("Tag '$expectTag' expected, but '$tag' found in stream"); } } public function checkTags($expectTags, $tag = NULL) { if (is_null($tag)) $tag = $this->stream->getc(); if (!in_array($tag, $expectTags)) { $expectTags = implode('', $expectTags); throw new HproseException("Tag '$expectTags' expected, but '$tag' found in stream"); } return $tag; } public function readInteger($includeTag = false) { if ($includeTag) { $tag = $this->stream->getc(); if (($tag >= '0') && ($tag <= '9')) { return (int)$tag; } $this->checkTag(HproseTags::TagInteger, $tag); } return (int)($this->stream->readuntil(HproseTags::TagSemicolon)); } public function readLong($includeTag = false) { if ($includeTag) { $tag = $this->stream->getc(); if (($tag >= '0') && ($tag <= '9')) { return $tag; } $this->checkTag(HproseTags::TagLong, $tag); } return $this->stream->readuntil(HproseTags::TagSemicolon); } public function readDouble($includeTag = false) { if ($includeTag) { $tag = $this->stream->getc(); if (($tag >= '0') && ($tag <= '9')) { return (double)$tag; } $this->checkTag(HproseTags::TagDouble, $tag); } return (double)($this->stream->readuntil(HproseTags::TagSemicolon)); } public function readNaN() { $this->checkTag(HproseTags::TagNaN); return log(-1); } public function readInfinity($includeTag = false) { if ($includeTag) $this->checkTag(HproseTags::TagInfinity); return (($this->stream->getc() == HproseTags::TagNeg) ? log(0) : -log(0)); } public function readNull() { $this->checkTag(HproseTags::TagNull); return NULL; } public function readEmpty() { $this->checkTag(HproseTags::TagEmpty); return ''; } public function readBoolean() { $tag = $this->checkTags(array(HproseTags::TagTrue, HproseTags::TagFalse)); return ($tag == HproseTags::TagTrue); } public function readDate($includeTag = false) { if ($includeTag) $this->checkTag(HproseTags::TagDate); $year = (int)($this->stream->read(4)); $month = (int)($this->stream->read(2)); $day = (int)($this->stream->read(2)); $tag = $this->stream->getc(); if ($tag == HproseTags::TagTime) { $hour = (int)($this->stream->read(2)); $minute = (int)($this->stream->read(2)); $second = (int)($this->stream->read(2)); $microsecond = 0; $tag = $this->stream->getc(); if ($tag == HproseTags::TagPoint) { $microsecond = (int)($this->stream->read(3)) * 1000; $tag = $this->stream->getc(); if (($tag >= '0') && ($tag <= '9')) { $microsecond += (int)($tag) * 100 + (int)($this->stream->read(2)); $tag = $this->stream->getc(); if (($tag >= '0') && ($tag <= '9')) { $this->stream->skip(2); $tag = $this->stream->getc(); } } } if ($tag == HproseTags::TagUTC) { $date = new HproseDateTime($year, $month, $day, $hour, $minute, $second, $microsecond, true); } else { $date = new HproseDateTime($year, $month, $day, $hour, $minute, $second, $microsecond); } } elseif ($tag == HproseTags::TagUTC) { $date = new HproseDate($year, $month, $day, true); } else { $date = new HproseDate($year, $month, $day); } return $date; } public function readTime($includeTag = false) { if ($includeTag) $this->checkTag(HproseTags::TagTime); $hour = (int)($this->stream->read(2)); $minute = (int)($this->stream->read(2)); $second = (int)($this->stream->read(2)); $microsecond = 0; $tag = $this->stream->getc(); if ($tag == HproseTags::TagPoint) { $microsecond = (int)($this->stream->read(3)) * 1000; $tag = $this->stream->getc(); if (($tag >= '0') && ($tag <= '9')) { $microsecond += (int)($tag) * 100 + (int)($this->stream->read(2)); $tag = $this->stream->getc(); if (($tag >= '0') && ($tag <= '9')) { $this->stream->skip(2); $tag = $this->stream->getc(); } } } if ($tag == HproseTags::TagUTC) { $time = new HproseTime($hour, $minute, $second, $microsecond, true); } else { $time = new HproseTime($hour, $minute, $second, $microsecond); } return $time; } public function readBytes($includeTag = false) { if ($includeTag) $this->checkTag(HproseTags::TagBytes); $count = (int)($this->stream->readuntil(HproseTags::TagQuote)); $bytes = $this->stream->read($count); $this->stream->skip(1); return $bytes; } public function readUTF8Char($includeTag = false) { if ($includeTag) $this->checkTag(HproseTags::TagUTF8Char); $c = $this->stream->getc(); $s = $c; $a = ord($c); if (($a & 0xE0) == 0xC0) { $s .= $this->stream->getc(); } elseif (($a & 0xF0) == 0xE0) { $s .= $this->stream->read(2); } elseif ($a > 0x7F) { throw new HproseException("bad utf-8 encoding"); } return $s; } public function readString($includeTag = false) { if ($includeTag) $this->checkTag(HproseTags::TagString); $len = (int)$this->stream->readuntil(HproseTags::TagQuote); $this->stream->mark(); $utf8len = 0; for ($i = 0; $i < $len; ++$i) { switch (ord($this->stream->getc()) >> 4) { case 0: case 1: case 2: case 3: case 4: case 5: case 6: case 7: { // 0xxx xxxx $utf8len++; break; } case 12: case 13: { // 110x xxxx 10xx xxxx $this->stream->skip(1); $utf8len += 2; break; } case 14: { // 1110 xxxx 10xx xxxx 10xx xxxx $this->stream->skip(2); $utf8len += 3; break; } case 15: { // 1111 0xxx 10xx xxxx 10xx xxxx 10xx xxxx $this->stream->skip(3); $utf8len += 4; ++$i; break; } default: { throw new HproseException('bad utf-8 encoding'); } } } $this->stream->reset(); $this->stream->unmark(); $s = $this->stream->read($utf8len); $this->stream->skip(1); return $s; } public function readGuid($includeTag = false) { if ($includeTag) $this->checkTag(HproseTags::TagGuid); $this->stream->skip(1); $s = $this->stream->read(36); $this->stream->skip(1); return $s; } protected function &readListBegin() { $list = array(); return $list; } protected function &readListEnd(&$list) { $count = (int)$this->stream->readuntil(HproseTags::TagOpenbrace); for ($i = 0; $i < $count; ++$i) { $list[] = &$this->unserialize(); } $this->stream->skip(1); return $list; } public function &readList($includeTag = false) { if ($includeTag) $this->checkTag(HproseTags::TagList); $list = &$this->readListBegin(); return $this->readListEnd($list); } protected function &readMapBegin() { $map = array(); return $map; } protected function &readMapEnd(&$map) { $count = (int)$this->stream->readuntil(HproseTags::TagOpenbrace); for ($i = 0; $i < $count; ++$i) { $key = &$this->unserialize(); $map[$key] = &$this->unserialize(); } $this->stream->skip(1); return $map; } public function &readMap($includeTag = false) { if ($includeTag) $this->checkTag(HproseTags::TagMap); $map = &$this->readMapBegin(); return $this->readMapEnd($map); } protected function readObjectBegin() { list($classname, $fields) = $this->classref[(int)$this->stream->readuntil(HproseTags::TagOpenbrace)]; $object = new $classname; return array($object, $fields); } protected function readObjectEnd($object, $fields) { $count = count($fields); if (class_exists('ReflectionClass')) { $reflector = new ReflectionClass($object); for ($i = 0; $i < $count; ++$i) { $field = $fields[$i]; if ($reflector->hasProperty($field)) { $property = $reflector->getProperty($field); $property->setAccessible(true); $property->setValue($object, $this->unserialize()); } else { $object->$field = &$this->unserialize(); } } } else { for ($i = 0; $i < $count; ++$i) { $object->$fields[$i] = &$this->unserialize(); } } $this->stream->skip(1); return $object; } public function readObject($includeTag = false) { if ($includeTag) { $tag = $this->checkTags(array(HproseTags::TagClass, HproseTags::TagObject)); if ($tag == HproseTags::TagClass) { $this->readClass(); return $this->readObject(true); } } list($object, $fields) = $this->readObjectBegin(); return $this->readObjectEnd($object, $fields); } protected function readClass() { $classname = HproseClassManager::getClass(self::readString()); $count = (int)$this->stream->readuntil(HproseTags::TagOpenbrace); $fields = array(); for ($i = 0; $i < $count; ++$i) { $fields[] = $this->readString(true); } $this->stream->skip(1); $this->classref[] = array($classname, $fields); } public function reset() { $this->classref = array(); } } class HproseReader extends HproseSimpleReader { private $ref; function __construct(&$stream) { parent::__construct($stream); $this->ref = array(); } public function &unserialize($tag = NULL) { if (is_null($tag)) { $tag = $this->stream->getc(); } if ($tag == HproseTags::TagRef) { return $this->readRef(); } return parent::unserialize($tag); } public function readDate($includeTag = false) { if ($includeTag) { $tag = $this->checkTags(array(HproseTags::TagDate, HproseTags::TagRef)); if ($tag == HproseTags::TagRef) return $this->readRef(); } $date = parent::readDate(); $this->ref[] = $date; return $date; } public function readTime($includeTag = false) { if ($includeTag) { $tag = $this->checkTags(array(HproseTags::TagTime, HproseTags::TagRef)); if ($tag == HproseTags::TagRef) return $this->readRef(); } $time = parent::readTime(); $this->ref[] = $time; return $time; } public function readBytes($includeTag = false) { if ($includeTag) { $tag = $this->checkTags(array(HproseTags::TagBytes, HproseTags::TagRef)); if ($tag == HproseTags::TagRef) return $this->readRef(); } $bytes = parent::readBytes(); $this->ref[] = $bytes; return $bytes; } public function readString($includeTag = false) { if ($includeTag) { $tag = $this->checkTags(array(HproseTags::TagString, HproseTags::TagRef)); if ($tag == HproseTags::TagRef) return $this->readRef(); } $str = parent::readString(); $this->ref[] = $str; return $str; } public function readGuid($includeTag = false) { if ($includeTag) { $tag = $this->checkTags(array(HproseTags::TagGuid, HproseTags::TagRef)); if ($tag == HproseTags::TagRef) return $this->readRef(); } $guid = parent::readGuid(); $this->ref[] = $guid; return $guid; } public function &readList($includeTag = false) { if ($includeTag) { $tag = $this->checkTags(array(HproseTags::TagList, HproseTags::TagRef)); if ($tag == HproseTags::TagRef) return $this->readRef(); } $list = &$this->readListBegin(); $this->ref[] = &$list; return $this->readListEnd($list); } public function &readMap($includeTag = false) { if ($includeTag) { $tag = $this->checkTags(array(HproseTags::TagMap, HproseTags::TagRef)); if ($tag == HproseTags::TagRef) return $this->readRef(); } $map = &$this->readMapBegin(); $this->ref[] = &$map; return $this->readMapEnd($map); } public function readObject($includeTag = false) { if ($includeTag) { $tag = $this->checkTags(array(HproseTags::TagClass, HproseTags::TagObject, HproseTags::TagRef)); if ($tag == HproseTags::TagRef) return $this->readRef(); if ($tag == HproseTags::TagClass) { $this->readClass(); return $this->readObject(true); } } list($object, $fields) = $this->readObjectBegin(); $this->ref[] = $object; return $this->readObjectEnd($object, $fields); } private function &readRef() { $ref = &$this->ref[(int)$this->stream->readuntil(HproseTags::TagSemicolon)]; if (gettype($ref) == 'array') { $result = &$ref; } else { $result = $ref; } return $result; } public function reset() { parent::reset(); $this->ref = array(); } } ?>