com.drew.lang.ByteArrayReader Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of metadata-extractor Show documentation
Show all versions of metadata-extractor Show documentation
Java library for extracting EXIF, IPTC, XMP, ICC and other metadata from image and video files.
/*
* Copyright 2002-2012 Drew Noakes
*
* Licensed 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.
*
* More information about this project is available at:
*
* http://drewnoakes.com/code/exif/
* http://code.google.com/p/metadata-extractor/
*/
package com.drew.lang;
import com.drew.lang.annotations.NotNull;
import java.io.UnsupportedEncodingException;
/**
* Provides methods to read specific values from a byte array, with a consistent, checked exception structure for
* issues.
*
* By default, the reader operates with Motorola byte order (big endianness). This can be changed by calling
* {@see setMotorolaByteOrder(boolean)}.
*
* @author Drew Noakes http://drewnoakes.com
* */
public class ByteArrayReader implements BufferReader
{
@NotNull
private final byte[] _buffer;
private boolean _isMotorolaByteOrder = true;
@SuppressWarnings({ "ConstantConditions" })
@com.drew.lang.annotations.SuppressWarnings(value = "EI_EXPOSE_REP2", justification = "Design intent")
public ByteArrayReader(@NotNull byte[] buffer)
{
if (buffer == null)
throw new NullPointerException();
_buffer = buffer;
}
public long getLength()
{
return _buffer.length;
}
public void setMotorolaByteOrder(boolean motorolaByteOrder)
{
_isMotorolaByteOrder = motorolaByteOrder;
}
public boolean isMotorolaByteOrder()
{
return _isMotorolaByteOrder;
}
public short getUInt8(int index) throws BufferBoundsException
{
checkBounds(index, 1);
return (short) (_buffer[index] & 255);
}
public byte getInt8(int index) throws BufferBoundsException
{
checkBounds(index, 1);
return _buffer[index];
}
public int getUInt16(int index) throws BufferBoundsException
{
checkBounds(index, 2);
if (_isMotorolaByteOrder) {
// Motorola - MSB first
return (_buffer[index ] << 8 & 0xFF00) |
(_buffer[index + 1] & 0xFF);
} else {
// Intel ordering - LSB first
return (_buffer[index + 1] << 8 & 0xFF00) |
(_buffer[index ] & 0xFF);
}
}
public short getInt16(int index) throws BufferBoundsException
{
checkBounds(index, 2);
if (_isMotorolaByteOrder) {
// Motorola - MSB first
return (short) (((short)_buffer[index ] << 8 & (short)0xFF00) |
((short)_buffer[index + 1] & (short)0xFF));
} else {
// Intel ordering - LSB first
return (short) (((short)_buffer[index + 1] << 8 & (short)0xFF00) |
((short)_buffer[index ] & (short)0xFF));
}
}
public long getUInt32(int index) throws BufferBoundsException
{
checkBounds(index, 4);
if (_isMotorolaByteOrder) {
// Motorola - MSB first (big endian)
return (((long)_buffer[index ]) << 24 & 0xFF000000L) |
(((long)_buffer[index + 1]) << 16 & 0xFF0000L) |
(((long)_buffer[index + 2]) << 8 & 0xFF00L) |
(((long)_buffer[index + 3]) & 0xFFL);
} else {
// Intel ordering - LSB first (little endian)
return (((long)_buffer[index + 3]) << 24 & 0xFF000000L) |
(((long)_buffer[index + 2]) << 16 & 0xFF0000L) |
(((long)_buffer[index + 1]) << 8 & 0xFF00L) |
(((long)_buffer[index ]) & 0xFFL);
}
}
public int getInt32(int index) throws BufferBoundsException
{
checkBounds(index, 4);
if (_isMotorolaByteOrder) {
// Motorola - MSB first (big endian)
return (_buffer[index ] << 24 & 0xFF000000) |
(_buffer[index + 1] << 16 & 0xFF0000) |
(_buffer[index + 2] << 8 & 0xFF00) |
(_buffer[index + 3] & 0xFF);
} else {
// Intel ordering - LSB first (little endian)
return (_buffer[index + 3] << 24 & 0xFF000000) |
(_buffer[index + 2] << 16 & 0xFF0000) |
(_buffer[index + 1] << 8 & 0xFF00) |
(_buffer[index ] & 0xFF);
}
}
public long getInt64(int index) throws BufferBoundsException
{
checkBounds(index, 8);
if (_isMotorolaByteOrder) {
// Motorola - MSB first
return ((long)_buffer[index ] << 56 & 0xFF00000000000000L) |
((long)_buffer[index + 1] << 48 & 0xFF000000000000L) |
((long)_buffer[index + 2] << 40 & 0xFF0000000000L) |
((long)_buffer[index + 3] << 32 & 0xFF00000000L) |
((long)_buffer[index + 4] << 24 & 0xFF000000L) |
((long)_buffer[index + 5] << 16 & 0xFF0000L) |
((long)_buffer[index + 6] << 8 & 0xFF00L) |
((long)_buffer[index + 7] & 0xFFL);
} else {
// Intel ordering - LSB first
return ((long)_buffer[index + 7] << 56 & 0xFF00000000000000L) |
((long)_buffer[index + 6] << 48 & 0xFF000000000000L) |
((long)_buffer[index + 5] << 40 & 0xFF0000000000L) |
((long)_buffer[index + 4] << 32 & 0xFF00000000L) |
((long)_buffer[index + 3] << 24 & 0xFF000000L) |
((long)_buffer[index + 2] << 16 & 0xFF0000L) |
((long)_buffer[index + 1] << 8 & 0xFF00L) |
((long)_buffer[index ] & 0xFFL);
}
}
public float getS15Fixed16(int index) throws BufferBoundsException
{
checkBounds(index, 4);
if (_isMotorolaByteOrder) {
float res = (_buffer[index ] & 255) << 8 |
(_buffer[index + 1] & 255);
int d = (_buffer[index + 2] & 255) << 8 |
(_buffer[index + 3] & 255);
return (float)(res + d/65536.0);
} else {
// this particular branch is untested
float res = (_buffer[index + 3] & 255) << 8 |
(_buffer[index + 2] & 255);
int d = (_buffer[index + 1] & 255) << 8 |
(_buffer[index ] & 255);
return (float)(res + d/65536.0);
}
}
public float getFloat32(int index) throws BufferBoundsException
{
return Float.intBitsToFloat(getInt32(index));
}
public double getDouble64(int index) throws BufferBoundsException
{
return Double.longBitsToDouble(getInt64(index));
}
@NotNull
public byte[] getBytes(int index, int count) throws BufferBoundsException
{
checkBounds(index, count);
byte[] bytes = new byte[count];
System.arraycopy(_buffer, index, bytes, 0, count);
return bytes;
}
@NotNull
public String getString(int index, int bytesRequested) throws BufferBoundsException
{
return new String(getBytes(index, bytesRequested));
}
@NotNull
public String getString(int index, int bytesRequested, String charset) throws BufferBoundsException
{
byte[] bytes = getBytes(index, bytesRequested);
try {
return new String(bytes, charset);
} catch (UnsupportedEncodingException e) {
return new String(bytes);
}
}
@NotNull
public String getNullTerminatedString(int index, int maxLengthBytes) throws BufferBoundsException
{
// NOTE currently only really suited to single-byte character strings
checkBounds(index, maxLengthBytes);
// Check for null terminators
int length = 0;
while ((index + length) < _buffer.length && _buffer[index + length] != '\0' && length < maxLengthBytes)
length++;
byte[] bytes = getBytes(index, length);
return new String(bytes);
}
private void checkBounds(final int index, final int bytesRequested) throws BufferBoundsException
{
if (bytesRequested < 0 || index < 0 || (long)index + (long)bytesRequested - 1L >= (long)_buffer.length)
throw new BufferBoundsException(_buffer, index, bytesRequested);
}
}