0 ) $b |= 0x80 | 0x40; else $b |= 0x40; } else { $b = gmp_intval( gmp_and( $iIn, 0x3f ) ); if( gmp_cmp( $iIn, $b ) > 0 ) $b |= 0x80; } $ret .= chr( $b ); $iIn = gmp_div( $iIn, 64 ); while( gmp_cmp( $iIn, 0 ) > 0 ) { $b = gmp_intval( gmp_and( $iIn, 0x7f ) ); if( gmp_cmp( $iIn, $b ) > 0 ) $b |= 0x80; $ret .= chr( $b ); $iIn = gmp_div( $iIn, 128 ); } return $ret; } /** * Read a gats packed integer into a gmp_int * @param $sIn (string) the input stream * @param &$pos (integer) the current position in the input stream (will be modified) * @returns (gmp_int) the integer */ function phpgats_readInt( $sIn, &$pos ) { $neg = false; $b = ord($sIn[$pos++]); if( ($b&0x40) == 0x40 ) $neg = true; $iOut = gmp_init( $b&0x3f ); $mult = gmp_init( 64 ); while( ($b&0x80) ) { $b = ord($sIn[$pos++]); $iOut = gmp_or( $iOut, gmp_mul( $b&0x7f, $mult ) ); $mult = gmp_mul( $mult, 128 ); } if( $neg == true ) $iOut = gmp_mul( $iOut, -1 ); return $iOut; } /** * Boolean Gats type (true or false) */ class phpgats_Boolean extends phpgats_Element { public $elem = false; /** * Creates a phpgats_Boolean out of a php type * @param $_elem (mixed) the php type to convert to a gats boolean */ function __construct( $_elem ) { $this->elem = ($_elem==true)?true:false; } /** * Sets this phpgats_Boolean type based on php type $_elem * @param $_elem (mixed) the php type to convert to a gats boolean */ function set( $_elem ) { $this->elem = ($_elem==true)?true:false; } /** * Get the php type of this element * @returns (bool) */ function get() { return $this->elem; } function encode() { return ($this->elem==true)?"1":"0"; } function getStr() { return ($this->elem==true)?"true":"false"; } /** * Get the gats type of the current element * @returns "boolean" */ function getGatsType() { return "boolean"; } } /** * String Gats type */ class phpgats_String extends phpgats_Element { public $elem = ""; /** * Creates a phpgats_String out of a php type * @param $_elem (mixed) the php type to convert to a gats string */ function __construct( $_elem ) { $this->elem = $_elem . ""; } /** * Sets this phpgats_String type based on php type $_elem * @param $_elem (mixed) the php type to convert to a gats string */ function set( $_elem ) { $this->elem = $_elem . ""; } /** * Get the php type of this element * @returns (string) */ function get() { return $this->elem; } function encode() { return 's' . phpgats_writeInt(strlen($this->elem)) . $this->elem; } function getStr() { return $this->get(); } /** * Get the gats type of the current element * @returns "string" */ function getGatsType() { return "string"; } } /** * Integer Gats type (gmp_int) */ class phpgats_Integer extends phpgats_Element { public $elem = 0; /** * Creates a phpgats_Integer out of a php type * @param $_elem (mixed) the php type to convert to a gats integer */ function __construct( $_elem ) { if( $_elem === '' ) $this->elem = gmp_init(0); else if( getType($_elem) == "resource" ) $this->elem = $_elem; else if( getType($_elem) == "string" ) $this->elem = gmp_init($_elem); else if( getType($_elem) == "integer" ) $this->elem = gmp_init($_elem+0); else if( getType($_elem) == "double" ) $this->elem = gmp_init(intval($_elem)); else throw new Exception("Bad phpgats_Integer type: '" . getType($_elem) . "'."); } /** * Sets this phpgats_Integer type based on php type $_elem * @param $_elem (mixed) the php type to convert to a gats integer */ function set( $_elem ) { $this->elem = gmp_init($_elem); } /** * Get the php type of this element * @returns (int) */ function get() { return gmp_intval($this->elem); } /** * Get the php type of this element * @returns (gmp_int) */ function get64() { return $this->elem; } function encode() { return "i" . phpgats_writeInt($this->elem); } function getStr() { return gmp_strval($this->elem); } /** * Get the gats type of the current element * @returns "integer" */ function getGatsType() { return "integer"; } } /** * Float Gats type */ class phpgats_Float extends phpgats_Element { public $elem = 0; /** * Creates a phpgats_Float out of a php type * @param $_elem (mixed) the php type to convert to a gats float */ function __construct( $_elem ) { $this->elem = $_elem+0.0; } /** * Sets this phpgats_Float type based on php type $_elem * @param $_elem (mixed) the php type to convert to a gats float */ function set( $_elem ) { $this->elem = $_elem+0.0; } /** * Get the php type of this element * @returns (float) */ function get() { return $this->elem; } function encode() { if( $this->elem == 0.0 ) { return 'Fz'; } else if( is_nan( $this->elem ) ) { return 'Fn'; } else if( is_infinite( $this->elem ) ) { if( $this->elem < 0.0 ) return 'FI'; else return 'Fi'; } else { $e = $this->elem; $neg = false; if( $e < 0.0 ) { $e = -$e; $neg = true; } $iScale = (int)(floor(log($e)/log(256.0))); $e = $e/pow(256.0, $iScale); $s = chr((int)($e)); $e = $e - (int)($e); for( $j = 0; $j < 150 && $e > 0.0; $j++ ) { $e = $e * 256.0; $s .= chr((int)($e)); $e -= (int)($e); } $ilen = strlen($s); if( $neg ) $ilen = -$ilen; return "f" . phpgats_writeInt($ilen) . $s . phpgats_writeInt($iScale); } } function getStr() { return $this->elem+""; } /** * Get the gats type of the current element * @returns "float" */ function getGatsType() { return "float"; } } /** * List Gats type */ class phpgats_List extends phpgats_Element { public $elems = array(); /** * Append an element to this phpgats_List * @param $_elem (phpgats_Element) the element to append */ function append( $_elem ) { if( !is_subclass_of( $_elem, "phpgats_Element" ) ) throw new Exception( "can only call phpgats_List::append with phpgats_Element." ); array_push( $this->elems, $_elem ); } /** * Returns the php array that is the core of this element * @returns (array) */ function get() { return $this->elems; } /** * Returns the current size of this list * @returns (int) the number of elements */ function size() { return count($this->elems); } function encode() { $s_out = "l"; foreach( $this->elems as $val ) { $s_out .= $val->encode(); } $s_out .= "e"; return $s_out; } /** * Get the gats type of the current element * @returns "list" */ function getGatsType() { return "list"; } } /** * Dictionary Gats type */ class phpgats_Dictionary extends phpgats_Element { public $elems = array(); /** * Append an element to the phpgats_Dictionary * @param $_name (string) the key under which to place this element * @param $_val (phpgats_Element) the phpgats_Element to place in the dictionary */ function append( $_name, $_val ) { if( !is_subclass_of( $_val, "phpgats_Element" ) || gettype($_name)!="string") throw new Exception( "can only call phpgats_Dictionary::append with str,phpgats_Element." ); $this->elems[$_name] = $_val; } /** * Returns the php associative array that is the core of this element * @returns (array) */ function get() { return $this->elems; } /** * Returns the current size of the dictionary * @returns (int) */ function size() { return count($this->elems); } function encode() { $s_out = "d"; foreach( $this->elems as $key => $val ) { $n = new phpgats_String( $key ); $s_out .= $n->encode(); $s_out .= $val->encode(); } $s_out .= "e"; return $s_out; } /** * Get the gats type of the current element * @returns "dictionary" */ function getGatsType() { return "dictionary"; } } /** * Make sure we can read a character off the input stream * @param $str_data (string) the input stream * @param $offset (integer) the current position in the input stream */ function phpgats_pC( $str_data, $offset ) { if($offset>strlen($str_data)) throw new Exception("Not enough data"); } /** * Parse a string element out of the input stream * @param $str_data (string) the input stream * @param &$offset (integer) the current position in the input stream (will be updated) * @param $dbg (integer) the current depth (for pretty printing) * @returns (phpgats_String) the element read */ function phpgats_pS( $str_data, &$offset, $dbg ) { $str_tmp = ""; $gmpSize = phpgats_readInt( $str_data, $offset ); if( gmp_cmp( $gmpSize, 2147483647 ) > 0 ) { throw new Exception( "size (" . gmp_strval($gmpSize) . ") > phpgats can handle\n"); } $iSize = gmp_intval($gmpSize); $i=0; $str_tmp = ""; while( $i<$iSize ) { phpgats_pC( $str_data, $offset+1 ); $str_tmp .= $str_data[$offset++]; ++$i; } return new phpgats_String($str_tmp); } /** * Parse an integer element out of the input stream * @param $str_data (string) the input stream * @param &$offset (integer) the current position in the input stream (will be updated) * @param $dbg (integer) the current depth (for pretty printing) * @returns (phpgats_Integer) the element read */ function phpgats_pI( $str_data, &$offset, $dbg ) { return new phpgats_Integer(phpgats_readInt($str_data, $offset)); } /** * Parse a float element out of the input stream * @param $str_data (string) the input stream * @param &$offset (integer) the current position in the input stream (will be updated) * @param $dbg (integer) the current depth (for pretty printing) * @returns (phpgats_Float) the element read */ function phpgats_pF( $str_data, &$offset, $dbg ) { $str_tmp = ""; $iSize = gmp_intval(phpgats_readInt( $str_data, $offset )); $neg = false; if( $iSize < 0.0 ) { $iSize = -$iSize; $neg = true; } $i=0; $str_tmp = ""; while( $i<$iSize ) { phpgats_pC( $str_data, $offset+1 ); $str_tmp .= $str_data[$offset++]; ++$i; } $iScale = gmp_intval(phpgats_readInt( $str_data, $offset )); $e = 0.0; for( $j = $iSize-1; $j > 0; $j-- ) { $e = ($e+ord($str_tmp[$j]))*.00390625; } $e = ($e+ord($str_tmp[0])) * pow( 256.0, $iScale ); if( $neg ) $e = -$e; return new phpgats_Float( $e ); } /** * Parse a list element out of the input stream * @param $str_data (string) the input stream * @param &$offset (integer) the current position in the input stream (will be updated) * @param $dbg (integer) the current depth (for pretty printing) * @returns (phpgats_List) the element read */ function phpgats_pL( $str_data, &$offset, $dbg ) { phpgats_pC( $str_data, $offset ); $c = $str_data[$offset]; $l_out = new phpgats_List(); while( $c != "e" ) { $obj = phpgats_pM( $str_data, $offset, $dbg ); $l_out->append( $obj ); phpgats_pC( $str_data, $offset ); $c = $str_data[$offset]; } $offset++; return $l_out; } /** * Parse a dictionary element out of the input stream * @param $str_data (string) the input stream * @param &$offset (integer) the current position in the input stream (will be updated) * @param $dbg (integer) the current depth (for pretty printing) * @returns (phpgats_Dictionary) the element read */ function phpgats_pD( $str_data, &$offset, $dbg ) { phpgats_pC( $str_data, $offset ); $c = $str_data[$offset]; $d_out = new phpgats_Dictionary(); while( $c != "e" ) { $obj1 = phpgats_pM( $str_data, $offset, $dbg ); $obj2 = phpgats_pM( $str_data, $offset, $dbg ); $d_out->append( $obj1->get(), $obj2 ); phpgats_pC( $str_data, $offset ); $c = $str_data[$offset]; } $offset++; return $d_out; } /** * The internal master recursive parse function * @param $str_data (string) the input stream * @param &$offset (integer) the current position in the input stream (will be updated) * @param $dbg (integer) the current depth (for pretty printing) * @returns (phpgats_Element) the element read */ function phpgats_pM( $str_data, &$offset, $dbg=0 ) { phpgats_pC( $str_data, $offset ); $c = $str_data[$offset++]; //for( $meme=0; $meme<$dbg; $meme++ ) // echo " "; switch( $c ) { case 'i': //echo "int:"; $obj = phpgats_pI( $str_data, $offset, $dbg ); //echo gmp_strval($obj->get()) . "\n"; return $obj; break; case 'l': //echo "list:\n"; $obj = phpgats_pL( $str_data, $offset, $dbg+1 ); return $obj; break; case 'd': //echo "dic:\n"; $obj = phpgats_pD( $str_data, $offset, $dbg+1 ); return $obj; break; case 'f': //echo "float:\n"; $obj = phpgats_pF( $str_data, $offset, $dbg ); return $obj; break; case 'F': phpgats_pC( $str_data, $offset ); switch( $str_data[$offset++] ) { case 'Z': return new phpgats_Float( -0.0 ); case 'z': return new phpgats_Float( 0.0 ); case 'N': return new phpgats_Float( -NAN ); case 'n': return new phpgats_Float( NAN ); case 'I': return new phpgats_Float( -INF ); case 'i': return new phpgats_Float( INF ); } break; case '1': //echo "true\n"; return new phpgats_Boolean( true ); break; case '0': //echo "false\n"; return new phpgats_Boolean( false ); break; default: //echo "str:"; $obj = phpgats_pS( $str_data, $offset, $dbg ); //echo $obj->get() . "\n"; return $obj; break; } } /** * Call this function to parse a gats binary string into a phpgats_Element object * @param $str_data (string) the binary gats data to be parsed * @returns (phpgats_Element) */ function phpgats_parseGats( $str_data ) { //print "parsing\n"; $offset = 0; $data_size = strlen( $str_data ); if( $data_size < 5 ) { throw new Exception( "invalid size (< 5)\n" ); return false; } if( ord($str_data) != 1 ) //version { throw new Exception( "invalid gats version" ); return false; } $size = "" . $str_data[1] . $str_data[2] . $str_data[3] . $str_data[4]; $size = unpack( "Nsize", $size ); $size = $size["size"]; if( $data_size < $size ) { throw new Exception( "Not enough data" ); return false; } $offset+=5; return phpgats_pM( $str_data, $offset ); } /** * Call this function to generate a binary gats stream from the given phpgats_Element object * @param $elem (phpgats_Element) the gats element object from which to generate a binary blob * @returns (string) binary gats data */ function phpgats_writeGats( $elem ) { $str_out = $elem->encode(); $str_out = "\x01" . pack( "N", strlen($str_out)+5 ) . $str_out; return $str_out; } /* $l = new phpgats_List(); $l->append( new phpgats_Float( 123000000000.0 ) ); $l->append( new phpgats_Float( -0.000087687 ) ); $l->append( new phpgats_Float( -INF ) ); $l->append( new phpgats_Float( INF ) ); $l->append( new phpgats_Float( -NAN ) ); $l->append( new phpgats_Float( NAN ) ); $l->append( new phpgats_Float( -0.0 ) ); $l->append( new phpgats_Float( 0.0 ) ); $l->append( new phpgats_Integer("27") ); $l->append( new phpgats_Boolean(true) ); $l->append( new phpgats_String("testing your monkey") ); $d = new phpgats_Dictionary(); $d->append( "theList", $l ); $d->append( "theFalse", new phpgats_Boolean(false) ); $f = fopen("testinggats.gats", "w"); $theStr = phpgats_writeGats($d); fwrite( $f, $theStr ); fclose( $f ); $obj = phpgats_parseGats( $theStr ); print_r( $obj ); */ ?>