  | 
      
        
          1樓
          巨大八爪鱼
          2016-2-8 17:55
          
          
           
         
        文件名:rxdata_library.php <?php   /**  ** PHP RXData 解析庫 V1.0  **   ** 本函數庫是巨大八爪魚編寫的  ** 使用和轉載時請保留此信息  **/    define('MARSHAL_MAJOR', 4);  define('MARSHAL_MINOR', 8);    define('RBT_NIL', '0');  define('RBT_TRUE', 'T');  define('RBT_FALSE', 'F');  define('RBT_FIXNUM', 'i');  define('RBT_EXTENDED', 'e');  define('RBT_UCLASS', 'C');  define('RBT_OBJECT', 'o');  define('RBT_DATA', 'd');  define('RBT_USERDEF', 'u');  define('RBT_USRMARSHAL', 'U');  define('RBT_FLOAT', 'f');  define('RBT_BIGNUM', 'l');  define('RBT_STRING', '"');  define('RBT_REGEXP', '/');  define('RBT_ARRAY', '[');  define('RBT_HASH', '{');  define('RBT_HASH_DEF', '}');  define('RBT_STRUCT', 'S');  define('RBT_MODULE_OLD', 'M'); // 該類型為老版格式,已棄用  define('RBT_CLASS', 'c');  define('RBT_MODULE', 'm');  define('RBT_SYMBOL', ':'); // 符號對象  define('RBT_SYMLINK', ';'); // 連結到符號對象  define('RBT_IVAR', 'I');  define('RBT_LINK', '@'); // 連結到非符號對象    define('ONIG_OPTION_IGNORECASE', 0x01);  define('ONIG_OPTION_EXTEND', 0x02);  define('ONIG_OPTION_MULTILINE', 0x04);    define('SIZEOF_CHAR', 1);  define('SIZEOF_DOUBLE', 8);  define('SIZEOF_INT', 2);  define('SIZEOF_LONG', 4); // 在C語言中,int和long都是4個字節...  define('SIZEOF_LONGLONG', 8);    class RubyClass {      public $name;  }    class RubyModule extends RubyClass {}    class RubyNil {}    class RubyObject {      public $_name = '';      public $_length = 0;      public $_extension = '';      public $_data = array();      public function __get($property) {          if (is_numeric($this->_length)) {              return $this->_data[$property];          } else {              if (isset($this->_data['extension'][$property])) {                  return $this->_data['extension'][$property];              } else if (isset($this->data['base'][$property])) {                  return $this->_data['base'][$property];              } else {                  return NULL;              }          }      }  }    class RubySymbol {      public $name;      public function getMember(RubyObject $obj) {          $member = $this->getMemberName();          return $obj->_data[$member];      }      public function getMemberName() {          if ($this->isMember()) {              return substr($this->name, 1);          } else {              return $this->name;          }      }      // 判斷該符號對象是不是一個類的屬性名稱      public function isMember() {          return ($this->name{0} == '@');      }      public function setMember(RubyObject $obj, $value) {          $member = $this->getMemberName();          $obj->_data[$member] = $value;      }  }    /* 根據文件名打開文件並讀取一個項目,返回讀取的對象並關閉文件 */  function rxdata_load($filename) {      $file = fopen($filename, 'rb');      if ($file === false) {          return NULL;      }      $data = rxdata_load_one($file);      fclose($file);      return $data;  }    /* 根據文件名打開文件並讀取全部項目,通過數組返回後關閉文件 */  function rxdata_load_all($filename) {      $file = fopen($filename, 'rb');      if ($file === false) {          return NULL;      }      $data = array();      while ($obj = rxdata_load_one($file)) {          array_push($data, $obj);      }      return $data;  }    /* 從打開的文件中讀取一個項目 */  function rxdata_load_one($file) {      $data = NULL;      if (rxdata_read_header($file)) {          rxdata_reset(); // 移除之前的符號表          $data = rxdata_read($file);      }      return $data;  }          /* 讀取文件中接下來的符號對象或符號連結所指向的符號對象,以該符號的名稱作為對象名,創建並註冊對象,返回所創建的對象 */  function rxdata_prepare_object($file, $has_length = true) {      // 在Ruby中,類名和變量名都是符號,且同名符號只能在內存中存在一次      $sym = rxdata_read_symbol_block($file);      $obj = new RubyObject();      $obj->_name = $sym->name;      if ($has_length) {          $obj->_length = rxdata_read_long($file);      }      rxdata_register_object($obj); // 創建對象後立即註冊對象(的引用),以便於之後能夠連結到該對象      return $obj;  }    function rxdata_read($file) {      $type = fgetc($file);      switch ($type) {      case RBT_ARRAY:          return rxdata_read_array($file);      case RBT_BIGNUM:          return rxdata_read_bignum($file);      case RBT_CLASS:          return rxdata_read_class($file);      case RBT_EXTENDED:          return rxdata_read_extended($file);      case RBT_FALSE:          return false;      case RBT_FIXNUM:          return rxdata_read_fixnum($file);      case RBT_FLOAT:          return rxdata_read_float($file);      case RBT_HASH:          return rxdata_read_hash($file);      case RBT_HASH_DEF:          return rxdata_read_hash($file, true);      case RBT_IVAR:          return rxdata_read_ivar($file);      case RBT_LINK:          return rxdata_read_link($file);      case RBT_MODULE:          return rxdata_read_module($file);      case RBT_NIL:          return new RubyNil();      case RBT_OBJECT:      case RBT_STRUCT:          return rxdata_read_object($file);      case RBT_REGEXP:          return rxdata_read_regexp($file);      case RBT_TRUE:          return true;      case RBT_STRING:          return rxdata_read_string($file, true);      case RBT_SYMBOL:          return rxdata_read_symbol($file);      case RBT_SYMLINK:          return rxdata_read_symlink($file);      case RBT_UCLASS:          return rxdata_read_uclass($file);      case RBT_USERDEF:          return rxdata_read_userdef($file);      case RBT_USRMARSHAL:          return rxdata_read_usrmarshal($file);      default:          trigger_error(sprintf('文件中0x%x處含有無法識別的Ruby數據類型: \'%s\' (0x%02X)', ftell($file), $type, ord($type)), E_USER_WARNING);          return NULL;      }  }    function rxdata_read_array($file) {      $arr = array();      rxdata_register_object($arr);      $len = rxdata_read_long($file);      for ($i = 0; $i < $len; $i++) {          $arr[$i] = rxdata_read($file);      }      return $arr;  }    /* 從文件中讀取一個字節 */  /* 此函數讀出來的字節一定是無符號十六進制整數 */  function rxdata_read_byte($file) {      $ch = ord(fgetc($file));      return $ch;  }    function rxdata_read_bignum($file) {      $sign = fgetc($file);      $n = rxdata_read_long($file);      $num = rxdata_read_ulong($file, 2 * $n);      if ($sign == '-') {          $num = -$num;      }      rxdata_register_object($num);      return $num;  }    function rxdata_read_class($file) {      $class = new RubyClass();      rxdata_register_object($class);      $class->name = rxdata_read_string($file);      return $class;  }    function rxdata_read_extended($file) {      $ex = rxdata_read_symbol_block($file);      $obj = rxdata_read($file);      if (is_object($obj)) {          $obj->_extension = $ex->name;          return $obj;      } else {          $package = new RubyObject();          $package->_length = count($obj);          $package->_extension = $ex->name;          $package->_data = $obj;          rxdata_registry_replace($obj, $package); // 重定向連接表中的註冊信息          return $package;      }  }    /*  注意:      使用rxdata_read_fixnum讀取一個Fixnum對象      使用rxdata_read_long讀取任意對象原始二進制數據中的長整數值(例如String對象中表示字符串長度的長整數)  */  function rxdata_read_fixnum($file) {      // 在Ruby Marshal中,Fixnum類型的數據無需註冊      return rxdata_read_long($file);  }    function rxdata_read_float($file) {      $str = rxdata_read_string($file);      if (in_array($str, array('nan', 'inf', '-inf'))) {          $data = $str;      } else {          $data = (float)$str;      }      rxdata_register_object($data);      return $data;  }    function rxdata_read_hash($file, $hasDefaultValue = false) {      $len = rxdata_read_long($file);      $hash = array();      if ($hasDefaultValue) {          $obj = array(&$hash);      } else {          $obj = &$hash;      }      rxdata_register_object($obj);      for ($i = 0; $i < $len; $i++) {          $key = rxdata_read($file);          $hash[$key] = rxdata_read($file);      }      if ($hasDefaultValue) {          $obj[1] = rxdata_read($file);      }      return $obj;  }    /* 讀取Marshal數據頭 */  function rxdata_read_header($file) {      $oldpos = ftell($file);      $a = rxdata_read_byte($file);      $b = rxdata_read_byte($file);      if ($a == MARSHAL_MAJOR && $b == MARSHAL_MINOR) {          return true; // 如果讀取成功則返回true,且指針移動到數據頭的後面      } else {          fseek($file, $oldpos); // 如果讀取失敗,則退回到讀取前的位置,並返回false          return false;      }  }    function rxdata_read_ivar($file) {      $obj = rxdata_read($file);      $base_len = $obj->_length;      $base_data = $obj->_data;      $obj->_length = rxdata_read_long($file);      $obj->_data = array();            rxdata_read_object($file, $obj);      $obj->_length = array('base' => $base_len, 'extension' => $obj->_length);      $obj->_data = array('base' => $base_data, 'extension' => $obj->_data);      return $obj;  }    /* 連結到字節流中的非符號對象 */  function rxdata_read_link($file) {      $id = rxdata_read_long($file);      return rxdata_fetch_object($id);  }    /* 讀取一個經過Ruby Marshal特殊處理的有符號長整數(不含類型標記) */  function rxdata_read_long($file) {      $ch = to_signed(rxdata_read_byte($file));      if ($ch == 0) {          return 0;      }      if ($ch > 0) {          if ($ch > 4 && $ch < 128) {              return $ch - 5;          }          $x = 0;          for ($i = 0; $i < $ch; $i++) {              $x |= to_signed(rxdata_read_byte($file), SIZEOF_LONG) << (8 * $i);          }      } else {          if ($ch > -129 && $ch < -4) {              return $ch + 5;          }          $ch = -$ch;          $x = -1;          for ($i = 0; $i < $ch; $i++) {              $x &= ~(0xff << (8 * $i));              $x |= to_signed(rxdata_read_byte($file), SIZEOF_LONG) << (8 * $i);          }      }      return $x;  }    function rxdata_read_module($file) {      $module = new RubyModule();      rxdata_register_object($module);      $module->name = rxdata_read_string($file);      return $module;  }    // 如果指定了參數$obj,則此函數隻讀取成員變量  function rxdata_read_object($file, $obj = NULL) {      if (is_null($obj)) {          $obj = rxdata_prepare_object($file);      }      for ($i = 0; $i < $obj->_length; $i++) {          $memsym = rxdata_read_symbol_block($file);          $memsym->setMember($obj, rxdata_read($file, $obj));      }      return $obj;  }    function rxdata_read_regexp($file) {      $reg = '/' . rxdata_read_string($file) . '/';      $options = rxdata_read_byte($file);      if ($options & ONIG_OPTION_IGNORECASE) {          $reg .= 'i';      }      if ($options & ONIG_OPTION_MULTILINE) {          $reg .= 'm';      }      if ($options & ONIG_OPTION_EXTEND) {          $reg .= 'x';      }      rxdata_register_object($reg);      return $reg;  }    function rxdata_read_string($file, $register = false) {      $len = rxdata_read_long($file);      if ($len > 0) {          $str = fread($file, $len);      } else {          $str = '';      }      if ($register) {          rxdata_register_object($str);      }      return $str;  }    function rxdata_read_symbol($file) {      $symbol = new RubySymbol();      $symbol->name = rxdata_read_string($file);      rxdata_register_symbol($symbol); // 註冊該符號,以便於之後連結回來。因為在內存中,同名符號對象只允許存在一次      return $symbol;  }  function rxdata_read_symbol_block($file) {      $type = fgetc($file);      if ($type == RBT_SYMBOL) {          return rxdata_read_symbol($file);      } else if ($type == RBT_SYMLINK) {          return rxdata_read_symlink($file);      } else {          return NULL;      }  }  function rxdata_read_symlink($file) {      $id = rxdata_read_long($file);      return rxdata_fetch_symbol($id);  }    function rxdata_read_uclass($file) {      $obj = rxdata_prepare_object($file, false);      $next_registry = count($GLOBALS['_RBOBJLIST']);      $obj->_data = rxdata_read($file);      rxdata_unregister_object($next_registry); // 由於$obj已經註冊,所以需要刪除重複註冊的$obj->_data      $obj->_length = count($obj->_data);      return $obj;  }    /* 獲取一個由固定n個字節(小端序)表示的無符號整數 */  function rxdata_read_ulong($file, $n = SIZEOF_LONG) {      $num = 0;      for ($i = 0; $i < $n; $i++) {          $v = rxdata_read_byte($file);          $num += ($v << ($i * 8));      }      return $num;  }    // 注意:由於$obj已經註冊,所以返回時必須返回$obj,不能返回其他變量  function rxdata_read_userdef($file) {      $obj = rxdata_prepare_object($file);      switch ($obj->_name) {      case 'Table':          // Table是RGSS自帶的內部類,不是Ruby自帶的類          // 地圖圖層的三維數組的結構是: data[x坐標, y坐標, 地圖id]          $dim = rxdata_read_ulong($file); // 數組的維數          $xsize = rxdata_read_ulong($file);          $ysize = rxdata_read_ulong($file);          $zsize = rxdata_read_ulong($file);          $total = rxdata_read_ulong($file);                    $arr = array();          for ($i = 0; $i < $total; $i++) {              $value = to_signed(rxdata_read_ulong($file, SIZEOF_INT), SIZEOF_INT);              if ($dim == 1) {                  $arr[$i] = $value;              } else if ($dim == 2) {                  $x = $i % $xsize;                  $y = (int)($i / $xsize);                  if (!isset($arr[$x])) {                      $arr[$x] = array();                  }                  $arr[$x][$y] = $value;              } else if ($dim == 3) {                  $x = $i % $xsize;                  $y = (int)($i % ($xsize * $ysize) / $xsize);                  $z = (int)($i / ($xsize * $ysize));                  if (!isset($arr[$x])) {                      $arr[$x] = array();                  }                  if (!isset($arr[$x][$y])) {                      $arr[$x][$y] = array();                  }                  $arr[$x][$y][$z] = $value;              }          }          $obj->_data = $arr;          break;      case 'Color':      case 'Tone':          $format = 'dred/dgreen/dblue/d';          if ($obj->_name == 'Color') {              $format .= 'alpha';          } else {              $format .= 'gray';          }          $data = fread($file, 4 * SIZEOF_DOUBLE);          $obj->_data = unpack($format, $data);          break;      default:          /* 輸出範例:          ** Array ( [0] => RubyObject Object ( [_name] => Color [_length] => 32 [_data] => Array ( ) [data] => 00 00 00 00 00 C0 58 40 00 00 00 00 00 00 59 40 00 00 00 00 00 C0 62 40 00 00 00 00 00 E0 6F 40 ) )           **/          $data = fread($file, $obj->_length);          trigger_error("無法解析的自定義對象類型\"{$obj->_name}\"", E_USER_NOTICE);          $obj->_data = '';          for ($i = 0; $i < $obj->_length; $i++) {              $obj->_data .= sprintf("%02X ", ord($data{$i}));          }          $obj->_data = rtrim($obj->_data);      }      return $obj;  }    function rxdata_read_usrmarshal($file) {      $obj = rxdata_prepare_object($file, false);      $obj->_length = 1;      $obj->_data = rxdata_read($file);      return $obj;  }    /* Ruby連結列表相關函數 */  $_RBOBJLIST = array(); // 當前字節流中出現的所有非符號對象  $_RBSYMLIST = array(); // 當前字節流中出現的所有符號對象    // 獲取已註冊的非符號對象  function rxdata_fetch_object($id) {      global $_RBOBJLIST;      if (isset($_RBOBJLIST[$id])) {          return $_RBOBJLIST[$id];      } else {          trigger_error(sprintf('引用未註冊的非符號對象ID: %d,已註冊的最大ID為: %d', $id, count($_RBOBJLIST) - 1), E_USER_WARNING);          return NULL;      }  }    // 獲取已註冊的符號對象  function rxdata_fetch_symbol($id) {      global $_RBSYMLIST;      if (isset($_RBSYMLIST[$id])) {          return $_RBSYMLIST[$id];      } else {          trigger_error(sprintf('引用未註冊的符號對象ID: %d,已註冊的最大ID為: %d', $id, count($_RBSYMLIST) - 1), E_USER_WARNING);          return NULL;      }  }    // 註冊非符號對象  function rxdata_register_object(&$obj) {      global $_RBOBJLIST;      $id = count($_RBOBJLIST);      $_RBOBJLIST[$id] = &$obj;      return $id;  }    // 註冊符號對象  function rxdata_register_symbol(RubySymbol $sym) {      global $_RBSYMLIST;      $id = count($_RBSYMLIST);      $_RBSYMLIST[$id] = $sym; // $sym本身就是一個php對象,所以這裏無需加上引用符號      return $id;  }    // 替換非符號對象註冊信息  function rxdata_registry_replace(&$old, &$new) {      global $_RBOBJLIST;      foreach ($_RBOBJLIST as $i => $v) {          if ($v === $old) {              $_RBOBJLIST[$i] = &$new;          }      }  }    // 清空上一個字節流的所有連結列表  function rxdata_reset() {      $GLOBALS['_RBOBJLIST'] = array();      $GLOBALS['_RBSYMLIST'] = array();  }    function rxdata_unregister_object($id = NULL) {      global $_RBOBJLIST;      if (is_null($id)) {          // 取消註冊最近註冊的對象          array_pop($_RBOBJLIST);      } else {          // 取消註冊指定序號的對象          unset($_RBOBJLIST[$id]);          $_RBOBJLIST = array_values($_RBOBJLIST);      }  }        /* 將無符號十六進制數轉換為有符號十進制整數, 參數$bytes規定了有符號整數類型的字節數 */  /* 在marshal.c中,宏SIGN_EXTEND_CHAR(n)就相當於這裏的to_signed(n) */  function to_signed($hex, $bytes = SIZEOF_CHAR) {      $mask = 1 << ($bytes * 8 - 1);      return ($hex ^ $mask) - $mask;  }    /* 將有符號十進制整數轉換為無符號十六進制整數 */  function to_unsigned($dex, $bytes = SIZEOF_CHAR) {      $mask = 1 << ($bytes * 8 - 1);      return ($dex + $mask) ^ $mask;  }    // 在64位php中,整數1的十六進制是0x01,而整數-1的十六進制數是0xffffffffffffffff  // 因此,如果想要char a = -1的十六進制值,只需在php中寫上-1 & 0xff即可  // echo '0x', dechex(-1 & 0xff); // 輸出0xff  // 使用to_unsigned函數也能達到同樣的目的: echo to_unsigned(-1, SIZEOF_CHAR);  // 此外,php還提供了unpack函數讀取二進制字符串表示的無符號整數 
       | 
    
    
        | 
      
        
          8樓
          巨大八爪鱼
          2016-2-8 18:29
          
          
           
         
        【示例代碼4:輸出所有地圖的名稱和大小等信息】 <?php  include_once('rxdata_library.php'); $maps = rxdata_load('project/Data/MapInfos.rxdata'); foreach ($maps as $map_id => $map) {  $map_info = rxdata_load(sprintf('project/Data/Map%03d.rxdata', $map_id));  $events_num = count($map_info->events);  if (isset($map_info->events[1])) {   $first_event_name = $map_info->events[1]->name;  } else {   $first_event_name = '無';  }  printf('地圖: %s, 尺寸: %dx%d, 事件數: %d, 第一個事件的名稱: %s<br>', $map->name, $map_info->width, $map_info->height, $events_num, $first_event_name); } ?>
  【運行結果】
  
   
       |