Reading DB2 files - some questions

Hey :slight_smile:

a few hours ago I’ve started writing a PHP library to access the db2 files of the current WoW client.

To test my library I’ve implemented the structure of CharTitles.db2. This looks like that:

class CharTitles extends DB2File
{
public function __construct(File $file)
{
parent::__construct(new BinaryReader($file->getBuffer()));
}

public function getStructure() : array
{
return [
DB2File::FIELD_STR,
DB2File::FIELD_STR,
DB2File::FIELD_INT16,
DB2File::FIELD_BYTE
];
}

public function hasIndexFieldInData() : bool
{
return true;
}
}

I’ve taken the structure from the current trinitycore version.

If I load the file now, I’ll just get one correct record (the first one). The others are containing bad data.

The reason for this is a single byte after each record so if change the structure to this

DB2File::FIELD_STR,
DB2File::FIELD_STR,
DB2File::FIELD_INT16,
DB2File::FIELD_INT16

all will work as it should.

Now my question.

What exactly is that byte after each record? Is it a kind of seperator or is the structure of the current trinitycore just outdated?

Thanks in advance!

I did another test with ChatChannels.db2. It seems that the total amount of bytes in a record modulo 4 must be 0.

So I’ve implemented following logic

$bytesToSkip = 4 - ($recordSize % 4);
if ($bytesToSkip != 4)
$this->reader->skip($bytesToSkip);

Is this correct or just a bad hack?

EDIT#1: In general it seems to work

[records:protected] => Array
(
[0] => DB2\DB2Record Object
(
[id:protected] => 1
[fields:protected] => Array
(
[0] => 1572875
[1] => General - %s
[2] => General
[3] => 0
)

)

[1] => DB2\DB2Record Object
(
[id:protected] => 2
[fields:protected] => Array
(
[0] => 1048635
[1] => Trade - %s
[2] => Trade
[3] => 0
)

) …

They are not aligned to 4 bytes, they are aligned to RecordSize from db2 header

Ok understand. Thanks you Shauren.

But now I have another question.

For the AreaTable.db2 I can read this header

DB2Header Object
(
[magic] => WDB5
[recordCount] => 5564
[fieldCount] => 23
[recordSize] => 56
[stringTableSize] => 158430
[tableHash] => 1918102339
[layoutHash] => 886938365
[minId] => 1
[maxId] => 8623
[locale] => 1
[copyTableSize] => 0
[flags] => 262144
[idIndex] => 0
)

You see the recordSize of 56 but if I count the bytes of the structure excepting the ID field, it will be 58 bytes long.

How is this possible?

Whenever you see uint32 near the end of structure its not uint32, its something called varint and its size will be determined by the field table block in header (https://github.com/TrinityCore/TrinityCore/blob/master/src/server/shared/DataStores/DB2StorageLoader.cpp#L197)

Ah I understand. Thank you very much for your help!