32 import java.util.Iterator; 33 import java.util.List; 34 import java.util.Set; 35 import javax.imageio.IIOException; 36 import javax.imageio.stream.ImageInputStream; 37 import javax.imageio.stream.ImageOutputStream; 38 import javax.imageio.plugins.tiff.BaselineTIFFTagSet; 39 import javax.imageio.plugins.tiff.TIFFDirectory; 40 import javax.imageio.plugins.tiff.TIFFField; 41 import javax.imageio.plugins.tiff.TIFFTag; 42 import javax.imageio.plugins.tiff.TIFFTagSet; 43 44 public class TIFFIFD extends TIFFDirectory { 45 private static final long MAX_SAMPLES_PER_PIXEL = 0xffff; 46 private static final long MAX_ASCII_SIZE = 0xffff; 47 48 private long stripOrTileByteCountsPosition = -1; 49 private long stripOrTileOffsetsPosition = -1; 50 private long lastPosition = -1; 51 52 53 /** 54 * Converts a {@code TIFFDirectory} to a {@code TIFFIFD}. 55 */ 56 public static TIFFIFD getDirectoryAsIFD(TIFFDirectory dir) { 57 if(dir instanceof TIFFIFD) { 58 return (TIFFIFD)dir; 59 } 60 61 TIFFIFD ifd = new TIFFIFD(Arrays.asList(dir.getTagSets()), 62 dir.getParentTag()); 63 TIFFField[] fields = dir.getTIFFFields(); 64 int numFields = fields.length; 65 for(int i = 0; i < numFields; i++) { 66 TIFFField f = fields[i]; 67 TIFFTag tag = f.getTag(); 68 if(tag.isIFDPointer()) { 69 TIFFDirectory subDir = null; 70 if (f.hasDirectory()) { 71 subDir = f.getDirectory(); 490 if (off + 16 > streamLength) { 491 throw new IIOException("JPEGACTables data out of stream"); 492 } 493 } 494 } 495 } 496 497 // Stream position initially at beginning, left at end 498 // if ignoreUnknownFields is true, do not load fields for which 499 // a tag cannot be found in an allowed TagSet. 500 public void initialize(ImageInputStream stream, boolean isPrimaryIFD, 501 boolean ignoreUnknownFields) throws IOException { 502 503 removeTIFFFields(); 504 505 long streamLength = stream.length(); 506 boolean haveStreamLength = streamLength != -1; 507 508 List<TIFFTagSet> tagSetList = getTagSetList(); 509 510 List<Object> entries = new ArrayList<>(); 511 Object[] entryData = new Object[1]; // allocate once for later reuse. 512 513 // Read the IFD entries, loading the field values which are no more than 514 // four bytes long, and storing the 4-byte offsets for the others. 515 int numEntries = stream.readUnsignedShort(); 516 for (int i = 0; i < numEntries; i++) { 517 // Read tag number, value type, and value count. 518 int tagNumber = stream.readUnsignedShort(); 519 int type = stream.readUnsignedShort(); 520 int sizeOfType; 521 try { 522 sizeOfType = TIFFTag.getSizeOfType(type); 523 } catch (IllegalArgumentException ignored) { 524 // Continue with the next IFD entry. 525 stream.skipBytes(4); 526 continue; 527 } 528 long longCount = stream.readUnsignedInt(); 529 530 // Get the associated TIFFTag. 531 TIFFTag tag = getTag(tagNumber, tagSetList); 532 533 // Ignore unknown fields, fields with unknown type, and fields 534 // with count out of int range. 535 if((tag == null && ignoreUnknownFields) 536 || (tag != null && !tag.isDataTypeOK(type)) 537 || longCount > Integer.MAX_VALUE) { 538 // Skip the value/offset so as to leave the stream 539 // position at the start of the next IFD entry. 540 stream.skipBytes(4); 541 542 // Continue with the next IFD entry. 543 continue; 544 } 545 546 int count = (int)longCount; 547 548 if (tag == null) { 549 tag = new TIFFTag(TIFFTag.UNKNOWN_TAG_NAME, tagNumber, 550 1 << type, count); 551 } else { 552 int expectedCount = tag.getCount(); | 32 import java.util.Iterator; 33 import java.util.List; 34 import java.util.Set; 35 import javax.imageio.IIOException; 36 import javax.imageio.stream.ImageInputStream; 37 import javax.imageio.stream.ImageOutputStream; 38 import javax.imageio.plugins.tiff.BaselineTIFFTagSet; 39 import javax.imageio.plugins.tiff.TIFFDirectory; 40 import javax.imageio.plugins.tiff.TIFFField; 41 import javax.imageio.plugins.tiff.TIFFTag; 42 import javax.imageio.plugins.tiff.TIFFTagSet; 43 44 public class TIFFIFD extends TIFFDirectory { 45 private static final long MAX_SAMPLES_PER_PIXEL = 0xffff; 46 private static final long MAX_ASCII_SIZE = 0xffff; 47 48 private long stripOrTileByteCountsPosition = -1; 49 private long stripOrTileOffsetsPosition = -1; 50 private long lastPosition = -1; 51 52 // 53 // A set of tag numbers corresponding to tags essential to decoding 54 // the image and metadata required to interpret its samples. 55 // 56 private static volatile Set<Integer> essentialTags = null; 57 58 private static void initializeEssentialTags() { 59 Set<Integer> tags = essentialTags; 60 if (tags == null) { 61 essentialTags = tags = Set.of( 62 BaselineTIFFTagSet.TAG_BITS_PER_SAMPLE, 63 BaselineTIFFTagSet.TAG_COLOR_MAP, 64 BaselineTIFFTagSet.TAG_COMPRESSION, 65 BaselineTIFFTagSet.TAG_EXTRA_SAMPLES, 66 BaselineTIFFTagSet.TAG_FILL_ORDER, 67 BaselineTIFFTagSet.TAG_ICC_PROFILE, 68 BaselineTIFFTagSet.TAG_IMAGE_LENGTH, 69 BaselineTIFFTagSet.TAG_IMAGE_WIDTH, 70 BaselineTIFFTagSet.TAG_JPEG_AC_TABLES, 71 BaselineTIFFTagSet.TAG_JPEG_DC_TABLES, 72 BaselineTIFFTagSet.TAG_JPEG_INTERCHANGE_FORMAT, 73 BaselineTIFFTagSet.TAG_JPEG_INTERCHANGE_FORMAT_LENGTH, 74 BaselineTIFFTagSet.TAG_JPEG_PROC, 75 BaselineTIFFTagSet.TAG_JPEG_Q_TABLES, 76 BaselineTIFFTagSet.TAG_JPEG_RESTART_INTERVAL, 77 BaselineTIFFTagSet.TAG_JPEG_TABLES, 78 BaselineTIFFTagSet.TAG_PHOTOMETRIC_INTERPRETATION, 79 BaselineTIFFTagSet.TAG_PLANAR_CONFIGURATION, 80 BaselineTIFFTagSet.TAG_PREDICTOR, 81 BaselineTIFFTagSet.TAG_REFERENCE_BLACK_WHITE, 82 BaselineTIFFTagSet.TAG_ROWS_PER_STRIP, 83 BaselineTIFFTagSet.TAG_SAMPLES_PER_PIXEL, 84 BaselineTIFFTagSet.TAG_SAMPLE_FORMAT, 85 BaselineTIFFTagSet.TAG_STRIP_BYTE_COUNTS, 86 BaselineTIFFTagSet.TAG_STRIP_OFFSETS, 87 BaselineTIFFTagSet.TAG_T4_OPTIONS, 88 BaselineTIFFTagSet.TAG_T6_OPTIONS, 89 BaselineTIFFTagSet.TAG_TILE_BYTE_COUNTS, 90 BaselineTIFFTagSet.TAG_TILE_LENGTH, 91 BaselineTIFFTagSet.TAG_TILE_OFFSETS, 92 BaselineTIFFTagSet.TAG_TILE_WIDTH, 93 BaselineTIFFTagSet.TAG_Y_CB_CR_COEFFICIENTS, 94 BaselineTIFFTagSet.TAG_Y_CB_CR_SUBSAMPLING 95 ); 96 } 97 } 98 99 /** 100 * Converts a {@code TIFFDirectory} to a {@code TIFFIFD}. 101 */ 102 public static TIFFIFD getDirectoryAsIFD(TIFFDirectory dir) { 103 if(dir instanceof TIFFIFD) { 104 return (TIFFIFD)dir; 105 } 106 107 TIFFIFD ifd = new TIFFIFD(Arrays.asList(dir.getTagSets()), 108 dir.getParentTag()); 109 TIFFField[] fields = dir.getTIFFFields(); 110 int numFields = fields.length; 111 for(int i = 0; i < numFields; i++) { 112 TIFFField f = fields[i]; 113 TIFFTag tag = f.getTag(); 114 if(tag.isIFDPointer()) { 115 TIFFDirectory subDir = null; 116 if (f.hasDirectory()) { 117 subDir = f.getDirectory(); 536 if (off + 16 > streamLength) { 537 throw new IIOException("JPEGACTables data out of stream"); 538 } 539 } 540 } 541 } 542 543 // Stream position initially at beginning, left at end 544 // if ignoreUnknownFields is true, do not load fields for which 545 // a tag cannot be found in an allowed TagSet. 546 public void initialize(ImageInputStream stream, boolean isPrimaryIFD, 547 boolean ignoreUnknownFields) throws IOException { 548 549 removeTIFFFields(); 550 551 long streamLength = stream.length(); 552 boolean haveStreamLength = streamLength != -1; 553 554 List<TIFFTagSet> tagSetList = getTagSetList(); 555 556 boolean ensureEssentialTags = false; 557 TIFFTagSet baselineTagSet = null; 558 if (isPrimaryIFD && ignoreUnknownFields 559 && !tagSetList.contains(BaselineTIFFTagSet.getInstance())) { 560 ensureEssentialTags = true; 561 initializeEssentialTags(); 562 baselineTagSet = BaselineTIFFTagSet.getInstance(); 563 } 564 565 List<Object> entries = new ArrayList<>(); 566 Object[] entryData = new Object[1]; // allocate once for later reuse. 567 568 // Read the IFD entries, loading the field values which are no more than 569 // four bytes long, and storing the 4-byte offsets for the others. 570 int numEntries = stream.readUnsignedShort(); 571 for (int i = 0; i < numEntries; i++) { 572 // Read tag number, value type, and value count. 573 int tagNumber = stream.readUnsignedShort(); 574 int type = stream.readUnsignedShort(); 575 int sizeOfType; 576 try { 577 sizeOfType = TIFFTag.getSizeOfType(type); 578 } catch (IllegalArgumentException ignored) { 579 // Continue with the next IFD entry. 580 stream.skipBytes(4); 581 continue; 582 } 583 long longCount = stream.readUnsignedInt(); 584 585 // Get the associated TIFFTag. 586 TIFFTag tag = getTag(tagNumber, tagSetList); 587 588 if (tag == null && ensureEssentialTags 589 && essentialTags.contains(tagNumber)) { 590 tag = baselineTagSet.getTag(tagNumber); 591 } 592 593 // Ignore unknown fields, fields with unknown type, and fields 594 // with count out of int range. 595 if((tag == null && ignoreUnknownFields) 596 || (tag != null && !tag.isDataTypeOK(type)) 597 || longCount > Integer.MAX_VALUE) { 598 // Skip the value/offset so as to leave the stream 599 // position at the start of the next IFD entry. 600 stream.skipBytes(4); 601 602 // Continue with the next IFD entry. 603 continue; 604 } 605 606 int count = (int)longCount; 607 608 if (tag == null) { 609 tag = new TIFFTag(TIFFTag.UNKNOWN_TAG_NAME, tagNumber, 610 1 << type, count); 611 } else { 612 int expectedCount = tag.getCount(); |