Načtení DBC souborů v PHP
Z WoWResource Wiki
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";
}
