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.fieldtypes;
018
019import java.nio.ByteOrder;
020import java.nio.charset.StandardCharsets;
021
022import org.apache.commons.imaging.ImageWriteException;
023import org.apache.commons.imaging.formats.tiff.TiffField;
024
025public class FieldTypeAscii extends FieldType {
026    public FieldTypeAscii(final int type, final String name) {
027        super(type, name, 1);
028    }
029
030    @Override
031    public Object getValue(final TiffField entry) {
032        // According to EXIF specification
033        // "2 = ASCII An 8-bit byte containing one 7-bit ASCII code. The final byte is terminated with NULL."
034        final byte[] bytes = entry.getByteArrayValue();
035        int nullCount = 1;
036        for (int i = 0; i < bytes.length - 1; i++) {
037            if (bytes[i] == 0) {
038                nullCount++;
039            }
040        }
041        final String[] strings = new String[nullCount];
042        int stringsAdded = 0;
043        strings[0] = ""; // if we have a 0 length string
044        int nextStringPos = 0;
045        // According to the Exiftool FAQ, http://www.metadataworkinggroup.org
046        // specifies that the TIFF ASCII fields are actually UTF-8.
047        // Exiftool however allows you to configure the charset used.
048        for (int i = 0; i < bytes.length; i++) {
049            if (bytes[i] == 0) {
050                final String string = new String(bytes, nextStringPos, i
051                        - nextStringPos, StandardCharsets.UTF_8);
052                strings[stringsAdded++] = string;
053                nextStringPos = i + 1;
054            }
055        }
056        if (nextStringPos < bytes.length) {
057            // Buggy file, string wasn't null terminated
058            final String string = new String(bytes, nextStringPos, bytes.length
059                    - nextStringPos, StandardCharsets.UTF_8);
060            strings[stringsAdded++] = string;
061        }
062        if (strings.length == 1) {
063            return strings[0];
064        }
065        return strings;
066    }
067
068    @Override
069    public byte[] writeData(final Object o, final ByteOrder byteOrder) throws ImageWriteException {
070        if (o instanceof byte[]) {
071            final byte[] bytes = (byte[]) o;
072            final byte[] result = new byte[bytes.length + 1];
073            System.arraycopy(bytes, 0, result, 0, bytes.length);
074            result[result.length - 1] = 0;
075            return result;
076        }
077        if (o instanceof String) {
078            final byte[] bytes = ((String) o).getBytes(StandardCharsets.UTF_8);
079            final byte[] result = new byte[bytes.length + 1];
080            System.arraycopy(bytes, 0, result, 0, bytes.length);
081            result[result.length - 1] = 0;
082            return result;
083        }
084        if (!(o instanceof String[])) {
085            throw new ImageWriteException("Unknown data type: " + o);
086        }
087        final String[] strings = (String[]) o;
088        int totalLength = 0;
089        for (final String string : strings) {
090            final byte[] bytes = string.getBytes(StandardCharsets.UTF_8);
091            totalLength += (bytes.length + 1);
092        }
093        final byte[] result = new byte[totalLength];
094        int position = 0;
095        for (final String string : strings) {
096            final byte[] bytes = string.getBytes(StandardCharsets.UTF_8);
097            System.arraycopy(bytes, 0, result, position, bytes.length);
098            position += (bytes.length + 1);
099        }
100        return result;
101    }
102
103}