Načtení DBC souborů v PHP

Z WoWResource Wiki
Přejít na: navigace, hledání

Popis PHP třídy

$dbc = new DbcReader(); // Vztvoření instance
$dbc->loadDbc("jmenosoubor.dbc", "format souboru"); // Načtení souboru

Formátovací značky

  • u - unsigned long (4B - 32 bitu)
  • i - signed long (4B - 32 bitu)
  • s - retezec
  • f - float (4B)
  • x - preskoč 4B
  • X - preskoč 1B

Načtení hodnot se provádí pomocí fcí getInt(row, col), getUint(r, c), getString(r, c), getFloat(r, c), getByte(r, c). Funkce count() vrací počet řádků v dbc soubrou, fieldCount() vrací počet polí v jednom řádku. getLine(row) vrací celý jeden řádek, getLineCols(row, array cols) vrací vybrané sloupce jednoho řádku.

Kód tříd

 class BinaryReader
 {
   private $handle;  /// Handle na otevreny dbc soubor
   
   /// Konstruktor
   function __construct()
   {
     $this->handle = false;
   } 
   
   /// Destruktor
   function __destruct() 
   {
     if ($this->handle)
       fclose($this->handle);
   }
   
   public function loadFile($filename)
   {
     if ($this->handle)
       fclose($this->handle);
   
     $this->handle = @fopen($filename, "rb");
     if (!$this->handle)
       die ("Soubor $filename neexistuje");  
   }
   
   /// Nacteni bytu
   public function readByte()
   {
     return ord(fread($this->handle, 1));
   }  
   
   /// Nacteni unsigned int
   public function readUint()
   {
     $val = unpack("V*", fread($this->handle, 4));
     return $val[1];
   }
   
   /// Nacteni signed int
   public function readInt()
   {
     $val = unpack("I*", fread($this->handle, 4));
     return $val[1];
   }  
   
   /// Nacteni float
   public function readFloat()
   {
     $val = unpack("f*", fread($this->handle, 4));
     return $val[1];
   }
   
   /// Nacteni znaku
   public function readChar()
   {
     return fgetc($this->handle);
   }    
   
   public function seekPos($pos, $type = SEEK_SET)
   {
     fseek($this->handle, $pos, $type);
   }
 }
 
 class DbcReader extends BinaryReader
 {
   private $offsets; /// Offsety jednotlivych poli
   private $format;  /// Format dbc souboru
   
   private $recSize; /// Velikost jednoho zaznamu
   private $recCount;/// Pocet zaznamu
   private $strSize; /// Velikost string casti
   private $fldCount;/// Pocet poli (v 1 zaznamu)
      
   /// Nacteni dbc souboru
   public function loadDbc($file, $format)
   {
     $this->loadFile($file);
     
     if ($this->readUint() != 0x43424457)
       die ("NO DBC!");
       
     $this->recCount = $this->readUint();
     $this->fldCount = $this->readUint();
     $this->recSize = $this->readUint();
     $this->strSize = $this->readUint();
     
     //if (strlen($format) != $this->fldCount)
     //  die ("Field count error");
     
     $this->format = $format;
     $this->generateOffsetTable($format);
   }
   
   /// Vytvoreni tabulky offsetu
   private function generateOffsetTable($format)
   {
     $this->offsets = array();
     $this->offsets[0] = 0;
     for ($i = 1; $i < strlen($format); $i++)
     {
       $this->offsets[$i] = $this->offsets[$i-1];
       switch ($format[$i-1])
       {
         case "b": case "X": $this->offsets[$i] += 1;	break;
         case "x": case "u": case "i": case "f": case "s": $this->offsets[$i] += 4;	break;
       } 
     }
     
     $lastOff = $this->offsets[strlen($format) - 1] + ($format[strlen($format)-1] == "b" || $format[strlen($format)-1] == "X" ? 1 : 4);
     if ($lastOff != $this->recSize)
       die ("Record size error!"); 
   }
   
   //////////////////////////////////////////////////////////////////////////////
 
   /// Nastaveni pozice v souboru
   private function seekPosi($row, $col)
   {
     $pos = 20 + $row*$this->recSize + $this->offsets[$col];
     //fseek($this->handle, $pos, SEEK_SET);
     $this->seekPos($pos);
   }
   
   //////////////////////////////////////////////////////////////////////////////
   
   public function getByte($row, $col)
   {
     $this->seekPosi($row, $col);  
     return $this->readByte();
   }   
   
   public function getUint($row, $col)
   {
     $this->seekPosi($row, $col);  
     return $this->readUint();
   }
   
   public function getInt($row, $col)
   {
     $this->seekPosi($row, $col);  
     return $this->readInt();
   }  
   
   public function getFloat($row, $col)
   {
     $this->seekPosi($row, $col);  
     return $this->readFloat();
   }
   
   public function getString($row, $col)
   {
     $offset = $this->getUint($row, $col);
     
     $pos = 20 + $this->recCount * $this->recSize + $offset;
     $this->seekPos($pos);
     
     $str = "";
     while (($char = $this->readChar()) != "\0")
       $str .= $char;
     
     return $str;
   }    
   
   /// Vrati jeden cely radek jako pole
   public function getLine($row)
   {
     $ret = array();
     for($i = 0; $i < $this->fldCount; $i++)
     {
       switch($this->format[$i])
       {
         case "b": $ret[$i] = $this->getByte($row, $i); break;
         case "u": $ret[$i] = $this->getUint($row, $i); break;
         case "i": $ret[$i] = $this->getInt($row, $i); break;
         case "f": $ret[$i] = $this->getFloat($row, $i); break;
         case "s": $ret[$i] = $this->getString($row, $i); break;
         case "x": case "X": default: break;
       }
     }
     return $ret;
   }
   
   /// Vrati vybrane sloupecky z jednoho radku
   public function getLineCols($row, $cols)
   {
     $ret = array();
     for($i = 0; $i < count($cols); $i++)
     {
       switch($this->format[$cols[$i]])
       {
         case "b": $ret[$i] = $this->getByte($row, $cols[$i]); break;
         case "u": $ret[$i] = $this->getUint($row, $cols[$i]); break;
         case "i": $ret[$i] = $this->getInt($row, $cols[$i]); break;
         case "f": $ret[$i] = $this->getFloat($row, $cols[$i]); break;
         case "s": $ret[$i] = $this->getString($row, $cols[$i]); break;
         case "x": case "X": default: break;
       }
     }
     return $ret;  
   }
   
   /// Pocet zaznamu
   public function count() { return $this->recCount; }
   /// Pocet poli
   public function fieldCount() { return $this->fldCount; }
 }

Příklad použití

 $dbc =& new DbcReader();
 $dbc->loadDbc("Map.dbc", "uxixssssssssssssssssxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxixxxxx");
 //$dbc->loadDbc("SpellItemEnchantmentCondition.dbc", "ubbbbbxxxxxbbbbbbbbbbiiiiiXXXXX");
 $c = $dbc->count();
 for($i = 0; $i < $c; $i++)
 {
   echo $dbc->getUint($i, 0). "\t".$dbc->getInt($i, 2)."\t".$dbc->getString($i, 4)." \n";
   //echo $dbc->getUint($i,0)."\t".$dbc->getByte($i,1)."\t".$dbc->getByte($i,2)."\t".$dbc->getByte($i,3)."\n";
 }