Issues (17)

src/Archive/AIDXReader.php (2 issues)

Labels
Severity
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
It seems like unpack('LNameOffset/LBlo...', fread($this->fh, 8)) can also be of type false; however, parameter $data of codemasher\WildstarDB\Ar...irectory::__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 ignore-type  annotation

70
			$dirs[$i] = new Directory(/** @scrutinizer ignore-type */ unpack('LNameOffset/LBlockIndex', fread($this->fh, 8)), $parent);
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 ignore-type  annotation

75
			$files[$i] = new File(/** @scrutinizer ignore-type */ unpack($this::AIDX_DATA, fread($this->fh, 56)), $parent);
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