497 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
			
		
		
	
	
			497 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
<?php
 | 
						|
class ERROR {
 | 
						|
	const INVALID_DATA = 1;
 | 
						|
	const UNDEFINED_DATA = 2;
 | 
						|
	const TYPE_MISSMATCH = 3;
 | 
						|
 | 
						|
	const READ_ONLY = 11;
 | 
						|
	const GREATER_COMPARATIVE = 21;
 | 
						|
 | 
						|
	const EOF = 100;
 | 
						|
 | 
						|
	function __construct($type, $a, $b)
 | 
						|
	{
 | 
						|
		throw new Exception($type);
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
class ByteArray extends ArrayObject {
 | 
						|
		private $position = 0;
 | 
						|
		public function ByteArray($str = NULL) {
 | 
						|
			if(is_string($str)) {
 | 
						|
				$length = strlen($str);
 | 
						|
				for($i = 0; $i < $length; $i ++)
 | 
						|
					$this[] = ord($str[$i]);
 | 
						|
			}
 | 
						|
		}
 | 
						|
		//<editor-fold defaultstate="collapsed" desc="Cryptographic">
 | 
						|
		public function encrypt() {
 | 
						|
 | 
						|
		}
 | 
						|
		public function decrypt() {
 | 
						|
 | 
						|
		}
 | 
						|
		//</editor-fold>
 | 
						|
		//<editor-fold defaultstate="collapsed" desc="GET,SET,OFFSET.SET">
 | 
						|
		public function __get($prop) {
 | 
						|
			switch($prop) {
 | 
						|
				case 'length':
 | 
						|
					return count($this);
 | 
						|
				break;
 | 
						|
				case 'position':
 | 
						|
					return $this->position;
 | 
						|
				break;
 | 
						|
				case 'byteAvailable' :
 | 
						|
					return count($this) - $this->position;
 | 
						|
				break;
 | 
						|
				default :
 | 
						|
					return "Property($prop) is undefined";
 | 
						|
			}
 | 
						|
		}
 | 
						|
		public function __set($prop, $val) {
 | 
						|
			try {
 | 
						|
				switch ($prop) {
 | 
						|
					case 'length':
 | 
						|
						if (is_int($val)) {
 | 
						|
							$l = count($this);
 | 
						|
							if ($val < $l) {
 | 
						|
								if ($val > -1) {
 | 
						|
									while ($val < count($this)) {
 | 
						|
										$this->offsetUnset(count($this) - 1);
 | 
						|
									}
 | 
						|
								} else {
 | 
						|
									new ERROR(ERROR::INVALID_DATA, "length($val)");
 | 
						|
								}
 | 
						|
							} else {
 | 
						|
								while (count($this) < $val)
 | 
						|
							 $this[] = 0;
 | 
						|
							}
 | 
						|
						} else {
 | 
						|
							new ERROR(ERROR::TYPE_MISSMATCH, "($val)", 'an integer');
 | 
						|
						}
 | 
						|
					break;
 | 
						|
					case 'position':
 | 
						|
						if (is_int($val)) {
 | 
						|
							$l = count($this);
 | 
						|
							if ($val < $l) {
 | 
						|
								if ($val > -1) {
 | 
						|
									$this->position = $val;
 | 
						|
								} else {
 | 
						|
									new ERROR(ERROR::INVALID_DATA, "length($val)");
 | 
						|
								}
 | 
						|
							} else {
 | 
						|
								new ERROR(ERROR::GREATER_COMPARATIVE, "Position($val)", "length($l)");
 | 
						|
							}
 | 
						|
						} else {
 | 
						|
							new ERROR(ERROR::TYPE_MISSMATCH, "($val)", 'an integer');
 | 
						|
						}
 | 
						|
					break;
 | 
						|
					case 'byteAvailable' :
 | 
						|
						new ERROR(ERROR::READ_ONLY, "Property($prop)");
 | 
						|
					break;
 | 
						|
					default :
 | 
						|
						new ERROR(ERROR::UNDEFINED_DATA, "property($prop)");
 | 
						|
				}
 | 
						|
			} catch(Exception $e) {
 | 
						|
				echo $e;
 | 
						|
			}
 | 
						|
		}
 | 
						|
		public function offsetSet($i, $val) {
 | 
						|
			try {
 | 
						|
				if(is_int($val)) {
 | 
						|
					if($i > -1) {
 | 
						|
						while(count($this) < $i)
 | 
						|
							$this[] = 0;
 | 
						|
						parent::offsetSet($i, $val & 0xff);
 | 
						|
					} else if($i == NULL) {
 | 
						|
						parent::offsetSet(count($this), $val & 0xff);
 | 
						|
					} else {
 | 
						|
						new ERROR(ERROR::TYPE_MISSMATCH, "index($val)");
 | 
						|
					}
 | 
						|
				} else {
 | 
						|
					new ERROR(ERROR::TYPE_MISSMATCH, "($val)", 'an integer');
 | 
						|
				}
 | 
						|
			} catch(Exception $e) {
 | 
						|
				echo $e;
 | 
						|
			}
 | 
						|
		}
 | 
						|
		//</editor-fold>
 | 
						|
		public function compress() {
 | 
						|
			$str = gzcompress($this->save());
 | 
						|
			$this->clear();
 | 
						|
			$this->ByteArray($str);
 | 
						|
		}
 | 
						|
		public function deflate() {
 | 
						|
			$str = gzuncompress($this->save());
 | 
						|
			$this->clear();
 | 
						|
			$this->ByteArray($str);
 | 
						|
		}
 | 
						|
		public function save() {
 | 
						|
			$str = '';
 | 
						|
			foreach($this as $i)
 | 
						|
				$str .= chr($i);
 | 
						|
			return $str;
 | 
						|
		}
 | 
						|
		public function clear() {
 | 
						|
			$this->length = 0;
 | 
						|
			$this->position = 0;
 | 
						|
		}
 | 
						|
		// <editor-fold defaultstate="collapsed" desc="ReadUtils">
 | 
						|
		public function readBoolean() {
 | 
						|
			$p = $this->getPos();
 | 
						|
			if ($p)
 | 
						|
				return (bool) $this[$p];
 | 
						|
			else
 | 
						|
				return NULL;
 | 
						|
			}
 | 
						|
		public function readByte() {
 | 
						|
			//Returns -128 ~ 127
 | 
						|
			$p = $this->getPos();
 | 
						|
			if(is_int($p)) {
 | 
						|
				$p = $this[$p];
 | 
						|
				return $p < 128 ? $p : $p - 256;
 | 
						|
			}
 | 
						|
			return NULL;
 | 
						|
		}
 | 
						|
		public function readBytes(ByteArray $b, $p = 0, $l = 0) {
 | 
						|
			try {
 | 
						|
				if (($this->position + $l) < count($this)) {
 | 
						|
					if ($l > 0 || ($l = count($this))) {
 | 
						|
						for ($i = 0; $i < $l; $i++)
 | 
						|
							$b[$p + $i] = $this->readByte();
 | 
						|
					} else {
 | 
						|
						new ERROR(ERROR::UNDEFINED_DATA);
 | 
						|
					}
 | 
						|
				} else {
 | 
						|
					new ERROR(ERROR::EOF);
 | 
						|
				}
 | 
						|
			} catch (Exception $e) {
 | 
						|
				echo $e;
 | 
						|
			}
 | 
						|
		}
 | 
						|
		public function readDouble() {
 | 
						|
			//Reads an IEEE 754 double-precision (64-bit) floating-point number from the byte stream.
 | 
						|
			$s = $this->tobin($this->readByte())
 | 
						|
			.$this->tobin($this->readByte())
 | 
						|
			.$this->tobin($this->readByte())
 | 
						|
			.$this->tobin($this->readByte())
 | 
						|
			.$this->tobin($this->readByte())
 | 
						|
			.$this->tobin($this->readByte())
 | 
						|
			.$this->tobin($this->readByte())
 | 
						|
			.$this->tobin($this->readByte());
 | 
						|
			if($s*1 == 0)
 | 
						|
				return 0;
 | 
						|
			return $this->decodeIEEE($s);
 | 
						|
		}
 | 
						|
 | 
						|
		public function readFloat() {
 | 
						|
			//Reads an IEEE 754 single-precision (32-bit) floating-point number from the byte stream.
 | 
						|
			$s = $this->tobin($this->readByte())
 | 
						|
			.$this->tobin($this->readByte())
 | 
						|
			.$this->tobin($this->readByte())
 | 
						|
			.$this->tobin($this->readByte());
 | 
						|
			if($s*1 == 0)
 | 
						|
				return 0;
 | 
						|
			return $this->decodeIEEE($s);
 | 
						|
		}
 | 
						|
		public function readInt() {
 | 
						|
			//Returns -2147483648 ~ 2147483647
 | 
						|
			if(($s = hexdec($this->tohex($this->readByte())
 | 
						|
						.$this->tohex($this->readByte())
 | 
						|
						.$this->tohex($this->readByte())
 | 
						|
						.$this->tohex($this->readByte())))
 | 
						|
					> 2147483647)
 | 
						|
				$s -= 4294967296;
 | 
						|
			return $s;
 | 
						|
		}
 | 
						|
		public function readMultiByte($length, $charSet) {
 | 
						|
		}
 | 
						|
		public function readShort() {
 | 
						|
			if(($s = hexdec($this->tohex($this->readByte())
 | 
						|
						.$this->tohex($this->readByte())))
 | 
						|
					> 32767)
 | 
						|
				$s -= 65536;
 | 
						|
			return $s;
 | 
						|
		}
 | 
						|
		public function readUnsignedByte() {
 | 
						|
			return hexdec($this->tohex($this->readByte()));
 | 
						|
		}
 | 
						|
		public function readUnsignedInt() {
 | 
						|
			return hexdec($this->tohex($this->readByte())
 | 
						|
						.$this->tohex($this->readByte())
 | 
						|
						.$this->tohex($this->readByte())
 | 
						|
						.$this->tohex($this->readByte()));
 | 
						|
		}
 | 
						|
		public function readUnsignedShort() {
 | 
						|
			return hexdec($this->tohex($this->readByte())
 | 
						|
						.$this->tohex($this->readByte())
 | 
						|
						.$this->tohex($this->readByte())
 | 
						|
						.$this->tohex($this->readByte()));
 | 
						|
		}
 | 
						|
		public function readUTF() {
 | 
						|
		}
 | 
						|
		public function readUTFBytes() {
 | 
						|
		}
 | 
						|
		// </editor-fold>
 | 
						|
		// <editor-fold defaultstate="collapsed" desc="WriteUtils">
 | 
						|
		public function writeBoolean($b) {
 | 
						|
			try {
 | 
						|
				if (is_bool($b)) {
 | 
						|
					new ERROR(ERROR::TYPE_MISSMATCH, "($b)");
 | 
						|
				} else {
 | 
						|
					if ($this->position < count($this))
 | 
						|
						$b ? ($this[$this->getPos()] = 1) : ($this[$this->getPos()] = 0);
 | 
						|
					else
 | 
						|
						$b ? ($this[] = 1) : ($this[] = 0);
 | 
						|
				}
 | 
						|
			} catch (Exception $e) {
 | 
						|
				echo $e;
 | 
						|
			}
 | 
						|
		}
 | 
						|
		public function writeByte($b) {
 | 
						|
			if($this->position < count($this)) {
 | 
						|
				$this[$this->getPos()] = $b;
 | 
						|
			} else {
 | 
						|
				$this[] = $b;
 | 
						|
				$this->getPos();
 | 
						|
			}
 | 
						|
		}
 | 
						|
		public function writeBytes(ByteArray $b, $p = 0, $l = 0) {
 | 
						|
			try {
 | 
						|
				if ($l > 0 || ($l = count($b))) {
 | 
						|
					for ($i = 0; $i < $l; $i++)
 | 
						|
						$this->writeByte($b[$p + $i]);
 | 
						|
				} else {
 | 
						|
					new ERROR(ERROR::UNDEFINED_DATA);
 | 
						|
				}
 | 
						|
			} catch (Exception $e) {
 | 
						|
				echo $e;
 | 
						|
			}
 | 
						|
		}
 | 
						|
		public function writeDouble($num) {
 | 
						|
			if($num == 0) {
 | 
						|
				$num = str_pad('', 64, '0');
 | 
						|
			} else {
 | 
						|
				$num = $this->encodeIEEE($num, 8)."\n";
 | 
						|
			}
 | 
						|
			for($i = 0; $i < 64; $i += 8)
 | 
						|
				$this->writeByte(bindec(substr($num, $i, 8)));
 | 
						|
		}
 | 
						|
		public function writeFloat($num) {
 | 
						|
			if($num == 0) {
 | 
						|
				$num = str_pad('', 32, '0');
 | 
						|
			} else {
 | 
						|
				$num = $this->encodeIEEE($num, 4)."\n";
 | 
						|
			}
 | 
						|
			for($i = 0; $i < 32; $i += 8)
 | 
						|
				$this->writeByte(bindec(substr($num, $i, 8)));
 | 
						|
		}
 | 
						|
		public function writeInt($num) {
 | 
						|
			$this->writeByte($num >> 24 & 0xFF);
 | 
						|
			$this->writeByte($num >> 16 & 0xFF);
 | 
						|
			$this->writeByte($num >> 8 & 0xFF);
 | 
						|
			$this->writeByte($num & 0xFF);
 | 
						|
		}
 | 
						|
		public function writeMultiByte($length, $charSet) {
 | 
						|
		}
 | 
						|
		public function writeShort($num) {
 | 
						|
			$this->writeByte($num >> 8 & 0xFF);
 | 
						|
			$this->writeByte($num & 0xFF);
 | 
						|
		}
 | 
						|
		public function writeUnsignedInt($num) {
 | 
						|
			$this->writeByte($num >> 56 & 0xFF);
 | 
						|
			$this->writeByte($num >> 48 & 0xFF);
 | 
						|
			$this->writeByte($num >> 40 & 0xFF);
 | 
						|
			$this->writeByte($num >> 32 & 0xFF);
 | 
						|
			$this->writeByte($num >> 24 & 0xFF);
 | 
						|
			$this->writeByte($num >> 16 & 0xFF);
 | 
						|
			$this->writeByte($num >> 8 & 0xFF);
 | 
						|
			$this->writeByte($num & 0xFF);
 | 
						|
		}
 | 
						|
		public function writeUTF() {
 | 
						|
		}
 | 
						|
		public function writeUTFBytes() {
 | 
						|
		}
 | 
						|
		//</editor-fold>
 | 
						|
		//<editor-fold defaultstate="collapsed" desc="IEEE convertions">
 | 
						|
		private function decodeIEEE($str) {
 | 
						|
			$s = $str[0] ? -1:1;
 | 
						|
			if(($l = strlen($str)) == 8) {
 | 
						|
				$e = bindec(substr($str, 1, 3)) - 3;
 | 
						|
				$m = substr($str, 4, 8);
 | 
						|
			} else if($l == 16) {
 | 
						|
				
 | 
						|
			} else if($l == 32) {
 | 
						|
				$e = bindec(substr($str, 1, 8)) - 127;
 | 
						|
				$m = '1'.substr($str, 9, 32);
 | 
						|
			} else if($l == 64) {
 | 
						|
				$e = bindec(substr($str, 1, 11)) - 1023;
 | 
						|
				$m = '1'.substr($str, 12, 64);
 | 
						|
			}
 | 
						|
			if((++ $e) > 0) {
 | 
						|
				$m1 = substr($m, 0, $e);
 | 
						|
				$m2 = substr($m, $e);
 | 
						|
			} else {
 | 
						|
				while($e < 0) {
 | 
						|
					$m = '0'.$m;
 | 
						|
					$e ++;
 | 
						|
				}
 | 
						|
				$m1 = 0;
 | 
						|
				$m2 = $m;
 | 
						|
			}
 | 
						|
			$str = 0;
 | 
						|
			$e = strlen($m1);
 | 
						|
			for($i = 0; $i < $e; $i ++) {
 | 
						|
				if($m1[$i]) {
 | 
						|
					$str += $m1[$i]*pow(2, ($e - 1) - $i);
 | 
						|
				}
 | 
						|
			}
 | 
						|
			$e = strlen($m2);
 | 
						|
			for($i = 0; $i < $e; $i ++) {
 | 
						|
				if($m2[$i]) {
 | 
						|
					$str += $m2[$i]*pow(2, -($i + 1));
 | 
						|
				}
 | 
						|
			}
 | 
						|
			return $str*$s;
 | 
						|
		}
 | 
						|
		private function encodeIEEE($num, $byte) {
 | 
						|
			try {
 | 
						|
				if(is_numeric($num)) {
 | 
						|
					$s = $num > 0 ? 0:1;
 | 
						|
					$m1 = $s ? -1*$num : 1*$num;
 | 
						|
					$num = explode('.', $num);
 | 
						|
					$m1 = $num[0]*1;
 | 
						|
					if(count($num) > 1)
 | 
						|
						$m2 = '0.'.$num[1];
 | 
						|
					else $m2 = '0';
 | 
						|
					if($byte == 1) {
 | 
						|
 | 
						|
					} else if($byte == 2) {
 | 
						|
 | 
						|
					} else if($byte == 4) {
 | 
						|
						$e = 8;
 | 
						|
						$f = 23;
 | 
						|
						$b = 127;
 | 
						|
					} else if($byte == 8) {
 | 
						|
						$e = 11;
 | 
						|
						$f = 52;
 | 
						|
						$b = 1023;
 | 
						|
					} else {
 | 
						|
						new ERROR(ERROR::INVALID_DATA, "byte($byte)");
 | 
						|
					}
 | 
						|
					$num = '';
 | 
						|
					if($m1 > 1) {
 | 
						|
						$m1 = decbin($m1);
 | 
						|
						$e = str_pad(decbin(strlen($m1) - 1 + $b), $e, '0', STR_PAD_LEFT);
 | 
						|
					} else if($m1 == 1) {
 | 
						|
						$e = '0'.str_pad('', $e - 1, '1');
 | 
						|
					}
 | 
						|
					$num .= $m1;
 | 
						|
					$f *= 2;
 | 
						|
					for($i = 0; $i < $f; $i ++) {
 | 
						|
						$m2 *= 2;
 | 
						|
						if($m2 >= 1) {
 | 
						|
							$num .= '1';
 | 
						|
							$m2 -= 1;
 | 
						|
						} else {
 | 
						|
							$num .= '0';
 | 
						|
						}
 | 
						|
					}
 | 
						|
					if($m1 == 0) {
 | 
						|
						for($m1 = 0; $num[0] == '0'; $m1 --) {
 | 
						|
							$num = substr($num, 1);
 | 
						|
						}
 | 
						|
						$e = str_pad(decbin($m1 + $b), $e, '0', STR_PAD_LEFT);
 | 
						|
					}
 | 
						|
					$num = substr($num, 1, $f *= .5);
 | 
						|
					$num || ($num = str_pad('', $f, '0'));
 | 
						|
					return "$s$e$num";
 | 
						|
				} else {
 | 
						|
					new ERROR(ERROR::INVALID_DATA, $num);
 | 
						|
				}
 | 
						|
			} catch(Exception $e) {
 | 
						|
				echo $e;
 | 
						|
			}
 | 
						|
		}
 | 
						|
		//</editor-fold>
 | 
						|
		private function getPos() {
 | 
						|
 | 
						|
			try {
 | 
						|
				if ($this->position < count($this))
 | 
						|
					return $this->position++;
 | 
						|
				else
 | 
						|
					new ERROR(ERROR::EOF);
 | 
						|
			} catch (Exception $e) {
 | 
						|
				echo $e;
 | 
						|
			}
 | 
						|
		 return NULL;
 | 
						|
		}
 | 
						|
		private function tobin($num) {
 | 
						|
			$num = $num < 0 ? $num + 256:$num;
 | 
						|
			$num = decbin($num);
 | 
						|
			while(strlen($num) != 8) {
 | 
						|
				$num = '0'.$num;
 | 
						|
			}
 | 
						|
			return $num;
 | 
						|
		}
 | 
						|
		private function tohex($num) {
 | 
						|
			return (($num = ($num < 0) ? $num + 256:$num) < 16) ? '0'.dechex($num):dechex($num);
 | 
						|
		}
 | 
						|
	}
 | 
						|
//* Tests
 | 
						|
	$a = new ByteArray();
 | 
						|
	$a->writeInt(12345);
 | 
						|
	$a->writeShort(11223);
 | 
						|
	$a->writeUnsignedInt(1125434357);
 | 
						|
	$a->position = 0;
 | 
						|
	echo "ReadInt: ";
 | 
						|
	echo $a->readInt()."\n";
 | 
						|
	echo "ReadShort: ";
 | 
						|
	echo $a->readShort()."\n";
 | 
						|
	echo "readUnsignedShort: ";
 | 
						|
	echo $a->readUnsignedInt()."\n";
 | 
						|
	$a->position = 0;
 | 
						|
	$a->writeDouble(1);
 | 
						|
	$a->writeDouble(0);
 | 
						|
	$a->writeDouble(1.00123);
 | 
						|
	$a->writeDouble(0.2156);
 | 
						|
	$a->writeDouble(100);
 | 
						|
	$a->writeDouble(1012.1234);
 | 
						|
 | 
						|
	$a->writeFloat(2);
 | 
						|
	$a->writeFloat(1);
 | 
						|
	$a->writeFloat(0);
 | 
						|
	$a->writeFloat(0.00123);
 | 
						|
	$a->writeFloat(23.2156);
 | 
						|
	$a->writeFloat(150);
 | 
						|
	$a->writeFloat(132.1);
 | 
						|
	$a->position = 0;
 | 
						|
	echo "readDouble: ";
 | 
						|
	echo $a->readDouble()."\n";
 | 
						|
	echo "readDouble: ";
 | 
						|
	echo $a->readDouble()."\n";
 | 
						|
	echo "readDouble: ";
 | 
						|
	echo $a->readDouble()."\n";
 | 
						|
	echo "readDouble: ";
 | 
						|
	echo $a->readDouble()."\n";
 | 
						|
	echo "readDouble: ";
 | 
						|
	echo $a->readDouble()."\n";
 | 
						|
	echo "readDouble: ";
 | 
						|
	echo $a->readDouble()."\n";
 | 
						|
 | 
						|
	echo "readFloat: ";
 | 
						|
	echo $a->readFloat()."\n";
 | 
						|
	echo "readFloat: ";
 | 
						|
	echo $a->readFloat()."\n";
 | 
						|
	echo "readFloat: ";
 | 
						|
	echo $a->readFloat()."\n";
 | 
						|
	echo "readFloat: ";
 | 
						|
	echo $a->readFloat()."\n";
 | 
						|
	echo "readFloat: ";
 | 
						|
	echo $a->readFloat()."\n";
 | 
						|
	echo "readFloat: ";
 | 
						|
	echo $a->readFloat()."\n";
 | 
						|
 | 
						|
//*/
 | 
						|
?>
 |