1 /*
2 * Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26 package com.sun.imageio.plugins.gif;
27
28 import javax.imageio.metadata.IIOInvalidTreeException;
29 import javax.imageio.metadata.IIOMetadata;
30 import javax.imageio.metadata.IIOMetadataFormatImpl;
31 import org.w3c.dom.Node;
32
33 /**
34 * Class which adds utility DOM element attribute access methods to
35 * {@code IIOMetadata} for subclass use.
36 */
37 abstract class GIFMetadata extends IIOMetadata {
38
39 /**
40 * Represents an undefined value of integer attributes.
41 */
42 static final int UNDEFINED_INTEGER_VALUE = -1;
43
44 //
45 // Note: These attribute methods were shamelessly lifted from
46 // com.sun.imageio.plugins.png.PNGMetadata and modified.
47 //
48
49 // Shorthand for throwing an IIOInvalidTreeException
50 protected static void fatal(Node node, String reason)
51 throws IIOInvalidTreeException {
52 throw new IIOInvalidTreeException(reason, node);
53 }
54
55 // Get an integer-valued attribute
56 protected static String getStringAttribute(Node node, String name,
57 String defaultValue,
58 boolean required,
59 String[] range)
60 throws IIOInvalidTreeException {
61 Node attr = node.getAttributes().getNamedItem(name);
62 if (attr == null) {
63 if (!required) {
64 return defaultValue;
65 } else {
66 fatal(node, "Required attribute " + name + " not present!");
67 }
68 }
69 String value = attr.getNodeValue();
70
71 if (range != null) {
72 if (value == null) {
73 fatal(node,
74 "Null value for "+node.getNodeName()+
75 " attribute "+name+"!");
76 }
77 boolean validValue = false;
78 int len = range.length;
79 for (int i = 0; i < len; i++) {
80 if (value.equals(range[i])) {
81 validValue = true;
82 break;
83 }
84 }
85 if (!validValue) {
86 fatal(node,
87 "Bad value for "+node.getNodeName()+
88 " attribute "+name+"!");
89 }
90 }
91
92 return value;
93 }
94
95
96 // Get an integer-valued attribute
97 protected static int getIntAttribute(Node node, String name,
98 int defaultValue, boolean required,
99 boolean bounded, int min, int max)
100 throws IIOInvalidTreeException {
101 String value = getStringAttribute(node, name, null, required, null);
102 if (value == null || "".equals(value)) {
103 return defaultValue;
104 }
105
106 int intValue = defaultValue;
107 try {
108 intValue = Integer.parseInt(value);
109 } catch (NumberFormatException e) {
110 fatal(node,
111 "Bad value for "+node.getNodeName()+
112 " attribute "+name+"!");
113 }
114 if (bounded && (intValue < min || intValue > max)) {
115 fatal(node,
116 "Bad value for "+node.getNodeName()+
117 " attribute "+name+"!");
118 }
119 return intValue;
120 }
121
122 // Get a float-valued attribute
123 protected static float getFloatAttribute(Node node, String name,
124 float defaultValue,
125 boolean required)
126 throws IIOInvalidTreeException {
127 String value = getStringAttribute(node, name, null, required, null);
128 if (value == null) {
129 return defaultValue;
130 }
131 return Float.parseFloat(value);
132 }
133
134 // Get a required integer-valued attribute
135 protected static int getIntAttribute(Node node, String name,
136 boolean bounded, int min, int max)
137 throws IIOInvalidTreeException {
138 return getIntAttribute(node, name, -1, true, bounded, min, max);
139 }
140
141 // Get a required float-valued attribute
142 protected static float getFloatAttribute(Node node, String name)
143 throws IIOInvalidTreeException {
144 return getFloatAttribute(node, name, -1.0F, true);
145 }
146
147 // Get a boolean-valued attribute
148 protected static boolean getBooleanAttribute(Node node, String name,
149 boolean defaultValue,
150 boolean required)
151 throws IIOInvalidTreeException {
152 Node attr = node.getAttributes().getNamedItem(name);
153 if (attr == null) {
154 if (!required) {
155 return defaultValue;
156 } else {
157 fatal(node, "Required attribute " + name + " not present!");
158 }
159 }
160 String value = attr.getNodeValue();
161 // Allow lower case booleans for backward compatibility, #5082756
162 if (value.equals("TRUE") || value.equals("true")) {
163 return true;
164 } else if (value.equals("FALSE") || value.equals("false")) {
165 return false;
166 } else {
167 fatal(node, "Attribute " + name + " must be 'TRUE' or 'FALSE'!");
168 return false;
169 }
170 }
171
172 // Get a required boolean-valued attribute
173 protected static boolean getBooleanAttribute(Node node, String name)
174 throws IIOInvalidTreeException {
175 return getBooleanAttribute(node, name, false, true);
176 }
177
178 // Get an enumerated attribute as an index into a String array
179 protected static int getEnumeratedAttribute(Node node,
180 String name,
181 String[] legalNames,
182 int defaultValue,
183 boolean required)
184 throws IIOInvalidTreeException {
185 Node attr = node.getAttributes().getNamedItem(name);
186 if (attr == null) {
187 if (!required) {
188 return defaultValue;
189 } else {
190 fatal(node, "Required attribute " + name + " not present!");
191 }
192 }
193 String value = attr.getNodeValue();
194 for (int i = 0; i < legalNames.length; i++) {
195 if(value.equals(legalNames[i])) {
196 return i;
197 }
198 }
199
200 fatal(node, "Illegal value for attribute " + name + "!");
201 return -1;
202 }
203
204 // Get a required enumerated attribute as an index into a String array
205 protected static int getEnumeratedAttribute(Node node,
206 String name,
207 String[] legalNames)
208 throws IIOInvalidTreeException {
209 return getEnumeratedAttribute(node, name, legalNames, -1, true);
210 }
211
212 // Get a String-valued attribute
213 protected static String getAttribute(Node node, String name,
214 String defaultValue, boolean required)
215 throws IIOInvalidTreeException {
216 Node attr = node.getAttributes().getNamedItem(name);
217 if (attr == null) {
218 if (!required) {
219 return defaultValue;
220 } else {
221 fatal(node, "Required attribute " + name + " not present!");
222 }
223 }
224 return attr.getNodeValue();
225 }
226
227 // Get a required String-valued attribute
228 protected static String getAttribute(Node node, String name)
229 throws IIOInvalidTreeException {
230 return getAttribute(node, name, null, true);
231 }
232
233 protected GIFMetadata(boolean standardMetadataFormatSupported,
234 String nativeMetadataFormatName,
235 String nativeMetadataFormatClassName,
236 String[] extraMetadataFormatNames,
237 String[] extraMetadataFormatClassNames) {
238 super(standardMetadataFormatSupported,
239 nativeMetadataFormatName,
240 nativeMetadataFormatClassName,
241 extraMetadataFormatNames,
242 extraMetadataFormatClassNames);
243 }
244
245 public void mergeTree(String formatName, Node root)
246 throws IIOInvalidTreeException {
247 if (formatName.equals(nativeMetadataFormatName)) {
248 if (root == null) {
249 throw new IllegalArgumentException("root == null!");
250 }
251 mergeNativeTree(root);
252 } else if (formatName.equals
253 (IIOMetadataFormatImpl.standardMetadataFormatName)) {
254 if (root == null) {
255 throw new IllegalArgumentException("root == null!");
256 }
257 mergeStandardTree(root);
258 } else {
259 throw new IllegalArgumentException("Not a recognized format!");
260 }
261 }
262
263 protected byte[] getColorTable(Node colorTableNode,
264 String entryNodeName,
265 boolean lengthExpected,
266 int expectedLength)
267 throws IIOInvalidTreeException {
268 byte[] red = new byte[256];
269 byte[] green = new byte[256];
270 byte[] blue = new byte[256];
271 int maxIndex = -1;
272
273 Node entry = colorTableNode.getFirstChild();
274 if (entry == null) {
275 fatal(colorTableNode, "Palette has no entries!");
276 }
277
278 while (entry != null) {
279 if (!entry.getNodeName().equals(entryNodeName)) {
280 fatal(colorTableNode,
281 "Only a "+entryNodeName+" may be a child of a "+
282 entry.getNodeName()+"!");
283 }
284
285 int index = getIntAttribute(entry, "index", true, 0, 255);
286 if (index > maxIndex) {
287 maxIndex = index;
288 }
289 red[index] = (byte)getIntAttribute(entry, "red", true, 0, 255);
290 green[index] = (byte)getIntAttribute(entry, "green", true, 0, 255);
291 blue[index] = (byte)getIntAttribute(entry, "blue", true, 0, 255);
292
293 entry = entry.getNextSibling();
294 }
295
296 int numEntries = maxIndex + 1;
297
298 if (lengthExpected && numEntries != expectedLength) {
299 fatal(colorTableNode, "Unexpected length for palette!");
300 }
301
302 byte[] colorTable = new byte[3*numEntries];
303 for (int i = 0, j = 0; i < numEntries; i++) {
304 colorTable[j++] = red[i];
305 colorTable[j++] = green[i];
306 colorTable[j++] = blue[i];
307 }
308
309 return colorTable;
310 }
311
312 protected abstract void mergeNativeTree(Node root)
313 throws IIOInvalidTreeException;
314
315 protected abstract void mergeStandardTree(Node root)
316 throws IIOInvalidTreeException;
317 }
--- EOF ---