<?php
class Chinese {
	var $TableName		= 'wap/encode/encode.table';
	var $TableHandle	= 0;
	var $EncodeLang		= '';
	var $IconvEnabled	= false;
	var $TableIndex		= array();
	var $TableEncode	= array();
	var $IndexPoint		= array(
		'GBKtoUTF8'		=> 0,
		'GBKtoUNICODE'	=> 0,
		'BIG5toUTF8'	=> 1024,
		'BIG5toUNICODE'	=> 1024,
		'UTF8toGBK'		=> 512,
		'UTF8toBIG5'	=> 1536,
	);

	function Chinese($SourceLang='',$TargetLang='',$ForceTable = false) {
		if ($SourceLang && $TargetLang) {
			$this->initConvert($SourceLang,$TargetLang,$ForceTable);
		}
	}

	function initConvert($SourceLang,$TargetLang,$ForceTable) {
		if (($SourceLang = $this->getCharset($SourceLang)) && ($TargetLang = $this->getCharset($TargetLang)) && $SourceLang != $TargetLang) {
			$this->EncodeLang = $SourceLang.'to'.$TargetLang;
			$this->IconvEnabled = (function_exists('iconv') && $TargetLang != 'BIG5' && !$ForceTable) ? true : false;
			$this->IconvEnabled || is_resource($this->TableHandle) || $this->TableHandle = fopen(R_P.$this->TableName,"r");
		}
	}

	function getCharset($lang){
		switch (strtoupper(substr($lang,0,2))) {
			case 'GB' :
				$lang = 'GBK';break;
			case 'UT' :
				$lang = 'UTF8';break;
			case 'UN' :
				$lang = 'UNICODE';break;
			case 'BI' :
				$lang = 'BIG5';break;
			default :
				$lang = '';
		}
		return $lang;
	}

	function UNICODEtoUTF8($c){
		if($c < 0x80) {
			$c = chr($c);
		}elseif($c < 0x800) {
			$c = chr(0xC0|$c>>6).chr(0x80|$c&0x3F);
		}elseif($c < 0x10000) {
			$c = chr(0xE0|$c>>12).chr(0x80|$c>>6&0x3F).chr(0x80|$c&0x3F);
		}elseif($c < 0x200000) {
			$c = chr(0xF0|$c>>18).chr(0x80|$c>>12&0x3F).chr(0x80|$c>>6&0x3F).chr(0x80|$c&0x3F);
		}elseif($c < 0x4000000){
			$c = chr(0xF8|$c>>24).chr(0xF0|$c>>18).chr(0x80|$c>>12&0x3F).chr(0x80|$c>>6&0x3F).chr(0x80|$c&0x3F);
		}else{
			$c = chr(0xF8|$c>>30).chr(0xF8|$c>>24).chr(0xF0|$c>>18).chr(0x80|$c>>12&0x3F).chr(0x80|$c>>6&0x3F).chr(0x80|$c&0x3F);
		}
		return $c;
	}

	function CHSUTF8toU($c) {
		switch(strlen($c)) {
			case 1:
				return ord($c);
			case 2:
				return ((ord($c[0])&0x3F)<<6) + (ord($c[1])&0x3F);
			case 3:
				return ((ord($c[0])&0x1F)<<12) + ((ord($c[1])&0x3F)<<6) + (ord($c[2])&0x3F);
			case 4:
				return ((ord($c[0])&0x0F)<<18) + ((ord($c[1])&0x3F)<<12) + ((ord($c[2])&0x3F)<<6) + (ord($c[3])&0x3F);
		}
		return 32;
	}
	function getTableIndex() {
		if (!isset($this->TableIndex[$this->EncodeLang])) {
			fseek($this->TableHandle,$this->IndexPoint[$this->EncodeLang]);
			$tmpData = fread($this->TableHandle, 512);
			$pFirstEncode = hexdec(bin2hex(substr($tmpData,4,4)));
			for($i = 8; $i < 512; $i += 4) {
				$item = unpack('nkey/nvalue',substr($tmpData,$i,4));
				if (isset($this->TableIndex[$this->EncodeLang][$item['key']])) break;
				$this->TableIndex[$this->EncodeLang][$item['key']] = $pFirstEncode + $item['value'];
			}
		}
	}

