001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017package org.apache.commons.imaging.formats.tiff.write; 018 019import static org.apache.commons.imaging.formats.tiff.constants.TiffConstants.TIFF_ENTRY_MAX_VALUE_LENGTH; 020 021import java.io.IOException; 022import java.nio.ByteOrder; 023import java.util.Arrays; 024 025import org.apache.commons.imaging.ImagingException; 026import org.apache.commons.imaging.common.BinaryOutputStream; 027import org.apache.commons.imaging.formats.tiff.fieldtypes.AbstractFieldType; 028import org.apache.commons.imaging.formats.tiff.taginfos.TagInfo; 029 030public class TiffOutputField { 031 private static final String NEWLINE = System.lineSeparator(); 032 033 protected static TiffOutputField createOffsetField(final TagInfo tagInfo, final ByteOrder byteOrder) throws ImagingException { 034 return new TiffOutputField(tagInfo, AbstractFieldType.LONG, 1, AbstractFieldType.LONG.writeData(0, byteOrder)); 035 } 036 037 public final int tag; 038 public final TagInfo tagInfo; 039 public final AbstractFieldType abstractFieldType; 040 public final int count; 041 private byte[] bytes; 042 private final AbstractTiffOutputItem.Value separateValueItem; 043 044 private int sortHint = -1; 045 046 public TiffOutputField(final int tag, final TagInfo tagInfo, final AbstractFieldType abstractFieldType, final int count, final byte[] bytes) { 047 this.tag = tag; 048 this.tagInfo = tagInfo; 049 this.abstractFieldType = abstractFieldType; 050 this.count = count; 051 this.bytes = bytes; 052 053 if (isLocalValue()) { 054 separateValueItem = null; 055 } else { 056 final String name = "Field Separate value (" + tagInfo.getDescription() + ")"; 057 separateValueItem = new AbstractTiffOutputItem.Value(name, bytes); 058 } 059 } 060 061 public TiffOutputField(final TagInfo tagInfo, final AbstractFieldType abstractFieldType, final int count, final byte[] bytes) { 062 this(tagInfo.tag, tagInfo, abstractFieldType, count, bytes); 063 } 064 065 public boolean bytesEqual(final byte[] data) { 066 return Arrays.equals(bytes, data); 067 } 068 069 protected AbstractTiffOutputItem getSeperateValue() { 070 return separateValueItem; 071 } 072 073 public int getSortHint() { 074 return sortHint; 075 } 076 077 protected final boolean isLocalValue() { 078 return bytes.length <= TIFF_ENTRY_MAX_VALUE_LENGTH; 079 } 080 081 protected void setData(final byte[] bytes) throws ImagingException { 082 // if (tagInfo.isUnknown()) 083 // Debug.debug("unknown tag(0x" + Integer.toHexString(tag) 084 // + ") setData", bytes); 085 086 if (this.bytes.length != bytes.length) { 087 throw new ImagingException("Cannot change size of value."); 088 } 089 090 // boolean wasLocalValue = isLocalValue(); 091 this.bytes = bytes; 092 if (separateValueItem != null) { 093 separateValueItem.updateValue(bytes); 094 } 095 // if (isLocalValue() != wasLocalValue) 096 // throw new Error("Bug. Locality disrupted! " 097 // + tagInfo.getDescription()); 098 } 099 100 public void setSortHint(final int sortHint) { 101 this.sortHint = sortHint; 102 } 103 104 @Override 105 public String toString() { 106 return toString(null); 107 } 108 109 public String toString(String prefix) { 110 if (prefix == null) { 111 prefix = ""; 112 } 113 final StringBuilder result = new StringBuilder(); 114 115 result.append(prefix); 116 result.append(tagInfo); 117 result.append(NEWLINE); 118 119 result.append(prefix); 120 result.append("count: "); 121 result.append(count); 122 result.append(NEWLINE); 123 124 result.append(prefix); 125 result.append(abstractFieldType); 126 result.append(NEWLINE); 127 128 return result.toString(); 129 } 130 131 protected void writeField(final BinaryOutputStream bos) throws IOException, ImagingException { 132 bos.write2Bytes(tag); 133 bos.write2Bytes(abstractFieldType.getType()); 134 bos.write4Bytes(count); 135 136 if (isLocalValue()) { 137 if (separateValueItem != null) { 138 throw new ImagingException("Unexpected separate value item."); 139 } 140 if (bytes.length > 4) { 141 throw new ImagingException("Local value has invalid length: " + bytes.length); 142 } 143 144 bos.write(bytes); 145 final int remainder = TIFF_ENTRY_MAX_VALUE_LENGTH - bytes.length; 146 for (int i = 0; i < remainder; i++) { 147 bos.write(0); 148 } 149 } else { 150 if (separateValueItem == null) { 151 throw new ImagingException("Missing separate value item."); 152 } 153 154 bos.write4Bytes((int) separateValueItem.getOffset()); 155 } 156 } 157}