blob: dfe3ddb7133dcb181d2037ac67e4eca6a58a4b24 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.commons.imaging.formats.tiff.taginfos;
import java.io.UnsupportedEncodingException;
import org.apache.commons.imaging.ImageReadException;
import org.apache.commons.imaging.ImageWriteException;
import org.apache.commons.imaging.common.BinaryConstants;
import org.apache.commons.imaging.common.BinaryFileFunctions;
import org.apache.commons.imaging.formats.tiff.TiffField;
import org.apache.commons.imaging.formats.tiff.constants.TiffDirectoryType;
import org.apache.commons.imaging.formats.tiff.fieldtypes.FieldType;
import org.apache.commons.imaging.util.Debug;
public final class TagInfoGpsText extends TagInfo
{
public TagInfoGpsText(String name, int tag, FieldType dataType, int length,
TiffDirectoryType exifDirectory)
{
super(name, tag, dataType, length, exifDirectory);
}
@Override
public boolean isText()
{
return true;
}
private static final class TextEncoding
{
public final byte prefix[];
public final String encodingNameLE;
public final String encodingNameBE;
public TextEncoding(final byte[] prefix, final String encodingNameLE,
final String encodingNameBE)
{
this.prefix = prefix;
this.encodingNameLE = encodingNameLE;
this.encodingNameBE = encodingNameBE;
}
public String getEncodingName(int byteOrder) {
if (byteOrder == BinaryConstants.BYTE_ORDER_BIG_ENDIAN) {
return encodingNameBE;
} else {
return encodingNameLE;
}
}
}
private static final TagInfoGpsText.TextEncoding TEXT_ENCODING_ASCII = new TextEncoding(
new byte[]{
0x41, 0x53, 0x43, 0x49, 0x49, 0x00, 0x00, 0x00,
}, "US-ASCII", "US-ASCII"); // ITU-T T.50 IA5
private static final TagInfoGpsText.TextEncoding TEXT_ENCODING_JIS = new TextEncoding(
new byte[]{
0x4A, 0x49, 0x53, 0x00, 0x00, 0x00, 0x00, 0x00,
}, "JIS", "JIS"); // JIS X208-1990
private static final TagInfoGpsText.TextEncoding TEXT_ENCODING_UNICODE = new TextEncoding(
new byte[]{
0x55, 0x4E, 0x49, 0x43, 0x4F, 0x44, 0x45, 0x00,
// Which Unicode encoding to use, UTF-8?
}, "UTF-16LE", "UTF-16BE"); // Unicode Standard
private static final TagInfoGpsText.TextEncoding TEXT_ENCODING_UNDEFINED = new TextEncoding(
new byte[]{
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// Try to interpret an undefined text as ISO-8859-1 (Latin)
}, "ISO-8859-1", "ISO-8859-1"); // Undefined
private static final TagInfoGpsText.TextEncoding TEXT_ENCODINGS[] = {
TEXT_ENCODING_ASCII, //
TEXT_ENCODING_JIS, //
TEXT_ENCODING_UNICODE, //
TEXT_ENCODING_UNDEFINED, //
};
@Override
public byte[] encodeValue(FieldType fieldType, Object value,
int byteOrder) throws ImageWriteException
{
if (!(value instanceof String))
throw new ImageWriteException("GPS text value not String: " + value
+ " (" + Debug.getType(value) + ")");
String s = (String) value;
try
{
// try ASCII, with NO prefix.
byte asciiBytes[] = s
.getBytes(TEXT_ENCODING_ASCII.getEncodingName(byteOrder));
String decodedAscii = new String(asciiBytes,
TEXT_ENCODING_ASCII.getEncodingName(byteOrder));
if (decodedAscii.equals(s))
{
// no unicode/non-ascii values.
byte result[] = new byte[asciiBytes.length
+ TEXT_ENCODING_ASCII.prefix.length];
System.arraycopy(TEXT_ENCODING_ASCII.prefix, 0, result, 0,
TEXT_ENCODING_ASCII.prefix.length);
System.arraycopy(asciiBytes, 0, result,
TEXT_ENCODING_ASCII.prefix.length,
asciiBytes.length);
return result;
}
else
{
// use unicode
byte unicodeBytes[] = s
.getBytes(TEXT_ENCODING_UNICODE.getEncodingName(byteOrder));
byte result[] = new byte[unicodeBytes.length
+ TEXT_ENCODING_UNICODE.prefix.length];
System.arraycopy(TEXT_ENCODING_UNICODE.prefix, 0, result,
0, TEXT_ENCODING_UNICODE.prefix.length);
System.arraycopy(unicodeBytes, 0, result,
TEXT_ENCODING_UNICODE.prefix.length,
unicodeBytes.length);
return result;
}
}
catch (UnsupportedEncodingException e)
{
throw new ImageWriteException(e.getMessage(), e);
}
}
@Override
public String getValue(TiffField entry) throws ImageReadException
{
if (entry.type == FIELD_TYPE_ASCII.type) {
Object object = FIELD_TYPE_ASCII.getSimpleValue(entry);
if (object instanceof String) {
return (String) object;
} else if (object instanceof String[]) {
// Use of arrays with the ASCII type
// should be extremely rare, and use of
// ASCII type in GPS fields should be
// forbidden. So assume the 2 never happen
// together and return incomplete strings if they do.
return ((String[]) object)[0];
} else {
throw new ImageReadException("Unexpected ASCII type decoded");
}
} else if (entry.type == FIELD_TYPE_UNDEFINED.type) {
/* later */
} else if (entry.type == FIELD_TYPE_BYTE.type) {
/* later */
} else {
Debug.debug("entry.type", entry.type);
Debug.debug("entry.directoryType", entry.directoryType);
Debug.debug("entry.type", entry.getDescriptionWithoutValue());
Debug.debug("entry.type", entry.fieldType);
throw new ImageReadException("GPS text field not encoded as bytes.");
}
byte bytes[] = entry.fieldType.getRawBytes(entry);
if (bytes.length < 8)
{
try
{
// try ASCII, with NO prefix.
return new String(bytes, "US-ASCII");
}
catch (UnsupportedEncodingException e)
{
throw new ImageReadException(
"GPS text field missing encoding prefix.");
}
}
for (int i = 0; i < TEXT_ENCODINGS.length; i++)
{
TagInfoGpsText.TextEncoding encoding = TEXT_ENCODINGS[i];
if (BinaryFileFunctions.compareBytes(bytes, 0, encoding.prefix,
0, encoding.prefix.length))
{
try
{
return new String(bytes, encoding.prefix.length,
bytes.length - encoding.prefix.length,
encoding.getEncodingName(entry.byteOrder));
}
catch (UnsupportedEncodingException e)
{
throw new ImageReadException(e.getMessage(), e);
}
}
}
try
{
// try ASCII, with NO prefix.
return new String(bytes, "US-ASCII");
}
catch (UnsupportedEncodingException e)
{
throw new ImageReadException("Unknown GPS text encoding prefix.");
}
}
}