|
18 | 18 |
|
19 | 19 | import static java.nio.charset.StandardCharsets.UTF_8; |
20 | 20 |
|
21 | | -import java.math.BigInteger; |
22 | 21 | import java.util.ArrayList; |
23 | 22 | import java.util.HashSet; |
24 | 23 | import java.util.List; |
@@ -220,17 +219,12 @@ private void enumerateOneSegment(byte[] dir_chunk) throws ChmParsingException, T |
220 | 219 | //setPlaceHolder(header_len); |
221 | 220 | while (placeHolder > 0 && placeHolder < dir_chunk.length - PMGLheader.getFreeSpace() |
222 | 221 | /*&& dir_chunk[placeHolder - 1] != 115*/) { |
223 | | - //get entry name length |
224 | | - int strlen = 0;// = getEncint(data); |
225 | | - byte temp; |
226 | | - while ((temp = dir_chunk[placeHolder++]) >= 0x80) { |
227 | | - strlen <<= 7; |
228 | | - strlen += temp & 0x7f; |
229 | | - } |
230 | | - |
231 | | - strlen = (strlen << 7) + temp & 0x7f; |
| 222 | + //get entry name length (variable-length ENCINT). The old inline |
| 223 | + //decoder compared a signed byte to 0x80 (never true), so it read a |
| 224 | + //single byte and capped the length at 127, corrupting longer names. |
| 225 | + int strlen = getEncint(dir_chunk); |
232 | 226 |
|
233 | | - if (strlen > dir_chunk.length) { |
| 227 | + if (strlen < 0 || strlen > dir_chunk.length) { |
234 | 228 | throw new ChmParsingException("Bad data of a string length."); |
235 | 229 | } |
236 | 230 |
|
@@ -324,22 +318,33 @@ private void enumerateOneSegment(byte[] dir_chunk) throws ChmParsingException, T |
324 | 318 | * @param data_chunk |
325 | 319 | * @return |
326 | 320 | */ |
327 | | - private int getEncint(byte[] data_chunk) { |
328 | | - byte ob; |
329 | | - BigInteger bi = BigInteger.ZERO; |
330 | | - byte[] nb = new byte[1]; |
331 | | - |
332 | | - if (placeHolder < data_chunk.length) { |
333 | | - while ((ob = data_chunk[placeHolder]) < 0) { |
334 | | - nb[0] = (byte) ((ob & 0x7f)); |
335 | | - bi = bi.shiftLeft(7).add(new BigInteger(nb)); |
336 | | - setPlaceHolder(placeHolder + 1); |
337 | | - } |
338 | | - nb[0] = (byte) ((ob & 0x7f)); |
339 | | - bi = bi.shiftLeft(7).add(new BigInteger(nb)); |
| 321 | + private int getEncint(byte[] dataChunk) { |
| 322 | + int start = placeHolder; |
| 323 | + //advance past the continuation bytes (high bit set) and the terminating byte |
| 324 | + while (placeHolder < dataChunk.length && dataChunk[placeHolder] < 0) { |
| 325 | + setPlaceHolder(placeHolder + 1); |
| 326 | + } |
| 327 | + if (placeHolder < dataChunk.length) { |
340 | 328 | setPlaceHolder(placeHolder + 1); |
341 | 329 | } |
342 | | - return bi.intValue(); |
| 330 | + return (int) decodeEncint(dataChunk, start); |
| 331 | + } |
| 332 | + |
| 333 | + /** |
| 334 | + * Decodes a variable-length ENCINT beginning at {@code offset}: each byte |
| 335 | + * contributes its low 7 bits (most-significant group first) and the high bit |
| 336 | + * signals that another byte follows. Package-private for testing. |
| 337 | + */ |
| 338 | + static long decodeEncint(byte[] data, int offset) { |
| 339 | + long value = 0; |
| 340 | + while (offset < data.length && data[offset] < 0) { |
| 341 | + value = (value << 7) | (data[offset] & 0x7f); |
| 342 | + offset++; |
| 343 | + } |
| 344 | + if (offset < data.length) { |
| 345 | + value = (value << 7) | (data[offset] & 0x7f); |
| 346 | + } |
| 347 | + return value; |
343 | 348 | } |
344 | 349 |
|
345 | 350 | /** |
|
0 commit comments