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