IsoFile::processFile()   C
last analyzed

Complexity

Conditions 13
Paths 18

Size

Total Lines 52
Code Lines 28

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 23
CRAP Score 13.5489

Importance

Changes 0
Metric Value
eloc 28
c 0
b 0
f 0
dl 0
loc 52
ccs 23
cts 27
cp 0.8519
rs 6.6166
cc 13
nc 18
nop 0
crap 13.5489

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
declare(strict_types=1);
4
5
namespace PhpIso;
6
7
use PhpIso\Descriptor\Reader;
8
use PhpIso\Descriptor\Type;
9
use PhpIso\Descriptor\UdfDescriptor;
10
use PhpIso\Descriptor\UdfTeaDescriptor;
11
12
class IsoFile
13
{
14
    /**
15
     * @var array<int, Descriptor>
16
     */
17
    public array $descriptors = [];
18
19
    /**
20
     * @var ?resource
21
     */
22
    protected mixed $fileHandle;
23
24 21
    public function __construct(protected string $isoFilePath)
25
    {
26 21
        $this->openFile();
27
28 20
        $this->processFile();
29
    }
30
31 20
    public function __destruct()
32
    {
33 20
        $this->closeFile();
34
    }
35
36 20
    public function seek(int $offset, int $whence = SEEK_SET): int
37
    {
38 20
        if ($this->fileHandle === null) {
39 1
            return -1;
40
        }
41
42 20
        return fseek($this->fileHandle, $offset, $whence);
43
    }
44
45 20
    public function read(int $length): string|false
46
    {
47 20
        if ($length < 1) {
48 1
            return false;
49
        }
50
51 20
        if ($this->fileHandle === null) {
52 1
            return false;
53
        }
54
55 20
        return fread($this->fileHandle, $length);
56
    }
57
58 21
    public function openFile(): void
59
    {
60 21
        if (file_exists($this->isoFilePath) === false) {
61 1
            throw new Exception('File does not exist: ' . $this->isoFilePath);
62
        }
63
64 20
        $fileHandle = fopen($this->isoFilePath, 'rb');
65
66 20
        if ($fileHandle === false) {
67
            throw new Exception('Cannot open file for reading: ' . $this->isoFilePath);
68
        }
69
70 20
        $this->fileHandle = $fileHandle;
71
    }
72
73 19
    public function closeFile(): void
74
    {
75 19
        if ($this->fileHandle === null) {
76 1
            return;
77
        }
78
79 19
        fclose($this->fileHandle);
80 19
        $this->fileHandle = null;
81
    }
82
83 20
    protected function processFile(): bool
84
    {
85 20
        if ($this->seek(16 * 2048, SEEK_SET) === -1) {
86
            return false;
87
        }
88
89 20
        $reader = new Reader($this);
90
91 20
        $foundTerminator = false;
92 20
        while (true) {
93
            try {
94 20
                $descriptor = $reader->read();
95
96 19
                if ($descriptor === null) {
97
                    throw new Exception('Finished reading');
98
                }
99
100 19
                if (isset($this->descriptors[$descriptor->getType()]) && ! ($descriptor instanceof UdfDescriptor)) {
101 2
                    throw new Exception('Descriptor ' . $descriptor->getType() . ' already exists');
102
                }
103
104 19
                $this->descriptors[$descriptor->getType()] = $descriptor;
105 10
            } catch (Exception $ex) {
106 10
                if ($foundTerminator) {
107 9
                    break;
108
                }
109 1
                throw $ex;
110
            }
111
112
            // If it's a UDF descriptor, handle it separately
113 19
            if ($descriptor instanceof UdfDescriptor) {
114 10
                if ($descriptor instanceof UdfTeaDescriptor) {
115 10
                    break; // Stop at Terminating Extended Area Descriptor
116
                }
117
            } else {
118 17
                if ($foundTerminator) {
119
                    break;
120
                }
121
            }
122
123 19
            if ($descriptor->getType() === Type::TERMINATOR_DESC) {
124 17
                if ($foundTerminator) {
125
                    break;
126
                }
127
128 17
                $foundTerminator = true;
129
                // Keep going if UDF might still be present
130 17
                continue;
131
            }
132
        }
133
134 19
        return count($this->descriptors) > 0;
135
    }
136
}
137