1 | <?php |
||
14 | class CHM |
||
15 | { |
||
16 | /** |
||
17 | * The reader that provides the data. |
||
18 | * |
||
19 | * @var Reader |
||
20 | */ |
||
21 | protected $reader; |
||
22 | |||
23 | /** |
||
24 | * The CHM initial header. |
||
25 | * |
||
26 | * @var Header\ITSF |
||
27 | */ |
||
28 | protected $itsf; |
||
29 | |||
30 | /** |
||
31 | * The directory listing header. |
||
32 | * |
||
33 | * @var Header\ITSP |
||
34 | */ |
||
35 | protected $itsp; |
||
36 | |||
37 | /** |
||
38 | * The entries found in this CHM. |
||
39 | * |
||
40 | * @var Entry[] |
||
41 | */ |
||
42 | protected $entries; |
||
43 | |||
44 | /** |
||
45 | * The data sections. |
||
46 | * |
||
47 | * @var Section\Section[] |
||
48 | */ |
||
49 | protected $sections; |
||
50 | |||
51 | /** |
||
52 | * Initializes the instance. |
||
53 | * |
||
54 | * @param Reader $reader The reader that provides the data. |
||
55 | * |
||
56 | * @throws Exception Throws an Exception in case of errors. |
||
57 | */ |
||
58 | 1 | public function __construct(Reader $reader) |
|
59 | { |
||
60 | 1 | $this->reader = $reader; |
|
61 | 1 | $reader->setPosition(0); |
|
62 | 1 | $this->itsf = new Header\ITSF($reader); |
|
63 | 1 | if ($this->itsf->getSectionOffset() >= 0 && $this->itsf->getSectionLength() >= 16 /* === 24*/) { |
|
64 | 1 | $reader->setPosition($this->itsf->getSectionOffset()); |
|
65 | 1 | /* Unknown (510) */ $reader->readUInt32(); |
|
|
|||
66 | 1 | /* Unknown (0) */ $reader->readUInt32(); |
|
67 | 1 | $totalLength = $reader->readUInt64(); |
|
68 | 1 | if ($totalLength !== $reader->getLength()) { |
|
69 | throw new Exception("Invalid CHM size: expected length $totalLength, current length {$reader->getLength()}"); |
||
70 | } |
||
71 | 1 | } |
|
72 | 1 | $reader->setPosition($this->itsf->getDirectoryOffset()); |
|
73 | 1 | $this->itsp = new Header\ITSP($reader); |
|
74 | |||
75 | 1 | $expectedDirectoryLength = $this->itsf->getDirectoryLength(); |
|
76 | 1 | $calculatedDirectoryLength = $this->itsp->getHeaderLength() + $this->itsp->getNumberOfDirectoryChunks() * $this->itsp->getDirectoryChunkSize(); |
|
77 | 1 | if ($expectedDirectoryLength !== $calculatedDirectoryLength) { |
|
78 | throw new Exception("Unexpected directory list size (expected: $expectedDirectoryLength, calculated: $calculatedDirectoryLength)"); |
||
79 | } |
||
80 | |||
81 | 1 | $this->sections = array(); |
|
82 | 1 | $this->sections[0] = new Section\UncompressedSection($this); |
|
83 | |||
84 | 1 | $this->entries = $this->retrieveEntryList(); |
|
85 | |||
86 | 1 | $this->retrieveSectionList(); |
|
87 | 1 | } |
|
88 | |||
89 | /** |
||
90 | * Destruct the instance. |
||
91 | */ |
||
92 | public function __destruct() |
||
96 | |||
97 | /** |
||
98 | * Create a new CHM instance reading a file. |
||
99 | * |
||
100 | * @param string $filename |
||
101 | * |
||
102 | * @return static |
||
103 | */ |
||
104 | 1 | public static function fromFile($filename) |
|
110 | |||
111 | /** |
||
112 | * Get the reader that provides the data. |
||
113 | * |
||
114 | * @return Reader |
||
115 | */ |
||
116 | 465 | public function getReader() |
|
120 | |||
121 | /** |
||
122 | * Get the CHM initial header. |
||
123 | * |
||
124 | * @return Header\ITSF |
||
125 | */ |
||
126 | 1 | public function getITSF() |
|
130 | |||
131 | /** |
||
132 | * Get the directory listing header. |
||
133 | * |
||
134 | * @return Header\ITSP |
||
135 | */ |
||
136 | public function getITSP() |
||
140 | |||
141 | /** |
||
142 | * Get an entry given its full path. |
||
143 | * |
||
144 | * @param string $path The full path (case sensitive) of the entry to look for. |
||
145 | * |
||
146 | * @return Entry|null |
||
147 | */ |
||
148 | 466 | public function getEntryByPath($path) |
|
152 | |||
153 | /** |
||
154 | * Get the entries contained in this CHM. |
||
155 | * |
||
156 | * @param int|null $type One or more Entry::TYPE_... values (defaults to Entry::TYPE_FILE | Entry::TYPE_DIRECTORY if null). |
||
157 | */ |
||
158 | 1 | public function getEntries($type = null) |
|
159 | { |
||
160 | 1 | if ($type === null) { |
|
161 | $type = Entry::TYPE_FILE | Entry::TYPE_DIRECTORY; |
||
162 | } |
||
163 | 1 | $result = array(); |
|
164 | 1 | foreach ($this->entries as $entry) { |
|
165 | 1 | if (($entry->getType() & $type) !== 0) { |
|
166 | 1 | $result[] = $entry; |
|
167 | 1 | } |
|
168 | 1 | } |
|
169 | |||
170 | 1 | return $result; |
|
171 | } |
||
172 | |||
173 | /** |
||
174 | * Return a section given its index. |
||
175 | * |
||
176 | * @param int $i |
||
177 | * |
||
178 | * @return Section\Section|null |
||
179 | */ |
||
180 | 466 | public function getSectionByIndex($i) |
|
184 | |||
185 | /** |
||
186 | * Retrieve the list of the entries contained in this CHM. |
||
187 | * |
||
188 | * @throws Exception Throws an Exception in case of errors. |
||
189 | * |
||
190 | * @return Entry[] |
||
191 | */ |
||
192 | 1 | protected function retrieveEntryList() |
|
224 | |||
225 | /** |
||
226 | * Retrieve the list of the data sections contained in this CHM. |
||
227 | * |
||
228 | * @throws Exception Throws an Exception in case of errors. |
||
229 | */ |
||
230 | 1 | protected function retrieveSectionList() |
|
267 | } |
||
268 |
Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.
The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.
This check looks for comments that seem to be mostly valid code and reports them.