Iso::getFileNames()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
cc 1
eloc 1
nc 1
nop 0
dl 0
loc 3
ccs 0
cts 0
cp 0
crap 2
rs 10
c 0
b 0
f 0
1
<?php
2
namespace wapmorgan\UnifiedArchive\Drivers;
3
4
use wapmorgan\UnifiedArchive\Abilities;
5
use wapmorgan\UnifiedArchive\ArchiveEntry;
6
use wapmorgan\UnifiedArchive\ArchiveInformation;
7
use wapmorgan\UnifiedArchive\Drivers\Basic\BasicPureDriver;
8
use wapmorgan\UnifiedArchive\Exceptions\UnsupportedOperationException;
9
use wapmorgan\UnifiedArchive\Formats;
10
11
class Iso extends BasicPureDriver
12
{
13
    const PACKAGE_NAME = 'phpclasses/php-iso-file';
14
    const MAIN_CLASS = '\CISOFile';
15
16
    /** @var \CISOFile */
0 ignored issues
show
Bug introduced by
The type CISOFile was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
17
    protected $iso;
18
19
    /** @var array List of files */
20
    protected $files = [];
21
22
    /** @var array  */
23
    protected $filesData = [];
24
25
    /** @var int */
26
    protected $filesSize = 0;
27
28
    /** @var null|int Size of block in ISO. Used to find real position of file in ISO */
29
    protected $blockSize;
30 1
31
    /**
32
     * @inheritDoc
33 1
     */
34
    public static function getDescription()
35
    {
36
        return 'iso archives reader';
37
    }
38
39
    /**
40
     * @return array
41 1
     */
42
    public static function getFormats()
43
    {
44 1
        return [
45 1
            Formats::ISO,
46
        ];
47
    }
48
49
    /**
50
     * @param $format
51
     * @return array
52
     */
53
    public static function getFormatAbilities($format)
54
    {
55
        if (!static::isInstalled()) {
56
            return [];
57
        }
58
59
        switch ($format) {
60
            case Formats::ISO:
61
                return [
62
                    Abilities::OPEN,
63
                    Abilities::EXTRACT_CONTENT,
64
                ];
65
        }
66
    }
67
68
    /**
69
     * @inheritDoc
70
     * @throws UnsupportedOperationException
71
     */
72
    public function __construct($archiveFileName, $format, $password = null)
73
    {
74
        parent::__construct($archiveFileName, $format);
75
        $this->open($archiveFileName);
76
        if ($password !== null)
77
            throw new UnsupportedOperationException('Iso archive does not support password!');
78
    }
79
80
    /**
81
     * Iso format destructor
82
     */
83
    public function __destruct()
84
    {
85
        $this->iso->close();
86
    }
87
88
    /**
89
     * @param $archiveFileName
90
     */
91
    protected function open($archiveFileName)
92
    {
93
        // load php-iso-files
94
        $this->iso = new \CISOFile;
95
        $this->iso->open($archiveFileName);
96
        $this->iso->ISOInit();
97
98
        /** @var \CVolumeDescriptor $usedDesc */
99
        $usedDesc = $this->iso->GetDescriptor(SUPPLEMENTARY_VOLUME_DESC);
0 ignored issues
show
Bug introduced by
The constant wapmorgan\UnifiedArchive...PPLEMENTARY_VOLUME_DESC was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
100
        if (!$usedDesc)
0 ignored issues
show
introduced by
$usedDesc is of type CVolumeDescriptor, thus it always evaluated to true.
Loading history...
101
            $usedDesc = $this->iso->GetDescriptor(PRIMARY_VOLUME_DESC);
0 ignored issues
show
Bug introduced by
The constant wapmorgan\UnifiedArchive...ers\PRIMARY_VOLUME_DESC was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
102
        $this->blockSize = $usedDesc->iBlockSize;
103
        $directories = $usedDesc->LoadMPathTable($this->iso);
104
        // iterate over all directories
105
        /** @var \CPathTableRecord $Directory */
106
        foreach ($directories as $Directory) {
107
            $directory = $Directory->GetFullPath($directories);
108
            // ? here is for some unexpected problem with ? appearing
109
            $directory = trim($directory, '/?');
110
            if ($directory != '') {
111
                $directory .= '/';
112
//                $this->files[$Directory->Location] = $directory;
113
            }
114
//            $this->isoCatalogsStructure[$Directory->Location]
115
//                = $directory;
116
117
            /** @var \CFileDirDescriptors[] $files */
118
            $files = $Directory->LoadExtents($this->iso,
119
                $usedDesc->iBlockSize, true);
120
            if ($files) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $files of type CFileDirDescriptors[] is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
121
                /** @var \CFileDirDescriptors $file */
122
                foreach ($files as $file) {
123
                    if (in_array($file->strd_FileId, ['.', '..']) || $file->IsDirectory())
124
                        continue;
125
                    $this->files[$file->Location] = $directory.$file->strd_FileId;
126
                    $this->filesSize += $file->DataLen;
127
128
                    $this->filesData[$directory . $file->strd_FileId] =
129
                        [
130
                            'size' => $file->DataLen,
131
                            'mtime' =>
132
                                strtotime((string)$file->isoRecDate),
133
                        ];
134
                }
135
            }
136
            // break;
137
        }
138
    }
