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 | }
|
---|