Setup/DBCReader
* port extended client file handling from other branch * class DBC -> DBCReader now initializes a DBCFile which itself is a BinaryFile * update DBCReader to use the new DB wrappers multi-insert feature
This commit is contained in:
parent
69df50619a
commit
c85675e181
11 changed files with 766 additions and 524 deletions
104
includes/setup/datatypes/primitives.php
Normal file
104
includes/setup/datatypes/primitives.php
Normal file
|
|
@ -0,0 +1,104 @@
|
|||
<?php
|
||||
|
||||
namespace Aowow;
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
|
||||
abstract class Primitive
|
||||
{
|
||||
public const /* int */ SIZE = 1;
|
||||
public const /* string */ PACK_FMT = 'x';
|
||||
|
||||
protected string $data;
|
||||
|
||||
public function __construct(BinaryFile|string $data)
|
||||
{
|
||||
if (is_string($data))
|
||||
$this->data = $data;
|
||||
else
|
||||
$this->data = $data->read(static::SIZE);
|
||||
}
|
||||
|
||||
public function pack() : string
|
||||
{
|
||||
return $this->data;
|
||||
}
|
||||
|
||||
public function unpack() : mixed
|
||||
{
|
||||
return current(unpack(static::PACK_FMT, $this->data));
|
||||
}
|
||||
|
||||
public function __debugInfo() : array
|
||||
{
|
||||
return [$this->unpack()];
|
||||
}
|
||||
}
|
||||
|
||||
class Char extends Primitive
|
||||
{
|
||||
public const /* int */ SIZE = 1;
|
||||
public const /* string */ PACK_FMT = 'C';
|
||||
|
||||
public function unpack() : string
|
||||
{
|
||||
return chr(parent::unpack());
|
||||
}
|
||||
}
|
||||
|
||||
class Boolean extends Primitive
|
||||
{
|
||||
public const /* int */ SIZE = 1;
|
||||
public const /* string */ PACK_FMT = 'C';
|
||||
|
||||
public function unpack() : string
|
||||
{
|
||||
return !!(parent::unpack());
|
||||
}
|
||||
}
|
||||
|
||||
class UInt8 extends Primitive
|
||||
{
|
||||
public const /* int */ SIZE = 1;
|
||||
public const /* string */ PACK_FMT = 'C';
|
||||
}
|
||||
|
||||
class Int8 extends Primitive
|
||||
{
|
||||
public const /* int */ SIZE = 1;
|
||||
public const /* string */ PACK_FMT = 'c';
|
||||
}
|
||||
|
||||
class UInt16 extends Primitive
|
||||
{
|
||||
public const /* int */ SIZE = 2;
|
||||
public const /* string */ PACK_FMT = 'v';
|
||||
}
|
||||
|
||||
class Int16 extends Primitive
|
||||
{
|
||||
public const /* int */ SIZE = 2;
|
||||
public const /* string */ PACK_FMT = 's';
|
||||
}
|
||||
|
||||
class UInt32 extends Primitive
|
||||
{
|
||||
public const /* int */ SIZE = 4;
|
||||
public const /* string */ PACK_FMT = 'V';
|
||||
}
|
||||
|
||||
class Int32 extends Primitive
|
||||
{
|
||||
public const /* int */ SIZE = 4;
|
||||
public const /* string */ PACK_FMT = 'l';
|
||||
}
|
||||
|
||||
class Double extends Primitive
|
||||
{
|
||||
public const /* int */ SIZE = 4;
|
||||
public const /* string */ PACK_FMT = 'f';
|
||||
}
|
||||
|
||||
?>
|
||||
202
includes/setup/files/binaryfile.class.php
Normal file
202
includes/setup/files/binaryfile.class.php
Normal file
|
|
@ -0,0 +1,202 @@
|
|||
<?php
|
||||
|
||||
namespace Aowow;
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
|
||||
class BinaryFile
|
||||
{
|
||||
private /*res*/ $handle = null;
|
||||
private string $data = '';
|
||||
private int $pos = 0;
|
||||
|
||||
protected int $filesize = 0;
|
||||
|
||||
public string $error = '';
|
||||
|
||||
public function __construct(string $file, private bool $inRAM = true)
|
||||
{
|
||||
if (!file_exists($file))
|
||||
{
|
||||
$this->error = 'file '.$file.' not found';
|
||||
return;
|
||||
}
|
||||
|
||||
if (!$this->handle = fopen($file, 'rb'))
|
||||
{
|
||||
$this->error = 'failed to open file '.$file;
|
||||
return;
|
||||
}
|
||||
|
||||
$this->filesize = filesize($file);
|
||||
|
||||
if ($inRAM)
|
||||
$this->data = file_get_contents($file);
|
||||
}
|
||||
|
||||
public function __destruct()
|
||||
{
|
||||
$this->close();
|
||||
}
|
||||
|
||||
|
||||
/**********************/
|
||||
/* direct file access */
|
||||
/**********************/
|
||||
|
||||
public function read(int $bytes) : ?string
|
||||
{
|
||||
if ($this->error || !is_resource($this->handle) || $bytes < 0)
|
||||
return null;
|
||||
|
||||
$start = $this->pos;
|
||||
$this->pos += $bytes;
|
||||
|
||||
if ($this->inRAM)
|
||||
return substr($this->data, $start, $bytes);
|
||||
else
|
||||
return fread($this->handle, $bytes);
|
||||
}
|
||||
|
||||
public function readOffset(int $bytes, int $offset, bool $jumpBack = true) : ?string
|
||||
{
|
||||
if ($this->error || !is_resource($this->handle))
|
||||
return null;
|
||||
|
||||
if ($jumpBack)
|
||||
$curPos = $this->inRAM ? $this->pos : ftell($this->handle);
|
||||
|
||||
$this->seek($offset);
|
||||
|
||||
$str = $this->read($bytes);
|
||||
|
||||
if ($jumpBack)
|
||||
$this->seek($curPos);
|
||||
|
||||
return $str;
|
||||
}
|
||||
|
||||
public function seek(int $pos) : int
|
||||
{
|
||||
if (!is_resource($this->handle))
|
||||
return 0;
|
||||
|
||||
if ($pos < 0)
|
||||
$pos = 0;
|
||||
if ($pos > $this->filesize)
|
||||
$pos = $this->filesize;
|
||||
|
||||
$this->pos = $pos;
|
||||
|
||||
if (!$this->inRAM)
|
||||
fseek($this->handle, $pos, SEEK_SET);
|
||||
|
||||
return $pos;
|
||||
}
|
||||
|
||||
public function ffwd(int $bytes) : int
|
||||
{
|
||||
if (!is_resource($this->handle))
|
||||
return 0;
|
||||
|
||||
$curPos = $this->inRAM ? $this->pos : ftell($this->handle);
|
||||
|
||||
if ($curPos + $bytes < 0)
|
||||
$bytes -= $curPos;
|
||||
if ($curPos + $bytes > $this->filesize)
|
||||
$bytes -= $this->filesize;
|
||||
|
||||
$this->pos += $bytes;
|
||||
|
||||
if ($this->inRAM)
|
||||
return $this->pos;
|
||||
|
||||
fseek($this->handle, $bytes, SEEK_CUR);
|
||||
return ftell($this->handle);
|
||||
}
|
||||
|
||||
public function close() : void
|
||||
{
|
||||
if (is_resource($this->handle))
|
||||
fclose($this->handle);
|
||||
}
|
||||
|
||||
public function tell() : int
|
||||
{
|
||||
if (!is_resource($this->handle))
|
||||
return 0;
|
||||
|
||||
return $this->inRAM ? $this->pos : ftell($this->handle);
|
||||
}
|
||||
|
||||
/******************/
|
||||
/* read Primitive */
|
||||
/******************/
|
||||
|
||||
public function readInt8() : ?Int8
|
||||
{
|
||||
if (!is_resource($this->handle))
|
||||
return null;
|
||||
return new Int8($this);
|
||||
}
|
||||
|
||||
public function readInt16() : ?Int16
|
||||
{
|
||||
if (!is_resource($this->handle))
|
||||
return null;
|
||||
return new Int16($this);
|
||||
}
|
||||
|
||||
public function readInt32() : ?Int32
|
||||
{
|
||||
if (!is_resource($this->handle))
|
||||
return null;
|
||||
return new Int32($this);
|
||||
}
|
||||
|
||||
public function readUInt8() : ?UInt8
|
||||
{
|
||||
if (!is_resource($this->handle))
|
||||
return null;
|
||||
return new UInt8($this);
|
||||
}
|
||||
|
||||
public function readUInt16() : ?UInt16
|
||||
{
|
||||
if (!is_resource($this->handle))
|
||||
return null;
|
||||
return new UInt16($this);
|
||||
}
|
||||
|
||||
public function readUInt32() : ?UInt32
|
||||
{
|
||||
if (!is_resource($this->handle))
|
||||
return null;
|
||||
return new UInt32($this);
|
||||
}
|
||||
|
||||
public function readFloat() : ?Double
|
||||
{
|
||||
if (!is_resource($this->handle))
|
||||
return null;
|
||||
return new Double($this);
|
||||
}
|
||||
|
||||
public function readChar() : ?Char
|
||||
{
|
||||
if (!is_resource($this->handle))
|
||||
return null;
|
||||
return new Char($this);
|
||||
}
|
||||
|
||||
public function readBool() : ?Boolean
|
||||
{
|
||||
if (!is_resource($this->handle))
|
||||
return null;
|
||||
return new Boolean($this);
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
83
includes/setup/files/dbcfile.class.php
Normal file
83
includes/setup/files/dbcfile.class.php
Normal file
|
|
@ -0,0 +1,83 @@
|
|||
<?php
|
||||
|
||||
namespace Aowow;
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
|
||||
class DBCFile extends BinaryFile
|
||||
{
|
||||
private const /* string */ MAGIC = 'WDBC';
|
||||
private const /* int */ HEADER_SIZE = 16;
|
||||
|
||||
private readonly int $stringSize;
|
||||
private readonly int $stringOffset;
|
||||
|
||||
public readonly int $nCols;
|
||||
public readonly int $nRows;
|
||||
public readonly int $recordSize;
|
||||
|
||||
public function __construct(string $file)
|
||||
{
|
||||
parent::__construct($file);
|
||||
|
||||
if ($this->filesize < strlen(self::MAGIC) + self::HEADER_SIZE)
|
||||
{
|
||||
$this->error = 'file '.$file.' too small for a dbc';
|
||||
$this->close();
|
||||
return;
|
||||
}
|
||||
|
||||
if ($this->read(4) != self::MAGIC)
|
||||
{
|
||||
$this->error = 'file '.$file.' has incorrect magic bytes';
|
||||
$this->close();
|
||||
return;
|
||||
}
|
||||
|
||||
[, $this->nRows, $this->nCols, $this->recordSize, $this->stringSize] = unpack(UInt32::PACK_FMT.'4', $this->read(self::HEADER_SIZE));
|
||||
$this->stringOffset = strlen(self::MAGIC) + self::HEADER_SIZE + $this->recordSize * $this->nRows;
|
||||
|
||||
if ($this->stringOffset + $this->stringSize != $this->filesize)
|
||||
{
|
||||
$this->error = 'file '.$file.' has unexpected size - expected: '.($this->stringOffset + $this->stringSize).' has: '.$this->filesize;
|
||||
$this->close();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
public function readRecord(string $colFmt = "V*") : array
|
||||
{
|
||||
return unpack($colFmt, $this->read($this->recordSize));
|
||||
}
|
||||
|
||||
public function readString() : ?string
|
||||
{
|
||||
$x = $this->readUInt32();
|
||||
if (is_null($x))
|
||||
return null;
|
||||
|
||||
return $this->getStringFromBlock($x->unpack());
|
||||
}
|
||||
|
||||
public function getStringFromBlock(int $offset) : ?string
|
||||
{
|
||||
$curPos = $this->tell();
|
||||
|
||||
$this->seek($this->stringOffset + $offset);
|
||||
|
||||
// apparently it is more efficient to read more than one byte at once..?
|
||||
$str = '';
|
||||
while (($pos = strpos($str, "\0")) === false)
|
||||
$str .= $this->read(255);
|
||||
|
||||
$str = substr($str, 0, $pos);
|
||||
|
||||
$this->seek($curPos);
|
||||
|
||||
return $pos ? $str : null;
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
Loading…
Add table
Add a link
Reference in a new issue