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