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 8149562 8169725 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 + "negative value"); 69 70 ok = false; 71 try { new TIFFField(tag, 1L << 32); } 72 catch (IllegalArgumentException e) { ok = true; } 73 check(ok, CONSTRUCT + "value > 0xffffffff"); 74 75 ok = false; 76 try { 77 TIFFTag t = new TIFFTag(NAME, NUM, 1 << TIFFTag.TIFF_SHORT); 78 new TIFFField(t, 0x10000); 79 } catch (IllegalArgumentException e) { ok = true; } 80 check(ok, CONSTRUCT + "value 0x10000 incompatible with TIFF_SHORT"); 81 82 ok = false; 83 try { 84 TIFFTag t = new TIFFTag(NAME, NUM, 1 << TIFFTag.TIFF_LONG); 85 new TIFFField(t, 0xffff); 86 } catch (IllegalArgumentException e) { ok = true; } 87 check(ok, CONSTRUCT + "value 0xffff incompatible with TIFF_LONG"); 88 89 // check value type recognition 90 int v = 1 << 16; 91 f = new TIFFField(tag, v - 1); 92 check(f.getType() == TIFFTag.TIFF_SHORT, "must be treated as short"); 93 check(f.isIntegral(), "must be integral"); 94 f = new TIFFField(tag, v); 95 check(f.getType() == TIFFTag.TIFF_LONG, "must be treated as long"); 96 97 // other checks 98 check(f.getAsLongs().length == 1, "invalid long[] size"); 99 check(f.isIntegral(), "must be integral"); 100 check((f.getDirectory() == null) && !f.hasDirectory(), 101 "must not have directory"); 102 check(f.getValueAsString(0).equals(String.valueOf(v)), 103 "invalid string representation of value"); 104 check(f.getTag().getNumber() == f.getTagNumber(), 105 "invalid tag number"); 106 check(f.getCount() == 1, "invalid count"); 107 check(f.getTagNumber() == NUM, "invalid tag number"); 108 109 // constructor: TIFFField(tag, type, count) 110 int type = TIFFTag.TIFF_SHORT; 111 112 ok = false; 113 try { new TIFFField(null, type, 1); } 114 catch (NullPointerException e) { ok = true; } 115 check(ok, CONSTRUCT + "null tag"); 116 117 ok = false; 118 try { new TIFFField(tag, MAX_TYPE + 1, 1); } 119 catch (IllegalArgumentException e) { ok = true; } 120 check(ok, CONSTRUCT + "invalid type tag"); 121 122 // check that count == 1 for TIFF_IFD_POINTER 123 ok = false; 124 try { new TIFFField(tag, TIFFTag.TIFF_IFD_POINTER, 0); } 125 catch (IllegalArgumentException e) { ok = true; } 126 check(ok, "only count = 1 should be allowed for IFDPointer"); 127 128 ok = false; 129 try { new TIFFField(tag, TIFFTag.TIFF_IFD_POINTER, 2); } 130 catch (IllegalArgumentException e) { ok = true; } 131 check(ok, "only count = 1 should be allowed for IFDPointer"); 132 133 // check that count == 0 is not allowed for TIFF_RATIONAL, TIFF_SRATIONAL 134 // (see fix for JDK-8149120) 135 ok = false; 136 try { new TIFFField(tag, TIFFTag.TIFF_RATIONAL, 0); } 137 catch (IllegalArgumentException e) { ok = true; } 138 check(ok, "count = 0 should not be allowed for Rational"); 139 140 ok = false; 141 try { new TIFFField(tag, TIFFTag.TIFF_SRATIONAL, 0); } 142 catch (IllegalArgumentException e) { ok = true; } 143 check(ok, "count = 0 should not be allowed for SRational"); 144 145 ok = false; 146 try { new TIFFField(tag, type, -1); } 147 catch (IllegalArgumentException e) { ok = true; } 148 check(ok, CONSTRUCT + "with invalid data count"); 149 150 f = new TIFFField(tag, type, 0); 151 check(f.getCount() == 0, "invalid count"); 152 check(!f.hasDirectory(), "must not have directory"); 153 154 // constructor: TIFFField(tag, type, count, data) 155 double a[] = {0.1, 0.2, 0.3}; 156 ok = false; 157 try { new TIFFField(null, TIFFTag.TIFF_DOUBLE, a.length, a); } 158 catch (NullPointerException e) { ok = true; } 159 check(ok, CONSTRUCT + "null tag"); 160 161 ok = false; 162 try { new TIFFField(tag, type, a.length - 1, a); } 163 catch (IllegalArgumentException e) { ok = true; } 164 check(ok, CONSTRUCT + "invalid data count"); 165 166 String a2[] = {"one", "two"}; 167 ok = false; 168 try { new TIFFField(tag, type, 2, a2); } 169 catch (IllegalArgumentException e) { ok = true; } 170 check(ok, CONSTRUCT + "invalid data type"); 171 check((f.getDirectory() == null) && !f.hasDirectory(), 172 "must not have directory"); 173 174 // constructor: TIFFField(tag, type, offset, dir) 175 List<TIFFTag> tags = new ArrayList<>(); 176 tags.add(tag); 177 TIFFTagSet sets[] = {new TIFFTagSet(tags)}; 178 TIFFDirectory dir = new TIFFDirectory(sets, null); 179 180 ok = false; 181 try { new TIFFField(null, type, 4L, dir); } 182 catch (NullPointerException e) { ok = true; } 183 check(ok, CONSTRUCT + "null tag"); 184 185 ok = false; 186 try { new TIFFField(tag, type, 0L, dir); } 187 catch (IllegalArgumentException e) { ok = true; } 188 check(ok, CONSTRUCT + "non-positive offset"); 189 190 long offset = 4; 191 192 for (int t = MIN_TYPE; t <= MAX_TYPE; t++) { 193 194 tag = new TIFFTag(NAME, NUM, 1 << t); 195 196 // only TIFF_LONG and TIFF_IFD_POINTER types are allowed 197 if (t == TIFFTag.TIFF_LONG || t == TIFFTag.TIFF_IFD_POINTER) { 198 199 f = new TIFFField(tag, t, offset, dir); 200 check(f.hasDirectory(), "must have directory"); 201 202 check(f.getDirectory().getTag(NUM).getName().equals(NAME), 203 "invalid tag name"); 204 205 check(f.getCount() == 1, "invalid count"); 206 check(f.getAsLong(0) == offset, "invalid offset"); 207 } else { 208 ok = false; 209 try { new TIFFField(tag, t, offset, dir); } 210 catch (IllegalArgumentException e) { ok = true; } 211 check(ok, CONSTRUCT + "invalid data type"); 212 } 213 } 214 215 type = TIFFTag.TIFF_IFD_POINTER; 216 tag = new TIFFTag(NAME, NUM, 1 << type); 217 ok = false; 218 try { new TIFFField(tag, type, offset, null); } 219 catch (NullPointerException e) { ok = true; } 220 check(ok, CONSTRUCT + "null TIFFDirectory"); 221 222 type = TIFFTag.TIFF_LONG; 223 tag = new TIFFTag(NAME, NUM, 1 << type); 224 ok = false; 225 try { new TIFFField(tag, type, offset, null); } 226 catch (NullPointerException e) { ok = true; } 227 check(ok, CONSTRUCT + "null TIFFDirectory"); 228 } 229 230 private void testTypes() { 231 232 // test getTypeName(), getTypeByName() methods 233 234 boolean ok = false; 235 try { TIFFField.getTypeName(MIN_TYPE - 1); } 236 catch (IllegalArgumentException e) { ok = true; } 237 check(ok, "invalid data type number used"); 238 239 ok = false; 240 try { TIFFField.getTypeName(MAX_TYPE + 1); } 241 catch (IllegalArgumentException e) { ok = true; } 242 check(ok, "invalid data type number used"); 243 244 for (int type = MIN_TYPE; type <= MAX_TYPE; type++) { 245 String name = TIFFField.getTypeName(type); 246 check(TIFFField.getTypeByName(name) == type, "invalid type"); 247 } 248 249 for (int type = MIN_TYPE; type <= MAX_TYPE; type++) { 250 251 TIFFTag tag = new TIFFTag(NAME, NUM, 1 << type); 252 TIFFField f = new TIFFField(tag, type, 1); 253 check(f.getType() == type, "invalid type"); 254 255 // check that invalid data types can not be used 256 for (int type2 = MIN_TYPE; type2 <= MAX_TYPE; ++type2) { 257 if (type2 != type) { 258 ok = false; 259 try { new TIFFField(tag, type2, 1); } // invalid type 260 catch (IllegalArgumentException e) { ok = true; } 261 check(ok, "invalid type was successfully set"); 262 } 263 } 264 } 265 } 266 267 private void testGetAs() { 268 269 // test getAs...() methods 270 271 int type = TIFFTag.TIFF_SHORT; 272 TIFFTag tag = new TIFFTag(NAME, NUM, 1 << TIFFTag.TIFF_SHORT); 273 274 short v = 123; 275 TIFFField f = new TIFFField(tag, v); 276 277 check(f.getAsInt(0) == (int) v, "invalid int value"); 278 check(f.getAsLong(0) == (long) v, "invalid long value"); 279 check(f.getAsFloat(0) == (float) v, "invalid float value"); 280 check(f.getAsDouble(0) == (double) v, "invalid double value"); 281 check(f.getValueAsString(0).equals(Short.toString(v)), 282 "invalid string representation"); 283 284 check(f.getAsInts().length == 1, "inavlid array size"); 285 check((int) v == f.getAsInts()[0], "invalid int value"); 286 287 float fa[] = {0.01f, 1.01f}; 288 type = TIFFTag.TIFF_FLOAT; 289 f = new TIFFField( 290 new TIFFTag(NAME, NUM, 1 << type), type, fa.length, fa); 291 check(f.getCount() == fa.length, "invalid count"); 292 float fa2[] = f.getAsFloats(); 293 check(fa2.length == fa.length, "invalid array size"); 294 295 for (int i = 0; i < fa.length; i++) { 296 check(fa2[i] == fa[i], "invalid value"); 297 check(f.getAsDouble(i) == fa[i], "invalid value"); 298 check(f.getAsInt(i) == (int) fa[i], "invalid value"); // cast to int 299 check(f.getValueAsString(i).equals(Float.toString(fa[i])), 300 "invalid string representation"); 301 } 302 303 byte ba[] = {-1, -10, -100}; 304 type = TIFFTag.TIFF_BYTE; 305 f = new TIFFField( 306 new TIFFTag(NAME, NUM, 1 << type), type, ba.length, ba); 307 check(f.getCount() == ba.length, "invalid count"); 308 byte ba2[] = f.getAsBytes(); 309 check(ba2.length == ba.length, "invalid count"); 310 311 for (int i = 0; i < ba.length; i++) { 312 check(ba[i] == ba2[i], "invalid value"); 313 check(ba[i] == (byte) f.getAsDouble(i), "invalid value"); 314 check(ba[i] == (byte) f.getAsLong(i), "invalid value"); 315 316 int unsigned = ba[i] & 0xff; 317 check(f.getAsInt(i) == unsigned, "must be treated as unsigned"); 318 } 319 320 char ca[] = {'a', 'z', 0xffff}; 321 type = TIFFTag.TIFF_SHORT; 322 f = new TIFFField( 323 new TIFFTag(NAME, NUM, 1 << type), type, ca.length, ca); 324 check(f.getCount() == ca.length, "invalid count"); 325 char ca2[] = f.getAsChars(); 326 check(ba2.length == ba.length, "invalid count"); 327 328 for (int i = 0; i < ca.length; i++) { 329 check(ca[i] == ca2[i], "invalid value"); 330 check(ca[i] == (char) f.getAsDouble(i), "invalid value"); 331 check(ca[i] == (char) f.getAsLong(i), "invalid value"); 332 check(ca[i] == (char) f.getAsInt(i), "invalid value"); 333 } 334 335 type = TIFFTag.TIFF_DOUBLE; 336 double da[] = {0.1, 0.2, 0.3}; 337 f = new TIFFField( 338 new TIFFTag(NAME, NUM, 1 << type), type, da.length, da); 339 check(!f.isIntegral(), "isIntegral must be false"); 340 341 double da2[] = f.getAsDoubles(); 342 check(f.getData() instanceof double[], "invalid data type"); 343 double da3[] = (double[]) f.getData(); 344 check((da.length == da2.length) && 345 (da.length == da2.length) && 346 (da.length == f.getCount()), 347 "invalid data count"); 348 for (int i = 0; i < da.length; ++i) { 349 check(da[i] == da2[i], "invalid data"); 350 check(da[i] == da3[i], "invalid data"); 351 } 352 353 boolean ok = false; 354 try { f.getAsShorts(); } 355 catch (ClassCastException e) { ok = true; } 356 check(ok, "invalid data cast"); 357 358 ok = false; 359 try { f.getAsRationals(); } 360 catch (ClassCastException e) { ok = true; } 361 check(ok, "invalid data cast"); 362 363 ok = false; 364 try { TIFFField.createArrayForType(TIFFTag.MIN_DATATYPE - 1, 1); } 365 catch (IllegalArgumentException e) { ok = true; } 366 check(ok, "can create array with invalid datatype"); 367 368 ok = false; 369 try { TIFFField.createArrayForType(TIFFTag.MAX_DATATYPE + 1, 1); } 370 catch (IllegalArgumentException e) { ok = true; } 371 check(ok, "can create array with invalid datatype"); 372 373 ok = false; 374 try { TIFFField.createArrayForType(TIFFTag.TIFF_FLOAT, -1); } 375 catch (IllegalArgumentException e) { ok = true; } 376 check(ok, "can create array with negative count"); 377 378 int n = 3; 379 Object 380 RA = TIFFField.createArrayForType(TIFFTag.TIFF_RATIONAL, n), 381 SRA = TIFFField.createArrayForType(TIFFTag.TIFF_SRATIONAL, n); 382 check(RA instanceof long[][], "invalid data type"); 383 check(SRA instanceof int[][], "invalid data type"); 384 385 long ra[][] = (long[][]) RA; 386 int sra[][] = (int[][]) SRA; 387 check((ra.length == n) && (sra.length == n), "invalid data size"); 388 for (int i = 0; i < n; i++) { 389 check((ra[i].length == 2) && (sra[i].length == 2), 390 "invalid data size"); 391 ra[i][0] = 1; ra[i][1] = 5 + i; 392 sra[i][0] = -1; sra[i][1] = 5 + i; 393 } 394 395 type = TIFFTag.TIFF_RATIONAL; 396 TIFFField f1 = new TIFFField( 397 new TIFFTag(NAME, NUM, 1 << type), type, n, ra); 398 type = TIFFTag.TIFF_SRATIONAL; 399 TIFFField f2 = new TIFFField( 400 new TIFFTag(NAME, NUM, 1 << type), type, n, sra); 401 402 check((f1.getCount() == ra.length) && (f2.getCount() == sra.length), 403 "invalid data count"); 404 405 check(f1.getAsRationals().length == n, "invalid data count"); 406 check(f2.getAsSRationals().length == n, "invalid data count"); 407 for (int i = 0; i < n; i++) { 408 long r[] = f1.getAsRational(i); 409 check(r.length == 2, "invalid data format"); 410 check((r[0] == 1) && (r[1] == i + 5), "invalid data"); 411 412 int sr[] = f2.getAsSRational(i); 413 check(sr.length == 2, "invalid data format"); 414 check((sr[0] == -1) && (sr[1] == i + 5), "invalid data"); 415 416 // check string representation 417 String s = Long.toString(r[0]) + "/" + Long.toString(r[1]); 418 check(s.equals(f1.getValueAsString(i)), 419 "invalid string representation"); 420 421 s = Integer.toString(sr[0]) + "/" + Integer.toString(sr[1]); 422 check(s.equals(f2.getValueAsString(i)), 423 "invalid string representation"); 424 425 // see the documentation for getAsInt: 426 // TIFF_SRATIONAL or TIFF_RATIONAL format are evaluated 427 // by dividing the numerator into the denominator using 428 // double-precision arithmetic and then casting to int 429 check(f1.getAsInt(i) == (int)(r[0] / r[1]), 430 "invalid result for getAsInt"); 431 check(f2.getAsInt(i) == (int)(r[0] / r[1]), 432 "invalid result for getAsInt"); 433 } 434 435 ok = false; 436 try { f1.getAsRational(ra.length); } 437 catch (ArrayIndexOutOfBoundsException e) { ok = true; } 438 check(ok, "invalid index"); 439 440 String sa[] = {"-1.e-25", "22", "-1.23E5"}; 441 type = TIFFTag.TIFF_ASCII; 442 f = new TIFFField( 443 new TIFFTag(NAME, NUM, 1 << type), type, sa.length, sa); 444 445 // test clone() method 446 TIFFField cloned = null; 447 try { cloned = f.clone(); } catch (CloneNotSupportedException e) { 448 throw new RuntimeException(e); 449 } 450 451 check(f.getCount() == cloned.getCount(), "invalid cloned field count"); 452 453 check(f.getCount() == sa.length, "invalid data count"); 454 for (int i = 0; i < sa.length; i++) { 455 check(sa[i].equals(f.getAsString(i)), "invalid data"); 456 // see docs: "data in TIFF_ASCII format will be parsed as by 457 // the Double.parseDouble method, with the result cast to int" 458 check(f.getAsInt(i) == 459 (int) Double.parseDouble(sa[i]), "invalid data"); 460 check(f.getAsDouble(i) == Double.parseDouble(sa[i]), "invalid data"); 461 462 check(sa[i].equals(cloned.getAsString(i)), "invalid cloned data"); 463 } 464 } 465 466 private void testCreateFromNode() { 467 468 int type = TIFFTag.TIFF_LONG; 469 470 List<TIFFTag> tags = new ArrayList<>(); 471 int v = 1234567; 472 TIFFTag tag = new TIFFTag(NAME, NUM, 1 << type); 473 tags.add(tag); 474 TIFFTagSet ts = new TIFFTagSet(tags); 475 476 boolean ok = false; 477 try { 478 TIFFField.createFromMetadataNode(ts, null); 479 } catch (IllegalArgumentException e) { 480 // createFromMetadataNode() formerly threw a NullPointerException 481 // if its Node parameter was null, but the specification has been 482 // modified to allow only IllegalArgumentExceptions, perhaps with 483 // a cause set. In the present invocation the cause would be set 484 // to a NullPointerException but this is not explicitly specified 485 // hence not verified here. 486 ok = true; 487 } 488 check(ok, "can create TIFFField from a null node"); 489 490 TIFFField f = new TIFFField(tag, v); 491 Node node = f.getAsNativeNode(); 492 check(node.getNodeName().equals(f.getClass().getSimpleName()), 493 "invalid node name"); 494 495 NamedNodeMap attrs = node.getAttributes(); 496 for (int i = 0; i < attrs.getLength(); i++) { 497 String an = attrs.item(i).getNodeName().toLowerCase(); 498 String av = attrs.item(i).getNodeValue(); 499 if (an.contains("name")) { 500 check(av.equals(NAME), "invalid tag name"); 501 } else if (an.contains("number")) { 502 check(av.equals(Integer.toString(NUM)), "invalid tag number"); 503 } 504 } 505 506 // invalid node 507 IIOMetadataNode nok = new IIOMetadataNode("NOK"); 508 509 ok = false; 510 try { TIFFField.createFromMetadataNode(ts, nok); } 511 catch (IllegalArgumentException e) { ok = true; } 512 check(ok, CONSTRUCT + "invalid node name"); 513 514 TIFFField f2 = TIFFField.createFromMetadataNode(ts, node); 515 check(f2.getType() == type, "invalid type"); 516 check(f2.getTagNumber() == NUM, "invalid tag number"); 517 check(f2.getTag().getName().equals(NAME), "invalid tag name"); 518 check(f2.getCount() == 1, "invalid count"); 519 check(f2.getAsInt(0) == v, "invalid value"); 520 } 521 522 public static void main(String[] args) { 523 524 TIFFFieldTest test = new TIFFFieldTest(); 525 test.testConstructors(); 526 test.testCreateFromNode(); 527 test.testTypes(); 528 test.testGetAs(); 529 } 530 }