PHP TibiaCam file reader

Simple reader for uncompressed TibiaCam files (binary files, up to 60MB).

It’s also example of fast reading binary data from file and handling it as stream.

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
<?php
class BinaryData
{
/** @var resource */
private $data;
/** @var int */
private $length;
/**
* BinaryData constructor.
* @param string $data
*/
public function __construct($data)
{
$this->data = fopen('php://memory', 'wb+');
fwrite($this->data, $data);
$this->length = ftell($this->data);
rewind($this->data);
}
/**
* @return int
*/
public function getLength()
{
return $this->length;
}
/**
* @return bool
*/
public function isEof()
{
return ftell($this->data) == $this->length;
}
/**
* @param int $length
*/
public function skip($length)
{
fseek($this->data, $length, SEEK_CUR);
}
/**
* @return int
*/
public function getU8()
{
return unpack('C', fread($this->data, 1))[1];
}
/**
* @return int
*/
public function getU16()
{
return unpack('v', fread($this->data, 2))[1];
}
/**
* @return int
*/
public function getU32()
{
return unpack('V', fread($this->data, 4))[1];
}
/**
* @return int
*/
public function getU64()
{
return unpack('P', fread($this->data, 8))[1];
}
/**
* @param int $length
* @return string
*/
public function getString($length = -1)
{
if ($length == -1) {
$length = $this->getU16();
}
return fread($this->data, $length);
}
}
class NetworkPacket extends BinaryData
{
/**
* 0x01 = packets sent to player
* 0x03 = packets received from player
* 0x05 = refresh packets for fast cam rewinding
*/
const TYPE_OUT = 0x01;
const TYPE_IN = 0x03;
const TYPE_REFRESH = 0x05;
/** @var int */
private $type;
/**
* NetworkPacket constructor.
* @param string $data
*/
public function __construct($data)
{
parent::__construct($data);
$this->type = $this->getU8();
}
/**
* @return int
*/
public function getType()
{
return $this->type;
}
}
class Cam extends BinaryData
{
/**
* Cam constructor.
* @param string $filePath path to cam file
*/
public function __construct($filePath)
{
parent::__construct(file_get_contents($filePath));
}
/**
* @return array
*/
public function readTibiaCamAttributes()
{
$this->skip(8); // text: TIBIACAM
$camVersion = $this->getU8();
$playerId = $this->getU32();
$playerName = $this->getString();
$protocolVersion = $this->getU16();
$timeCreated = $this->getU64();
return [$camVersion, $playerId, $playerName, $protocolVersion, $timeCreated];
}
}
$fileName = 'nowy.cam.ready';
$cam = new Cam($fileName);
$camAttributes = $cam->readTibiaCamAttributes();
var_dump($camAttributes);
while (!$cam->isEof()) {
$packetTime = $cam->getU64();
var_dump($packetTime);
$packet = new NetworkPacket($cam->getString());
var_dump($packet->getType());
var_dump($packet->getLength());
}
<?php class BinaryData { /** @var resource */ private $data; /** @var int */ private $length; /** * BinaryData constructor. * @param string $data */ public function __construct($data) { $this->data = fopen('php://memory', 'wb+'); fwrite($this->data, $data); $this->length = ftell($this->data); rewind($this->data); } /** * @return int */ public function getLength() { return $this->length; } /** * @return bool */ public function isEof() { return ftell($this->data) == $this->length; } /** * @param int $length */ public function skip($length) { fseek($this->data, $length, SEEK_CUR); } /** * @return int */ public function getU8() { return unpack('C', fread($this->data, 1))[1]; } /** * @return int */ public function getU16() { return unpack('v', fread($this->data, 2))[1]; } /** * @return int */ public function getU32() { return unpack('V', fread($this->data, 4))[1]; } /** * @return int */ public function getU64() { return unpack('P', fread($this->data, 8))[1]; } /** * @param int $length * @return string */ public function getString($length = -1) { if ($length == -1) { $length = $this->getU16(); } return fread($this->data, $length); } } class NetworkPacket extends BinaryData { /** * 0x01 = packets sent to player * 0x03 = packets received from player * 0x05 = refresh packets for fast cam rewinding */ const TYPE_OUT = 0x01; const TYPE_IN = 0x03; const TYPE_REFRESH = 0x05; /** @var int */ private $type; /** * NetworkPacket constructor. * @param string $data */ public function __construct($data) { parent::__construct($data); $this->type = $this->getU8(); } /** * @return int */ public function getType() { return $this->type; } } class Cam extends BinaryData { /** * Cam constructor. * @param string $filePath path to cam file */ public function __construct($filePath) { parent::__construct(file_get_contents($filePath)); } /** * @return array */ public function readTibiaCamAttributes() { $this->skip(8); // text: TIBIACAM $camVersion = $this->getU8(); $playerId = $this->getU32(); $playerName = $this->getString(); $protocolVersion = $this->getU16(); $timeCreated = $this->getU64(); return [$camVersion, $playerId, $playerName, $protocolVersion, $timeCreated]; } } $fileName = 'nowy.cam.ready'; $cam = new Cam($fileName); $camAttributes = $cam->readTibiaCamAttributes(); var_dump($camAttributes); while (!$cam->isEof()) { $packetTime = $cam->getU64(); var_dump($packetTime); $packet = new NetworkPacket($cam->getString()); var_dump($packet->getType()); var_dump($packet->getLength()); }
<?php

class BinaryData
{
    /** @var resource */
    private $data;
    /** @var int */
    private $length;

    /**
     * BinaryData constructor.
     * @param string $data
     */
    public function __construct($data)
    {
        $this->data = fopen('php://memory', 'wb+');
        fwrite($this->data, $data);
        $this->length = ftell($this->data);
        rewind($this->data);
    }

    /**
     * @return int
     */
    public function getLength()
    {
        return $this->length;
    }

    /**
     * @return bool
     */
    public function isEof()
    {
        return ftell($this->data) == $this->length;
    }

    /**
     * @param int $length
     */
    public function skip($length)
    {
        fseek($this->data, $length, SEEK_CUR);
    }

    /**
     * @return int
     */
    public function getU8()
    {
        return unpack('C', fread($this->data, 1))[1];
    }

    /**
     * @return int
     */
    public function getU16()
    {
        return unpack('v', fread($this->data, 2))[1];
    }

    /**
     * @return int
     */
    public function getU32()
    {
        return unpack('V', fread($this->data, 4))[1];
    }

    /**
     * @return int
     */
    public function getU64()
    {
        return unpack('P', fread($this->data, 8))[1];
    }

    /**
     * @param int $length
     * @return string
     */
    public function getString($length = -1)
    {
        if ($length == -1) {
            $length = $this->getU16();
        }

        return fread($this->data, $length);
    }

}

class NetworkPacket extends BinaryData
{
    /**
     * 0x01 = packets sent to player
     * 0x03 = packets received from player
     * 0x05 = refresh packets for fast cam rewinding
     */
    const TYPE_OUT = 0x01;
    const TYPE_IN = 0x03;
    const TYPE_REFRESH = 0x05;

    /** @var int */
    private $type;

    /**
     * NetworkPacket constructor.
     * @param string $data
     */
    public function __construct($data)
    {
        parent::__construct($data);
        $this->type = $this->getU8();
    }

    /**
     * @return int
     */
    public function getType()
    {
        return $this->type;
    }

}

class Cam extends BinaryData
{
    /**
     * Cam constructor.
     * @param string $filePath path to cam file
     */
    public function __construct($filePath)
    {
        parent::__construct(file_get_contents($filePath));
    }

    /**
     * @return array
     */
    public function readTibiaCamAttributes()
    {
        $this->skip(8); // text: TIBIACAM

        $camVersion = $this->getU8();
        $playerId = $this->getU32();
        $playerName = $this->getString();
        $protocolVersion = $this->getU16();
        $timeCreated = $this->getU64();

        return [$camVersion, $playerId, $playerName, $protocolVersion, $timeCreated];
    }

}

$fileName = 'nowy.cam.ready';
$cam = new Cam($fileName);
$camAttributes = $cam->readTibiaCamAttributes();
var_dump($camAttributes);

while (!$cam->isEof()) {
    $packetTime = $cam->getU64();
    var_dump($packetTime);
    $packet = new NetworkPacket($cam->getString());
    var_dump($packet->getType());
    var_dump($packet->getLength());
}

Leave a Reply

Your email address will not be published. Required fields are marked *