1:
37:
38: package ;
39:
40: import ;
41: import ;
42: import ;
43: import ;
44:
45:
48: public class PNGChunk
49: {
50:
51:
54: private static long[] crcTable;
55:
56: static
57: {
58: long c;
59: crcTable = new long[256];
60:
61: for(int i = 0; i < 256; i++)
62: {
63: c = i;
64: for(int j = 0; j < 8; j++)
65: if( (c & 1) == 1 )
66: c = 0xEDB88320L ^ (c >> 1);
67: else
68: c = c >> 1;
69: crcTable[i] = c;
70: }
71: }
72:
73:
76: public static final int TYPE_HEADER = 0x49484452;
77: public static final int TYPE_PALETTE = 0x504c5445;
78: public static final int TYPE_DATA = 0x49444154;
79: public static final int TYPE_TIME = 0x74494d45;
80: public static final int TYPE_END = 0x49454e44;
81: public static final int TYPE_PHYS = 0x70485973;
82: public static final int TYPE_GAMMA = 0x67414d41;
83: public static final int TYPE_PROFILE = 0x69434350;
84:
85:
88: private int type;
89:
90:
93: protected byte[] data;
94:
95:
98: private int crc;
99:
100:
103: protected PNGChunk( int type, byte[] data, int crc )
104: {
105: this.type = type;
106: this.data = data;
107: this.crc = crc;
108: }
109:
110:
114: protected PNGChunk( int type )
115: {
116: this.type = type;
117: }
118:
119:
126: public static PNGChunk readChunk(InputStream in, boolean strict)
127: throws IOException, PNGException
128: {
129: byte data[] = new byte[4];
130: if( in.read( data ) != 4 )
131: throw new IOException("Could not read chunk length.");
132: int length = ((data[0] & 0xFF) << 24) | ((data[1] & 0xFF) << 16 ) |
133: ((data[2] & 0xFF) << 8) | (data[3] & 0xFF);
134:
135: if( in.read( data ) != 4 )
136: throw new IOException("Could not read chunk type.");
137: int type = ((data[0] & 0xFF) << 24) | ((data[1] & 0xFF) << 16 ) |
138: ((data[2] & 0xFF) << 8) | (data[3] & 0xFF);
139:
140: byte[] chkdata = new byte[ length ];
141: if( in.read( chkdata ) != length )
142: throw new IOException("Could not read chunk data.");
143:
144: if( in.read( data ) != 4 )
145: throw new IOException("Could not read chunk CRC.");
146:
147: int crc = ((data[0] & 0xFF) << 24) | ( (data[1] & 0xFF) << 16 ) |
148: ((data[2] & 0xFF) << 8) | (data[3] & 0xFF);
149:
150: if( strict )
151: return getChunk( type, chkdata, crc );
152: else
153: {
154: try
155: {
156: return getChunk( type, chkdata, crc );
157: }
158: catch(PNGException pnge)
159: {
160: if( isEssentialChunk( type ) )
161: throw pnge;
162: return null;
163: }
164: }
165: }
166:
167:
170: private static PNGChunk getChunk( int type, byte[] data, int crc )
171: throws PNGException
172: {
173: switch( type )
174: {
175: case TYPE_HEADER:
176: return new PNGHeader( type, data, crc );
177: case TYPE_DATA:
178: return new PNGData( type, data, crc );
179: case TYPE_PALETTE:
180: return new PNGPalette( type, data, crc );
181: case TYPE_TIME:
182: return new PNGTime( type, data, crc );
183: case TYPE_PHYS:
184: return new PNGPhys( type, data, crc );
185: case TYPE_GAMMA:
186: return new PNGGamma( type, data, crc );
187: case TYPE_PROFILE:
188: return new PNGICCProfile( type, data, crc );
189: default:
190: return new PNGChunk( type, data, crc );
191: }
192: }
193:
194:
197: private static boolean isEssentialChunk( int type )
198: {
199: switch( type )
200: {
201: case TYPE_HEADER:
202: case TYPE_DATA:
203: case TYPE_PALETTE:
204: case TYPE_END:
205: return true;
206: default:
207: return false;
208: }
209: }
210:
211:
214: public boolean isValidChunk()
215: {
216: return (crc == calcCRC());
217: }
218:
219:
222: public int getType()
223: {
224: return type;
225: }
226:
227:
231: public void writeChunk(OutputStream out) throws IOException
232: {
233: out.write( getInt(data.length) );
234: out.write( getInt(type) );
235: out.write( data );
236: out.write( getInt(calcCRC()) );
237: }
238:
239:
242: public boolean isEmpty()
243: {
244: return ( data.length == 0 );
245: }
246:
247:
251: public static byte[] getInt(int intValue)
252: {
253: long i = (intValue & 0xFFFFFFFFL);
254: byte[] b = new byte[4];
255: b[0] = (byte)((i & 0xFF000000L) >> 24);
256: b[1] = (byte)((i & 0x00FF0000L) >> 16);
257: b[2] = (byte)((i & 0x0000FF00L) >> 8);
258: b[3] = (byte)(i & 0x000000FFL);
259: return b;
260: }
261:
262:
265: private int calcCRC()
266: {
267: long c = 0xFFFFFFFFL;
268: byte[] t = getInt( type );
269: for(int i = 0; i < 4; i++)
270: c = crcTable[ (int)((c ^ t[i]) & 0xFF) ] ^ (c >> 8);
271:
272: for(int i = 0; i < data.length; i++)
273: c = crcTable[ (int)((c ^ data[i]) & 0xFF) ] ^ (c >> 8);
274:
275: return (int)(c ^ 0xFFFFFFFFL);
276: }
277:
278: public String toString()
279: {
280: return "PNG Chunk. Type: " + new String( getInt(type) ) + " , CRC: " +
281: crc + " , calculated CRC: "+calcCRC();
282: }
283:
284: }