1 11 package org.eclipse.swt.internal.image; 12 13 import java.io.*; 14 15 public class PngLzBlockReader { 16 boolean isLastBlock; 17 byte compressionType; 18 int uncompressedBytesRemaining; 19 PngDecodingDataStream stream; 20 PngHuffmanTables huffmanTables; 21 22 byte[] window; 23 int windowIndex; 24 int copyIndex; 25 int copyBytesRemaining; 26 27 static final int UNCOMPRESSED = 0; 28 static final int COMPRESSED_FIXED = 1; 29 static final int COMPRESSED_DYNAMIC = 2; 30 31 static final int END_OF_COMPRESSED_BLOCK = 256; 32 static final int FIRST_LENGTH_CODE = 257; 33 static final int LAST_LENGTH_CODE = 285; 34 static final int FIRST_DISTANCE_CODE = 1; 35 static final int LAST_DISTANCE_CODE = 29; 36 static final int FIRST_CODE_LENGTH_CODE = 4; 37 static final int LAST_CODE_LENGTH_CODE = 19; 38 39 static final int[] lengthBases = { 40 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 41 31, 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258 42 } ; 43 static final int[] extraLengthBits = { 44 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 45 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0, 46 }; 47 static final int[] distanceBases = { 48 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 49 193, 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 50 6145, 8193, 12289, 16385, 24577, 51 }; 52 static final int[] extraDistanceBits = { 53 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 54 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13, 55 }; 56 57 58 PngLzBlockReader(PngDecodingDataStream stream) { 59 this.stream = stream; 60 isLastBlock = false; 61 } 62 63 void setWindowSize(int windowSize) { 64 window = new byte[windowSize]; 65 } 66 67 void readNextBlockHeader() throws IOException { 68 isLastBlock = stream.getNextIdatBit() != 0; 69 compressionType = (byte)(stream.getNextIdatBits(2) & 0xFF); 70 if (compressionType > 2) stream.error(); 71 72 if (compressionType == UNCOMPRESSED) { 73 byte b1 = stream.getNextIdatByte(); 74 byte b2 = stream.getNextIdatByte(); 75 byte b3 = stream.getNextIdatByte(); 76 byte b4 = stream.getNextIdatByte(); 77 if (b1 != ~b3 || b2 != ~b4) stream.error(); 78 uncompressedBytesRemaining = (b1 & 0xFF) | ((b2 & 0xFF) << 8); 79 } else if (compressionType == COMPRESSED_DYNAMIC) { 80 huffmanTables = PngHuffmanTables.getDynamicTables(stream); 81 } else { 82 huffmanTables = PngHuffmanTables.getFixedTables(); 83 } 84 } 85 86 byte getNextByte() throws IOException { 87 if (compressionType == UNCOMPRESSED) { 88 if (uncompressedBytesRemaining == 0) { 89 readNextBlockHeader(); 90 return getNextByte(); 91 } 92 uncompressedBytesRemaining--; 93 return stream.getNextIdatByte(); 94 } else { 95 byte value = getNextCompressedByte(); 96 if (value == END_OF_COMPRESSED_BLOCK) { 97 if (isLastBlock) stream.error(); 98 readNextBlockHeader(); 99 return getNextByte(); 100 } else { 101 return value; 102 } 103 } 104 } 105 106 private void assertBlockAtEnd() throws IOException { 107 if (compressionType == UNCOMPRESSED) { 108 if (uncompressedBytesRemaining > 0) stream.error(); 109 } else if (copyBytesRemaining > 0 || 110 (huffmanTables.getNextLiteralValue(stream) != END_OF_COMPRESSED_BLOCK)) 111 { 112 stream.error(); 113 } 114 } 115 void assertCompressedDataAtEnd() throws IOException { 116 assertBlockAtEnd(); 117 while (!isLastBlock) { 118 readNextBlockHeader(); 119 assertBlockAtEnd(); 120 } 121 } 122 123 private byte getNextCompressedByte() throws IOException { 124 if (copyBytesRemaining > 0) { 125 byte value = window[copyIndex]; 126 window[windowIndex] = value; 127 copyBytesRemaining--; 128 129 copyIndex++; 130 windowIndex++; 131 if (copyIndex == window.length) copyIndex = 0; 132 if (windowIndex == window.length) windowIndex = 0; 133 134 return value; 135 } 136 137 int value = huffmanTables.getNextLiteralValue(stream); 138 if (value < END_OF_COMPRESSED_BLOCK) { 139 window[windowIndex] = (byte) (value & 0xFF); 140 windowIndex++; 141 if (windowIndex >= window.length) windowIndex = 0; 142 return (byte) (value & 0xFF); 143 } else if (value == END_OF_COMPRESSED_BLOCK) { 144 readNextBlockHeader(); 145 return getNextByte(); 146 } else if (value <= LAST_LENGTH_CODE) { 147 int extraBits = extraLengthBits[value - FIRST_LENGTH_CODE]; 148 int length = lengthBases[value - FIRST_LENGTH_CODE]; 149 if (extraBits > 0) { 150 length += stream.getNextIdatBits(extraBits); 151 } 152 153 value = huffmanTables.getNextDistanceValue(stream); 154 if (value > LAST_DISTANCE_CODE) stream.error(); 155 extraBits = extraDistanceBits[value]; 156 int distance = distanceBases[value]; 157 if (extraBits > 0) { 158 distance += stream.getNextIdatBits(extraBits); 159 } 160 161 copyIndex = windowIndex - distance; 162 if (copyIndex < 0) copyIndex += window.length; 163 164 copyBytesRemaining = length; 165 return getNextCompressedByte(); 166 } else { 167 stream.error(); 168 return 0; 169 } 170 } 171 172 } 173 | Popular Tags |