You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

301 lines
11 KiB
PHP

<?php
/**********************************************************\
| |
| hprose |
| |
| Official WebSite: http://www.hprose.com/ |
| http://www.hprose.net/ |
| http://www.hprose.org/ |
| |
\**********************************************************/
/**********************************************************\
* *
* HproseWriter.php *
* *
* hprose writer library for php5. *
* *
* LastModified: Nov 13, 2013 *
* Author: Ma Bingyao <andot@hprfc.com> *
* *
\**********************************************************/
require_once('HproseCommon.php');
require_once('HproseTags.php');
require_once('HproseClassManager.php');
class HproseSimpleWriter {
public $stream;
private $classref;
private $fieldsref;
function __construct(&$stream) {
$this->stream = &$stream;
$this->classref = array();
$this->fieldsref = array();
}
public function serialize(&$var) {
if ((!isset($var)) || ($var === NULL)) {
$this->writeNull();
}
elseif (is_scalar($var)) {
if (is_int($var)) {
$this->writeInteger($var);
}
elseif (is_bool($var)) {
$this->writeBoolean($var);
}
elseif (is_float($var)) {
$this->writeDouble($var);
}
elseif (is_string($var)) {
if ($var === '') {
$this->writeEmpty();
}
elseif ((strlen($var) < 4) && is_utf8($var) && (ustrlen($var) == 1)) {
$this->writeUTF8Char($var);
}
elseif (is_utf8($var)) {
$this->writeString($var, true);
}
else {
$this->writeBytes($var, true);
}
}
}
elseif (is_array($var)) {
if (is_list($var)) {
$this->writeList($var, true);
}
else {
$this->writeMap($var, true);
}
}
elseif (is_object($var)) {
if ($var instanceof stdClass) {
$this->writeStdObject($var, true);
}
elseif (($var instanceof HproseDate) || ($var instanceof HproseDateTime)) {
$this->writeDate($var, true);
}
elseif ($var instanceof HproseTime) {
$this->writeTime($var, true);
}
else {
$this->writeObject($var, true);
}
}
else {
throw new HproseException('Not support to serialize this data');
}
}
public function writeInteger($integer) {
if ($integer >= 0 && $integer <= 9) {
$this->stream->write((string)$integer);
}
else {
$this->stream->write(HproseTags::TagInteger . $integer . HproseTags::TagSemicolon);
}
}
public function writeLong($long) {
if ($long >= '0' && $long <= '9') {
$this->stream->write($long);
}
else {
$this->stream->write(HproseTags::TagLong . $long . HproseTags::TagSemicolon);
}
}
public function writeDouble($double) {
if (is_nan($double)) {
$this->writeNaN();
}
elseif (is_infinite($double)) {
$this->writeInfinity($double > 0);
}
else {
$this->stream->write(HproseTags::TagDouble . $double . HproseTags::TagSemicolon);
}
}
public function writeNaN() {
$this->stream->write(HproseTags::TagNaN);
}
public function writeInfinity($positive = true) {
$this->stream->write(HproseTags::TagInfinity . ($positive ? HproseTags::TagPos : HproseTags::TagNeg));
}
public function writeNull() {
$this->stream->write(HproseTags::TagNull);
}
public function writeEmpty() {
$this->stream->write(HproseTags::TagEmpty);
}
public function writeBoolean($bool) {
$this->stream->write($bool ? HproseTags::TagTrue : HproseTags::TagFalse);
}
public function writeDate($date, $checkRef = false) {
if ($date->utc) {
$this->stream->write(HproseTags::TagDate . $date->toString(false));
}
else {
$this->stream->write(HproseTags::TagDate . $date->toString(false) . HproseTags::TagSemicolon);
}
}
public function writeTime($time, $checkRef = false) {
if ($time->utc) {
$this->stream->write(HproseTags::TagTime . $time->toString(false));
}
else {
$this->stream->write(HproseTags::TagTime . $time->toString(false) . HproseTags::TagSemicolon);
}
}
public function writeBytes($bytes, $checkRef = false) {
$len = strlen($bytes);
$this->stream->write(HproseTags::TagBytes);
if ($len > 0) $this->stream->write((string)$len);
$this->stream->write(HproseTags::TagQuote . $bytes . HproseTags::TagQuote);
}
public function writeUTF8Char($char) {
$this->stream->write(HproseTags::TagUTF8Char . $char);
}
public function writeString($str, $checkRef = false) {
$len = ustrlen($str);
$this->stream->write(HproseTags::TagString);
if ($len > 0) $this->stream->write((string)$len);
$this->stream->write(HproseTags::TagQuote . $str . HproseTags::TagQuote);
}
public function writeList(&$list, $checkRef = false) {
$count = count($list);
$this->stream->write(HproseTags::TagList);
if ($count > 0) $this->stream->write((string)$count);
$this->stream->write(HproseTags::TagOpenbrace);
for ($i = 0; $i < $count; ++$i) {
$this->serialize($list[$i]);
}
$this->stream->write(HproseTags::TagClosebrace);
}
public function writeMap(&$map, $checkRef = false) {
$count = count($map);
$this->stream->write(HproseTags::TagMap);
if ($count > 0) $this->stream->write((string)$count);
$this->stream->write(HproseTags::TagOpenbrace);
foreach ($map as $key => &$value) {
$this->serialize($key);
$this->serialize($value);
}
$this->stream->write(HproseTags::TagClosebrace);
}
public function writeStdObject($obj, $checkRef = false) {
$map = (array)$obj;
self::writeMap($map);
}
protected function writeObjectBegin($obj) {
$class = get_class($obj);
$alias = HproseClassManager::getClassAlias($class);
$fields = array_keys((array)$obj);
if (array_key_exists($alias, $this->classref)) {
$index = $this->classref[$alias];
}
else {
$index = $this->writeClass($alias, $fields);
}
return $index;
}
protected function writeObjectEnd($obj, $index) {
$fields = $this->fieldsref[$index];
$count = count($fields);
$this->stream->write(HproseTags::TagObject . $index . HproseTags::TagOpenbrace);
$array = (array)$obj;
for ($i = 0; $i < $count; ++$i) {
$this->serialize($array[$fields[$i]]);
}
$this->stream->write(HproseTags::TagClosebrace);
}
public function writeObject($obj, $checkRef = false) {
$this->writeObjectEnd($obj, $this->writeObjectBegin($obj));
}
protected function writeClass($alias, $fields) {
$len = ustrlen($alias);
$this->stream->write(HproseTags::TagClass . $len .
HproseTags::TagQuote . $alias . HproseTags::TagQuote);
$count = count($fields);
if ($count > 0) $this->stream->write((string)$count);
$this->stream->write(HproseTags::TagOpenbrace);
for ($i = 0; $i < $count; ++$i) {
$field = $fields[$i];
if ($field{0} === "\0") {
$field = substr($field, strpos($field, "\0", 1) + 1);
}
$this->writeString($field);
}
$this->stream->write(HproseTags::TagClosebrace);
$index = count($this->fieldsref);
$this->classref[$alias] = $index;
$this->fieldsref[$index] = $fields;
return $index;
}
public function reset() {
$this->classref = array();
$this->fieldsref = array();
}
}
class HproseWriter extends HproseSimpleWriter {
private $ref;
private $arrayref;
function __construct(&$stream) {
parent::__construct($stream);
$this->ref = array();
$this->arrayref = array();
}
private function writeRef(&$obj, $checkRef, $writeBegin, $writeEnd) {
if (is_string($obj)) {
$key = 's_' . $obj;
}
elseif (is_array($obj)) {
if (($i = array_ref_search($obj, $this->arrayref)) === false) {
$i = count($this->arrayref);
$this->arrayref[$i] = &$obj;
}
$key = 'a_' . $i;
}
else {
$key = 'o_' . spl_object_hash($obj);
}
if ($checkRef && array_key_exists($key, $this->ref)) {
$this->stream->write(HproseTags::TagRef . $this->ref[$key] . HproseTags::TagSemicolon);
}
else {
$result = $writeBegin ? call_user_func_array($writeBegin, array(&$obj)) : false;
$index = count($this->ref);
$this->ref[$key] = $index;
call_user_func_array($writeEnd, array(&$obj, $result));
}
}
public function writeDate($date, $checkRef = false) {
$this->writeRef($date, $checkRef, NULL, array(&$this, 'parent::writeDate'));
}
public function writeTime($time, $checkRef = false) {
$this->writeRef($time, $checkRef, NULL, array(&$this, 'parent::writeTime'));
}
public function writeBytes($bytes, $checkRef = false) {
$this->writeRef($bytes, $checkRef, NULL, array(&$this, 'parent::writeBytes'));
}
public function writeString($str, $checkRef = false) {
$this->writeRef($str, $checkRef, NULL, array(&$this, 'parent::writeString'));
}
public function writeList(&$list, $checkRef = false) {
$this->writeRef($list, $checkRef, NULL, array(&$this, 'parent::writeList'));
}
public function writeMap(&$map, $checkRef = false) {
$this->writeRef($map, $checkRef, NULL, array(&$this, 'parent::writeMap'));
}
public function writeStdObject($obj, $checkRef = false) {
$this->writeRef($obj, $checkRef, NULL, array(&$this, 'parent::writeStdObject'));
}
public function writeObject($obj, $checkRef = false) {
$this->writeRef($obj, $checkRef, array(&$this, 'writeObjectBegin'), array(&$this, 'writeObjectEnd'));
}
public function reset() {
parent::reset();
$this->ref = array();
$this->arrayref = array();
}
}
?>