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.
<?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());
}