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.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.AbstractBinaryOutputStream; 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 /** 066 * Return a copy of the data in this TIFF output field. 067 * @return a copy of the data in this TIFF output field. 068 */ 069 public byte[] getData() { 070 return Arrays.copyOf(this.bytes, this.bytes.length); 071 } 072 073 protected AbstractTiffOutputItem getSeperateValue() { 074 return separateValueItem; 075 } 076 077 public int getSortHint() { 078 return sortHint; 079 } 080 081 protected final boolean isLocalValue() { 082 return bytes.length <= ENTRY_MAX_VALUE_LENGTH; 083 } 084 085 /** 086 * Set the data for this TIFF output field. 087 * 088 * @param bytes TIFF output field data. 089 * @throws ImagingException if the length of the bytes array do not match. 090 */ 091 public void setData(final byte[] bytes) throws ImagingException { 092 // if (tagInfo.isUnknown()) 093 // Debug.debug("unknown tag(0x" + Integer.toHexString(tag) 094 // + ") setData", bytes); 095 096 if (this.bytes.length != bytes.length) { 097 throw new ImagingException("Cannot change size of value."); 098 } 099 100 // boolean wasLocalValue = isLocalValue(); 101 this.bytes = bytes; 102 if (separateValueItem != null) { 103 separateValueItem.updateValue(bytes); 104 } 105 // if (isLocalValue() != wasLocalValue) 106 // throw new Error("Bug. Locality disrupted! " 107 // + tagInfo.getDescription()); 108 } 109 110 public void setSortHint(final int sortHint) { 111 this.sortHint = sortHint; 112 } 113 114 @Override 115 public String toString() { 116 return toString(null); 117 } 118 119 public String toString(String prefix) { 120 if (prefix == null) { 121 prefix = ""; 122 } 123 final StringBuilder result = new StringBuilder(); 124 125 result.append(prefix); 126 result.append(tagInfo); 127 result.append(NEWLINE); 128 129 result.append(prefix); 130 result.append("count: "); 131 result.append(count); 132 result.append(NEWLINE); 133 134 result.append(prefix); 135 result.append(abstractFieldType); 136 result.append(NEWLINE); 137 138 return result.toString(); 139 } 140 141 protected void writeField(final AbstractBinaryOutputStream bos) throws IOException, ImagingException { 142 bos.write2Bytes(tag); 143 bos.write2Bytes(abstractFieldType.getType()); 144 bos.write4Bytes(count); 145 146 if (isLocalValue()) { 147 if (separateValueItem != null) { 148 throw new ImagingException("Unexpected separate value item."); 149 } 150 if (bytes.length > 4) { 151 throw new ImagingException("Local value has invalid length: " + bytes.length); 152 } 153 154 bos.write(bytes); 155 final int remainder = ENTRY_MAX_VALUE_LENGTH - bytes.length; 156 for (int i = 0; i < remainder; i++) { 157 bos.write(0); 158 } 159 } else { 160 if (separateValueItem == null) { 161 throw new ImagingException("Missing separate value item."); 162 } 163 164 bos.write4Bytes((int) separateValueItem.getOffset()); 165 } 166 } 167}