139
140
    /**
141
     * @return ArchiveInformation
142
     */
143
    public function getArchiveInformation()
144
    {
145
        $information = new ArchiveInformation();
146
        $information->files = array_values($this->files);
147
        $information->compressedFilesSize = $information->uncompressedFilesSize = $this->filesSize;
148
        return $information;
149
    }
150
151
    /**
152
     * @return array
153
     */
154
    public function getFileNames()
155
    {
156
        return array_values($this->files);
157
    }
158
159
    /**
160
     * @param string $fileName
161
     *
162
     * @return bool
163
     */
164
    public function isFileExists($fileName)
165
    {
166
        return array_key_exists($fileName, $this->filesData);
167
    }
168
169
    /**
170
     * @param string $fileName
171
     *
172
     * @return ArchiveEntry|false
173
     */
174
    public function getFileData($fileName)
175
    {
176
        if (!isset($this->filesData[$fileName]))
177
            return false;
178
179
        return new ArchiveEntry(
180
            $fileName,
181
            $this->filesData[$fileName]['size'],
182
            $this->filesData[$fileName]['size'],
183
            $this->filesData[$fileName]['mtime'],
184
            false
185
        );
186
    }
187
188
    /**
189
     * @param string $fileName
190
     *
191
     * @return string|false
192
     */
193
    public function getFileContent($fileName)
194
    {
195
        $data = $this->prepareForFileExtracting($fileName);
196
        return $this->iso->Read($data['size']);
197
    }
198
199
    /**
200
     * @param string $fileName
201
     *
202
     * @return bool|resource|string
203
     */
204
    public function getFileStream($fileName)
205
    {
206
        $data = $this->prepareForFileExtracting($fileName);
207
        return self::wrapStringInStream($this->iso->Read($data['size']));
208
    }
209
210
    /**
211
     * @param string $fileName
212
     * @return array
213
     */
214
    protected function prepareForFileExtracting($fileName)
215
    {
216
        $Location = array_search($fileName, $this->files, true);
217
        if (!isset($this->filesData[$fileName])) return false;
0 ignored issues
show
Bug Best Practice introduced by
The expression return false returns the type false which is incompatible with the documented return type array.
Loading history...
218
        $data = $this->filesData[$fileName];
219
        $Location_Real = $Location * $this->blockSize;
220
        if ($this->iso->Seek($Location_Real, SEEK_SET) === false)
221
            return false;
0 ignored issues
show
Bug Best Practice introduced by
The expression return false returns the type false which is incompatible with the documented return type array.
Loading history...
222
        return $data;
223
    }
224
225
    /**
226
     * @param string $outputFolder
227
     * @param array $files
228
     * @return int
229
     * @throws UnsupportedOperationException
230
     */
231
    public function extractFiles($outputFolder, array $files)
232
    {
233
        foreach ($files as $file) {
234
            $destination_file = rtrim($outputFolder, '/'). '/' . ltrim($file, '/');
235
            $destination_dir = dirname($destination_file);
236
237
            if (!empty($destination_dir)) {
238
                if (!is_dir($destination_dir)) {
239
                    mkdir($destination_dir, 0777, true);
240
                } else {
241
                    if (!is_writable($destination_dir)) {
242
                        chmod($destination_dir, 0777);
243
                    }
244
                }
245
            }
246
247
            file_put_contents($destination_file, $this->getFileContent($file));
248
        }
249
        return count($files);
250
    }
251
252
    /**
253
     * @param string $outputFolder
254
     * @return int
255
     * @throws UnsupportedOperationException
256
     * @todo Implement extracting with reading & writing to FS
257
     */
258
    public function extractArchive($outputFolder)
259
    {
260
        return $this->extractFiles($outputFolder, $this->files);
261
    }
262
}
263