PathTableRecord::loadExtents()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 1
c 1
b 0
f 0
dl 0
loc 3
ccs 2
cts 2
cp 1
rs 10
cc 1
nc 1
nop 4
crap 1
1
<?php
2
3
declare(strict_types=1);
4
5
namespace PhpIso;
6
7
use PhpIso\Util\Buffer;
8
9
class PathTableRecord
10
{
11
    /**
12
     * The directory number
13
     */
14
    public int $dirNum;
15
16
    /**
17
     * The length of the Dir Identifier
18
     */
19
    public int $dirIdLen;
20
21
    /**
22
     * The length of the extended attributes
23
     */
24
    public int $extendedAttrLength;
25
26
    /**
27
     * The location of this "Path Table Record"
28
     */
29
    public int $location;
30
31
    /**
32
     * The parent's directory number
33
     */
34
    public int $parentDirNum;
35
36
    /**
37
     * The directory identifier.
38
     */
39
    public string $dirIdentifier;
40
41
    /**
42
     * Set the directory number
43
     */
44 4
    public function setDirectoryNumber(int $dirNum): void
45
    {
46 4
        $this->dirNum = $dirNum;
47
    }
48
49
    /**
50
     * Load the "Path Table Record" from buffer
51
     *
52
     * @param array<int, int> $bytes
53
     */
54 4
    public function init(array &$bytes, int &$offset, bool $supplementary = false): bool
55
    {
56 4
        $offsetTmp = $offset;
57
58 4
        $this->dirIdLen = $bytes[$offsetTmp];
59 4
        $offsetTmp++;
60
61 4
        if ($this->dirIdLen === 0) {
62 4
            return false;
63
        }
64
65 3
        $this->extendedAttrLength = $bytes[$offsetTmp];
66 3
        $offsetTmp++;
67 3
        $this->location = Buffer::readInt32($bytes, $offsetTmp);
68 3
        $this->parentDirNum = Buffer::readInt16($bytes, $offsetTmp);
69 3
        $this->dirIdentifier = Buffer::readAString($bytes, $this->dirIdLen, $offsetTmp);
70
71 3
        if ($this->dirIdLen % 2 !== 0) {
72 3
            $offsetTmp++;
73
        }
74
75 3
        $offset = $offsetTmp;
76 3
        return true;
77
    }
78
79
    /**
80
     * Load the "File Directory Descriptors"(extents) from ISO file
81
     *
82
     * @return array<int, FileDirectory>|false
83
     */
84 3
    public function loadExtents(IsoFile &$isoFile, int $blockSize, bool $supplementary = false, int $jolietLevel = 0): array|false
85
    {
86 3
        return FileDirectory::loadExtentsSt($isoFile, $blockSize, $this->location, $supplementary, $jolietLevel);
87
    }
88
89
    public function extractFile(IsoFile &$isoFile, int $blockSize, int $location, int $dataLength, string $destinationFile): void
90
    {
91
        $seekLocation = $location * $blockSize;
92
93
        if ($isoFile->seek($seekLocation, SEEK_SET) === -1) {
94
            throw new Exception('Failed to seek to location');
95
        }
96
97
        $writeHandle = fopen($destinationFile, 'wb');
98
99
        if ($writeHandle === false) {
100
            throw new Exception('Failed to open file for writing: ' . $destinationFile);
101
        }
102
103
        do {
104
            $readLength = 1024;
105
106
            if ($dataLength < $readLength) {
107
                $readLength = $dataLength;
108
            }
109
110
            $readResult = $isoFile->read($readLength);
111
112
            if ($readResult === false) {
113
                break;
114
            }
115
116
            $writeResult = fwrite($writeHandle, $readResult);
117
118
            if ($writeResult === false) {
119
                throw new Exception('Failed to write to file: ' . $destinationFile);
120
            }
121
122
            $dataLength -= $readLength;
123
        } while ($dataLength > 0);
124
125
        fclose($writeHandle);
126
    }
127
128
    /**
129
     * Build the full path of a PathTableRecord object based on it's parent(s)
130
     *
131
     * @param array<int, PathTableRecord> $pathTable
132
     *
133
     * @throws Exception
134
     */
135 5
    public function getFullPath(array $pathTable): string
136
    {
137 5
        if ($this->parentDirNum === 1) {
138 4
            if ($this->dirIdentifier === '') {
139 3
                return DIRECTORY_SEPARATOR;
140
            }
141
142 4
            return DIRECTORY_SEPARATOR . $this->dirIdentifier . DIRECTORY_SEPARATOR;
143
        }
144
145 3
        $path = $this->dirIdentifier;
146 3
        $used = $pathTable[$this->parentDirNum];
147
148 3
        $depth = 0;
149 3
        while (true) {
150 3
            $depth++;
151
152
            // max depth check
153 3
            if ($depth > 1000) {
154 1
                throw new Exception('Maximum depth of 1000 reached');
155
            }
156
157 3
            $path = $used->dirIdentifier . DIRECTORY_SEPARATOR . $path;
158
159 3
            if ($used->parentDirNum === 1) {
160 2
                break;
161
            }
162
163 2
            $used = $pathTable[$used->parentDirNum];
164
        }
165
166 2
        return DIRECTORY_SEPARATOR . $path . DIRECTORY_SEPARATOR;
167
    }
168
}
169