	function CHStoUTF8($srcText) {
		$this->getTableIndex();$tarText = '';
		for ($i=0;$i<strlen($srcText);$i+=2) {
			$h = ord($srcText[$i]);
			if($h>127 && isset($this->TableIndex[$this->EncodeLang][$h])) {
				$l = ord($srcText[$i+1]);
				if (!isset($this->TableEncode[$this->EncodeLang][$h][$l])) {
					fseek($this->TableHandle,$l*2+$this->TableIndex[$this->EncodeLang][$h]);
					$this->TableEncode[$this->EncodeLang][$h][$l] = $this->UNICODEtoUTF8(hexdec(bin2hex(fread($this->TableHandle,2))));
				}
				$tarText .= $this->TableEncode[$this->EncodeLang][$h][$l];
			} elseif ($h<128) {
				$tarText .= $srcText[$i];
				$i--;
			}
		}
		return $tarText;
	}

	function UTF8toCHS($srcText) {
		$this->getTableIndex();
		$tarText = '';$i = 0 ;
		while($i < strlen($srcText)) {
			$c = ord($srcText[$i++]);
			switch ($c >> 4) {
				case 0: case 1: case 2: case 3: case 4: case 5: case 6: case 7:
					$tarText .= chr($c);
				break;
				case 12: case 13:
					$c = (($c & 0x1F) << 6) | (ord($srcText[$i++]) & 0x3F);
					$h = $c>>8;
					if(isset($this->TableIndex[$this->EncodeLang][$h])) {
						$l = $c&0xFF;
						if (!isset($this->TableEncode[$this->EncodeLang][$h][$l])) {
							fseek($this->TableHandle,$l*2+$this->TableIndex[$this->EncodeLang][$h]);
							$this->TableEncode[$this->EncodeLang][$h][$l] = fread($this->TableHandle,2);
						}
						$tarText .= $this->TableEncode[$this->EncodeLang][$h][$l];
					}
				break;
				case 14:
					$c = (($c & 0x0F) << 12) | ((ord($srcText[$i++]) & 0x3F) << 6) | ((ord($srcText[$i++]) & 0x3F));
					$h = $c>>8;
					if(isset($this->TableIndex[$this->EncodeLang][$h])) {
						$l = $c&0xFF;
						if (!isset($this->TableEncode[$h][$l])) {
							fseek($this->TableHandle,$l*2+$this->TableIndex[$this->EncodeLang][$h]);
							$this->TableEncode[$h][$l] = fread($this->TableHandle,2);
						}
						$tarText .= $this->TableEncode[$h][$l];
					}
				break;
			}
		}
		return $tarText;
	}

	function CHStoUNICODE($srcText,$SourceLang='') {
		$tarText = '';
		if ($this->IconvEnabled && isset($SourceLang)) {
			for ($i=0;$i<strlen($srcText);$i+=2) {
				if(ord($srcText[$i]) > 127) {
					$tarText .= "&#x".dechex($this->Utf8_Unicode(iconv($SourceLang,"UTF-8",$srcText[$i].$srcText[$i+1]))).";";
				} else {
					$tarText .= $srcText[$i--];
				}
			}
		} else {
			$this->getTableIndex();
			for ($i=0;$i<strlen($srcText);$i+=2) {
				$h = ord($srcText[$i]);
				if($h>127 && isset($this->TableIndex[$this->EncodeLang][$h])) {
					$l = ord($srcText[$i+1]);
					if (!isset($this->TableEncode[$this->EncodeLang][$h][$l])) {
						fseek($this->TableHandle,$l*2+$this->TableIndex[$this->EncodeLang][$h]);
						$this->TableEncode[$this->EncodeLang][$h][$l] = '&#x'.bin2hex(fread($this->TableHandle,2)).';';
					}
					$tarText .= $this->TableEncode[$this->EncodeLang][$h][$l];
				} elseif ($h<128) {
					$tarText .= $srcText[$i--];
				}
			}
		}
		return $tarText;
	}

	function Convert(&$srcText,$SourceLang='',$TargetLang='',$ForceTable=false) {
		if ($SourceLang && $TargetLang) {
			$this->initConvert($SourceLang,$TargetLang,$ForceTable);
		}

		if ($this->EncodeLang) {
			switch ($this->EncodeLang) {
				case 'GBKtoUTF8':
					return $this->IconvEnabled ? iconv('GBK','UTF-8',$srcText) : $this->CHStoUTF8($srcText);break;
				case 'BIG5toUTF8':
					return $this->IconvEnabled ? iconv('BIG5','UTF-8',$srcText) : $this->CHStoUTF8($srcText);break;
				case 'UTF8toGBK':
					return $this->IconvEnabled ? iconv('UTF-8','GBK',$srcText) : $this->UTF8toCHS($srcText);break;
				case 'UTF8toBIG5':
					return $this->UTF8toCHS($srcText);break;
				case 'GBKtoUNICODE':
					return $this->CHStoUNICODE($srcText,'GBK');break;
				case 'BIG5toUNICODE' :
					return $this->CHStoUNICODE($srcText,'BIG5');break;
			}
		}
		return $srcText;
	}
}
?>