codemasher /
wildstar-database
| 1 | <?php |
||||
| 2 | /** |
||||
| 3 | * Class AIDXReader |
||||
| 4 | * |
||||
| 5 | * @link https://github.com/Narthorn/Halon/blob/master/halon.py |
||||
| 6 | * |
||||
| 7 | * @filesource AIDXReader.php |
||||
| 8 | * @created 06.01.2019 |
||||
| 9 | * @package codemasher\WildstarDB\Archive |
||||
| 10 | * @author smiley <[email protected]> |
||||
| 11 | * @copyright 2019 smiley |
||||
| 12 | * @license MIT |
||||
| 13 | */ |
||||
| 14 | |||||
| 15 | namespace codemasher\WildstarDB\Archive; |
||||
| 16 | |||||
| 17 | use codemasher\WildstarDB\WSDBException; |
||||
| 18 | |||||
| 19 | use function array_fill, array_merge, fread, fseek, ftell, strpos, substr, unpack; |
||||
| 20 | |||||
| 21 | /** |
||||
| 22 | * @property array $dirs |
||||
| 23 | */ |
||||
| 24 | final class AIDXReader extends PACKReaderAbstract{ |
||||
| 25 | |||||
| 26 | private const AIDX_ROOT = 'a4ArchiveType/LVersion/LBuildnumber/LIndex'; |
||||
| 27 | private const AIDX_DATA = 'LNameOffset/LFlags/QFiletime/QSizeUncompressed/QSizeCompressed/a20Hash/x4'; |
||||
| 28 | |||||
| 29 | /** @var array */ |
||||
| 30 | protected $dirs; |
||||
| 31 | |||||
| 32 | /** |
||||
| 33 | * @inheritDoc |
||||
| 34 | */ |
||||
| 35 | protected function readData():void{ |
||||
| 36 | |||||
| 37 | // get the root info block of the AIDX file (4+4+4+4 = 16 bytes) |
||||
| 38 | $rootInfo = unpack($this::AIDX_ROOT, fread($this->fh, 16)); |
||||
| 39 | |||||
| 40 | if($rootInfo['ArchiveType'] !== "\x58\x44\x49\x41"){ // XDIA |
||||
| 41 | throw new WSDBException('invalid AIDX'); |
||||
| 42 | } |
||||
| 43 | |||||
| 44 | $this->dirs = []; |
||||
| 45 | $this->data = $this->getBlock($this->blocktable[$rootInfo['Index']]); |
||||
| 46 | } |
||||
| 47 | |||||
| 48 | /** |
||||
| 49 | * @param array $blockInfo |
||||
| 50 | * @param string $parent |
||||
| 51 | * |
||||
| 52 | * @return array |
||||
| 53 | */ |
||||
| 54 | private function getBlock(array $blockInfo, string $parent = ''):array{ |
||||
| 55 | |||||
| 56 | // add the current path to the collection |
||||
| 57 | $this->dirs[] = $parent; |
||||
| 58 | |||||
| 59 | // find the info block |
||||
| 60 | fseek($this->fh, $blockInfo['Offset']); |
||||
| 61 | |||||
| 62 | // get the count of directories and files in that block (4+4 = 8 bytes) |
||||
| 63 | $n = unpack('Ldirs/Lfiles', fread($this->fh, 8)); |
||||
| 64 | |||||
| 65 | $dirs = array_fill(0, $n['dirs'], null); |
||||
| 66 | $files = array_fill(0, $n['files'], null); |
||||
| 67 | |||||
| 68 | // create a directory object for each dir (4+4 = 8 bytes) |
||||
| 69 | foreach($dirs as $i => $_){ |
||||
| 70 | $dirs[$i] = new Directory(unpack('LNameOffset/LBlockIndex', fread($this->fh, 8)), $parent); |
||||
|
0 ignored issues
–
show
Bug
introduced
by
Loading history...
|
|||||
| 71 | } |
||||
| 72 | |||||
| 73 | // create a file object for each file (4+4+8+8+8+20+4 = 56 bytes) |
||||
| 74 | foreach($files as $i => $_){ |
||||
| 75 | $files[$i] = new File(unpack($this::AIDX_DATA, fread($this->fh, 56)), $parent); |
||||
|
0 ignored issues
–
show
It seems like
unpack($this::AIDX_DATA, fread($this->fh, 56)) can also be of type false; however, parameter $data of codemasher\WildstarDB\Archive\File::__construct() does only seem to accept array, maybe add an additional type check?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
Loading history...
|
|||||
| 76 | } |
||||
| 77 | |||||
| 78 | // read the list of names from the remaining data |
||||
| 79 | $names = fread($this->fh, $blockInfo['Size'] - (ftell($this->fh) - $blockInfo['Offset'])); |
||||
| 80 | |||||
| 81 | $getname = function(ItemAbstract $e) use ($names){ |
||||
| 82 | return '/'.substr($names, $e->NameOffset, strpos($names, "\x00", $e->NameOffset) - $e->NameOffset); |
||||
| 83 | }; |
||||
| 84 | |||||
| 85 | // apply the names to each object in the block |
||||
| 86 | foreach($dirs as $i => $e){ |
||||
| 87 | $dirs[$i]->Name = $getname($e); |
||||
| 88 | } |
||||
| 89 | |||||
| 90 | foreach($files as $i => $e){ |
||||
| 91 | $files[$i]->Name = $getname($e); |
||||
| 92 | } |
||||
| 93 | |||||
| 94 | // loop through the directory stucture recursively and add the block data |
||||
| 95 | foreach($dirs as $i => $info){ |
||||
| 96 | if(isset($this->blocktable[$info->BlockIndex])){ |
||||
| 97 | $dirs[$i]->Content = $this->getBlock($this->blocktable[$info->BlockIndex], $parent.$info->Name); |
||||
| 98 | } |
||||
| 99 | } |
||||
| 100 | |||||
| 101 | return array_merge($dirs, $files); |
||||
| 102 | } |
||||
| 103 | |||||
| 104 | } |
||||
| 105 |