Total Complexity | 42 |
Total Lines | 355 |
Duplicated Lines | 0 % |
Changes | 2 | ||
Bugs | 0 | Features | 0 |
Complex classes like Biff8 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 Biff8, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
9 | class Biff8 extends Xls |
||
10 | { |
||
11 | /** |
||
12 | * read BIFF8 constant value array from array data |
||
13 | * returns e.g. ['value' => '{1,2;3,4}', 'size' => 40] |
||
14 | * section 2.5.8. |
||
15 | */ |
||
16 | protected static function readBIFF8ConstantArray(string $arrayData): array |
||
43 | ]; |
||
44 | } |
||
45 | |||
46 | /** |
||
47 | * read BIFF8 constant value which may be 'Empty Value', 'Number', 'String Value', 'Boolean Value', 'Error Value' |
||
48 | * section 2.5.7 |
||
49 | * returns e.g. ['value' => '5', 'size' => 9]. |
||
50 | */ |
||
51 | private static function readBIFF8Constant(string $valueData): array |
||
52 | { |
||
53 | // offset: 0; size: 1; identifier for type of constant |
||
54 | $identifier = ord($valueData[0]); |
||
55 | |||
56 | switch ($identifier) { |
||
57 | case 0x00: // empty constant (what is this?) |
||
58 | $value = ''; |
||
59 | $size = 9; |
||
60 | |||
61 | break; |
||
62 | case 0x01: // number |
||
63 | // offset: 1; size: 8; IEEE 754 floating-point value |
||
64 | $value = self::extractNumber(substr($valueData, 1, 8)); |
||
65 | $size = 9; |
||
66 | |||
67 | break; |
||
68 | case 0x02: // string value |
||
69 | // offset: 1; size: var; Unicode string, 16-bit string length |
||
70 | $string = self::readUnicodeStringLong(substr($valueData, 1)); |
||
71 | $value = '"' . $string['value'] . '"'; |
||
72 | $size = 1 + $string['size']; |
||
73 | |||
74 | break; |
||
75 | case 0x04: // boolean |
||
76 | // offset: 1; size: 1; 0 = FALSE, 1 = TRUE |
||
77 | if (ord($valueData[1])) { |
||
78 | $value = 'TRUE'; |
||
79 | } else { |
||
80 | $value = 'FALSE'; |
||
81 | } |
||
82 | $size = 9; |
||
83 | |||
84 | break; |
||
85 | case 0x10: // error code |
||
86 | // offset: 1; size: 1; error code |
||
87 | $value = ErrorCode::lookup(ord($valueData[1])); |
||
88 | $size = 9; |
||
89 | |||
90 | break; |
||
91 | default: |
||
92 | throw new ReaderException('Unsupported BIFF8 constant'); |
||
93 | } |
||
94 | |||
95 | return [ |
||
96 | 'value' => $value, |
||
97 | 'size' => $size, |
||
98 | ]; |
||
99 | } |
||
100 | |||
101 | /** |
||
102 | * Read BIFF8 cell range address list |
||
103 | * section 2.5.15. |
||
104 | */ |
||
105 | public static function readBIFF8CellRangeAddressList(string $subData): array |
||
122 | ]; |
||
123 | } |
||
124 | |||
125 | /** |
||
126 | * Reads a cell address in BIFF8 e.g. 'A2' or '$A$2' |
||
127 | * section 3.3.4. |
||
128 | */ |
||
129 | protected static function readBIFF8CellAddress(string $cellAddressStructure): string |
||
148 | } |
||
149 | |||
150 | /** |
||
151 | * Reads a cell address in BIFF8 for shared formulas. Uses positive and negative values for row and column |
||
152 | * to indicate offsets from a base cell |
||
153 | * section 3.3.4. |
||
154 | * |
||
155 | * @param string $baseCell Base cell, only needed when formula contains tRefN tokens, e.g. with shared formulas |
||
156 | */ |
||
157 | protected static function readBIFF8CellAddressB(string $cellAddressStructure, string $baseCell = 'A1'): string |
||
158 | { |
||
159 | [$baseCol, $baseRow] = Coordinate::coordinateFromString($baseCell); |
||
160 | $baseCol = Coordinate::columnIndexFromString($baseCol) - 1; |
||
161 | $baseRow = (int) $baseRow; |
||
162 | |||
163 | // offset: 0; size: 2; index to row (0... 65535) (or offset (-32768... 32767)) |
||
164 | $rowIndex = self::getUInt2d($cellAddressStructure, 0); |
||
165 | $row = self::getUInt2d($cellAddressStructure, 0) + 1; |
||
166 | |||
167 | // bit: 14; mask 0x4000; (1 = relative column index, 0 = absolute column index) |
||
168 | if (!(0x4000 & self::getUInt2d($cellAddressStructure, 2))) { |
||
169 | // offset: 2; size: 2; index to column or column offset + relative flags |
||
170 | // bit: 7-0; mask 0x00FF; column index |
||
171 | $colIndex = 0x00FF & self::getUInt2d($cellAddressStructure, 2); |
||
172 | |||
173 | $column = Coordinate::stringFromColumnIndex($colIndex + 1); |
||
174 | $column = '$' . $column; |
||
175 | } else { |
||
176 | // offset: 2; size: 2; index to column or column offset + relative flags |
||
177 | // bit: 7-0; mask 0x00FF; column index |
||
178 | $relativeColIndex = 0x00FF & self::getInt2d($cellAddressStructure, 2); |
||
179 | $colIndex = $baseCol + $relativeColIndex; |
||
180 | $colIndex = ($colIndex < 256) ? $colIndex : $colIndex - 256; |
||
181 | $colIndex = ($colIndex >= 0) ? $colIndex : $colIndex + 256; |
||
182 | $column = Coordinate::stringFromColumnIndex($colIndex + 1); |
||
183 | } |
||
184 | |||
185 | // bit: 15; mask 0x8000; (1 = relative row index, 0 = absolute row index) |
||
186 | if (!(0x8000 & self::getUInt2d($cellAddressStructure, 2))) { |
||
187 | $row = '$' . $row; |
||
188 | } else { |
||
189 | $rowIndex = ($rowIndex <= 32767) ? $rowIndex : $rowIndex - 65536; |
||
190 | $row = $baseRow + $rowIndex; |
||
191 | } |
||
192 | |||
193 | return $column . $row; |
||
194 | } |
||
195 | |||
196 | /** |
||
197 | * Reads a cell range address in BIFF8 e.g. 'A2:B6' or 'A1' |
||
198 | * always fixed range |
||
199 | * section 2.5.14. |
||
200 | */ |
||
201 | protected static function readBIFF8CellRangeAddressFixed(string $subData): string |
||
202 | { |
||
203 | // offset: 0; size: 2; index to first row |
||
204 | $fr = self::getUInt2d($subData, 0) + 1; |
||
205 | |||
206 | // offset: 2; size: 2; index to last row |
||
207 | $lr = self::getUInt2d($subData, 2) + 1; |
||
208 | |||
209 | // offset: 4; size: 2; index to first column |
||
210 | $fc = self::getUInt2d($subData, 4); |
||
211 | |||
212 | // offset: 6; size: 2; index to last column |
||
213 | $lc = self::getUInt2d($subData, 6); |
||
214 | |||
215 | // check values |
||
216 | if ($fr > $lr || $fc > $lc) { |
||
217 | throw new ReaderException('Not a cell range address'); |
||
218 | } |
||
219 | |||
220 | // column index to letter |
||
221 | $fc = Coordinate::stringFromColumnIndex($fc + 1); |
||
222 | $lc = Coordinate::stringFromColumnIndex($lc + 1); |
||
223 | |||
224 | if ($fr == $lr && $fc == $lc) { |
||
225 | return "$fc$fr"; |
||
226 | } |
||
227 | |||
228 | return "$fc$fr:$lc$lr"; |
||
229 | } |
||
230 | |||
231 | /** |
||
232 | * Reads a cell range address in BIFF8 e.g. 'A2:B6' or '$A$2:$B$6' |
||
233 | * there are flags indicating whether column/row index is relative |
||
234 | * section 3.3.4. |
||
235 | */ |
||
236 | protected static function readBIFF8CellRangeAddress(string $subData): string |
||
278 | } |
||
279 | |||
280 | /** |
||
281 | * Reads a cell range address in BIFF8 for shared formulas. Uses positive and negative values for row and column |
||
282 | * to indicate offsets from a base cell |
||
283 | * section 3.3.4. |
||
284 | * |
||
285 | * @param string $baseCell Base cell |
||
286 | * |
||
287 | * @return string Cell range address |
||
288 | */ |
||
289 | protected static function readBIFF8CellRangeAddressB(string $subData, string $baseCell = 'A1'): string |
||
366 |