[13350] | 1 | /*
|
---|
| 2 | * DecoderUtil
|
---|
| 3 | *
|
---|
| 4 | * Author: Lasse Collin <lasse.collin@tukaani.org>
|
---|
| 5 | *
|
---|
| 6 | * This file has been put into the public domain.
|
---|
| 7 | * You can do whatever you want with this file.
|
---|
| 8 | */
|
---|
| 9 |
|
---|
| 10 | package org.tukaani.xz.common;
|
---|
| 11 |
|
---|
| 12 | import java.io.InputStream;
|
---|
| 13 | import java.io.IOException;
|
---|
| 14 | import java.io.EOFException;
|
---|
| 15 | import java.util.zip.CRC32;
|
---|
| 16 | import org.tukaani.xz.XZ;
|
---|
| 17 | import org.tukaani.xz.XZFormatException;
|
---|
| 18 | import org.tukaani.xz.CorruptedInputException;
|
---|
| 19 | import org.tukaani.xz.UnsupportedOptionsException;
|
---|
| 20 |
|
---|
| 21 | public class DecoderUtil extends Util {
|
---|
| 22 | public static boolean isCRC32Valid(byte[] buf, int off, int len,
|
---|
| 23 | int ref_off) {
|
---|
| 24 | CRC32 crc32 = new CRC32();
|
---|
| 25 | crc32.update(buf, off, len);
|
---|
| 26 | long value = crc32.getValue();
|
---|
| 27 |
|
---|
| 28 | for (int i = 0; i < 4; ++i)
|
---|
| 29 | if ((byte)(value >>> (i * 8)) != buf[ref_off + i])
|
---|
| 30 | return false;
|
---|
| 31 |
|
---|
| 32 | return true;
|
---|
| 33 | }
|
---|
| 34 |
|
---|
| 35 | public static StreamFlags decodeStreamHeader(byte[] buf)
|
---|
| 36 | throws IOException {
|
---|
| 37 | for (int i = 0; i < XZ.HEADER_MAGIC.length; ++i)
|
---|
| 38 | if (buf[i] != XZ.HEADER_MAGIC[i])
|
---|
| 39 | throw new XZFormatException();
|
---|
| 40 |
|
---|
| 41 | if (!isCRC32Valid(buf, XZ.HEADER_MAGIC.length, 2,
|
---|
| 42 | XZ.HEADER_MAGIC.length + 2))
|
---|
| 43 | throw new CorruptedInputException("XZ Stream Header is corrupt");
|
---|
| 44 |
|
---|
| 45 | try {
|
---|
| 46 | return decodeStreamFlags(buf, XZ.HEADER_MAGIC.length);
|
---|
| 47 | } catch (UnsupportedOptionsException e) {
|
---|
| 48 | throw new UnsupportedOptionsException(
|
---|
| 49 | "Unsupported options in XZ Stream Header");
|
---|
| 50 | }
|
---|
| 51 | }
|
---|
| 52 |
|
---|
| 53 | public static StreamFlags decodeStreamFooter(byte[] buf)
|
---|
| 54 | throws IOException {
|
---|
| 55 | if (buf[10] != XZ.FOOTER_MAGIC[0] || buf[11] != XZ.FOOTER_MAGIC[1]) {
|
---|
| 56 | // NOTE: The exception could be XZFormatException too.
|
---|
| 57 | // It depends on the situation which one is better.
|
---|
| 58 | throw new CorruptedInputException("XZ Stream Footer is corrupt");
|
---|
| 59 | }
|
---|
| 60 |
|
---|
| 61 | if (!isCRC32Valid(buf, 4, 6, 0))
|
---|
| 62 | throw new CorruptedInputException("XZ Stream Footer is corrupt");
|
---|
| 63 |
|
---|
| 64 | StreamFlags streamFlags;
|
---|
| 65 | try {
|
---|
| 66 | streamFlags = decodeStreamFlags(buf, 8);
|
---|
| 67 | } catch (UnsupportedOptionsException e) {
|
---|
| 68 | throw new UnsupportedOptionsException(
|
---|
| 69 | "Unsupported options in XZ Stream Footer");
|
---|
| 70 | }
|
---|
| 71 |
|
---|
| 72 | streamFlags.backwardSize = 0;
|
---|
| 73 | for (int i = 0; i < 4; ++i)
|
---|
| 74 | streamFlags.backwardSize |= (buf[i + 4] & 0xFF) << (i * 8);
|
---|
| 75 |
|
---|
| 76 | streamFlags.backwardSize = (streamFlags.backwardSize + 1) * 4;
|
---|
| 77 |
|
---|
| 78 | return streamFlags;
|
---|
| 79 | }
|
---|
| 80 |
|
---|
| 81 | private static StreamFlags decodeStreamFlags(byte[] buf, int off)
|
---|
| 82 | throws UnsupportedOptionsException {
|
---|
| 83 | if (buf[off] != 0x00 || (buf[off + 1] & 0xFF) >= 0x10)
|
---|
| 84 | throw new UnsupportedOptionsException();
|
---|
| 85 |
|
---|
| 86 | StreamFlags streamFlags = new StreamFlags();
|
---|
| 87 | streamFlags.checkType = buf[off + 1];
|
---|
| 88 |
|
---|
| 89 | return streamFlags;
|
---|
| 90 | }
|
---|
| 91 |
|
---|
| 92 | public static boolean areStreamFlagsEqual(StreamFlags a, StreamFlags b) {
|
---|
| 93 | // backwardSize is intentionally not compared.
|
---|
| 94 | return a.checkType == b.checkType;
|
---|
| 95 | }
|
---|
| 96 |
|
---|
| 97 | public static long decodeVLI(InputStream in) throws IOException {
|
---|
| 98 | int b = in.read();
|
---|
| 99 | if (b == -1)
|
---|
| 100 | throw new EOFException();
|
---|
| 101 |
|
---|
| 102 | long num = b & 0x7F;
|
---|
| 103 | int i = 0;
|
---|
| 104 |
|
---|
| 105 | while ((b & 0x80) != 0x00) {
|
---|
| 106 | if (++i >= VLI_SIZE_MAX)
|
---|
| 107 | throw new CorruptedInputException();
|
---|
| 108 |
|
---|
| 109 | b = in.read();
|
---|
| 110 | if (b == -1)
|
---|
| 111 | throw new EOFException();
|
---|
| 112 |
|
---|
| 113 | if (b == 0x00)
|
---|
| 114 | throw new CorruptedInputException();
|
---|
| 115 |
|
---|
| 116 | num |= (long)(b & 0x7F) << (i * 7);
|
---|
| 117 | }
|
---|
| 118 |
|
---|
| 119 | return num;
|
---|
| 120 | }
|
---|
| 121 | }
|
---|