Total Complexity | 56 |
Total Lines | 268 |
Duplicated Lines | 0 % |
Changes | 1 | ||
Bugs | 0 | Features | 0 |
Complex classes like IsoTool often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.
Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.
While breaking up the class, it is a good idea to analyze how other classes use IsoTool, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
19 | class IsoTool |
||
20 | { |
||
21 | public function run(): void |
||
22 | { |
||
23 | $options = $this->parseCliArgs(); |
||
24 | |||
25 | if ($options === []) { |
||
26 | $this->displayHelp(); |
||
27 | exit(1); |
||
28 | } |
||
29 | |||
30 | $fileValue = $options['file'] ?? $options['f']; |
||
31 | |||
32 | $file = ''; |
||
33 | |||
34 | if (is_array($fileValue)) { |
||
35 | $file = current($fileValue); |
||
36 | } elseif (is_string($fileValue)) { |
||
37 | $file = $fileValue; |
||
38 | } |
||
39 | |||
40 | if (! is_string($file) || $file === '') { |
||
41 | $this->displayError('Invalid value for file received'); |
||
42 | exit(2); |
||
43 | } |
||
44 | |||
45 | $extractPath = ''; |
||
46 | if (isset($options['extract']) && is_string($options['extract'])) { |
||
47 | $extractPath = $options['extract']; |
||
48 | } elseif (isset($options['x']) && is_string($options['x'])) { |
||
49 | $extractPath = $options['x']; |
||
50 | } |
||
51 | |||
52 | echo 'Input ISO file: ' . $file . PHP_EOL; |
||
53 | |||
54 | try { |
||
55 | $this->checkIsoFile($file); |
||
56 | |||
57 | if ($extractPath !== '') { |
||
58 | $this->extractAction($file, $extractPath); |
||
59 | } else { |
||
60 | $this->infoAction($file); |
||
61 | } |
||
62 | } catch (Throwable $ex) { |
||
63 | $this->displayError($ex->getMessage()); |
||
64 | exit(3); |
||
65 | } |
||
66 | } |
||
67 | |||
68 | protected function checkIsoFile(string $file): void |
||
69 | { |
||
70 | if (! file_exists($file)) { |
||
71 | throw new Exception('ISO file does not exist.'); |
||
72 | } |
||
73 | |||
74 | if (! is_file($file)) { |
||
75 | throw new Exception('Path is not a valid file.'); |
||
76 | } |
||
77 | } |
||
78 | |||
79 | protected function infoAction(string $file): void |
||
80 | { |
||
81 | $isoFile = new IsoFile($file); |
||
82 | |||
83 | echo PHP_EOL; |
||
84 | |||
85 | echo 'Number of descriptors: ' . count($isoFile->descriptors) . PHP_EOL; |
||
86 | |||
87 | /** @var Descriptor $descriptor */ |
||
88 | foreach ($isoFile->descriptors as $descriptor) { |
||
89 | echo ' - ' . $descriptor->name . PHP_EOL; |
||
90 | |||
91 | if ($descriptor instanceof Volume) { |
||
92 | $this->infoVolume($descriptor); |
||
93 | $this->displayFiles($descriptor, $isoFile); |
||
94 | } elseif ($descriptor instanceof Boot) { |
||
95 | $this->infoBoot($descriptor); |
||
96 | } |
||
97 | |||
98 | echo PHP_EOL; |
||
99 | } |
||
100 | } |
||
101 | |||
102 | protected function extractAction(string $file, string $extractPath): void |
||
103 | { |
||
104 | if (! is_dir($extractPath)) { |
||
105 | $mkdirResult = mkdir($extractPath, 0777, true); |
||
106 | |||
107 | if ($mkdirResult === false) { |
||
108 | throw new Exception('Failed to create extract output directory: ' . $extractPath); |
||
109 | } |
||
110 | } |
||
111 | |||
112 | $isoFile = new IsoFile($file); |
||
113 | |||
114 | echo 'Extract ISO file to: ' . $extractPath . PHP_EOL; |
||
115 | |||
116 | if (isset($isoFile->descriptors[Type::SUPPLEMENTARY_VOLUME_DESC]) && $isoFile->descriptors[Type::SUPPLEMENTARY_VOLUME_DESC] instanceof SupplementaryVolume) { |
||
117 | $this->extractFiles($isoFile->descriptors[Type::SUPPLEMENTARY_VOLUME_DESC], $isoFile, $extractPath); |
||
118 | } elseif (isset($isoFile->descriptors[Type::PRIMARY_VOLUME_DESC]) && $isoFile->descriptors[Type::PRIMARY_VOLUME_DESC] instanceof PrimaryVolume) { |
||
119 | $this->extractFiles($isoFile->descriptors[Type::PRIMARY_VOLUME_DESC], $isoFile, $extractPath); |
||
120 | } |
||
121 | |||
122 | echo 'Extract finished!' . PHP_EOL; |
||
123 | } |
||
124 | |||
125 | protected function extractFiles(Volume $volumeDescriptor, IsoFile $isoFile, string $destinationDir): void |
||
126 | { |
||
127 | $pathTable = $volumeDescriptor->loadTable($isoFile); |
||
128 | |||
129 | if ($pathTable === null) { |
||
130 | return; |
||
131 | } |
||
132 | |||
133 | $destinationDir = rtrim($destinationDir, DIRECTORY_SEPARATOR); |
||
134 | |||
135 | /** @var PathTableRecord $pathRecord */ |
||
136 | foreach ($pathTable as $pathRecord) { |
||
137 | // check extents |
||
138 | $extents = $pathRecord->loadExtents($isoFile, $volumeDescriptor->blockSize, ($volumeDescriptor->getType() === Type::SUPPLEMENTARY_VOLUME_DESC), $volumeDescriptor->jolietLevel); |
||
139 | |||
140 | if ($extents !== false) { |
||
141 | /** @var FileDirectory $extentRecord */ |
||
142 | foreach ($extents as $extentRecord) { |
||
143 | $path = $extentRecord->fileId; |
||
144 | |||
145 | if (! $extentRecord->isThis() && ! $extentRecord->isParent()) { |
||
146 | $fullPath = $destinationDir . $pathRecord->getFullPath($pathTable) . $path; |
||
147 | if ($extentRecord->isDirectory()) { |
||
148 | $fullPath .= DIRECTORY_SEPARATOR; |
||
149 | } |
||
150 | |||
151 | if (! $extentRecord->isDirectory()) { |
||
152 | $location = $extentRecord->location; |
||
153 | $dataLength = $extentRecord->dataLength; |
||
154 | echo $fullPath . ' (location: ' . $location . ') (length: ' . $dataLength . ')' . PHP_EOL; |
||
155 | |||
156 | $dirPath = dirname($fullPath); |
||
157 | if (! is_dir($dirPath)) { |
||
158 | if (mkdir($dirPath, 0777, true) === false) { |
||
159 | throw new Exception('Failed to create directory: ' . $dirPath); |
||
160 | } |
||
161 | } |
||
162 | |||
163 | $pathRecord->extractFile($isoFile, $volumeDescriptor->blockSize, $location, $dataLength, $fullPath); |
||
164 | } else { |
||
165 | if (! is_dir($fullPath)) { |
||
166 | if (mkdir($fullPath, 0777, true) === false) { |
||
167 | throw new Exception('Failed to create directory: ' . $fullPath); |
||
168 | } |
||
169 | } |
||
170 | } |
||
171 | } |
||
172 | } |
||
173 | } |
||
174 | } |
||
175 | } |
||
176 | |||
177 | protected function infoVolume(Volume $volumeDescriptor): void |
||
178 | { |
||
179 | echo ' - System ID: ' . $volumeDescriptor->systemId . PHP_EOL; |
||
180 | echo ' - Volume ID: ' . $volumeDescriptor->volumeId . PHP_EOL; |
||
181 | echo ' - App ID: ' . $volumeDescriptor->appId . PHP_EOL; |
||
182 | echo ' - File Structure Version: ' . $volumeDescriptor->fileStructureVersion . PHP_EOL; |
||
183 | echo ' - Volume Space Size: ' . $volumeDescriptor->volumeSpaceSize . PHP_EOL; |
||
184 | echo ' - Volume Set Size: ' . $volumeDescriptor->volumeSetSize . PHP_EOL; |
||
185 | echo ' - Volume SeqNum: ' . $volumeDescriptor->volumeSeqNum . PHP_EOL; |
||
186 | echo ' - Block size: ' . $volumeDescriptor->blockSize . PHP_EOL; |
||
187 | echo ' - Volume Set ID: ' . $volumeDescriptor->volumeSetId . PHP_EOL; |
||
188 | echo ' - Publisher ID: ' . $volumeDescriptor->publisherId . PHP_EOL; |
||
189 | echo ' - Preparer ID: ' . $volumeDescriptor->preparerId . PHP_EOL; |
||
190 | echo ' - Copyright File ID: ' . $volumeDescriptor->copyrightFileId . PHP_EOL; |
||
191 | echo ' - Abstract File ID: ' . $volumeDescriptor->abstractFileId . PHP_EOL; |
||
192 | echo ' - Bibliographic File ID: ' . $volumeDescriptor->bibliographicFileId . PHP_EOL; |
||
193 | echo ' - Creation Date: ' . $volumeDescriptor->creationDate?->toDateTimeString() . PHP_EOL; |
||
194 | echo ' - Modification Date: ' . $volumeDescriptor->modificationDate?->toDateTimeString() . PHP_EOL; |
||
195 | echo ' - Expiration Date: ' . $volumeDescriptor->expirationDate?->toDateTimeString() . PHP_EOL; |
||
196 | echo ' - Effective Date: ' . $volumeDescriptor->effectiveDate?->toDateTimeString() . PHP_EOL; |
||
197 | |||
198 | if ($volumeDescriptor instanceof SupplementaryVolume && $volumeDescriptor->jolietLevel !== 0) { |
||
199 | echo ' - Joliet Level: ' . $volumeDescriptor->jolietLevel . PHP_EOL; |
||
200 | } |
||
201 | } |
||
202 | |||
203 | protected function displayFiles(Volume $volumeDescriptor, IsoFile $isoFile): void |
||
235 | } |
||
236 | } |
||
237 | } |
||
238 | } |
||
239 | } |
||
240 | } |
||
241 | |||
242 | protected function infoBoot(Boot $bootDescriptor): void |
||
243 | { |
||
244 | echo ' - Boot System ID: ' . $bootDescriptor->bootSysId . PHP_EOL; |
||
245 | echo ' - Boot ID: ' . $bootDescriptor->bootId . PHP_EOL; |
||
246 | echo ' - Boot Catalog Location: ' . $bootDescriptor->bootCatalogLocation . PHP_EOL; |
||
247 | } |
||
248 | |||
249 | /** |
||
250 | * @return array<string, mixed> |
||
251 | */ |
||
252 | protected function parseCliArgs(): array |
||
266 | } |
||
267 | |||
268 | protected function displayError(string $error): void |
||
271 | } |
||
272 | |||
273 | protected function displayHelp(): void |
||
274 | { |
||
289 |