001: /*
002: * $RCSfile: GIFMetadata.java,v $
003: *
004: *
005: * Copyright (c) 2005 Sun Microsystems, Inc. All Rights Reserved.
006: *
007: * Redistribution and use in source and binary forms, with or without
008: * modification, are permitted provided that the following conditions
009: * are met:
010: *
011: * - Redistribution of source code must retain the above copyright
012: * notice, this list of conditions and the following disclaimer.
013: *
014: * - Redistribution in binary form must reproduce the above copyright
015: * notice, this list of conditions and the following disclaimer in
016: * the documentation and/or other materials provided with the
017: * distribution.
018: *
019: * Neither the name of Sun Microsystems, Inc. or the names of
020: * contributors may be used to endorse or promote products derived
021: * from this software without specific prior written permission.
022: *
023: * This software is provided "AS IS," without a warranty of any
024: * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
025: * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
026: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
027: * EXCLUDED. SUN MIDROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
028: * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
029: * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
030: * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
031: * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
032: * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
033: * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
034: * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
035: * POSSIBILITY OF SUCH DAMAGES.
036: *
037: * You acknowledge that this software is not designed or intended for
038: * use in the design, construction, operation or maintenance of any
039: * nuclear facility.
040: *
041: * $Revision: 1.2 $
042: * $Date: 2006/03/24 22:30:10 $
043: * $State: Exp $
044: */
045:
046: package com.sun.media.imageioimpl.plugins.gif;
047:
048: import javax.imageio.metadata.IIOInvalidTreeException;
049: import javax.imageio.metadata.IIOMetadata;
050: import javax.imageio.metadata.IIOMetadataFormatImpl;
051: import org.w3c.dom.Node;
052:
053: /**
054: * Class which adds utility DOM element attribute access methods to
055: * <code>IIOMetadata</code> for subclass use.
056: */
057: abstract class GIFMetadata extends IIOMetadata {
058:
059: /**
060: * Represents an undefined value of integer attributes.
061: */
062: static final int UNDEFINED_INTEGER_VALUE = -1;
063:
064: //
065: // Note: These attribute methods were shamelessly lifted from
066: // com.sun.imageio.plugins.png.PNGMetadata and modified.
067: //
068:
069: // Shorthand for throwing an IIOInvalidTreeException
070: protected static void fatal(Node node, String reason)
071: throws IIOInvalidTreeException {
072: throw new IIOInvalidTreeException(reason, node);
073: }
074:
075: // Get an integer-valued attribute
076: protected static String getStringAttribute(Node node, String name,
077: String defaultValue, boolean required, String[] range)
078: throws IIOInvalidTreeException {
079: Node attr = node.getAttributes().getNamedItem(name);
080: if (attr == null) {
081: if (!required) {
082: return defaultValue;
083: } else {
084: fatal(node, "Required attribute " + name
085: + " not present!");
086: }
087: }
088: String value = attr.getNodeValue();
089:
090: if (range != null) {
091: if (value == null) {
092: fatal(node, "Null value for " + node.getNodeName()
093: + " attribute " + name + "!");
094: }
095: boolean validValue = false;
096: int len = range.length;
097: for (int i = 0; i < len; i++) {
098: if (value.equals(range[i])) {
099: validValue = true;
100: break;
101: }
102: }
103: if (!validValue) {
104: fatal(node, "Bad value for " + node.getNodeName()
105: + " attribute " + name + "!");
106: }
107: }
108:
109: return value;
110: }
111:
112: // Get an integer-valued attribute
113: protected static int getIntAttribute(Node node, String name,
114: int defaultValue, boolean required, boolean bounded,
115: int min, int max) throws IIOInvalidTreeException {
116: String value = getStringAttribute(node, name, null, required,
117: null);
118: if (value == null || "".equals(value)) {
119: return defaultValue;
120: }
121:
122: int intValue = defaultValue;
123: try {
124: intValue = Integer.parseInt(value);
125: } catch (NumberFormatException e) {
126: fatal(node, "Bad value for " + node.getNodeName()
127: + " attribute " + name + "!");
128: }
129: if (bounded && (intValue < min || intValue > max)) {
130: fatal(node, "Bad value for " + node.getNodeName()
131: + " attribute " + name + "!");
132: }
133: return intValue;
134: }
135:
136: // Get a float-valued attribute
137: protected static float getFloatAttribute(Node node, String name,
138: float defaultValue, boolean required)
139: throws IIOInvalidTreeException {
140: String value = getStringAttribute(node, name, null, required,
141: null);
142: if (value == null) {
143: return defaultValue;
144: }
145: return Float.parseFloat(value);
146: }
147:
148: // Get a required integer-valued attribute
149: protected static int getIntAttribute(Node node, String name,
150: boolean bounded, int min, int max)
151: throws IIOInvalidTreeException {
152: return getIntAttribute(node, name, -1, true, bounded, min, max);
153: }
154:
155: // Get a required float-valued attribute
156: protected static float getFloatAttribute(Node node, String name)
157: throws IIOInvalidTreeException {
158: return getFloatAttribute(node, name, -1.0F, true);
159: }
160:
161: // Get a boolean-valued attribute
162: protected static boolean getBooleanAttribute(Node node,
163: String name, boolean defaultValue, boolean required)
164: throws IIOInvalidTreeException {
165: Node attr = node.getAttributes().getNamedItem(name);
166: if (attr == null) {
167: if (!required) {
168: return defaultValue;
169: } else {
170: fatal(node, "Required attribute " + name
171: + " not present!");
172: }
173: }
174: String value = attr.getNodeValue();
175: // XXX Should be able to use equals() here instead of
176: // equalsIgnoreCase() but some boolean attributes are incorrectly
177: // set to "true" or "false" by the J2SE core metadata classes
178: // getAsTree() method (which are duplicated above). See bug 5082756.
179: if (value.equalsIgnoreCase("TRUE")) {
180: return true;
181: } else if (value.equalsIgnoreCase("FALSE")) {
182: return false;
183: } else {
184: fatal(node, "Attribute " + name
185: + " must be 'TRUE' or 'FALSE'!");
186: return false;
187: }
188: }
189:
190: // Get a required boolean-valued attribute
191: protected static boolean getBooleanAttribute(Node node, String name)
192: throws IIOInvalidTreeException {
193: return getBooleanAttribute(node, name, false, true);
194: }
195:
196: // Get an enumerated attribute as an index into a String array
197: protected static int getEnumeratedAttribute(Node node, String name,
198: String[] legalNames, int defaultValue, boolean required)
199: throws IIOInvalidTreeException {
200: Node attr = node.getAttributes().getNamedItem(name);
201: if (attr == null) {
202: if (!required) {
203: return defaultValue;
204: } else {
205: fatal(node, "Required attribute " + name
206: + " not present!");
207: }
208: }
209: String value = attr.getNodeValue();
210: for (int i = 0; i < legalNames.length; i++) {
211: if (value.equals(legalNames[i])) {
212: return i;
213: }
214: }
215:
216: fatal(node, "Illegal value for attribute " + name + "!");
217: return -1;
218: }
219:
220: // Get a required enumerated attribute as an index into a String array
221: protected static int getEnumeratedAttribute(Node node, String name,
222: String[] legalNames) throws IIOInvalidTreeException {
223: return getEnumeratedAttribute(node, name, legalNames, -1, true);
224: }
225:
226: // Get a String-valued attribute
227: protected static String getAttribute(Node node, String name,
228: String defaultValue, boolean required)
229: throws IIOInvalidTreeException {
230: Node attr = node.getAttributes().getNamedItem(name);
231: if (attr == null) {
232: if (!required) {
233: return defaultValue;
234: } else {
235: fatal(node, "Required attribute " + name
236: + " not present!");
237: }
238: }
239: return attr.getNodeValue();
240: }
241:
242: // Get a required String-valued attribute
243: protected static String getAttribute(Node node, String name)
244: throws IIOInvalidTreeException {
245: return getAttribute(node, name, null, true);
246: }
247:
248: protected GIFMetadata(boolean standardMetadataFormatSupported,
249: String nativeMetadataFormatName,
250: String nativeMetadataFormatClassName,
251: String[] extraMetadataFormatNames,
252: String[] extraMetadataFormatClassNames) {
253: super (standardMetadataFormatSupported,
254: nativeMetadataFormatName,
255: nativeMetadataFormatClassName,
256: extraMetadataFormatNames, extraMetadataFormatClassNames);
257: }
258:
259: public void mergeTree(String formatName, Node root)
260: throws IIOInvalidTreeException {
261: if (formatName.equals(nativeMetadataFormatName)) {
262: if (root == null) {
263: throw new IllegalArgumentException("root == null!");
264: }
265: mergeNativeTree(root);
266: } else if (formatName
267: .equals(IIOMetadataFormatImpl.standardMetadataFormatName)) {
268: if (root == null) {
269: throw new IllegalArgumentException("root == null!");
270: }
271: mergeStandardTree(root);
272: } else {
273: throw new IllegalArgumentException(
274: "Not a recognized format!");
275: }
276: }
277:
278: protected byte[] getColorTable(Node colorTableNode,
279: String entryNodeName, boolean lengthExpected,
280: int expectedLength) throws IIOInvalidTreeException {
281: byte[] red = new byte[256];
282: byte[] green = new byte[256];
283: byte[] blue = new byte[256];
284: int maxIndex = -1;
285:
286: Node entry = colorTableNode.getFirstChild();
287: if (entry == null) {
288: fatal(colorTableNode, "Palette has no entries!");
289: }
290:
291: while (entry != null) {
292: if (!entry.getNodeName().equals(entryNodeName)) {
293: fatal(colorTableNode, "Only a " + entryNodeName
294: + " may be a child of a " + entry.getNodeName()
295: + "!");
296: }
297:
298: int index = getIntAttribute(entry, "index", true, 0, 255);
299: if (index > maxIndex) {
300: maxIndex = index;
301: }
302: red[index] = (byte) getIntAttribute(entry, "red", true, 0,
303: 255);
304: green[index] = (byte) getIntAttribute(entry, "green", true,
305: 0, 255);
306: blue[index] = (byte) getIntAttribute(entry, "blue", true,
307: 0, 255);
308:
309: entry = entry.getNextSibling();
310: }
311:
312: int numEntries = maxIndex + 1;
313:
314: if (lengthExpected && numEntries != expectedLength) {
315: fatal(colorTableNode, "Unexpected length for palette!");
316: }
317:
318: byte[] colorTable = new byte[3 * numEntries];
319: for (int i = 0, j = 0; i < numEntries; i++) {
320: colorTable[j++] = red[i];
321: colorTable[j++] = green[i];
322: colorTable[j++] = blue[i];
323: }
324:
325: return colorTable;
326: }
327:
328: protected abstract void mergeNativeTree(Node root)
329: throws IIOInvalidTreeException;
330:
331: protected abstract void mergeStandardTree(Node root)
332: throws IIOInvalidTreeException;
333: }
|