FileDirectory::isThis()   A
last analyzed

Complexity

Conditions 2
Paths 2

Size

Total Lines 7
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 2.0625

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 3
c 1
b 0
f 0
dl 0
loc 7
ccs 3
cts 4
cp 0.75
rs 10
cc 2
nc 2
nop 0
crap 2.0625
1
<?php
2
3
declare(strict_types=1);
4
5
namespace PhpIso;
6
7
use Carbon\Carbon;
8
use PhpIso\Util\Buffer;
9
use PhpIso\Util\IsoDate;
10
11
class FileDirectory
12
{
13
    /**
14
     * If set to ZERO, shall mean that the existence of the file shall be made known to the
15
     * user upon an inquiry by the user.
16
     * If set to ONE, shall mean that the existence of the file need not be made known to
17
     * the user.
18
     */
19
    public const FILE_MODE_HIDDEN = 0x01;
20
21
    /**
22
     * If set to ZERO, shall mean that the Directory Record does not identify a directory.
23
     * If set to ONE, shall mean that the Directory Record identifies a directory.
24
     */
25
    public const FILE_MODE_DIRECTORY = 0x02;
26
27
    /**
28
     * If set to ZERO, shall mean that the file is not an Associated File.
29
     * If set to ONE, shall mean that the file is an Associated File.
30
     */
31
    public const FILE_MODE_ASSOCIATED = 0x04;
32
33
    /**
34
     * If set to ZERO, shall mean that the structure of the information in the file is not
35
     * specified by the Record Format field of any associated Extended Attribute Record (see 9.5.8).
36
     * If set to ONE, shall mean that the structure of the information in the file has a
37
     * record format specified by a number other than zero in the Record Format Field of
38
     * the Extended Attribute Record (see 9.5.8).
39
     */
40
    public const FILE_MODE_RECORD = 0x08;
41
    /**
42
     * If set to ZERO, shall mean that
43
     * - an Owner Identification and a Group Identification are not specified for the file (see 9.5.1 and 9.5.2);
44
     * - any user may read or execute the file (see 9.5.3). If set to ONE, shall mean that
45
     * - an Owner Identification and a Group Identification are specified for the file (see 9.5.1 and 9.5.2);
46
     * - at least one of the even-numbered bits or bit 0 in the Permissions field of the associated Extended Attribute Record is set to ONE (see 9.5.3).
47
     */
48
    public const FILE_MODE_PROTECTED = 0x10;
49
    /**
50
     * If set to ZERO, shall mean that this is the final Directory Record for the file.
51
     * If set to ONE, shall mean that this is not the final Directory Record for the file.
52
     */
53
    public const FILE_MODE_MULTI_EXTENT = 0x80;
54
55
    /**
56
     * The length of the "Directory Record"
57
     */
58
    public int $dirRecLength = 0;
59
60
    /**
61
     * The length of the "Directory Record" extended attribute record
62
     */
63
    public int $extendedAttrRecordLength;
64
65
    /**
66
     * Location of extents
67
     */
68
    public int $location;
69
70
    /**
71
     * The length of the data (the content for a file, the "child file & folder for a directory...
72
     */
73
    public int $dataLength;
74
75
    /**
76
     * The recording date
77
     */
78
    public ?Carbon $recordingDate = null;
79
80
    /**
81
     * File (or folder) flags.
82
     */
83
    public int $flags;
84
85
    /**
86
     * The File Unit Size
87
     */
88
    public int $fileUnitSize;
89
90
    /**
91
     * The Interleave Gap Size
92
     */
93
    public int $interleaveGapSize;
94
95
    /**
96
     * The ordinal number of the volume in the Volume Set
97
     */
98
    public int $volumeSeqNum;
99
100
    /**
101
     * The length of the file identifier
102
     */
103
    public int $fileIdLength;
104
105
    /**
106
     * The file identifier
107
     */
108
    public string $fileId;
109
110
    public int $jolietLevel = 0;
111
112
    /**
113
     * Load the "Directory Record" from buffer
114
     *
115
     * @param array<int, int> $buffer
116
     */
117 19
    public function init(array &$buffer, int &$offset, bool $supplementary = false): bool
118
    {
119 19
        $tmp = $offset;
120
121 19
        $this->dirRecLength = $buffer[$tmp];
122 19
        $tmp++;
123 19
        if ($this->dirRecLength === 0) {
124 7
            return false;
125
        }
126
127 15
        $this->extendedAttrRecordLength = $buffer[$tmp];
128 15
        $tmp++;
129
130 15
        $this->location = Buffer::readBBO($buffer, 8, $tmp);
131 15
        $this->dataLength = Buffer::readBBO($buffer, 8, $tmp);
132
133 15
        $this->recordingDate = IsoDate::init7($buffer, $tmp);
134
135 15
        $this->flags = $buffer[$tmp];
136 15
        $tmp++;
137 15
        $this->fileUnitSize = $buffer[$tmp];
138 15
        $tmp++;
139 15
        $this->interleaveGapSize = $buffer[$tmp];
140 15
        $tmp++;
141
142 15
        $this->volumeSeqNum = Buffer::readBBO($buffer, 4, $tmp);
143
144 15
        $this->fileIdLength = $buffer[$tmp];
145 15
        $tmp++;
146
147 15
        if ($this->fileIdLength === 1 && $buffer[$tmp] === 0) {
148 15
            $this->fileId = '.';
149 15
            $tmp++;
150 3
        } elseif ($this->fileIdLength === 1 && $buffer[$tmp] === 1) {
151 3
            $this->fileId = '..';
152 3
            $tmp++;
153
        } else {
154 3
            if ($this->jolietLevel === 3) {
155
                $this->fileId = Buffer::readDString($buffer, $this->fileIdLength, $tmp, $supplementary);
156
            } else {
157 3
                $this->fileId = Buffer::readAString($buffer, $this->fileIdLength, $tmp, $supplementary);
158
            }
159
160 3
            $pos = strpos($this->fileId, ';1');
161 3
            if ($pos !== false && $pos === strlen($this->fileId) - 2) {
162 3
                $this->fileId = substr($this->fileId, 0, strlen($this->fileId) - 2);
163
            }
164
165 3
            $this->fileId = trim($this->fileId);
166
        }
167
168 15
        $offset += $this->dirRecLength;
169 15
        return true;
170
    }
171
172
    /**
173
     * Test if the "Directory Record" is hidden
174
     */
175 2
    public function isHidden(): bool
176
    {
177 2
        return ($this->flags & self::FILE_MODE_HIDDEN) === self::FILE_MODE_HIDDEN;
178
    }
179
180
    /**
181
     * Test if the "Directory Record" is directory
182
     */
183 4
    public function isDirectory(): bool
184
    {
185 4
        return ($this->flags & self::FILE_MODE_DIRECTORY) === self::FILE_MODE_DIRECTORY;
186
    }
187
188
    /**
189
     * Test if the "Directory Record" is associated
190
     */
191 2
    public function isAssociated(): bool
192
    {
193 2
        return ($this->flags & self::FILE_MODE_ASSOCIATED) === self::FILE_MODE_ASSOCIATED;
194
    }
195
196
    /**
197
     * Test if the "Directory Record" is record
198
     */
199 2
    public function isRecord(): bool
200
    {
201 2
        return ($this->flags & self::FILE_MODE_RECORD) === self::FILE_MODE_RECORD;
202
    }
203
204
    /**
205
     * Test if the "Directory Record" is protected
206
     */
207 2
    public function isProtected(): bool
208
    {
209 2
        return ($this->flags & self::FILE_MODE_PROTECTED) === self::FILE_MODE_PROTECTED;
210
    }
211
212
    /**
213
     * Test if the "Directory Record" is a multi-extent
214
     */
215 2
    public function isMultiExtent(): bool
216
    {
217 2
        return ($this->flags & self::FILE_MODE_MULTI_EXTENT) === self::FILE_MODE_MULTI_EXTENT;
218
    }
219
220
    /**
221
     * Test if the "Directory Record" is a "node" to itself
222
     */
223 2
    public function isThis(): bool
224
    {
225 2
        if ($this->fileIdLength > 1) {
226
            return false;
227
        }
228
229 2
        return $this->fileId === '.';
230
    }
231
232
    /**
233
     * Test if the "Directory Record" is a "node" to its parent
234
     */
235 2
    public function isParent(): bool
236
    {
237 2
        if ($this->fileIdLength > 1) {
238
            return false;
239
        }
240
241 2
        return $this->fileId === '..';
242
    }
243
244
    /**
245
     * Load the "File Directory Descriptors" (extents) from ISO file
246
     *
247
     * @return array<int, FileDirectory>|false
248
     */
249
    public function loadExtents(IsoFile $isoFile, int $blockSize, bool $supplementary = false, int $jolietLevel = 0): array|false
250
    {
251
        return self::loadExtentsSt($isoFile, $blockSize, $this->location, $supplementary, $jolietLevel);
252
    }
253
254
    /**
255
     * Load the "File Directory Descriptors"(extents) from ISO file
256
     *
257
     * @return array<int, FileDirectory>|false
258
     */
259 4
    public static function loadExtentsSt(IsoFile $isoFile, int $blockSize, int $location, bool $supplementary = false, int $jolietLevel = 0): array|false
260
    {
261 4
        if ($isoFile->seek($location * $blockSize, SEEK_SET) === -1) {
262
            return false;
263
        }
264
265 4
        $string = $isoFile->read(4096);
266 4
        if ($string === false) {
267
            return false;
268
        }
269
270
        /** @var array<int, int>|false $bytes */
271 4
        $bytes = unpack('C*', $string);
272
273 4
        if ($bytes === false) {
274
            return false;
275
        }
276
277 4
        $offset = 1;
278 4
        $fdDesc = new self();
279 4
        $fdDesc->jolietLevel = $jolietLevel;
280 4
        $extents = [];
281
282 4
        while ($fdDesc->init($bytes, $offset, $supplementary) !== false) {
283 3
            $extents[] = $fdDesc;
284 3
            $fdDesc = new self();
285 3
            $fdDesc->jolietLevel = $jolietLevel;
286
        }
287
288 4
        return $extents;
289
    }
290
}
291