1 /* 2 * Copyright (c) 2016, 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. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 24 /** 25 * @test 26 * @bug 8152183 27 * @author a.stepanov 28 * @summary Some checks for TIFFField methods 29 * @run main TIFFFieldTest 30 */ 31 32 import java.util.List; 33 import java.util.ArrayList; 34 import javax.imageio.metadata.IIOMetadataNode; 35 import javax.imageio.plugins.tiff.*; 36 import org.w3c.dom.NamedNodeMap; 37 import org.w3c.dom.Node; 38 39 public class TIFFFieldTest { 40 41 private final static String NAME = "tag"; // tag name 42 private final static int NUM = 12345; // tag number 43 private final static int MIN_TYPE = TIFFTag.MIN_DATATYPE; 44 private final static int MAX_TYPE = TIFFTag.MAX_DATATYPE; 45 private final static String CONSTRUCT = "can construct TIFFField with "; 46 47 private void check(boolean ok, String msg) { 48 if (!ok) { throw new RuntimeException(msg); } 49 } 50 51 private void testConstructors() { 52 53 // test constructors 54 55 TIFFTag tag = new TIFFTag( 56 NAME, NUM, 1 << TIFFTag.TIFF_SHORT | 1 << TIFFTag.TIFF_LONG); 57 TIFFField f; 58 59 // constructor: TIFFField(tag, value) 60 boolean ok = false; 61 try { new TIFFField(null, 0); } 62 catch (NullPointerException e) { ok = true; } 63 check(ok, CONSTRUCT + "null tag"); 64 65 ok = false; 66 try { new TIFFField(tag, -1); } 67 catch (IllegalArgumentException e) { ok = true; } 68 check(ok, CONSTRUCT + "invalid count"); 69 70 // check value type recognition 71 int v = 1 << 16; 72 f = new TIFFField(tag, v - 1); 73 check(f.getType() == TIFFTag.TIFF_SHORT, "must be treated as short"); 74 check(f.isIntegral(), "must be integral"); 75 f = new TIFFField(tag, v); 76 check(f.getType() == TIFFTag.TIFF_LONG, "must be treated as long"); 77 78 // other checks 79 check(f.getAsLongs().length == 1, "invalid long[] size"); 80 check(f.isIntegral(), "must be integral"); 81 check((f.getDirectory() == null) && !f.hasDirectory(), 82 "must not have directory"); 83 check(f.getValueAsString(0).equals(String.valueOf(v)), 84 "invalid string representation of value"); 85 check(f.getTag().getNumber() == f.getTagNumber(), 86 "invalid tag number"); 87 check(f.getCount() == 1, "invalid count"); 88 check(f.getTagNumber() == NUM, "invalid tag number"); 89 90 // constructor: TIFFField(tag, type, count) 91 int type = TIFFTag.TIFF_SHORT; 92 93 ok = false; 94 try { new TIFFField(null, type, 1); } 95 catch (NullPointerException e) { ok = true; } 96 check(ok, CONSTRUCT + "null tag"); 97 98 ok = false; 99 try { new TIFFField(tag, MAX_TYPE + 1, 1); } 100 catch (IllegalArgumentException e) { ok = true; } 101 check(ok, CONSTRUCT + "invalid type tag"); 102 103 // check that count == 1 for TIFF_IFD_POINTER 104 ok = false; 105 try { new TIFFField(tag, TIFFTag.TIFF_IFD_POINTER, 0); } 106 catch (IllegalArgumentException e) { ok = true; } 107 check(ok, "only count = 1 should be allowed for IFDPointer"); 108 109 ok = false; 110 try { new TIFFField(tag, TIFFTag.TIFF_IFD_POINTER, 2); } 111 catch (IllegalArgumentException e) { ok = true; } 112 check(ok, "only count = 1 should be allowed for IFDPointer"); 113 114 // check that count == 0 is not allowed for TIFF_RATIONAL, TIFF_SRATIONAL 115 // (see fix for JDK-8149120) 116 ok = false; 117 try { new TIFFField(tag, TIFFTag.TIFF_RATIONAL, 0); } 118 catch (IllegalArgumentException e) { ok = true; } 119 check(ok, "count = 0 should not be allowed for Rational"); 120 121 ok = false; 122 try { new TIFFField(tag, TIFFTag.TIFF_SRATIONAL, 0); } 123 catch (IllegalArgumentException e) { ok = true; } 124 check(ok, "count = 0 should not be allowed for SRational"); 125 126 ok = false; 127 try { new TIFFField(tag, type, -1); } 128 catch (IllegalArgumentException e) { ok = true; } 129 check(ok, CONSTRUCT + "with invalid data count"); 130 131 f = new TIFFField(tag, type, 0); 132 check(f.getCount() == 0, "invalid count"); 133 check(!f.hasDirectory(), "must not have directory"); 134 135 // constructor: TIFFField(tag, type, count, data) 136 double a[] = {0.1, 0.2, 0.3}; 137 ok = false; 138 try { new TIFFField(null, TIFFTag.TIFF_DOUBLE, a.length, a); } 139 catch (NullPointerException e) { ok = true; } 140 check(ok, CONSTRUCT + "null tag"); 141 142 ok = false; 143 try { new TIFFField(tag, type, a.length - 1, a); } 144 catch (IllegalArgumentException e) { ok = true; } 145 check(ok, CONSTRUCT + "invalid data count"); 146 147 String a2[] = {"one", "two"}; 148 ok = false; 149 try { new TIFFField(tag, type, 2, a2); } 150 catch (IllegalArgumentException e) { ok = true; } 151 check(ok, CONSTRUCT + "invalid data type"); 152 check((f.getDirectory() == null) && !f.hasDirectory(), 153 "must not have directory"); 154 155 // constructor: TIFFField(tag, type, offset, dir) 156 List<TIFFTag> tags = new ArrayList<>(); 157 tags.add(tag); 158 TIFFTagSet sets[] = {new TIFFTagSet(tags)}; 159 TIFFDirectory dir = new TIFFDirectory(sets, null); 160 161 ok = false; 162 try { new TIFFField(null, type, 4L, dir); } 163 catch (NullPointerException e) { ok = true; } 164 check(ok, CONSTRUCT + "null tag"); 165 166 ok = false; 167 try { new TIFFField(tag, type, 0L, dir); } 168 catch (IllegalArgumentException e) { ok = true; } 169 check(ok, CONSTRUCT + "non-positive offset"); 170 171 long offset = 4; 172 173 for (int t = MIN_TYPE; t <= MAX_TYPE; t++) { 174 175 tag = new TIFFTag(NAME, NUM, 1 << t); 176 177 // only TIFF_LONG and TIFF_IFD_POINTER types are allowed 178 if (t == TIFFTag.TIFF_LONG || t == TIFFTag.TIFF_IFD_POINTER) { 179 180 f = new TIFFField(tag, t, offset, dir); 181 check(f.hasDirectory(), "must have directory"); 182 183 check(f.getDirectory().getTag(NUM).getName().equals(NAME), 184 "invalid tag name"); 185 186 check(f.getCount() == 1, "invalid count"); 187 check(f.getAsLong(0) == offset, "invalid offset"); 188 } else { 189 ok = false; 190 try { new TIFFField(tag, t, offset, dir); } 191 catch (IllegalArgumentException e) { ok = true; } 192 check(ok, CONSTRUCT + "invalid data type"); 193 } 194 } 195 196 type = TIFFTag.TIFF_IFD_POINTER; 197 tag = new TIFFTag(NAME, NUM, 1 << type); 198 ok = false; 199 try { new TIFFField(tag, type, offset, null); } 200 catch (NullPointerException e) { ok = true; } 201 check(ok, CONSTRUCT + "null TIFFDirectory"); 202 203 type = TIFFTag.TIFF_LONG; 204 tag = new TIFFTag(NAME, NUM, 1 << type); 205 ok = false; 206 try { new TIFFField(tag, type, offset, null); } 207 catch (NullPointerException e) { ok = true; } 208 check(ok, CONSTRUCT + "null TIFFDirectory"); 209 } 210 211 private void testTypes() { 212 213 // test getTypeName(), getTypeByName() methods 214 215 boolean ok = false; 216 try { TIFFField.getTypeName(MIN_TYPE - 1); } 217 catch (IllegalArgumentException e) { ok = true; } 218 check(ok, "invalid data type number used"); 219 220 ok = false; 221 try { TIFFField.getTypeName(MAX_TYPE + 1); } 222 catch (IllegalArgumentException e) { ok = true; } 223 check(ok, "invalid data type number used"); 224 225 for (int type = MIN_TYPE; type <= MAX_TYPE; type++) { 226 String name = TIFFField.getTypeName(type); 227 check(TIFFField.getTypeByName(name) == type, "invalid type"); 228 } 229 230 for (int type = MIN_TYPE; type <= MAX_TYPE; type++) { 231 232 TIFFTag tag = new TIFFTag(NAME, NUM, 1 << type); 233 TIFFField f = new TIFFField(tag, type, 1); 234 check(f.getType() == type, "invalid type"); 235 236 // check that invalid data types can not be used 237 for (int type2 = MIN_TYPE; type2 <= MAX_TYPE; ++type2) { 238 if (type2 != type) { 239 ok = false; 240 try { new TIFFField(tag, type2, 1); } // invalid type 241 catch (IllegalArgumentException e) { ok = true; } 242 check(ok, "invalid type was successfully set"); 243 } 244 } 245 } 246 } 247 248 private void testGetAs() { 249 250 // test getAs...() methods 251 252 int type = TIFFTag.TIFF_SHORT; 253 TIFFTag tag = new TIFFTag(NAME, NUM, 1 << TIFFTag.TIFF_SHORT); 254 255 short v = 123; 256 TIFFField f = new TIFFField(tag, v); 257 258 check(f.getAsInt(0) == (int) v, "invalid int value"); 259 check(f.getAsLong(0) == (long) v, "invalid long value"); 260 check(f.getAsFloat(0) == (float) v, "invalid float value"); 261 check(f.getAsDouble(0) == (double) v, "invalid double value"); 262 check(f.getValueAsString(0).equals(Short.toString(v)), 263 "invalid string representation"); 264 265 check(f.getAsInts().length == 1, "inavlid array size"); 266 check((int) v == f.getAsInts()[0], "invalid int value"); 267 268 float fa[] = {0.01f, 1.01f}; 269 type = TIFFTag.TIFF_FLOAT; 270 f = new TIFFField( 271 new TIFFTag(NAME, NUM, 1 << type), type, fa.length, fa); 272 check(f.getCount() == fa.length, "invalid count"); 273 float fa2[] = f.getAsFloats(); 274 check(fa2.length == fa.length, "invalid array size"); 275 276 for (int i = 0; i < fa.length; i++) { 277 check(fa2[i] == fa[i], "invalid value"); 278 check(f.getAsDouble(i) == fa[i], "invalid value"); 279 check(f.getAsInt(i) == (int) fa[i], "invalid value"); // cast to int 280 check(f.getValueAsString(i).equals(Float.toString(fa[i])), 281 "invalid string representation"); 282 } 283 284 byte ba[] = {-1, -10, -100}; 285 type = TIFFTag.TIFF_BYTE; 286 f = new TIFFField( 287 new TIFFTag(NAME, NUM, 1 << type), type, ba.length, ba); 288 check(f.getCount() == ba.length, "invalid count"); 289 byte ba2[] = f.getAsBytes(); 290 check(ba2.length == ba.length, "invalid count"); 291 292 for (int i = 0; i < ba.length; i++) { 293 check(ba[i] == ba2[i], "invalid value"); 294 check(ba[i] == (byte) f.getAsDouble(i), "invalid value"); 295 check(ba[i] == (byte) f.getAsLong(i), "invalid value"); 296 297 int unsigned = ba[i] & 0xff; 298 check(f.getAsInt(i) == unsigned, "must be treated as unsigned"); 299 } 300 301 char ca[] = {'a', 'z', 0xffff}; 302 type = TIFFTag.TIFF_SHORT; 303 f = new TIFFField( 304 new TIFFTag(NAME, NUM, 1 << type), type, ca.length, ca); 305 check(f.getCount() == ca.length, "invalid count"); 306 char ca2[] = f.getAsChars(); 307 check(ba2.length == ba.length, "invalid count"); 308 309 for (int i = 0; i < ca.length; i++) { 310 check(ca[i] == ca2[i], "invalid value"); 311 check(ca[i] == (char) f.getAsDouble(i), "invalid value"); 312 check(ca[i] == (char) f.getAsLong(i), "invalid value"); 313 check(ca[i] == (char) f.getAsInt(i), "invalid value"); 314 } 315 316 type = TIFFTag.TIFF_DOUBLE; 317 double da[] = {0.1, 0.2, 0.3}; 318 f = new TIFFField( 319 new TIFFTag(NAME, NUM, 1 << type), type, da.length, da); 320 check(!f.isIntegral(), "isIntegral must be false"); 321 322 double da2[] = f.getAsDoubles(); 323 check(f.getData() instanceof double[], "invalid data type"); 324 double da3[] = (double[]) f.getData(); 325 check((da.length == da2.length) && 326 (da.length == da2.length) && 327 (da.length == f.getCount()), 328 "invalid data count"); 329 for (int i = 0; i < da.length; ++i) { 330 check(da[i] == da2[i], "invalid data"); 331 check(da[i] == da3[i], "invalid data"); 332 } 333 334 boolean ok = false; 335 try { f.getAsShorts(); } 336 catch (ClassCastException e) { ok = true; } 337 check(ok, "invalid data cast"); 338 339 ok = false; 340 try { f.getAsRationals(); } 341 catch (ClassCastException e) { ok = true; } 342 check(ok, "invalid data cast"); 343 344 ok = false; 345 try { TIFFField.createArrayForType(TIFFTag.MIN_DATATYPE - 1, 1); } 346 catch (IllegalArgumentException e) { ok = true; } 347 check(ok, "can create array with invalid datatype"); 348 349 ok = false; 350 try { TIFFField.createArrayForType(TIFFTag.MAX_DATATYPE + 1, 1); } 351 catch (IllegalArgumentException e) { ok = true; } 352 check(ok, "can create array with invalid datatype"); 353 354 ok = false; 355 try { TIFFField.createArrayForType(TIFFTag.TIFF_FLOAT, -1); } 356 catch (IllegalArgumentException e) { ok = true; } 357 check(ok, "can create array with negative count"); 358 359 int n = 3; 360 Object 361 RA = TIFFField.createArrayForType(TIFFTag.TIFF_RATIONAL, n), 362 SRA = TIFFField.createArrayForType(TIFFTag.TIFF_SRATIONAL, n); 363 check(RA instanceof long[][], "invalid data type"); 364 check(SRA instanceof int[][], "invalid data type"); 365 366 long ra[][] = (long[][]) RA; 367 int sra[][] = (int[][]) SRA; 368 check((ra.length == n) && (sra.length == n), "invalid data size"); 369 for (int i = 0; i < n; i++) { 370 check((ra[i].length == 2) && (sra[i].length == 2), 371 "invalid data size"); 372 ra[i][0] = 1; ra[i][1] = 5 + i; 373 sra[i][0] = -1; sra[i][1] = 5 + i; 374 } 375 376 type = TIFFTag.TIFF_RATIONAL; 377 TIFFField f1 = new TIFFField( 378 new TIFFTag(NAME, NUM, 1 << type), type, n, ra); 379 type = TIFFTag.TIFF_SRATIONAL; 380 TIFFField f2 = new TIFFField( 381 new TIFFTag(NAME, NUM, 1 << type), type, n, sra); 382 383 check((f1.getCount() == ra.length) && (f2.getCount() == sra.length), 384 "invalid data count"); 385 386 check(f1.getAsRationals().length == n, "invalid data count"); 387 check(f2.getAsSRationals().length == n, "invalid data count"); 388 for (int i = 0; i < n; i++) { 389 long r[] = f1.getAsRational(i); 390 check(r.length == 2, "invalid data format"); 391 check((r[0] == 1) && (r[1] == i + 5), "invalid data"); 392 393 int sr[] = f2.getAsSRational(i); 394 check(sr.length == 2, "invalid data format"); 395 check((sr[0] == -1) && (sr[1] == i + 5), "invalid data"); 396 397 // check string representation 398 String s = Long.toString(r[0]) + "/" + Long.toString(r[1]); 399 check(s.equals(f1.getValueAsString(i)), 400 "invalid string representation"); 401 402 s = Integer.toString(sr[0]) + "/" + Integer.toString(sr[1]); 403 check(s.equals(f2.getValueAsString(i)), 404 "invalid string representation"); 405 406 // see the documentation for getAsInt: 407 // TIFF_SRATIONAL or TIFF_RATIONAL format are evaluated 408 // by dividing the numerator into the denominator using 409 // double-precision arithmetic and then casting to int 410 check(f1.getAsInt(i) == (int)(r[0] / r[1]), 411 "invalid result for getAsInt"); 412 check(f2.getAsInt(i) == (int)(r[0] / r[1]), 413 "invalid result for getAsInt"); 414 } 415 416 ok = false; 417 try { f1.getAsRational(ra.length); } 418 catch (ArrayIndexOutOfBoundsException e) { ok = true; } 419 check(ok, "invalid index"); 420 421 String sa[] = {"-1.e-25", "22", "-1.23E5"}; 422 type = TIFFTag.TIFF_ASCII; 423 f = new TIFFField( 424 new TIFFTag(NAME, NUM, 1 << type), type, sa.length, sa); 425 426 // test clone() method 427 TIFFField cloned = null; 428 try { cloned = f.clone(); } catch (CloneNotSupportedException e) { 429 throw new RuntimeException(e); 430 } 431 432 check(f.getCount() == cloned.getCount(), "invalid cloned field count"); 433 434 check(f.getCount() == sa.length, "invalid data count"); 435 for (int i = 0; i < sa.length; i++) { 436 check(sa[i].equals(f.getAsString(i)), "invalid data"); 437 // see docs: "data in TIFF_ASCII format will be parsed as by 438 // the Double.parseDouble method, with the result cast to int" 439 check(f.getAsInt(i) == 440 (int) Double.parseDouble(sa[i]), "invalid data"); 441 check(f.getAsDouble(i) == Double.parseDouble(sa[i]), "invalid data"); 442 443 check(sa[i].equals(cloned.getAsString(i)), "invalid cloned data"); 444 } 445 } 446 447 private void testCreateFromNode() { 448 449 int type = TIFFTag.TIFF_LONG; 450 451 List<TIFFTag> tags = new ArrayList<>(); 452 int v = 1234567; 453 TIFFTag tag = new TIFFTag(NAME, NUM, 1 << type); 454 tags.add(tag); 455 TIFFTagSet ts = new TIFFTagSet(tags); 456 457 boolean ok = false; 458 try { TIFFField.createFromMetadataNode(ts, null); } 459 catch (NullPointerException e) { ok = true; } 460 check(ok, "can create TIFFField from a null node"); 461 462 TIFFField f = new TIFFField(tag, v); 463 Node node = f.getAsNativeNode(); 464 check(node.getNodeName().equals(f.getClass().getSimpleName()), 465 "invalid node name"); 466 467 NamedNodeMap attrs = node.getAttributes(); 468 for (int i = 0; i < attrs.getLength(); i++) { 469 String an = attrs.item(i).getNodeName().toLowerCase(); 470 String av = attrs.item(i).getNodeValue(); 471 if (an.contains("name")) { 472 check(av.equals(NAME), "invalid tag name"); 473 } else if (an.contains("number")) { 474 check(av.equals(Integer.toString(NUM)), "invalid tag number"); 475 } 476 } 477 478 // invalid node 479 IIOMetadataNode nok = new IIOMetadataNode("NOK"); 480 481 ok = false; 482 try { TIFFField.createFromMetadataNode(ts, nok); } 483 catch (IllegalArgumentException e) { ok = true; } 484 check(ok, CONSTRUCT + "invalid node name"); 485 486 TIFFField f2 = TIFFField.createFromMetadataNode(ts, node); 487 check(f2.getType() == type, "invalid type"); 488 check(f2.getTagNumber() == NUM, "invalid tag number"); 489 check(f2.getTag().getName().equals(NAME), "invalid tag name"); 490 check(f2.getCount() == 1, "invalid count"); 491 check(f2.getAsInt(0) == v, "invalid value"); 492 } 493 494 public static void main(String[] args) { 495 496 TIFFFieldTest test = new TIFFFieldTest(); 497 test.testConstructors(); 498 test.testCreateFromNode(); 499 test.testTypes(); 500 test.testGetAs(); 501 } 502 }