All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.drew.lang.RandomAccessFileReader Maven / Gradle / Ivy

Go to download

Java library for extracting EXIF, IPTC, XMP, ICC and other metadata from image and video files.

There is a newer version: 2.19.0
Show newest version
/*
 * 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.IOException;
import java.io.RandomAccessFile;
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 RandomAccessFileReader implements BufferReader { @NotNull private final RandomAccessFile _file; private final long _length; private int _currentIndex; private boolean _isMotorolaByteOrder = true; @SuppressWarnings({ "ConstantConditions" }) @com.drew.lang.annotations.SuppressWarnings(value = "EI_EXPOSE_REP2", justification = "Design intent") public RandomAccessFileReader(@NotNull RandomAccessFile file) throws IOException { if (file == null) throw new NullPointerException(); _file = file; _length = _file.length(); } public long getLength() { return _length; } public void setMotorolaByteOrder(boolean motorolaByteOrder) { _isMotorolaByteOrder = motorolaByteOrder; } public boolean isMotorolaByteOrder() { return _isMotorolaByteOrder; } private byte read() throws BufferBoundsException { final int b; try { b = _file.read(); } catch (IOException e) { throw new BufferBoundsException("IOException reading from file.", e); } if (b < 0) throw new BufferBoundsException("Unexpected end of file encountered."); assert(b <= 0xff); _currentIndex++; return (byte) b; } private void seek(final int index) throws BufferBoundsException { if (index == _currentIndex) return; try { _file.seek(index); _currentIndex = index; } catch (IOException e) { throw new BufferBoundsException("IOException seeking in file.", e); } } public short getUInt8(int index) throws BufferBoundsException { checkBounds(index, 1); seek(index); return (short) (read() & 255); } public byte getInt8(int index) throws BufferBoundsException { checkBounds(index, 1); seek(index); return read(); } public int getUInt16(int index) throws BufferBoundsException { checkBounds(index, 2); seek(index); if (_isMotorolaByteOrder) { // Motorola - MSB first return (read() << 8 & 0xFF00) | (read() & 0xFF); } else { // Intel ordering - LSB first return (read() & 0xFF) | (read() << 8 & 0xFF00); } } public short getInt16(int index) throws BufferBoundsException { checkBounds(index, 2); seek(index); if (_isMotorolaByteOrder) { // Motorola - MSB first return (short) (((short) read() << 8 & (short)0xFF00) | ((short) read() & (short)0xFF)); } else { // Intel ordering - LSB first return (short) (((short) read() & (short)0xFF) | ((short) read() << 8 & (short)0xFF00)); } } public long getUInt32(int index) throws BufferBoundsException { checkBounds(index, 4); seek(index); if (_isMotorolaByteOrder) { // Motorola - MSB first (big endian) return (((long) read()) << 24 & 0xFF000000L) | (((long) read()) << 16 & 0xFF0000L) | (((long) read()) << 8 & 0xFF00L) | (((long) read()) & 0xFFL); } else { // Intel ordering - LSB first (little endian) return (((long) read()) & 0xFFL) | (((long) read()) << 8 & 0xFF00L) | (((long) read()) << 16 & 0xFF0000L) | (((long) read()) << 24 & 0xFF000000L); } } public int getInt32(int index) throws BufferBoundsException { checkBounds(index, 4); seek(index); if (_isMotorolaByteOrder) { // Motorola - MSB first (big endian) return (read() << 24 & 0xFF000000) | (read() << 16 & 0xFF0000) | (read() << 8 & 0xFF00) | (read() & 0xFF); } else { // Intel ordering - LSB first (little endian) return (read() & 0xFF) | (read() << 8 & 0xFF00) | (read() << 16 & 0xFF0000) | (read() << 24 & 0xFF000000); } } public long getInt64(int index) throws BufferBoundsException { checkBounds(index, 8); seek(index); if (_isMotorolaByteOrder) { // Motorola - MSB first return ((long) read() << 56 & 0xFF00000000000000L) | ((long) read() << 48 & 0xFF000000000000L) | ((long) read() << 40 & 0xFF0000000000L) | ((long) read() << 32 & 0xFF00000000L) | ((long) read() << 24 & 0xFF000000L) | ((long) read() << 16 & 0xFF0000L) | ((long) read() << 8 & 0xFF00L) | ((long) read() & 0xFFL); } else { // Intel ordering - LSB first return ((long) read() & 0xFFL) | ((long) read() << 8 & 0xFF00L) | ((long) read() << 16 & 0xFF0000L) | ((long) read() << 24 & 0xFF000000L) | ((long) read() << 32 & 0xFF00000000L) | ((long) read() << 40 & 0xFF0000000000L) | ((long) read() << 48 & 0xFF000000000000L) | ((long) read() << 56 & 0xFF00000000000000L); } } public float getS15Fixed16(int index) throws BufferBoundsException { checkBounds(index, 4); seek(index); if (_isMotorolaByteOrder) { float res = (read() & 255) << 8 | (read() & 255); int d = (read() & 255) << 8 | (read() & 255); return (float)(res + d/65536.0); } else { // this particular branch is untested int d = (read() & 255) | (read() & 255) << 8; float res = (read() & 255) | (read() & 255) << 8; 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); seek(index); byte[] bytes = new byte[count]; final int bytesRead; try { bytesRead = _file.read(bytes); _currentIndex += bytesRead; } catch (IOException e) { throw new BufferBoundsException("Unexpected end of file encountered.", e); } if (bytesRead != count) throw new BufferBoundsException("Unexpected end of file encountered."); 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 { checkBounds(index, bytesRequested); 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); seek(index); // Check for null terminators int length = 0; while ((index + length) < _length && read() != '\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) throw new BufferBoundsException("Requested negative number of bytes."); if (index < 0) throw new BufferBoundsException("Requested data from a negative index within the file."); if ((long)index + (long)bytesRequested - 1L >= _length) throw new BufferBoundsException("Requested data from beyond the end of the file."); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy