segments, @NotNull final Metadata metadata) throws IOException;
}
diff --git a/Source/com/drew/imaging/jpeg/JpegSegmentReader.java b/Source/com/drew/imaging/jpeg/JpegSegmentReader.java
index 55e6bd01b..56077a638 100644
--- a/Source/com/drew/imaging/jpeg/JpegSegmentReader.java
+++ b/Source/com/drew/imaging/jpeg/JpegSegmentReader.java
@@ -20,22 +20,35 @@
*/
package com.drew.imaging.jpeg;
-import com.drew.lang.SequentialReader;
-import com.drew.lang.StreamReader;
+import com.drew.lang.ByteTrie;
+import com.drew.lang.Charsets;
+import com.drew.lang.RandomAccessStream;
+import com.drew.lang.ReaderInfo;
import com.drew.lang.annotations.NotNull;
import com.drew.lang.annotations.Nullable;
+import com.drew.metadata.exif.ExifReader;
+import com.drew.metadata.adobe.AdobeJpegReader;
+import com.drew.metadata.photoshop.DuckyReader;
+import com.drew.metadata.photoshop.PhotoshopReader;
+import com.drew.metadata.jfif.JfifReader;
+import com.drew.metadata.jfxx.JfxxReader;
+import com.drew.metadata.icc.IccReader;
+import com.drew.metadata.xmp.XmpReader;
+
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
+import java.io.RandomAccessFile;
import java.util.HashSet;
import java.util.Set;
+import java.util.Collection;
/**
* Performs read functions of JPEG files, returning specific file segments.
*
* JPEG files are composed of a sequence of consecutive JPEG 'segments'. Each is identified by one of a set of byte
- * values, modelled in the {@link JpegSegmentType} enumeration. Use readSegments
to read out the some
+ * values, modeled in the {@link JpegSegmentType} enumeration. Use readSegments
to read out the some
* or all segments into a {@link JpegSegmentData} object, from which the raw JPEG segment byte arrays may be accessed.
*
* @author Drew Noakes https://drewnoakes.com
@@ -47,15 +60,26 @@ public class JpegSegmentReader
*/
private static final byte SEGMENT_IDENTIFIER = (byte) 0xFF;
- /**
- * Private, because this segment crashes my algorithm, and searching for it doesn't work (yet).
- */
- private static final byte SEGMENT_SOS = (byte) 0xDA;
-
- /**
- * Private, because one wouldn't search for it.
- */
- private static final byte MARKER_EOI = (byte) 0xD9;
+ private static final ByteTrie _appSegmentByPreambleBytes;
+ private static final HashSet _segmentMarkerBytes;
+
+ static
+ {
+ _appSegmentByPreambleBytes = new ByteTrie();
+ _appSegmentByPreambleBytes.addPath(AdobeJpegReader.JPEG_SEGMENT_ID, AdobeJpegReader.JPEG_SEGMENT_PREAMBLE.getBytes(Charsets.UTF_8));
+ _appSegmentByPreambleBytes.addPath(DuckyReader.JPEG_SEGMENT_ID, DuckyReader.JPEG_SEGMENT_PREAMBLE.getBytes(Charsets.UTF_8));
+ _appSegmentByPreambleBytes.addPath(ExifReader.JPEG_SEGMENT_ID, ExifReader.JPEG_SEGMENT_PREAMBLE.getBytes(Charsets.UTF_8));
+ _appSegmentByPreambleBytes.addPath(IccReader.JPEG_SEGMENT_ID, IccReader.JPEG_SEGMENT_PREAMBLE.getBytes(Charsets.UTF_8));
+ _appSegmentByPreambleBytes.addPath(JfifReader.JPEG_SEGMENT_ID, JfifReader.JPEG_SEGMENT_PREAMBLE.getBytes(Charsets.UTF_8));
+ _appSegmentByPreambleBytes.addPath(JfxxReader.JPEG_SEGMENT_ID, JfxxReader.JPEG_SEGMENT_PREAMBLE.getBytes(Charsets.UTF_8));
+ _appSegmentByPreambleBytes.addPath(PhotoshopReader.JPEG_SEGMENT_ID, PhotoshopReader.JPEG_SEGMENT_PREAMBLE.getBytes(Charsets.UTF_8));
+ _appSegmentByPreambleBytes.addPath(XmpReader.JPEG_SEGMENT_ID, XmpReader.JPEG_SEGMENT_PREAMBLE.getBytes(Charsets.UTF_8));
+ _appSegmentByPreambleBytes.addPath(XmpReader.JPEG_SEGMENT_EXTENSION_ID, XmpReader.JPEG_SEGMENT_PREAMBLE_EXTENSION.getBytes(Charsets.UTF_8));
+
+ _segmentMarkerBytes = new HashSet();
+ _segmentMarkerBytes.add((byte)0x1C);
+
+ }
/**
* Processes the provided JPEG data, and extracts the specified JPEG segments into a {@link JpegSegmentData} object.
@@ -66,32 +90,59 @@ public class JpegSegmentReader
* @param segmentTypes the set of JPEG segments types that are to be returned. If this argument is null
* then all found segment types are returned.
*/
+
@NotNull
- public static JpegSegmentData readSegments(@NotNull File file, @Nullable Iterable segmentTypes) throws JpegProcessingException, IOException
+ public static JpegSegmentData readSegments(@NotNull File file, @Nullable Collection segmentTypes) throws JpegProcessingException, IOException
{
- FileInputStream stream = null;
- try {
- stream = new FileInputStream(file);
- return readSegments(new StreamReader(stream), segmentTypes);
- } finally {
- if (stream != null) {
- stream.close();
+ return readSegments(file, segmentTypes, false);
+ }
+
+ @NotNull
+ public static JpegSegmentData readSegments(@NotNull File file, @Nullable Collection segmentTypes, boolean holdBytes) throws JpegProcessingException, IOException
+ {
+ if(file.isFile())
+ {
+ RandomAccessFile raFile = null;
+ try {
+ raFile = new RandomAccessFile(file, "r");
+ return readSegments(new RandomAccessStream(raFile).createReader(), segmentTypes, holdBytes);
+ } finally {
+ if(raFile != null)
+ raFile.close();
+ }
+ }
+ else
+ {
+ FileInputStream stream = null;
+ try {
+ stream = new FileInputStream(file);
+ return readSegments(new RandomAccessStream(stream, file.length()).createReader(), segmentTypes, holdBytes);
+ } finally {
+ if (stream != null) {
+ stream.close();
+ }
}
}
}
+ @NotNull
+ public static JpegSegmentData readSegments(@NotNull final ReaderInfo reader, @Nullable Collection segmentTypes) throws JpegProcessingException, IOException
+ {
+ return readSegments(reader, segmentTypes, false);
+ }
+
/**
* Processes the provided JPEG data, and extracts the specified JPEG segments into a {@link JpegSegmentData} object.
*
* Will not return SOS (start of scan) or EOI (end of image) segments.
*
- * @param reader a {@link SequentialReader} from which the JPEG data will be read. It must be positioned at the
+ * @param reader a {@link ReaderInfo} from which the JPEG data will be read. It must be positioned at the
* beginning of the JPEG data stream.
* @param segmentTypes the set of JPEG segments types that are to be returned. If this argument is null
* then all found segment types are returned.
*/
@NotNull
- public static JpegSegmentData readSegments(@NotNull final SequentialReader reader, @Nullable Iterable segmentTypes) throws JpegProcessingException, IOException
+ public static JpegSegmentData readSegments(@NotNull final ReaderInfo reader, @Nullable Collection segmentTypes, boolean holdBytes) throws JpegProcessingException, IOException
{
// Must be big-endian
assert (reader.isMotorolaByteOrder());
@@ -110,56 +161,125 @@ public static JpegSegmentData readSegments(@NotNull final SequentialReader reade
}
}
- JpegSegmentData segmentData = new JpegSegmentData();
+ JpegSegmentData segments = new JpegSegmentData();
+
+ boolean dobreak = false;
+
+ while (true)
+ {
+ int padding = 0;
+ dobreak = false;
- do {
// Find the segment marker. Markers are zero or more 0xFF bytes, followed
// by a 0xFF and then a byte not equal to 0x00 or 0xFF.
-
+ if (reader.isCloserToEnd(2))
+ break;
byte segmentIdentifier = reader.getInt8();
- byte segmentType = reader.getInt8();
+ byte segmentTypeByte = reader.getInt8();
// Read until we have a 0xFF byte followed by a byte that is not 0xFF or 0x00
- while (segmentIdentifier != SEGMENT_IDENTIFIER || segmentType == SEGMENT_IDENTIFIER || segmentType == 0) {
- segmentIdentifier = segmentType;
- segmentType = reader.getInt8();
+ while (segmentIdentifier != SEGMENT_IDENTIFIER || segmentTypeByte == SEGMENT_IDENTIFIER || segmentTypeByte == 0)
+ {
+ padding++;
+ if (reader.isCloserToEnd(2))
+ {
+ dobreak = true;
+ break;
+ }
+
+ segmentIdentifier = segmentTypeByte;
+ segmentTypeByte = reader.getInt8();
}
+ if(dobreak) break;
- if (segmentType == SEGMENT_SOS) {
- // The 'Start-Of-Scan' segment's length doesn't include the image data, instead would
- // have to search for the two bytes: 0xFF 0xD9 (EOI).
- // It comes last so simply return at this point
- return segmentData;
- }
+ JpegSegmentType segmentType = JpegSegmentType.fromByte(segmentTypeByte);
- if (segmentType == MARKER_EOI) {
- // the 'End-Of-Image' segment -- this should never be found in this fashion
- return segmentData;
- }
+ // decide whether this JPEG segment type's marker is followed by a length indicator
+ if (JpegSegmentType.containsPayload(segmentType))
+ {
+ // Need two more bytes for the segment length. If closer than two bytes to the end, yield
+ if (reader.isCloserToEnd(2))
+ break;
+
+ // Read the 2-byte big-endian segment length
+ // The length includes the two bytes for the length, but not the two bytes for the marker
+ int segmentLength = reader.getUInt16();
+
+ // A length of less than two would be an error
+ if (segmentLength < 2)
+ break;
+
+ // get position after id and type bytes (beginning of payload)
+ //offset += 2;
+
+ // TODO: would you rather break here or throw an exception?
+ /*if (segmentLength > (reader.Length - offset + 1))
+ yield break; // throw new JpegProcessingException($"Segment {segmentType} is truncated. Processing cannot proceed.");
+ else
+ {*/
+ // segment length includes size bytes, so subtract two
+ segmentLength -= 2;
+ //}
+
+ // Check whether we are interested in this segment
+ if (segmentTypes == null || segmentTypes.contains(segmentType))
+ {
+ byte[] preambleBytes = new byte[Math.min(segmentLength, _appSegmentByPreambleBytes.getMaxDepth())];
+ long read = reader.read(preambleBytes, 0, preambleBytes.length);
+ if (read != preambleBytes.length)
+ break;
+ String preamble = _appSegmentByPreambleBytes.find(preambleBytes); //?? "";
- // next 2-bytes are : [high-byte] [low-byte]
- int segmentLength = reader.getUInt16();
-
- // segment length includes size bytes, so subtract two
- segmentLength -= 2;
-
- if (segmentLength < 0)
- throw new JpegProcessingException("JPEG segment size would be less than zero");
-
- // Check whether we are interested in this segment
- if (segmentTypeBytes == null || segmentTypeBytes.contains(segmentType)) {
- byte[] segmentBytes = reader.getBytes(segmentLength);
- assert (segmentLength == segmentBytes.length);
- segmentData.addSegment(segmentType, segmentBytes);
- } else {
- // Skip this segment
- if (!reader.trySkip(segmentLength)) {
- // If skipping failed, just return the segments we found so far
- return segmentData;
+ // Preamble wasn't found in the list. Since preamble is used in string comparisons, set it to blank.
+ // (TODO: this might be a good place to record unknown preambles and report back somehow)
+ if (preamble == null)
+ preamble = "";
+
+ reader.skip(-read);
+
+ byte bytemarker = 0x00;
+ if(preamble.length() == 0)
+ {
+ bytemarker = reader.getInt8();
+ if (!_segmentMarkerBytes.contains(bytemarker))
+ bytemarker = 0x00;
+ reader.skip(-1);
+ }
+ JpegSegment segment = new JpegSegment(segmentType, reader.Clone(segmentLength), preamble, bytemarker);
+ if(holdBytes)
+ segment.holdAsBytes();
+ segments.addSegment(segment);
+ }
+
+ // seek to the end of the segment
+ reader.skip(segmentLength);
+
+ // Sos means entropy encoded data immediately follows, ending with Eoi or another indicator
+ // We already did a seek to the end of the SOS segment. A byte-by-byte scan follows to find the next indicator
+ if (segmentType == JpegSegmentType.SOS)
+ {
+ // yielding here makes Sos processing work the old way (ending at the first one)
+ break;
}
}
+ else
+ {
+ // Check whether we are interested in this non-payload segment
+ if (segmentTypes == null || segmentTypes.contains(segmentType))
+ {
+ JpegSegment segment = new JpegSegment(segmentType, reader.Clone(0));
+ if(holdBytes)
+ segment.holdAsBytes();
+ segments.addSegment(segment);
+ }
+
+ if (segmentType == JpegSegmentType.EOI)
+ break;
+ }
- } while (true);
+ }
+
+ return segments;
}
private JpegSegmentReader() throws Exception
diff --git a/Source/com/drew/imaging/jpeg/JpegSegmentType.java b/Source/com/drew/imaging/jpeg/JpegSegmentType.java
index 521e47854..d679a392b 100644
--- a/Source/com/drew/imaging/jpeg/JpegSegmentType.java
+++ b/Source/com/drew/imaging/jpeg/JpegSegmentType.java
@@ -38,148 +38,195 @@
*/
public enum JpegSegmentType
{
+ /// For temporary use in arithmetic coding.
+ /// No length or parameter sequence follows this marker.
+ TEM((byte)0x01), //, false),
+
/** APP0 JPEG segment identifier. Commonly contains JFIF, JFXX. */
- APP0((byte)0xE0, true),
+ APP0((byte)0xE0), //, true),
/** APP1 JPEG segment identifier. Commonly contains Exif. XMP data is also kept in here, though usually in a second instance. */
- APP1((byte)0xE1, true),
+ APP1((byte)0xE1), //, true),
/** APP2 JPEG segment identifier. Commonly contains ICC. */
- APP2((byte)0xE2, true),
+ APP2((byte)0xE2), //, true),
/** APP3 JPEG segment identifier. */
- APP3((byte)0xE3, true),
+ APP3((byte)0xE3), //, true),
/** APP4 JPEG segment identifier. */
- APP4((byte)0xE4, true),
+ APP4((byte)0xE4), //, true),
/** APP5 JPEG segment identifier. */
- APP5((byte)0xE5, true),
+ APP5((byte)0xE5), //, true),
/** APP6 JPEG segment identifier. */
- APP6((byte)0xE6, true),
+ APP6((byte)0xE6), //, true),
/** APP7 JPEG segment identifier. */
- APP7((byte)0xE7, true),
+ APP7((byte)0xE7), //, true),
/** APP8 JPEG segment identifier. */
- APP8((byte)0xE8, true),
+ APP8((byte)0xE8), //, true),
/** APP9 JPEG segment identifier. */
- APP9((byte)0xE9, true),
+ APP9((byte)0xE9), //, true),
/** APPA (App10) JPEG segment identifier. Can contain Unicode comments, though {@link JpegSegmentType#COM} is more commonly used for comments. */
- APPA((byte)0xEA, true),
+ APPA((byte)0xEA), //, true),
/** APPB (App11) JPEG segment identifier. */
- APPB((byte)0xEB, true),
+ APPB((byte)0xEB), //, true),
/** APPC (App12) JPEG segment identifier. */
- APPC((byte)0xEC, true),
+ APPC((byte)0xEC), //, true),
/** APPD (App13) JPEG segment identifier. Commonly contains IPTC, Photoshop data. */
- APPD((byte)0xED, true),
+ APPD((byte)0xED), //, true),
/** APPE (App14) JPEG segment identifier. Commonly contains Adobe data. */
- APPE((byte)0xEE, true),
+ APPE((byte)0xEE), //, true),
/** APPF (App15) JPEG segment identifier. */
- APPF((byte)0xEF, true),
+ APPF((byte)0xEF), //, true),
/** Start Of Image segment identifier. */
- SOI((byte)0xD8, false),
+ SOI((byte)0xD8), //, false),
/** Define Quantization Table segment identifier. */
- DQT((byte)0xDB, false),
+ DQT((byte)0xDB), //, false),
/** Define Number of Lines segment identifier. */
- DNL((byte)0xDC, false),
+ DNL((byte)0xDC), //, false),
/** Define Restart Interval segment identifier. */
- DRI((byte)0xDD, false),
+ DRI((byte)0xDD), //, false),
/** Define Hierarchical Progression segment identifier. */
- DHP((byte)0xDE, false),
+ DHP((byte)0xDE), //, false),
/** EXPand reference component(s) segment identifier. */
- EXP((byte)0xDF, false),
+ EXP((byte)0xDF), //, false),
/** Define Huffman Table segment identifier. */
- DHT((byte)0xC4, false),
+ DHT((byte)0xC4), //, false),
/** Define Arithmetic Coding conditioning segment identifier. */
- DAC((byte)0xCC, false),
+ DAC((byte)0xCC), //, false),
/** Start-of-Frame (0) segment identifier for Baseline DCT. */
- SOF0((byte)0xC0, true),
+ SOF0((byte)0xC0), //, true),
/** Start-of-Frame (1) segment identifier for Extended sequential DCT. */
- SOF1((byte)0xC1, true),
+ SOF1((byte)0xC1), //, true),
/** Start-of-Frame (2) segment identifier for Progressive DCT. */
- SOF2((byte)0xC2, true),
+ SOF2((byte)0xC2), //, true),
/** Start-of-Frame (3) segment identifier for Lossless (sequential). */
- SOF3((byte)0xC3, true),
+ SOF3((byte)0xC3), //, true),
// /** Start-of-Frame (4) segment identifier. */
// SOF4((byte)0xC4, true),
/** Start-of-Frame (5) segment identifier for Differential sequential DCT. */
- SOF5((byte)0xC5, true),
+ SOF5((byte)0xC5), //, true),
/** Start-of-Frame (6) segment identifier for Differential progressive DCT. */
- SOF6((byte)0xC6, true),
+ SOF6((byte)0xC6), //, true),
/** Start-of-Frame (7) segment identifier for Differential lossless (sequential). */
- SOF7((byte)0xC7, true),
+ SOF7((byte)0xC7), //, true),
/** Reserved for JPEG extensions. */
- JPG((byte)0xC8, true),
+ JPG((byte)0xC8), //, true),
/** Start-of-Frame (9) segment identifier for Extended sequential DCT. */
- SOF9((byte)0xC9, true),
+ SOF9((byte)0xC9), //, true),
/** Start-of-Frame (10) segment identifier for Progressive DCT. */
- SOF10((byte)0xCA, true),
+ SOF10((byte)0xCA), //, true),
/** Start-of-Frame (11) segment identifier for Lossless (sequential). */
- SOF11((byte)0xCB, true),
+ SOF11((byte)0xCB), //, true),
// /** Start-of-Frame (12) segment identifier. */
// SOF12((byte)0xCC, true),
/** Start-of-Frame (13) segment identifier for Differential sequential DCT. */
- SOF13((byte)0xCD, true),
+ SOF13((byte)0xCD), //, true),
/** Start-of-Frame (14) segment identifier for Differential progressive DCT. */
- SOF14((byte)0xCE, true),
+ SOF14((byte)0xCE), //, true),
/** Start-of-Frame (15) segment identifier for Differential lossless (sequential). */
- SOF15((byte)0xCF, true),
-
+ SOF15((byte)0xCF), //, true),
+
+ /** Restart. */
+ RST0((byte)0xD0), //, false),
+
+ /** Restart. */
+ RST1((byte)0xD1), //, false),
+
+ /** Restart. */
+ RST2((byte)0xD2), //, false),
+
+ /** Restart. */
+ RST3((byte)0xD3), //, false),
+
+ /** Restart. */
+ RST4((byte)0xD4), //, false),
+
+ /** Restart. */
+ RST5((byte)0xD5), //, false),
+
+ /** Restart. */
+ RST6((byte)0xD6), //, false),
+
+ /** Restart. */
+ RST7((byte)0xD7), //, false),
+
+ /** End-of-Image. Terminates the JPEG compressed data stream that started at Soi. */
+ EOI((byte)0xD9), //, false),
+
+ /** Start-of-scan. */
+ SOS((byte)0xDA), //, false),
+
/** JPEG comment segment identifier for comments. */
- COM((byte)0xFE, true);
+ COM((byte)0xFE); //, true);
public static final Collection canContainMetadataTypes;
static {
List segmentTypes = new ArrayList();
for (JpegSegmentType segmentType : JpegSegmentType.class.getEnumConstants()) {
- if (segmentType.canContainMetadata) {
+ if (canContainMetadata(segmentType)) {
segmentTypes.add(segmentType);
}
}
canContainMetadataTypes = segmentTypes;
}
+ /// Gets whether this JPEG segment type might contain metadata.
+ /// Used to exclude large image-data-only segment from certain types of processing.
+ public static boolean canContainMetadata(JpegSegmentType type)
+ {
+ switch (type)
+ {
+ case SOI:
+ case DQT:
+ case DHT:
+ return false;
+ default:
+ return true;
+ }
+ }
+
public final byte byteValue;
- public final boolean canContainMetadata;
- JpegSegmentType(byte byteValue, boolean canContainMetadata)
+ JpegSegmentType(byte byteValue)
{
this.byteValue = byteValue;
- this.canContainMetadata = canContainMetadata;
}
@Nullable
@@ -191,4 +238,25 @@ public static JpegSegmentType fromByte(byte segmentTypeByte)
}
return null;
}
+
+ public static boolean containsPayload(JpegSegmentType type)
+ {
+ switch (type)
+ {
+ case SOI:
+ case EOI:
+ case RST0:
+ case RST1:
+ case RST2:
+ case RST3:
+ case RST4:
+ case RST5:
+ case RST6:
+ case RST7:
+ case TEM:
+ return false;
+ default:
+ return true;
+ }
+ }
}
diff --git a/Source/com/drew/imaging/mp3/Mp3MetadataReader.java b/Source/com/drew/imaging/mp3/Mp3MetadataReader.java
index 148c04f0d..bdfec6c3e 100644
--- a/Source/com/drew/imaging/mp3/Mp3MetadataReader.java
+++ b/Source/com/drew/imaging/mp3/Mp3MetadataReader.java
@@ -21,6 +21,8 @@
package com.drew.imaging.mp3;
import com.drew.lang.annotations.NotNull;
+import com.drew.lang.RandomAccessStream;
+import com.drew.lang.ReaderInfo;
import com.drew.metadata.Metadata;
import com.drew.metadata.file.FileSystemMetadataReader;
import com.drew.metadata.mp3.Mp3Reader;
@@ -43,7 +45,7 @@ public static Metadata readMetadata(@NotNull File file) throws IOException
InputStream inputStream = new FileInputStream(file);
Metadata metadata;
try {
- metadata = readMetadata(inputStream);
+ metadata = readMetadata(new RandomAccessStream(inputStream, file.length()).createReader());
} finally {
inputStream.close();
}
@@ -52,10 +54,10 @@ public static Metadata readMetadata(@NotNull File file) throws IOException
}
@NotNull
- public static Metadata readMetadata(@NotNull InputStream inputStream)
+ public static Metadata readMetadata(@NotNull ReaderInfo reader)
{
Metadata metadata = new Metadata();
- new Mp3Reader().extract(inputStream, metadata);
+ new Mp3Reader().extract(reader, metadata);
return metadata;
}
}
diff --git a/Source/com/drew/imaging/mp4/Mp4MetadataReader.java b/Source/com/drew/imaging/mp4/Mp4MetadataReader.java
index 00c1a402a..b29335cf2 100644
--- a/Source/com/drew/imaging/mp4/Mp4MetadataReader.java
+++ b/Source/com/drew/imaging/mp4/Mp4MetadataReader.java
@@ -22,6 +22,8 @@
import com.drew.imaging.ImageProcessingException;
import com.drew.lang.annotations.NotNull;
+import com.drew.lang.RandomAccessStream;
+import com.drew.lang.ReaderInfo;
import com.drew.metadata.Metadata;
import com.drew.metadata.file.FileSystemMetadataReader;
import com.drew.metadata.mp4.Mp4BoxHandler;
@@ -42,7 +44,7 @@ public static Metadata readMetadata(@NotNull final File file) throws ImageProces
InputStream inputStream = new FileInputStream(file);
Metadata metadata;
try {
- metadata = readMetadata(inputStream);
+ metadata = readMetadata(new RandomAccessStream(inputStream, file.length()).createReader());
} finally {
inputStream.close();
}
@@ -51,10 +53,10 @@ public static Metadata readMetadata(@NotNull final File file) throws ImageProces
}
@NotNull
- public static Metadata readMetadata(@NotNull InputStream inputStream) throws IOException
+ public static Metadata readMetadata(@NotNull ReaderInfo reader) throws IOException
{
Metadata metadata = new Metadata();
- Mp4Reader.extract(inputStream, new Mp4BoxHandler(metadata));
+ Mp4Reader.extract(reader, new Mp4BoxHandler(metadata));
return metadata;
}
}
diff --git a/Source/com/drew/imaging/mp4/Mp4Reader.java b/Source/com/drew/imaging/mp4/Mp4Reader.java
index 5a62ab0b3..7f4c63723 100644
--- a/Source/com/drew/imaging/mp4/Mp4Reader.java
+++ b/Source/com/drew/imaging/mp4/Mp4Reader.java
@@ -20,12 +20,11 @@
*/
package com.drew.imaging.mp4;
-import com.drew.lang.StreamReader;
+import com.drew.lang.ReaderInfo;
import com.drew.lang.annotations.NotNull;
import com.drew.metadata.mp4.boxes.Box;
import java.io.IOException;
-import java.io.InputStream;
/**
* @author Payton Garland
@@ -34,18 +33,21 @@ public class Mp4Reader
{
private Mp4Reader() {}
- public static void extract(@NotNull InputStream inputStream, @NotNull Mp4Handler handler)
+ public static void extract(@NotNull ReaderInfo reader, @NotNull Mp4Handler handler) throws IOException
{
- StreamReader reader = new StreamReader(inputStream);
- reader.setMotorolaByteOrder(true);
+ if(!reader.isMotorolaByteOrder())
+ {
+ reader = reader.Clone();
+ reader.setMotorolaByteOrder(true);
+ }
processBoxes(reader, -1, handler);
}
- private static void processBoxes(StreamReader reader, long atomEnd, Mp4Handler handler)
+ private static void processBoxes(ReaderInfo reader, long atomEnd, Mp4Handler handler)
{
try {
- while (atomEnd == -1 || reader.getPosition() < atomEnd) {
+ while (atomEnd == -1 || reader.getLocalPosition() < atomEnd) {
Box box = new Box(reader);
@@ -53,7 +55,7 @@ private static void processBoxes(StreamReader reader, long atomEnd, Mp4Handler h
// Unknown atoms will be skipped
if (handler.shouldAcceptContainer(box)) {
- processBoxes(reader, box.size + reader.getPosition() - 8, handler.processContainer(box));
+ processBoxes(reader, box.size + reader.getLocalPosition() - 8, handler.processContainer(box));
} else if (handler.shouldAcceptBox(box)) {
handler = handler.processBox(box, reader.getBytes((int)box.size - 8));
} else if (box.usertype != null) {
diff --git a/Source/com/drew/imaging/netpbm/NetpbmMetadataReader.java b/Source/com/drew/imaging/netpbm/NetpbmMetadataReader.java
new file mode 100644
index 000000000..f5235f7c5
--- /dev/null
+++ b/Source/com/drew/imaging/netpbm/NetpbmMetadataReader.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright 2002-2017 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:
+ *
+ * https://drewnoakes.com/code/exif/
+ * https://github.com/drewnoakes/metadata-extractor
+ */
+
+package com.drew.imaging.netpbm;
+
+import com.drew.imaging.ImageProcessingException;
+import com.drew.lang.RandomAccessStream;
+import com.drew.lang.annotations.NotNull;
+import com.drew.lang.ReaderInfo;
+import com.drew.metadata.Metadata;
+import com.drew.metadata.file.FileSystemMetadataReader;
+import com.drew.metadata.netpbm.NetpbmReader;
+import java.io.File;
+import java.io.FileInputStream;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+/**
+ * Obtains metadata from Netpbm files.
+ *
+ * @author Drew Noakes https://drewnoakes.com
+ * @author Kevin Mott https://github.com/kwhopper
+ */
+public class NetpbmMetadataReader
+{
+ @NotNull
+ public static Metadata readMetadata(@NotNull File file) throws IOException, ImageProcessingException
+ {
+ InputStream inputStream = new FileInputStream(file);
+ Metadata metadata;
+ try {
+ metadata = readMetadata(new RandomAccessStream(inputStream, file.length()).createReader());
+ } finally {
+ inputStream.close();
+ }
+ new FileSystemMetadataReader().read(file, metadata);
+ return metadata;
+ }
+
+ @NotNull
+ public static Metadata readMetadata(@NotNull ReaderInfo reader) throws IOException, ImageProcessingException
+ {
+ Metadata metadata = new Metadata();
+ new NetpbmReader().extract(reader, metadata);
+ return metadata;
+ }
+}
diff --git a/Source/com/drew/imaging/pcx/PcxMetadataReader.java b/Source/com/drew/imaging/pcx/PcxMetadataReader.java
index 15caabe79..b50b147e5 100644
--- a/Source/com/drew/imaging/pcx/PcxMetadataReader.java
+++ b/Source/com/drew/imaging/pcx/PcxMetadataReader.java
@@ -20,10 +20,11 @@
*/
package com.drew.imaging.pcx;
-import com.drew.lang.StreamReader;
import com.drew.lang.annotations.NotNull;
-import com.drew.metadata.Metadata;
+import com.drew.lang.RandomAccessStream;
+import com.drew.lang.ReaderInfo;
import com.drew.metadata.file.FileSystemMetadataReader;
+import com.drew.metadata.Metadata;
import com.drew.metadata.pcx.PcxReader;
import java.io.*;
@@ -41,7 +42,7 @@ public static Metadata readMetadata(@NotNull File file) throws IOException
InputStream inputStream = new FileInputStream(file);
Metadata metadata;
try {
- metadata = readMetadata(inputStream);
+ metadata = readMetadata(new RandomAccessStream(inputStream, file.length()).createReader());
} finally {
inputStream.close();
}
@@ -50,10 +51,10 @@ public static Metadata readMetadata(@NotNull File file) throws IOException
}
@NotNull
- public static Metadata readMetadata(@NotNull InputStream inputStream)
+ public static Metadata readMetadata(@NotNull ReaderInfo reader)
{
Metadata metadata = new Metadata();
- new PcxReader().extract(new StreamReader(inputStream), metadata);
+ new PcxReader().extract(reader, metadata);
return metadata;
}
}
diff --git a/Source/com/drew/imaging/png/PngChromaticities.java b/Source/com/drew/imaging/png/PngChromaticities.java
index 094a89e2e..60489d4e8 100644
--- a/Source/com/drew/imaging/png/PngChromaticities.java
+++ b/Source/com/drew/imaging/png/PngChromaticities.java
@@ -20,8 +20,8 @@
*/
package com.drew.imaging.png;
-import com.drew.lang.SequentialByteArrayReader;
import com.drew.lang.annotations.NotNull;
+import com.drew.lang.ReaderInfo;
import java.io.IOException;
@@ -39,13 +39,12 @@ public class PngChromaticities
private final int _blueX;
private final int _blueY;
- public PngChromaticities(@NotNull byte[] bytes) throws PngProcessingException
+ public PngChromaticities(@NotNull ReaderInfo reader) throws PngProcessingException, IOException
{
- if (bytes.length != 8 * 4) {
+ if (reader.getLength() != 8 * 4) {
throw new PngProcessingException("Invalid number of bytes");
}
- SequentialByteArrayReader reader = new SequentialByteArrayReader(bytes);
try {
_whitePointX = reader.getInt32();
_whitePointY = reader.getInt32();
diff --git a/Source/com/drew/imaging/png/PngChunk.java b/Source/com/drew/imaging/png/PngChunk.java
index cbc4bb3c9..3d1eb9a8f 100644
--- a/Source/com/drew/imaging/png/PngChunk.java
+++ b/Source/com/drew/imaging/png/PngChunk.java
@@ -21,6 +21,7 @@
package com.drew.imaging.png;
import com.drew.lang.annotations.NotNull;
+import com.drew.lang.ReaderInfo;
/**
* @author Drew Noakes https://drewnoakes.com
@@ -30,12 +31,12 @@ public class PngChunk
@NotNull
private final PngChunkType _chunkType;
@NotNull
- private final byte[] _bytes;
+ private ReaderInfo _reader;
- public PngChunk(@NotNull PngChunkType chunkType, @NotNull byte[] bytes)
+ public PngChunk(@NotNull PngChunkType chunkType, @NotNull ReaderInfo chunkReader)
{
_chunkType = chunkType;
- _bytes = bytes;
+ _reader = chunkReader;
}
@NotNull
@@ -45,8 +46,8 @@ public PngChunkType getType()
}
@NotNull
- public byte[] getBytes()
+ public ReaderInfo getReader()
{
- return _bytes;
+ return _reader;
}
}
diff --git a/Source/com/drew/imaging/png/PngChunkReader.java b/Source/com/drew/imaging/png/PngChunkReader.java
index 16e25defa..5a38ae247 100644
--- a/Source/com/drew/imaging/png/PngChunkReader.java
+++ b/Source/com/drew/imaging/png/PngChunkReader.java
@@ -20,9 +20,9 @@
*/
package com.drew.imaging.png;
-import com.drew.lang.SequentialReader;
import com.drew.lang.annotations.NotNull;
import com.drew.lang.annotations.Nullable;
+import com.drew.lang.ReaderInfo;
import java.io.IOException;
import java.util.*;
@@ -34,7 +34,7 @@ public class PngChunkReader
{
private static final byte[] PNG_SIGNATURE_BYTES = {(byte)0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A};
- public Iterable extract(@NotNull final SequentialReader reader, @Nullable final Set desiredChunkTypes) throws PngProcessingException, IOException
+ public Iterable extract(@NotNull ReaderInfo reader, @Nullable final Set desiredChunkTypes) throws PngProcessingException, IOException
{
//
// PNG DATA STREAM
@@ -70,6 +70,7 @@ public Iterable extract(@NotNull final SequentialReader reader, @Nulla
// Time information: tIME
//
+ reader = reader.Clone();
reader.setMotorolaByteOrder(true); // network byte order
if (!Arrays.equals(PNG_SIGNATURE_BYTES, reader.getBytes(PNG_SIGNATURE_BYTES.length))) {
@@ -93,11 +94,12 @@ public Iterable extract(@NotNull final SequentialReader reader, @Nulla
boolean willStoreChunk = desiredChunkTypes == null || desiredChunkTypes.contains(chunkType);
- byte[] chunkData = reader.getBytes(chunkDataLength);
+ ReaderInfo chunkReader = reader.Clone(chunkDataLength);
// Skip the CRC bytes at the end of the chunk
// TODO consider verifying the CRC value to determine if we're processing bad data
- reader.skip(4);
+ //reader.skip(4);
+ reader.skip(chunkDataLength);
if (willStoreChunk && seenChunkTypes.contains(chunkType) && !chunkType.areMultipleAllowed()) {
throw new PngProcessingException(String.format("Observed multiple instances of PNG chunk '%s', for which multiples are not allowed", chunkType));
@@ -114,9 +116,13 @@ public Iterable extract(@NotNull final SequentialReader reader, @Nulla
}
if (willStoreChunk) {
- chunks.add(new PngChunk(chunkType, chunkData));
+ chunks.add(new PngChunk(chunkType, chunkReader));
}
+ // Skip the CRC bytes at the end of the chunk
+ // TODO consider verifying the CRC value to determine if we're processing bad data
+ reader.skip(4);
+
seenChunkTypes.add(chunkType);
}
diff --git a/Source/com/drew/imaging/png/PngHeader.java b/Source/com/drew/imaging/png/PngHeader.java
index 81fef4f57..97903e8bb 100644
--- a/Source/com/drew/imaging/png/PngHeader.java
+++ b/Source/com/drew/imaging/png/PngHeader.java
@@ -20,9 +20,8 @@
*/
package com.drew.imaging.png;
-import com.drew.lang.SequentialByteArrayReader;
-import com.drew.lang.SequentialReader;
import com.drew.lang.annotations.NotNull;
+import com.drew.lang.ReaderInfo;
import java.io.IOException;
@@ -40,12 +39,11 @@ public class PngHeader
private byte _filterMethod;
private byte _interlaceMethod;
- public PngHeader(@NotNull byte[] bytes) throws PngProcessingException
+ public PngHeader(@NotNull ReaderInfo reader) throws PngProcessingException, IOException
{
- if (bytes.length != 13) {
+ if (reader.getLength() != 13) {
throw new PngProcessingException("PNG header chunk must have 13 data bytes");
}
- SequentialReader reader = new SequentialByteArrayReader(bytes);
try {
_imageWidth = reader.getInt32();
_imageHeight = reader.getInt32();
diff --git a/Source/com/drew/imaging/png/PngMetadataReader.java b/Source/com/drew/imaging/png/PngMetadataReader.java
index a30012b62..8c8e8fe96 100644
--- a/Source/com/drew/imaging/png/PngMetadataReader.java
+++ b/Source/com/drew/imaging/png/PngMetadataReader.java
@@ -83,7 +83,7 @@ public static Metadata readMetadata(@NotNull File file) throws PngProcessingExce
InputStream inputStream = new FileInputStream(file);
Metadata metadata;
try {
- metadata = readMetadata(inputStream);
+ metadata = readMetadata(new RandomAccessStream(inputStream, file.length()).createReader());
} finally {
inputStream.close();
}
@@ -92,9 +92,9 @@ public static Metadata readMetadata(@NotNull File file) throws PngProcessingExce
}
@NotNull
- public static Metadata readMetadata(@NotNull InputStream inputStream) throws PngProcessingException, IOException
+ public static Metadata readMetadata(@NotNull ReaderInfo reader) throws PngProcessingException, IOException
{
- Iterable chunks = new PngChunkReader().extract(new StreamReader(inputStream), _desiredChunkTypes);
+ Iterable chunks = new PngChunkReader().extract(reader, _desiredChunkTypes);
Metadata metadata = new Metadata();
@@ -112,10 +112,9 @@ public static Metadata readMetadata(@NotNull InputStream inputStream) throws Png
private static void processChunk(@NotNull Metadata metadata, @NotNull PngChunk chunk) throws PngProcessingException, IOException
{
PngChunkType chunkType = chunk.getType();
- byte[] bytes = chunk.getBytes();
if (chunkType.equals(PngChunkType.IHDR)) {
- PngHeader header = new PngHeader(bytes);
+ PngHeader header = new PngHeader(chunk.getReader());
PngDirectory directory = new PngDirectory(PngChunkType.IHDR);
directory.setInt(PngDirectory.TAG_IMAGE_WIDTH, header.getImageWidth());
directory.setInt(PngDirectory.TAG_IMAGE_HEIGHT, header.getImageHeight());
@@ -127,19 +126,19 @@ private static void processChunk(@NotNull Metadata metadata, @NotNull PngChunk c
metadata.addDirectory(directory);
} else if (chunkType.equals(PngChunkType.PLTE)) {
PngDirectory directory = new PngDirectory(PngChunkType.PLTE);
- directory.setInt(PngDirectory.TAG_PALETTE_SIZE, bytes.length / 3);
+ directory.setInt(PngDirectory.TAG_PALETTE_SIZE, (int)chunk.getReader().getLength() / 3);
metadata.addDirectory(directory);
} else if (chunkType.equals(PngChunkType.tRNS)) {
PngDirectory directory = new PngDirectory(PngChunkType.tRNS);
directory.setInt(PngDirectory.TAG_PALETTE_HAS_TRANSPARENCY, 1);
metadata.addDirectory(directory);
} else if (chunkType.equals(PngChunkType.sRGB)) {
- int srgbRenderingIntent = bytes[0];
+ int srgbRenderingIntent = chunk.getReader().getInt8(); // bytes[0];
PngDirectory directory = new PngDirectory(PngChunkType.sRGB);
directory.setInt(PngDirectory.TAG_SRGB_RENDERING_INTENT, srgbRenderingIntent);
metadata.addDirectory(directory);
} else if (chunkType.equals(PngChunkType.cHRM)) {
- PngChromaticities chromaticities = new PngChromaticities(bytes);
+ PngChromaticities chromaticities = new PngChromaticities(chunk.getReader());
PngChromaticitiesDirectory directory = new PngChromaticitiesDirectory();
directory.setInt(PngChromaticitiesDirectory.TAG_WHITE_POINT_X, chromaticities.getWhitePointX());
directory.setInt(PngChromaticitiesDirectory.TAG_WHITE_POINT_Y, chromaticities.getWhitePointY());
@@ -151,29 +150,30 @@ private static void processChunk(@NotNull Metadata metadata, @NotNull PngChunk c
directory.setInt(PngChromaticitiesDirectory.TAG_BLUE_Y, chromaticities.getBlueY());
metadata.addDirectory(directory);
} else if (chunkType.equals(PngChunkType.gAMA)) {
- int gammaInt = ByteConvert.toInt32BigEndian(bytes);
- new SequentialByteArrayReader(bytes).getInt32();
+ int gammaInt = ByteConvert.toInt32BigEndian(chunk.getReader().toArray());
PngDirectory directory = new PngDirectory(PngChunkType.gAMA);
directory.setDouble(PngDirectory.TAG_GAMMA, gammaInt / 100000.0);
metadata.addDirectory(directory);
} else if (chunkType.equals(PngChunkType.iCCP)) {
- SequentialReader reader = new SequentialByteArrayReader(bytes);
+ ReaderInfo reader = chunk.getReader();
// Profile Name is 1-79 bytes, followed by the 1 byte null character
- byte[] profileNameBytes = reader.getNullTerminatedBytes(79 + 1);
+ StringValue profileName = reader.getNullTerminatedStringValue(79 + 1, _latin1Encoding);
PngDirectory directory = new PngDirectory(PngChunkType.iCCP);
- directory.setStringValue(PngDirectory.TAG_ICC_PROFILE_NAME, new StringValue(profileNameBytes, _latin1Encoding));
+ directory.setStringValue(PngDirectory.TAG_ICC_PROFILE_NAME, profileName);
byte compressionMethod = reader.getInt8();
// Only compression method allowed by the spec is zero: deflate
if (compressionMethod == 0) {
// bytes left for compressed text is:
// total bytes length - (profilenamebytes length + null byte + compression method byte)
- int bytesLeft = bytes.length - (profileNameBytes.length + 1 + 1);
+ int bytesLeft = (int)reader.getLength() - (profileName.getBytes().length + 1 + 1);
+
byte[] compressedProfile = reader.getBytes(bytesLeft);
try {
InflaterInputStream inflateStream = new InflaterInputStream(new ByteArrayInputStream(compressedProfile));
- new IccReader().extract(new RandomAccessStreamReader(inflateStream), metadata, directory);
+ // the inflate stream is compressed so the length is unknown. Set to Integer max...
+ new IccReader().extract(new RandomAccessStream(inflateStream, Integer.MAX_VALUE).createReader(), metadata, directory);
inflateStream.close();
} catch(java.util.zip.ZipException zex) {
directory.addError(String.format("Exception decompressing PNG iCCP chunk : %s", zex.getMessage()));
@@ -184,27 +184,29 @@ private static void processChunk(@NotNull Metadata metadata, @NotNull PngChunk c
}
metadata.addDirectory(directory);
} else if (chunkType.equals(PngChunkType.bKGD)) {
+ byte[] bytes = chunk.getReader().toArray();
PngDirectory directory = new PngDirectory(PngChunkType.bKGD);
directory.setByteArray(PngDirectory.TAG_BACKGROUND_COLOR, bytes);
metadata.addDirectory(directory);
} else if (chunkType.equals(PngChunkType.tEXt)) {
- SequentialReader reader = new SequentialByteArrayReader(bytes);
-
+ ReaderInfo reader = chunk.getReader();
+
// Keyword is 1-79 bytes, followed by the 1 byte null character
StringValue keywordsv = reader.getNullTerminatedStringValue(79 + 1, _latin1Encoding);
String keyword = keywordsv.toString();
// bytes left for text is:
// total bytes length - (Keyword length + null byte)
- int bytesLeft = bytes.length - (keywordsv.getBytes().length + 1);
+ int bytesLeft = (int)reader.getLength() - (keywordsv.getBytes().length + 1);
StringValue value = reader.getNullTerminatedStringValue(bytesLeft, _latin1Encoding);
+
List textPairs = new ArrayList();
textPairs.add(new KeyValuePair(keyword, value));
PngDirectory directory = new PngDirectory(PngChunkType.tEXt);
directory.setObject(PngDirectory.TAG_TEXTUAL_DATA, textPairs);
metadata.addDirectory(directory);
} else if (chunkType.equals(PngChunkType.zTXt)) {
- SequentialReader reader = new SequentialByteArrayReader(bytes);
+ ReaderInfo reader = chunk.getReader();
// Keyword is 1-79 bytes, followed by the 1 byte null character
StringValue keywordsv = reader.getNullTerminatedStringValue(79 + 1, _latin1Encoding);
@@ -213,11 +215,14 @@ private static void processChunk(@NotNull Metadata metadata, @NotNull PngChunk c
// bytes left for compressed text is:
// total bytes length - (Keyword length + null byte + compression method byte)
- int bytesLeft = bytes.length - (keywordsv.getBytes().length + 1 + 1);
+ int bytesLeft = (int)reader.getLength() - (keywordsv.getBytes().length + 1 + 1);
byte[] textBytes = null;
if (compressionMethod == 0) {
try {
- textBytes = StreamUtil.readAllBytes(new InflaterInputStream(new ByteArrayInputStream(bytes, bytes.length - bytesLeft, bytesLeft)));
+ byte[] bytes = chunk.getReader().getBytes((int)chunk.getReader().getLength() - bytesLeft, bytesLeft);
+ InflaterInputStream inflateStream = new InflaterInputStream(new ByteArrayInputStream(bytes));
+ textBytes = StreamUtil.readAllBytes(inflateStream);
+ inflateStream.close();
} catch(java.util.zip.ZipException zex) {
textBytes = null;
PngDirectory directory = new PngDirectory(PngChunkType.zTXt);
@@ -242,27 +247,30 @@ private static void processChunk(@NotNull Metadata metadata, @NotNull PngChunk c
}
}
} else if (chunkType.equals(PngChunkType.iTXt)) {
- SequentialReader reader = new SequentialByteArrayReader(bytes);
+ ReaderInfo reader = chunk.getReader();
// Keyword is 1-79 bytes, followed by the 1 byte null character
- StringValue keywordsv = reader.getNullTerminatedStringValue(79 + 1, _latin1Encoding);
+ StringValue keywordsv = reader.getNullTerminatedStringValue(79, _latin1Encoding);
String keyword = keywordsv.toString();
byte compressionFlag = reader.getInt8();
byte compressionMethod = reader.getInt8();
// TODO we currently ignore languageTagBytes and translatedKeywordBytes
- byte[] languageTagBytes = reader.getNullTerminatedBytes(bytes.length);
- byte[] translatedKeywordBytes = reader.getNullTerminatedBytes(bytes.length);
+ byte[] languageTagBytes = reader.getNullTerminatedBytes((int)reader.getLength());
+ byte[] translatedKeywordBytes = reader.getNullTerminatedBytes((int)reader.getLength());
// bytes left for compressed text is:
// total bytes length - (Keyword length + null byte + comp flag byte + comp method byte + lang length + null byte + translated length + null byte)
- int bytesLeft = bytes.length - (keywordsv.getBytes().length + 1 + 1 + 1 + languageTagBytes.length + 1 + translatedKeywordBytes.length + 1);
+ int bytesLeft = (int)reader.getLength() - (keywordsv.getBytes().length + 1 + 1 + 1 + languageTagBytes.length + 1 + translatedKeywordBytes.length + 1);
byte[] textBytes = null;
if (compressionFlag == 0) {
textBytes = reader.getNullTerminatedBytes(bytesLeft);
} else if (compressionFlag == 1) {
if (compressionMethod == 0) {
try {
- textBytes = StreamUtil.readAllBytes(new InflaterInputStream(new ByteArrayInputStream(bytes, bytes.length - bytesLeft, bytesLeft)));
+ byte[] bytes = chunk.getReader().getBytes((int)chunk.getReader().getLength() - bytesLeft, bytesLeft);
+ InflaterInputStream inflateStream = new InflaterInputStream(new ByteArrayInputStream(bytes));
+ textBytes = StreamUtil.readAllBytes(inflateStream);
+ inflateStream.close();
} catch(java.util.zip.ZipException zex) {
textBytes = null;
PngDirectory directory = new PngDirectory(PngChunkType.iTXt);
@@ -293,7 +301,7 @@ private static void processChunk(@NotNull Metadata metadata, @NotNull PngChunk c
}
}
} else if (chunkType.equals(PngChunkType.tIME)) {
- SequentialByteArrayReader reader = new SequentialByteArrayReader(bytes);
+ ReaderInfo reader = chunk.getReader();
int year = reader.getUInt16();
int month = reader.getUInt8();
int day = reader.getUInt8();
@@ -311,7 +319,7 @@ private static void processChunk(@NotNull Metadata metadata, @NotNull PngChunk c
}
metadata.addDirectory(directory);
} else if (chunkType.equals(PngChunkType.pHYs)) {
- SequentialByteArrayReader reader = new SequentialByteArrayReader(bytes);
+ ReaderInfo reader = chunk.getReader();
int pixelsPerUnitX = reader.getInt32();
int pixelsPerUnitY = reader.getInt32();
byte unitSpecifier = reader.getInt8();
@@ -321,6 +329,7 @@ private static void processChunk(@NotNull Metadata metadata, @NotNull PngChunk c
directory.setInt(PngDirectory.TAG_UNIT_SPECIFIER, unitSpecifier);
metadata.addDirectory(directory);
} else if (chunkType.equals(PngChunkType.sBIT)) {
+ byte[] bytes = chunk.getReader().toArray();
PngDirectory directory = new PngDirectory(PngChunkType.sBIT);
directory.setByteArray(PngDirectory.TAG_SIGNIFICANT_BITS, bytes);
metadata.addDirectory(directory);
diff --git a/Source/com/drew/imaging/psd/PsdMetadataReader.java b/Source/com/drew/imaging/psd/PsdMetadataReader.java
index 8f2001ea7..8ea417e21 100644
--- a/Source/com/drew/imaging/psd/PsdMetadataReader.java
+++ b/Source/com/drew/imaging/psd/PsdMetadataReader.java
@@ -21,8 +21,9 @@
package com.drew.imaging.psd;
-import com.drew.lang.StreamReader;
import com.drew.lang.annotations.NotNull;
+import com.drew.lang.RandomAccessStream;
+import com.drew.lang.ReaderInfo;
import com.drew.metadata.Metadata;
import com.drew.metadata.file.FileSystemMetadataReader;
import com.drew.metadata.photoshop.PsdReader;
@@ -42,7 +43,7 @@ public static Metadata readMetadata(@NotNull File file) throws IOException
InputStream inputStream = new FileInputStream(file);
Metadata metadata;
try {
- metadata = readMetadata(inputStream);
+ metadata = readMetadata(new RandomAccessStream(inputStream, file.length()).createReader());
} finally {
inputStream.close();
}
@@ -51,10 +52,10 @@ public static Metadata readMetadata(@NotNull File file) throws IOException
}
@NotNull
- public static Metadata readMetadata(@NotNull InputStream inputStream)
+ public static Metadata readMetadata(@NotNull ReaderInfo reader)
{
Metadata metadata = new Metadata();
- new PsdReader().extract(new StreamReader(inputStream), metadata);
+ new PsdReader().extract(reader, metadata);
return metadata;
}
}
diff --git a/Source/com/drew/imaging/quicktime/QuickTimeMetadataReader.java b/Source/com/drew/imaging/quicktime/QuickTimeMetadataReader.java
index b1fee85ce..2eb4ea513 100644
--- a/Source/com/drew/imaging/quicktime/QuickTimeMetadataReader.java
+++ b/Source/com/drew/imaging/quicktime/QuickTimeMetadataReader.java
@@ -22,6 +22,8 @@
import com.drew.imaging.ImageProcessingException;
import com.drew.lang.annotations.NotNull;
+import com.drew.lang.RandomAccessStream;
+import com.drew.lang.ReaderInfo;
import com.drew.metadata.Metadata;
import com.drew.metadata.file.FileSystemMetadataReader;
import com.drew.metadata.mov.QuickTimeAtomHandler;
@@ -39,7 +41,7 @@ public static Metadata readMetadata(@NotNull final File file) throws ImageProces
InputStream inputStream = new FileInputStream(file);
Metadata metadata;
try {
- metadata = readMetadata(inputStream);
+ metadata = readMetadata(new RandomAccessStream(inputStream, file.length()).createReader());
} finally {
inputStream.close();
}
@@ -48,10 +50,10 @@ public static Metadata readMetadata(@NotNull final File file) throws ImageProces
}
@NotNull
- public static Metadata readMetadata(@NotNull InputStream inputStream)
+ public static Metadata readMetadata(@NotNull ReaderInfo reader)
{
Metadata metadata = new Metadata();
- QuickTimeReader.extract(inputStream, new QuickTimeAtomHandler(metadata));
+ QuickTimeReader.extract(reader, new QuickTimeAtomHandler(metadata));
return metadata;
}
}
diff --git a/Source/com/drew/imaging/quicktime/QuickTimeReader.java b/Source/com/drew/imaging/quicktime/QuickTimeReader.java
index b011b2e8f..747bdeb93 100644
--- a/Source/com/drew/imaging/quicktime/QuickTimeReader.java
+++ b/Source/com/drew/imaging/quicktime/QuickTimeReader.java
@@ -20,14 +20,13 @@
*/
package com.drew.imaging.quicktime;
-import com.drew.lang.StreamReader;
import com.drew.lang.annotations.NotNull;
+import com.drew.lang.ReaderInfo;
import com.drew.metadata.Metadata;
import com.drew.metadata.mov.QuickTimeDirectory;
import com.drew.metadata.mov.atoms.Atom;
import java.io.IOException;
-import java.io.InputStream;
/**
* @author Payton Garland
@@ -36,18 +35,17 @@ public class QuickTimeReader
{
private QuickTimeReader() {}
- public static void extract(@NotNull InputStream inputStream, @NotNull QuickTimeHandler handler)
+ public static void extract(@NotNull ReaderInfo reader, @NotNull QuickTimeHandler handler)
{
- StreamReader reader = new StreamReader(inputStream);
reader.setMotorolaByteOrder(true);
processAtoms(reader, -1, handler);
}
- private static void processAtoms(StreamReader reader, long atomEnd, QuickTimeHandler handler)
+ private static void processAtoms(ReaderInfo reader, long atomEnd, QuickTimeHandler handler)
{
try {
- while (atomEnd == -1 || reader.getPosition() < atomEnd) {
+ while (atomEnd == -1 || reader.getLocalPosition() < atomEnd) {
Atom atom = new Atom(reader);
@@ -55,7 +53,7 @@ private static void processAtoms(StreamReader reader, long atomEnd, QuickTimeHan
// Unknown atoms will be skipped
if (handler.shouldAcceptContainer(atom)) {
- processAtoms(reader, atom.size + reader.getPosition() - 8, handler.processContainer(atom));
+ processAtoms(reader, atom.size + reader.getLocalPosition() - 8, handler.processContainer(atom));
} else if (handler.shouldAcceptAtom(atom)) {
handler = handler.processAtom(atom, reader.getBytes((int)atom.size - 8));
} else if (atom.size > 1) {
diff --git a/Source/com/drew/imaging/raf/RafMetadataReader.java b/Source/com/drew/imaging/raf/RafMetadataReader.java
index c3e6842b7..48c7fc68e 100644
--- a/Source/com/drew/imaging/raf/RafMetadataReader.java
+++ b/Source/com/drew/imaging/raf/RafMetadataReader.java
@@ -22,7 +22,9 @@
import com.drew.imaging.jpeg.JpegMetadataReader;
import com.drew.imaging.jpeg.JpegProcessingException;
+import com.drew.lang.RandomAccessStream;
import com.drew.lang.annotations.NotNull;
+import com.drew.lang.ReaderInfo;
import com.drew.metadata.Metadata;
import com.drew.metadata.file.FileSystemMetadataReader;
@@ -45,7 +47,7 @@ public static Metadata readMetadata(@NotNull File file) throws JpegProcessingExc
InputStream inputStream = new FileInputStream(file);
Metadata metadata;
try {
- metadata = readMetadata(inputStream);
+ metadata = readMetadata(new RandomAccessStream(inputStream, file.length()).createReader());
} finally {
inputStream.close();
}
@@ -54,32 +56,25 @@ public static Metadata readMetadata(@NotNull File file) throws JpegProcessingExc
}
@NotNull
- public static Metadata readMetadata(@NotNull InputStream inputStream) throws JpegProcessingException, IOException
+ public static Metadata readMetadata(@NotNull ReaderInfo reader) throws JpegProcessingException, IOException
{
- if (!inputStream.markSupported())
- throw new IOException("Stream must support mark/reset");
-
- inputStream.mark(512);
-
byte[] data = new byte[512];
- int bytesRead = inputStream.read(data);
+ int bytesRead = reader.read(data, 0, 512);
if (bytesRead == -1)
throw new IOException("Stream is empty");
- inputStream.reset();
+ reader.skip(-bytesRead);
for (int i = 0; i < bytesRead - 2; i++) {
// Look for the first three bytes of a JPEG encoded file
if (data[i] == (byte) 0xff && data[i + 1] == (byte) 0xd8 && data[i + 2] == (byte) 0xff) {
- long bytesSkipped = inputStream.skip(i);
- if (bytesSkipped != i)
- throw new IOException("Skipping stream bytes failed");
+ reader.skip(i);
break;
}
}
- return JpegMetadataReader.readMetadata(inputStream);
+ return JpegMetadataReader.readMetadata(reader);
}
private RafMetadataReader() throws Exception
diff --git a/Source/com/drew/imaging/riff/RiffHandler.java b/Source/com/drew/imaging/riff/RiffHandler.java
index 465816fd3..f788b161e 100644
--- a/Source/com/drew/imaging/riff/RiffHandler.java
+++ b/Source/com/drew/imaging/riff/RiffHandler.java
@@ -20,8 +20,11 @@
*/
package com.drew.imaging.riff;
+import com.drew.lang.ReaderInfo;
import com.drew.lang.annotations.NotNull;
+import java.io.IOException;
+
/**
* Interface of an class capable of handling events raised during the reading of a RIFF file
* via {@link RiffReader}.
@@ -43,11 +46,11 @@ public interface RiffHandler
/**
* Gets whether this handler is interested in the specific chunk type.
* Returns true
if the data should be copied into an array and passed
- * to {@link RiffHandler#processChunk(String, byte[])}, or false
to avoid
+ * to {@link RiffHandler#processChunk(String, ReaderInfo)}, or false
to avoid
* the copy and skip to the next chunk in the file, if any.
*
* @param fourCC the four character code of this chunk
- * @return true if {@link RiffHandler#processChunk(String, byte[])} should be called, otherwise false
+ * @return true if {@link RiffHandler#processChunk(String, ReaderInfo)} should be called, otherwise false
*/
boolean shouldAcceptChunk(@NotNull String fourCC);
@@ -57,7 +60,7 @@ public interface RiffHandler
* or false
to avoid any unknown chunks within the list.
*
* @param fourCC the four character code of this chunk
- * @return true if {@link RiffHandler#processChunk(String, byte[])} should be called, otherwise false
+ * @return true if {@link RiffHandler#processChunk(String, ReaderInfo)} should be called, otherwise false
*/
boolean shouldAcceptList(@NotNull String fourCC);
@@ -71,5 +74,5 @@ public interface RiffHandler
* @param fourCC the four character code of the chunk
* @param payload they payload of the chunk as a byte array
*/
- void processChunk(@NotNull String fourCC, @NotNull byte[] payload);
+ void processChunk(@NotNull String fourCC, @NotNull ReaderInfo payload) throws IOException;
}
diff --git a/Source/com/drew/imaging/riff/RiffReader.java b/Source/com/drew/imaging/riff/RiffReader.java
index 43ca1a4da..d2661f21b 100644
--- a/Source/com/drew/imaging/riff/RiffReader.java
+++ b/Source/com/drew/imaging/riff/RiffReader.java
@@ -20,7 +20,8 @@
*/
package com.drew.imaging.riff;
-import com.drew.lang.SequentialReader;
+import com.drew.lang.Charsets;
+import com.drew.lang.ReaderInfo;
import com.drew.lang.annotations.NotNull;
import java.io.IOException;
@@ -42,13 +43,13 @@ public class RiffReader
/**
* Processes a RIFF data sequence.
*
- * @param reader the {@link SequentialReader} from which the data should be read
+ * @param reader the {@link ReaderInfo} from which the data should be read
* @param handler the {@link RiffHandler} that will coordinate processing and accept read values
* @throws RiffProcessingException if an error occurred during the processing of RIFF data that could not be
* ignored or recovered from
* @throws IOException an error occurred while accessing the required data
*/
- public void processRiff(@NotNull final SequentialReader reader,
+ public void processRiff(@NotNull ReaderInfo reader,
@NotNull final RiffHandler handler) throws RiffProcessingException, IOException
{
// RIFF files are always little-endian
@@ -56,7 +57,7 @@ public void processRiff(@NotNull final SequentialReader reader,
// PROCESS FILE HEADER
- final String fileFourCC = reader.getString(4);
+ final String fileFourCC = reader.getString(4, Charsets.ASCII);
if (!fileFourCC.equals("RIFF"))
throw new RiffProcessingException("Invalid RIFF header: " + fileFourCC);
@@ -65,7 +66,7 @@ public void processRiff(@NotNull final SequentialReader reader,
final int fileSize = reader.getInt32();
int sizeLeft = fileSize;
- final String identifier = reader.getString(4);
+ final String identifier = reader.getString(4, Charsets.ASCII);
sizeLeft -= 4;
if (!handler.shouldAcceptRiffIdentifier(identifier))
@@ -75,27 +76,41 @@ public void processRiff(@NotNull final SequentialReader reader,
processChunks(reader, sizeLeft, handler);
}
- public void processChunks(SequentialReader reader, int sectionSize, RiffHandler handler) throws IOException
+ public void processChunks(ReaderInfo reader, int sizeLeft, RiffHandler handler) throws IOException, RiffProcessingException
{
- while (reader.getPosition() < sectionSize) {
- String fourCC = new String(reader.getBytes(4));
- int size = reader.getInt32();
- if (fourCC.equals("LIST") || fourCC.equals("RIFF")) {
+ // Processing chunks. Each chunk is 8 bytes header (4 bytes CC code + 4 bytes length of chunk) + data of the chunk
+ while (reader.getLocalPosition() < sizeLeft) {
+ // Check if end of the file is closer then 8 bytes
+ if (reader.isCloserToEnd(8)) return;
+
+ String chunkFourCC = new String(reader.getBytes(4));
+ int chunkSize = reader.getInt32();
+
+ // NOTE we fail a negative chunk size here (greater than 0x7FFFFFFF) as we cannot allocate arrays larger than this
+ if (chunkSize < 0 || sizeLeft < chunkSize)
+ throw new RiffProcessingException("Invalid RIFF chunk size");
+
+ // Check if end of the file is closer then chunkSize bytes
+ if (reader.isCloserToEnd(chunkSize)) return;
+
+ if (chunkFourCC.equals("LIST") || chunkFourCC.equals("RIFF")) {
String listName = new String(reader.getBytes(4));
if (handler.shouldAcceptList(listName)) {
- processChunks(reader, size - 4, handler);
+ processChunks(reader, sizeLeft - 4, handler);
} else {
- reader.skip(size - 4);
+ reader.skip(sizeLeft - 4);
}
} else {
- if (handler.shouldAcceptChunk(fourCC)) {
+ if (handler.shouldAcceptChunk(chunkFourCC)) {
// TODO is it feasible to avoid copying the chunk here, and to pass the sequential reader to the handler?
- handler.processChunk(fourCC, reader.getBytes(size));
- } else {
- reader.skip(size);
+ // Update: solved with ReaderInfo
+ handler.processChunk(chunkFourCC, reader.Clone(chunkSize));
}
+
+ reader.skip(chunkSize);
+
// Bytes read must be even - skip one if not
- if (size % 2 == 1) {
+ if (chunkSize % 2 == 1) {
reader.skip(1);
}
}
diff --git a/Source/com/drew/imaging/tiff/TiffHandler.java b/Source/com/drew/imaging/tiff/TiffHandler.java
index fd24d06a3..1254934d4 100644
--- a/Source/com/drew/imaging/tiff/TiffHandler.java
+++ b/Source/com/drew/imaging/tiff/TiffHandler.java
@@ -20,7 +20,7 @@
*/
package com.drew.imaging.tiff;
-import com.drew.lang.RandomAccessReader;
+import com.drew.lang.ReaderInfo;
import com.drew.lang.Rational;
import com.drew.lang.annotations.NotNull;
import com.drew.lang.annotations.Nullable;
@@ -56,9 +56,8 @@ public interface TiffHandler
Long tryCustomProcessFormat(int tagId, int formatCode, long componentCount);
boolean customProcessTag(int tagOffset,
- @NotNull Set processedIfdOffsets,
- int tiffHeaderOffset,
- @NotNull RandomAccessReader reader,
+ @NotNull Set processedIfdOffsets,
+ @NotNull ReaderInfo reader,
int tagId,
int byteCount) throws IOException;
diff --git a/Source/com/drew/imaging/tiff/TiffMetadataReader.java b/Source/com/drew/imaging/tiff/TiffMetadataReader.java
index 1c0a7a53b..6734994d5 100644
--- a/Source/com/drew/imaging/tiff/TiffMetadataReader.java
+++ b/Source/com/drew/imaging/tiff/TiffMetadataReader.java
@@ -20,9 +20,8 @@
*/
package com.drew.imaging.tiff;
-import com.drew.lang.RandomAccessFileReader;
-import com.drew.lang.RandomAccessReader;
-import com.drew.lang.RandomAccessStreamReader;
+import com.drew.lang.RandomAccessStream;
+import com.drew.lang.ReaderInfo;
import com.drew.lang.annotations.NotNull;
import com.drew.metadata.Metadata;
import com.drew.metadata.exif.ExifTiffHandler;
@@ -45,7 +44,7 @@ public static Metadata readMetadata(@NotNull File file) throws IOException, Tiff
RandomAccessFile randomAccessFile = new RandomAccessFile(file, "r");
Metadata metadata;
try {
- metadata = readMetadata(new RandomAccessFileReader(randomAccessFile));
+ metadata = readMetadata(new RandomAccessStream(randomAccessFile).createReader());
} finally {
randomAccessFile.close();
}
@@ -54,21 +53,17 @@ public static Metadata readMetadata(@NotNull File file) throws IOException, Tiff
}
@NotNull
- public static Metadata readMetadata(@NotNull InputStream inputStream) throws IOException, TiffProcessingException
+ public static Metadata readMetadata(@NotNull InputStream inputStream, long streamLength) throws IOException, TiffProcessingException
{
- // TIFF processing requires random access, as directories can be scattered throughout the byte sequence.
- // InputStream does not support seeking backwards, so we wrap it with RandomAccessStreamReader, which
- // buffers data from the stream as we seek forward.
-
- return readMetadata(new RandomAccessStreamReader(inputStream));
+ return readMetadata(new RandomAccessStream(inputStream, streamLength).createReader());
}
@NotNull
- public static Metadata readMetadata(@NotNull RandomAccessReader reader) throws IOException, TiffProcessingException
+ public static Metadata readMetadata(@NotNull ReaderInfo reader) throws IOException, TiffProcessingException
{
Metadata metadata = new Metadata();
ExifTiffHandler handler = new ExifTiffHandler(metadata, null);
- new TiffReader().processTiff(reader, handler, 0);
+ new TiffReader().processTiff(reader, handler);
return metadata;
}
}
diff --git a/Source/com/drew/imaging/tiff/TiffReader.java b/Source/com/drew/imaging/tiff/TiffReader.java
index dd4aefe50..14b4c5072 100644
--- a/Source/com/drew/imaging/tiff/TiffReader.java
+++ b/Source/com/drew/imaging/tiff/TiffReader.java
@@ -20,7 +20,7 @@
*/
package com.drew.imaging.tiff;
-import com.drew.lang.RandomAccessReader;
+import com.drew.lang.ReaderInfo;
import com.drew.lang.Rational;
import com.drew.lang.annotations.NotNull;
@@ -38,44 +38,45 @@ public class TiffReader
/**
* Processes a TIFF data sequence.
*
- * @param reader the {@link RandomAccessReader} from which the data should be read
+ * @param reader the {@link ReaderInfo} from which the data should be read
* @param handler the {@link TiffHandler} that will coordinate processing and accept read values
- * @param tiffHeaderOffset the offset within reader
at which the TIFF header starts
* @throws TiffProcessingException if an error occurred during the processing of TIFF data that could not be
* ignored or recovered from
* @throws IOException an error occurred while accessing the required data
*/
- public void processTiff(@NotNull final RandomAccessReader reader,
- @NotNull final TiffHandler handler,
- final int tiffHeaderOffset) throws TiffProcessingException, IOException
+ public void processTiff(@NotNull ReaderInfo reader,
+ @NotNull final TiffHandler handler) throws TiffProcessingException, IOException
{
// This must be either "MM" or "II".
- short byteOrderIdentifier = reader.getInt16(tiffHeaderOffset);
+ short byteOrderIdentifier = reader.getInt16(0);
if (byteOrderIdentifier == 0x4d4d) { // "MM"
- reader.setMotorolaByteOrder(true);
+ if(!reader.isMotorolaByteOrder())
+ reader = reader.Clone(false);
} else if (byteOrderIdentifier == 0x4949) { // "II"
- reader.setMotorolaByteOrder(false);
+ if(reader.isMotorolaByteOrder())
+ reader = reader.Clone(false);
} else {
throw new TiffProcessingException("Unclear distinction between Motorola/Intel byte ordering: " + byteOrderIdentifier);
}
// Check the next two values for correctness.
- final int tiffMarker = reader.getUInt16(2 + tiffHeaderOffset);
+ final int tiffMarker = reader.getUInt16(2);
handler.setTiffMarker(tiffMarker);
- int firstIfdOffset = reader.getInt32(4 + tiffHeaderOffset) + tiffHeaderOffset;
+ int firstIfdOffset = reader.getInt32(4);
// David Ekholm sent a digital camera image that has this problem
// TODO getLength should be avoided as it causes RandomAccessStreamReader to read to the end of the stream
+ // Update: solved with RandomAccessReader and ReaderInfo implementation
if (firstIfdOffset >= reader.getLength() - 1) {
handler.warn("First IFD offset is beyond the end of the TIFF data segment -- trying default offset");
// First directory normally starts immediately after the offset bytes, so try that
- firstIfdOffset = tiffHeaderOffset + 2 + 2 + 4;
+ firstIfdOffset = 2 + 2 + 4;
}
- Set processedIfdOffsets = new HashSet();
- processIfd(handler, reader, processedIfdOffsets, firstIfdOffset, tiffHeaderOffset);
+ Set processedIfdOffsets = new HashSet();
+ processIfd(handler, reader, processedIfdOffsets, firstIfdOffset);
}
/**
@@ -95,27 +96,25 @@ public void processTiff(@NotNull final RandomAccessReader reader,
*
*
* @param handler the {@link com.drew.imaging.tiff.TiffHandler} that will coordinate processing and accept read values
- * @param reader the {@link com.drew.lang.RandomAccessReader} from which the data should be read
+ * @param reader the {@link ReaderInfo} from which the data should be read
* @param processedIfdOffsets the set of visited IFD offsets, to avoid revisiting the same IFD in an endless loop
* @param ifdOffset the offset within reader
at which the IFD data starts
- * @param tiffHeaderOffset the offset within reader
at which the TIFF header starts
* @throws IOException an error occurred while accessing the required data
*/
public static void processIfd(@NotNull final TiffHandler handler,
- @NotNull final RandomAccessReader reader,
- @NotNull final Set processedIfdOffsets,
- final int ifdOffset,
- final int tiffHeaderOffset) throws IOException
+ @NotNull ReaderInfo reader,
+ @NotNull final Set processedIfdOffsets,
+ final int ifdOffset) throws IOException
{
- Boolean resetByteOrder = null;
try {
// check for directories we've already visited to avoid stack overflows when recursive/cyclic directory structures exist
- if (processedIfdOffsets.contains(Integer.valueOf(ifdOffset))) {
+ long globalIfdOffset = reader.getStartPosition() + ifdOffset;
+ if (processedIfdOffsets.contains(globalIfdOffset)) {
return;
}
// remember that we've visited this directory so that we don't visit it again later
- processedIfdOffsets.add(ifdOffset);
+ processedIfdOffsets.add(globalIfdOffset);
if (ifdOffset >= reader.getLength() || ifdOffset < 0) {
handler.error("Ignored IFD marked to start outside data segment");
@@ -130,9 +129,8 @@ public static void processIfd(@NotNull final TiffHandler handler,
// Here we detect switched bytes that suggest this problem, and temporarily swap the byte order.
// This was discussed in GitHub issue #136.
if (dirTagCount > 0xFF && (dirTagCount & 0xFF) == 0) {
- resetByteOrder = reader.isMotorolaByteOrder();
dirTagCount >>= 8;
- reader.setMotorolaByteOrder(!reader.isMotorolaByteOrder());
+ reader = reader.Clone(false);
}
int dirLength = (2 + (12 * dirTagCount) + 4);
@@ -147,7 +145,7 @@ public static void processIfd(@NotNull final TiffHandler handler,
int invalidTiffFormatCodeCount = 0;
for (int tagNumber = 0; tagNumber < dirTagCount; tagNumber++) {
final int tagOffset = calculateTagOffset(ifdOffset, tagNumber);
-
+
// 2 bytes for the tag id
final int tagId = reader.getUInt16(tagOffset);
@@ -180,13 +178,12 @@ public static void processIfd(@NotNull final TiffHandler handler,
final long tagValueOffset;
if (byteCount > 4) {
// If it's bigger than 4 bytes, the dir entry contains an offset.
- final long offsetVal = reader.getUInt32(tagOffset + 8);
- if (offsetVal + byteCount > reader.getLength()) {
+ tagValueOffset = reader.getUInt32(tagOffset + 8);
+ if (tagValueOffset + byteCount > reader.getLength()) {
// Bogus pointer offset and / or byteCount value
handler.error("Illegal TIFF tag pointer offset");
continue;
}
- tagValueOffset = tiffHeaderOffset + offsetVal;
} else {
// 4 bytes or less and value is in the dir entry itself.
tagValueOffset = tagOffset + 8;
@@ -210,14 +207,14 @@ public static void processIfd(@NotNull final TiffHandler handler,
for (int i = 0; i < componentCount; i++) {
if (handler.tryEnterSubIfd(tagId)) {
isIfdPointer = true;
- int subDirOffset = tiffHeaderOffset + reader.getInt32((int) (tagValueOffset + i * 4));
- processIfd(handler, reader, processedIfdOffsets, subDirOffset, tiffHeaderOffset);
+ int subDirOffset = reader.getInt32((int) (tagValueOffset + i * 4));
+ processIfd(handler, reader, processedIfdOffsets, subDirOffset);
}
}
}
// If it wasn't an IFD pointer, allow custom tag processing to occur
- if (!isIfdPointer && !handler.customProcessTag((int) tagValueOffset, processedIfdOffsets, tiffHeaderOffset, reader, tagId, (int) byteCount)) {
+ if (!isIfdPointer && !handler.customProcessTag((int) tagValueOffset, processedIfdOffsets, reader, tagId, (int) byteCount)) {
// If no custom processing occurred, process the tag in the standard fashion
processTag(handler, tagId, (int) tagValueOffset, (int) componentCount, formatCode, reader);
}
@@ -227,7 +224,6 @@ public static void processIfd(@NotNull final TiffHandler handler,
final int finalTagOffset = calculateTagOffset(ifdOffset, dirTagCount);
int nextIfdOffset = reader.getInt32(finalTagOffset);
if (nextIfdOffset != 0) {
- nextIfdOffset += tiffHeaderOffset;
if (nextIfdOffset >= reader.getLength()) {
// Last 4 bytes of IFD reference another IFD with an address that is out of bounds
// Note this could have been caused by jhead 1.3 cropping too much
@@ -239,13 +235,11 @@ public static void processIfd(@NotNull final TiffHandler handler,
}
if (handler.hasFollowerIfd()) {
- processIfd(handler, reader, processedIfdOffsets, nextIfdOffset, tiffHeaderOffset);
+ processIfd(handler, reader, processedIfdOffsets, nextIfdOffset);
}
}
} finally {
handler.endingIFD();
- if (resetByteOrder != null)
- reader.setMotorolaByteOrder(resetByteOrder);
}
}
@@ -254,7 +248,7 @@ private static void processTag(@NotNull final TiffHandler handler,
final int tagValueOffset,
final int componentCount,
final int formatCode,
- @NotNull final RandomAccessReader reader) throws IOException
+ @NotNull final ReaderInfo reader) throws IOException
{
switch (formatCode) {
case TiffDataFormat.CODE_UNDEFINED:
diff --git a/Source/com/drew/imaging/wav/WavMetadataReader.java b/Source/com/drew/imaging/wav/WavMetadataReader.java
index d90a68a1b..d257d2c5b 100644
--- a/Source/com/drew/imaging/wav/WavMetadataReader.java
+++ b/Source/com/drew/imaging/wav/WavMetadataReader.java
@@ -22,7 +22,8 @@
import com.drew.imaging.riff.RiffProcessingException;
import com.drew.imaging.riff.RiffReader;
-import com.drew.lang.StreamReader;
+import com.drew.lang.RandomAccessStream;
+import com.drew.lang.ReaderInfo;
import com.drew.lang.annotations.NotNull;
import com.drew.metadata.Metadata;
import com.drew.metadata.file.FileSystemMetadataReader;
@@ -46,7 +47,7 @@ public static Metadata readMetadata(@NotNull File file) throws IOException, Riff
InputStream inputStream = new FileInputStream(file);
Metadata metadata;
try {
- metadata = readMetadata(inputStream);
+ metadata = readMetadata(new RandomAccessStream(inputStream, file.length()).createReader());
} finally {
inputStream.close();
}
@@ -55,10 +56,10 @@ public static Metadata readMetadata(@NotNull File file) throws IOException, Riff
}
@NotNull
- public static Metadata readMetadata(@NotNull InputStream inputStream) throws IOException, RiffProcessingException
+ public static Metadata readMetadata(@NotNull ReaderInfo reader) throws IOException, RiffProcessingException
{
Metadata metadata = new Metadata();
- new RiffReader().processRiff(new StreamReader(inputStream), new WavRiffHandler(metadata));
+ new RiffReader().processRiff(reader, new WavRiffHandler(metadata));
return metadata;
}
}
diff --git a/Source/com/drew/imaging/webp/WebpMetadataReader.java b/Source/com/drew/imaging/webp/WebpMetadataReader.java
index 5c150ae2b..d4b443d50 100644
--- a/Source/com/drew/imaging/webp/WebpMetadataReader.java
+++ b/Source/com/drew/imaging/webp/WebpMetadataReader.java
@@ -22,7 +22,8 @@
import com.drew.imaging.riff.RiffProcessingException;
import com.drew.imaging.riff.RiffReader;
-import com.drew.lang.StreamReader;
+import com.drew.lang.RandomAccessStream;
+import com.drew.lang.ReaderInfo;
import com.drew.lang.annotations.NotNull;
import com.drew.metadata.Metadata;
import com.drew.metadata.file.FileSystemMetadataReader;
@@ -43,7 +44,7 @@ public static Metadata readMetadata(@NotNull File file) throws IOException, Riff
InputStream inputStream = new FileInputStream(file);
Metadata metadata;
try {
- metadata = readMetadata(inputStream);
+ metadata = readMetadata(new RandomAccessStream(inputStream, file.length()).createReader());
} finally {
inputStream.close();
}
@@ -52,10 +53,10 @@ public static Metadata readMetadata(@NotNull File file) throws IOException, Riff
}
@NotNull
- public static Metadata readMetadata(@NotNull InputStream inputStream) throws IOException, RiffProcessingException
+ public static Metadata readMetadata(@NotNull ReaderInfo reader) throws IOException, RiffProcessingException
{
Metadata metadata = new Metadata();
- new RiffReader().processRiff(new StreamReader(inputStream), new WebpRiffHandler(metadata));
+ new RiffReader().processRiff(reader, new WebpRiffHandler(metadata));
return metadata;
}
}
diff --git a/Source/com/drew/lang/BufferBoundsException.java b/Source/com/drew/lang/BufferBoundsException.java
index 6045a0ac1..44b6d6827 100644
--- a/Source/com/drew/lang/BufferBoundsException.java
+++ b/Source/com/drew/lang/BufferBoundsException.java
@@ -24,7 +24,7 @@
import java.io.IOException;
/**
- * A checked replacement for {@link IndexOutOfBoundsException}. Used by {@link RandomAccessReader}.
+ * A checked replacement for {@link IndexOutOfBoundsException}. Used by {@link RandomAccessStream}.
*
* @author Drew Noakes https://drewnoakes.com
*/
diff --git a/Source/com/drew/lang/ByteArrayReader.java b/Source/com/drew/lang/ByteArrayReader.java
deleted file mode 100644
index f5e58f071..000000000
--- a/Source/com/drew/lang/ByteArrayReader.java
+++ /dev/null
@@ -1,107 +0,0 @@
-/*
- * Copyright 2002-2017 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:
- *
- * https://drewnoakes.com/code/exif/
- * https://github.com/drewnoakes/metadata-extractor
- */
-
-package com.drew.lang;
-
-import com.drew.lang.annotations.NotNull;
-
-import java.io.IOException;
-
-/**
- * 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
- * setMotorolaByteOrder(boolean)
.
- *
- * @author Drew Noakes https://drewnoakes.com
- * */
-public class ByteArrayReader extends RandomAccessReader
-{
- @NotNull
- private final byte[] _buffer;
- private final int _baseOffset;
-
- @SuppressWarnings({ "ConstantConditions" })
- @com.drew.lang.annotations.SuppressWarnings(value = "EI_EXPOSE_REP2", justification = "Design intent")
- public ByteArrayReader(@NotNull byte[] buffer)
- {
- this(buffer, 0);
- }
-
- @SuppressWarnings({ "ConstantConditions" })
- @com.drew.lang.annotations.SuppressWarnings(value = "EI_EXPOSE_REP2", justification = "Design intent")
- public ByteArrayReader(@NotNull byte[] buffer, int baseOffset)
- {
- if (buffer == null)
- throw new NullPointerException();
- if (baseOffset < 0)
- throw new IllegalArgumentException("Must be zero or greater");
-
- _buffer = buffer;
- _baseOffset = baseOffset;
- }
-
- @Override
- public int toUnshiftedOffset(int localOffset)
- {
- return localOffset + _baseOffset;
- }
-
- @Override
- public long getLength()
- {
- return _buffer.length - _baseOffset;
- }
-
- @Override
- public byte getByte(int index) throws IOException
- {
- validateIndex(index, 1);
- return _buffer[index + _baseOffset];
- }
-
- @Override
- protected void validateIndex(int index, int bytesRequested) throws IOException
- {
- if (!isValidIndex(index, bytesRequested))
- throw new BufferBoundsException(toUnshiftedOffset(index), bytesRequested, _buffer.length);
- }
-
- @Override
- protected boolean isValidIndex(int index, int bytesRequested) throws IOException
- {
- return bytesRequested >= 0
- && index >= 0
- && (long)index + (long)bytesRequested - 1L < getLength();
- }
-
- @Override
- @NotNull
- public byte[] getBytes(int index, int count) throws IOException
- {
- validateIndex(index, count);
-
- byte[] bytes = new byte[count];
- System.arraycopy(_buffer, index + _baseOffset, bytes, 0, count);
- return bytes;
- }
-}
diff --git a/Source/com/drew/lang/IterableWordReader.java b/Source/com/drew/lang/IterableWordReader.java
new file mode 100644
index 000000000..e6c6bdfc0
--- /dev/null
+++ b/Source/com/drew/lang/IterableWordReader.java
@@ -0,0 +1,106 @@
+/*
+ * Copyright 2002-2017 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:
+ *
+ * https://drewnoakes.com/code/exif/
+ * https://github.com/drewnoakes/metadata-extractor
+ */
+package com.drew.lang;
+
+import java.io.IOException;
+import java.util.Iterator;
+import java.util.LinkedList;
+
+/**
+ * Reads lines and words from a reader sequentially
+ *
+ * @author Kevin Mott https://github.com/kwhopper
+ * @author Drew Noakes https://drewnoakes.com
+ */
+public class IterableWordReader implements Iterable, Iterator
+{
+ private final ReaderInfo _reader;
+ private final LinkedList _stringLinkedList = new LinkedList();
+
+ public IterableWordReader(ReaderInfo reader)
+ {
+ _reader = reader;
+ }
+
+ // the next three methods implement Iterator
+ @Override
+ public boolean hasNext()
+ {
+ if(_stringLinkedList.isEmpty())
+ {
+ while(true)
+ {
+ String line = null;
+ try
+ {
+ line = _reader.readLine();
+ }
+ catch(IOException ignore)
+ {
+ return false;
+ }
+
+ if (line != null)
+ {
+ int commentFromIndex = line.indexOf('#');
+ if (commentFromIndex != -1)
+ line = line.substring(0, commentFromIndex);
+
+ String[] words = line.split("\\s+");
+ for (String word : words)
+ {
+ String wordtrim = word.trim();
+ if(wordtrim.length() > 0)
+ _stringLinkedList.add(wordtrim);
+ }
+ }
+
+ // it's possible for line to be a zero-length string instead
+ // of null. In that case, keep reading lines until the list
+ // already contains a string or finally get a null line
+ if(line == null || !_stringLinkedList.isEmpty())
+ break;
+ }
+ }
+
+ return !_stringLinkedList.isEmpty();
+ }
+
+ @Override
+ public String next()
+ {
+ if(hasNext())
+ return _stringLinkedList.pop();
+ return "";
+ }
+
+ @Override
+ public void remove()
+ {
+ throw new UnsupportedOperationException();
+ }
+
+ // this method implements Iterable
+ @Override
+ public Iterator iterator() {
+ return this;
+ }
+}
diff --git a/Source/com/drew/lang/RandomAccessFileReader.java b/Source/com/drew/lang/RandomAccessFileReader.java
deleted file mode 100644
index 5f23fbe13..000000000
--- a/Source/com/drew/lang/RandomAccessFileReader.java
+++ /dev/null
@@ -1,129 +0,0 @@
-/*
- * Copyright 2002-2017 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:
- *
- * https://drewnoakes.com/code/exif/
- * https://github.com/drewnoakes/metadata-extractor
- */
-
-package com.drew.lang;
-
-import com.drew.lang.annotations.NotNull;
-
-import java.io.IOException;
-import java.io.RandomAccessFile;
-
-/**
- * Provides methods to read specific values from a {@link RandomAccessFile}, with a consistent, checked exception structure for
- * issues.
- *
- * @author Drew Noakes https://drewnoakes.com
- * */
-public class RandomAccessFileReader extends RandomAccessReader
-{
- @NotNull
- private final RandomAccessFile _file;
- private final long _length;
- private int _currentIndex;
-
- private final int _baseOffset;
-
- @SuppressWarnings({ "ConstantConditions" })
- @com.drew.lang.annotations.SuppressWarnings(value = "EI_EXPOSE_REP2", justification = "Design intent")
- public RandomAccessFileReader(@NotNull RandomAccessFile file) throws IOException
- {
- this(file, 0);
- }
-
- @SuppressWarnings({ "ConstantConditions" })
- @com.drew.lang.annotations.SuppressWarnings(value = "EI_EXPOSE_REP2", justification = "Design intent")
- public RandomAccessFileReader(@NotNull RandomAccessFile file, int baseOffset) throws IOException
- {
- if (file == null)
- throw new NullPointerException();
-
- _file = file;
- _baseOffset = baseOffset;
- _length = _file.length();
- }
-
- @Override
- public int toUnshiftedOffset(int localOffset)
- {
- return localOffset + _baseOffset;
- }
-
- @Override
- public long getLength()
- {
- return _length;
- }
-
- @Override
- public byte getByte(int index) throws IOException
- {
- if (index != _currentIndex)
- seek(index);
-
- final int b = _file.read();
- if (b < 0)
- throw new BufferBoundsException("Unexpected end of file encountered.");
- assert (b <= 0xff);
- _currentIndex++;
- return (byte)b;
- }
-
- @Override
- @NotNull
- public byte[] getBytes(int index, int count) throws IOException
- {
- validateIndex(index, count);
-
- if (index != _currentIndex)
- seek(index);
-
- byte[] bytes = new byte[count];
- final int bytesRead = _file.read(bytes);
- _currentIndex += bytesRead;
- if (bytesRead != count)
- throw new BufferBoundsException("Unexpected end of file encountered.");
- return bytes;
- }
-
- private void seek(final int index) throws IOException
- {
- if (index == _currentIndex)
- return;
-
- _file.seek(index);
- _currentIndex = index;
- }
-
- @Override
- protected boolean isValidIndex(int index, int bytesRequested) throws IOException
- {
- return bytesRequested >= 0
- && index >= 0
- && (long)index + (long)bytesRequested - 1L < _length;
- }
-
- @Override
- protected void validateIndex(final int index, final int bytesRequested) throws IOException
- {
- if (!isValidIndex(index, bytesRequested))
- throw new BufferBoundsException(index, bytesRequested, _length);
- }
-}
diff --git a/Source/com/drew/lang/RandomAccessReader.java b/Source/com/drew/lang/RandomAccessReader.java
deleted file mode 100644
index 7e5987a42..000000000
--- a/Source/com/drew/lang/RandomAccessReader.java
+++ /dev/null
@@ -1,445 +0,0 @@
-/*
- * Copyright 2002-2017 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:
- *
- * https://drewnoakes.com/code/exif/
- * https://github.com/drewnoakes/metadata-extractor
- */
-
-package com.drew.lang;
-
-import com.drew.lang.annotations.NotNull;
-import com.drew.lang.annotations.Nullable;
-import com.drew.metadata.StringValue;
-
-import java.io.IOException;
-import java.io.UnsupportedEncodingException;
-import java.nio.charset.Charset;
-
-/**
- * Base class for random access data reading operations of common data types.
- *
- * By default, the reader operates with Motorola byte order (big endianness). This can be changed by calling
- * {@link com.drew.lang.RandomAccessReader#setMotorolaByteOrder(boolean)}.
- *
- * Concrete implementations include:
- *
- * - {@link ByteArrayReader}
- * - {@link RandomAccessStreamReader}
- *
- *
- * @author Drew Noakes https://drewnoakes.com
- */
-public abstract class RandomAccessReader
-{
- private boolean _isMotorolaByteOrder = true;
-
- public abstract int toUnshiftedOffset(int localOffset);
-
- /**
- * Gets the byte value at the specified byte index
.
- *
- * Implementations should not perform any bounds checking in this method. That should be performed
- * in validateIndex
and isValidIndex
.
- *
- * @param index The index from which to read the byte
- * @return The read byte value
- * @throws IllegalArgumentException index
is negative
- * @throws BufferBoundsException if the requested byte is beyond the end of the underlying data source
- * @throws IOException if the byte is unable to be read
- */
- public abstract byte getByte(int index) throws IOException;
-
- /**
- * Returns the required number of bytes from the specified index from the underlying source.
- *
- * @param index The index from which the bytes begins in the underlying source
- * @param count The number of bytes to be returned
- * @return The requested bytes
- * @throws IllegalArgumentException index
or count
are negative
- * @throws BufferBoundsException if the requested bytes extend beyond the end of the underlying data source
- * @throws IOException if the byte is unable to be read
- */
- @NotNull
- public abstract byte[] getBytes(int index, int count) throws IOException;
-
- /**
- * Ensures that the buffered bytes extend to cover the specified index. If not, an attempt is made
- * to read to that point.
- *
- * If the stream ends before the point is reached, a {@link BufferBoundsException} is raised.
- *
- * @param index the index from which the required bytes start
- * @param bytesRequested the number of bytes which are required
- * @throws IOException if the stream ends before the required number of bytes are acquired
- */
- protected abstract void validateIndex(int index, int bytesRequested) throws IOException;
-
- protected abstract boolean isValidIndex(int index, int bytesRequested) throws IOException;
-
- /**
- * Returns the length of the data source in bytes.
- *
- * This is a simple operation for implementations (such as {@link RandomAccessFileReader} and
- * {@link ByteArrayReader}) that have the entire data source available.
- *
- * Users of this method must be aware that sequentially accessed implementations such as
- * {@link RandomAccessStreamReader} will have to read and buffer the entire data source in
- * order to determine the length.
- *
- * @return the length of the data source, in bytes.
- */
- public abstract long getLength() throws IOException;
-
- /**
- * Sets the endianness of this reader.
- *
- * true
for Motorola (or big) endianness (also known as network byte order), with MSB before LSB.
- * false
for Intel (or little) endianness, with LSB before MSB.
- *
- *
- * @param motorolaByteOrder true
for Motorola/big endian, false
for Intel/little endian
- */
- public void setMotorolaByteOrder(boolean motorolaByteOrder)
- {
- _isMotorolaByteOrder = motorolaByteOrder;
- }
-
- /**
- * Gets the endianness of this reader.
- *
- * true
for Motorola (or big) endianness (also known as network byte order), with MSB before LSB.
- * false
for Intel (or little) endianness, with LSB before MSB.
- *
- */
- public boolean isMotorolaByteOrder()
- {
- return _isMotorolaByteOrder;
- }
-
- /**
- * Gets whether a bit at a specific index is set or not.
- *
- * @param index the number of bits at which to test
- * @return true if the bit is set, otherwise false
- * @throws IOException the buffer does not contain enough bytes to service the request, or index is negative
- */
- public boolean getBit(int index) throws IOException
- {
- int byteIndex = index / 8;
- int bitIndex = index % 8;
-
- validateIndex(byteIndex, 1);
-
- byte b = getByte(byteIndex);
- return ((b >> bitIndex) & 1) == 1;
- }
-
- /**
- * Returns an unsigned 8-bit int calculated from one byte of data at the specified index.
- *
- * @param index position within the data buffer to read byte
- * @return the 8 bit int value, between 0 and 255
- * @throws IOException the buffer does not contain enough bytes to service the request, or index is negative
- */
- public short getUInt8(int index) throws IOException
- {
- validateIndex(index, 1);
-
- return (short) (getByte(index) & 0xFF);
- }
-
- /**
- * Returns a signed 8-bit int calculated from one byte of data at the specified index.
- *
- * @param index position within the data buffer to read byte
- * @return the 8 bit int value, between 0x00 and 0xFF
- * @throws IOException the buffer does not contain enough bytes to service the request, or index is negative
- */
- public byte getInt8(int index) throws IOException
- {
- validateIndex(index, 1);
-
- return getByte(index);
- }
-
- /**
- * Returns an unsigned 16-bit int calculated from two bytes of data at the specified index.
- *
- * @param index position within the data buffer to read first byte
- * @return the 16 bit int value, between 0x0000 and 0xFFFF
- * @throws IOException the buffer does not contain enough bytes to service the request, or index is negative
- */
- public int getUInt16(int index) throws IOException
- {
- validateIndex(index, 2);
-
- if (_isMotorolaByteOrder) {
- // Motorola - MSB first
- return (getByte(index ) << 8 & 0xFF00) |
- (getByte(index + 1) & 0xFF);
- } else {
- // Intel ordering - LSB first
- return (getByte(index + 1) << 8 & 0xFF00) |
- (getByte(index ) & 0xFF);
- }
- }
-
- /**
- * Returns a signed 16-bit int calculated from two bytes of data at the specified index (MSB, LSB).
- *
- * @param index position within the data buffer to read first byte
- * @return the 16 bit int value, between 0x0000 and 0xFFFF
- * @throws IOException the buffer does not contain enough bytes to service the request, or index is negative
- */
- public short getInt16(int index) throws IOException
- {
- validateIndex(index, 2);
-
- if (_isMotorolaByteOrder) {
- // Motorola - MSB first
- return (short) (((short)getByte(index ) << 8 & (short)0xFF00) |
- ((short)getByte(index + 1) & (short)0xFF));
- } else {
- // Intel ordering - LSB first
- return (short) (((short)getByte(index + 1) << 8 & (short)0xFF00) |
- ((short)getByte(index ) & (short)0xFF));
- }
- }
-
- /**
- * Get a 24-bit unsigned integer from the buffer, returning it as an int.
- *
- * @param index position within the data buffer to read first byte
- * @return the unsigned 24-bit int value as a long, between 0x00000000 and 0x00FFFFFF
- * @throws IOException the buffer does not contain enough bytes to service the request, or index is negative
- */
- public int getInt24(int index) throws IOException
- {
- validateIndex(index, 3);
-
- if (_isMotorolaByteOrder) {
- // Motorola - MSB first (big endian)
- return (((int)getByte(index )) << 16 & 0xFF0000) |
- (((int)getByte(index + 1)) << 8 & 0xFF00) |
- (((int)getByte(index + 2)) & 0xFF);
- } else {
- // Intel ordering - LSB first (little endian)
- return (((int)getByte(index + 2)) << 16 & 0xFF0000) |
- (((int)getByte(index + 1)) << 8 & 0xFF00) |
- (((int)getByte(index )) & 0xFF);
- }
- }
-
- /**
- * Get a 32-bit unsigned integer from the buffer, returning it as a long.
- *
- * @param index position within the data buffer to read first byte
- * @return the unsigned 32-bit int value as a long, between 0x00000000 and 0xFFFFFFFF
- * @throws IOException the buffer does not contain enough bytes to service the request, or index is negative
- */
- public long getUInt32(int index) throws IOException
- {
- validateIndex(index, 4);
-
- if (_isMotorolaByteOrder) {
- // Motorola - MSB first (big endian)
- return (((long)getByte(index )) << 24 & 0xFF000000L) |
- (((long)getByte(index + 1)) << 16 & 0xFF0000L) |
- (((long)getByte(index + 2)) << 8 & 0xFF00L) |
- (((long)getByte(index + 3)) & 0xFFL);
- } else {
- // Intel ordering - LSB first (little endian)
- return (((long)getByte(index + 3)) << 24 & 0xFF000000L) |
- (((long)getByte(index + 2)) << 16 & 0xFF0000L) |
- (((long)getByte(index + 1)) << 8 & 0xFF00L) |
- (((long)getByte(index )) & 0xFFL);
- }
- }
-
- /**
- * Returns a signed 32-bit integer from four bytes of data at the specified index the buffer.
- *
- * @param index position within the data buffer to read first byte
- * @return the signed 32 bit int value, between 0x00000000 and 0xFFFFFFFF
- * @throws IOException the buffer does not contain enough bytes to service the request, or index is negative
- */
- public int getInt32(int index) throws IOException
- {
- validateIndex(index, 4);
-
- if (_isMotorolaByteOrder) {
- // Motorola - MSB first (big endian)
- return (getByte(index ) << 24 & 0xFF000000) |
- (getByte(index + 1) << 16 & 0xFF0000) |
- (getByte(index + 2) << 8 & 0xFF00) |
- (getByte(index + 3) & 0xFF);
- } else {
- // Intel ordering - LSB first (little endian)
- return (getByte(index + 3) << 24 & 0xFF000000) |
- (getByte(index + 2) << 16 & 0xFF0000) |
- (getByte(index + 1) << 8 & 0xFF00) |
- (getByte(index ) & 0xFF);
- }
- }
-
- /**
- * Get a signed 64-bit integer from the buffer.
- *
- * @param index position within the data buffer to read first byte
- * @return the 64 bit int value, between 0x0000000000000000 and 0xFFFFFFFFFFFFFFFF
- * @throws IOException the buffer does not contain enough bytes to service the request, or index is negative
- */
- public long getInt64(int index) throws IOException
- {
- validateIndex(index, 8);
-
- if (_isMotorolaByteOrder) {
- // Motorola - MSB first
- return ((long)getByte(index ) << 56 & 0xFF00000000000000L) |
- ((long)getByte(index + 1) << 48 & 0xFF000000000000L) |
- ((long)getByte(index + 2) << 40 & 0xFF0000000000L) |
- ((long)getByte(index + 3) << 32 & 0xFF00000000L) |
- ((long)getByte(index + 4) << 24 & 0xFF000000L) |
- ((long)getByte(index + 5) << 16 & 0xFF0000L) |
- ((long)getByte(index + 6) << 8 & 0xFF00L) |
- ((long)getByte(index + 7) & 0xFFL);
- } else {
- // Intel ordering - LSB first
- return ((long)getByte(index + 7) << 56 & 0xFF00000000000000L) |
- ((long)getByte(index + 6) << 48 & 0xFF000000000000L) |
- ((long)getByte(index + 5) << 40 & 0xFF0000000000L) |
- ((long)getByte(index + 4) << 32 & 0xFF00000000L) |
- ((long)getByte(index + 3) << 24 & 0xFF000000L) |
- ((long)getByte(index + 2) << 16 & 0xFF0000L) |
- ((long)getByte(index + 1) << 8 & 0xFF00L) |
- ((long)getByte(index ) & 0xFFL);
- }
- }
-
- /**
- * Gets a s15.16 fixed point float from the buffer.
- *
- * This particular fixed point encoding has one sign bit, 15 numerator bits and 16 denominator bits.
- *
- * @return the floating point value
- * @throws IOException the buffer does not contain enough bytes to service the request, or index is negative
- */
- public float getS15Fixed16(int index) throws IOException
- {
- validateIndex(index, 4);
-
- if (_isMotorolaByteOrder) {
- float res = (getByte(index ) & 0xFF) << 8 |
- (getByte(index + 1) & 0xFF);
- int d = (getByte(index + 2) & 0xFF) << 8 |
- (getByte(index + 3) & 0xFF);
- return (float)(res + d/65536.0);
- } else {
- // this particular branch is untested
- float res = (getByte(index + 3) & 0xFF) << 8 |
- (getByte(index + 2) & 0xFF);
- int d = (getByte(index + 1) & 0xFF) << 8 |
- (getByte(index ) & 0xFF);
- return (float)(res + d/65536.0);
- }
- }
-
- public float getFloat32(int index) throws IOException
- {
- return Float.intBitsToFloat(getInt32(index));
- }
-
- public double getDouble64(int index) throws IOException
- {
- return Double.longBitsToDouble(getInt64(index));
- }
-
- @NotNull
- public StringValue getStringValue(int index, int bytesRequested, @Nullable Charset charset) throws IOException
- {
- return new StringValue(getBytes(index, bytesRequested), charset);
- }
-
- @NotNull
- public String getString(int index, int bytesRequested, @NotNull Charset charset) throws IOException
- {
- return new String(getBytes(index, bytesRequested), charset.name());
- }
-
- @NotNull
- public String getString(int index, int bytesRequested, @NotNull String charset) throws IOException
- {
- byte[] bytes = getBytes(index, bytesRequested);
- try {
- return new String(bytes, charset);
- } catch (UnsupportedEncodingException e) {
- return new String(bytes);
- }
- }
-
- /**
- * Creates a String from the _data buffer starting at the specified index,
- * and ending where byte=='\0'
or where length==maxLength
.
- *
- * @param index The index within the buffer at which to start reading the string.
- * @param maxLengthBytes The maximum number of bytes to read. If a zero-byte is not reached within this limit,
- * reading will stop and the string will be truncated to this length.
- * @return The read string.
- * @throws IOException The buffer does not contain enough bytes to satisfy this request.
- */
- @NotNull
- public String getNullTerminatedString(int index, int maxLengthBytes, @NotNull Charset charset) throws IOException
- {
- return new String(getNullTerminatedBytes(index, maxLengthBytes), charset.name());
- }
-
- @NotNull
- public StringValue getNullTerminatedStringValue(int index, int maxLengthBytes, @Nullable Charset charset) throws IOException
- {
- byte[] bytes = getNullTerminatedBytes(index, maxLengthBytes);
-
- return new StringValue(bytes, charset);
- }
-
- /**
- * Returns the sequence of bytes punctuated by a \0
value.
- *
- * @param index The index within the buffer at which to start reading the string.
- * @param maxLengthBytes The maximum number of bytes to read. If a \0
byte is not reached within this limit,
- * the returned array will be maxLengthBytes
long.
- * @return The read byte array, excluding the null terminator.
- * @throws IOException The buffer does not contain enough bytes to satisfy this request.
- */
- @NotNull
- public byte[] getNullTerminatedBytes(int index, int maxLengthBytes) throws IOException
- {
- byte[] buffer = getBytes(index, maxLengthBytes);
-
- // Count the number of non-null bytes
- int length = 0;
- while (length < buffer.length && buffer[length] != 0)
- length++;
-
- if (length == maxLengthBytes)
- return buffer;
-
- byte[] bytes = new byte[length];
- if (length > 0)
- System.arraycopy(buffer, 0, bytes, 0, length);
- return bytes;
- }
-}
diff --git a/Source/com/drew/lang/RandomAccessStream.java b/Source/com/drew/lang/RandomAccessStream.java
new file mode 100644
index 000000000..580b2de16
--- /dev/null
+++ b/Source/com/drew/lang/RandomAccessStream.java
@@ -0,0 +1,629 @@
+/*
+ * Copyright 2002-2017 Drew Noakes
+ * Copyright 2018 Kevin Mott
+ *
+ * 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:
+ *
+ * https://drewnoakes.com/code/exif/
+ * https://github.com/drewnoakes/metadata-extractor
+ */
+
+package com.drew.lang;
+
+import com.drew.lang.annotations.NotNull;
+
+import java.io.EOFException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.RandomAccessFile;
+import java.util.Collections;
+import java.util.HashMap;
+/**
+ *
+ * @author Kevin Mott https://github.com/kwhopper
+ * @author Drew Noakes https://drewnoakes.com
+ */
+public class RandomAccessStream
+{
+ private final RandomAccessFile _raFile;
+ private final InputStream _inputStream;
+
+ private long _streamLength = -1;
+
+ private boolean _canSeek = false;
+ private boolean _isStreamFinished;
+
+ public final static int DEFAULT_CHUNK_LENGTH = 2 * 1024;
+ private final int _chunkLength;
+
+ @NotNull
+ public final HashMap _chunks = new HashMap();
+
+ private long _totalBytesRead = 0;
+
+
+ public RandomAccessStream(@NotNull RandomAccessFile raFile) throws IOException
+ {
+ if (raFile == null)
+ throw new NullPointerException();
+
+ _raFile = raFile;
+ _canSeek = true;
+ _chunkLength = DEFAULT_CHUNK_LENGTH;
+
+ _streamLength = raFile.length();
+
+ _inputStream = null;
+ }
+
+ public RandomAccessStream(@NotNull InputStream stream, long streamLength)
+ {
+ if (stream == null)
+ throw new NullPointerException();
+ if (streamLength <= 0L)
+ throw new IllegalArgumentException("streamLength must be greater than zero");
+
+ _inputStream = stream;
+ _canSeek = false;
+ _streamLength = streamLength;
+
+ _chunkLength = DEFAULT_CHUNK_LENGTH;
+
+ _raFile = null;
+ }
+
+ public RandomAccessStream(@NotNull byte[] bytes)
+ {
+ if (bytes == null)
+ throw new NullPointerException();
+
+ _canSeek = true;
+
+ _chunks.put(0L, bytes);
+ _chunkLength = bytes.length;
+
+ _streamLength = bytes.length;
+ _isStreamFinished = true;
+
+ _raFile = null;
+ _inputStream = null;
+ }
+
+ public boolean canSeek()
+ {
+ return _canSeek;
+ }
+
+ public long getLength()
+ {
+ return _streamLength;
+ }
+
+ public ReaderInfo createReader()
+ {
+ return createReader(-1L, -1L, true);
+ }
+ public ReaderInfo createReader(boolean isMotorolaByteOrder)
+ {
+ return createReader(-1L, -1L, isMotorolaByteOrder);
+ }
+ public ReaderInfo createReader(long startPosition, long length, boolean isMotorolaByteOrder)
+ {
+ long pos = startPosition >= 0 ? startPosition : 0;
+
+ //var rdrInfo = new ReaderInfo(this, pos, 0, length, isMotorolaByteOrder);
+ //rdrList.Add(rdrInfo);
+ //return rdrInfo;
+ return new ReaderInfo(this, pos, 0L, length, isMotorolaByteOrder);
+ }
+
+ /**
+ * Retrieves bytes, writing them into a caller-provided buffer.
+ * SequentialFlag as index indicates this call should read sequentially
+ *
+ * @param index position within the data buffer to read bytes
+ * @param buffer array to write bytes to
+ * @param offset starting position with buffer to write to
+ * @param count The number of bytes to be written
+ * @param isSequential flag indicating if caller is using sequential access
+ * @return The requested bytes
+ * @throws IOException if the byte is unable to be read
+ * @throws EOFException if the requested bytes extend beyond the end of the underlying data source
+ * @throws BufferBoundsException if the requested byte is beyond the end of the underlying data source
+ */
+ public int read(long index, byte[] buffer, int offset, int count, boolean isSequential) throws IOException, EOFException, BufferBoundsException
+ {
+ return read(index, buffer, offset, count, isSequential, true);
+ }
+
+ /**
+ * Retrieves bytes, writing them into a caller-provided buffer.
+ * SequentialFlag as index indicates this call should read sequentially
+ *
+ * @param index position within the data buffer to read bytes
+ * @param buffer array to write bytes to
+ * @param offset starting position with buffer to write to
+ * @param count The number of bytes to be written
+ * @param isSequential flag indicating if caller is using sequential access
+ * @param allowPartial flag indicating if fewer than count bytes can be returned
+ * @return The requested bytes
+ * @throws IOException if the byte is unable to be read
+ * @throws EOFException if the requested bytes extend beyond the end of the underlying data source
+ * @throws BufferBoundsException if the requested byte is beyond the end of the underlying data source
+ */
+ public int read(long index, byte[] buffer, int offset, int count, boolean isSequential, boolean allowPartial) throws IOException, EOFException, BufferBoundsException
+ {
+ count = (int)validateIndex(index, count, isSequential, allowPartial);
+
+ // This bypasses a lot of checks particularly when the input was a byte[]
+ if (_isStreamFinished && _chunks.size() == 1)
+ {
+ System.arraycopy(_chunks.get(0L), (int)index, buffer, 0, count);
+ return count;
+ }
+
+ int remaining = count; // how many bytes are requested
+ int fromOffset = (int)index;
+ int toIndex = offset > 0 ? offset : 0;
+ while (remaining != 0)
+ {
+ int fromChunkIndex = fromOffset / _chunkLength; // chunk integer key
+ int fromInnerIndex = fromOffset % _chunkLength; // index inside the chunk to start reading
+ int length = Math.min(remaining, _chunkLength - fromInnerIndex);
+ byte[] chunk = _chunks.get((long)fromChunkIndex);
+ System.arraycopy(chunk, fromInnerIndex, buffer, toIndex, length);
+ remaining -= length;
+ fromOffset += length;
+ toIndex += length;
+ }
+
+ return toIndex - offset;
+ }
+
+ /**
+ * Gets the byte value at the specified byte index
.
+ *
+ * Implementations should not perform any bounds checking in this method. That should be performed
+ * in validateIndex
and bytesAvailable
.
+ *
+ * @param index The index from which to read the byte
+ * @param isSequential flag indicating if caller is using sequential access
+ * @return The read byte value
+ * @throws IOException if the byte is unable to be read
+ * @throws EOFException if the requested bytes extend beyond the end of the underlying data source
+ * @throws BufferBoundsException if the requested byte is beyond the end of the underlying data source
+ */
+ public byte getByte(long index, boolean isSequential) throws IOException, EOFException, BufferBoundsException
+ {
+ validateIndex(index, 1, isSequential);
+
+ // This bypasses a lot of checks particularly when the input was a byte[]
+ if (_isStreamFinished && _chunks.size() == 1)
+ return _chunks.get(0L)[(int)index];
+
+ long chunkIndex = index / _chunkLength;
+ long innerIndex = index % _chunkLength;
+
+ if (_chunks.containsKey(chunkIndex))
+ return (byte)_chunks.get(chunkIndex)[(int)innerIndex];
+ else
+ return (byte)255; // unchecked((byte)-1);
+ }
+
+ /**
+ * Returns an unsigned 16-bit int calculated from two bytes of data at the specified index.
+ *
+ * @param index position within the data buffer to read first byte
+ * @param isMotorolaByteOrder true
for Motorola/big endian, false
for Intel/little endian
+ * @param isSequential flag indicating if caller is using sequential access
+ * @return the 16 bit int value, between 0x0000 and 0xFFFF
+ * @throws IOException if the byte is unable to be read
+ * @throws EOFException if the requested bytes extend beyond the end of the underlying data source
+ * @throws BufferBoundsException if the requested byte is beyond the end of the underlying data source
+ */
+ public int getUInt16(long index, boolean isMotorolaByteOrder, boolean isSequential) throws IOException, EOFException, BufferBoundsException
+ {
+ byte[] bytes = new byte[2];
+ read(index, bytes, 0, bytes.length, isSequential, false);
+
+ if (isMotorolaByteOrder) {
+ // Motorola - MSB first
+ return (bytes[0] << 8 & 0xFF00) |
+ (bytes[1] & 0xFF);
+ } else {
+ // Intel ordering - LSB first
+ return (bytes[1] << 8 & 0xFF00) |
+ (bytes[0] & 0xFF);
+ }
+ }
+
+ /**
+ * Returns a signed 16-bit int calculated from two bytes of data at the specified index.
+ *
+ * @param index position within the data buffer to read first byte
+ * @param isMotorolaByteOrder true
for Motorola/big endian, false
for Intel/little endian
+ * @param isSequential flag indicating if caller is using sequential access
+ * @return the 16 bit int value, between 0x0000 and 0xFFFF
+ * @throws IOException if the byte is unable to be read
+ * @throws EOFException if the requested bytes extend beyond the end of the underlying data source
+ * @throws BufferBoundsException if the requested byte is beyond the end of the underlying data source
+ */
+ public short getInt16(long index, boolean isMotorolaByteOrder, boolean isSequential) throws IOException, EOFException, BufferBoundsException
+ {
+ byte[] bytes = new byte[2];
+ read(index, bytes, 0, bytes.length, isSequential, false);
+
+ if (isMotorolaByteOrder) {
+ // Motorola - MSB first
+ return (short) (((short)bytes[0] << 8 & (short)0xFF00) |
+ ((short)bytes[1] & (short)0xFF));
+ } else {
+ // Intel ordering - LSB first
+ return (short) (((short)bytes[1] << 8 & (short)0xFF00) |
+ ((short)bytes[0] & (short)0xFF));
+ }
+ }
+
+ /**
+ * Get a 24-bit unsigned integer from the buffer, returning it as an int.
+ *
+ * @param index position within the data buffer to read first byte
+ * @param isMotorolaByteOrder true
for Motorola/big endian, false
for Intel/little endian
+ * @param isSequential flag indicating if caller is using sequential access
+ * @return the unsigned 24-bit int value as a long, between 0x00000000 and 0x00FFFFFF
+ * @throws IOException if the byte is unable to be read
+ * @throws EOFException if the requested bytes extend beyond the end of the underlying data source
+ * @throws BufferBoundsException if the requested byte is beyond the end of the underlying data source
+ */
+ public int getInt24(long index, boolean isMotorolaByteOrder, boolean isSequential) throws IOException, EOFException, BufferBoundsException
+ {
+ byte[] bytes = new byte[3];
+ read(index, bytes, 0, bytes.length, isSequential, false);
+
+ if (isMotorolaByteOrder) {
+ // Motorola - MSB first (big endian)
+ return (((int)bytes[0]) << 16 & 0xFF0000) |
+ (((int)bytes[1]) << 8 & 0xFF00) |
+ (((int)bytes[2]) & 0xFF);
+ } else {
+ // Intel ordering - LSB first (little endian)
+ return (((int)bytes[2]) << 16 & 0xFF0000) |
+ (((int)bytes[1]) << 8 & 0xFF00) |
+ (((int)bytes[0]) & 0xFF);
+ }
+ }
+
+ /**
+ * Get a 32-bit unsigned integer from the buffer, returning it as a long.
+ *
+ * @param index position within the data buffer to read first byte
+ * @param isMotorolaByteOrder true
for Motorola/big endian, false
for Intel/little endian
+ * @param isSequential flag indicating if caller is using sequential access
+ * @return the unsigned 32-bit int value as a long, between 0x00000000 and 0xFFFFFFFF
+ * @throws IOException if the byte is unable to be read
+ * @throws EOFException if the requested bytes extend beyond the end of the underlying data source
+ * @throws BufferBoundsException if the requested byte is beyond the end of the underlying data source
+ */
+ public long getUInt32(long index, boolean isMotorolaByteOrder, boolean isSequential) throws IOException, EOFException, BufferBoundsException
+ {
+ byte[] bytes = new byte[4];
+ read(index, bytes, 0, bytes.length, isSequential, false);
+
+ if (isMotorolaByteOrder) {
+ // Motorola - MSB first (big endian)
+ return (((long)bytes[0]) << 24 & 0xFF000000L) |
+ (((long)bytes[1]) << 16 & 0xFF0000L) |
+ (((long)bytes[2]) << 8 & 0xFF00L) |
+ (((long)bytes[3]) & 0xFFL);
+ } else {
+ // Intel ordering - LSB first (little endian)
+ return (((long)bytes[3]) << 24 & 0xFF000000L) |
+ (((long)bytes[2]) << 16 & 0xFF0000L) |
+ (((long)bytes[1]) << 8 & 0xFF00L) |
+ (((long)bytes[0]) & 0xFFL);
+ }
+ }
+
+ /**
+ * Get a 32-bit signed integer from the buffer, returning it as a long.
+ *
+ * @param index position within the data buffer to read first byte
+ * @param isMotorolaByteOrder true
for Motorola/big endian, false
for Intel/little endian
+ * @param isSequential flag indicating if caller is using sequential access
+ * @return the signed 32-bit int value as a long, between 0x00000000 and 0xFFFFFFFF
+ * @throws IOException if the byte is unable to be read
+ * @throws EOFException if the requested bytes extend beyond the end of the underlying data source
+ * @throws BufferBoundsException if the requested byte is beyond the end of the underlying data source
+ */
+ public int getInt32(long index, boolean isMotorolaByteOrder, boolean isSequential) throws IOException, EOFException, BufferBoundsException
+ {
+ byte[] bytes = new byte[4];
+ read(index, bytes, 0, bytes.length, isSequential, false);
+
+ if (isMotorolaByteOrder) {
+ // Motorola - MSB first (big endian)
+ return (bytes[0] << 24 & 0xFF000000) |
+ (bytes[1] << 16 & 0xFF0000) |
+ (bytes[2] << 8 & 0xFF00) |
+ (bytes[3] & 0xFF);
+ } else {
+ // Intel ordering - LSB first (little endian)
+ return (bytes[3] << 24 & 0xFF000000) |
+ (bytes[2] << 16 & 0xFF0000) |
+ (bytes[1] << 8 & 0xFF00) |
+ (bytes[0] & 0xFF);
+ }
+ }
+
+ /**
+ * Get a signed 64-bit integer from the buffer.
+ *
+ * @param index position within the data buffer to read first byte
+ * @param isMotorolaByteOrder true
for Motorola/big endian, false
for Intel/little endian
+ * @param isSequential flag indicating if caller is using sequential access
+ * @return the 64 bit int value, between 0x0000000000000000 and 0xFFFFFFFFFFFFFFFF
+ * @throws IOException if the byte is unable to be read
+ * @throws EOFException if the requested bytes extend beyond the end of the underlying data source
+ * @throws BufferBoundsException if the requested byte is beyond the end of the underlying data source
+ */
+ public long getInt64(long index, boolean isMotorolaByteOrder, boolean isSequential) throws IOException, EOFException, BufferBoundsException
+ {
+ byte[] bytes = new byte[8];
+ read(index, bytes, 0, bytes.length, isSequential, false);
+
+ if (isMotorolaByteOrder) {
+ // Motorola - MSB first
+ return ((long)bytes[0] << 56 & 0xFF00000000000000L) |
+ ((long)bytes[1] << 48 & 0xFF000000000000L) |
+ ((long)bytes[2] << 40 & 0xFF0000000000L) |
+ ((long)bytes[3] << 32 & 0xFF00000000L) |
+ ((long)bytes[4] << 24 & 0xFF000000L) |
+ ((long)bytes[5] << 16 & 0xFF0000L) |
+ ((long)bytes[6] << 8 & 0xFF00L) |
+ ((long)bytes[7] & 0xFFL);
+ } else {
+ // Intel ordering - LSB first
+ return ((long)bytes[7] << 56 & 0xFF00000000000000L) |
+ ((long)bytes[6] << 48 & 0xFF000000000000L) |
+ ((long)bytes[5] << 40 & 0xFF0000000000L) |
+ ((long)bytes[4] << 32 & 0xFF00000000L) |
+ ((long)bytes[3] << 24 & 0xFF000000L) |
+ ((long)bytes[2] << 16 & 0xFF0000L) |
+ ((long)bytes[1] << 8 & 0xFF00L) |
+ ((long)bytes[0] & 0xFFL);
+ }
+ }
+
+ /**
+ * Gets a s15.16 fixed point float from the buffer.
+ *
+ * This particular fixed point encoding has one sign bit, 15 numerator bits and 16 denominator bits.
+ * @param index position within the data buffer to read first byte
+ * @param isMotorolaByteOrder true
for Motorola/big endian, false
for Intel/little endian
+ * @param isSequential flag indicating if caller is using sequential access
+ * @return the floating point value
+ * @throws IOException if the byte is unable to be read
+ * @throws EOFException if the requested bytes extend beyond the end of the underlying data source
+ * @throws BufferBoundsException if the requested byte is beyond the end of the underlying data source
+ */
+ public float getS15Fixed16(long index, boolean isMotorolaByteOrder, boolean isSequential) throws IOException, EOFException, BufferBoundsException
+ {
+ byte[] bytes = new byte[4];
+ read(index, bytes, 0, bytes.length, isSequential, false);
+
+ if (isMotorolaByteOrder) {
+ float res = (bytes[0] & 0xFF) << 8 |
+ (bytes[1] & 0xFF);
+ int d = (bytes[2] & 0xFF) << 8 |
+ (bytes[3] & 0xFF);
+ return (float)(res + d/65536.0);
+ } else {
+ // this particular branch is untested
+ float res = (bytes[3] & 0xFF) << 8 |
+ (bytes[2] & 0xFF);
+ int d = (bytes[1] & 0xFF) << 8 |
+ (bytes[0] & 0xFF);
+ return (float)(res + d/65536.0);
+ }
+ }
+
+ /**
+ * Skips to a specific index in the sequence. If the sequence ends, an {@link EOFException} is thrown.
+ *
+ * @param index the number of bytes to skip.
+ * @throws IOException if the byte is unable to be read
+ * @throws EOFException if the requested bytes extend beyond the end of the underlying data source
+ * @throws BufferBoundsException if the requested byte is beyond the end of the underlying data source
+ */
+ public void seek(final long index) throws IOException, EOFException, BufferBoundsException
+ {
+ validateIndex((index == 0) ? 0 : (index - 1), 1L, false);
+ }
+
+ /**
+ * Ensures that the buffered bytes extend to cover the specified index. If not, an attempt is made
+ * to read to that point.
+ *
+ * If the stream ends before the point is reached, a {@link BufferBoundsException} is raised.
+ *
+ * @param index the index from which the required bytes start
+ * @param bytesRequested the number of bytes which are required
+ * @param isSequential flag indicating if caller is using sequential access
+ * @return count of bytes available at the given index
+ * @throws IOException if the byte is unable to be read
+ * @throws EOFException if the requested bytes extend beyond the end of the underlying data source
+ * @throws BufferBoundsException if the requested byte is beyond the end of the underlying data source
+ */
+ public long validateIndex(long index, long bytesRequested, boolean isSequential) throws IOException, EOFException, BufferBoundsException
+ {
+ return validateIndex(index, bytesRequested, isSequential, false);
+ }
+
+ /**
+ * Ensures that the buffered bytes extend to cover the specified index. If not, an attempt is made
+ * to read to that point.
+ *
+ * If the stream ends before the point is reached, a {@link BufferBoundsException} might be raised.
+ *
+ * @param index the index from which the required bytes start
+ * @param bytesRequested the number of bytes which are required
+ * @param isSequential flag indicating if caller is using sequential access
+ * @param allowPartial flag indicating if fewer than count bytes can be returned
+ * @return count of bytes available at the given index
+ * @throws IOException if the byte is unable to be read
+ * @throws EOFException if the requested bytes extend beyond the end of the underlying data source
+ * @throws BufferBoundsException if the requested byte is beyond the end of the underlying data source
+ */
+ public long validateIndex(long index, long bytesRequested, boolean isSequential, boolean allowPartial) throws IOException, EOFException, BufferBoundsException
+ {
+ long available = bytesAvailable(index, bytesRequested);
+ if(available != bytesRequested && !allowPartial)
+ {
+ if(index < 0)
+ throw new BufferBoundsException("Attempt to read from buffer using a negative index (" + ((Long)index).toString() + ")");
+ if (bytesRequested < 0)
+ throw new BufferBoundsException("Number of requested bytes must be zero or greater");
+ if (index + bytesRequested - 1 > Integer.MAX_VALUE)
+ throw new BufferBoundsException("Number of requested bytes summed with starting index exceed maximum range of signed 32 bit integers (requested index: " + ((Long)index).toString() + ", requested count: " + ((Long)bytesRequested).toString() + ")");
+ if (index + bytesRequested >= _streamLength && isSequential)
+ throw new EOFException("End of data reached.");
+
+ // TODO test that can continue using an instance of this type after this exception
+ throw new BufferBoundsException((int)index, (int)bytesRequested, _streamLength);
+ }
+
+ return available;
+ }
+
+ /**
+ * Determines how many bytes of bytesRequested are available at index
+ * @param index the index from which the required bytes start
+ * @param bytesRequested the number of bytes which are required
+ * @return number of bytes available on and after the given index
+ * @throws IOException
+ */
+ private long bytesAvailable(long index, long bytesRequested) throws IOException
+ {
+ if (index < 0 || bytesRequested < 0)
+ return 0;
+
+ // if there's only one chunk, there's no need to calculate anything.
+ // This bypasses a lot of checks particularly when the input was a byte[]
+ if (_isStreamFinished && _chunks.size() == 1)
+ {
+ if ((index + bytesRequested) < _streamLength)
+ return bytesRequested;
+ else if (index > _streamLength)
+ return 0;
+ else
+ return _streamLength - index;
+ }
+
+ long endIndex = index + bytesRequested - 1;
+ if (endIndex < 0) endIndex = 0;
+
+ // Maybe don't check this?
+ if (endIndex > Integer.MAX_VALUE)
+ return 0;
+
+ // zero-based
+ long chunkstart = index / _chunkLength;
+ long chunkend = ((index + bytesRequested) / _chunkLength) + 1;
+
+
+ if (!_chunks.containsKey(chunkstart))
+ {
+ if(!_canSeek)
+ chunkstart = _chunks.isEmpty() ? 0 : Collections.max(_chunks.keySet()) + 1;
+ }
+
+ for (long i = chunkstart; i < chunkend; i++)
+ {
+ if (!_chunks.containsKey(i))
+ {
+ _isStreamFinished = false;
+
+
+ // chunkstart can be anywhere. Try to seek
+ if (_canSeek && _raFile != null)
+ _raFile.seek(i * _chunkLength);
+
+ byte[] chunk = new byte[_chunkLength];
+
+ int totalBytesRead = 0;
+ while (!_isStreamFinished && totalBytesRead != _chunkLength)
+ {
+ int bytesRead;
+ if(_canSeek && _raFile != null)
+ bytesRead = _raFile.read(chunk, totalBytesRead, _chunkLength - totalBytesRead);
+ else
+ bytesRead = _inputStream.read(chunk, totalBytesRead, _chunkLength - totalBytesRead);
+
+ if (bytesRead == -1)
+ {
+ // the stream has ended, which may be ok
+ _isStreamFinished = true;
+ _streamLength = i * _chunkLength + totalBytesRead;
+
+ // check we have enough bytes for the requested index
+ if (endIndex >= _streamLength)
+ {
+ _totalBytesRead += totalBytesRead;
+ _chunks.put(i, chunk);
+ return (index + bytesRequested) <= _streamLength ? bytesRequested : _streamLength - index;
+ }
+ }
+ else
+ {
+ totalBytesRead += bytesRead;
+ }
+ }
+
+ _totalBytesRead += totalBytesRead;
+ _chunks.put(i, chunk);
+ }
+ }
+
+ if (_isStreamFinished)
+ return (index + bytesRequested) <= _streamLength ? bytesRequested : 0;
+ else
+ return bytesRequested;
+ }
+
+ public long getTotalBytesRead()
+ {
+ return _totalBytesRead;
+ }
+
+ public byte[] toArray(long index, int count) throws IOException
+ {
+ byte[] buffer = null;
+ // if this was a byte array and asking for the whole thing...
+ if (_isStreamFinished &&
+ _chunks.size() == 1 &&
+ index == 0 &&
+ count == getLength())
+ {
+ buffer = _chunks.get(0L);
+ }
+ else
+ {
+ buffer = new byte[count];
+ read(index, buffer, 0, count, false);
+ }
+
+ return buffer;
+ }
+}
diff --git a/Source/com/drew/lang/RandomAccessStreamReader.java b/Source/com/drew/lang/RandomAccessStreamReader.java
deleted file mode 100644
index e9c4056fb..000000000
--- a/Source/com/drew/lang/RandomAccessStreamReader.java
+++ /dev/null
@@ -1,215 +0,0 @@
-/*
- * Copyright 2002-2017 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:
- *
- * https://drewnoakes.com/code/exif/
- * https://github.com/drewnoakes/metadata-extractor
- */
-
-package com.drew.lang;
-
-import com.drew.lang.annotations.NotNull;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.util.ArrayList;
-
-/**
- * @author Drew Noakes https://drewnoakes.com
- */
-public class RandomAccessStreamReader extends RandomAccessReader
-{
- public final static int DEFAULT_CHUNK_LENGTH = 2 * 1024;
-
- @NotNull
- private final InputStream _stream;
- private final int _chunkLength;
-
- private final ArrayList _chunks = new ArrayList();
-
- private boolean _isStreamFinished;
- private long _streamLength;
-
- public RandomAccessStreamReader(@NotNull InputStream stream)
- {
- this(stream, DEFAULT_CHUNK_LENGTH, -1);
- }
-
- public RandomAccessStreamReader(@NotNull InputStream stream, int chunkLength)
- {
- this(stream, chunkLength, -1);
- }
-
- public RandomAccessStreamReader(@NotNull InputStream stream, int chunkLength, long streamLength)
- {
- if (stream == null)
- throw new NullPointerException();
- if (chunkLength <= 0)
- throw new IllegalArgumentException("chunkLength must be greater than zero");
-
- _chunkLength = chunkLength;
- _stream = stream;
- _streamLength = streamLength;
- }
-
- /**
- * Reads to the end of the stream, in order to determine the total number of bytes.
- * In general, this is not a good idea for this implementation of {@link RandomAccessReader}.
- *
- * @return the length of the data source, in bytes.
- */
- @Override
- public long getLength() throws IOException
- {
- if (_streamLength != -1) {
- return _streamLength;
- }
-
- isValidIndex(Integer.MAX_VALUE, 1);
- assert(_isStreamFinished);
- return _streamLength;
- }
-
- /**
- * Ensures that the buffered bytes extend to cover the specified index. If not, an attempt is made
- * to read to that point.
- *
- * If the stream ends before the point is reached, a {@link BufferBoundsException} is raised.
- *
- * @param index the index from which the required bytes start
- * @param bytesRequested the number of bytes which are required
- * @throws BufferBoundsException if the stream ends before the required number of bytes are acquired
- */
- @Override
- protected void validateIndex(int index, int bytesRequested) throws IOException
- {
- if (index < 0) {
- throw new BufferBoundsException(String.format("Attempt to read from buffer using a negative index (%d)", index));
- } else if (bytesRequested < 0) {
- throw new BufferBoundsException("Number of requested bytes must be zero or greater");
- } else if ((long)index + bytesRequested - 1 > Integer.MAX_VALUE) {
- throw new BufferBoundsException(String.format("Number of requested bytes summed with starting index exceed maximum range of signed 32 bit integers (requested index: %d, requested count: %d)", index, bytesRequested));
- }
-
- if (!isValidIndex(index, bytesRequested)) {
- assert(_isStreamFinished);
- // TODO test that can continue using an instance of this type after this exception
- throw new BufferBoundsException(index, bytesRequested, _streamLength);
- }
- }
-
- @Override
- protected boolean isValidIndex(int index, int bytesRequested) throws IOException
- {
- if (index < 0 || bytesRequested < 0) {
- return false;
- }
-
- long endIndexLong = (long)index + bytesRequested - 1;
-
- if (endIndexLong > Integer.MAX_VALUE) {
- return false;
- }
-
- int endIndex = (int)endIndexLong;
-
- if (_isStreamFinished) {
- return endIndex < _streamLength;
- }
-
- int chunkIndex = endIndex / _chunkLength;
-
- // TODO test loading several chunks for a single request
- while (chunkIndex >= _chunks.size()) {
- assert (!_isStreamFinished);
-
- byte[] chunk = new byte[_chunkLength];
- int totalBytesRead = 0;
- while (!_isStreamFinished && totalBytesRead != _chunkLength) {
- int bytesRead = _stream.read(chunk, totalBytesRead, _chunkLength - totalBytesRead);
- if (bytesRead == -1) {
- // the stream has ended, which may be ok
- _isStreamFinished = true;
- int observedStreamLength = _chunks.size() * _chunkLength + totalBytesRead;
- if (_streamLength == -1) {
- _streamLength = observedStreamLength;
- } else if (_streamLength != observedStreamLength) {
- assert(false);
- }
-
- // check we have enough bytes for the requested index
- if (endIndex >= _streamLength) {
- _chunks.add(chunk);
- return false;
- }
- } else {
- totalBytesRead += bytesRead;
- }
- }
-
- _chunks.add(chunk);
- }
-
- return true;
- }
-
- @Override
- public int toUnshiftedOffset(int localOffset)
- {
- return localOffset;
- }
-
- @Override
- public byte getByte(int index) throws IOException
- {
- assert(index >= 0);
-
- final int chunkIndex = index / _chunkLength;
- final int innerIndex = index % _chunkLength;
- final byte[] chunk = _chunks.get(chunkIndex);
-
- return chunk[innerIndex];
- }
-
- @NotNull
- @Override
- public byte[] getBytes(int index, int count) throws IOException
- {
- validateIndex(index, count);
-
- byte[] bytes = new byte[count];
-
- int remaining = count;
- int fromIndex = index;
- int toIndex = 0;
-
- while (remaining != 0) {
- int fromChunkIndex = fromIndex / _chunkLength;
- int fromInnerIndex = fromIndex % _chunkLength;
- int length = Math.min(remaining, _chunkLength - fromInnerIndex);
-
- byte[] chunk = _chunks.get(fromChunkIndex);
-
- System.arraycopy(chunk, fromInnerIndex, bytes, toIndex, length);
-
- remaining -= length;
- fromIndex += length;
- toIndex += length;
- }
-
- return bytes;
- }
-}
diff --git a/Source/com/drew/lang/ReaderInfo.java b/Source/com/drew/lang/ReaderInfo.java
new file mode 100644
index 000000000..a9edd8e59
--- /dev/null
+++ b/Source/com/drew/lang/ReaderInfo.java
@@ -0,0 +1,943 @@
+/*
+ * Copyright 2002-2017 Drew Noakes
+ * Copyright 2018 Kevin Mott
+ *
+ * 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:
+ *
+ * https://drewnoakes.com/code/exif/
+ * https://github.com/drewnoakes/metadata-extractor
+ */
+
+package com.drew.lang;
+
+import com.drew.lang.annotations.NotNull;
+import com.drew.lang.annotations.Nullable;
+import com.drew.metadata.StringValue;
+
+import java.io.EOFException;
+import java.io.IOException;
+import java.io.UnsupportedEncodingException;
+import java.nio.charset.Charset;
+/**
+ *
+ * @author Kevin Mott https://github.com/kwhopper
+ * @author Drew Noakes https://drewnoakes.com
+ */
+public class ReaderInfo
+{
+ // this flag is compared to index inputs and indicates sequential access
+ private final int SequentialFlag = Integer.MIN_VALUE;
+
+ private RandomAccessStream _ras = null;
+ private long _length = -1;
+
+ private long _startPosition;
+ private long _localPosition;
+ private boolean _isMotorolaByteOrder;
+
+ public ReaderInfo(RandomAccessStream parent)
+ {
+ this(parent, 0L);
+ }
+
+ public ReaderInfo(RandomAccessStream parent, long startPosition)
+ {
+ this(parent, startPosition, 0L);
+ }
+
+ public ReaderInfo(RandomAccessStream parent, long startPosition, long localPosition)
+ {
+ this(parent, startPosition, localPosition, -1L);
+ }
+
+ public ReaderInfo(RandomAccessStream parent, long startPosition, long localPosition, long length)
+ {
+ this(parent, startPosition, localPosition, length, true);
+ }
+
+ public ReaderInfo(RandomAccessStream parent, long startPosition, long localPosition, long length, boolean isMotorolaByteOrder)
+ {
+ _ras = parent;
+ _startPosition = startPosition;
+ _localPosition = localPosition;
+ _length = length;
+
+ _isMotorolaByteOrder = isMotorolaByteOrder;
+ }
+
+ public static ReaderInfo createFromArray(@NotNull byte[] bytes) throws NullPointerException
+ {
+ if(bytes == null)
+ throw new NullPointerException();
+
+ return new RandomAccessStream(bytes).createReader();
+ }
+
+ private long getGlobalPosition()
+ {
+ return getStartPosition() + getLocalPosition();
+ }
+
+ public long getStartPosition()
+ {
+ return _startPosition;
+ }
+
+ public long getLocalPosition()
+ {
+ return _localPosition;
+ }
+
+ public long getLength() throws IOException
+ {
+ return (_length != -1) ? _length : (_ras.getLength() - getStartPosition());
+ }
+
+ /**
+ * Gets the endianness of this reader.
+ *
+ * true
for Motorola (or big) endianness (also known as network byte order), with MSB before LSB.
+ * false
for Intel (or little) endianness, with LSB before MSB.
+ *
+ */
+ public boolean isMotorolaByteOrder()
+ {
+ return _isMotorolaByteOrder;
+ }
+
+ /**
+ * Sets the endianness of this reader.
+ *
+ * true
for Motorola (or big) endianness (also known as network byte order), with MSB before LSB.
+ * false
for Intel (or little) endianness, with LSB before MSB.
+ *
+ *
+ * @param value true
for Motorola/big endian, false
for Intel/little endian
+ */
+ public void setMotorolaByteOrder(boolean value)
+ {
+ _isMotorolaByteOrder = value;
+ }
+
+ /**
+ * Creates a new ReaderInfo with the current properties of this reader
+ * @return a clones ReaderInfo
+ * @throws IOException
+ */
+ public ReaderInfo Clone() throws IOException
+ {
+ return Clone(0L, -1L, true);
+ }
+ public ReaderInfo Clone(boolean useByteOrder) throws IOException
+ {
+ return Clone(0L, useByteOrder);
+ }
+ public ReaderInfo Clone(long length) throws IOException
+ {
+ return Clone(0L, length, true);
+ }
+ public ReaderInfo Clone(long offset, long length) throws IOException
+ {
+ return Clone(offset, length, true);
+ }
+ public ReaderInfo Clone(long offset, boolean useByteOrder) throws IOException
+ {
+ return Clone(offset, -1L, useByteOrder);
+ }
+ public ReaderInfo Clone(long offset, long length, boolean useByteOrder) throws IOException
+ {
+ return _ras.createReader(getGlobalPosition() + offset, (length > -1 ? length : getLength() - offset), useByteOrder ? isMotorolaByteOrder() : !isMotorolaByteOrder());
+ }
+
+ /**
+ * Skips forward or backward in the sequence. If the sequence ends, an {@link EOFException} is thrown.
+ *
+ * @param offset the number of bytes to skip.
+ * @throws IOException if the byte is unable to be read
+ * @throws EOFException if the requested bytes extend beyond the end of the underlying data source
+ * @throws BufferBoundsException if the requested byte is beyond the end of the underlying data source
+ */
+ public void skip(long offset) throws IOException, EOFException, BufferBoundsException
+ {
+ if (offset + getLocalPosition() < 0)
+ offset = -getLocalPosition();
+
+ _ras.seek(getLocalPosition() + offset);
+
+ _localPosition += offset;
+ }
+
+ /**
+ * Skips forward or backward in the sequence, returning a boolean indicating whether the skip succeeded, or whether the sequence ended.
+ *
+ * @param n the number of byte to skip. Must be zero or greater.
+ * @return a boolean indicating whether the skip succeeded, or whether the sequence ended.
+ * @throws IOException if the byte is unable to be read
+ * @throws EOFException if the requested bytes extend beyond the end of the underlying data source
+ * @throws BufferBoundsException if the requested byte is beyond the end of the underlying data source
+ */
+ public boolean trySkip(long n) throws IOException, EOFException, BufferBoundsException
+ {
+ try
+ {
+ skip(n);
+ return true;
+ }
+ catch (IOException ex)
+ {
+ // Stream ended, or error reading from underlying source
+ return false;
+ }
+ }
+
+ /**
+ * Retrieves bytes, writing them into a caller-provided buffer.
+ *
+ * @param buffer array to write bytes to
+ * @param offset starting position with buffer to write to
+ * @param count The number of bytes to be written
+ * @return The requested bytes
+ * @throws IOException if the byte is unable to be read
+ * @throws EOFException if the requested bytes extend beyond the end of the underlying data source
+ * @throws BufferBoundsException if the requested byte is beyond the end of the underlying data source
+ */
+ public int read(byte[] buffer, int offset, int count) throws IOException, EOFException, BufferBoundsException
+ {
+ return read(buffer, offset, SequentialFlag, count);
+ }
+
+ /**
+ * Retrieves bytes, writing them into a caller-provided buffer.
+ * SequentialFlag as index indicates this call should read sequentially
+ *
+ * @param buffer array to write bytes to
+ * @param offset starting position with buffer to write to
+ * @param index position within the data buffer to read bytes
+ * @param count The number of bytes to be written
+ * @return The requested bytes
+ * @throws IOException if the byte is unable to be read
+ * @throws EOFException if the requested bytes extend beyond the end of the underlying data source
+ * @throws BufferBoundsException if the requested byte is beyond the end of the underlying data source
+ */
+ public int read(byte[] buffer, int offset, long index, int count) throws IOException, EOFException, BufferBoundsException
+ {
+ boolean isSeq = (index == SequentialFlag);
+ long readat = isSeq ? getGlobalPosition() : (getStartPosition() + index);
+
+ return readAtGlobal(readat, buffer, offset, count, isSeq, true);
+ }
+
+ private int readAtGlobal(long readat, byte[] buffer, int offset, int count, boolean isSequential, boolean allowPartial) throws IOException, EOFException, BufferBoundsException
+ {
+ int read = _ras.read(readat, buffer, offset, count, isSequential, allowPartial);
+
+ if (isSequential && read > 0)
+ _localPosition += read; // advance the sequential position
+
+ return read;
+ }
+
+ /**
+ * Determine if the next bytes match the input pattern. Internal sequential variables are unaffected
+ *
+ * @param pattern the byte pattern to match
+ * @return true if this pattern is found or false if any part of it is not found
+ * @throws IOException if the byte is unable to be read
+ * @throws EOFException if the requested bytes extend beyond the end of the underlying data source
+ * @throws BufferBoundsException if the requested byte is beyond the end of the underlying data source
+ */
+ public boolean startsWith(byte[] pattern) throws IOException, EOFException, BufferBoundsException
+ {
+ if (getLength() < pattern.length)
+ return false;
+
+ boolean ret = true;
+ int i = 0;
+ for (i = 0; i < pattern.length; i++)
+ {
+ if (getByte(i) != pattern[i])
+ {
+ ret = false;
+ break;
+ }
+ }
+
+ return ret;
+ }
+
+ /**
+ * Gets the byte value at the current sequential index
+ *
+ * Implementations should not perform any bounds checking in this method. That should be performed
+ * in validateIndex
and bytesAvailable
.
+ *
+ * @return The read byte value
+ * @throws IOException if the byte is unable to be read
+ * @throws EOFException if the requested bytes extend beyond the end of the underlying data source
+ * @throws BufferBoundsException if the requested byte is beyond the end of the underlying data source
+ */
+ public byte getByte() throws IOException, EOFException, BufferBoundsException
+ {
+ return getByte(SequentialFlag);
+ }
+
+ /**
+ * Gets the byte value at the specified byte index
.
+ *
+ * Implementations should not perform any bounds checking in this method. That should be performed
+ * in validateIndex
and bytesAvailable
.
+ *
+ * @param index The index from which to read the byte
+ * @return The read byte value
+ * @throws IOException if the byte is unable to be read
+ * @throws EOFException if the requested bytes extend beyond the end of the underlying data source
+ * @throws BufferBoundsException if the requested byte is beyond the end of the underlying data source
+ */
+ public byte getByte(long index) throws IOException, EOFException, BufferBoundsException
+ {
+ boolean isSeq = (index == SequentialFlag);
+ long readat = isSeq ? getGlobalPosition() : (getStartPosition() + index);
+
+ byte read = _ras.getByte(readat, isSeq);
+
+ if (isSeq)
+ _localPosition++; // advance the sequential position
+
+ return read;
+ }
+
+ /**
+ * Returns the required number of bytes sequentially from the underlying source.
+ *
+ * @param count The number of bytes to be returned
+ * @return The requested bytes
+ * @throws IOException if the byte is unable to be read
+ * @throws EOFException if the requested bytes extend beyond the end of the underlying data source
+ * @throws BufferBoundsException if the requested byte is beyond the end of the underlying data source
+ */
+ public byte[] getBytes(int count) throws IOException, EOFException, BufferBoundsException
+ {
+ return getBytes(SequentialFlag, count);
+ }
+
+ /**
+ * Returns the required number of bytes from the specified index from the underlying source.
+ *
+ * @param index The index from which the bytes begins in the underlying source
+ * @param count The number of bytes to be returned
+ * @return The requested bytes
+ * @throws IOException if the byte is unable to be read
+ * @throws EOFException if the requested bytes extend beyond the end of the underlying data source
+ * @throws BufferBoundsException if the requested byte is beyond the end of the underlying data source
+ */
+ public byte[] getBytes(long index, int count) throws IOException, EOFException, BufferBoundsException
+ {
+ // validate the index now to avoid creating a byte array that could cause a heap overflow
+ boolean isSeq = (index == SequentialFlag);
+ long readat = isSeq ? getGlobalPosition() : (getStartPosition() + index);
+ long available = _ras.validateIndex(readat, count, isSeq, false);
+
+ if(available <= 0)
+ return new byte[0];
+
+ byte[] bytes = new byte[count];
+ readAtGlobal(readat, bytes, 0, count, isSeq, false);
+
+ return bytes;
+ }
+
+ /**
+ * Gets whether a bit at the current sequential index is set or not.
+ *
+ * @return true if the bit is set, otherwise false
+ * @throws IOException if the byte is unable to be read
+ * @throws EOFException if the requested bytes extend beyond the end of the underlying data source
+ * @throws BufferBoundsException if the requested byte is beyond the end of the underlying data source
+ */
+ public boolean getBit() throws IOException, EOFException, BufferBoundsException
+ {
+ return getBit(SequentialFlag);
+ }
+
+ /**
+ * Gets whether a bit at a specific index is set or not.
+ *
+ * @param index the number of bits at which to test
+ * @return true if the bit is set, otherwise false
+ * @throws IOException if the byte is unable to be read
+ * @throws EOFException if the requested bytes extend beyond the end of the underlying data source
+ * @throws BufferBoundsException if the requested byte is beyond the end of the underlying data source
+ */
+ public boolean getBit(int index) throws IOException, EOFException, BufferBoundsException
+ {
+ int byteIndex = index / 8;
+ int bitIndex = index % 8;
+
+ byte b = getByte(byteIndex);
+ return ((b >> bitIndex) & 1) == 1;
+ }
+
+ /**
+ * Returns an unsigned 8-bit int calculated from one byte of data at the current sequential index.
+ *
+ * @return the 8 bit int value, between 0 and 255
+ * @throws IOException if the byte is unable to be read
+ * @throws EOFException if the requested bytes extend beyond the end of the underlying data source
+ * @throws BufferBoundsException if the requested byte is beyond the end of the underlying data source
+ */
+ public short getUInt8() throws IOException, EOFException, BufferBoundsException
+ {
+ return getUInt8(SequentialFlag);
+ }
+
+ /**
+ * Returns an unsigned 8-bit int calculated from one byte of data at the specified index.
+ *
+ * @param index position within the data buffer to read byte
+ * @return the 8 bit int value, between 0 and 255
+ * @throws IOException if the byte is unable to be read
+ * @throws EOFException if the requested bytes extend beyond the end of the underlying data source
+ * @throws BufferBoundsException if the requested byte is beyond the end of the underlying data source
+ */
+ public short getUInt8(int index) throws IOException, EOFException, BufferBoundsException
+ {
+ return (short) (getByte(index) & 0xFF);
+ }
+
+ /**
+ * Returns a signed 8-bit int calculated from one byte of data at the current sequential index.
+ *
+ * @return the 8 bit int value, between 0x00 and 0xFF
+ * @throws IOException if the byte is unable to be read
+ * @throws EOFException if the requested bytes extend beyond the end of the underlying data source
+ * @throws BufferBoundsException if the requested byte is beyond the end of the underlying data source
+ */
+ public byte getInt8() throws IOException, EOFException, BufferBoundsException
+ {
+ return getInt8(SequentialFlag);
+ }
+
+ /**
+ * Returns a signed 8-bit int calculated from one byte of data at the specified index.
+ *
+ * @param index position within the data buffer to read byte
+ * @return the 8 bit int value, between 0x00 and 0xFF
+ * @throws IOException if the byte is unable to be read
+ * @throws EOFException if the requested bytes extend beyond the end of the underlying data source
+ * @throws BufferBoundsException if the requested byte is beyond the end of the underlying data source
+ */
+ public byte getInt8(int index) throws IOException, EOFException, BufferBoundsException
+ {
+ return getByte(index);
+ }
+
+ /**
+ * Returns an unsigned 16-bit int calculated from two bytes of data at the current sequential index.
+ *
+ * @return the 16 bit int value, between 0x0000 and 0xFFFF
+ * @throws IOException if the byte is unable to be read
+ * @throws EOFException if the requested bytes extend beyond the end of the underlying data source
+ * @throws BufferBoundsException if the requested byte is beyond the end of the underlying data source
+ */
+ public int getUInt16() throws IOException, EOFException, BufferBoundsException
+ {
+ return getUInt16(SequentialFlag);
+ }
+
+ /**
+ * Returns an unsigned 16-bit int calculated from two bytes of data at the specified index.
+ *
+ * @param index position within the data buffer to read first byte
+ * @return the 16 bit int value, between 0x0000 and 0xFFFF
+ * @throws IOException if the byte is unable to be read
+ * @throws EOFException if the requested bytes extend beyond the end of the underlying data source
+ * @throws BufferBoundsException if the requested byte is beyond the end of the underlying data source
+ */
+ public int getUInt16(int index) throws IOException, EOFException, BufferBoundsException
+ {
+ boolean isSeq = (index == SequentialFlag);
+ long readat = isSeq ? getGlobalPosition() : (getStartPosition() + index);
+
+ int read = _ras.getUInt16(readat, isMotorolaByteOrder(), isSeq);
+
+ if (isSeq)
+ _localPosition += 2; // advance the sequential position
+
+ return read;
+ }
+
+ /**
+ * Returns a signed 16-bit int calculated from two bytes of data at the current sequential index (MSB, LSB).
+ *
+ * @return the 16 bit int value, between 0x0000 and 0xFFFF
+ * @throws IOException if the byte is unable to be read
+ * @throws EOFException if the requested bytes extend beyond the end of the underlying data source
+ * @throws BufferBoundsException if the requested byte is beyond the end of the underlying data source
+ */
+ public short getInt16() throws IOException, EOFException, BufferBoundsException
+ {
+ return getInt16(SequentialFlag);
+ }
+
+ /**
+ * Returns a signed 16-bit int calculated from two bytes of data at the specified index (MSB, LSB).
+ *
+ * @param index position within the data buffer to read first byte
+ * @return the 16 bit int value, between 0x0000 and 0xFFFF
+ * @throws IOException if the byte is unable to be read
+ * @throws EOFException if the requested bytes extend beyond the end of the underlying data source
+ * @throws BufferBoundsException if the requested byte is beyond the end of the underlying data source
+ */
+ public short getInt16(int index) throws IOException, EOFException, BufferBoundsException
+ {
+ boolean isSeq = (index == SequentialFlag);
+ long readat = isSeq ? getGlobalPosition() : (getStartPosition() + index);
+
+ short read = _ras.getInt16(readat, isMotorolaByteOrder(), isSeq);
+
+ if (isSeq)
+ _localPosition += 2; // advance the sequential position
+
+ return read;
+ }
+
+ /**
+ * Get a 24-bit unsigned integer from the current sequential index, returning it as an int.
+ *
+ * @return the unsigned 24-bit int value as a long, between 0x00000000 and 0x00FFFFFF
+ * @throws IOException if the byte is unable to be read
+ * @throws EOFException if the requested bytes extend beyond the end of the underlying data source
+ * @throws BufferBoundsException if the requested byte is beyond the end of the underlying data source
+ */
+ public int getInt24() throws IOException, EOFException, BufferBoundsException
+ {
+ return getInt24(SequentialFlag);
+ }
+
+ /**
+ * Get a 24-bit unsigned integer from the buffer, returning it as an int.
+ *
+ * @param index position within the data buffer to read first byte
+ * @return the unsigned 24-bit int value as a long, between 0x00000000 and 0x00FFFFFF
+ * @throws IOException if the byte is unable to be read
+ * @throws EOFException if the requested bytes extend beyond the end of the underlying data source
+ * @throws BufferBoundsException if the requested byte is beyond the end of the underlying data source
+ */
+ public int getInt24(int index) throws IOException, EOFException, BufferBoundsException
+ {
+ boolean isSeq = (index == SequentialFlag);
+ long readat = isSeq ? getGlobalPosition() : (getStartPosition() + index);
+
+ int read = _ras.getInt24(readat, isMotorolaByteOrder(), isSeq);
+
+ if (isSeq)
+ _localPosition += 3; // advance the sequential position
+
+ return read;
+ }
+
+ /**
+ * Get a 32-bit unsigned integer from the current sequential index, returning it as a long.
+ *
+ * @return the unsigned 32-bit int value as a long, between 0x00000000 and 0xFFFFFFFF
+ * @throws IOException if the byte is unable to be read
+ * @throws EOFException if the requested bytes extend beyond the end of the underlying data source
+ * @throws BufferBoundsException if the requested byte is beyond the end of the underlying data source
+ */
+ public long getUInt32() throws IOException, EOFException, BufferBoundsException
+ {
+ return getUInt32(SequentialFlag);
+ }
+
+ /**
+ * Get a 32-bit unsigned integer from the buffer, returning it as a long.
+ *
+ * @param index position within the data buffer to read first byte
+ * @return the unsigned 32-bit int value as a long, between 0x00000000 and 0xFFFFFFFF
+ * @throws IOException if the byte is unable to be read
+ * @throws EOFException if the requested bytes extend beyond the end of the underlying data source
+ * @throws BufferBoundsException if the requested byte is beyond the end of the underlying data source
+ */
+ public long getUInt32(int index) throws IOException, EOFException, BufferBoundsException
+ {
+ boolean isSeq = (index == SequentialFlag);
+ long readat = isSeq ? getGlobalPosition() : (getStartPosition() + index);
+
+ long read = _ras.getUInt32(readat, isMotorolaByteOrder(), isSeq);
+
+ if (isSeq)
+ _localPosition += 4; // advance the sequential position
+
+ return read;
+ }
+
+ /**
+ * Returns a signed 32-bit integer from four bytes of data at the current sequential index of the buffer.
+ *
+ * @return the signed 32 bit int value, between 0x00000000 and 0xFFFFFFFF
+ * @throws IOException if the byte is unable to be read
+ * @throws EOFException if the requested bytes extend beyond the end of the underlying data source
+ * @throws BufferBoundsException if the requested byte is beyond the end of the underlying data source
+ */
+ public int getInt32() throws IOException, EOFException, BufferBoundsException
+ {
+ return getInt32(SequentialFlag);
+ }
+
+ /**
+ * Returns a signed 32-bit integer from four bytes of data at the specified index of the buffer.
+ *
+ * @param index position within the data buffer to read first byte
+ * @return the signed 32 bit int value, between 0x00000000 and 0xFFFFFFFF
+ * @throws IOException if the byte is unable to be read
+ * @throws EOFException if the requested bytes extend beyond the end of the underlying data source
+ * @throws BufferBoundsException if the requested byte is beyond the end of the underlying data source
+ */
+ public int getInt32(int index) throws IOException, EOFException, BufferBoundsException
+ {
+ boolean isSeq = (index == SequentialFlag);
+ long readat = isSeq ? getGlobalPosition() : (getStartPosition() + index);
+
+ int read = _ras.getInt32(readat, isMotorolaByteOrder(), isSeq);
+
+ if (isSeq)
+ _localPosition += 4; // advance the sequential position
+
+ return read;
+ }
+
+ /**
+ * Get a signed 64-bit integer from the current sequential index of the buffer.
+ *
+ * @return the 64 bit int value, between 0x0000000000000000 and 0xFFFFFFFFFFFFFFFF
+ * @throws IOException if the byte is unable to be read
+ * @throws EOFException if the requested bytes extend beyond the end of the underlying data source
+ * @throws BufferBoundsException if the requested byte is beyond the end of the underlying data source
+ */
+ public long getInt64() throws IOException, EOFException, BufferBoundsException
+ {
+ return getInt64(SequentialFlag);
+ }
+
+ /**
+ * Get a signed 64-bit integer from the buffer.
+ *
+ * @param index position within the data buffer to read first byte
+ * @return the 64 bit int value, between 0x0000000000000000 and 0xFFFFFFFFFFFFFFFF
+ * @throws IOException if the byte is unable to be read
+ * @throws EOFException if the requested bytes extend beyond the end of the underlying data source
+ * @throws BufferBoundsException if the requested byte is beyond the end of the underlying data source
+ */
+ public long getInt64(int index) throws IOException, EOFException, BufferBoundsException
+ {
+ boolean isSeq = (index == SequentialFlag);
+ long readat = isSeq ? getGlobalPosition() : (getStartPosition() + index);
+
+ long read = _ras.getInt64(readat, isMotorolaByteOrder(), isSeq);
+
+ if (isSeq)
+ _localPosition += 8; // advance the sequential position
+
+ return read;
+ }
+
+ /**
+ * Gets a s15.16 fixed point float from the buffer sequentially.
+ *
+ * This particular fixed point encoding has one sign bit, 15 numerator bits and 16 denominator bits.
+ *
+ * @return the floating point value
+ * @throws IOException if the byte is unable to be read
+ * @throws EOFException if the requested bytes extend beyond the end of the underlying data source
+ * @throws BufferBoundsException if the requested byte is beyond the end of the underlying data source
+ */
+ public float getS15Fixed16() throws IOException, EOFException, BufferBoundsException
+ {
+ return getS15Fixed16(SequentialFlag);
+ }
+
+ /**
+ * Gets a s15.16 fixed point float from the buffer.
+ *
+ * This particular fixed point encoding has one sign bit, 15 numerator bits and 16 denominator bits.
+ *
+ * @param index position within the data buffer to read first byte
+ * @return the floating point value
+ * @throws IOException if the byte is unable to be read
+ * @throws EOFException if the requested bytes extend beyond the end of the underlying data source
+ * @throws BufferBoundsException if the requested byte is beyond the end of the underlying data source
+ */
+ public float getS15Fixed16(int index) throws IOException, EOFException, BufferBoundsException
+ {
+ boolean isSeq = (index == SequentialFlag);
+ long readat = isSeq ? getGlobalPosition() : (getStartPosition() + index);
+
+ float read = _ras.getS15Fixed16(readat, isMotorolaByteOrder(), isSeq);
+
+ if (isSeq)
+ _localPosition += 4; // advance the sequential position
+
+ return read;
+ }
+
+ public float getFloat32() throws IOException, EOFException, BufferBoundsException
+ {
+ return getFloat32(SequentialFlag);
+ }
+
+ public float getFloat32(int index) throws IOException, EOFException, BufferBoundsException
+ {
+ return Float.intBitsToFloat(getInt32(index));
+ }
+
+ public double getDouble64() throws IOException, EOFException, BufferBoundsException
+ {
+ return getDouble64(SequentialFlag);
+ }
+
+ public double getDouble64(int index) throws IOException, EOFException, BufferBoundsException
+ {
+ return Double.longBitsToDouble(getInt64(index));
+ }
+
+ @NotNull
+ public StringValue getStringValue(int bytesRequested, @Nullable Charset charset) throws IOException, EOFException, BufferBoundsException
+ {
+ return getStringValue(SequentialFlag, bytesRequested, charset);
+ }
+
+ @NotNull
+ public StringValue getStringValue(int index, int bytesRequested, @Nullable Charset charset) throws IOException, EOFException, BufferBoundsException
+ {
+ return new StringValue(getBytes(index, bytesRequested), charset);
+ }
+
+ @NotNull
+ public String getString(int bytesRequested, @NotNull Charset charset) throws IOException, EOFException, BufferBoundsException
+ {
+ return getString(SequentialFlag, bytesRequested, charset);
+ }
+
+ @NotNull
+ public String getString(int index, int bytesRequested, @NotNull Charset charset) throws IOException, EOFException, BufferBoundsException
+ {
+ return new String(getBytes(index, bytesRequested), charset.name());
+ }
+
+ @NotNull
+ public String getString(int index, int bytesRequested, @NotNull String charset) throws IOException, EOFException, BufferBoundsException
+ {
+ byte[] bytes = getBytes(index, bytesRequested);
+ try {
+ return new String(bytes, charset);
+ } catch (UnsupportedEncodingException e) {
+ return new String(bytes);
+ }
+ }
+
+ /**
+ * Creates a String from the _data buffer starting at the current sequential index,
+ * and ending where byte=='\0'
or where length==maxLength
.
+ *
+ * @param maxLengthBytes The maximum number of bytes to read. If a zero-byte is not reached within this limit,
+ * reading will stop and the string will be truncated to this length.
+ * @param charset The Charset
to register with the returned StringValue
, or null
if the encoding
+ * is unknown
+ * @return The read string.
+ * @throws IOException if the byte is unable to be read
+ * @throws EOFException if the requested bytes extend beyond the end of the underlying data source
+ * @throws BufferBoundsException if the requested byte is beyond the end of the underlying data source
+ */
+ @NotNull
+ public String getNullTerminatedString(int maxLengthBytes, @NotNull Charset charset) throws IOException, EOFException, BufferBoundsException
+ {
+ return getNullTerminatedString(SequentialFlag, maxLengthBytes, charset);
+ }
+
+ /**
+ * Creates a String from the _data buffer starting at the specified index,
+ * and ending where byte=='\0'
or where length==maxLength
.
+ *
+ * @param index The index within the buffer at which to start reading the string.
+ * @param maxLengthBytes The maximum number of bytes to read. If a zero-byte is not reached within this limit,
+ * reading will stop and the string will be truncated to this length.
+ * @param charset The Charset
to register with the returned StringValue
, or null
if the encoding
+ * is unknown
+ * @return The read string.
+ * @throws IOException if the byte is unable to be read
+ * @throws EOFException if the requested bytes extend beyond the end of the underlying data source
+ * @throws BufferBoundsException if the requested byte is beyond the end of the underlying data source
+ */
+ @NotNull
+ public String getNullTerminatedString(int index, int maxLengthBytes, @NotNull Charset charset) throws IOException, EOFException, BufferBoundsException
+ {
+ return new String(getNullTerminatedBytes(index, maxLengthBytes), charset.name());
+ }
+
+ /**
+ * Creates a String from the _data buffer starting at the current sequential index,
+ * and ending where byte=='\0'
or where length==maxLength
.
+ *
+ * @param maxLengthBytes The maximum number of bytes to read. If a zero-byte is not reached within this limit,
+ * reading will stop and the string will be truncated to this length.
+ * @param charset The Charset
to register with the returned StringValue
, or null
if the encoding
+ * is unknown
+ * @return The read string.
+ * @throws IOException if the byte is unable to be read
+ * @throws EOFException if the requested bytes extend beyond the end of the underlying data source
+ * @throws BufferBoundsException if the requested byte is beyond the end of the underlying data source
+ */
+ @NotNull
+ public StringValue getNullTerminatedStringValue(int maxLengthBytes, @Nullable Charset charset) throws IOException, EOFException, BufferBoundsException
+ {
+ return getNullTerminatedStringValue(SequentialFlag, maxLengthBytes, charset);
+ }
+
+ /**
+ * Creates a String from the _data buffer starting at the specified index,
+ * and ending where byte=='\0'
or where length==maxLength
.
+ *
+ * @param index The index within the buffer at which to start reading the string.
+ * @param maxLengthBytes The maximum number of bytes to read. If a zero-byte is not reached within this limit,
+ * reading will stop and the string will be truncated to this length.
+ * @param charset The Charset
to register with the returned StringValue
, or null
if the encoding
+ * is unknown
+ * @return The read string.
+ * @throws IOException if the byte is unable to be read
+ * @throws EOFException if the requested bytes extend beyond the end of the underlying data source
+ * @throws BufferBoundsException if the requested byte is beyond the end of the underlying data source
+ */
+ @NotNull
+ public StringValue getNullTerminatedStringValue(int index, int maxLengthBytes, @Nullable Charset charset) throws IOException, EOFException, BufferBoundsException
+ {
+ byte[] bytes = getNullTerminatedBytes(index, maxLengthBytes);
+
+ return new StringValue(bytes, charset);
+ }
+
+ /**
+ * Returns the sequence of bytes punctuated by a \0
value.
+ *
+ * @param maxLengthBytes The maximum number of bytes to read. If a \0
byte is not reached within this limit,
+ * the returned array will be maxLengthBytes
long.
+ * @return The read byte array, excluding the null terminator.
+ * @throws IOException if the byte is unable to be read
+ * @throws EOFException if the requested bytes extend beyond the end of the underlying data source
+ * @throws BufferBoundsException if the requested byte is beyond the end of the underlying data source
+ */
+ @NotNull
+ public byte[] getNullTerminatedBytes(int maxLengthBytes) throws IOException, EOFException, BufferBoundsException
+ {
+ return getNullTerminatedBytes(SequentialFlag, maxLengthBytes);
+ }
+
+ /**
+ * Returns the sequence of bytes punctuated by a \0
value.
+ *
+ * @param index The index within the buffer at which to start reading the string.
+ * @param maxLengthBytes The maximum number of bytes to read. If a \0
byte is not reached within this limit,
+ * the returned array will be maxLengthBytes
long.
+ * @return The read byte array, excluding the null terminator.
+ * @throws IOException if the byte is unable to be read
+ * @throws EOFException if the requested bytes extend beyond the end of the underlying data source
+ * @throws BufferBoundsException if the requested byte is beyond the end of the underlying data source
+ */
+ @NotNull
+ public byte[] getNullTerminatedBytes(int index, int maxLengthBytes) throws IOException, EOFException, BufferBoundsException
+ {
+ boolean isSeq = (index == SequentialFlag);
+ byte[] buffer = !isSeq ? getBytes(index, maxLengthBytes) : new byte[maxLengthBytes];
+
+ // Count the number of non-null bytes
+ int length = 0;
+ if(!isSeq)
+ {
+ while (length < buffer.length && buffer[length] != 0)
+ length++;
+ }
+ else
+ {
+ byte getB = getByte();
+ while(length < buffer.length && getB != 0)
+ {
+ buffer[length] = getB;
+ getB = getByte();
+ length++;
+ }
+ }
+
+ if (length == maxLengthBytes)
+ return buffer;
+
+ byte[] bytes = new byte[length];
+ if (length > 0)
+ System.arraycopy(buffer, 0, bytes, 0, length);
+ return bytes;
+ }
+
+ /// Returns the bytes described by this particular reader
+ ///
+ /**
+ * Returns the bytes described by this particular reader
+ * @return byte array
+ * @throws IOException if the byte is unable to be read
+ * @throws EOFException if the requested bytes extend beyond the end of the underlying data source
+ * @throws BufferBoundsException if the requested byte is beyond the end of the underlying data source
+ */
+ public byte[] toArray() throws IOException, EOFException, BufferBoundsException
+ {
+ return _ras.toArray(getStartPosition(), (int)getLength());
+ }
+
+ public String readLine() throws IOException
+ {
+ StringBuilder sb = new StringBuilder();
+ while (true)
+ {
+ if (getLocalPosition() == getLength())
+ break;
+
+ int ch = getByte();
+ if (ch == -1) break;
+ if (ch == '\r' || ch == '\n')
+ {
+ byte nextbyte = 0;
+ if(getGlobalPosition() + 1 < getLength())
+ nextbyte = getByte();
+ if (!(ch == '\r' && nextbyte == '\n'))
+ skip(-1);
+
+ return sb.toString();
+ }
+ sb.append((char)ch);
+ }
+ if (sb.length() > 0) return sb.toString();
+ return null;
+ }
+
+ /**
+ * Returns true in case the sequence supports length checking and distance to the end of the stream is less then number of bytes in parameter.
+ * Otherwise false.
+ * @param numberOfBytes count of bytes to try and read
+ * @return True if we are going to have an exception while reading next numberOfBytes bytes from the stream
+ * @throws IOException if the byte is unable to be read
+ * @throws EOFException if the requested bytes extend beyond the end of the underlying data source
+ * @throws BufferBoundsException if the requested byte is beyond the end of the underlying data source
+ */
+ public boolean isCloserToEnd(long numberOfBytes) throws IOException, EOFException, BufferBoundsException
+ {
+ return (getLocalPosition() + numberOfBytes) > getLength();
+ }
+}
diff --git a/Source/com/drew/lang/SequentialByteArrayReader.java b/Source/com/drew/lang/SequentialByteArrayReader.java
deleted file mode 100644
index 846efeb6f..000000000
--- a/Source/com/drew/lang/SequentialByteArrayReader.java
+++ /dev/null
@@ -1,130 +0,0 @@
-/*
- * Copyright 2002-2017 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:
- *
- * https://drewnoakes.com/code/exif/
- * https://github.com/drewnoakes/metadata-extractor
- */
-
-package com.drew.lang;
-
-import com.drew.lang.annotations.NotNull;
-
-import java.io.EOFException;
-import java.io.IOException;
-
-/**
- *
- * @author Drew Noakes https://drewnoakes.com
- */
-public class SequentialByteArrayReader extends SequentialReader
-{
- @NotNull
- private final byte[] _bytes;
- private int _index;
-
- @Override
- public long getPosition()
- {
- return _index;
- }
-
- public SequentialByteArrayReader(@NotNull byte[] bytes)
- {
- this(bytes, 0);
- }
-
- @SuppressWarnings("ConstantConditions")
- public SequentialByteArrayReader(@NotNull byte[] bytes, int baseIndex)
- {
- if (bytes == null)
- throw new NullPointerException();
-
- _bytes = bytes;
- _index = baseIndex;
- }
-
- @Override
- public byte getByte() throws IOException
- {
- if (_index >= _bytes.length) {
- throw new EOFException("End of data reached.");
- }
- return _bytes[_index++];
- }
-
- @NotNull
- @Override
- public byte[] getBytes(int count) throws IOException
- {
- if (_index + count > _bytes.length) {
- throw new EOFException("End of data reached.");
- }
-
- byte[] bytes = new byte[count];
- System.arraycopy(_bytes, _index, bytes, 0, count);
- _index += count;
-
- return bytes;
- }
-
- @Override
- public void getBytes(@NotNull byte[] buffer, int offset, int count) throws IOException
- {
- if (_index + count > _bytes.length) {
- throw new EOFException("End of data reached.");
- }
-
- System.arraycopy(_bytes, _index, buffer, offset, count);
- _index += count;
- }
-
- @Override
- public void skip(long n) throws IOException
- {
- if (n < 0) {
- throw new IllegalArgumentException("n must be zero or greater.");
- }
-
- if (_index + n > _bytes.length) {
- throw new EOFException("End of data reached.");
- }
-
- _index += n;
- }
-
- @Override
- public boolean trySkip(long n) throws IOException
- {
- if (n < 0) {
- throw new IllegalArgumentException("n must be zero or greater.");
- }
-
- _index += n;
-
- if (_index > _bytes.length) {
- _index = _bytes.length;
- return false;
- }
-
- return true;
- }
-
- @Override
- public int available() {
- return _bytes.length - _index;
- }
-}
diff --git a/Source/com/drew/lang/SequentialReader.java b/Source/com/drew/lang/SequentialReader.java
deleted file mode 100644
index d172aa944..000000000
--- a/Source/com/drew/lang/SequentialReader.java
+++ /dev/null
@@ -1,389 +0,0 @@
-/*
- * Copyright 2002-2017 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:
- *
- * https://drewnoakes.com/code/exif/
- * https://github.com/drewnoakes/metadata-extractor
- */
-
-package com.drew.lang;
-
-import com.drew.lang.annotations.NotNull;
-import com.drew.lang.annotations.Nullable;
-import com.drew.metadata.StringValue;
-
-import java.io.EOFException;
-import java.io.IOException;
-import java.io.UnsupportedEncodingException;
-import java.nio.charset.Charset;
-
-/**
- * @author Drew Noakes https://drewnoakes.com
- */
-@SuppressWarnings("WeakerAccess")
-public abstract class SequentialReader
-{
- // TODO review whether the masks are needed (in both this and RandomAccessReader)
-
- private boolean _isMotorolaByteOrder = true;
-
- public abstract long getPosition() throws IOException;
-
- /**
- * Gets the next byte in the sequence.
- *
- * @return The read byte value
- */
- public abstract byte getByte() throws IOException;
-
- /**
- * Returns the required number of bytes from the sequence.
- *
- * @param count The number of bytes to be returned
- * @return The requested bytes
- */
- @NotNull
- public abstract byte[] getBytes(int count) throws IOException;
-
- /**
- * Retrieves bytes, writing them into a caller-provided buffer.
- * @param buffer The array to write bytes to.
- * @param offset The starting position within buffer to write to.
- * @param count The number of bytes to be written.
- */
- public abstract void getBytes(@NotNull byte[] buffer, int offset, int count) throws IOException;
-
- /**
- * Skips forward in the sequence. If the sequence ends, an {@link EOFException} is thrown.
- *
- * @param n the number of byte to skip. Must be zero or greater.
- * @throws EOFException the end of the sequence is reached.
- * @throws IOException an error occurred reading from the underlying source.
- */
- public abstract void skip(long n) throws IOException;
-
- /**
- * Skips forward in the sequence, returning a boolean indicating whether the skip succeeded, or whether the sequence ended.
- *
- * @param n the number of byte to skip. Must be zero or greater.
- * @return a boolean indicating whether the skip succeeded, or whether the sequence ended.
- * @throws IOException an error occurred reading from the underlying source.
- */
- public abstract boolean trySkip(long n) throws IOException;
-
- /**
- * Returns an estimate of the number of bytes that can be read (or skipped
- * over) from this {@link SequentialReader} without blocking by the next
- * invocation of a method for this input stream. A single read or skip of
- * this many bytes will not block, but may read or skip fewer bytes.
- *
- * Note that while some implementations of {@link SequentialReader} like
- * {@link SequentialByteArrayReader} will return the total remaining number
- * of bytes in the stream, others will not. It is never correct to use the
- * return value of this method to allocate a buffer intended to hold all
- * data in this stream.
- *
- * @return an estimate of the number of bytes that can be read (or skipped
- * over) from this {@link SequentialReader} without blocking or
- * {@code 0} when it reaches the end of the input stream.
- */
- public abstract int available();
-
- /**
- * Sets the endianness of this reader.
- *
- * true
for Motorola (or big) endianness (also known as network byte order), with MSB before LSB.
- * false
for Intel (or little) endianness, with LSB before MSB.
- *
- *
- * @param motorolaByteOrder true
for Motorola/big endian, false
for Intel/little endian
- */
- public void setMotorolaByteOrder(boolean motorolaByteOrder)
- {
- _isMotorolaByteOrder = motorolaByteOrder;
- }
-
- /**
- * Gets the endianness of this reader.
- *
- * true
for Motorola (or big) endianness (also known as network byte order), with MSB before LSB.
- * false
for Intel (or little) endianness, with LSB before MSB.
- *
- */
- public boolean isMotorolaByteOrder()
- {
- return _isMotorolaByteOrder;
- }
-
- /**
- * Returns an unsigned 8-bit int calculated from the next byte of the sequence.
- *
- * @return the 8 bit int value, between 0 and 255
- */
- public short getUInt8() throws IOException
- {
- return (short) (getByte() & 0xFF);
- }
-
- /**
- * Returns a signed 8-bit int calculated from the next byte the sequence.
- *
- * @return the 8 bit int value, between 0x00 and 0xFF
- */
- public byte getInt8() throws IOException
- {
- return getByte();
- }
-
- /**
- * Returns an unsigned 16-bit int calculated from the next two bytes of the sequence.
- *
- * @return the 16 bit int value, between 0x0000 and 0xFFFF
- */
- public int getUInt16() throws IOException
- {
- if (_isMotorolaByteOrder) {
- // Motorola - MSB first
- return (getByte() << 8 & 0xFF00) |
- (getByte() & 0xFF);
- } else {
- // Intel ordering - LSB first
- return (getByte() & 0xFF) |
- (getByte() << 8 & 0xFF00);
- }
- }
-
- /**
- * Returns a signed 16-bit int calculated from two bytes of data (MSB, LSB).
- *
- * @return the 16 bit int value, between 0x0000 and 0xFFFF
- * @throws IOException the buffer does not contain enough bytes to service the request
- */
- public short getInt16() throws IOException
- {
- if (_isMotorolaByteOrder) {
- // Motorola - MSB first
- return (short) (((short)getByte() << 8 & (short)0xFF00) |
- ((short)getByte() & (short)0xFF));
- } else {
- // Intel ordering - LSB first
- return (short) (((short)getByte() & (short)0xFF) |
- ((short)getByte() << 8 & (short)0xFF00));
- }
- }
-
- /**
- * Get a 32-bit unsigned integer from the buffer, returning it as a long.
- *
- * @return the unsigned 32-bit int value as a long, between 0x00000000 and 0xFFFFFFFF
- * @throws IOException the buffer does not contain enough bytes to service the request
- */
- public long getUInt32() throws IOException
- {
- if (_isMotorolaByteOrder) {
- // Motorola - MSB first (big endian)
- return (((long)getByte()) << 24 & 0xFF000000L) |
- (((long)getByte()) << 16 & 0xFF0000L) |
- (((long)getByte()) << 8 & 0xFF00L) |
- (((long)getByte()) & 0xFFL);
- } else {
- // Intel ordering - LSB first (little endian)
- return (((long)getByte()) & 0xFFL) |
- (((long)getByte()) << 8 & 0xFF00L) |
- (((long)getByte()) << 16 & 0xFF0000L) |
- (((long)getByte()) << 24 & 0xFF000000L);
- }
- }
-
- /**
- * Returns a signed 32-bit integer from four bytes of data.
- *
- * @return the signed 32 bit int value, between 0x00000000 and 0xFFFFFFFF
- * @throws IOException the buffer does not contain enough bytes to service the request
- */
- public int getInt32() throws IOException
- {
- if (_isMotorolaByteOrder) {
- // Motorola - MSB first (big endian)
- return (getByte() << 24 & 0xFF000000) |
- (getByte() << 16 & 0xFF0000) |
- (getByte() << 8 & 0xFF00) |
- (getByte() & 0xFF);
- } else {
- // Intel ordering - LSB first (little endian)
- return (getByte() & 0xFF) |
- (getByte() << 8 & 0xFF00) |
- (getByte() << 16 & 0xFF0000) |
- (getByte() << 24 & 0xFF000000);
- }
- }
-
- /**
- * Get a signed 64-bit integer from the buffer.
- *
- * @return the 64 bit int value, between 0x0000000000000000 and 0xFFFFFFFFFFFFFFFF
- * @throws IOException the buffer does not contain enough bytes to service the request
- */
- public long getInt64() throws IOException
- {
- if (_isMotorolaByteOrder) {
- // Motorola - MSB first
- return ((long)getByte() << 56 & 0xFF00000000000000L) |
- ((long)getByte() << 48 & 0xFF000000000000L) |
- ((long)getByte() << 40 & 0xFF0000000000L) |
- ((long)getByte() << 32 & 0xFF00000000L) |
- ((long)getByte() << 24 & 0xFF000000L) |
- ((long)getByte() << 16 & 0xFF0000L) |
- ((long)getByte() << 8 & 0xFF00L) |
- ((long)getByte() & 0xFFL);
- } else {
- // Intel ordering - LSB first
- return ((long)getByte() & 0xFFL) |
- ((long)getByte() << 8 & 0xFF00L) |
- ((long)getByte() << 16 & 0xFF0000L) |
- ((long)getByte() << 24 & 0xFF000000L) |
- ((long)getByte() << 32 & 0xFF00000000L) |
- ((long)getByte() << 40 & 0xFF0000000000L) |
- ((long)getByte() << 48 & 0xFF000000000000L) |
- ((long)getByte() << 56 & 0xFF00000000000000L);
- }
- }
-
- /**
- * Gets a s15.16 fixed point float from the buffer.
- *
- * This particular fixed point encoding has one sign bit, 15 numerator bits and 16 denominator bits.
- *
- * @return the floating point value
- * @throws IOException the buffer does not contain enough bytes to service the request
- */
- public float getS15Fixed16() throws IOException
- {
- if (_isMotorolaByteOrder) {
- float res = (getByte() & 0xFF) << 8 |
- (getByte() & 0xFF);
- int d = (getByte() & 0xFF) << 8 |
- (getByte() & 0xFF);
- return (float)(res + d/65536.0);
- } else {
- // this particular branch is untested
- int d = (getByte() & 0xFF) |
- (getByte() & 0xFF) << 8;
- float res = (getByte() & 0xFF) |
- (getByte() & 0xFF) << 8;
- return (float)(res + d/65536.0);
- }
- }
-
- public float getFloat32() throws IOException
- {
- return Float.intBitsToFloat(getInt32());
- }
-
- public double getDouble64() throws IOException
- {
- return Double.longBitsToDouble(getInt64());
- }
-
- @NotNull
- public String getString(int bytesRequested) throws IOException
- {
- return new String(getBytes(bytesRequested));
- }
-
- @NotNull
- public String getString(int bytesRequested, String charset) throws IOException
- {
- byte[] bytes = getBytes(bytesRequested);
- try {
- return new String(bytes, charset);
- } catch (UnsupportedEncodingException e) {
- return new String(bytes);
- }
- }
-
- @NotNull
- public String getString(int bytesRequested, @NotNull Charset charset) throws IOException
- {
- byte[] bytes = getBytes(bytesRequested);
- return new String(bytes, charset);
- }
-
- @NotNull
- public StringValue getStringValue(int bytesRequested, @Nullable Charset charset) throws IOException
- {
- return new StringValue(getBytes(bytesRequested), charset);
- }
-
- /**
- * Creates a String from the stream, ending where byte=='\0'
or where length==maxLength
.
- *
- * @param maxLengthBytes The maximum number of bytes to read. If a zero-byte is not reached within this limit,
- * reading will stop and the string will be truncated to this length.
- * @return The read string.
- * @throws IOException The buffer does not contain enough bytes to satisfy this request.
- */
- @NotNull
- public String getNullTerminatedString(int maxLengthBytes, Charset charset) throws IOException
- {
- return getNullTerminatedStringValue(maxLengthBytes, charset).toString();
- }
-
- /**
- * Creates a String from the stream, ending where byte=='\0'
or where length==maxLength
.
- *
- * @param maxLengthBytes The maximum number of bytes to read. If a \0
byte is not reached within this limit,
- * reading will stop and the string will be truncated to this length.
- * @param charset The Charset
to register with the returned StringValue
, or null
if the encoding
- * is unknown
- * @return The read string.
- * @throws IOException The buffer does not contain enough bytes to satisfy this request.
- */
- @NotNull
- public StringValue getNullTerminatedStringValue(int maxLengthBytes, Charset charset) throws IOException
- {
- byte[] bytes = getNullTerminatedBytes(maxLengthBytes);
-
- return new StringValue(bytes, charset);
- }
-
- /**
- * Returns the sequence of bytes punctuated by a \0
value.
- *
- * @param maxLengthBytes The maximum number of bytes to read. If a \0
byte is not reached within this limit,
- * the returned array will be maxLengthBytes
long.
- * @return The read byte array, excluding the null terminator.
- * @throws IOException The buffer does not contain enough bytes to satisfy this request.
- */
- @NotNull
- public byte[] getNullTerminatedBytes(int maxLengthBytes) throws IOException
- {
- byte[] buffer = new byte[maxLengthBytes];
-
- // Count the number of non-null bytes
- int length = 0;
- while (length < buffer.length && (buffer[length] = getByte()) != 0)
- length++;
-
- if (length == maxLengthBytes)
- return buffer;
-
- byte[] bytes = new byte[length];
- if (length > 0)
- System.arraycopy(buffer, 0, bytes, 0, length);
- return bytes;
- }
-}
diff --git a/Source/com/drew/lang/StreamReader.java b/Source/com/drew/lang/StreamReader.java
deleted file mode 100644
index 1e30b12ef..000000000
--- a/Source/com/drew/lang/StreamReader.java
+++ /dev/null
@@ -1,140 +0,0 @@
-/*
- * Copyright 2002-2017 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:
- *
- * https://drewnoakes.com/code/exif/
- * https://github.com/drewnoakes/metadata-extractor
- */
-
-package com.drew.lang;
-
-import com.drew.lang.annotations.NotNull;
-
-import java.io.EOFException;
-import java.io.IOException;
-import java.io.InputStream;
-
-/**
- *
- * @author Drew Noakes https://drewnoakes.com
- */
-public class StreamReader extends SequentialReader
-{
- @NotNull
- private final InputStream _stream;
-
- private long _pos;
-
- @Override
- public long getPosition()
- {
- return _pos;
- }
-
- @SuppressWarnings("ConstantConditions")
- public StreamReader(@NotNull InputStream stream)
- {
- if (stream == null)
- throw new NullPointerException();
-
- _stream = stream;
- _pos = 0;
- }
-
- @Override
- public byte getByte() throws IOException
- {
- int value = _stream.read();
- if (value == -1)
- throw new EOFException("End of data reached.");
- _pos++;
- return (byte)value;
- }
-
- @NotNull
- @Override
- public byte[] getBytes(int count) throws IOException
- {
- byte[] bytes = new byte[count];
- getBytes(bytes, 0, count);
- return bytes;
- }
-
- @Override
- public void getBytes(@NotNull byte[] buffer, int offset, int count) throws IOException
- {
- int totalBytesRead = 0;
- while (totalBytesRead != count)
- {
- final int bytesRead = _stream.read(buffer, offset + totalBytesRead, count - totalBytesRead);
- if (bytesRead == -1)
- throw new EOFException("End of data reached.");
- totalBytesRead += bytesRead;
- assert(totalBytesRead <= count);
- }
- _pos += totalBytesRead;
- }
-
- @Override
- public void skip(long n) throws IOException
- {
- if (n < 0)
- throw new IllegalArgumentException("n must be zero or greater.");
-
- long skippedCount = skipInternal(n);
-
- if (skippedCount != n)
- throw new EOFException(String.format("Unable to skip. Requested %d bytes but skipped %d.", n, skippedCount));
- }
-
- @Override
- public boolean trySkip(long n) throws IOException
- {
- if (n < 0)
- throw new IllegalArgumentException("n must be zero or greater.");
-
- return skipInternal(n) == n;
- }
-
- @Override
- public int available() {
- try {
- return _stream.available();
- } catch (IOException e) {
- return 0;
- }
- }
-
- private long skipInternal(long n) throws IOException
- {
- // It seems that for some streams, such as BufferedInputStream, that skip can return
- // some smaller number than was requested. So loop until we either skip enough, or
- // InputStream.skip returns zero.
- //
- // See http://stackoverflow.com/questions/14057720/robust-skipping-of-data-in-a-java-io-inputstream-and-its-subtypes
- //
- long skippedTotal = 0;
- while (skippedTotal != n) {
- long skipped = _stream.skip(n - skippedTotal);
- assert(skipped >= 0);
- skippedTotal += skipped;
- if (skipped == 0)
- break;
- }
- _pos += skippedTotal;
- return skippedTotal;
- }
-}
diff --git a/Source/com/drew/metadata/MetadataReader.java b/Source/com/drew/metadata/MetadataReader.java
deleted file mode 100644
index 9459fd351..000000000
--- a/Source/com/drew/metadata/MetadataReader.java
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Copyright 2002-2017 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:
- *
- * https://drewnoakes.com/code/exif/
- * https://github.com/drewnoakes/metadata-extractor
- */
-package com.drew.metadata;
-
-import com.drew.lang.RandomAccessReader;
-import com.drew.lang.annotations.NotNull;
-
-/**
- * Defines an object capable of processing a particular type of metadata from a {@link RandomAccessReader}.
- *
- * Instances of this interface must be thread-safe and reusable.
- *
- * @author Drew Noakes https://drewnoakes.com
- */
-public interface MetadataReader
-{
- /**
- * Extracts metadata from reader
and merges it into the specified {@link Metadata} object.
- *
- * @param reader The {@link RandomAccessReader} from which the metadata should be extracted.
- * @param metadata The {@link Metadata} object into which extracted values should be merged.
- */
- void extract(@NotNull final RandomAccessReader reader, @NotNull final Metadata metadata);
-}
diff --git a/Source/com/drew/metadata/adobe/AdobeJpegReader.java b/Source/com/drew/metadata/adobe/AdobeJpegReader.java
index d5d910150..a2dc4f83f 100644
--- a/Source/com/drew/metadata/adobe/AdobeJpegReader.java
+++ b/Source/com/drew/metadata/adobe/AdobeJpegReader.java
@@ -23,8 +23,9 @@
import com.drew.imaging.jpeg.JpegSegmentMetadataReader;
import com.drew.imaging.jpeg.JpegSegmentType;
-import com.drew.lang.SequentialByteArrayReader;
-import com.drew.lang.SequentialReader;
+import com.drew.imaging.jpeg.JpegSegment;
+import com.drew.lang.Charsets;
+import com.drew.lang.ReaderInfo;
import com.drew.lang.annotations.NotNull;
import com.drew.metadata.Directory;
import com.drew.metadata.Metadata;
@@ -41,7 +42,8 @@
@SuppressWarnings("WeakerAccess")
public class AdobeJpegReader implements JpegSegmentMetadataReader
{
- public static final String PREAMBLE = "Adobe";
+ public static final String JPEG_SEGMENT_ID = "Adobe";
+ public static final String JPEG_SEGMENT_PREAMBLE = "Adobe";
@NotNull
public Iterable getSegmentTypes()
@@ -49,15 +51,15 @@ public Iterable getSegmentTypes()
return Collections.singletonList(JpegSegmentType.APPE);
}
- public void readJpegSegments(@NotNull Iterable segments, @NotNull Metadata metadata, @NotNull JpegSegmentType segmentType)
+ public void readJpegSegments(@NotNull Iterable segments, @NotNull Metadata metadata) throws IOException
{
- for (byte[] bytes : segments) {
- if (bytes.length == 12 && PREAMBLE.equalsIgnoreCase(new String(bytes, 0, PREAMBLE.length())))
- extract(new SequentialByteArrayReader(bytes), metadata);
+ for (JpegSegment segment : segments) {
+ if (segment.getReader().getLength() == 12 && JPEG_SEGMENT_ID.equals(segment.getPreamble()))
+ extract(segment.getReader().Clone(), metadata);
}
}
- public void extract(@NotNull SequentialReader reader, @NotNull Metadata metadata)
+ public void extract(@NotNull ReaderInfo reader, @NotNull Metadata metadata)
{
Directory directory = new AdobeJpegDirectory();
metadata.addDirectory(directory);
@@ -65,7 +67,7 @@ public void extract(@NotNull SequentialReader reader, @NotNull Metadata metadata
try {
reader.setMotorolaByteOrder(false);
- if (!reader.getString(PREAMBLE.length()).equals(PREAMBLE)) {
+ if (!reader.getString(JPEG_SEGMENT_PREAMBLE.length(), Charsets.UTF_8).equals(JPEG_SEGMENT_PREAMBLE)) {
directory.addError("Invalid Adobe JPEG data header.");
return;
}
diff --git a/Source/com/drew/metadata/avi/AviRiffHandler.java b/Source/com/drew/metadata/avi/AviRiffHandler.java
index b528e51fc..b55ad0111 100644
--- a/Source/com/drew/metadata/avi/AviRiffHandler.java
+++ b/Source/com/drew/metadata/avi/AviRiffHandler.java
@@ -21,7 +21,7 @@
package com.drew.metadata.avi;
import com.drew.imaging.riff.RiffHandler;
-import com.drew.lang.ByteArrayReader;
+import com.drew.lang.ReaderInfo;
import com.drew.lang.annotations.NotNull;
import com.drew.metadata.Metadata;
@@ -48,9 +48,6 @@ public class AviRiffHandler implements RiffHandler
@NotNull
private final AviDirectory _directory;
-// @NotNull
-// private String _currentList = "";
-
public AviRiffHandler(@NotNull Metadata metadata)
{
_directory = new AviDirectory();
@@ -80,11 +77,11 @@ public boolean shouldAcceptList(@NotNull String fourCC)
|| fourCC.equals(AviDirectory.FORMAT);
}
- public void processChunk(@NotNull String fourCC, @NotNull byte[] payload)
+ public void processChunk(@NotNull String fourCC, @NotNull ReaderInfo chunkReader)
{
try {
if (fourCC.equals(AviDirectory.CHUNK_STREAM_HEADER)) {
- ByteArrayReader reader = new ByteArrayReader(payload);
+ ReaderInfo reader = chunkReader.Clone();
reader.setMotorolaByteOrder(false);
String fccType = new String(reader.getBytes(0, 4));
@@ -121,7 +118,7 @@ public void processChunk(@NotNull String fourCC, @NotNull byte[] payload)
}
}
} else if (fourCC.equals(AviDirectory.CHUNK_MAIN_HEADER)) {
- ByteArrayReader reader = new ByteArrayReader(payload);
+ ReaderInfo reader = chunkReader.Clone();
reader.setMotorolaByteOrder(false);
// int dwMicroSecPerFrame = reader.getInt32(0);
diff --git a/Source/com/drew/metadata/bmp/BmpReader.java b/Source/com/drew/metadata/bmp/BmpReader.java
index 019f2f7a1..030e30590 100644
--- a/Source/com/drew/metadata/bmp/BmpReader.java
+++ b/Source/com/drew/metadata/bmp/BmpReader.java
@@ -20,9 +20,8 @@
*/
package com.drew.metadata.bmp;
-import com.drew.lang.ByteArrayReader;
import com.drew.lang.Charsets;
-import com.drew.lang.SequentialReader;
+import com.drew.lang.ReaderInfo;
import com.drew.lang.annotations.NotNull;
import com.drew.metadata.Directory;
import com.drew.metadata.ErrorDirectory;
@@ -76,7 +75,7 @@ public class BmpReader
*/
public static final int OS2_POINTER = 0x5450;
- public void extract(@NotNull final SequentialReader reader, final @NotNull Metadata metadata)
+ public void extract(@NotNull final ReaderInfo reader, final @NotNull Metadata metadata)
{
reader.setMotorolaByteOrder(false);
@@ -88,7 +87,7 @@ public void extract(@NotNull final SequentialReader reader, final @NotNull Metad
readFileHeader(reader, metadata, true);
}
- protected void readFileHeader(@NotNull final SequentialReader reader, final @NotNull Metadata metadata, boolean allowArray) {
+ protected void readFileHeader(@NotNull final ReaderInfo reader, final @NotNull Metadata metadata, boolean allowArray) {
/*
* There are two possible headers a file can start with. If the magic
* number is OS/2 Bitmap Array (0x4142) the OS/2 Bitmap Array Header
@@ -136,11 +135,11 @@ protected void readFileHeader(@NotNull final SequentialReader reader, final @Not
if (nextHeaderOffset == 0) {
return; // No more bitmaps
}
- if (reader.getPosition() > nextHeaderOffset) {
+ if (reader.getLocalPosition() > nextHeaderOffset) {
addError("Invalid next header offset", metadata);
return;
}
- reader.skip(nextHeaderOffset - reader.getPosition());
+ reader.skip(nextHeaderOffset - reader.getLocalPosition());
readFileHeader(reader, metadata, true);
break;
case BITMAP:
@@ -153,7 +152,7 @@ protected void readFileHeader(@NotNull final SequentialReader reader, final @Not
directory.setInt(BmpHeaderDirectory.TAG_BITMAP_TYPE, magicNumber);
// skip past the rest of the file header
reader.skip(4 + 2 + 2 + 4);
- readBitmapHeader(reader, (BmpHeaderDirectory) directory, metadata);
+ readBitmapHeader(reader.Clone(), (BmpHeaderDirectory) directory, metadata);
break;
default:
metadata.addDirectory(new ErrorDirectory("Invalid BMP magic number 0x" + Integer.toHexString(magicNumber)));
@@ -168,7 +167,7 @@ protected void readFileHeader(@NotNull final SequentialReader reader, final @Not
}
}
- protected void readBitmapHeader(@NotNull final SequentialReader reader, final @NotNull BmpHeaderDirectory directory, final @NotNull Metadata metadata) {
+ protected void readBitmapHeader(@NotNull final ReaderInfo reader, final @NotNull BmpHeaderDirectory directory, final @NotNull Metadata metadata) {
/*
* BITMAPCOREHEADER (12 bytes):
*
@@ -263,7 +262,7 @@ protected void readBitmapHeader(@NotNull final SequentialReader reader, final @N
try {
int bitmapType = directory.getInt(BmpHeaderDirectory.TAG_BITMAP_TYPE);
- long headerOffset = reader.getPosition();
+ long headerOffset = reader.getLocalPosition();
int headerSize = reader.getInt32();
directory.setInt(BmpHeaderDirectory.TAG_HEADER_SIZE, headerSize);
@@ -362,16 +361,17 @@ protected void readBitmapHeader(@NotNull final SequentialReader reader, final @N
if (csType == ColorSpaceType.PROFILE_EMBEDDED.getValue() || csType == ColorSpaceType.PROFILE_LINKED.getValue()) {
long profileOffset = reader.getUInt32();
int profileSize = reader.getInt32();
- if (reader.getPosition() > headerOffset + profileOffset) {
+ if (reader.getLocalPosition() > headerOffset + profileOffset) {
directory.addError("Invalid profile data offset 0x" + Long.toHexString(headerOffset + profileOffset));
return;
}
- reader.skip(headerOffset + profileOffset - reader.getPosition());
+ reader.skip(headerOffset + profileOffset - reader.getLocalPosition());
if (csType == ColorSpaceType.PROFILE_LINKED.getValue()) {
directory.setString(BmpHeaderDirectory.TAG_LINKED_PROFILE, reader.getNullTerminatedString(profileSize, Charsets.WINDOWS_1252));
} else {
- ByteArrayReader randomAccessReader = new ByteArrayReader(reader.getBytes(profileSize));
- new IccReader().extract(randomAccessReader, metadata, directory);
+ //ByteArrayReader randomAccessReader = new ByteArrayReader(reader.getBytes(profileSize));
+ ReaderInfo iccReader = reader.Clone(profileSize);
+ new IccReader().extract(iccReader, metadata, directory);
}
} else {
reader.skip(
diff --git a/Source/com/drew/metadata/eps/EpsReader.java b/Source/com/drew/metadata/eps/EpsReader.java
index 24d8233c5..031a57192 100644
--- a/Source/com/drew/metadata/eps/EpsReader.java
+++ b/Source/com/drew/metadata/eps/EpsReader.java
@@ -13,7 +13,6 @@
import java.io.ByteArrayOutputStream;
import java.io.IOException;
-import java.io.InputStream;
/**
* Reads file passed in through SequentialReader and parses encountered data:
@@ -48,12 +47,11 @@ public class EpsReader
* data and then set the position to the beginning of the PostScript data. If it does not, the position will not
* be changed. After both scenarios, the main extract method is called.
*
- * @param inputStream InputStream containing file
+ * @param reader ReaderInfo containing file
* @param metadata Metadata to add directory to and extracted data
*/
- public void extract(@NotNull final InputStream inputStream, @NotNull final Metadata metadata) throws IOException
+ public void extract(@NotNull ReaderInfo reader, @NotNull final Metadata metadata) throws IOException
{
- RandomAccessStreamReader reader = new RandomAccessStreamReader(inputStream);
EpsDirectory directory = new EpsDirectory();
metadata.addDirectory(directory);
@@ -62,6 +60,8 @@ public void extract(@NotNull final InputStream inputStream, @NotNull final Metad
*
* 0x25215053 (%!PS) signifies an EPS File and leads straight into the PostScript
*/
+ ReaderInfo origreader = reader.Clone();
+
switch (reader.getInt32(0)) {
case 0xC5D0D3C6:
reader.setMotorolaByteOrder(false);
@@ -79,8 +79,7 @@ public void extract(@NotNull final InputStream inputStream, @NotNull final Metad
directory.setInt(EpsDirectory.TAG_TIFF_PREVIEW_OFFSET, tifOffset);
// Get Tiff metadata
try {
- ByteArrayReader byteArrayReader = new ByteArrayReader(reader.getBytes(tifOffset, tifSize));
- new TiffReader().processTiff(byteArrayReader, new PhotoshopTiffHandler(metadata, null), 0);
+ new TiffReader().processTiff(reader.Clone(tifOffset, tifSize), new PhotoshopTiffHandler(metadata, null));
} catch (TiffProcessingException ex) {
directory.addError("Unable to process TIFF data: " + ex.getMessage());
}
@@ -90,11 +89,10 @@ public void extract(@NotNull final InputStream inputStream, @NotNull final Metad
}
// TODO avoid allocating byte array here -- read directly from InputStream
- extract(directory, metadata, new SequentialByteArrayReader(reader.getBytes(postScriptOffset, postScriptLength)));
+ extract(directory, metadata, reader.Clone(postScriptOffset, postScriptLength));
break;
case 0x25215053:
- inputStream.reset();
- extract(directory, metadata, new StreamReader(inputStream));
+ extract(directory, metadata, origreader);
break;
default:
directory.addError("File type not supported.");
@@ -110,7 +108,8 @@ public void extract(@NotNull final InputStream inputStream, @NotNull final Metad
*
* @param metadata Metadata to add directory to and extracted data
*/
- private void extract(@NotNull final EpsDirectory directory, @NotNull Metadata metadata, @NotNull SequentialReader reader) throws IOException
+ //private void extract(@NotNull final EpsDirectory directory, @NotNull Metadata metadata, @NotNull SequentialReader reader) throws IOException
+ private void extract(@NotNull final EpsDirectory directory, @NotNull Metadata metadata, @NotNull ReaderInfo reader) throws IOException
{
StringBuilder line = new StringBuilder();
@@ -229,29 +228,29 @@ else if (colorType == 4)
/**
* Decodes a commented hex section, and uses {@link PhotoshopReader} to decode the resulting data.
*/
- private static void extractPhotoshopData(@NotNull final Metadata metadata, @NotNull SequentialReader reader) throws IOException
+ private static void extractPhotoshopData(@NotNull final Metadata metadata, @NotNull ReaderInfo reader) throws IOException
{
byte[] buffer = decodeHexCommentBlock(reader);
if (buffer != null)
- new PhotoshopReader().extract(new SequentialByteArrayReader(buffer), buffer.length, metadata);
+ new PhotoshopReader().extract(ReaderInfo.createFromArray(buffer), metadata);
}
/**
* Decodes a commented hex section, and uses {@link IccReader} to decode the resulting data.
*/
- private static void extractIccData(@NotNull final Metadata metadata, @NotNull SequentialReader reader) throws IOException
+ private static void extractIccData(@NotNull final Metadata metadata, @NotNull ReaderInfo reader) throws IOException
{
byte[] buffer = decodeHexCommentBlock(reader);
if (buffer != null)
- new IccReader().extract(new ByteArrayReader(buffer), metadata);
+ new IccReader().extract(ReaderInfo.createFromArray(buffer), metadata);
}
/**
* Extracts an XMP xpacket, and uses {@link XmpReader} to decode the resulting data.
*/
- private static void extractXmpData(@NotNull final Metadata metadata, @NotNull SequentialReader reader) throws IOException
+ private static void extractXmpData(@NotNull final Metadata metadata, @NotNull ReaderInfo reader) throws IOException
{
byte[] bytes = readUntil(reader, "".getBytes());
String xmp = new String(bytes, Charsets.UTF_8);
@@ -262,7 +261,7 @@ private static void extractXmpData(@NotNull final Metadata metadata, @NotNull Se
* Reads all bytes until the given sentinel is observed.
* The sentinel will be included in the returned bytes.
*/
- private static byte[] readUntil(@NotNull SequentialReader reader, @NotNull byte[] sentinel) throws IOException
+ private static byte[] readUntil(@NotNull ReaderInfo reader, @NotNull byte[] sentinel) throws IOException
{
ByteArrayOutputStream bytes = new ByteArrayOutputStream();
@@ -301,7 +300,7 @@ private static byte[] readUntil(@NotNull SequentialReader reader, @NotNull byte[
* @return The decoded bytes, or null
if decoding failed.
*/
@Nullable
- private static byte[] decodeHexCommentBlock(@NotNull SequentialReader reader) throws IOException
+ private static byte[] decodeHexCommentBlock(@NotNull ReaderInfo reader) throws IOException
{
ByteArrayOutputStream bytes = new ByteArrayOutputStream();
diff --git a/Source/com/drew/metadata/exif/ExifDescriptorBase.java b/Source/com/drew/metadata/exif/ExifDescriptorBase.java
index 45d2e2d33..4f2243966 100644
--- a/Source/com/drew/metadata/exif/ExifDescriptorBase.java
+++ b/Source/com/drew/metadata/exif/ExifDescriptorBase.java
@@ -25,7 +25,7 @@
import com.drew.lang.Rational;
import com.drew.lang.annotations.NotNull;
import com.drew.lang.annotations.Nullable;
-import com.drew.lang.ByteArrayReader;
+import com.drew.lang.ReaderInfo;
import com.drew.metadata.Directory;
import com.drew.metadata.TagDescriptor;
@@ -1139,7 +1139,7 @@ private int[] decodeCfaPattern(int tagType)
ret = new int[values.length - 2];
try {
- ByteArrayReader reader = new ByteArrayReader(values);
+ ReaderInfo reader = ReaderInfo.createFromArray(values);
// first two values should be read as 16-bits (2 bytes)
short item0 = reader.getInt16(0);
diff --git a/Source/com/drew/metadata/exif/ExifReader.java b/Source/com/drew/metadata/exif/ExifReader.java
index ffc77c67c..3c143bc71 100644
--- a/Source/com/drew/metadata/exif/ExifReader.java
+++ b/Source/com/drew/metadata/exif/ExifReader.java
@@ -22,10 +22,10 @@
import com.drew.imaging.jpeg.JpegSegmentMetadataReader;
import com.drew.imaging.jpeg.JpegSegmentType;
+import com.drew.imaging.jpeg.JpegSegment;
import com.drew.imaging.tiff.TiffProcessingException;
import com.drew.imaging.tiff.TiffReader;
-import com.drew.lang.ByteArrayReader;
-import com.drew.lang.RandomAccessReader;
+import com.drew.lang.ReaderInfo;
import com.drew.lang.annotations.NotNull;
import com.drew.lang.annotations.Nullable;
import com.drew.metadata.Directory;
@@ -44,6 +44,7 @@
@SuppressWarnings("WeakerAccess")
public class ExifReader implements JpegSegmentMetadataReader
{
+ public static final String JPEG_SEGMENT_ID = "Exif";
/** Exif data stored in JPEG files' APP1 segment are preceded by this six character preamble. */
public static final String JPEG_SEGMENT_PREAMBLE = "Exif\0\0";
@@ -53,41 +54,33 @@ public Iterable getSegmentTypes()
return Collections.singletonList(JpegSegmentType.APP1);
}
- public void readJpegSegments(@NotNull final Iterable segments, @NotNull final Metadata metadata, @NotNull final JpegSegmentType segmentType)
+ @Override
+ public void readJpegSegments(@NotNull final Iterable segments, @NotNull final Metadata metadata) throws IOException
{
- assert(segmentType == JpegSegmentType.APP1);
-
- for (byte[] segmentBytes : segments) {
+ //assert(segmentType == JpegSegmentType.APP1);
+ for (JpegSegment segment : segments) {
// Filter any segments containing unexpected preambles
- if (segmentBytes.length < JPEG_SEGMENT_PREAMBLE.length() || !new String(segmentBytes, 0, JPEG_SEGMENT_PREAMBLE.length()).equals(JPEG_SEGMENT_PREAMBLE))
- continue;
- extract(new ByteArrayReader(segmentBytes), metadata, JPEG_SEGMENT_PREAMBLE.length());
+ if (segment.getReader().getLength() >= JPEG_SEGMENT_PREAMBLE.length() && JPEG_SEGMENT_ID.equals(segment.getPreamble()))
+ extract(segment.getReader().Clone(JPEG_SEGMENT_PREAMBLE.length(), segment.getReader().getLength() - JPEG_SEGMENT_PREAMBLE.length()), metadata);
}
}
- /** Reads TIFF formatted Exif data from start of the specified {@link RandomAccessReader}. */
- public void extract(@NotNull final RandomAccessReader reader, @NotNull final Metadata metadata)
- {
- extract(reader, metadata, 0);
- }
-
- /** Reads TIFF formatted Exif data a specified offset within a {@link RandomAccessReader}. */
- public void extract(@NotNull final RandomAccessReader reader, @NotNull final Metadata metadata, int readerOffset)
+ /** Reads TIFF formatted Exif data within a {@link ReaderInfo}. */
+ public void extract(@NotNull final ReaderInfo reader, @NotNull final Metadata metadata)
{
- extract(reader, metadata, readerOffset, null);
+ extract(reader, metadata, null);
}
- /** Reads TIFF formatted Exif data at a specified offset within a {@link RandomAccessReader}. */
- public void extract(@NotNull final RandomAccessReader reader, @NotNull final Metadata metadata, int readerOffset, @Nullable Directory parentDirectory)
+ /** Reads TIFF formatted Exif data within a {@link ReaderInfo}. */
+ public void extract(@NotNull ReaderInfo reader, @NotNull final Metadata metadata, @Nullable Directory parentDirectory)
{
ExifTiffHandler exifTiffHandler = new ExifTiffHandler(metadata, parentDirectory);
try {
// Read the TIFF-formatted Exif data
new TiffReader().processTiff(
- reader,
- exifTiffHandler,
- readerOffset
+ reader,
+ exifTiffHandler
);
} catch (TiffProcessingException e) {
exifTiffHandler.error("Exception processing TIFF data: " + e.getMessage());
diff --git a/Source/com/drew/metadata/exif/ExifTiffHandler.java b/Source/com/drew/metadata/exif/ExifTiffHandler.java
index 04f66ec95..623dea443 100644
--- a/Source/com/drew/metadata/exif/ExifTiffHandler.java
+++ b/Source/com/drew/metadata/exif/ExifTiffHandler.java
@@ -25,10 +25,8 @@
import com.drew.imaging.jpeg.JpegMetadataReader;
import com.drew.imaging.jpeg.JpegProcessingException;
import com.drew.lang.BufferBoundsException;
-import com.drew.lang.ByteArrayReader;
import com.drew.lang.Charsets;
-import com.drew.lang.RandomAccessReader;
-import com.drew.lang.SequentialByteArrayReader;
+import com.drew.lang.ReaderInfo;
import com.drew.lang.annotations.NotNull;
import com.drew.lang.annotations.Nullable;
import com.drew.metadata.Directory;
@@ -41,10 +39,10 @@
import com.drew.metadata.tiff.DirectoryTiffHandler;
import com.drew.metadata.xmp.XmpReader;
-import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.util.Arrays;
import java.util.Set;
+//import javax.xml.parsers.DocumentBuilderFactory;
/**
* Implementation of {@link com.drew.imaging.tiff.TiffHandler} used for handling TIFF tags according to the Exif
@@ -61,6 +59,7 @@ public ExifTiffHandler(@NotNull Metadata metadata, @Nullable Directory parentDir
super(metadata, parentDirectory);
}
+ @Override
public void setTiffMarker(int marker) throws TiffProcessingException
{
final int standardTiffMarker = 0x002A;
@@ -82,6 +81,7 @@ public void setTiffMarker(int marker) throws TiffProcessingException
}
}
+ @Override
public boolean tryEnterSubIfd(int tagId)
{
if (tagId == ExifDirectoryBase.TAG_SUB_IFD_OFFSET) {
@@ -142,6 +142,7 @@ public boolean tryEnterSubIfd(int tagId)
return false;
}
+ @Override
public boolean hasFollowerIfd()
{
// In Exif, the only known 'follower' IFD is the thumbnail one, however this may not be the case.
@@ -166,6 +167,7 @@ public boolean hasFollowerIfd()
}
@Nullable
+ @Override
public Long tryCustomProcessFormat(final int tagId, final int formatCode, final long componentCount)
{
if (formatCode == 13)
@@ -178,10 +180,10 @@ public Long tryCustomProcessFormat(final int tagId, final int formatCode, final
return null;
}
+ @Override
public boolean customProcessTag(final int tagOffset,
- final @NotNull Set processedIfdOffsets,
- final int tiffHeaderOffset,
- final @NotNull RandomAccessReader reader,
+ final @NotNull Set processedIfdOffsets,
+ @NotNull ReaderInfo reader,
final int tagId,
final int byteCount) throws IOException
{
@@ -201,15 +203,14 @@ public boolean customProcessTag(final int tagOffset,
// Custom processing for the Makernote tag
if (tagId == ExifSubIFDDirectory.TAG_MAKERNOTE && _currentDirectory instanceof ExifSubIFDDirectory) {
- return processMakernote(tagOffset, processedIfdOffsets, tiffHeaderOffset, reader);
+ return processMakernote(tagOffset, processedIfdOffsets, reader.Clone(tagOffset, -1));
}
// Custom processing for embedded IPTC data
if (tagId == ExifSubIFDDirectory.TAG_IPTC_NAA && _currentDirectory instanceof ExifIFD0Directory) {
// NOTE Adobe sets type 4 for IPTC instead of 7
if (reader.getInt8(tagOffset) == 0x1c) {
- final byte[] iptcBytes = reader.getBytes(tagOffset, byteCount);
- new IptcReader().extract(new SequentialByteArrayReader(iptcBytes), _metadata, iptcBytes.length, _currentDirectory);
+ new IptcReader().extract(reader.Clone(tagOffset, byteCount), _metadata, _currentDirectory);
return true;
}
return false;
@@ -217,20 +218,18 @@ public boolean customProcessTag(final int tagOffset,
// Custom processing for ICC Profile data
if (tagId == ExifSubIFDDirectory.TAG_INTER_COLOR_PROFILE) {
- final byte[] iccBytes = reader.getBytes(tagOffset, byteCount);
- new IccReader().extract(new ByteArrayReader(iccBytes), _metadata);
+ new IccReader().extract(reader.Clone(tagOffset, byteCount), _metadata);
return true;
}
// Custom processing for Photoshop data
if (tagId == ExifSubIFDDirectory.TAG_PHOTOSHOP_SETTINGS && _currentDirectory instanceof ExifIFD0Directory) {
- final byte[] photoshopBytes = reader.getBytes(tagOffset, byteCount);
- new PhotoshopReader().extract(new SequentialByteArrayReader(photoshopBytes), byteCount, _metadata);
+ new PhotoshopReader().extract(reader.Clone(tagOffset, byteCount), _metadata);
return true;
}
// Custom processing for embedded XMP data
- if (tagId == ExifSubIFDDirectory.TAG_APPLICATION_NOTES && _currentDirectory instanceof ExifIFD0Directory) {
+ if (tagId == ExifSubIFDDirectory.TAG_APPLICATION_NOTES && _currentDirectory instanceof ExifIFD0Directory) {
new XmpReader().extract(reader.getNullTerminatedBytes(tagOffset, byteCount), _metadata, _currentDirectory);
return true;
}
@@ -250,35 +249,35 @@ public boolean customProcessTag(final int tagOffset,
switch (tagId) {
case OlympusMakernoteDirectory.TAG_EQUIPMENT:
pushDirectory(OlympusEquipmentMakernoteDirectory.class);
- TiffReader.processIfd(this, reader, processedIfdOffsets, tagOffset, tiffHeaderOffset);
+ TiffReader.processIfd(this, reader, processedIfdOffsets, tagOffset);
return true;
case OlympusMakernoteDirectory.TAG_CAMERA_SETTINGS:
pushDirectory(OlympusCameraSettingsMakernoteDirectory.class);
- TiffReader.processIfd(this, reader, processedIfdOffsets, tagOffset, tiffHeaderOffset);
+ TiffReader.processIfd(this, reader, processedIfdOffsets, tagOffset);
return true;
case OlympusMakernoteDirectory.TAG_RAW_DEVELOPMENT:
pushDirectory(OlympusRawDevelopmentMakernoteDirectory.class);
- TiffReader.processIfd(this, reader, processedIfdOffsets, tagOffset, tiffHeaderOffset);
+ TiffReader.processIfd(this, reader, processedIfdOffsets, tagOffset);
return true;
case OlympusMakernoteDirectory.TAG_RAW_DEVELOPMENT_2:
pushDirectory(OlympusRawDevelopment2MakernoteDirectory.class);
- TiffReader.processIfd(this, reader, processedIfdOffsets, tagOffset, tiffHeaderOffset);
+ TiffReader.processIfd(this, reader, processedIfdOffsets, tagOffset);
return true;
case OlympusMakernoteDirectory.TAG_IMAGE_PROCESSING:
pushDirectory(OlympusImageProcessingMakernoteDirectory.class);
- TiffReader.processIfd(this, reader, processedIfdOffsets, tagOffset, tiffHeaderOffset);
+ TiffReader.processIfd(this, reader, processedIfdOffsets, tagOffset);
return true;
case OlympusMakernoteDirectory.TAG_FOCUS_INFO:
pushDirectory(OlympusFocusInfoMakernoteDirectory.class);
- TiffReader.processIfd(this, reader, processedIfdOffsets, tagOffset, tiffHeaderOffset);
+ TiffReader.processIfd(this, reader, processedIfdOffsets, tagOffset);
return true;
case OlympusMakernoteDirectory.TAG_RAW_INFO:
pushDirectory(OlympusRawInfoMakernoteDirectory.class);
- TiffReader.processIfd(this, reader, processedIfdOffsets, tagOffset, tiffHeaderOffset);
+ TiffReader.processIfd(this, reader, processedIfdOffsets, tagOffset);
return true;
case OlympusMakernoteDirectory.TAG_MAIN_INFO:
pushDirectory(OlympusMakernoteDirectory.class);
- TiffReader.processIfd(this, reader, processedIfdOffsets, tagOffset, tiffHeaderOffset);
+ TiffReader.processIfd(this, reader, processedIfdOffsets, tagOffset);
return true;
}
}
@@ -310,12 +309,13 @@ public boolean customProcessTag(final int tagOffset,
// Panasonic RAW sometimes contains an embedded version of the data as a JPG file.
if (tagId == PanasonicRawIFD0Directory.TagJpgFromRaw && _currentDirectory instanceof PanasonicRawIFD0Directory) {
- byte[] jpegrawbytes = reader.getBytes(tagOffset, byteCount);
+ ReaderInfo jpgreader = reader.Clone(tagOffset, byteCount);
+ jpgreader.setMotorolaByteOrder(true);
// Extract information from embedded image since it is metadata-rich
- ByteArrayInputStream jpegmem = new ByteArrayInputStream(jpegrawbytes);
+
try {
- Metadata jpegDirectory = JpegMetadataReader.readMetadata(jpegmem);
+ Metadata jpegDirectory = JpegMetadataReader.readMetadata(jpgreader); //jpegmem);
for (Directory directory : jpegDirectory.getDirectories()) {
directory.setParent(_currentDirectory);
_metadata.addDirectory(directory);
@@ -331,7 +331,7 @@ public boolean customProcessTag(final int tagOffset,
return false;
}
- private static void processBinary(@NotNull final Directory directory, final int tagValueOffset, @NotNull final RandomAccessReader reader, final int byteCount, final Boolean isSigned, final int arrayLength) throws IOException
+ private static void processBinary(@NotNull final Directory directory, final int tagValueOffset, @NotNull final ReaderInfo reader, final int byteCount, final Boolean isSigned, final int arrayLength) throws IOException
{
// expects signed/unsigned int16 (for now)
//int byteSize = isSigned ? sizeof(short) : sizeof(ushort);
@@ -377,19 +377,18 @@ private static void processBinary(@NotNull final Directory directory, final int
* a full-on failure.
*/
@NotNull
- private static String getReaderString(final @NotNull RandomAccessReader reader, final int makernoteOffset, final int bytesRequested) throws IOException
+ private static String getReaderString(final @NotNull ReaderInfo reader, final int bytesRequested) throws IOException
{
try {
- return reader.getString(makernoteOffset, bytesRequested, Charsets.UTF_8);
+ return reader.getString(0, bytesRequested, Charsets.UTF_8);
} catch(BufferBoundsException e) {
return "";
}
}
private boolean processMakernote(final int makernoteOffset,
- final @NotNull Set processedIfdOffsets,
- final int tiffHeaderOffset,
- final @NotNull RandomAccessReader reader) throws IOException
+ final @NotNull Set processedIfdOffsets,
+ @NotNull ReaderInfo reader) throws IOException
{
assert(_currentDirectory != null);
@@ -398,35 +397,33 @@ private boolean processMakernote(final int makernoteOffset,
String cameraMake = ifd0Directory == null ? null : ifd0Directory.getString(ExifIFD0Directory.TAG_MAKE);
- final String firstTwoChars = getReaderString(reader, makernoteOffset, 2);
- final String firstThreeChars = getReaderString(reader, makernoteOffset, 3);
- final String firstFourChars = getReaderString(reader, makernoteOffset, 4);
- final String firstFiveChars = getReaderString(reader, makernoteOffset, 5);
- final String firstSixChars = getReaderString(reader, makernoteOffset, 6);
- final String firstSevenChars = getReaderString(reader, makernoteOffset, 7);
- final String firstEightChars = getReaderString(reader, makernoteOffset, 8);
- final String firstNineChars = getReaderString(reader, makernoteOffset, 9);
- final String firstTenChars = getReaderString(reader, makernoteOffset, 10);
- final String firstTwelveChars = getReaderString(reader, makernoteOffset, 12);
-
- boolean byteOrderBefore = reader.isMotorolaByteOrder();
+ final String firstTwoChars = getReaderString(reader, 2);
+ final String firstThreeChars = getReaderString(reader, 3);
+ final String firstFourChars = getReaderString(reader, 4);
+ final String firstFiveChars = getReaderString(reader, 5);
+ final String firstSixChars = getReaderString(reader, 6);
+ final String firstSevenChars = getReaderString(reader, 7);
+ final String firstEightChars = getReaderString(reader, 8);
+ final String firstNineChars = getReaderString(reader, 9);
+ final String firstTenChars = getReaderString(reader, 10);
+ final String firstTwelveChars = getReaderString(reader, 12);
if ("OLYMP\0".equals(firstSixChars) || "EPSON".equals(firstFiveChars) || "AGFA".equals(firstFourChars)) {
// Olympus Makernote
// Epson and Agfa use Olympus makernote standard: http://www.ozhiker.com/electronics/pjmt/jpeg_info/
pushDirectory(OlympusMakernoteDirectory.class);
- TiffReader.processIfd(this, reader, processedIfdOffsets, makernoteOffset + 8, tiffHeaderOffset);
+ TiffReader.processIfd(this, reader.Clone(-makernoteOffset, -1), processedIfdOffsets, makernoteOffset + 8);
} else if ("OLYMPUS\0II".equals(firstTenChars)) {
// Olympus Makernote (alternate)
// Note that data is relative to the beginning of the makernote
// http://exiv2.org/makernote.html
pushDirectory(OlympusMakernoteDirectory.class);
- TiffReader.processIfd(this, reader, processedIfdOffsets, makernoteOffset + 12, makernoteOffset);
+ TiffReader.processIfd(this, reader, processedIfdOffsets, 12);
} else if (cameraMake != null && cameraMake.toUpperCase().startsWith("MINOLTA")) {
// Cases seen with the model starting with MINOLTA in capitals seem to have a valid Olympus makernote
// area that commences immediately.
pushDirectory(OlympusMakernoteDirectory.class);
- TiffReader.processIfd(this, reader, processedIfdOffsets, makernoteOffset, tiffHeaderOffset);
+ TiffReader.processIfd(this, reader.Clone(-makernoteOffset, -1), processedIfdOffsets, makernoteOffset);
} else if (cameraMake != null && cameraMake.trim().toUpperCase().startsWith("NIKON")) {
if ("Nikon".equals(firstFiveChars)) {
/* There are two scenarios here:
@@ -437,14 +434,14 @@ private boolean processMakernote(final int makernoteOffset,
* :0000: 4E 69 6B 6F 6E 00 02 00-00 00 4D 4D 00 2A 00 00 Nikon....MM.*...
* :0010: 00 08 00 1E 00 01 00 07-00 00 00 04 30 32 30 30 ............0200
*/
- switch (reader.getUInt8(makernoteOffset + 6)) {
+ switch (reader.getUInt8(6)) {
case 1:
pushDirectory(NikonType1MakernoteDirectory.class);
- TiffReader.processIfd(this, reader, processedIfdOffsets, makernoteOffset + 8, tiffHeaderOffset);
+ TiffReader.processIfd(this, reader.Clone(-makernoteOffset, -1), processedIfdOffsets, makernoteOffset + 8);
break;
case 2:
pushDirectory(NikonType2MakernoteDirectory.class);
- TiffReader.processIfd(this, reader, processedIfdOffsets, makernoteOffset + 18, makernoteOffset + 10);
+ TiffReader.processIfd(this, reader.Clone(10, -1), processedIfdOffsets, 8);
break;
default:
_currentDirectory.addError("Unsupported Nikon makernote data ignored.");
@@ -453,41 +450,41 @@ private boolean processMakernote(final int makernoteOffset,
} else {
// The IFD begins with the first Makernote byte (no ASCII name). This occurs with CoolPix 775, E990 and D1 models.
pushDirectory(NikonType2MakernoteDirectory.class);
- TiffReader.processIfd(this, reader, processedIfdOffsets, makernoteOffset, tiffHeaderOffset);
+ TiffReader.processIfd(this, reader.Clone(-makernoteOffset, -1), processedIfdOffsets, makernoteOffset);
}
} else if ("SONY CAM".equals(firstEightChars) || "SONY DSC".equals(firstEightChars)) {
pushDirectory(SonyType1MakernoteDirectory.class);
- TiffReader.processIfd(this, reader, processedIfdOffsets, makernoteOffset + 12, tiffHeaderOffset);
+ TiffReader.processIfd(this, reader.Clone(-makernoteOffset, -1), processedIfdOffsets, makernoteOffset + 12);
// Do this check LAST after most other Sony checks
} else if (cameraMake != null && cameraMake.startsWith("SONY") &&
- !Arrays.equals(reader.getBytes(makernoteOffset, 2), new byte[]{ 0x01, 0x00 }) ) {
+ !Arrays.equals(reader.getBytes(0, 2), new byte[]{ 0x01, 0x00 }) ) {
// The IFD begins with the first Makernote byte (no ASCII name). Used in SR2 and ARW images
pushDirectory(SonyType1MakernoteDirectory.class);
- TiffReader.processIfd(this, reader, processedIfdOffsets, makernoteOffset, tiffHeaderOffset);
+ TiffReader.processIfd(this, reader.Clone(-makernoteOffset, -1), processedIfdOffsets, makernoteOffset);
} else if ("SEMC MS\u0000\u0000\u0000\u0000\u0000".equals(firstTwelveChars)) {
// force MM for this directory
reader.setMotorolaByteOrder(true);
// skip 12 byte header + 2 for "MM" + 6
pushDirectory(SonyType6MakernoteDirectory.class);
- TiffReader.processIfd(this, reader, processedIfdOffsets, makernoteOffset + 20, tiffHeaderOffset);
+ TiffReader.processIfd(this, reader.Clone(-makernoteOffset, -1), processedIfdOffsets, makernoteOffset + 20);
} else if ("SIGMA\u0000\u0000\u0000".equals(firstEightChars) || "FOVEON\u0000\u0000".equals(firstEightChars)) {
pushDirectory(SigmaMakernoteDirectory.class);
- TiffReader.processIfd(this, reader, processedIfdOffsets, makernoteOffset + 10, tiffHeaderOffset);
+ TiffReader.processIfd(this, reader.Clone(-makernoteOffset, -1), processedIfdOffsets, makernoteOffset + 10);
} else if ("KDK".equals(firstThreeChars)) {
reader.setMotorolaByteOrder(firstSevenChars.equals("KDK INFO"));
KodakMakernoteDirectory directory = new KodakMakernoteDirectory();
_metadata.addDirectory(directory);
- processKodakMakernote(directory, makernoteOffset, reader);
+ processKodakMakernote(directory, makernoteOffset, reader.Clone(-makernoteOffset, -1));
} else if ("Canon".equalsIgnoreCase(cameraMake)) {
pushDirectory(CanonMakernoteDirectory.class);
- TiffReader.processIfd(this, reader, processedIfdOffsets, makernoteOffset, tiffHeaderOffset);
+ TiffReader.processIfd(this, reader.Clone(-makernoteOffset, -1), processedIfdOffsets, makernoteOffset);
} else if (cameraMake != null && cameraMake.toUpperCase().startsWith("CASIO")) {
if ("QVC\u0000\u0000\u0000".equals(firstSixChars)) {
pushDirectory(CasioType2MakernoteDirectory.class);
- TiffReader.processIfd(this, reader, processedIfdOffsets, makernoteOffset + 6, tiffHeaderOffset);
+ TiffReader.processIfd(this, reader.Clone(-makernoteOffset, -1), processedIfdOffsets, makernoteOffset + 6);
} else {
pushDirectory(CasioType1MakernoteDirectory.class);
- TiffReader.processIfd(this, reader, processedIfdOffsets, makernoteOffset, tiffHeaderOffset);
+ TiffReader.processIfd(this, reader.Clone(-makernoteOffset, -1), processedIfdOffsets, makernoteOffset);
}
} else if ("FUJIFILM".equals(firstEightChars) || "Fujifilm".equalsIgnoreCase(cameraMake)) {
// Note that this also applies to certain Leica cameras, such as the Digilux-4.3
@@ -495,13 +492,13 @@ private boolean processMakernote(final int makernoteOffset,
// the 4 bytes after "FUJIFILM" in the makernote point to the start of the makernote
// IFD, though the offset is relative to the start of the makernote, not the TIFF
// header (like everywhere else)
- int ifdStart = makernoteOffset + reader.getInt32(makernoteOffset + 8);
+ int ifdStart = reader.getInt32(8);
pushDirectory(FujifilmMakernoteDirectory.class);
- TiffReader.processIfd(this, reader, processedIfdOffsets, ifdStart, makernoteOffset);
+ TiffReader.processIfd(this, reader, processedIfdOffsets, ifdStart);
} else if ("KYOCERA".equals(firstSevenChars)) {
// http://www.ozhiker.com/electronics/pjmt/jpeg_info/kyocera_mn.html
pushDirectory(KyoceraMakernoteDirectory.class);
- TiffReader.processIfd(this, reader, processedIfdOffsets, makernoteOffset + 22, tiffHeaderOffset);
+ TiffReader.processIfd(this, reader, processedIfdOffsets, 22);
} else if ("LEICA".equals(firstFiveChars)) {
reader.setMotorolaByteOrder(false);
@@ -519,14 +516,14 @@ private boolean processMakernote(final int makernoteOffset,
"LEICA\0\u0007\0".equals(firstEightChars))
{
pushDirectory(LeicaType5MakernoteDirectory.class);
- TiffReader.processIfd(this, reader, processedIfdOffsets, makernoteOffset + 8, makernoteOffset);
+ TiffReader.processIfd(this, reader, processedIfdOffsets, 8);
} else if ("Leica Camera AG".equals(cameraMake)) {
pushDirectory(LeicaMakernoteDirectory.class);
- TiffReader.processIfd(this, reader, processedIfdOffsets, makernoteOffset + 8, tiffHeaderOffset);
+ TiffReader.processIfd(this, reader.Clone(-makernoteOffset, -1), processedIfdOffsets, makernoteOffset + 8);
} else if ("LEICA".equals(cameraMake)) {
// Some Leica cameras use Panasonic makernote tags
pushDirectory(PanasonicMakernoteDirectory.class);
- TiffReader.processIfd(this, reader, processedIfdOffsets, makernoteOffset + 8, tiffHeaderOffset);
+ TiffReader.processIfd(this, reader.Clone(-makernoteOffset, -1), processedIfdOffsets, makernoteOffset + 8);
} else {
return false;
}
@@ -535,7 +532,7 @@ private boolean processMakernote(final int makernoteOffset,
// Offsets are relative to the start of the TIFF header at the beginning of the EXIF segment
// more information here: http://www.ozhiker.com/electronics/pjmt/jpeg_info/panasonic_mn.html
pushDirectory(PanasonicMakernoteDirectory.class);
- TiffReader.processIfd(this, reader, processedIfdOffsets, makernoteOffset + 12, tiffHeaderOffset);
+ TiffReader.processIfd(this, reader.Clone(-makernoteOffset, -1), processedIfdOffsets, makernoteOffset + 12);
} else if ("AOC\u0000".equals(firstFourChars)) {
// NON-Standard TIFF IFD Data using Casio Type 2 Tags
// IFD has no Next-IFD pointer at end of IFD, and
@@ -543,7 +540,7 @@ private boolean processMakernote(final int makernoteOffset,
// Observed for:
// - Pentax ist D
pushDirectory(CasioType2MakernoteDirectory.class);
- TiffReader.processIfd(this, reader, processedIfdOffsets, makernoteOffset + 6, makernoteOffset);
+ TiffReader.processIfd(this, reader, processedIfdOffsets, 6);
} else if (cameraMake != null && (cameraMake.toUpperCase().startsWith("PENTAX") || cameraMake.toUpperCase().startsWith("ASAHI"))) {
// NON-Standard TIFF IFD Data using Pentax Tags
// IFD has no Next-IFD pointer at end of IFD, and
@@ -552,7 +549,7 @@ private boolean processMakernote(final int makernoteOffset,
// - PENTAX Optio 330
// - PENTAX Optio 430
pushDirectory(PentaxMakernoteDirectory.class);
- TiffReader.processIfd(this, reader, processedIfdOffsets, makernoteOffset, makernoteOffset);
+ TiffReader.processIfd(this, reader, processedIfdOffsets, 0);
// } else if ("KC".equals(firstTwoChars) || "MINOL".equals(firstFiveChars) || "MLY".equals(firstThreeChars) || "+M+M+M+M".equals(firstEightChars)) {
// // This Konica data is not understood. Header identified in accordance with information at this site:
// // http://www.ozhiker.com/electronics/pjmt/jpeg_info/minolta_mn.html
@@ -560,7 +557,7 @@ private boolean processMakernote(final int makernoteOffset,
// exifDirectory.addError("Unsupported Konica/Minolta data ignored.");
} else if ("SANYO\0\1\0".equals(firstEightChars)) {
pushDirectory(SanyoMakernoteDirectory.class);
- TiffReader.processIfd(this, reader, processedIfdOffsets, makernoteOffset + 8, makernoteOffset);
+ TiffReader.processIfd(this, reader, processedIfdOffsets, 8);
} else if (cameraMake != null && cameraMake.toLowerCase().startsWith("ricoh")) {
if (firstTwoChars.equals("Rv") || firstThreeChars.equals("Rev")) {
// This is a textual format, where the makernote bytes look like:
@@ -573,34 +570,33 @@ private boolean processMakernote(final int makernoteOffset,
// Always in Motorola byte order
reader.setMotorolaByteOrder(true);
pushDirectory(RicohMakernoteDirectory.class);
- TiffReader.processIfd(this, reader, processedIfdOffsets, makernoteOffset + 8, makernoteOffset);
+ TiffReader.processIfd(this, reader, processedIfdOffsets, 8);
}
} else if (firstTenChars.equals("Apple iOS\0")) {
// Always in Motorola byte order
boolean orderBefore = reader.isMotorolaByteOrder();
reader.setMotorolaByteOrder(true);
pushDirectory(AppleMakernoteDirectory.class);
- TiffReader.processIfd(this, reader, processedIfdOffsets, makernoteOffset + 14, makernoteOffset);
+ TiffReader.processIfd(this, reader, processedIfdOffsets, 14);
reader.setMotorolaByteOrder(orderBefore);
- } else if (reader.getUInt16(makernoteOffset) == ReconyxHyperFireMakernoteDirectory.MAKERNOTE_VERSION) {
+ } else if (reader.getUInt16(0) == ReconyxHyperFireMakernoteDirectory.MAKERNOTE_VERSION) {
ReconyxHyperFireMakernoteDirectory directory = new ReconyxHyperFireMakernoteDirectory();
_metadata.addDirectory(directory);
- processReconyxHyperFireMakernote(directory, makernoteOffset, reader);
+ processReconyxHyperFireMakernote(directory, makernoteOffset, reader.Clone(-makernoteOffset, -1));
} else if (firstNineChars.equalsIgnoreCase("RECONYXUF")) {
ReconyxUltraFireMakernoteDirectory directory = new ReconyxUltraFireMakernoteDirectory();
_metadata.addDirectory(directory);
- processReconyxUltraFireMakernote(directory, makernoteOffset, reader);
+ processReconyxUltraFireMakernote(directory, makernoteOffset, reader.Clone(-makernoteOffset, -1));
} else if ("SAMSUNG".equals(cameraMake)) {
// Only handles Type2 notes correctly. Others aren't implemented, and it's complex to determine which ones to use
pushDirectory(SamsungType2MakernoteDirectory.class);
- TiffReader.processIfd(this, reader, processedIfdOffsets, makernoteOffset, tiffHeaderOffset);
+ TiffReader.processIfd(this, reader.Clone(-makernoteOffset, -1), processedIfdOffsets, makernoteOffset);
} else {
// The makernote is not comprehended by this library.
// If you are reading this and believe a particular camera's image should be processed, get in touch.
return false;
}
- reader.setMotorolaByteOrder(byteOrderBefore);
return true;
}
@@ -634,9 +630,9 @@ private static boolean handlePrintIM(@NotNull final Directory directory, final i
/// http://www.sno.phy.queensu.ca/~phil/exiftool/
/// lib\Image\ExifTool\PrintIM.pm
///
- private static void processPrintIM(@NotNull final PrintIMDirectory directory, final int tagValueOffset, @NotNull final RandomAccessReader reader, final int byteCount) throws IOException
+ private static void processPrintIM(@NotNull final PrintIMDirectory directory, final int tagValueOffset, @NotNull final ReaderInfo reader, final int byteCount) throws IOException
{
- Boolean resetByteOrder = null;
+ //Boolean resetByteOrder = null;
if (byteCount == 0) {
directory.addError("Empty PrintIM data");
@@ -655,14 +651,14 @@ private static void processPrintIM(@NotNull final PrintIMDirectory directory, fi
return;
}
+ ReaderInfo localReader = reader;
// check size of PrintIM block
- int num = reader.getUInt16(tagValueOffset + 14);
-
+ int num = localReader.getUInt16(tagValueOffset + 14);
if (byteCount < 16 + num * 6) {
// size is too big, maybe byte ordering is wrong
- resetByteOrder = reader.isMotorolaByteOrder();
- reader.setMotorolaByteOrder(!reader.isMotorolaByteOrder());
- num = reader.getUInt16(tagValueOffset + 14);
+ localReader = reader.Clone(false);
+
+ num = localReader.getUInt16(tagValueOffset + 14);
if (byteCount < 16 + num * 6) {
directory.addError("Bad PrintIM size");
return;
@@ -673,17 +669,14 @@ private static void processPrintIM(@NotNull final PrintIMDirectory directory, fi
for (int n = 0; n < num; n++) {
int pos = tagValueOffset + 16 + n * 6;
- int tag = reader.getUInt16(pos);
- long val = reader.getUInt32(pos + 2);
+ int tag = localReader.getUInt16(pos);
+ long val = localReader.getUInt32(pos + 2);
directory.setObject(tag, val);
}
-
- if (resetByteOrder != null)
- reader.setMotorolaByteOrder(resetByteOrder);
}
- private static void processKodakMakernote(@NotNull final KodakMakernoteDirectory directory, final int tagValueOffset, @NotNull final RandomAccessReader reader)
+ private static void processKodakMakernote(@NotNull final KodakMakernoteDirectory directory, final int tagValueOffset, @NotNull final ReaderInfo reader)
{
// Kodak's makernote is not in IFD format. It has values at fixed offsets.
int dataOffset = tagValueOffset + 8;
@@ -719,7 +712,7 @@ private static void processKodakMakernote(@NotNull final KodakMakernoteDirectory
}
}
- private static void processReconyxHyperFireMakernote(@NotNull final ReconyxHyperFireMakernoteDirectory directory, final int makernoteOffset, @NotNull final RandomAccessReader reader) throws IOException
+ private static void processReconyxHyperFireMakernote(@NotNull final ReconyxHyperFireMakernoteDirectory directory, final int makernoteOffset, @NotNull ReaderInfo reader) throws IOException
{
directory.setObject(ReconyxHyperFireMakernoteDirectory.TAG_MAKERNOTE_VERSION, reader.getUInt16(makernoteOffset));
@@ -791,7 +784,7 @@ private static void processReconyxHyperFireMakernote(@NotNull final ReconyxHyper
directory.setString(ReconyxHyperFireMakernoteDirectory.TAG_USER_LABEL, reader.getNullTerminatedString(makernoteOffset + ReconyxHyperFireMakernoteDirectory.TAG_USER_LABEL, 44, Charsets.UTF_8));
}
- private static void processReconyxUltraFireMakernote(@NotNull final ReconyxUltraFireMakernoteDirectory directory, final int makernoteOffset, @NotNull final RandomAccessReader reader) throws IOException
+ private static void processReconyxUltraFireMakernote(@NotNull final ReconyxUltraFireMakernoteDirectory directory, final int makernoteOffset, @NotNull ReaderInfo reader) throws IOException
{
directory.setString(ReconyxUltraFireMakernoteDirectory.TAG_LABEL, reader.getString(makernoteOffset, 9, Charsets.UTF_8));
/*uint makernoteID = ByteConvert.FromBigEndianToNative(reader.GetUInt32(makernoteOffset + ReconyxUltraFireMakernoteDirectory.TagMakernoteID));
diff --git a/Source/com/drew/metadata/exif/makernotes/NikonType2MakernoteDescriptor.java b/Source/com/drew/metadata/exif/makernotes/NikonType2MakernoteDescriptor.java
index d105d0f46..740e23c01 100644
--- a/Source/com/drew/metadata/exif/makernotes/NikonType2MakernoteDescriptor.java
+++ b/Source/com/drew/metadata/exif/makernotes/NikonType2MakernoteDescriptor.java
@@ -25,6 +25,7 @@
import com.drew.lang.annotations.Nullable;
import com.drew.metadata.TagDescriptor;
+import java.nio.ByteBuffer;
import java.text.DecimalFormat;
import static com.drew.metadata.exif.makernotes.NikonType2MakernoteDirectory.*;
@@ -104,7 +105,15 @@ public String getDescription(int tagType)
@Nullable
public String getPowerUpTimeDescription()
{
- return getEpochTimeDescription(TAG_POWER_UP_TIME);
+ // this is generally a byte[] of length 8 directly representing a date and time.
+ // the format is : first 2 bytes together are the year, and then each byte after
+ // is month, day, hour, minute, second with the eighth byte unused
+ // e.g., 2011:04:25 01:54:58
+
+ byte[] values = _directory.getByteArray(TAG_POWER_UP_TIME);
+ short year = ByteBuffer.wrap(new byte[]{values[0], values[1]}).getShort();
+ return String.format("%04d:%02d:%02d %02d:%02d:%02d", year, values[2], values[3],
+ values[4], values[5], values[6]);
}
@Nullable
diff --git a/Source/com/drew/metadata/exif/makernotes/OlympusMakernoteDirectory.java b/Source/com/drew/metadata/exif/makernotes/OlympusMakernoteDirectory.java
index 2856a6603..ae6d5deec 100644
--- a/Source/com/drew/metadata/exif/makernotes/OlympusMakernoteDirectory.java
+++ b/Source/com/drew/metadata/exif/makernotes/OlympusMakernoteDirectory.java
@@ -20,7 +20,7 @@
*/
package com.drew.metadata.exif.makernotes;
-import com.drew.lang.SequentialByteArrayReader;
+import com.drew.lang.ReaderInfo;
import com.drew.lang.annotations.NotNull;
import com.drew.metadata.Directory;
@@ -476,7 +476,7 @@ public void setByteArray(int tagType, @NotNull byte[] bytes)
private void processCameraSettings(byte[] bytes)
{
- SequentialByteArrayReader reader = new SequentialByteArrayReader(bytes);
+ ReaderInfo reader = ReaderInfo.createFromArray(bytes);
reader.setMotorolaByteOrder(true);
int count = bytes.length / 4;
diff --git a/Source/com/drew/metadata/exif/makernotes/PanasonicMakernoteDescriptor.java b/Source/com/drew/metadata/exif/makernotes/PanasonicMakernoteDescriptor.java
index d5e4943fb..5426a2221 100644
--- a/Source/com/drew/metadata/exif/makernotes/PanasonicMakernoteDescriptor.java
+++ b/Source/com/drew/metadata/exif/makernotes/PanasonicMakernoteDescriptor.java
@@ -20,9 +20,8 @@
*/
package com.drew.metadata.exif.makernotes;
-import com.drew.lang.ByteArrayReader;
import com.drew.lang.Charsets;
-import com.drew.lang.RandomAccessReader;
+import com.drew.lang.ReaderInfo;
import com.drew.lang.annotations.NotNull;
import com.drew.lang.annotations.Nullable;
import com.drew.metadata.Age;
@@ -275,7 +274,7 @@ private String getTransformDescription(int tag)
if (values == null)
return null;
- RandomAccessReader reader = new ByteArrayReader(values);
+ ReaderInfo reader = ReaderInfo.createFromArray(values);
try
{
diff --git a/Source/com/drew/metadata/exif/makernotes/PanasonicMakernoteDirectory.java b/Source/com/drew/metadata/exif/makernotes/PanasonicMakernoteDirectory.java
index b2b6c25d0..277d4cfba 100644
--- a/Source/com/drew/metadata/exif/makernotes/PanasonicMakernoteDirectory.java
+++ b/Source/com/drew/metadata/exif/makernotes/PanasonicMakernoteDirectory.java
@@ -20,8 +20,7 @@
*/
package com.drew.metadata.exif.makernotes;
-import com.drew.lang.ByteArrayReader;
-import com.drew.lang.RandomAccessReader;
+import com.drew.lang.ReaderInfo;
import com.drew.lang.annotations.NotNull;
import com.drew.lang.annotations.Nullable;
import com.drew.metadata.Age;
@@ -637,7 +636,7 @@ public Face[] getDetectedFaces()
if (bytes==null)
return null;
- RandomAccessReader reader = new ByteArrayReader(bytes);
+ ReaderInfo reader = ReaderInfo.createFromArray(bytes);
reader.setMotorolaByteOrder(false);
try {
@@ -668,7 +667,7 @@ public Face[] getRecognizedFaces()
if (bytes == null)
return null;
- RandomAccessReader reader = new ByteArrayReader(bytes);
+ ReaderInfo reader = ReaderInfo.createFromArray(bytes);
reader.setMotorolaByteOrder(false);
try {
diff --git a/Source/com/drew/metadata/file/FileSystemMetadataReader.java b/Source/com/drew/metadata/file/FileSystemMetadataReader.java
index ce58f4e93..9bc0b68ee 100644
--- a/Source/com/drew/metadata/file/FileSystemMetadataReader.java
+++ b/Source/com/drew/metadata/file/FileSystemMetadataReader.java
@@ -27,7 +27,7 @@
import java.util.Date;
public class FileSystemMetadataReader
-{
+{
public void read(@NotNull File file, @NotNull Metadata metadata) throws IOException
{
if (!file.isFile())
diff --git a/Source/com/drew/metadata/gif/GifReader.java b/Source/com/drew/metadata/gif/GifReader.java
index 289e6b0db..e4e9360d2 100644
--- a/Source/com/drew/metadata/gif/GifReader.java
+++ b/Source/com/drew/metadata/gif/GifReader.java
@@ -20,9 +20,8 @@
*/
package com.drew.metadata.gif;
-import com.drew.lang.ByteArrayReader;
import com.drew.lang.Charsets;
-import com.drew.lang.SequentialReader;
+import com.drew.lang.ReaderInfo;
import com.drew.lang.annotations.NotNull;
import com.drew.lang.annotations.Nullable;
@@ -31,7 +30,6 @@
import com.drew.metadata.icc.IccReader;
import com.drew.metadata.xmp.XmpReader;
-import java.io.ByteArrayOutputStream;
import java.io.IOException;
/**
@@ -52,9 +50,10 @@ public class GifReader
private static final String GIF_87A_VERSION_IDENTIFIER = "87a";
private static final String GIF_89A_VERSION_IDENTIFIER = "89a";
- public void extract(@NotNull final SequentialReader reader, final @NotNull Metadata metadata)
+ public void extract(@NotNull ReaderInfo reader, final @NotNull Metadata metadata) throws IOException
{
- reader.setMotorolaByteOrder(false);
+ if(reader.isMotorolaByteOrder())
+ reader = reader.Clone(false);
GifHeaderDirectory header;
try {
@@ -131,7 +130,7 @@ public void extract(@NotNull final SequentialReader reader, final @NotNull Metad
}
}
- private static GifHeaderDirectory readGifHeader(@NotNull final SequentialReader reader) throws IOException
+ private static GifHeaderDirectory readGifHeader(@NotNull ReaderInfo reader) throws IOException
{
// FILE HEADER
//
@@ -152,7 +151,7 @@ private static GifHeaderDirectory readGifHeader(@NotNull final SequentialReader
GifHeaderDirectory headerDirectory = new GifHeaderDirectory();
- String signature = reader.getString(3);
+ String signature = reader.getString(3, Charsets.UTF_8);
if (!signature.equals("GIF"))
{
@@ -160,7 +159,7 @@ private static GifHeaderDirectory readGifHeader(@NotNull final SequentialReader
return headerDirectory;
}
- String version = reader.getString(3);
+ String version = reader.getString(3, Charsets.UTF_8);
if (!version.equals(GIF_87A_VERSION_IDENTIFIER) && !version.equals(GIF_89A_VERSION_IDENTIFIER)) {
headerDirectory.addError("Unexpected GIF version");
@@ -202,11 +201,11 @@ private static GifHeaderDirectory readGifHeader(@NotNull final SequentialReader
return headerDirectory;
}
- private static void readGifExtensionBlock(SequentialReader reader, Metadata metadata) throws IOException
+ private static void readGifExtensionBlock(ReaderInfo reader, Metadata metadata) throws IOException
{
byte extensionLabel = reader.getInt8();
short blockSizeBytes = reader.getUInt8();
- long blockStartPos = reader.getPosition();
+ long blockStartPos = reader.getLocalPosition();
switch (extensionLabel)
{
@@ -229,13 +228,13 @@ private static void readGifExtensionBlock(SequentialReader reader, Metadata meta
break;
}
- long skipCount = blockStartPos + blockSizeBytes - reader.getPosition();
+ long skipCount = blockStartPos + blockSizeBytes - reader.getLocalPosition();
if (skipCount > 0)
reader.skip(skipCount);
}
@Nullable
- private static Directory readPlainTextBlock(SequentialReader reader, int blockSizeBytes) throws IOException
+ private static Directory readPlainTextBlock(ReaderInfo reader, int blockSizeBytes) throws IOException
{
// It seems this extension is deprecated. If somebody finds an image with this in it, could implement here.
// Just skip the entire block for now.
@@ -252,13 +251,13 @@ private static Directory readPlainTextBlock(SequentialReader reader, int blockSi
return null;
}
- private static GifCommentDirectory readCommentBlock(SequentialReader reader, int blockSizeBytes) throws IOException
+ private static GifCommentDirectory readCommentBlock(ReaderInfo reader, int blockSizeBytes) throws IOException
{
- byte[] buffer = gatherBytes(reader, blockSizeBytes);
- return new GifCommentDirectory(new StringValue(buffer, Charsets.ASCII));
+ ReaderInfo buffer = gatherBytes(reader, blockSizeBytes);
+ return new GifCommentDirectory(new StringValue(buffer.toArray(), Charsets.ASCII));
}
- private static void readApplicationExtensionBlock(SequentialReader reader, int blockSizeBytes, Metadata metadata) throws IOException
+ private static void readApplicationExtensionBlock(ReaderInfo reader, int blockSizeBytes, Metadata metadata) throws IOException
{
if (blockSizeBytes != 11)
{
@@ -271,15 +270,15 @@ private static void readApplicationExtensionBlock(SequentialReader reader, int b
if (extensionType.equals("XMP DataXMP"))
{
// XMP data extension
- byte[] xmpBytes = gatherBytes(reader);
- new XmpReader().extract(xmpBytes, 0, xmpBytes.length - 257, metadata, null);
+ ReaderInfo xmpBytes = gatherBytes(reader);
+ new XmpReader().extract(xmpBytes.Clone(xmpBytes.getLength() - 257), metadata);
}
else if (extensionType.equals("ICCRGBG1012"))
{
// ICC profile extension
- byte[] iccBytes = gatherBytes(reader, ((int) reader.getByte()) & 0xff);
- if (iccBytes.length != 0)
- new IccReader().extract(new ByteArrayReader(iccBytes), metadata);
+ ReaderInfo iccBytes = gatherBytes(reader, ((int)reader.getByte()) & 0xff);
+ if (iccBytes.getLength() != 0)
+ new IccReader().extract(iccBytes, metadata);
}
else if (extensionType.equals("NETSCAPE2.0"))
{
@@ -299,7 +298,7 @@ else if (extensionType.equals("NETSCAPE2.0"))
}
}
- private static GifControlDirectory readControlBlock(SequentialReader reader, int blockSizeBytes) throws IOException
+ private static GifControlDirectory readControlBlock(ReaderInfo reader, int blockSizeBytes) throws IOException
{
if (blockSizeBytes < 4)
blockSizeBytes = 4;
@@ -319,7 +318,7 @@ private static GifControlDirectory readControlBlock(SequentialReader reader, int
return directory;
}
- private static GifImageDirectory readImageBlock(SequentialReader reader) throws IOException
+ private static GifImageDirectory readImageBlock(ReaderInfo reader) throws IOException
{
GifImageDirectory imageDirectory = new GifImageDirectory();
@@ -353,42 +352,41 @@ private static GifImageDirectory readImageBlock(SequentialReader reader) throws
return imageDirectory;
}
- private static byte[] gatherBytes(SequentialReader reader) throws IOException
+ private static ReaderInfo gatherBytes(ReaderInfo reader) throws IOException
{
- ByteArrayOutputStream bytes = new ByteArrayOutputStream();
- byte[] buffer = new byte[257];
+ int length = 0;
while (true)
{
byte b = reader.getByte();
if (b == 0)
- return bytes.toByteArray();
+ break;
int bInt = b & 0xFF;
+ reader.skip(bInt);
- buffer[0] = b;
- reader.getBytes(buffer, 1, bInt);
- bytes.write(buffer, 0, bInt + 1);
+ length += bInt + 1;
}
+
+ return reader.Clone(-length - 1, length);
}
- private static byte[] gatherBytes(SequentialReader reader, int firstLength) throws IOException
+ private static ReaderInfo gatherBytes(ReaderInfo reader, int firstLength) throws IOException
{
- ByteArrayOutputStream buffer = new ByteArrayOutputStream();
-
int length = firstLength;
-
+ int readerLength = 0;
+
while (length > 0)
{
- buffer.write(reader.getBytes(length), 0, length);
-
+ reader.skip(length);
+ readerLength += length;
length = reader.getByte() & 0xff;
}
- return buffer.toByteArray();
+ return reader.Clone(-readerLength - 1, readerLength);
}
- private static void skipBlocks(SequentialReader reader) throws IOException
+ private static void skipBlocks(ReaderInfo reader) throws IOException
{
while (true)
{
diff --git a/Source/com/drew/metadata/heif/HeifBoxHandler.java b/Source/com/drew/metadata/heif/HeifBoxHandler.java
index f40ee2984..d0aa23741 100644
--- a/Source/com/drew/metadata/heif/HeifBoxHandler.java
+++ b/Source/com/drew/metadata/heif/HeifBoxHandler.java
@@ -21,8 +21,7 @@
package com.drew.metadata.heif;
import com.drew.imaging.heif.HeifHandler;
-import com.drew.lang.SequentialByteArrayReader;
-import com.drew.lang.SequentialReader;
+import com.drew.lang.ReaderInfo;
import com.drew.lang.annotations.NotNull;
import com.drew.metadata.Metadata;
import com.drew.metadata.heif.boxes.*;
@@ -70,14 +69,13 @@ public boolean shouldAcceptContainer(Box box)
}
@Override
- public HeifHandler processBox(@NotNull Box box, @NotNull byte[] payload) throws IOException
+ public HeifHandler processBox(@NotNull Box box, @NotNull ReaderInfo payloadReader) throws IOException
{
- if (payload != null) {
- SequentialReader reader = new SequentialByteArrayReader(payload);
+ if (payloadReader != null) {
if (box.type.equals(HeifBoxTypes.BOX_FILE_TYPE)) {
- processFileType(reader, box);
+ processFileType(payloadReader, box);
}else if (box.type.equals(HeifBoxTypes.BOX_HANDLER)) {
- handlerBox = new HandlerBox(reader, box);
+ handlerBox = new HandlerBox(payloadReader, box);
return handlerFactory.getHandler(handlerBox, metadata);
}
}
@@ -85,14 +83,14 @@ public HeifHandler processBox(@NotNull Box box, @NotNull byte[] payload) throws
}
@Override
- public void processContainer(@NotNull Box box, @NotNull SequentialReader reader) throws IOException
+ public void processContainer(@NotNull Box box, @NotNull ReaderInfo reader) throws IOException
{
if (box.type.equals(HeifContainerTypes.BOX_METADATA)) {
new FullBox(reader, box);
}
}
- private void processFileType(@NotNull SequentialReader reader, @NotNull Box box) throws IOException
+ private void processFileType(@NotNull ReaderInfo reader, @NotNull Box box) throws IOException
{
FileTypeBox fileTypeBox = new FileTypeBox(reader, box);
fileTypeBox.addMetadata(directory);
diff --git a/Source/com/drew/metadata/heif/HeifPictureHandler.java b/Source/com/drew/metadata/heif/HeifPictureHandler.java
index 6cec834cd..eb8fa4107 100644
--- a/Source/com/drew/metadata/heif/HeifPictureHandler.java
+++ b/Source/com/drew/metadata/heif/HeifPictureHandler.java
@@ -21,8 +21,7 @@
package com.drew.metadata.heif;
import com.drew.imaging.heif.HeifHandler;
-import com.drew.lang.SequentialByteArrayReader;
-import com.drew.lang.SequentialReader;
+import com.drew.lang.ReaderInfo;
import com.drew.metadata.Metadata;
import com.drew.metadata.heif.boxes.*;
@@ -71,29 +70,29 @@ protected boolean shouldAcceptContainer(Box box)
}
@Override
- protected HeifHandler processBox(Box box, byte[] payload) throws IOException
+ //protected HeifHandler processBox(Box box, byte[] payload) throws IOException
+ protected HeifHandler processBox(Box box, ReaderInfo payloadReader) throws IOException
{
- SequentialReader reader = new SequentialByteArrayReader(payload);
if (box.type.equals(HeifBoxTypes.BOX_ITEM_PROTECTION)) {
- itemProtectionBox = new ItemProtectionBox(reader, box);
+ itemProtectionBox = new ItemProtectionBox(payloadReader, box);
} else if (box.type.equals(HeifBoxTypes.BOX_PRIMARY_ITEM)) {
- primaryItemBox = new PrimaryItemBox(reader, box);
+ primaryItemBox = new PrimaryItemBox(payloadReader, box);
} else if (box.type.equals(HeifBoxTypes.BOX_ITEM_INFO)) {
- itemInfoBox = new ItemInfoBox(reader, box);
+ itemInfoBox = new ItemInfoBox(payloadReader, box);
itemInfoBox.addMetadata(directory);
} else if (box.type.equals(HeifBoxTypes.BOX_ITEM_LOCATION)) {
- itemLocationBox = new ItemLocationBox(reader, box);
+ itemLocationBox = new ItemLocationBox(payloadReader, box);
} else if (box.type.equals(HeifBoxTypes.BOX_IMAGE_SPATIAL_EXTENTS)) {
- ImageSpatialExtentsProperty imageSpatialExtentsProperty = new ImageSpatialExtentsProperty(reader, box);
+ ImageSpatialExtentsProperty imageSpatialExtentsProperty = new ImageSpatialExtentsProperty(payloadReader, box);
imageSpatialExtentsProperty.addMetadata(directory);
} else if (box.type.equals(HeifBoxTypes.BOX_AUXILIARY_TYPE_PROPERTY)) {
- AuxiliaryTypeProperty auxiliaryTypeProperty = new AuxiliaryTypeProperty(reader, box);
+ AuxiliaryTypeProperty auxiliaryTypeProperty = new AuxiliaryTypeProperty(payloadReader, box);
}
return this;
}
@Override
- protected void processContainer(Box box, SequentialReader reader) throws IOException
+ protected void processContainer(Box box, ReaderInfo reader) throws IOException
{
}
diff --git a/Source/com/drew/metadata/heif/boxes/AuxiliaryTypeProperty.java b/Source/com/drew/metadata/heif/boxes/AuxiliaryTypeProperty.java
index 04f19cb5e..6ed6d1a6e 100644
--- a/Source/com/drew/metadata/heif/boxes/AuxiliaryTypeProperty.java
+++ b/Source/com/drew/metadata/heif/boxes/AuxiliaryTypeProperty.java
@@ -20,10 +20,9 @@
*/
package com.drew.metadata.heif.boxes;
-import com.drew.lang.SequentialReader;
+import com.drew.lang.ReaderInfo;
import java.io.IOException;
-import java.nio.charset.Charset;
/**
* ISO/IEC 23008-12:2017 pg.14
@@ -33,7 +32,7 @@ public class AuxiliaryTypeProperty extends FullBox
String auxType;
int[] auxSubtype;
- public AuxiliaryTypeProperty(SequentialReader reader, Box box) throws IOException
+ public AuxiliaryTypeProperty(ReaderInfo reader, Box box) throws IOException
{
super(reader, box);
@@ -41,7 +40,7 @@ public AuxiliaryTypeProperty(SequentialReader reader, Box box) throws IOExceptio
// auxSubtype
}
- private String getZeroTerminatedString(int maxLengthBytes, SequentialReader reader) throws IOException
+ private String getZeroTerminatedString(int maxLengthBytes, ReaderInfo reader) throws IOException
{
StringBuilder stringBuilder = new StringBuilder();
for (int i = 0; i < maxLengthBytes; i++) {
diff --git a/Source/com/drew/metadata/heif/boxes/Box.java b/Source/com/drew/metadata/heif/boxes/Box.java
index b436df8f7..33e9b2592 100644
--- a/Source/com/drew/metadata/heif/boxes/Box.java
+++ b/Source/com/drew/metadata/heif/boxes/Box.java
@@ -20,7 +20,8 @@
*/
package com.drew.metadata.heif.boxes;
-import com.drew.lang.SequentialReader;
+import com.drew.lang.ReaderInfo;
+import com.drew.lang.Charsets;
import java.io.IOException;
@@ -33,17 +34,17 @@ public class Box
public String type;
String usertype;
- public Box(SequentialReader reader) throws IOException
+ public Box(ReaderInfo reader) throws IOException
{
this.size = reader.getUInt32();
- this.type = reader.getString(4);
+ this.type = reader.getString(4, Charsets.UTF_8);
if (size == 1) {
size = reader.getInt64();
} else if (size == 0) {
size = -1;
}
if (type.equals("uuid")) {
- usertype = reader.getString(16);
+ usertype = reader.getString(16, Charsets.UTF_8);
}
}
diff --git a/Source/com/drew/metadata/heif/boxes/FileTypeBox.java b/Source/com/drew/metadata/heif/boxes/FileTypeBox.java
index eaa1fc4e0..c9c399f6a 100644
--- a/Source/com/drew/metadata/heif/boxes/FileTypeBox.java
+++ b/Source/com/drew/metadata/heif/boxes/FileTypeBox.java
@@ -20,9 +20,11 @@
*/
package com.drew.metadata.heif.boxes;
-import com.drew.lang.SequentialReader;
+import com.drew.lang.ReaderInfo;
import com.drew.metadata.heif.HeifDirectory;
+import com.drew.lang.Charsets;
+
import java.io.IOException;
import java.util.ArrayList;
@@ -35,15 +37,15 @@ public class FileTypeBox extends Box
long minorVersion;
ArrayList compatibleBrands;
- public FileTypeBox(SequentialReader reader, Box box) throws IOException
+ public FileTypeBox(ReaderInfo reader, Box box) throws IOException
{
super(box);
- majorBrand = reader.getString(4);
+ majorBrand = reader.getString(4, Charsets.UTF_8);
minorVersion = reader.getUInt32();
compatibleBrands = new ArrayList();
for (int i = 16; i < size; i += 4) {
- compatibleBrands.add(reader.getString(4));
+ compatibleBrands.add(reader.getString(4, Charsets.UTF_8));
}
}
diff --git a/Source/com/drew/metadata/heif/boxes/FullBox.java b/Source/com/drew/metadata/heif/boxes/FullBox.java
index 382ca1483..b4bd40a93 100644
--- a/Source/com/drew/metadata/heif/boxes/FullBox.java
+++ b/Source/com/drew/metadata/heif/boxes/FullBox.java
@@ -20,7 +20,7 @@
*/
package com.drew.metadata.heif.boxes;
-import com.drew.lang.SequentialReader;
+import com.drew.lang.ReaderInfo;
import java.io.IOException;
@@ -32,7 +32,7 @@ public class FullBox extends Box
byte[] flags;
int version;
- public FullBox(SequentialReader reader, Box box) throws IOException
+ public FullBox(ReaderInfo reader, Box box) throws IOException
{
super(box);
diff --git a/Source/com/drew/metadata/heif/boxes/HandlerBox.java b/Source/com/drew/metadata/heif/boxes/HandlerBox.java
index 673c69fa8..f5670ca7f 100644
--- a/Source/com/drew/metadata/heif/boxes/HandlerBox.java
+++ b/Source/com/drew/metadata/heif/boxes/HandlerBox.java
@@ -20,7 +20,8 @@
*/
package com.drew.metadata.heif.boxes;
-import com.drew.lang.SequentialReader;
+import com.drew.lang.ReaderInfo;
+import com.drew.lang.Charsets;
import java.io.IOException;
import java.nio.charset.Charset;
@@ -34,12 +35,12 @@ public class HandlerBox extends FullBox
String handlerType;
String name;
- public HandlerBox(SequentialReader reader, Box box) throws IOException
+ public HandlerBox(ReaderInfo reader, Box box) throws IOException
{
super(reader, box);
reader.skip(4); // Pre-defined
- handlerType = reader.getString(4);
+ handlerType = reader.getString(4, Charsets.UTF_8);
reader.skip(12); // Reserved
name = reader.getNullTerminatedString((int)box.size - 32, Charset.defaultCharset());
}
diff --git a/Source/com/drew/metadata/heif/boxes/ImageSpatialExtentsProperty.java b/Source/com/drew/metadata/heif/boxes/ImageSpatialExtentsProperty.java
index d786c1786..c1c864326 100644
--- a/Source/com/drew/metadata/heif/boxes/ImageSpatialExtentsProperty.java
+++ b/Source/com/drew/metadata/heif/boxes/ImageSpatialExtentsProperty.java
@@ -20,7 +20,7 @@
*/
package com.drew.metadata.heif.boxes;
-import com.drew.lang.SequentialReader;
+import com.drew.lang.ReaderInfo;
import com.drew.metadata.heif.HeifDirectory;
import java.io.IOException;
@@ -33,7 +33,7 @@ public class ImageSpatialExtentsProperty extends FullBox
long width;
long height;
- public ImageSpatialExtentsProperty(SequentialReader reader, Box box) throws IOException
+ public ImageSpatialExtentsProperty(ReaderInfo reader, Box box) throws IOException
{
super(reader, box);
diff --git a/Source/com/drew/metadata/heif/boxes/ItemInfoBox.java b/Source/com/drew/metadata/heif/boxes/ItemInfoBox.java
index 4c89207a9..09e3e00d9 100644
--- a/Source/com/drew/metadata/heif/boxes/ItemInfoBox.java
+++ b/Source/com/drew/metadata/heif/boxes/ItemInfoBox.java
@@ -20,12 +20,11 @@
*/
package com.drew.metadata.heif.boxes;
-import com.drew.lang.SequentialByteArrayReader;
-import com.drew.lang.SequentialReader;
+import com.drew.lang.Charsets;
+import com.drew.lang.ReaderInfo;
import com.drew.metadata.heif.HeifDirectory;
import java.io.IOException;
-import java.nio.charset.Charset;
import java.util.ArrayList;
/**
@@ -36,7 +35,7 @@ public class ItemInfoBox extends FullBox
long entryCount;
ArrayList entries;
- public ItemInfoBox(SequentialReader reader, Box box) throws IOException
+ public ItemInfoBox(ReaderInfo reader, Box box) throws IOException
{
super(reader, box);
@@ -49,7 +48,7 @@ public ItemInfoBox(SequentialReader reader, Box box) throws IOException
for (int i = 1; i <= entryCount; i++)
{
Box entryBox = new Box(reader);
- SequentialByteArrayReader byteReader = new SequentialByteArrayReader(reader.getBytes((int)entryBox.size - 8));
+ ReaderInfo byteReader = reader.Clone((int)entryBox.size - 8);
entries.add(new ItemInfoEntry(byteReader, entryBox));
}
}
@@ -65,22 +64,22 @@ class ItemInfoEntry extends FullBox
String itemType;
String itemUriType;
- public ItemInfoEntry(SequentialReader reader, Box box) throws IOException
+ public ItemInfoEntry(ReaderInfo reader, Box box) throws IOException
{
super(reader, box);
if ((version == 0) || (version == 1)) {
itemID = reader.getUInt16();
itemProtectionIndex = reader.getUInt16();
- itemName = reader.getString(4);
- contentType = reader.getString(4);
+ itemName = reader.getString(4, Charsets.UTF_8);
+ contentType = reader.getString(4, Charsets.UTF_8);
if (box.size - 28 > 0) {
- extensionType = reader.getString((int)box.size - 28);
+ extensionType = reader.getString((int)box.size - 28, Charsets.UTF_8);
}
}
if (version == 1) {
if (box.size - 28 >= 4) {
- contentEncoding = reader.getString(4);
+ contentEncoding = reader.getString(4, Charsets.UTF_8);
}
}
if (version >= 2) {
@@ -90,13 +89,13 @@ public ItemInfoEntry(SequentialReader reader, Box box) throws IOException
itemID = reader.getUInt32();
}
itemProtectionIndex = reader.getUInt16();
- itemType = reader.getString(4);
+ itemType = reader.getString(4, Charsets.UTF_8);
- itemName = reader.getString(4);
+ itemName = reader.getString(4, Charsets.UTF_8);
if (itemType.equals("mime")) {
- contentType = reader.getString(4);
+ contentType = reader.getString(4, Charsets.UTF_8);
} else if (itemType.equals("uri ")) {
- itemUriType = reader.getString(4);
+ itemUriType = reader.getString(4, Charsets.UTF_8);
}
}
}
diff --git a/Source/com/drew/metadata/heif/boxes/ItemLocationBox.java b/Source/com/drew/metadata/heif/boxes/ItemLocationBox.java
index f6ee812fc..26f01be29 100644
--- a/Source/com/drew/metadata/heif/boxes/ItemLocationBox.java
+++ b/Source/com/drew/metadata/heif/boxes/ItemLocationBox.java
@@ -20,7 +20,7 @@
*/
package com.drew.metadata.heif.boxes;
-import com.drew.lang.SequentialReader;
+import com.drew.lang.ReaderInfo;
import java.io.IOException;
@@ -41,7 +41,7 @@ public class ItemLocationBox extends FullBox
int extentCount;
Extent[] extents;
- public ItemLocationBox(SequentialReader reader, Box box) throws IOException
+ public ItemLocationBox(ReaderInfo reader, Box box) throws IOException
{
super(reader, box);
@@ -90,7 +90,7 @@ public ItemLocationBox(SequentialReader reader, Box box) throws IOException
}
}
- public Long getIntFromUnknownByte(int variable, SequentialReader reader) throws IOException
+ public Long getIntFromUnknownByte(int variable, ReaderInfo reader) throws IOException
{
switch(variable) {
case (1):
diff --git a/Source/com/drew/metadata/heif/boxes/ItemProtectionBox.java b/Source/com/drew/metadata/heif/boxes/ItemProtectionBox.java
index 4dfd42c94..210e0ebe3 100644
--- a/Source/com/drew/metadata/heif/boxes/ItemProtectionBox.java
+++ b/Source/com/drew/metadata/heif/boxes/ItemProtectionBox.java
@@ -20,7 +20,8 @@
*/
package com.drew.metadata.heif.boxes;
-import com.drew.lang.SequentialReader;
+import com.drew.lang.ReaderInfo;
+import com.drew.lang.Charsets;
import java.io.IOException;
import java.util.ArrayList;
@@ -33,7 +34,7 @@ public class ItemProtectionBox extends FullBox
int protectionCount;
ArrayList protectionSchemes;
- public ItemProtectionBox(SequentialReader reader, Box box) throws IOException
+ public ItemProtectionBox(ReaderInfo reader, Box box) throws IOException
{
super(reader, box);
@@ -46,7 +47,7 @@ public ItemProtectionBox(SequentialReader reader, Box box) throws IOException
class ProtectionSchemeInfoBox extends Box
{
- public ProtectionSchemeInfoBox(SequentialReader reader, Box box) throws IOException
+ public ProtectionSchemeInfoBox(ReaderInfo reader, Box box) throws IOException
{
super(box);
}
@@ -55,11 +56,11 @@ class OriginalFormatBox extends Box
{
String dataFormat;
- public OriginalFormatBox(SequentialReader reader, Box box) throws IOException
+ public OriginalFormatBox(ReaderInfo reader, Box box) throws IOException
{
super(reader);
- dataFormat = reader.getString(4);
+ dataFormat = reader.getString(4, Charsets.UTF_8);
}
}
}
diff --git a/Source/com/drew/metadata/heif/boxes/PrimaryItemBox.java b/Source/com/drew/metadata/heif/boxes/PrimaryItemBox.java
index 8c41c4ce8..09feb0033 100644
--- a/Source/com/drew/metadata/heif/boxes/PrimaryItemBox.java
+++ b/Source/com/drew/metadata/heif/boxes/PrimaryItemBox.java
@@ -20,7 +20,7 @@
*/
package com.drew.metadata.heif.boxes;
-import com.drew.lang.SequentialReader;
+import com.drew.lang.ReaderInfo;
import java.io.IOException;
@@ -31,7 +31,7 @@ public class PrimaryItemBox extends FullBox
{
long itemID;
- public PrimaryItemBox(SequentialReader reader, Box box) throws IOException
+ public PrimaryItemBox(ReaderInfo reader, Box box) throws IOException
{
super(reader, box);
diff --git a/Source/com/drew/metadata/icc/IccDescriptor.java b/Source/com/drew/metadata/icc/IccDescriptor.java
index 13363a650..2e6d50e00 100644
--- a/Source/com/drew/metadata/icc/IccDescriptor.java
+++ b/Source/com/drew/metadata/icc/IccDescriptor.java
@@ -21,8 +21,7 @@
package com.drew.metadata.icc;
-import com.drew.lang.ByteArrayReader;
-import com.drew.lang.RandomAccessReader;
+import com.drew.lang.ReaderInfo;
import com.drew.lang.annotations.NotNull;
import com.drew.lang.annotations.Nullable;
import com.drew.metadata.TagDescriptor;
@@ -80,7 +79,7 @@ private String getTagDataString(int tagType)
byte[] bytes = _directory.getByteArray(tagType);
if (bytes == null)
return _directory.getString(tagType);
- RandomAccessReader reader = new ByteArrayReader(bytes);
+ ReaderInfo reader = ReaderInfo.createFromArray(bytes);
int iccTagType = reader.getInt32(0);
switch (iccTagType) {
case ICC_TAG_TYPE_TEXT:
@@ -337,6 +336,6 @@ private String getProfileVersionDescription()
private static int getInt32FromString(@NotNull String string) throws IOException
{
byte[] bytes = string.getBytes();
- return new ByteArrayReader(bytes).getInt32(0);
+ return ReaderInfo.createFromArray(bytes).getInt32(0);
}
}
diff --git a/Source/com/drew/metadata/icc/IccReader.java b/Source/com/drew/metadata/icc/IccReader.java
index 090c9b482..ae55f7448 100644
--- a/Source/com/drew/metadata/icc/IccReader.java
+++ b/Source/com/drew/metadata/icc/IccReader.java
@@ -22,14 +22,13 @@
import com.drew.imaging.jpeg.JpegSegmentMetadataReader;
import com.drew.imaging.jpeg.JpegSegmentType;
-import com.drew.lang.ByteArrayReader;
+import com.drew.imaging.jpeg.JpegSegment;
+import com.drew.lang.ReaderInfo;
import com.drew.lang.DateUtil;
-import com.drew.lang.RandomAccessReader;
import com.drew.lang.annotations.NotNull;
import com.drew.lang.annotations.Nullable;
import com.drew.metadata.Directory;
import com.drew.metadata.Metadata;
-import com.drew.metadata.MetadataReader;
import java.io.IOException;
import java.util.Collections;
@@ -47,55 +46,61 @@
* @author Yuri Binev
* @author Drew Noakes https://drewnoakes.com
*/
-public class IccReader implements JpegSegmentMetadataReader, MetadataReader
+public class IccReader implements JpegSegmentMetadataReader
{
+ public static final String JPEG_SEGMENT_ID = "ICC";
public static final String JPEG_SEGMENT_PREAMBLE = "ICC_PROFILE";
-
+
@NotNull
public Iterable getSegmentTypes()
{
return Collections.singletonList(JpegSegmentType.APP2);
}
- public void readJpegSegments(@NotNull Iterable segments, @NotNull Metadata metadata, @NotNull JpegSegmentType segmentType)
+ public void readJpegSegments(@NotNull Iterable segments, @NotNull Metadata metadata) throws IOException
{
- final int preambleLength = JPEG_SEGMENT_PREAMBLE.length();
+ // NOTE the header is 14 bytes, while "ICC_PROFILE" is 11
+ final int preambleLength = 14;
// ICC data can be spread across multiple JPEG segments.
// We concat them together in this buffer for later processing.
byte[] buffer = null;
- for (byte[] segmentBytes : segments) {
+ for (JpegSegment segment : segments) {
// Skip any segments that do not contain the required preamble
- if (segmentBytes.length < preambleLength || !JPEG_SEGMENT_PREAMBLE.equalsIgnoreCase(new String(segmentBytes, 0, preambleLength)))
+ if (segment.getReader().getLength() < preambleLength || !JPEG_SEGMENT_ID.equalsIgnoreCase(segment.getPreamble()))
continue;
// NOTE we ignore three bytes here -- are they useful for anything?
+ ReaderInfo segmentReader = segment.getReader();
// Grow the buffer
if (buffer == null) {
- buffer = new byte[segmentBytes.length - 14];
+ buffer = new byte[(int)segmentReader.getLength() - preambleLength];
// skip the first 14 bytes
- System.arraycopy(segmentBytes, 14, buffer, 0, segmentBytes.length - 14);
+ System.arraycopy(segmentReader.toArray(), preambleLength, buffer, 0, (int)segmentReader.getLength() - preambleLength);
} else {
- byte[] newBuffer = new byte[buffer.length + segmentBytes.length - 14];
+ byte[] newBuffer = new byte[buffer.length + (int)segmentReader.getLength() - preambleLength];
System.arraycopy(buffer, 0, newBuffer, 0, buffer.length);
- System.arraycopy(segmentBytes, 14, newBuffer, buffer.length, segmentBytes.length - 14);
+ System.arraycopy(segmentReader.toArray(), preambleLength, newBuffer, buffer.length, (int)segmentReader.getLength() - preambleLength);
buffer = newBuffer;
}
}
if (buffer != null)
- extract(new ByteArrayReader(buffer), metadata);
+ extract(ReaderInfo.createFromArray(buffer), metadata);
}
- public void extract(@NotNull final RandomAccessReader reader, @NotNull final Metadata metadata)
+ public void extract(@NotNull ReaderInfo reader, @NotNull final Metadata metadata) throws IOException
{
extract(reader, metadata, null);
}
- public void extract(@NotNull final RandomAccessReader reader, @NotNull final Metadata metadata, @Nullable Directory parentDirectory)
+ public void extract(@NotNull ReaderInfo reader, @NotNull final Metadata metadata, @Nullable Directory parentDirectory) throws IOException
{
+ if (!reader.isMotorolaByteOrder())
+ reader = reader.Clone(false);
+
// TODO review whether the 'tagPtr' values below really do require RandomAccessReader or whether SequentialReader may be used instead
IccDirectory directory = new IccDirectory();
@@ -157,14 +162,14 @@ public void extract(@NotNull final RandomAccessReader reader, @NotNull final Met
metadata.addDirectory(directory);
}
- private void set4ByteString(@NotNull Directory directory, int tagType, @NotNull RandomAccessReader reader) throws IOException
+ private void set4ByteString(@NotNull Directory directory, int tagType, @NotNull ReaderInfo reader) throws IOException
{
int i = reader.getInt32(tagType);
if (i != 0)
directory.setString(tagType, getStringFromInt32(i));
}
- private void setInt32(@NotNull Directory directory, int tagType, @NotNull RandomAccessReader reader) throws IOException
+ private void setInt32(@NotNull Directory directory, int tagType, @NotNull ReaderInfo reader) throws IOException
{
int i = reader.getInt32(tagType);
if (i != 0)
@@ -172,7 +177,7 @@ private void setInt32(@NotNull Directory directory, int tagType, @NotNull Random
}
@SuppressWarnings({"SameParameterValue"})
- private void setInt64(@NotNull Directory directory, int tagType, @NotNull RandomAccessReader reader) throws IOException
+ private void setInt64(@NotNull Directory directory, int tagType, @NotNull ReaderInfo reader) throws IOException
{
long l = reader.getInt64(tagType);
if (l != 0)
@@ -180,7 +185,7 @@ private void setInt64(@NotNull Directory directory, int tagType, @NotNull Random
}
@SuppressWarnings({"SameParameterValue", "MagicConstant"})
- private void setDate(@NotNull final IccDirectory directory, final int tagType, @NotNull RandomAccessReader reader) throws IOException
+ private void setDate(@NotNull final IccDirectory directory, final int tagType, @NotNull ReaderInfo reader) throws IOException
{
final int y = reader.getUInt16(tagType);
final int m = reader.getUInt16(tagType + 2);
diff --git a/Source/com/drew/metadata/ico/IcoReader.java b/Source/com/drew/metadata/ico/IcoReader.java
index 49df0f2d1..7bb7b6323 100644
--- a/Source/com/drew/metadata/ico/IcoReader.java
+++ b/Source/com/drew/metadata/ico/IcoReader.java
@@ -20,7 +20,7 @@
*/
package com.drew.metadata.ico;
-import com.drew.lang.SequentialReader;
+import com.drew.lang.ReaderInfo;
import com.drew.lang.annotations.NotNull;
import com.drew.metadata.Metadata;
@@ -36,7 +36,7 @@
*/
public class IcoReader
{
- public void extract(@NotNull final SequentialReader reader, @NotNull final Metadata metadata)
+ public void extract(@NotNull ReaderInfo reader, @NotNull final Metadata metadata)
{
reader.setMotorolaByteOrder(false);
diff --git a/Source/com/drew/metadata/iptc/IptcReader.java b/Source/com/drew/metadata/iptc/IptcReader.java
index 7a21c0c2a..59d5d0524 100644
--- a/Source/com/drew/metadata/iptc/IptcReader.java
+++ b/Source/com/drew/metadata/iptc/IptcReader.java
@@ -22,8 +22,8 @@
import com.drew.imaging.jpeg.JpegSegmentMetadataReader;
import com.drew.imaging.jpeg.JpegSegmentType;
-import com.drew.lang.SequentialByteArrayReader;
-import com.drew.lang.SequentialReader;
+import com.drew.imaging.jpeg.JpegSegment;
+import com.drew.lang.ReaderInfo;
import com.drew.lang.annotations.NotNull;
import com.drew.lang.annotations.Nullable;
import com.drew.metadata.Directory;
@@ -65,12 +65,13 @@ public Iterable getSegmentTypes()
return Collections.singletonList(JpegSegmentType.APPD);
}
- public void readJpegSegments(@NotNull Iterable segments, @NotNull Metadata metadata, @NotNull JpegSegmentType segmentType)
+ @Override
+ public void readJpegSegments(@NotNull Iterable segments, @NotNull Metadata metadata) throws IOException
{
- for (byte[] segmentBytes : segments) {
+ for (JpegSegment segment : segments) {
// Ensure data starts with the IPTC marker byte
- if (segmentBytes.length != 0 && segmentBytes[0] == IptcMarkerByte) {
- extract(new SequentialByteArrayReader(segmentBytes), metadata, segmentBytes.length);
+ if (segment.getReader().getLength() != 0 && segment.getByteMarker() == IptcMarkerByte) {
+ extract(segment.getReader(), metadata);
}
}
}
@@ -78,16 +79,19 @@ public void readJpegSegments(@NotNull Iterable segments, @NotNull Metada
/**
* Performs the IPTC data extraction, adding found values to the specified instance of {@link Metadata}.
*/
- public void extract(@NotNull final SequentialReader reader, @NotNull final Metadata metadata, long length)
+ public void extract(@NotNull ReaderInfo reader, @NotNull final Metadata metadata) throws IOException
{
- extract(reader, metadata, length, null);
+ extract(reader, metadata, null);
}
/**
* Performs the IPTC data extraction, adding found values to the specified instance of {@link Metadata}.
*/
- public void extract(@NotNull final SequentialReader reader, @NotNull final Metadata metadata, long length, @Nullable Directory parentDirectory)
+ public void extract(@NotNull ReaderInfo reader, @NotNull final Metadata metadata, @Nullable Directory parentDirectory) throws IOException
{
+ if(!reader.isMotorolaByteOrder())
+ reader = reader.Clone(false);
+
IptcDirectory directory = new IptcDirectory();
metadata.addDirectory(directory);
@@ -97,7 +101,7 @@ public void extract(@NotNull final SequentialReader reader, @NotNull final Metad
int offset = 0;
// for each tag
- while (offset < length) {
+ while (offset < reader.getLength()) {
// identifies start of a tag
short startByte;
@@ -112,13 +116,13 @@ public void extract(@NotNull final SequentialReader reader, @NotNull final Metad
if (startByte != IptcMarkerByte) {
// NOTE have seen images where there was one extra byte at the end, giving
// offset==length at this point, which is not worth logging as an error.
- if (offset != length)
+ if (offset != reader.getLength())
directory.addError("Invalid IPTC tag marker at offset " + (offset - 1) + ". Expected '0x" + Integer.toHexString(IptcMarkerByte) + "' but got '0x" + Integer.toHexString(startByte) + "'.");
return;
}
// we need at least four bytes left to read a tag
- if (offset + 4 > length) {
+ if (offset + 4 > reader.getLength()) {
directory.addError("Too few bytes remain for a valid IPTC tag");
return;
}
@@ -141,7 +145,7 @@ public void extract(@NotNull final SequentialReader reader, @NotNull final Metad
return;
}
- if (offset + tagByteCount > length) {
+ if (offset + tagByteCount > reader.getLength()) {
directory.addError("Data for tag extends beyond end of IPTC segment");
return;
}
@@ -157,7 +161,7 @@ public void extract(@NotNull final SequentialReader reader, @NotNull final Metad
}
}
- private void processTag(@NotNull SequentialReader reader, @NotNull Directory directory, int directoryType, int tagType, int tagByteCount) throws IOException
+ private void processTag(@NotNull ReaderInfo reader, @NotNull Directory directory, int directoryType, int tagType, int tagByteCount) throws IOException
{
int tagIdentifier = tagType | (directoryType << 8);
diff --git a/Source/com/drew/metadata/jfif/JfifReader.java b/Source/com/drew/metadata/jfif/JfifReader.java
index 55db301a1..5d357c689 100644
--- a/Source/com/drew/metadata/jfif/JfifReader.java
+++ b/Source/com/drew/metadata/jfif/JfifReader.java
@@ -20,13 +20,12 @@
*/
package com.drew.metadata.jfif;
+import com.drew.imaging.jpeg.JpegSegment;
import com.drew.imaging.jpeg.JpegSegmentMetadataReader;
import com.drew.imaging.jpeg.JpegSegmentType;
-import com.drew.lang.ByteArrayReader;
-import com.drew.lang.RandomAccessReader;
+import com.drew.lang.ReaderInfo;
import com.drew.lang.annotations.NotNull;
import com.drew.metadata.Metadata;
-import com.drew.metadata.MetadataReader;
import java.io.IOException;
import java.util.Collections;
@@ -41,9 +40,10 @@
*
* @author Yuri Binev, Drew Noakes, Markus Meyer
*/
-public class JfifReader implements JpegSegmentMetadataReader, MetadataReader
+public class JfifReader implements JpegSegmentMetadataReader //, MetadataReader
{
- public static final String PREAMBLE = "JFIF";
+ public static final String JPEG_SEGMENT_ID = "JFIF";
+ public static final String JPEG_SEGMENT_PREAMBLE = "JFIF";
@NotNull
public Iterable getSegmentTypes()
@@ -51,12 +51,13 @@ public Iterable getSegmentTypes()
return Collections.singletonList(JpegSegmentType.APP0);
}
- public void readJpegSegments(@NotNull Iterable segments, @NotNull Metadata metadata, @NotNull JpegSegmentType segmentType)
+ @Override
+ public void readJpegSegments(@NotNull final Iterable segments, @NotNull Metadata metadata) throws IOException
{
- for (byte[] segmentBytes : segments) {
+ for (JpegSegment segment : segments) {
// Skip segments not starting with the required header
- if (segmentBytes.length >= PREAMBLE.length() && PREAMBLE.equals(new String(segmentBytes, 0, PREAMBLE.length())))
- extract(new ByteArrayReader(segmentBytes), metadata);
+ if (segment.getReader().getLength() >= JPEG_SEGMENT_PREAMBLE.length() && JPEG_SEGMENT_ID.equals(segment.getPreamble()))
+ extract(segment.getReader().Clone(segment.getReader().getLocalPosition(), -1), metadata);
}
}
@@ -64,7 +65,7 @@ public void readJpegSegments(@NotNull Iterable segments, @NotNull Metada
* Performs the Jfif data extraction, adding found values to the specified
* instance of {@link Metadata}.
*/
- public void extract(@NotNull final RandomAccessReader reader, @NotNull final Metadata metadata)
+ public void extract(@NotNull ReaderInfo reader, @NotNull final Metadata metadata)
{
JfifDirectory directory = new JfifDirectory();
metadata.addDirectory(directory);
diff --git a/Source/com/drew/metadata/jfxx/JfxxReader.java b/Source/com/drew/metadata/jfxx/JfxxReader.java
index ca68ad9c7..770d51eca 100644
--- a/Source/com/drew/metadata/jfxx/JfxxReader.java
+++ b/Source/com/drew/metadata/jfxx/JfxxReader.java
@@ -22,11 +22,10 @@
import com.drew.imaging.jpeg.JpegSegmentMetadataReader;
import com.drew.imaging.jpeg.JpegSegmentType;
-import com.drew.lang.ByteArrayReader;
-import com.drew.lang.RandomAccessReader;
+import com.drew.imaging.jpeg.JpegSegment;
+import com.drew.lang.ReaderInfo;
import com.drew.lang.annotations.NotNull;
import com.drew.metadata.Metadata;
-import com.drew.metadata.MetadataReader;
import java.io.IOException;
import java.util.Collections;
@@ -41,9 +40,10 @@
*
* @author Drew Noakes
*/
-public class JfxxReader implements JpegSegmentMetadataReader, MetadataReader
+public class JfxxReader implements JpegSegmentMetadataReader //, MetadataReader
{
- public static final String PREAMBLE = "JFXX";
+ public static final String JPEG_SEGMENT_ID = "JFXX";
+ public static final String JPEG_SEGMENT_PREAMBLE = "JFXX";
@NotNull
public Iterable getSegmentTypes()
@@ -51,12 +51,12 @@ public Iterable getSegmentTypes()
return Collections.singletonList(JpegSegmentType.APP0);
}
- public void readJpegSegments(@NotNull Iterable segments, @NotNull Metadata metadata, @NotNull JpegSegmentType segmentType)
+ public void readJpegSegments(@NotNull Iterable segments, @NotNull Metadata metadata) throws IOException
{
- for (byte[] segmentBytes : segments) {
+ for (JpegSegment segment : segments) {
// Skip segments not starting with the required header
- if (segmentBytes.length >= PREAMBLE.length() && PREAMBLE.equals(new String(segmentBytes, 0, PREAMBLE.length())))
- extract(new ByteArrayReader(segmentBytes), metadata);
+ if (segment.getReader().getLength() >= JPEG_SEGMENT_PREAMBLE.length() && segment.getPreamble() == JPEG_SEGMENT_ID)
+ extract(segment.getReader(), metadata);
}
}
@@ -64,7 +64,7 @@ public void readJpegSegments(@NotNull Iterable segments, @NotNull Metada
* Performs the JFXX data extraction, adding found values to the specified
* instance of {@link Metadata}.
*/
- public void extract(@NotNull final RandomAccessReader reader, @NotNull final Metadata metadata)
+ public void extract(@NotNull ReaderInfo reader, @NotNull final Metadata metadata)
{
JfxxDirectory directory = new JfxxDirectory();
metadata.addDirectory(directory);
diff --git a/Source/com/drew/metadata/jpeg/JpegCommentReader.java b/Source/com/drew/metadata/jpeg/JpegCommentReader.java
index 8170ba5f2..5abb7766a 100644
--- a/Source/com/drew/metadata/jpeg/JpegCommentReader.java
+++ b/Source/com/drew/metadata/jpeg/JpegCommentReader.java
@@ -22,11 +22,13 @@
import com.drew.imaging.jpeg.JpegSegmentMetadataReader;
import com.drew.imaging.jpeg.JpegSegmentType;
+import com.drew.imaging.jpeg.JpegSegment;
import com.drew.lang.annotations.NotNull;
import com.drew.metadata.Metadata;
import com.drew.metadata.StringValue;
import java.util.Collections;
+import java.io.IOException;
/**
* Decodes the comment stored within JPEG files, populating a {@link Metadata} object with tag values in a
@@ -37,19 +39,21 @@
public class JpegCommentReader implements JpegSegmentMetadataReader
{
@NotNull
+ @Override
public Iterable getSegmentTypes()
{
return Collections.singletonList(JpegSegmentType.COM);
}
- public void readJpegSegments(@NotNull Iterable segments, @NotNull Metadata metadata, @NotNull JpegSegmentType segmentType)
+ @Override
+ public void readJpegSegments(@NotNull Iterable segments, @NotNull Metadata metadata) throws IOException
{
- for (byte[] segmentBytes : segments) {
+ for (JpegSegment segment : segments) {
JpegCommentDirectory directory = new JpegCommentDirectory();
metadata.addDirectory(directory);
// The entire contents of the directory are the comment
- directory.setStringValue(JpegCommentDirectory.TAG_COMMENT, new StringValue(segmentBytes, null));
+ directory.setStringValue(JpegCommentDirectory.TAG_COMMENT, new StringValue(segment.getReader().toArray(), null));
}
}
}
diff --git a/Source/com/drew/metadata/jpeg/JpegDhtReader.java b/Source/com/drew/metadata/jpeg/JpegDhtReader.java
index f8f769151..61b8ade5f 100644
--- a/Source/com/drew/metadata/jpeg/JpegDhtReader.java
+++ b/Source/com/drew/metadata/jpeg/JpegDhtReader.java
@@ -22,8 +22,8 @@
import com.drew.imaging.jpeg.JpegSegmentMetadataReader;
import com.drew.imaging.jpeg.JpegSegmentType;
-import com.drew.lang.SequentialByteArrayReader;
-import com.drew.lang.SequentialReader;
+import com.drew.imaging.jpeg.JpegSegment;
+import com.drew.lang.ReaderInfo;
import com.drew.lang.annotations.NotNull;
import com.drew.metadata.Metadata;
import com.drew.metadata.jpeg.HuffmanTablesDirectory.HuffmanTable;
@@ -39,15 +39,17 @@
public class JpegDhtReader implements JpegSegmentMetadataReader
{
@NotNull
+ @Override
public Iterable getSegmentTypes()
{
return Collections.singletonList(JpegSegmentType.DHT);
}
- public void readJpegSegments(@NotNull Iterable segments, @NotNull Metadata metadata, @NotNull JpegSegmentType segmentType)
+ @Override
+ public void readJpegSegments(@NotNull Iterable segments, @NotNull Metadata metadata)
{
- for (byte[] segmentBytes : segments) {
- extract(new SequentialByteArrayReader(segmentBytes), metadata);
+ for (JpegSegment segment : segments) {
+ extract(segment.getReader(), metadata);
}
}
@@ -55,7 +57,7 @@ public void readJpegSegments(@NotNull Iterable segments, @NotNull Metada
* Performs the DHT tables extraction, adding found tables to the specified
* instance of {@link Metadata}.
*/
- public void extract(@NotNull final SequentialReader reader, @NotNull final Metadata metadata)
+ public void extract(@NotNull ReaderInfo reader, @NotNull final Metadata metadata)
{
HuffmanTablesDirectory directory = metadata.getFirstDirectoryOfType(HuffmanTablesDirectory.class);
if (directory == null) {
@@ -64,7 +66,7 @@ public void extract(@NotNull final SequentialReader reader, @NotNull final Metad
}
try {
- while (reader.available() > 0) {
+ while (!reader.isCloserToEnd(1)) {
byte header = reader.getByte();
HuffmanTableClass tableClass = HuffmanTableClass.typeOf((header & 0xF0) >> 4);
int tableDestinationId = header & 0xF;
@@ -84,7 +86,7 @@ public void extract(@NotNull final SequentialReader reader, @NotNull final Metad
directory.setInt(HuffmanTablesDirectory.TAG_NUMBER_OF_TABLES, directory.getTables().size());
}
- private byte[] getBytes(@NotNull final SequentialReader reader, int count) throws IOException {
+ private byte[] getBytes(@NotNull ReaderInfo reader, int count) throws IOException {
byte[] bytes = new byte[count];
for (int i = 0; i < count; i++) {
byte b = reader.getByte();
diff --git a/Source/com/drew/metadata/jpeg/JpegDnlReader.java b/Source/com/drew/metadata/jpeg/JpegDnlReader.java
index 6fc348747..3a855b7d7 100644
--- a/Source/com/drew/metadata/jpeg/JpegDnlReader.java
+++ b/Source/com/drew/metadata/jpeg/JpegDnlReader.java
@@ -22,8 +22,8 @@
import com.drew.imaging.jpeg.JpegSegmentMetadataReader;
import com.drew.imaging.jpeg.JpegSegmentType;
-import com.drew.lang.SequentialByteArrayReader;
-import com.drew.lang.SequentialReader;
+import com.drew.imaging.jpeg.JpegSegment;
+import com.drew.lang.ReaderInfo;
import com.drew.lang.annotations.NotNull;
import com.drew.metadata.ErrorDirectory;
import com.drew.metadata.Metadata;
@@ -39,19 +39,21 @@
public class JpegDnlReader implements JpegSegmentMetadataReader
{
@NotNull
+ @Override
public Iterable getSegmentTypes()
{
return Collections.singletonList(JpegSegmentType.DNL);
}
- public void readJpegSegments(@NotNull Iterable segments, @NotNull Metadata metadata, @NotNull JpegSegmentType segmentType)
+ @Override
+ public void readJpegSegments(@NotNull Iterable segments, @NotNull Metadata metadata) throws IOException
{
- for (byte[] segmentBytes : segments) {
- extract(segmentBytes, metadata, segmentType);
+ for (JpegSegment segment : segments) {
+ extract(segment.getReader().Clone(), metadata);
}
}
- public void extract(byte[] segmentBytes, Metadata metadata, JpegSegmentType segmentType)
+ public void extract(ReaderInfo reader, Metadata metadata)
{
JpegDirectory directory = metadata.getFirstDirectoryOfType(JpegDirectory.class);
if (directory == null) {
@@ -61,8 +63,6 @@ public void extract(byte[] segmentBytes, Metadata metadata, JpegSegmentType segm
return;
}
- SequentialReader reader = new SequentialByteArrayReader(segmentBytes);
-
try {
// Only set height from DNL if it's not already defined
Integer i = directory.getInteger(JpegDirectory.TAG_IMAGE_HEIGHT);
diff --git a/Source/com/drew/metadata/jpeg/JpegReader.java b/Source/com/drew/metadata/jpeg/JpegReader.java
index 9e6bf6619..58c56e811 100644
--- a/Source/com/drew/metadata/jpeg/JpegReader.java
+++ b/Source/com/drew/metadata/jpeg/JpegReader.java
@@ -20,10 +20,10 @@
*/
package com.drew.metadata.jpeg;
+import com.drew.imaging.jpeg.JpegSegment;
import com.drew.imaging.jpeg.JpegSegmentMetadataReader;
import com.drew.imaging.jpeg.JpegSegmentType;
-import com.drew.lang.SequentialByteArrayReader;
-import com.drew.lang.SequentialReader;
+import com.drew.lang.ReaderInfo;
import com.drew.lang.annotations.NotNull;
import com.drew.metadata.Metadata;
@@ -62,23 +62,24 @@ public Iterable getSegmentTypes()
);
}
- public void readJpegSegments(@NotNull Iterable segments, @NotNull Metadata metadata, @NotNull JpegSegmentType segmentType)
+ @Override
+ public void readJpegSegments(@NotNull Iterable segments, @NotNull Metadata metadata) //, @NotNull JpegSegmentType segmentType)
{
- for (byte[] segmentBytes : segments) {
- extract(segmentBytes, metadata, segmentType);
+ for (JpegSegment segment : segments) {
+ extract(segment, metadata); //, segmentType);
}
}
- public void extract(byte[] segmentBytes, Metadata metadata, JpegSegmentType segmentType)
+ public void extract(JpegSegment segment, Metadata metadata) //, JpegSegmentType segmentType)
{
JpegDirectory directory = new JpegDirectory();
metadata.addDirectory(directory);
// The value of TAG_COMPRESSION_TYPE is determined by the segment type found
- directory.setInt(JpegDirectory.TAG_COMPRESSION_TYPE, segmentType.byteValue - JpegSegmentType.SOF0.byteValue);
-
- SequentialReader reader = new SequentialByteArrayReader(segmentBytes);
+ directory.setInt(JpegDirectory.TAG_COMPRESSION_TYPE, segment.getType().byteValue - JpegSegmentType.SOF0.byteValue);
+ ReaderInfo reader = segment.getReader();
+
try {
directory.setInt(JpegDirectory.TAG_DATA_PRECISION, reader.getUInt8());
directory.setInt(JpegDirectory.TAG_IMAGE_HEIGHT, reader.getUInt16());
diff --git a/Source/com/drew/metadata/mov/QuickTimeAtomHandler.java b/Source/com/drew/metadata/mov/QuickTimeAtomHandler.java
index c5dbac2b7..bbd3adf72 100644
--- a/Source/com/drew/metadata/mov/QuickTimeAtomHandler.java
+++ b/Source/com/drew/metadata/mov/QuickTimeAtomHandler.java
@@ -21,8 +21,7 @@
package com.drew.metadata.mov;
import com.drew.imaging.quicktime.QuickTimeHandler;
-import com.drew.lang.SequentialByteArrayReader;
-import com.drew.lang.SequentialReader;
+import com.drew.lang.ReaderInfo;
import com.drew.lang.annotations.NotNull;
import com.drew.lang.annotations.Nullable;
import com.drew.metadata.Metadata;
@@ -72,7 +71,7 @@ public boolean shouldAcceptContainer(@NotNull Atom atom)
public QuickTimeHandler processAtom(@NotNull Atom atom, @Nullable byte[] payload) throws IOException
{
if (payload != null) {
- SequentialReader reader = new SequentialByteArrayReader(payload);
+ ReaderInfo reader = ReaderInfo.createFromArray(payload);
if (atom.type.equals(QuickTimeAtomTypes.ATOM_MOVIE_HEADER)) {
MovieHeaderAtom movieHeaderAtom = new MovieHeaderAtom(reader, atom);
diff --git a/Source/com/drew/metadata/mov/QuickTimeMediaHandler.java b/Source/com/drew/metadata/mov/QuickTimeMediaHandler.java
index 8dfc53dc0..7fa38436e 100644
--- a/Source/com/drew/metadata/mov/QuickTimeMediaHandler.java
+++ b/Source/com/drew/metadata/mov/QuickTimeMediaHandler.java
@@ -21,8 +21,7 @@
package com.drew.metadata.mov;
import com.drew.imaging.quicktime.QuickTimeHandler;
-import com.drew.lang.SequentialByteArrayReader;
-import com.drew.lang.SequentialReader;
+import com.drew.lang.ReaderInfo;
import com.drew.lang.annotations.NotNull;
import com.drew.lang.annotations.Nullable;
import com.drew.metadata.Metadata;
@@ -78,7 +77,7 @@ public boolean shouldAcceptContainer(@NotNull Atom atom)
public QuickTimeMediaHandler processAtom(@NotNull Atom atom, @Nullable byte[] payload) throws IOException
{
if (payload != null) {
- SequentialReader reader = new SequentialByteArrayReader(payload);
+ ReaderInfo reader = ReaderInfo.createFromArray(payload);
if (atom.type.equals(getMediaInformation())) {
processMediaInformation(reader, atom);
} else if (atom.type.equals(QuickTimeAtomTypes.ATOM_SAMPLE_DESCRIPTION)) {
@@ -92,9 +91,9 @@ public QuickTimeMediaHandler processAtom(@NotNull Atom atom, @Nullable byte[] pa
protected abstract String getMediaInformation();
- protected abstract void processSampleDescription(@NotNull SequentialReader reader, @NotNull Atom atom) throws IOException;
+ protected abstract void processSampleDescription(@NotNull ReaderInfo reader, @NotNull Atom atom) throws IOException;
- protected abstract void processMediaInformation(@NotNull SequentialReader reader, @NotNull Atom atom) throws IOException;
+ protected abstract void processMediaInformation(@NotNull ReaderInfo reader, @NotNull Atom atom) throws IOException;
- protected abstract void processTimeToSample(@NotNull SequentialReader reader, @NotNull Atom atom) throws IOException;
+ protected abstract void processTimeToSample(@NotNull ReaderInfo reader, @NotNull Atom atom) throws IOException;
}
diff --git a/Source/com/drew/metadata/mov/QuickTimeMetadataHandler.java b/Source/com/drew/metadata/mov/QuickTimeMetadataHandler.java
index 55d4da4eb..dab78f6ad 100644
--- a/Source/com/drew/metadata/mov/QuickTimeMetadataHandler.java
+++ b/Source/com/drew/metadata/mov/QuickTimeMetadataHandler.java
@@ -21,7 +21,7 @@
package com.drew.metadata.mov;
import com.drew.imaging.quicktime.QuickTimeHandler;
-import com.drew.lang.SequentialByteArrayReader;
+import com.drew.lang.ReaderInfo;
import com.drew.lang.annotations.NotNull;
import com.drew.lang.annotations.Nullable;
import com.drew.metadata.Metadata;
@@ -65,7 +65,7 @@ protected boolean shouldAcceptContainer(@NotNull Atom atom)
protected QuickTimeHandler processAtom(@NotNull Atom atom, @Nullable byte[] payload) throws IOException
{
if (payload != null) {
- SequentialByteArrayReader reader = new SequentialByteArrayReader(payload);
+ ReaderInfo reader = ReaderInfo.createFromArray(payload);
if (atom.type.equals(QuickTimeAtomTypes.ATOM_KEYS)) {
processKeys(reader);
} else if (atom.type.equals(QuickTimeAtomTypes.ATOM_DATA)) {
@@ -75,7 +75,7 @@ protected QuickTimeHandler processAtom(@NotNull Atom atom, @Nullable byte[] payl
return this;
}
- protected abstract void processKeys(@NotNull SequentialByteArrayReader reader) throws IOException;
+ protected abstract void processKeys(@NotNull ReaderInfo reader) throws IOException;
- protected abstract void processData(@NotNull byte[] payload, @NotNull SequentialByteArrayReader reader) throws IOException;
+ protected abstract void processData(@NotNull byte[] payload, @NotNull ReaderInfo reader) throws IOException;
}
diff --git a/Source/com/drew/metadata/mov/atoms/Atom.java b/Source/com/drew/metadata/mov/atoms/Atom.java
index cc0b1b631..982784d79 100644
--- a/Source/com/drew/metadata/mov/atoms/Atom.java
+++ b/Source/com/drew/metadata/mov/atoms/Atom.java
@@ -20,7 +20,8 @@
*/
package com.drew.metadata.mov.atoms;
-import com.drew.lang.SequentialReader;
+import com.drew.lang.Charsets;
+import com.drew.lang.ReaderInfo;
import java.io.IOException;
@@ -34,10 +35,10 @@ public class Atom
public long size;
public String type;
- public Atom(SequentialReader reader) throws IOException
+ public Atom(ReaderInfo reader) throws IOException
{
this.size = reader.getUInt32();
- this.type = reader.getString(4);
+ this.type = reader.getString(4, Charsets.ASCII);
if (size == 1) {
size = reader.getInt64();
} else if (size == 0) {
diff --git a/Source/com/drew/metadata/mov/atoms/FileTypeCompatibilityAtom.java b/Source/com/drew/metadata/mov/atoms/FileTypeCompatibilityAtom.java
index e0dcefaaf..4447c4010 100644
--- a/Source/com/drew/metadata/mov/atoms/FileTypeCompatibilityAtom.java
+++ b/Source/com/drew/metadata/mov/atoms/FileTypeCompatibilityAtom.java
@@ -20,7 +20,8 @@
*/
package com.drew.metadata.mov.atoms;
-import com.drew.lang.SequentialReader;
+import com.drew.lang.Charsets;
+import com.drew.lang.ReaderInfo;
import com.drew.metadata.mov.QuickTimeDirectory;
import java.io.IOException;
@@ -37,15 +38,15 @@ public class FileTypeCompatibilityAtom extends Atom
long minorVersion;
ArrayList compatibleBrands;
- public FileTypeCompatibilityAtom(SequentialReader reader, Atom atom) throws IOException
+ public FileTypeCompatibilityAtom(ReaderInfo reader, Atom atom) throws IOException
{
super(atom);
- majorBrand = reader.getString(4);
+ majorBrand = reader.getString(4, Charsets.UTF_8);
minorVersion = reader.getUInt32();
compatibleBrands = new ArrayList((int) ((size/16)>>2));
for (int i = 16; i < size; i += 4) {
- compatibleBrands.add(reader.getString(4));
+ compatibleBrands.add(reader.getString(4, Charsets.UTF_8));
}
}
diff --git a/Source/com/drew/metadata/mov/atoms/FullAtom.java b/Source/com/drew/metadata/mov/atoms/FullAtom.java
index e2383485f..fd177601e 100644
--- a/Source/com/drew/metadata/mov/atoms/FullAtom.java
+++ b/Source/com/drew/metadata/mov/atoms/FullAtom.java
@@ -20,7 +20,7 @@
*/
package com.drew.metadata.mov.atoms;
-import com.drew.lang.SequentialReader;
+import com.drew.lang.ReaderInfo;
import java.io.IOException;
@@ -34,7 +34,7 @@ public class FullAtom extends Atom
int version;
byte[] flags;
- public FullAtom(SequentialReader reader, Atom atom) throws IOException
+ public FullAtom(ReaderInfo reader, Atom atom) throws IOException
{
super(atom);
diff --git a/Source/com/drew/metadata/mov/atoms/HandlerReferenceAtom.java b/Source/com/drew/metadata/mov/atoms/HandlerReferenceAtom.java
index 4f0bf83c4..b5cd7d85e 100644
--- a/Source/com/drew/metadata/mov/atoms/HandlerReferenceAtom.java
+++ b/Source/com/drew/metadata/mov/atoms/HandlerReferenceAtom.java
@@ -20,7 +20,8 @@
*/
package com.drew.metadata.mov.atoms;
-import com.drew.lang.SequentialReader;
+import com.drew.lang.Charsets;
+import com.drew.lang.ReaderInfo;
import java.io.IOException;
@@ -40,15 +41,15 @@ public String getComponentType()
String componentSubtype;
String componentName;
- public HandlerReferenceAtom(SequentialReader reader, Atom atom) throws IOException
+ public HandlerReferenceAtom(ReaderInfo reader, Atom atom) throws IOException
{
super(reader, atom);
- componentType = reader.getString(4);
- componentSubtype = reader.getString(4);
+ componentType = reader.getString(4, Charsets.UTF_8);
+ componentSubtype = reader.getString(4, Charsets.UTF_8);
reader.skip(4); // Reserved
reader.skip(4); // Reserved
reader.skip(4); // Reserved
- componentName = reader.getString(reader.getUInt8());
+ componentName = reader.getString(reader.getUInt8(), Charsets.UTF_8);
}
}
diff --git a/Source/com/drew/metadata/mov/atoms/MediaHeaderAtom.java b/Source/com/drew/metadata/mov/atoms/MediaHeaderAtom.java
index 28343653d..4e7c7888c 100644
--- a/Source/com/drew/metadata/mov/atoms/MediaHeaderAtom.java
+++ b/Source/com/drew/metadata/mov/atoms/MediaHeaderAtom.java
@@ -20,7 +20,7 @@
*/
package com.drew.metadata.mov.atoms;
-import com.drew.lang.SequentialReader;
+import com.drew.lang.ReaderInfo;
import com.drew.metadata.mov.QuickTimeHandlerFactory;
import java.io.IOException;
@@ -39,7 +39,7 @@ public class MediaHeaderAtom extends FullAtom
int language;
int quality;
- public MediaHeaderAtom(SequentialReader reader, Atom atom) throws IOException
+ public MediaHeaderAtom(ReaderInfo reader, Atom atom) throws IOException
{
super(reader, atom);
diff --git a/Source/com/drew/metadata/mov/atoms/MovieHeaderAtom.java b/Source/com/drew/metadata/mov/atoms/MovieHeaderAtom.java
index 1cfd2aecc..315afccdb 100644
--- a/Source/com/drew/metadata/mov/atoms/MovieHeaderAtom.java
+++ b/Source/com/drew/metadata/mov/atoms/MovieHeaderAtom.java
@@ -21,7 +21,7 @@
package com.drew.metadata.mov.atoms;
import com.drew.lang.Rational;
-import com.drew.lang.SequentialReader;
+import com.drew.lang.ReaderInfo;
import com.drew.metadata.mov.QuickTimeDirectory;
import java.io.IOException;
@@ -52,7 +52,7 @@ public class MovieHeaderAtom extends FullAtom
long currentTime;
long nextTrackID;
- public MovieHeaderAtom(SequentialReader reader, Atom atom) throws IOException
+ public MovieHeaderAtom(ReaderInfo reader, Atom atom) throws IOException
{
super(reader, atom);
diff --git a/Source/com/drew/metadata/mov/atoms/MusicSampleDescriptionAtom.java b/Source/com/drew/metadata/mov/atoms/MusicSampleDescriptionAtom.java
index 1369fc6e0..4560e37d9 100644
--- a/Source/com/drew/metadata/mov/atoms/MusicSampleDescriptionAtom.java
+++ b/Source/com/drew/metadata/mov/atoms/MusicSampleDescriptionAtom.java
@@ -20,7 +20,7 @@
*/
package com.drew.metadata.mov.atoms;
-import com.drew.lang.SequentialReader;
+import com.drew.lang.ReaderInfo;
import com.drew.metadata.mov.media.QuickTimeMusicDirectory;
import java.io.IOException;
@@ -32,13 +32,13 @@
*/
public class MusicSampleDescriptionAtom extends SampleDescriptionAtom
{
- public MusicSampleDescriptionAtom(SequentialReader reader, Atom atom) throws IOException
+ public MusicSampleDescriptionAtom(ReaderInfo reader, Atom atom) throws IOException
{
super(reader, atom);
}
@Override
- MusicSampleDescription getSampleDescription(SequentialReader reader) throws IOException
+ MusicSampleDescription getSampleDescription(ReaderInfo reader) throws IOException
{
return new MusicSampleDescription(reader);
}
@@ -52,7 +52,7 @@ class MusicSampleDescription extends SampleDescription
{
long flags;
- public MusicSampleDescription(SequentialReader reader) throws IOException
+ public MusicSampleDescription(ReaderInfo reader) throws IOException
{
super(reader);
diff --git a/Source/com/drew/metadata/mov/atoms/SampleDescription.java b/Source/com/drew/metadata/mov/atoms/SampleDescription.java
index 9fe4188fa..f59b04432 100644
--- a/Source/com/drew/metadata/mov/atoms/SampleDescription.java
+++ b/Source/com/drew/metadata/mov/atoms/SampleDescription.java
@@ -20,7 +20,8 @@
*/
package com.drew.metadata.mov.atoms;
-import com.drew.lang.SequentialReader;
+import com.drew.lang.Charsets;
+import com.drew.lang.ReaderInfo;
import java.io.IOException;
@@ -35,10 +36,10 @@ public class SampleDescription
String dataFormat;
int dataReferenceIndex;
- public SampleDescription(SequentialReader reader) throws IOException
+ public SampleDescription(ReaderInfo reader) throws IOException
{
sampleDescriptionSize = reader.getUInt32();
- dataFormat = reader.getString(4);
+ dataFormat = reader.getString(4, Charsets.UTF_8);
reader.skip(6); // Reserved
dataReferenceIndex = reader.getUInt16();
}
diff --git a/Source/com/drew/metadata/mov/atoms/SampleDescriptionAtom.java b/Source/com/drew/metadata/mov/atoms/SampleDescriptionAtom.java
index a1b2e27d2..28e33ee19 100644
--- a/Source/com/drew/metadata/mov/atoms/SampleDescriptionAtom.java
+++ b/Source/com/drew/metadata/mov/atoms/SampleDescriptionAtom.java
@@ -20,7 +20,7 @@
*/
package com.drew.metadata.mov.atoms;
-import com.drew.lang.SequentialReader;
+import com.drew.lang.ReaderInfo;;
import com.drew.lang.annotations.Nullable;
import java.io.IOException;
@@ -36,7 +36,7 @@ public abstract class SampleDescriptionAtom extends
long numberOfEntries;
ArrayList sampleDescriptions;
- public SampleDescriptionAtom(SequentialReader reader, Atom atom) throws IOException
+ public SampleDescriptionAtom(ReaderInfo reader, Atom atom) throws IOException
{
super(reader, atom);
@@ -48,5 +48,5 @@ public SampleDescriptionAtom(SequentialReader reader, Atom atom) throws IOExcept
}
@Nullable
- abstract T getSampleDescription(SequentialReader reader) throws IOException;
+ abstract T getSampleDescription(ReaderInfo reader) throws IOException;
}
diff --git a/Source/com/drew/metadata/mov/atoms/SoundInformationMediaHeaderAtom.java b/Source/com/drew/metadata/mov/atoms/SoundInformationMediaHeaderAtom.java
index 4566db16b..da283bfbd 100644
--- a/Source/com/drew/metadata/mov/atoms/SoundInformationMediaHeaderAtom.java
+++ b/Source/com/drew/metadata/mov/atoms/SoundInformationMediaHeaderAtom.java
@@ -20,7 +20,7 @@
*/
package com.drew.metadata.mov.atoms;
-import com.drew.lang.SequentialReader;
+import com.drew.lang.ReaderInfo;
import com.drew.metadata.mov.media.QuickTimeSoundDirectory;
import java.io.IOException;
@@ -34,7 +34,7 @@ public class SoundInformationMediaHeaderAtom extends FullAtom
{
int balance;
- public SoundInformationMediaHeaderAtom(SequentialReader reader, Atom atom) throws IOException
+ public SoundInformationMediaHeaderAtom(ReaderInfo reader, Atom atom) throws IOException
{
super(reader, atom);
diff --git a/Source/com/drew/metadata/mov/atoms/SoundSampleDescriptionAtom.java b/Source/com/drew/metadata/mov/atoms/SoundSampleDescriptionAtom.java
index 0112753e7..08bd9da51 100644
--- a/Source/com/drew/metadata/mov/atoms/SoundSampleDescriptionAtom.java
+++ b/Source/com/drew/metadata/mov/atoms/SoundSampleDescriptionAtom.java
@@ -20,7 +20,7 @@
*/
package com.drew.metadata.mov.atoms;
-import com.drew.lang.SequentialReader;
+import com.drew.lang.ReaderInfo;
import com.drew.metadata.mov.QuickTimeDictionary;
import com.drew.metadata.mov.media.QuickTimeSoundDirectory;
@@ -33,13 +33,13 @@
*/
public class SoundSampleDescriptionAtom extends SampleDescriptionAtom
{
- public SoundSampleDescriptionAtom(SequentialReader reader, Atom atom) throws IOException
+ public SoundSampleDescriptionAtom(ReaderInfo reader, Atom atom) throws IOException
{
super(reader, atom);
}
@Override
- SoundSampleDescription getSampleDescription(SequentialReader reader) throws IOException
+ SoundSampleDescription getSampleDescription(ReaderInfo reader) throws IOException
{
return new SoundSampleDescription(reader);
}
@@ -64,7 +64,7 @@ class SoundSampleDescription extends SampleDescription
int packetSize;
long sampleRate;
- public SoundSampleDescription(SequentialReader reader) throws IOException
+ public SoundSampleDescription(ReaderInfo reader) throws IOException
{
super(reader);
diff --git a/Source/com/drew/metadata/mov/atoms/SubtitleSampleDescriptionAtom.java b/Source/com/drew/metadata/mov/atoms/SubtitleSampleDescriptionAtom.java
index 805417e58..ff5639d81 100644
--- a/Source/com/drew/metadata/mov/atoms/SubtitleSampleDescriptionAtom.java
+++ b/Source/com/drew/metadata/mov/atoms/SubtitleSampleDescriptionAtom.java
@@ -20,7 +20,7 @@
*/
package com.drew.metadata.mov.atoms;
-import com.drew.lang.SequentialReader;
+import com.drew.lang.ReaderInfo;
import com.drew.metadata.mov.media.QuickTimeSubtitleDirectory;
import java.io.IOException;
@@ -32,13 +32,13 @@
*/
public class SubtitleSampleDescriptionAtom extends SampleDescriptionAtom
{
- public SubtitleSampleDescriptionAtom(SequentialReader reader, Atom atom) throws IOException
+ public SubtitleSampleDescriptionAtom(ReaderInfo reader, Atom atom) throws IOException
{
super(reader, atom);
}
@Override
- SubtitleSampleDescription getSampleDescription(SequentialReader reader) throws IOException
+ SubtitleSampleDescription getSampleDescription(ReaderInfo reader) throws IOException
{
return null;
}
@@ -52,7 +52,7 @@ class SubtitleSampleDescription extends SampleDescription
int fontSize;
int[] foregroundColor;
- public SubtitleSampleDescription(SequentialReader reader) throws IOException
+ public SubtitleSampleDescription(ReaderInfo reader) throws IOException
{
super(reader);
diff --git a/Source/com/drew/metadata/mov/atoms/TextSampleDescriptionAtom.java b/Source/com/drew/metadata/mov/atoms/TextSampleDescriptionAtom.java
index afdbcf6a9..c6a5084ec 100644
--- a/Source/com/drew/metadata/mov/atoms/TextSampleDescriptionAtom.java
+++ b/Source/com/drew/metadata/mov/atoms/TextSampleDescriptionAtom.java
@@ -20,7 +20,8 @@
*/
package com.drew.metadata.mov.atoms;
-import com.drew.lang.SequentialReader;
+import com.drew.lang.Charsets;
+import com.drew.lang.ReaderInfo;
import com.drew.metadata.mov.media.QuickTimeTextDirectory;
import java.io.IOException;
@@ -32,13 +33,13 @@
*/
public class TextSampleDescriptionAtom extends SampleDescriptionAtom
{
- public TextSampleDescriptionAtom(SequentialReader reader, Atom atom) throws IOException
+ public TextSampleDescriptionAtom(ReaderInfo reader, Atom atom) throws IOException
{
super(reader, atom);
}
@Override
- TextSampleDescription getSampleDescription(SequentialReader reader) throws IOException
+ TextSampleDescription getSampleDescription(ReaderInfo reader) throws IOException
{
return new TextSampleDescription(reader);
}
@@ -120,7 +121,7 @@ class TextSampleDescription extends SampleDescription
int[] foregroundColor;
String textName;
- public TextSampleDescription(SequentialReader reader) throws IOException
+ public TextSampleDescription(ReaderInfo reader) throws IOException
{
super(reader);
@@ -134,7 +135,7 @@ public TextSampleDescription(SequentialReader reader) throws IOException
reader.skip(1); // 8-bits of reserved space set to 0
reader.skip(2); // 16-bits of reserved space set to 0
foregroundColor = new int[]{reader.getUInt16(), reader.getUInt16(), reader.getUInt16()};
- textName = reader.getString(reader.getUInt8());
+ textName = reader.getString(reader.getUInt8(), Charsets.UTF_8);
}
}
}
diff --git a/Source/com/drew/metadata/mov/atoms/TimeToSampleAtom.java b/Source/com/drew/metadata/mov/atoms/TimeToSampleAtom.java
index f06294c33..73905cab6 100644
--- a/Source/com/drew/metadata/mov/atoms/TimeToSampleAtom.java
+++ b/Source/com/drew/metadata/mov/atoms/TimeToSampleAtom.java
@@ -20,7 +20,7 @@
*/
package com.drew.metadata.mov.atoms;
-import com.drew.lang.SequentialReader;
+import com.drew.lang.ReaderInfo;
import com.drew.metadata.mov.QuickTimeHandlerFactory;
import com.drew.metadata.mov.media.QuickTimeVideoDirectory;
@@ -39,7 +39,7 @@ public class TimeToSampleAtom extends FullAtom
long sampleCount;
long sampleDuration;
- public TimeToSampleAtom(SequentialReader reader, Atom atom) throws IOException
+ public TimeToSampleAtom(ReaderInfo reader, Atom atom) throws IOException
{
super(reader, atom);
@@ -55,7 +55,7 @@ class Entry
long sampleCount;
long sampleDuration;
- public Entry(SequentialReader reader) throws IOException
+ public Entry(ReaderInfo reader) throws IOException
{
sampleCount = reader.getUInt32();
sampleDuration = reader.getUInt32();
diff --git a/Source/com/drew/metadata/mov/atoms/TimecodeInformationMediaAtom.java b/Source/com/drew/metadata/mov/atoms/TimecodeInformationMediaAtom.java
index d12a42ec7..a72160819 100644
--- a/Source/com/drew/metadata/mov/atoms/TimecodeInformationMediaAtom.java
+++ b/Source/com/drew/metadata/mov/atoms/TimecodeInformationMediaAtom.java
@@ -20,7 +20,8 @@
*/
package com.drew.metadata.mov.atoms;
-import com.drew.lang.SequentialReader;
+import com.drew.lang.Charsets;
+import com.drew.lang.ReaderInfo;
import com.drew.metadata.mov.media.QuickTimeTimecodeDirectory;
import java.io.IOException;
@@ -39,7 +40,7 @@ public class TimecodeInformationMediaAtom extends FullAtom
int[] backgroundColor;
String fontName;
- public TimecodeInformationMediaAtom(SequentialReader reader, Atom atom) throws IOException
+ public TimecodeInformationMediaAtom(ReaderInfo reader, Atom atom) throws IOException
{
super(reader, atom);
@@ -49,7 +50,7 @@ public TimecodeInformationMediaAtom(SequentialReader reader, Atom atom) throws I
reader.skip(2); // Reserved
textColor = new int[]{reader.getUInt16(), reader.getUInt16(), reader.getUInt16()};
backgroundColor = new int[]{reader.getUInt16(), reader.getUInt16(), reader.getUInt16()};
- fontName = reader.getString(reader.getUInt8());
+ fontName = reader.getString(reader.getUInt8(), Charsets.UTF_8);
}
public void addMetadata(QuickTimeTimecodeDirectory directory)
diff --git a/Source/com/drew/metadata/mov/atoms/TimecodeSampleDescriptionAtom.java b/Source/com/drew/metadata/mov/atoms/TimecodeSampleDescriptionAtom.java
index e0feefa77..15f8a8e79 100644
--- a/Source/com/drew/metadata/mov/atoms/TimecodeSampleDescriptionAtom.java
+++ b/Source/com/drew/metadata/mov/atoms/TimecodeSampleDescriptionAtom.java
@@ -20,7 +20,7 @@
*/
package com.drew.metadata.mov.atoms;
-import com.drew.lang.SequentialReader;
+import com.drew.lang.ReaderInfo;
import com.drew.metadata.mov.media.QuickTimeTimecodeDirectory;
import java.io.IOException;
@@ -32,13 +32,13 @@
*/
public class TimecodeSampleDescriptionAtom extends SampleDescriptionAtom
{
- public TimecodeSampleDescriptionAtom(SequentialReader reader, Atom atom) throws IOException
+ public TimecodeSampleDescriptionAtom(ReaderInfo reader, Atom atom) throws IOException
{
super(reader, atom);
}
@Override
- TimecodeSampleDescription getSampleDescription(SequentialReader reader) throws IOException
+ TimecodeSampleDescription getSampleDescription(ReaderInfo reader) throws IOException
{
return new TimecodeSampleDescription(reader);
}
@@ -60,7 +60,7 @@ class TimecodeSampleDescription extends SampleDescription
int frameDuration;
int numberOfFrames;
- public TimecodeSampleDescription(SequentialReader reader) throws IOException
+ public TimecodeSampleDescription(ReaderInfo reader) throws IOException
{
super(reader);
diff --git a/Source/com/drew/metadata/mov/atoms/VideoInformationMediaHeaderAtom.java b/Source/com/drew/metadata/mov/atoms/VideoInformationMediaHeaderAtom.java
index 6727c8920..49f6454f3 100644
--- a/Source/com/drew/metadata/mov/atoms/VideoInformationMediaHeaderAtom.java
+++ b/Source/com/drew/metadata/mov/atoms/VideoInformationMediaHeaderAtom.java
@@ -20,7 +20,7 @@
*/
package com.drew.metadata.mov.atoms;
-import com.drew.lang.SequentialReader;
+import com.drew.lang.ReaderInfo;
import com.drew.metadata.mov.media.QuickTimeVideoDirectory;
import java.io.IOException;
@@ -35,7 +35,7 @@ public class VideoInformationMediaHeaderAtom extends FullAtom
int graphicsMode;
int[] opcolor;
- public VideoInformationMediaHeaderAtom(SequentialReader reader, Atom atom) throws IOException
+ public VideoInformationMediaHeaderAtom(ReaderInfo reader, Atom atom) throws IOException
{
super(reader, atom);
diff --git a/Source/com/drew/metadata/mov/atoms/VideoSampleDescriptionAtom.java b/Source/com/drew/metadata/mov/atoms/VideoSampleDescriptionAtom.java
index 503b9012c..7d95bbb37 100644
--- a/Source/com/drew/metadata/mov/atoms/VideoSampleDescriptionAtom.java
+++ b/Source/com/drew/metadata/mov/atoms/VideoSampleDescriptionAtom.java
@@ -20,7 +20,8 @@
*/
package com.drew.metadata.mov.atoms;
-import com.drew.lang.SequentialReader;
+import com.drew.lang.Charsets;
+import com.drew.lang.ReaderInfo;
import com.drew.metadata.mov.QuickTimeDictionary;
import com.drew.metadata.mov.media.QuickTimeVideoDirectory;
@@ -33,13 +34,13 @@
*/
public class VideoSampleDescriptionAtom extends SampleDescriptionAtom
{
- public VideoSampleDescriptionAtom(SequentialReader reader, Atom atom) throws IOException
+ public VideoSampleDescriptionAtom(ReaderInfo reader, Atom atom) throws IOException
{
super(reader, atom);
}
@Override
- VideoSampleDescription getSampleDescription(SequentialReader reader) throws IOException
+ VideoSampleDescription getSampleDescription(ReaderInfo reader) throws IOException
{
return new VideoSampleDescription(reader);
}
@@ -90,13 +91,13 @@ class VideoSampleDescription extends SampleDescription
int depth;
int colorTableID;
- public VideoSampleDescription(SequentialReader reader) throws IOException
+ public VideoSampleDescription(ReaderInfo reader) throws IOException
{
super(reader);
version = reader.getUInt16();
revisionLevel = reader.getUInt16();
- vendor = reader.getString(4);
+ vendor = reader.getString(4, Charsets.UTF_8);
temporalQuality = reader.getUInt32();
spatialQuality = reader.getUInt32();
width = reader.getUInt16();
@@ -105,7 +106,7 @@ public VideoSampleDescription(SequentialReader reader) throws IOException
verticalResolution = reader.getUInt32();
dataSize = reader.getUInt32();
frameCount = reader.getUInt16();
- compressorName = reader.getString(32);
+ compressorName = reader.getString(32, Charsets.UTF_8);
depth = reader.getUInt16();
colorTableID = reader.getInt16();
}
diff --git a/Source/com/drew/metadata/mov/media/QuickTimeMusicHandler.java b/Source/com/drew/metadata/mov/media/QuickTimeMusicHandler.java
index 6a3c2b8a4..8dd609707 100644
--- a/Source/com/drew/metadata/mov/media/QuickTimeMusicHandler.java
+++ b/Source/com/drew/metadata/mov/media/QuickTimeMusicHandler.java
@@ -20,7 +20,7 @@
*/
package com.drew.metadata.mov.media;
-import com.drew.lang.SequentialReader;
+import com.drew.lang.ReaderInfo;
import com.drew.lang.annotations.NotNull;
import com.drew.metadata.Metadata;
import com.drew.metadata.mov.QuickTimeMediaHandler;
@@ -53,20 +53,20 @@ protected String getMediaInformation()
}
@Override
- protected void processSampleDescription(@NotNull SequentialReader reader, @NotNull Atom atom) throws IOException
+ protected void processSampleDescription(@NotNull ReaderInfo reader, @NotNull Atom atom) throws IOException
{
MusicSampleDescriptionAtom musicSampleDescriptionAtom = new MusicSampleDescriptionAtom(reader, atom);
musicSampleDescriptionAtom.addMetadata(directory);
}
@Override
- protected void processMediaInformation(@NotNull SequentialReader reader, @NotNull Atom atom) throws IOException
+ protected void processMediaInformation(@NotNull ReaderInfo reader, @NotNull Atom atom) throws IOException
{
// Not yet implemented
}
@Override
- protected void processTimeToSample(@NotNull SequentialReader reader, @NotNull Atom atom) throws IOException
+ protected void processTimeToSample(@NotNull ReaderInfo reader, @NotNull Atom atom) throws IOException
{
// Not yet implemented
}
diff --git a/Source/com/drew/metadata/mov/media/QuickTimeSoundHandler.java b/Source/com/drew/metadata/mov/media/QuickTimeSoundHandler.java
index 0f3787ff0..8669fbd81 100644
--- a/Source/com/drew/metadata/mov/media/QuickTimeSoundHandler.java
+++ b/Source/com/drew/metadata/mov/media/QuickTimeSoundHandler.java
@@ -20,7 +20,7 @@
*/
package com.drew.metadata.mov.media;
-import com.drew.lang.SequentialReader;
+import com.drew.lang.ReaderInfo;
import com.drew.lang.annotations.NotNull;
import com.drew.metadata.Metadata;
import com.drew.metadata.mov.*;
@@ -54,21 +54,21 @@ protected String getMediaInformation()
}
@Override
- public void processSampleDescription(@NotNull SequentialReader reader, @NotNull Atom atom) throws IOException
+ public void processSampleDescription(@NotNull ReaderInfo reader, @NotNull Atom atom) throws IOException
{
SoundSampleDescriptionAtom soundSampleDescriptionAtom = new SoundSampleDescriptionAtom(reader, atom);
soundSampleDescriptionAtom.addMetadata(directory);
}
@Override
- public void processMediaInformation(@NotNull SequentialReader reader, @NotNull Atom atom) throws IOException
+ public void processMediaInformation(@NotNull ReaderInfo reader, @NotNull Atom atom) throws IOException
{
SoundInformationMediaHeaderAtom soundInformationMediaHeaderAtom = new SoundInformationMediaHeaderAtom(reader, atom);
soundInformationMediaHeaderAtom.addMetadata(directory);
}
@Override
- protected void processTimeToSample(@NotNull SequentialReader reader, @NotNull Atom atom) throws IOException
+ protected void processTimeToSample(@NotNull ReaderInfo reader, @NotNull Atom atom) throws IOException
{
directory.setDouble(QuickTimeSoundDirectory.TAG_AUDIO_SAMPLE_RATE, QuickTimeHandlerFactory.HANDLER_PARAM_TIME_SCALE);
}
diff --git a/Source/com/drew/metadata/mov/media/QuickTimeSubtitleHandler.java b/Source/com/drew/metadata/mov/media/QuickTimeSubtitleHandler.java
index 819383c17..d41bc6863 100644
--- a/Source/com/drew/metadata/mov/media/QuickTimeSubtitleHandler.java
+++ b/Source/com/drew/metadata/mov/media/QuickTimeSubtitleHandler.java
@@ -20,7 +20,7 @@
*/
package com.drew.metadata.mov.media;
-import com.drew.lang.SequentialReader;
+import com.drew.lang.ReaderInfo;
import com.drew.lang.annotations.NotNull;
import com.drew.metadata.Metadata;
import com.drew.metadata.mov.QuickTimeMediaHandler;
@@ -54,20 +54,20 @@ protected String getMediaInformation()
}
@Override
- protected void processSampleDescription(@NotNull SequentialReader reader, @NotNull Atom atom) throws IOException
+ protected void processSampleDescription(@NotNull ReaderInfo reader, @NotNull Atom atom) throws IOException
{
SubtitleSampleDescriptionAtom subtitleSampleDescriptionAtom = new SubtitleSampleDescriptionAtom(reader, atom);
subtitleSampleDescriptionAtom.addMetadata(directory);
}
@Override
- protected void processMediaInformation(@NotNull SequentialReader reader, @NotNull Atom atom) throws IOException
+ protected void processMediaInformation(@NotNull ReaderInfo reader, @NotNull Atom atom) throws IOException
{
// Not yet implemented
}
@Override
- protected void processTimeToSample(@NotNull SequentialReader reader, @NotNull Atom atom) throws IOException
+ protected void processTimeToSample(@NotNull ReaderInfo reader, @NotNull Atom atom) throws IOException
{
// Not yet implemented
}
diff --git a/Source/com/drew/metadata/mov/media/QuickTimeTextHandler.java b/Source/com/drew/metadata/mov/media/QuickTimeTextHandler.java
index c136f2173..7b6feddd6 100644
--- a/Source/com/drew/metadata/mov/media/QuickTimeTextHandler.java
+++ b/Source/com/drew/metadata/mov/media/QuickTimeTextHandler.java
@@ -20,7 +20,7 @@
*/
package com.drew.metadata.mov.media;
-import com.drew.lang.SequentialReader;
+import com.drew.lang.ReaderInfo;
import com.drew.lang.annotations.NotNull;
import com.drew.metadata.Metadata;
import com.drew.metadata.mov.QuickTimeAtomTypes;
@@ -54,20 +54,20 @@ protected String getMediaInformation()
}
@Override
- protected void processSampleDescription(@NotNull SequentialReader reader, @NotNull Atom atom) throws IOException
+ protected void processSampleDescription(@NotNull ReaderInfo reader, @NotNull Atom atom) throws IOException
{
TextSampleDescriptionAtom textSampleDescriptionAtom = new TextSampleDescriptionAtom(reader, atom);
textSampleDescriptionAtom.addMetadata(directory);
}
@Override
- protected void processMediaInformation(@NotNull SequentialReader reader, @NotNull Atom atom) throws IOException
+ protected void processMediaInformation(@NotNull ReaderInfo reader, @NotNull Atom atom) throws IOException
{
// Not yet implemented
}
@Override
- protected void processTimeToSample(@NotNull SequentialReader reader, @NotNull Atom atom) throws IOException
+ protected void processTimeToSample(@NotNull ReaderInfo reader, @NotNull Atom atom) throws IOException
{
// Not yet implemented
}
diff --git a/Source/com/drew/metadata/mov/media/QuickTimeTimecodeHandler.java b/Source/com/drew/metadata/mov/media/QuickTimeTimecodeHandler.java
index 72fb7bf09..6d4bad51d 100644
--- a/Source/com/drew/metadata/mov/media/QuickTimeTimecodeHandler.java
+++ b/Source/com/drew/metadata/mov/media/QuickTimeTimecodeHandler.java
@@ -20,7 +20,7 @@
*/
package com.drew.metadata.mov.media;
-import com.drew.lang.SequentialReader;
+import com.drew.lang.ReaderInfo;
import com.drew.lang.annotations.NotNull;
import com.drew.metadata.Metadata;
import com.drew.metadata.mov.QuickTimeAtomTypes;
@@ -55,21 +55,21 @@ protected String getMediaInformation()
}
@Override
- public void processSampleDescription(@NotNull SequentialReader reader, @NotNull Atom atom) throws IOException
+ public void processSampleDescription(@NotNull ReaderInfo reader, @NotNull Atom atom) throws IOException
{
TimecodeSampleDescriptionAtom timecodeSampleDescriptionAtom = new TimecodeSampleDescriptionAtom(reader, atom);
timecodeSampleDescriptionAtom.addMetadata(directory);
}
@Override
- public void processMediaInformation(@NotNull SequentialReader reader, @NotNull Atom atom) throws IOException
+ public void processMediaInformation(@NotNull ReaderInfo reader, @NotNull Atom atom) throws IOException
{
TimecodeInformationMediaAtom timecodeInformationMediaAtom = new TimecodeInformationMediaAtom(reader, atom);
timecodeInformationMediaAtom.addMetadata(directory);
}
@Override
- protected void processTimeToSample(@NotNull SequentialReader reader, @NotNull Atom atom) throws IOException
+ protected void processTimeToSample(@NotNull ReaderInfo reader, @NotNull Atom atom) throws IOException
{
// Do nothing
}
diff --git a/Source/com/drew/metadata/mov/media/QuickTimeVideoHandler.java b/Source/com/drew/metadata/mov/media/QuickTimeVideoHandler.java
index ba34266e7..048ee3203 100644
--- a/Source/com/drew/metadata/mov/media/QuickTimeVideoHandler.java
+++ b/Source/com/drew/metadata/mov/media/QuickTimeVideoHandler.java
@@ -20,7 +20,7 @@
*/
package com.drew.metadata.mov.media;
-import com.drew.lang.SequentialReader;
+import com.drew.lang.ReaderInfo;
import com.drew.lang.annotations.NotNull;
import com.drew.metadata.Metadata;
import com.drew.metadata.mov.QuickTimeAtomTypes;
@@ -56,21 +56,21 @@ protected QuickTimeVideoDirectory getDirectory()
}
@Override
- public void processSampleDescription(@NotNull SequentialReader reader, @NotNull Atom atom) throws IOException
+ public void processSampleDescription(@NotNull ReaderInfo reader, @NotNull Atom atom) throws IOException
{
VideoSampleDescriptionAtom videoSampleDescriptionAtom = new VideoSampleDescriptionAtom(reader, atom);
videoSampleDescriptionAtom.addMetadata(directory);
}
@Override
- public void processMediaInformation(@NotNull SequentialReader reader, @NotNull Atom atom) throws IOException
+ public void processMediaInformation(@NotNull ReaderInfo reader, @NotNull Atom atom) throws IOException
{
VideoInformationMediaHeaderAtom videoInformationMediaHeaderAtom = new VideoInformationMediaHeaderAtom(reader, atom);
videoInformationMediaHeaderAtom.addMetadata(directory);
}
@Override
- public void processTimeToSample(@NotNull SequentialReader reader, @NotNull Atom atom) throws IOException
+ public void processTimeToSample(@NotNull ReaderInfo reader, @NotNull Atom atom) throws IOException
{
TimeToSampleAtom timeToSampleAtom = new TimeToSampleAtom(reader, atom);
timeToSampleAtom.addMetadata(directory);
diff --git a/Source/com/drew/metadata/mov/metadata/QuickTimeDataHandler.java b/Source/com/drew/metadata/mov/metadata/QuickTimeDataHandler.java
index 1729883b5..a8cddd3b0 100644
--- a/Source/com/drew/metadata/mov/metadata/QuickTimeDataHandler.java
+++ b/Source/com/drew/metadata/mov/metadata/QuickTimeDataHandler.java
@@ -22,7 +22,8 @@
import com.drew.imaging.quicktime.QuickTimeHandler;
import com.drew.lang.ByteUtil;
-import com.drew.lang.SequentialByteArrayReader;
+import com.drew.lang.Charsets;
+import com.drew.lang.ReaderInfo;
import com.drew.lang.annotations.NotNull;
import com.drew.lang.annotations.Nullable;
import com.drew.metadata.Metadata;
@@ -66,7 +67,8 @@ protected boolean shouldAcceptContainer(@NotNull Atom atom)
protected QuickTimeHandler processAtom(@NotNull Atom atom, @Nullable byte[] payload) throws IOException
{
if (payload != null) {
- SequentialByteArrayReader reader = new SequentialByteArrayReader(payload);
+ //SequentialByteArrayReader reader = new SequentialByteArrayReader(payload);
+ ReaderInfo reader = ReaderInfo.createFromArray(payload);
if (atom.type.equals(QuickTimeAtomTypes.ATOM_KEYS)) {
processKeys(reader);
} else if (atom.type.equals(QuickTimeAtomTypes.ATOM_DATA)) {
@@ -82,7 +84,7 @@ protected QuickTimeHandler processAtom(@NotNull Atom atom, @Nullable byte[] payl
}
@Override
- protected void processKeys(@NotNull SequentialByteArrayReader reader) throws IOException
+ protected void processKeys(@NotNull ReaderInfo reader) throws IOException
{
// Version 1-byte and Flags 3-bytes
reader.skip(4);
@@ -96,7 +98,7 @@ protected void processKeys(@NotNull SequentialByteArrayReader reader) throws IOE
}
@Override
- protected void processData(@NotNull byte[] payload, @NotNull SequentialByteArrayReader reader) throws IOException
+ protected void processData(@NotNull byte[] payload, @NotNull ReaderInfo reader) throws IOException
{
int type = reader.getInt32();
// 4 bytes: locale indicator
@@ -106,7 +108,7 @@ protected void processData(@NotNull byte[] payload, @NotNull SequentialByteArray
int length = payload.length - 8;
switch (type) {
case 1:
- directory.setString(tag, reader.getString(length, "UTF-8"));
+ directory.setString(tag, reader.getString(length, Charsets.UTF_8));
break;
case 13:
case 14:
@@ -114,9 +116,8 @@ protected void processData(@NotNull byte[] payload, @NotNull SequentialByteArray
directory.setByteArray(tag, reader.getBytes(length));
break;
case 22:
- byte[] buf = new byte[4];
- reader.getBytes(buf, 4 - length, length);
- directory.setInt(tag, new SequentialByteArrayReader(buf).getInt32());
+ byte[] buf = reader.getBytes(4 - length, length);
+ directory.setInt(tag, ReaderInfo.createFromArray(buf).getInt32());
break;
case 23:
directory.setFloat(tag, reader.getFloat32());
diff --git a/Source/com/drew/metadata/mov/metadata/QuickTimeDirectoryHandler.java b/Source/com/drew/metadata/mov/metadata/QuickTimeDirectoryHandler.java
index e0a624ef0..1e7285dda 100644
--- a/Source/com/drew/metadata/mov/metadata/QuickTimeDirectoryHandler.java
+++ b/Source/com/drew/metadata/mov/metadata/QuickTimeDirectoryHandler.java
@@ -21,7 +21,7 @@
package com.drew.metadata.mov.metadata;
import com.drew.imaging.quicktime.QuickTimeHandler;
-import com.drew.lang.SequentialByteArrayReader;
+import com.drew.lang.ReaderInfo;
import com.drew.lang.annotations.NotNull;
import com.drew.lang.annotations.Nullable;
import com.drew.metadata.Metadata;
@@ -61,7 +61,7 @@ protected boolean shouldAcceptContainer(@NotNull Atom atom)
protected QuickTimeHandler processAtom(@NotNull Atom atom, @Nullable byte[] payload) throws IOException
{
if (payload != null) {
- SequentialByteArrayReader reader = new SequentialByteArrayReader(payload);
+ ReaderInfo reader = ReaderInfo.createFromArray(payload);
if (atom.type.equals(QuickTimeAtomTypes.ATOM_DATA) && currentData != null) {
processData(payload, reader);
} else {
@@ -78,7 +78,7 @@ protected QuickTimeHandler processAtom(@NotNull Atom atom, @Nullable byte[] payl
}
@Override
- protected void processData(@NotNull byte[] payload, @NotNull SequentialByteArrayReader reader) throws IOException
+ protected void processData(@NotNull byte[] payload, @NotNull ReaderInfo reader) throws IOException
{
// 4 bytes: type indicator
// 4 bytes: locale indicator
@@ -88,7 +88,7 @@ protected void processData(@NotNull byte[] payload, @NotNull SequentialByteArray
}
@Override
- protected void processKeys(@NotNull SequentialByteArrayReader reader) throws IOException
+ protected void processKeys(@NotNull ReaderInfo reader) throws IOException
{
// Do nothing
}
diff --git a/Source/com/drew/metadata/mp3/Mp3Reader.java b/Source/com/drew/metadata/mp3/Mp3Reader.java
index 3af21af27..e3b6f2b94 100644
--- a/Source/com/drew/metadata/mp3/Mp3Reader.java
+++ b/Source/com/drew/metadata/mp3/Mp3Reader.java
@@ -21,13 +21,11 @@
package com.drew.metadata.mp3;
import com.drew.imaging.ImageProcessingException;
-import com.drew.lang.SequentialReader;
-import com.drew.lang.StreamReader;
+import com.drew.lang.ReaderInfo;
import com.drew.lang.annotations.NotNull;
import com.drew.metadata.Metadata;
import java.io.IOException;
-import java.io.InputStream;
/**
* Sources: http://id3.org/mp3Frame
@@ -38,15 +36,12 @@
public class Mp3Reader
{
- public void extract(@NotNull final InputStream inputStream, @NotNull final Metadata metadata)
+ public void extract(@NotNull ReaderInfo reader, @NotNull final Metadata metadata)
{
Mp3Directory directory = new Mp3Directory();
metadata.addDirectory(directory);
try {
- inputStream.reset();
- SequentialReader reader = new StreamReader(inputStream);
-
int header = reader.getInt32();
// ID: MPEG-2.5, MPEG-2, or MPEG-1
diff --git a/Source/com/drew/metadata/mp4/Mp4BoxHandler.java b/Source/com/drew/metadata/mp4/Mp4BoxHandler.java
index ed2af4464..22f97e7f1 100644
--- a/Source/com/drew/metadata/mp4/Mp4BoxHandler.java
+++ b/Source/com/drew/metadata/mp4/Mp4BoxHandler.java
@@ -21,8 +21,7 @@
package com.drew.metadata.mp4;
import com.drew.imaging.mp4.Mp4Handler;
-import com.drew.lang.SequentialByteArrayReader;
-import com.drew.lang.SequentialReader;
+import com.drew.lang.ReaderInfo;
import com.drew.lang.annotations.NotNull;
import com.drew.lang.annotations.Nullable;
import com.drew.metadata.Metadata;
@@ -72,7 +71,7 @@ public boolean shouldAcceptContainer(@NotNull Box box)
public Mp4Handler processBox(@NotNull Box box, @Nullable byte[] payload) throws IOException
{
if (payload != null) {
- SequentialReader reader = new SequentialByteArrayReader(payload);
+ ReaderInfo reader = ReaderInfo.createFromArray(payload);
if (box.type.equals(Mp4BoxTypes.BOX_MOVIE_HEADER)) {
processMovieHeader(reader, box);
} else if (box.type.equals(Mp4BoxTypes.BOX_FILE_TYPE)) {
@@ -93,24 +92,24 @@ public Mp4Handler processBox(@NotNull Box box, @Nullable byte[] payload) throws
return this;
}
- private void processFileType(@NotNull SequentialReader reader, @NotNull Box box) throws IOException
+ private void processFileType(@NotNull ReaderInfo reader, @NotNull Box box) throws IOException
{
FileTypeBox fileTypeBox = new FileTypeBox(reader, box);
fileTypeBox.addMetadata(directory);
}
- private void processMovieHeader(@NotNull SequentialReader reader, @NotNull Box box) throws IOException
+ private void processMovieHeader(@NotNull ReaderInfo reader, @NotNull Box box) throws IOException
{
MovieHeaderBox movieHeaderBox = new MovieHeaderBox(reader, box);
movieHeaderBox.addMetadata(directory);
}
- private void processMediaHeader(@NotNull SequentialReader reader, @NotNull Box box) throws IOException
+ private void processMediaHeader(@NotNull ReaderInfo reader, @NotNull Box box) throws IOException
{
MediaHeaderBox mediaHeaderBox = new MediaHeaderBox(reader, box);
}
- private void processTrackHeader(@NotNull SequentialReader reader, @NotNull Box box) throws IOException
+ private void processTrackHeader(@NotNull ReaderInfo reader, @NotNull Box box) throws IOException
{
TrackHeaderBox trackHeaderBox = new TrackHeaderBox(reader, box);
trackHeaderBox.addMetadata(directory);
diff --git a/Source/com/drew/metadata/mp4/Mp4MediaHandler.java b/Source/com/drew/metadata/mp4/Mp4MediaHandler.java
index c757a9fe7..3d14cdc08 100644
--- a/Source/com/drew/metadata/mp4/Mp4MediaHandler.java
+++ b/Source/com/drew/metadata/mp4/Mp4MediaHandler.java
@@ -21,8 +21,7 @@
package com.drew.metadata.mp4;
import com.drew.imaging.mp4.Mp4Handler;
-import com.drew.lang.SequentialByteArrayReader;
-import com.drew.lang.SequentialReader;
+import com.drew.lang.ReaderInfo;
import com.drew.lang.annotations.NotNull;
import com.drew.lang.annotations.Nullable;
import com.drew.metadata.Metadata;
@@ -72,7 +71,7 @@ public boolean shouldAcceptContainer(@NotNull Box box)
public Mp4Handler processBox(@NotNull Box box, @Nullable byte[] payload) throws IOException
{
if (payload != null) {
- SequentialReader reader = new SequentialByteArrayReader(payload);
+ ReaderInfo reader = ReaderInfo.createFromArray(payload);
if (box.type.equals(getMediaInformation())) {
processMediaInformation(reader, box);
} else if (box.type.equals(Mp4BoxTypes.BOX_SAMPLE_DESCRIPTION)) {
@@ -86,9 +85,9 @@ public Mp4Handler processBox(@NotNull Box box, @Nullable byte[] payload) throws
protected abstract String getMediaInformation();
- protected abstract void processSampleDescription(@NotNull SequentialReader reader, @NotNull Box box) throws IOException;
+ protected abstract void processSampleDescription(@NotNull ReaderInfo reader, @NotNull Box box) throws IOException;
- protected abstract void processMediaInformation(@NotNull SequentialReader reader, @NotNull Box box) throws IOException;
+ protected abstract void processMediaInformation(@NotNull ReaderInfo reader, @NotNull Box box) throws IOException;
- protected abstract void processTimeToSample(@NotNull SequentialReader reader, @NotNull Box box) throws IOException;
+ protected abstract void processTimeToSample(@NotNull ReaderInfo reader, @NotNull Box box) throws IOException;
}
diff --git a/Source/com/drew/metadata/mp4/boxes/AudioSampleEntry.java b/Source/com/drew/metadata/mp4/boxes/AudioSampleEntry.java
index 78de479ec..eab77cf8b 100644
--- a/Source/com/drew/metadata/mp4/boxes/AudioSampleEntry.java
+++ b/Source/com/drew/metadata/mp4/boxes/AudioSampleEntry.java
@@ -20,7 +20,7 @@
*/
package com.drew.metadata.mp4.boxes;
-import com.drew.lang.SequentialReader;
+import com.drew.lang.ReaderInfo;
import com.drew.metadata.mp4.Mp4Dictionary;
import com.drew.metadata.mp4.media.Mp4SoundDirectory;
@@ -35,7 +35,7 @@ public class AudioSampleEntry extends SampleEntry
int samplesize;
long samplerate;
- public AudioSampleEntry(SequentialReader reader, Box box) throws IOException
+ public AudioSampleEntry(ReaderInfo reader, Box box) throws IOException
{
super(reader, box);
diff --git a/Source/com/drew/metadata/mp4/boxes/Box.java b/Source/com/drew/metadata/mp4/boxes/Box.java
index 578f017d9..1938b0105 100644
--- a/Source/com/drew/metadata/mp4/boxes/Box.java
+++ b/Source/com/drew/metadata/mp4/boxes/Box.java
@@ -20,7 +20,8 @@
*/
package com.drew.metadata.mp4.boxes;
-import com.drew.lang.SequentialReader;
+import com.drew.lang.ReaderInfo;
+import com.drew.lang.Charsets;
import java.io.IOException;
@@ -33,17 +34,17 @@ public class Box
public String type;
public String usertype;
- public Box(SequentialReader reader) throws IOException
+ public Box(ReaderInfo reader) throws IOException
{
this.size = reader.getUInt32();
- this.type = reader.getString(4);
+ this.type = reader.getString(4, Charsets.UTF_8);
if (size == 1) {
size = reader.getInt64();
} else if (size == 0) {
size = -1;
}
if (type.equals("uuid")) {
- usertype = reader.getString(16);
+ usertype = reader.getString(16, Charsets.UTF_8);
}
}
diff --git a/Source/com/drew/metadata/mp4/boxes/FileTypeBox.java b/Source/com/drew/metadata/mp4/boxes/FileTypeBox.java
index 569d1153a..363a640fb 100644
--- a/Source/com/drew/metadata/mp4/boxes/FileTypeBox.java
+++ b/Source/com/drew/metadata/mp4/boxes/FileTypeBox.java
@@ -20,7 +20,8 @@
*/
package com.drew.metadata.mp4.boxes;
-import com.drew.lang.SequentialReader;
+import com.drew.lang.Charsets;
+import com.drew.lang.ReaderInfo;
import com.drew.metadata.mp4.Mp4Directory;
import java.io.IOException;
@@ -35,15 +36,15 @@ public class FileTypeBox extends Box
long minorVersion;
ArrayList compatibleBrands;
- public FileTypeBox(SequentialReader reader, Box box) throws IOException
+ public FileTypeBox(ReaderInfo reader, Box box) throws IOException
{
super(box);
- majorBrand = reader.getString(4);
+ majorBrand = reader.getString(4, Charsets.UTF_8);
minorVersion = reader.getUInt32();
compatibleBrands = new ArrayList();
for (int i = 16; i < size; i += 4) {
- compatibleBrands.add(reader.getString(4));
+ compatibleBrands.add(reader.getString(4, Charsets.UTF_8));
}
}
diff --git a/Source/com/drew/metadata/mp4/boxes/FullBox.java b/Source/com/drew/metadata/mp4/boxes/FullBox.java
index aad0e7d68..3622d7e47 100644
--- a/Source/com/drew/metadata/mp4/boxes/FullBox.java
+++ b/Source/com/drew/metadata/mp4/boxes/FullBox.java
@@ -20,7 +20,7 @@
*/
package com.drew.metadata.mp4.boxes;
-import com.drew.lang.SequentialReader;
+import com.drew.lang.ReaderInfo;
import java.io.IOException;
@@ -32,7 +32,7 @@ public class FullBox extends Box
protected int version;
protected byte[] flags;
- public FullBox(SequentialReader reader, Box box) throws IOException
+ public FullBox(ReaderInfo reader, Box box) throws IOException
{
super(box);
diff --git a/Source/com/drew/metadata/mp4/boxes/HandlerBox.java b/Source/com/drew/metadata/mp4/boxes/HandlerBox.java
index bd061e5d9..be865f9de 100644
--- a/Source/com/drew/metadata/mp4/boxes/HandlerBox.java
+++ b/Source/com/drew/metadata/mp4/boxes/HandlerBox.java
@@ -20,7 +20,8 @@
*/
package com.drew.metadata.mp4.boxes;
-import com.drew.lang.SequentialReader;
+import com.drew.lang.Charsets;
+import com.drew.lang.ReaderInfo;
import java.io.IOException;
import java.nio.charset.Charset;
@@ -39,12 +40,12 @@ public String getHandlerType()
String name;
- public HandlerBox(SequentialReader reader, Box box) throws IOException
+ public HandlerBox(ReaderInfo reader, Box box) throws IOException
{
super(reader, box);
reader.skip(4); // Pre-defined
- handlerType = reader.getString(4);
+ handlerType = reader.getString(4, Charsets.UTF_8);
reader.skip(12); // Reserved
name = reader.getNullTerminatedString((int)size - 32, Charset.defaultCharset());
}
diff --git a/Source/com/drew/metadata/mp4/boxes/HintMediaHeaderBox.java b/Source/com/drew/metadata/mp4/boxes/HintMediaHeaderBox.java
index 843d0ca83..cb3c9e86b 100644
--- a/Source/com/drew/metadata/mp4/boxes/HintMediaHeaderBox.java
+++ b/Source/com/drew/metadata/mp4/boxes/HintMediaHeaderBox.java
@@ -20,7 +20,7 @@
*/
package com.drew.metadata.mp4.boxes;
-import com.drew.lang.SequentialReader;
+import com.drew.lang.ReaderInfo;
import com.drew.metadata.mp4.media.Mp4HintDirectory;
import java.io.IOException;
@@ -35,7 +35,7 @@ public class HintMediaHeaderBox extends FullBox
long maxbitrate;
long avgbitrate;
- public HintMediaHeaderBox(SequentialReader reader, Box box) throws IOException
+ public HintMediaHeaderBox(ReaderInfo reader, Box box) throws IOException
{
super(reader, box);
diff --git a/Source/com/drew/metadata/mp4/boxes/MediaHeaderBox.java b/Source/com/drew/metadata/mp4/boxes/MediaHeaderBox.java
index b3c665dd1..e85b88eee 100644
--- a/Source/com/drew/metadata/mp4/boxes/MediaHeaderBox.java
+++ b/Source/com/drew/metadata/mp4/boxes/MediaHeaderBox.java
@@ -20,7 +20,7 @@
*/
package com.drew.metadata.mp4.boxes;
-import com.drew.lang.SequentialReader;
+import com.drew.lang.ReaderInfo;
import com.drew.metadata.mp4.Mp4HandlerFactory;
import java.io.IOException;
@@ -36,7 +36,7 @@ public class MediaHeaderBox extends FullBox
long duration;
String language;
- public MediaHeaderBox(SequentialReader reader, Box box) throws IOException
+ public MediaHeaderBox(ReaderInfo reader, Box box) throws IOException
{
super(reader, box);
diff --git a/Source/com/drew/metadata/mp4/boxes/MovieHeaderBox.java b/Source/com/drew/metadata/mp4/boxes/MovieHeaderBox.java
index 6b1cc9b4e..841a1536d 100644
--- a/Source/com/drew/metadata/mp4/boxes/MovieHeaderBox.java
+++ b/Source/com/drew/metadata/mp4/boxes/MovieHeaderBox.java
@@ -21,7 +21,7 @@
package com.drew.metadata.mp4.boxes;
import com.drew.lang.Rational;
-import com.drew.lang.SequentialReader;
+import com.drew.lang.ReaderInfo;
import com.drew.metadata.mp4.Mp4Directory;
import java.io.IOException;
@@ -42,7 +42,7 @@ public class MovieHeaderBox extends FullBox
protected int[] matrix;
protected long nextTrackID;
- public MovieHeaderBox(SequentialReader reader, Box box) throws IOException
+ public MovieHeaderBox(ReaderInfo reader, Box box) throws IOException
{
super(reader, box);
if (version == 1) {
diff --git a/Source/com/drew/metadata/mp4/boxes/SampleEntry.java b/Source/com/drew/metadata/mp4/boxes/SampleEntry.java
index b76eba551..ace8279f6 100644
--- a/Source/com/drew/metadata/mp4/boxes/SampleEntry.java
+++ b/Source/com/drew/metadata/mp4/boxes/SampleEntry.java
@@ -20,7 +20,8 @@
*/
package com.drew.metadata.mp4.boxes;
-import com.drew.lang.SequentialReader;
+import com.drew.lang.Charsets;
+import com.drew.lang.ReaderInfo;
import java.io.IOException;
@@ -34,13 +35,13 @@ public class SampleEntry extends FullBox
String format;
int dataReferenceIndex;
- public SampleEntry(SequentialReader reader, Box box) throws IOException
+ public SampleEntry(ReaderInfo reader, Box box) throws IOException
{
super(reader, box);
numberOfEntries = reader.getUInt32();
sampleDescriptionSize = reader.getUInt32();
- format = reader.getString(4);
+ format = reader.getString(4, Charsets.UTF_8);
reader.skip(6); // Reserved
dataReferenceIndex = reader.getUInt16();
}
diff --git a/Source/com/drew/metadata/mp4/boxes/SoundMediaHeaderBox.java b/Source/com/drew/metadata/mp4/boxes/SoundMediaHeaderBox.java
index df6957083..9c8ba0962 100644
--- a/Source/com/drew/metadata/mp4/boxes/SoundMediaHeaderBox.java
+++ b/Source/com/drew/metadata/mp4/boxes/SoundMediaHeaderBox.java
@@ -20,7 +20,7 @@
*/
package com.drew.metadata.mp4.boxes;
-import com.drew.lang.SequentialReader;
+import com.drew.lang.ReaderInfo;
import com.drew.metadata.mp4.media.Mp4SoundDirectory;
import java.io.IOException;
@@ -32,7 +32,7 @@ public class SoundMediaHeaderBox extends FullBox
{
int balance;
- public SoundMediaHeaderBox(SequentialReader reader, Box box) throws IOException
+ public SoundMediaHeaderBox(ReaderInfo reader, Box box) throws IOException
{
super(reader, box);
diff --git a/Source/com/drew/metadata/mp4/boxes/TimeToSampleBox.java b/Source/com/drew/metadata/mp4/boxes/TimeToSampleBox.java
index 56fcb67cb..f029bf8f9 100644
--- a/Source/com/drew/metadata/mp4/boxes/TimeToSampleBox.java
+++ b/Source/com/drew/metadata/mp4/boxes/TimeToSampleBox.java
@@ -20,7 +20,7 @@
*/
package com.drew.metadata.mp4.boxes;
-import com.drew.lang.SequentialReader;
+import com.drew.lang.ReaderInfo;
import com.drew.metadata.mp4.Mp4HandlerFactory;
import com.drew.metadata.mp4.media.Mp4SoundDirectory;
import com.drew.metadata.mp4.media.Mp4VideoDirectory;
@@ -36,7 +36,7 @@ public class TimeToSampleBox extends FullBox
long entryCount;
ArrayList entries;
- public TimeToSampleBox(SequentialReader reader, Box box) throws IOException
+ public TimeToSampleBox(ReaderInfo reader, Box box) throws IOException
{
super(reader, box);
diff --git a/Source/com/drew/metadata/mp4/boxes/TrackHeaderBox.java b/Source/com/drew/metadata/mp4/boxes/TrackHeaderBox.java
index 6b228ca50..a16d2d223 100644
--- a/Source/com/drew/metadata/mp4/boxes/TrackHeaderBox.java
+++ b/Source/com/drew/metadata/mp4/boxes/TrackHeaderBox.java
@@ -20,7 +20,7 @@
*/
package com.drew.metadata.mp4.boxes;
-import com.drew.lang.SequentialReader;
+import com.drew.lang.ReaderInfo;
import com.drew.metadata.mp4.Mp4Directory;
import java.awt.*;
@@ -42,7 +42,7 @@ public class TrackHeaderBox extends FullBox
long width;
long height;
- public TrackHeaderBox(SequentialReader reader, Box box) throws IOException
+ public TrackHeaderBox(ReaderInfo reader, Box box) throws IOException
{
super(reader, box);
diff --git a/Source/com/drew/metadata/mp4/boxes/VideoMediaHeaderBox.java b/Source/com/drew/metadata/mp4/boxes/VideoMediaHeaderBox.java
index dada8f535..d12382ce1 100644
--- a/Source/com/drew/metadata/mp4/boxes/VideoMediaHeaderBox.java
+++ b/Source/com/drew/metadata/mp4/boxes/VideoMediaHeaderBox.java
@@ -20,7 +20,7 @@
*/
package com.drew.metadata.mp4.boxes;
-import com.drew.lang.SequentialReader;
+import com.drew.lang.ReaderInfo;
import com.drew.metadata.mp4.media.Mp4VideoDirectory;
import java.io.IOException;
@@ -33,7 +33,7 @@ public class VideoMediaHeaderBox extends FullBox
int graphicsMode;
int[] opcolor;
- public VideoMediaHeaderBox(SequentialReader reader, Box box) throws IOException
+ public VideoMediaHeaderBox(ReaderInfo reader, Box box) throws IOException
{
super(reader, box);
diff --git a/Source/com/drew/metadata/mp4/boxes/VisualSampleEntry.java b/Source/com/drew/metadata/mp4/boxes/VisualSampleEntry.java
index c3c009d37..1240c8a4c 100644
--- a/Source/com/drew/metadata/mp4/boxes/VisualSampleEntry.java
+++ b/Source/com/drew/metadata/mp4/boxes/VisualSampleEntry.java
@@ -20,7 +20,8 @@
*/
package com.drew.metadata.mp4.boxes;
-import com.drew.lang.SequentialReader;
+import com.drew.lang.Charsets;
+import com.drew.lang.ReaderInfo;
import com.drew.metadata.mp4.Mp4Dictionary;
import com.drew.metadata.mp4.media.Mp4VideoDirectory;
@@ -44,13 +45,13 @@ public class VisualSampleEntry extends SampleEntry
String compressorname;
int depth;
- public VisualSampleEntry(SequentialReader reader, Box box) throws IOException
+ public VisualSampleEntry(ReaderInfo reader, Box box) throws IOException
{
super(reader, box);
version = reader.getInt16();
revisionLevel = reader.getInt16();
- vendor = reader.getString(4);
+ vendor = reader.getString(4, Charsets.UTF_8);
temporalQuality = reader.getInt32();
spatialQuality = reader.getInt32();
width = reader.getUInt16();
@@ -59,7 +60,7 @@ public VisualSampleEntry(SequentialReader reader, Box box) throws IOException
vertresolution = reader.getUInt32();
reader.skip(4); // Reserved
frameCount = reader.getUInt16();
- compressorname = reader.getString(32);
+ compressorname = reader.getString(32, Charsets.UTF_8);
depth = reader.getUInt16();
reader.skip(2); // Pre-defined
}
diff --git a/Source/com/drew/metadata/mp4/media/Mp4HintHandler.java b/Source/com/drew/metadata/mp4/media/Mp4HintHandler.java
index 48c0343e9..0815691fb 100644
--- a/Source/com/drew/metadata/mp4/media/Mp4HintHandler.java
+++ b/Source/com/drew/metadata/mp4/media/Mp4HintHandler.java
@@ -20,7 +20,7 @@
*/
package com.drew.metadata.mp4.media;
-import com.drew.lang.SequentialReader;
+import com.drew.lang.ReaderInfo;
import com.drew.lang.annotations.NotNull;
import com.drew.metadata.Metadata;
import com.drew.metadata.mp4.Mp4BoxTypes;
@@ -51,20 +51,20 @@ protected String getMediaInformation()
}
@Override
- protected void processSampleDescription(@NotNull SequentialReader reader, @NotNull Box box) throws IOException
+ protected void processSampleDescription(@NotNull ReaderInfo reader, @NotNull Box box) throws IOException
{
}
@Override
- protected void processMediaInformation(@NotNull SequentialReader reader, @NotNull Box box) throws IOException
+ protected void processMediaInformation(@NotNull ReaderInfo reader, @NotNull Box box) throws IOException
{
HintMediaHeaderBox hintMediaHeaderBox = new HintMediaHeaderBox(reader, box);
hintMediaHeaderBox.addMetadata(directory);
}
@Override
- protected void processTimeToSample(@NotNull SequentialReader reader, @NotNull Box box) throws IOException
+ protected void processTimeToSample(@NotNull ReaderInfo reader, @NotNull Box box) throws IOException
{
}
diff --git a/Source/com/drew/metadata/mp4/media/Mp4MetaHandler.java b/Source/com/drew/metadata/mp4/media/Mp4MetaHandler.java
index de7644331..30aeb5735 100644
--- a/Source/com/drew/metadata/mp4/media/Mp4MetaHandler.java
+++ b/Source/com/drew/metadata/mp4/media/Mp4MetaHandler.java
@@ -20,7 +20,7 @@
*/
package com.drew.metadata.mp4.media;
-import com.drew.lang.SequentialReader;
+import com.drew.lang.ReaderInfo;
import com.drew.lang.annotations.NotNull;
import com.drew.metadata.Metadata;
import com.drew.metadata.mp4.Mp4ContainerTypes;
@@ -50,19 +50,19 @@ protected String getMediaInformation()
}
@Override
- protected void processSampleDescription(@NotNull SequentialReader reader, @NotNull Box box) throws IOException
+ protected void processSampleDescription(@NotNull ReaderInfo reader, @NotNull Box box) throws IOException
{
}
@Override
- protected void processMediaInformation(@NotNull SequentialReader reader, @NotNull Box box) throws IOException
+ protected void processMediaInformation(@NotNull ReaderInfo reader, @NotNull Box box) throws IOException
{
}
@Override
- protected void processTimeToSample(@NotNull SequentialReader reader, @NotNull Box box) throws IOException
+ protected void processTimeToSample(@NotNull ReaderInfo reader, @NotNull Box box) throws IOException
{
}
diff --git a/Source/com/drew/metadata/mp4/media/Mp4SoundHandler.java b/Source/com/drew/metadata/mp4/media/Mp4SoundHandler.java
index 0739751c5..b51caf49e 100644
--- a/Source/com/drew/metadata/mp4/media/Mp4SoundHandler.java
+++ b/Source/com/drew/metadata/mp4/media/Mp4SoundHandler.java
@@ -20,7 +20,7 @@
*/
package com.drew.metadata.mp4.media;
-import com.drew.lang.SequentialReader;
+import com.drew.lang.ReaderInfo;
import com.drew.lang.annotations.NotNull;
import com.drew.metadata.Metadata;
import com.drew.metadata.mp4.Mp4BoxTypes;
@@ -53,21 +53,21 @@ protected String getMediaInformation()
}
@Override
- public void processSampleDescription(@NotNull SequentialReader reader, @NotNull Box box) throws IOException
+ public void processSampleDescription(@NotNull ReaderInfo reader, @NotNull Box box) throws IOException
{
AudioSampleEntry audioSampleEntry = new AudioSampleEntry(reader, box);
audioSampleEntry.addMetadata(directory);
}
@Override
- public void processMediaInformation(@NotNull SequentialReader reader, @NotNull Box box) throws IOException
+ public void processMediaInformation(@NotNull ReaderInfo reader, @NotNull Box box) throws IOException
{
SoundMediaHeaderBox soundMediaHeaderBox = new SoundMediaHeaderBox(reader, box);
soundMediaHeaderBox.addMetadata(directory);
}
@Override
- protected void processTimeToSample(@NotNull SequentialReader reader, @NotNull Box box) throws IOException
+ protected void processTimeToSample(@NotNull ReaderInfo reader, @NotNull Box box) throws IOException
{
TimeToSampleBox timeToSampleBox = new TimeToSampleBox(reader, box);
timeToSampleBox.addMetadata(directory);
diff --git a/Source/com/drew/metadata/mp4/media/Mp4TextHandler.java b/Source/com/drew/metadata/mp4/media/Mp4TextHandler.java
index e4835e2bf..377fd29d1 100644
--- a/Source/com/drew/metadata/mp4/media/Mp4TextHandler.java
+++ b/Source/com/drew/metadata/mp4/media/Mp4TextHandler.java
@@ -20,7 +20,7 @@
*/
package com.drew.metadata.mp4.media;
-import com.drew.lang.SequentialReader;
+import com.drew.lang.ReaderInfo;
import com.drew.lang.annotations.NotNull;
import com.drew.metadata.Metadata;
import com.drew.metadata.mp4.Mp4ContainerTypes;
@@ -50,19 +50,19 @@ protected String getMediaInformation()
}
@Override
- protected void processSampleDescription(@NotNull SequentialReader reader, @NotNull Box box) throws IOException
+ protected void processSampleDescription(@NotNull ReaderInfo reader, @NotNull Box box) throws IOException
{
}
@Override
- protected void processMediaInformation(@NotNull SequentialReader reader, @NotNull Box box) throws IOException
+ protected void processMediaInformation(@NotNull ReaderInfo reader, @NotNull Box box) throws IOException
{
}
@Override
- protected void processTimeToSample(@NotNull SequentialReader reader, @NotNull Box box) throws IOException
+ protected void processTimeToSample(@NotNull ReaderInfo reader, @NotNull Box box) throws IOException
{
}
diff --git a/Source/com/drew/metadata/mp4/media/Mp4VideoHandler.java b/Source/com/drew/metadata/mp4/media/Mp4VideoHandler.java
index c938117d3..30baa60ad 100644
--- a/Source/com/drew/metadata/mp4/media/Mp4VideoHandler.java
+++ b/Source/com/drew/metadata/mp4/media/Mp4VideoHandler.java
@@ -20,7 +20,7 @@
*/
package com.drew.metadata.mp4.media;
-import com.drew.lang.SequentialReader;
+import com.drew.lang.ReaderInfo;
import com.drew.lang.annotations.NotNull;
import com.drew.metadata.Metadata;
import com.drew.metadata.mp4.Mp4BoxTypes;
@@ -53,21 +53,21 @@ protected Mp4VideoDirectory getDirectory()
}
@Override
- public void processSampleDescription(@NotNull SequentialReader reader, @NotNull Box box) throws IOException
+ public void processSampleDescription(@NotNull ReaderInfo reader, @NotNull Box box) throws IOException
{
VisualSampleEntry visualSampleEntry = new VisualSampleEntry(reader, box);
visualSampleEntry.addMetadata(directory);
}
@Override
- public void processMediaInformation(@NotNull SequentialReader reader, @NotNull Box box) throws IOException
+ public void processMediaInformation(@NotNull ReaderInfo reader, @NotNull Box box) throws IOException
{
VideoMediaHeaderBox videoMediaHeaderBox = new VideoMediaHeaderBox(reader, box);
videoMediaHeaderBox.addMetadata(directory);
}
@Override
- public void processTimeToSample(@NotNull SequentialReader reader, @NotNull Box box) throws IOException
+ public void processTimeToSample(@NotNull ReaderInfo reader, @NotNull Box box) throws IOException
{
TimeToSampleBox timeToSampleBox = new TimeToSampleBox(reader, box);
timeToSampleBox.addMetadata(directory);
diff --git a/Source/com/drew/metadata/netpbm/NetpbmHeaderDescriptor.java b/Source/com/drew/metadata/netpbm/NetpbmHeaderDescriptor.java
new file mode 100644
index 000000000..334b419e3
--- /dev/null
+++ b/Source/com/drew/metadata/netpbm/NetpbmHeaderDescriptor.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright 2002-2017 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:
+ *
+ * https://drewnoakes.com/code/exif/
+ * https://github.com/drewnoakes/metadata-extractor
+ */
+package com.drew.metadata.netpbm;
+
+import com.drew.lang.annotations.Nullable;
+import com.drew.lang.annotations.NotNull;
+import com.drew.metadata.TagDescriptor;
+
+import static com.drew.metadata.netpbm.NetpbmHeaderDirectory.*;
+
+/**
+ * @author Drew Noakes https://drewnoakes.com
+ * @author Kevin Mott https://github.com/kwhopper
+ */
+@SuppressWarnings("WeakerAccess")
+public class NetpbmHeaderDescriptor extends TagDescriptor
+{
+ public NetpbmHeaderDescriptor(@NotNull NetpbmHeaderDirectory directory)
+ {
+ super(directory);
+ }
+
+ @Override
+ public String getDescription(int tagType)
+ {
+ switch (tagType) {
+ case TAG_FORMAT_TYPE:
+ return getFormatTypeDescription();
+ default:
+ return super.getDescription(tagType);
+ }
+ }
+
+ @Nullable
+ private String getFormatTypeDescription()
+ {
+ return getIndexedDescription(TAG_FORMAT_TYPE, 1,
+ "Portable BitMap (ASCII, B&W)",
+ "Portable GrayMap (ASCII, B&W)",
+ "Portable PixMap (ASCII, B&W)",
+ "Portable BitMap (RAW, B&W)",
+ "Portable GrayMap (RAW, B&W)",
+ "Portable PixMap (RAW, B&W)",
+ "Portable Arbitrary Map"
+ );
+ }
+}
diff --git a/Source/com/drew/metadata/netpbm/NetpbmHeaderDirectory.java b/Source/com/drew/metadata/netpbm/NetpbmHeaderDirectory.java
new file mode 100644
index 000000000..e9d4bbcc8
--- /dev/null
+++ b/Source/com/drew/metadata/netpbm/NetpbmHeaderDirectory.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright 2002-2017 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:
+ *
+ * https://drewnoakes.com/code/exif/
+ * https://github.com/drewnoakes/metadata-extractor
+ */
+
+package com.drew.metadata.netpbm;
+
+import com.drew.lang.annotations.NotNull;
+import com.drew.metadata.Directory;
+
+import java.util.HashMap;
+/**
+ *
+ * @author Drew Noakes https://drewnoakes.com
+ * @author Kevin Mott https://github.com/kwhopper
+ */
+public class NetpbmHeaderDirectory extends Directory
+{
+ public static final int TAG_FORMAT_TYPE = 1;
+ public static final int TAG_WIDTH = 2;
+ public static final int TAG_HEIGHT = 3;
+ public static final int TAG_MAXIMUM_VALUE = 4;
+
+ @NotNull
+ protected static final HashMap _tagNameMap = new HashMap();
+
+ static {
+ _tagNameMap.put(TAG_FORMAT_TYPE, "Format Type");
+ _tagNameMap.put(TAG_WIDTH, "Width");
+ _tagNameMap.put(TAG_HEIGHT, "Height");
+ _tagNameMap.put(TAG_MAXIMUM_VALUE, "Maximum Value");
+ }
+
+ public NetpbmHeaderDirectory()
+ {
+ this.setDescriptor(new NetpbmHeaderDescriptor(this));
+ }
+
+ @Override
+ @NotNull
+ public String getName()
+ {
+ return "Netpbm";
+ }
+
+ @Override
+ @NotNull
+ protected HashMap getTagNameMap()
+ {
+ return _tagNameMap;
+ }
+}
diff --git a/Source/com/drew/metadata/netpbm/NetpbmReader.java b/Source/com/drew/metadata/netpbm/NetpbmReader.java
new file mode 100644
index 000000000..35bacd0b1
--- /dev/null
+++ b/Source/com/drew/metadata/netpbm/NetpbmReader.java
@@ -0,0 +1,106 @@
+/*
+ * Copyright 2002-2017 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:
+ *
+ * https://drewnoakes.com/code/exif/
+ * https://github.com/drewnoakes/metadata-extractor
+ */
+
+package com.drew.metadata.netpbm;
+
+import com.drew.imaging.ImageProcessingException;
+import com.drew.lang.IterableWordReader;
+import com.drew.lang.ReaderInfo;
+import com.drew.lang.annotations.NotNull;
+import com.drew.metadata.Metadata;
+import java.io.IOException;
+import java.util.*;
+
+/**
+ * Reads metadata from Netpbm files.
+ *
+ * @author Drew Noakes https://drewnoakes.com
+ * @author Kevin Mott https://github.com/kwhopper
+ */
+public class NetpbmReader
+{
+ public void extract(ReaderInfo reader, final @NotNull Metadata metadata) throws IOException, ImageProcessingException
+ {
+ NetpbmHeaderDirectory directory = new NetpbmHeaderDirectory();
+
+ Iterator words = new IterableWordReader(reader);
+ String current = "";
+
+ if (!words.hasNext())
+ throw new IOException("Unexpected EOF.");
+ String magic = words.next();
+
+ if (magic.charAt(0) != 'P')
+ throw new ImageProcessingException("Invalid Netpbm magic number");
+ int magicNum = magic.charAt(1) - '0';
+ if (magicNum < 1 || magicNum > 7)
+ throw new ImageProcessingException("Invalid Netpbm magic number");
+
+ directory.setInt(NetpbmHeaderDirectory.TAG_FORMAT_TYPE, magicNum);
+
+ if (!words.hasNext())
+ throw new IOException("Unexpected EOF.");
+
+ current = words.next();
+ int width;
+ try {
+ width = Integer.parseInt(current);
+ }
+ catch(NumberFormatException parseError) {
+ throw new IOException("Width is not parseable as an integer.");
+ }
+
+ directory.setInt(NetpbmHeaderDirectory.TAG_WIDTH, width);
+
+ if (!words.hasNext())
+ throw new IOException("Unexpected EOF.");
+
+ current = words.next();
+ int height;
+ try {
+ height = Integer.parseInt(current);
+ }
+ catch(NumberFormatException parseError) {
+ throw new IOException("Height is not parseable as an integer.");
+ }
+
+ directory.setInt(NetpbmHeaderDirectory.TAG_HEIGHT, height);
+
+ if (!words.hasNext())
+ throw new IOException("Unexpected EOF.");
+
+ current = words.next();
+ if (magicNum != 1 && magicNum != 6)
+ {
+ int maxValue;
+ try {
+ maxValue = Integer.parseInt(current);
+ }
+ catch(NumberFormatException parseError) {
+ throw new IOException("MaxValue is not parseable as an integer.");
+ }
+
+ directory.setInt(NetpbmHeaderDirectory.TAG_MAXIMUM_VALUE, maxValue);
+ }
+
+ metadata.addDirectory(directory);
+ }
+}
diff --git a/Source/com/drew/metadata/pcx/PcxReader.java b/Source/com/drew/metadata/pcx/PcxReader.java
index 4acf82de0..1d26e1cf3 100644
--- a/Source/com/drew/metadata/pcx/PcxReader.java
+++ b/Source/com/drew/metadata/pcx/PcxReader.java
@@ -21,7 +21,7 @@
package com.drew.metadata.pcx;
import com.drew.imaging.ImageProcessingException;
-import com.drew.lang.SequentialReader;
+import com.drew.lang.ReaderInfo;
import com.drew.lang.annotations.NotNull;
import com.drew.metadata.Metadata;
@@ -38,7 +38,7 @@
*/
public class PcxReader
{
- public void extract(@NotNull final SequentialReader reader, @NotNull final Metadata metadata)
+ public void extract(@NotNull ReaderInfo reader, @NotNull final Metadata metadata)
{
reader.setMotorolaByteOrder(false);
diff --git a/Source/com/drew/metadata/photoshop/DuckyReader.java b/Source/com/drew/metadata/photoshop/DuckyReader.java
index f740acaf7..c096c6797 100644
--- a/Source/com/drew/metadata/photoshop/DuckyReader.java
+++ b/Source/com/drew/metadata/photoshop/DuckyReader.java
@@ -22,9 +22,9 @@
import com.drew.imaging.jpeg.JpegSegmentMetadataReader;
import com.drew.imaging.jpeg.JpegSegmentType;
+import com.drew.imaging.jpeg.JpegSegment;
import com.drew.lang.Charsets;
-import com.drew.lang.SequentialByteArrayReader;
-import com.drew.lang.SequentialReader;
+import com.drew.lang.ReaderInfo;
import com.drew.lang.annotations.NotNull;
import com.drew.metadata.Metadata;
@@ -40,7 +40,9 @@
public class DuckyReader implements JpegSegmentMetadataReader
{
@NotNull
- private static final String JPEG_SEGMENT_PREAMBLE = "Ducky";
+ public static final String JPEG_SEGMENT_ID = "Ducky";
+ @NotNull
+ public static final String JPEG_SEGMENT_PREAMBLE = "Ducky";
@NotNull
public Iterable getSegmentTypes()
@@ -48,22 +50,18 @@ public Iterable getSegmentTypes()
return Collections.singletonList(JpegSegmentType.APPC);
}
- public void readJpegSegments(@NotNull Iterable segments, @NotNull Metadata metadata, @NotNull JpegSegmentType segmentType)
+ public void readJpegSegments(@NotNull Iterable segments, @NotNull Metadata metadata) throws IOException
{
final int preambleLength = JPEG_SEGMENT_PREAMBLE.length();
- for (byte[] segmentBytes : segments) {
+ for (JpegSegment segment : segments) {
// Ensure data starts with the necessary preamble
- if (segmentBytes.length < preambleLength || !JPEG_SEGMENT_PREAMBLE.equals(new String(segmentBytes, 0, preambleLength)))
- continue;
-
- extract(
- new SequentialByteArrayReader(segmentBytes, preambleLength),
- metadata);
+ if (segment.getReader().getLength() >= preambleLength && JPEG_SEGMENT_ID.equals(segment.getPreamble()))
+ extract(segment.getReader().Clone(preambleLength, segment.getReader().getLength() - preambleLength), metadata);
}
}
- public void extract(@NotNull final SequentialReader reader, @NotNull final Metadata metadata)
+ public void extract(@NotNull ReaderInfo reader, @NotNull final Metadata metadata)
{
DuckyDirectory directory = new DuckyDirectory();
metadata.addDirectory(directory);
diff --git a/Source/com/drew/metadata/photoshop/PhotoshopDescriptor.java b/Source/com/drew/metadata/photoshop/PhotoshopDescriptor.java
index a43672f5c..03127a290 100644
--- a/Source/com/drew/metadata/photoshop/PhotoshopDescriptor.java
+++ b/Source/com/drew/metadata/photoshop/PhotoshopDescriptor.java
@@ -20,9 +20,8 @@
*/
package com.drew.metadata.photoshop;
-import com.drew.lang.ByteArrayReader;
import com.drew.lang.Charsets;
-import com.drew.lang.RandomAccessReader;
+import com.drew.lang.ReaderInfo;
import com.drew.lang.annotations.NotNull;
import com.drew.lang.annotations.Nullable;
import com.drew.metadata.TagDescriptor;
@@ -95,7 +94,7 @@ public String getJpegQualityString()
if (b == null)
return _directory.getString(TAG_JPEG_QUALITY);
- RandomAccessReader reader = new ByteArrayReader(b);
+ ReaderInfo reader = ReaderInfo.createFromArray(b);
int q = reader.getUInt16(0); // & 0xFFFF;
int f = reader.getUInt16(2); // & 0xFFFF;
int s = reader.getUInt16(4);
@@ -164,7 +163,7 @@ public String getPixelAspectRatioString()
byte[] bytes = _directory.getByteArray(TAG_PIXEL_ASPECT_RATIO);
if (bytes == null)
return null;
- RandomAccessReader reader = new ByteArrayReader(bytes);
+ ReaderInfo reader = ReaderInfo.createFromArray(bytes);
double d = reader.getDouble64(4);
return Double.toString(d);
} catch (Exception e) {
@@ -179,7 +178,7 @@ public String getPrintScaleDescription()
byte bytes[] = _directory.getByteArray(TAG_PRINT_SCALE);
if (bytes == null)
return null;
- RandomAccessReader reader = new ByteArrayReader(bytes);
+ ReaderInfo reader = ReaderInfo.createFromArray(bytes);
int style = reader.getInt32(0);
float locX = reader.getFloat32(2);
float locY = reader.getFloat32(6);
@@ -206,7 +205,7 @@ public String getResolutionInfoDescription()
byte[] bytes = _directory.getByteArray(TAG_RESOLUTION_INFO);
if (bytes == null)
return null;
- RandomAccessReader reader = new ByteArrayReader(bytes);
+ ReaderInfo reader = ReaderInfo.createFromArray(bytes);
float resX = reader.getS15Fixed16(0);
float resY = reader.getS15Fixed16(8); // is this the correct offset? it's only reading 4 bytes each time
DecimalFormat format = new DecimalFormat("0.##");
@@ -223,7 +222,7 @@ public String getVersionDescription()
final byte[] bytes = _directory.getByteArray(TAG_VERSION);
if (bytes == null)
return null;
- RandomAccessReader reader = new ByteArrayReader(bytes);
+ ReaderInfo reader = ReaderInfo.createFromArray(bytes);
int pos = 0;
int ver = reader.getInt32(0);
pos += 4;
@@ -250,7 +249,7 @@ public String getSlicesDescription()
final byte bytes[] = _directory.getByteArray(TAG_SLICES);
if (bytes == null)
return null;
- RandomAccessReader reader = new ByteArrayReader(bytes);
+ ReaderInfo reader = ReaderInfo.createFromArray(bytes);
int nameLength = reader.getInt32(20);
String name = reader.getString(24, nameLength * 2, "UTF-16");
int pos = 24 + nameLength * 2;
@@ -269,7 +268,7 @@ public String getThumbnailDescription(int tagType)
byte[] v = _directory.getByteArray(tagType);
if (v == null)
return null;
- RandomAccessReader reader = new ByteArrayReader(v);
+ ReaderInfo reader = ReaderInfo.createFromArray(v);
int format = reader.getInt32(0);
int width = reader.getInt32(4);
int height = reader.getInt32(8);
@@ -301,7 +300,7 @@ private String get32BitNumberString(int tag)
byte[] bytes = _directory.getByteArray(tag);
if (bytes == null)
return null;
- RandomAccessReader reader = new ByteArrayReader(bytes);
+ ReaderInfo reader = ReaderInfo.createFromArray(bytes);
try {
return String.format("%d", reader.getInt32(0));
} catch (IOException e) {
@@ -334,7 +333,7 @@ public String getClippingPathNameString(int tagType)
byte[] bytes = _directory.getByteArray(tagType);
if (bytes == null)
return null;
- RandomAccessReader reader = new ByteArrayReader(bytes);
+ ReaderInfo reader = ReaderInfo.createFromArray(bytes);
int length = reader.getByte(0);
return new String(reader.getBytes(1, length), "UTF-8");
} catch (Exception e) {
@@ -349,7 +348,7 @@ public String getPathString(int tagType)
byte[] bytes = _directory.getByteArray(tagType);
if (bytes == null)
return null;
- RandomAccessReader reader = new ByteArrayReader(bytes);
+ ReaderInfo reader = ReaderInfo.createFromArray(bytes);
int length = (int) (reader.getLength() - reader.getByte((int)reader.getLength() - 1) - 1) / 26;
String fillRecord = null;
diff --git a/Source/com/drew/metadata/photoshop/PhotoshopReader.java b/Source/com/drew/metadata/photoshop/PhotoshopReader.java
index dd06b8638..f972586c2 100644
--- a/Source/com/drew/metadata/photoshop/PhotoshopReader.java
+++ b/Source/com/drew/metadata/photoshop/PhotoshopReader.java
@@ -23,9 +23,9 @@
import com.drew.imaging.ImageProcessingException;
import com.drew.imaging.jpeg.JpegSegmentMetadataReader;
import com.drew.imaging.jpeg.JpegSegmentType;
-import com.drew.lang.ByteArrayReader;
-import com.drew.lang.SequentialByteArrayReader;
-import com.drew.lang.SequentialReader;
+import com.drew.imaging.jpeg.JpegSegment;
+import com.drew.lang.ReaderInfo;
+import com.drew.lang.Charsets;
import com.drew.lang.annotations.NotNull;
import com.drew.metadata.Metadata;
import com.drew.metadata.exif.ExifReader;
@@ -33,6 +33,7 @@
import com.drew.metadata.iptc.IptcReader;
import com.drew.metadata.xmp.XmpReader;
+import java.io.IOException;
import java.util.Arrays;
import java.util.Collections;
@@ -48,7 +49,9 @@
public class PhotoshopReader implements JpegSegmentMetadataReader
{
@NotNull
- private static final String JPEG_SEGMENT_PREAMBLE = "Photoshop 3.0";
+ public static final String JPEG_SEGMENT_ID = "Photoshop";
+ @NotNull
+ public static final String JPEG_SEGMENT_PREAMBLE = "Photoshop 3.0";
@NotNull
public Iterable getSegmentTypes()
@@ -56,24 +59,22 @@ public Iterable getSegmentTypes()
return Collections.singletonList(JpegSegmentType.APPD);
}
- public void readJpegSegments(@NotNull Iterable segments, @NotNull Metadata metadata, @NotNull JpegSegmentType segmentType)
+ public void readJpegSegments(@NotNull Iterable segments, @NotNull Metadata metadata) throws IOException
{
final int preambleLength = JPEG_SEGMENT_PREAMBLE.length();
- for (byte[] segmentBytes : segments) {
+ for (JpegSegment segment : segments) {
// Ensure data starts with the necessary preamble
- if (segmentBytes.length < preambleLength + 1 || !JPEG_SEGMENT_PREAMBLE.equals(new String(segmentBytes, 0, preambleLength)))
- continue;
-
- extract(
- new SequentialByteArrayReader(segmentBytes, preambleLength + 1),
- segmentBytes.length - preambleLength - 1,
- metadata);
+ if (segment.getReader().getLength() >= preambleLength + 1 && JPEG_SEGMENT_ID.equals(segment.getPreamble()))
+ extract(segment.getReader().Clone(preambleLength + 1, segment.getReader().getLength() - preambleLength - 1), metadata);
}
}
- public void extract(@NotNull final SequentialReader reader, int length, @NotNull final Metadata metadata)
+ public void extract(@NotNull ReaderInfo reader, @NotNull final Metadata metadata) throws IOException
{
+ if (!reader.isMotorolaByteOrder())
+ reader = reader.Clone(false);
+
PhotoshopDirectory directory = new PhotoshopDirectory();
metadata.addDirectory(directory);
@@ -89,10 +90,11 @@ public void extract(@NotNull final SequentialReader reader, int length, @NotNull
int pos = 0;
int clippingPathCount = 0;
+ int length = (int)reader.getLength();
while (pos < length) {
try {
// 4 bytes for the signature ("8BIM", "PHUT", etc.)
- String signature = reader.getString(4);
+ String signature = reader.getString(4, Charsets.UTF_8);
pos += 4;
// 2 bytes for the resource identifier (tag type).
@@ -102,6 +104,7 @@ public void extract(@NotNull final SequentialReader reader, int length, @NotNull
// A variable number of bytes holding a pascal string (two leading bytes for length).
short descriptionLength = reader.getUInt8();
pos += 1;
+
// Some basic bounds checking
if (descriptionLength < 0 || descriptionLength + pos > length)
throw new ImageProcessingException("Invalid string length");
@@ -117,6 +120,7 @@ public void extract(@NotNull final SequentialReader reader, int length, @NotNull
// The number of bytes is padded with a trailing zero, if needed, to make the size even.
if (pos % 2 != 0) {
+ //reader.skip(1);
reader.skip(1);
pos++;
}
@@ -124,9 +128,12 @@ public void extract(@NotNull final SequentialReader reader, int length, @NotNull
// 4 bytes for the size of the resource data that follows.
int byteCount = reader.getInt32();
pos += 4;
+
// The resource data.
- byte[] tagBytes = reader.getBytes(byteCount);
+ ReaderInfo tagReader = reader.Clone(byteCount);
+ reader.skip(byteCount);
pos += byteCount;
+
// The number of bytes is padded with a trailing zero, if needed, to make the size even.
if (pos % 2 != 0) {
reader.skip(1);
@@ -135,16 +142,16 @@ public void extract(@NotNull final SequentialReader reader, int length, @NotNull
if (signature.equals("8BIM")) {
if (tagType == PhotoshopDirectory.TAG_IPTC)
- new IptcReader().extract(new SequentialByteArrayReader(tagBytes), metadata, tagBytes.length, directory);
+ new IptcReader().extract(tagReader, metadata, directory);
else if (tagType == PhotoshopDirectory.TAG_ICC_PROFILE_BYTES)
- new IccReader().extract(new ByteArrayReader(tagBytes), metadata, directory);
+ new IccReader().extract(tagReader, metadata, directory);
else if (tagType == PhotoshopDirectory.TAG_EXIF_DATA_1 || tagType == PhotoshopDirectory.TAG_EXIF_DATA_3)
- new ExifReader().extract(new ByteArrayReader(tagBytes), metadata, 0, directory);
+ new ExifReader().extract(tagReader, metadata, directory);
else if (tagType == PhotoshopDirectory.TAG_XMP_DATA)
- new XmpReader().extract(tagBytes, metadata, directory);
+ new XmpReader().extract(tagReader, metadata, directory);
else if (tagType >= 0x07D0 && tagType <= 0x0BB6) {
clippingPathCount++;
- tagBytes = Arrays.copyOf(tagBytes, tagBytes.length + description.length() + 1);
+ byte[] tagBytes = Arrays.copyOf(tagReader.toArray(), (int)tagReader.getLength() + description.length() + 1);
// Append description(name) to end of byte array with 1 byte before the description representing the length
for (int i = tagBytes.length - description.length() - 1; i < tagBytes.length; i++) {
if (i % (tagBytes.length - description.length() - 1 + description.length()) == 0)
@@ -156,7 +163,7 @@ else if (tagType >= 0x07D0 && tagType <= 0x0BB6) {
directory.setByteArray(0x07CF + clippingPathCount, tagBytes);
}
else
- directory.setByteArray(tagType, tagBytes);
+ directory.setByteArray(tagType, tagReader.toArray());
if (tagType >= 0x0fa0 && tagType <= 0x1387)
PhotoshopDirectory._tagNameMap.put(tagType, String.format("Plug-in %d Data", tagType - 0x0fa0 + 1));
diff --git a/Source/com/drew/metadata/photoshop/PhotoshopTiffHandler.java b/Source/com/drew/metadata/photoshop/PhotoshopTiffHandler.java
index b5de35ea8..4352282c0 100644
--- a/Source/com/drew/metadata/photoshop/PhotoshopTiffHandler.java
+++ b/Source/com/drew/metadata/photoshop/PhotoshopTiffHandler.java
@@ -1,8 +1,6 @@
package com.drew.metadata.photoshop;
-import com.drew.lang.ByteArrayReader;
-import com.drew.lang.RandomAccessReader;
-import com.drew.lang.SequentialByteArrayReader;
+import com.drew.lang.ReaderInfo;
import com.drew.lang.annotations.NotNull;
import com.drew.metadata.Directory;
import com.drew.metadata.Metadata;
@@ -36,10 +34,12 @@ public PhotoshopTiffHandler(Metadata metadata, Directory parentDirectory)
super(metadata, parentDirectory);
}
+ @Override
public boolean customProcessTag(final int tagOffset,
- final @NotNull Set processedIfdOffsets,
- final int tiffHeaderOffset,
- final @NotNull RandomAccessReader reader,
+ final @NotNull Set processedIfdOffsets,
+ //final int tiffHeaderOffset,
+ //final @NotNull RandomAccessReader reader,
+ @NotNull ReaderInfo reader,
final int tagId,
final int byteCount) throws IOException
{
@@ -48,14 +48,14 @@ public boolean customProcessTag(final int tagOffset,
new XmpReader().extract(reader.getBytes(tagOffset, byteCount), _metadata);
return true;
case TAG_PHOTOSHOP_IMAGE_RESOURCES:
- new PhotoshopReader().extract(new SequentialByteArrayReader(reader.getBytes(tagOffset, byteCount)), byteCount, _metadata);
+ new PhotoshopReader().extract(reader.Clone(tagOffset, byteCount), _metadata);
return true;
case TAG_ICC_PROFILES:
- new IccReader().extract(new ByteArrayReader(reader.getBytes(tagOffset, byteCount)), _metadata);
+ new IccReader().extract(reader.Clone(tagOffset, byteCount), _metadata);
return true;
}
- return super.customProcessTag(tagOffset, processedIfdOffsets, tiffHeaderOffset, reader, tagId, byteCount);
+ return super.customProcessTag(tagOffset, processedIfdOffsets, reader, tagId, byteCount);
}
}
diff --git a/Source/com/drew/metadata/photoshop/PsdReader.java b/Source/com/drew/metadata/photoshop/PsdReader.java
index 55542d79c..60db5d4c1 100644
--- a/Source/com/drew/metadata/photoshop/PsdReader.java
+++ b/Source/com/drew/metadata/photoshop/PsdReader.java
@@ -21,7 +21,7 @@
package com.drew.metadata.photoshop;
-import com.drew.lang.SequentialReader;
+import com.drew.lang.ReaderInfo;
import com.drew.lang.annotations.NotNull;
import com.drew.metadata.Metadata;
@@ -34,7 +34,7 @@
*/
public class PsdReader
{
- public void extract(@NotNull final SequentialReader reader, @NotNull final Metadata metadata)
+ public void extract(@NotNull ReaderInfo reader, @NotNull final Metadata metadata)
{
PsdHeaderDirectory directory = new PsdHeaderDirectory();
metadata.addDirectory(directory);
@@ -109,7 +109,7 @@ public void extract(@NotNull final SequentialReader reader, @NotNull final Metad
assert(sectionLength <= Integer.MAX_VALUE);
- new PhotoshopReader().extract(reader, (int)sectionLength, metadata);
+ new PhotoshopReader().extract(reader.Clone(0, (int)sectionLength), metadata);
} catch (IOException e) {
// ignore
}
diff --git a/Source/com/drew/metadata/png/PngDescriptor.java b/Source/com/drew/metadata/png/PngDescriptor.java
index b59d4d8cc..447613106 100644
--- a/Source/com/drew/metadata/png/PngDescriptor.java
+++ b/Source/com/drew/metadata/png/PngDescriptor.java
@@ -22,8 +22,7 @@
import com.drew.imaging.png.PngColorType;
import com.drew.lang.KeyValuePair;
-import com.drew.lang.SequentialByteArrayReader;
-import com.drew.lang.SequentialReader;
+import com.drew.lang.ReaderInfo;
import com.drew.lang.annotations.NotNull;
import com.drew.lang.annotations.Nullable;
import com.drew.metadata.TagDescriptor;
@@ -155,7 +154,7 @@ public String getBackgroundColorDescription()
if (bytes == null) {
return null;
}
- SequentialReader reader = new SequentialByteArrayReader(bytes);
+ ReaderInfo reader = ReaderInfo.createFromArray(bytes);
try {
// TODO do we need to normalise these based upon the bit depth?
switch (bytes.length) {
diff --git a/Source/com/drew/metadata/wav/WavRiffHandler.java b/Source/com/drew/metadata/wav/WavRiffHandler.java
index ed7e4f059..f7e067d1f 100644
--- a/Source/com/drew/metadata/wav/WavRiffHandler.java
+++ b/Source/com/drew/metadata/wav/WavRiffHandler.java
@@ -1,7 +1,7 @@
package com.drew.metadata.wav;
import com.drew.imaging.riff.RiffHandler;
-import com.drew.lang.ByteArrayReader;
+import com.drew.lang.ReaderInfo;
import com.drew.lang.annotations.NotNull;
import com.drew.metadata.Metadata;
import com.drew.metadata.MetadataException;
@@ -39,11 +39,13 @@ public WavRiffHandler(@NotNull Metadata metadata)
metadata.addDirectory(_directory);
}
+ @Override
public boolean shouldAcceptRiffIdentifier(@NotNull String identifier)
{
return identifier.equals(WavDirectory.FORMAT);
}
+ @Override
public boolean shouldAcceptChunk(@NotNull String fourCC)
{
return fourCC.equals(WavDirectory.CHUNK_FORMAT)
@@ -63,11 +65,12 @@ public boolean shouldAcceptList(@NotNull String fourCC)
}
}
- public void processChunk(@NotNull String fourCC, @NotNull byte[] payload)
+ @Override
+ public void processChunk(@NotNull String fourCC, @NotNull ReaderInfo chunkReader) // @NotNull byte[] payload)
{
try {
if (fourCC.equals(WavDirectory.CHUNK_FORMAT)) {
- ByteArrayReader reader = new ByteArrayReader(payload);
+ ReaderInfo reader = chunkReader.Clone();
reader.setMotorolaByteOrder(false);
int wFormatTag = reader.getInt16(0);
int wChannels = reader.getInt16(2);
@@ -97,7 +100,7 @@ public void processChunk(@NotNull String fourCC, @NotNull byte[] payload)
} else if (fourCC.equals(WavDirectory.CHUNK_DATA)) {
try {
if (_directory.containsTag(WavDirectory.TAG_BYTES_PER_SEC)) {
- double duration = (double)payload.length / _directory.getDouble(WavDirectory.TAG_BYTES_PER_SEC);
+ double duration = (double)chunkReader.getLength() / _directory.getDouble(WavDirectory.TAG_BYTES_PER_SEC);
Integer hours = (int)duration / (int)(Math.pow(60, 2));
Integer minutes = ((int)duration / (int)(Math.pow(60, 1))) - (hours * 60);
Integer seconds = (int)Math.round((duration / (Math.pow(60, 0))) - (minutes * 60));
@@ -108,6 +111,7 @@ public void processChunk(@NotNull String fourCC, @NotNull byte[] payload)
_directory.addError("Error calculating duration: bytes per second not found");
}
}else if (WavDirectory._tagIntegerMap.containsKey(fourCC)) {
+ byte[] payload = chunkReader.toArray();
_directory.setString(WavDirectory._tagIntegerMap.get(fourCC), new String(payload).substring(0, payload.length - 1));
}
} catch (IOException ex) {
diff --git a/Source/com/drew/metadata/webp/WebpRiffHandler.java b/Source/com/drew/metadata/webp/WebpRiffHandler.java
index eb27b66af..702535137 100644
--- a/Source/com/drew/metadata/webp/WebpRiffHandler.java
+++ b/Source/com/drew/metadata/webp/WebpRiffHandler.java
@@ -21,8 +21,7 @@
package com.drew.metadata.webp;
import com.drew.imaging.riff.RiffHandler;
-import com.drew.lang.ByteArrayReader;
-import com.drew.lang.RandomAccessReader;
+import com.drew.lang.ReaderInfo;
import com.drew.lang.annotations.NotNull;
import com.drew.metadata.Metadata;
import com.drew.metadata.exif.ExifReader;
@@ -53,11 +52,13 @@ public WebpRiffHandler(@NotNull Metadata metadata)
_metadata = metadata;
}
+ @Override
public boolean shouldAcceptRiffIdentifier(@NotNull String identifier)
{
return identifier.equals(WebpDirectory.FORMAT);
}
+ @Override
public boolean shouldAcceptChunk(@NotNull String fourCC)
{
return fourCC.equals(WebpDirectory.CHUNK_VP8X)
@@ -74,18 +75,18 @@ public boolean shouldAcceptList(@NotNull String fourCC)
return false;
}
- public void processChunk(@NotNull String fourCC, @NotNull byte[] payload)
+ @Override
+ public void processChunk(@NotNull String fourCC, @NotNull ReaderInfo chunkReader) throws IOException // @NotNull byte[] payload)
{
-// System.out.println("Chunk " + fourCC + " " + payload.length + " bytes");
WebpDirectory directory = new WebpDirectory();
if (fourCC.equals(WebpDirectory.CHUNK_EXIF)) {
- new ExifReader().extract(new ByteArrayReader(payload), _metadata);
+ new ExifReader().extract(chunkReader, _metadata);
} else if (fourCC.equals(WebpDirectory.CHUNK_ICCP)) {
- new IccReader().extract(new ByteArrayReader(payload), _metadata);
+ new IccReader().extract(chunkReader, _metadata);
} else if (fourCC.equals(WebpDirectory.CHUNK_XMP)) {
- new XmpReader().extract(payload, _metadata);
- } else if (fourCC.equals(WebpDirectory.CHUNK_VP8X) && payload.length == 10) {
- RandomAccessReader reader = new ByteArrayReader(payload);
+ new XmpReader().extract(chunkReader, _metadata);
+ } else if (fourCC.equals(WebpDirectory.CHUNK_VP8X) && chunkReader.getLength() == 10) {
+ ReaderInfo reader = chunkReader.Clone();
reader.setMotorolaByteOrder(false);
try {
@@ -111,8 +112,8 @@ public void processChunk(@NotNull String fourCC, @NotNull byte[] payload)
} catch (IOException e) {
e.printStackTrace(System.err);
}
- } else if (fourCC.equals(WebpDirectory.CHUNK_VP8L) && payload.length > 4) {
- RandomAccessReader reader = new ByteArrayReader(payload);
+ } else if (fourCC.equals(WebpDirectory.CHUNK_VP8L) && chunkReader.getLength() > 4) {
+ ReaderInfo reader = chunkReader.Clone();
reader.setMotorolaByteOrder(false);
try {
@@ -138,8 +139,8 @@ public void processChunk(@NotNull String fourCC, @NotNull byte[] payload)
} catch (IOException e) {
e.printStackTrace(System.err);
}
- } else if (fourCC.equals(WebpDirectory.CHUNK_VP8) && payload.length > 9) {
- RandomAccessReader reader = new ByteArrayReader(payload);
+ } else if (fourCC.equals(WebpDirectory.CHUNK_VP8) && chunkReader.getLength() > 9) {
+ ReaderInfo reader = chunkReader.Clone();
reader.setMotorolaByteOrder(false);
try {
diff --git a/Source/com/drew/metadata/xmp/XmpReader.java b/Source/com/drew/metadata/xmp/XmpReader.java
index bfcb2bb94..80292a501 100644
--- a/Source/com/drew/metadata/xmp/XmpReader.java
+++ b/Source/com/drew/metadata/xmp/XmpReader.java
@@ -28,8 +28,9 @@
import com.adobe.xmp.properties.XMPPropertyInfo;
import com.drew.imaging.jpeg.JpegSegmentMetadataReader;
import com.drew.imaging.jpeg.JpegSegmentType;
-import com.drew.lang.SequentialByteArrayReader;
-import com.drew.lang.SequentialReader;
+import com.drew.imaging.jpeg.JpegSegment;
+import com.drew.lang.Charsets;
+import com.drew.lang.ReaderInfo;
import com.drew.metadata.Directory;
import com.drew.lang.annotations.NotNull;
import com.drew.lang.annotations.Nullable;
@@ -40,6 +41,8 @@
import java.util.Collection;
import java.util.Collections;
+import java.io.ByteArrayInputStream;
+
/**
* Extracts XMP data from JPEG APP1 segments.
*
@@ -57,9 +60,15 @@
public class XmpReader implements JpegSegmentMetadataReader
{
@NotNull
- private static final String XMP_JPEG_PREAMBLE = "http://ns.adobe.com/xap/1.0/\0";
+ public static final String JPEG_SEGMENT_ID = "XMP";
+ @NotNull
+ public static final String JPEG_SEGMENT_PREAMBLE = "http://ns.adobe.com/xap/1.0/\0";
+
+ @NotNull
+ public static final String JPEG_SEGMENT_EXTENSION_ID = "XMP (Extended)";
@NotNull
- private static final String XMP_EXTENSION_JPEG_PREAMBLE = "http://ns.adobe.com/xmp/extension/\0";
+ public static final String JPEG_SEGMENT_PREAMBLE_EXTENSION = "http://ns.adobe.com/xmp/extension/\0";
+
@NotNull
private static final String SCHEMA_XMP_NOTES = "http://ns.adobe.com/xmp/note/";
@NotNull
@@ -70,8 +79,14 @@ public class XmpReader implements JpegSegmentMetadataReader
*/
private static final int EXTENDED_XMP_GUID_LENGTH = 32;
private static final int EXTENDED_XMP_INT_LENGTH = 4;
+
+ private static final byte[] jpegSegmentPreambleBytes = JPEG_SEGMENT_PREAMBLE.getBytes();
+ private static final byte[] jpegSegmentPreambleExtensionBytes = JPEG_SEGMENT_PREAMBLE_EXTENSION.getBytes();
+
+ private static final byte[] xmpStringBytes = "XMP".getBytes();
@NotNull
+ @Override
public Iterable getSegmentTypes()
{
return Collections.singletonList(JpegSegmentType.APP1);
@@ -83,27 +98,24 @@ public Iterable getSegmentTypes()
*
* @param segments The byte array from which the metadata should be extracted.
* @param metadata The {@link Metadata} object into which extracted values should be merged.
- * @param segmentType The {@link JpegSegmentType} being read.
*/
- public void readJpegSegments(@NotNull Iterable segments, @NotNull Metadata metadata, @NotNull JpegSegmentType segmentType)
+ @Override
+ public void readJpegSegments(@NotNull Iterable segments, @NotNull Metadata metadata) throws IOException
{
- final int preambleLength = XMP_JPEG_PREAMBLE.length();
- final int extensionPreambleLength = XMP_EXTENSION_JPEG_PREAMBLE.length();
+ final int preambleLength = JPEG_SEGMENT_PREAMBLE.length();
+ final int extensionPreambleLength = JPEG_SEGMENT_PREAMBLE_EXTENSION.length();
String extendedXMPGUID = null;
byte[] extendedXMPBuffer = null;
- for (byte[] segmentBytes : segments) {
+ for (JpegSegment segment : segments) {
// XMP in a JPEG file has an identifying preamble which is not valid XML
- if (segmentBytes.length >= preambleLength) {
+ if (segment.getReader().getLength() >= preambleLength) {
// NOTE we expect the full preamble here, but some images (such as that reported on GitHub #102)
// start with "XMP\0://ns.adobe.com/xap/1.0/" which appears to be an error but is easily recovered
// from. In such cases, the actual XMP data begins at the same offset.
- if (XMP_JPEG_PREAMBLE.equalsIgnoreCase(new String(segmentBytes, 0, preambleLength)) ||
- "XMP".equalsIgnoreCase(new String(segmentBytes, 0, 3))) {
+ if (isXmpSegment(segment)) {
+ extract(segment.getReader().Clone(preambleLength, segment.getReader().getLength() - preambleLength), metadata);
- byte[] xmlBytes = new byte[segmentBytes.length - preambleLength];
- System.arraycopy(segmentBytes, preambleLength, xmlBytes, 0, xmlBytes.length);
- extract(xmlBytes, metadata);
// Check in the Standard XMP if there should be a Extended XMP part in other chunks.
extendedXMPGUID = getExtendedXMPGUID(metadata);
continue;
@@ -112,10 +124,10 @@ public void readJpegSegments(@NotNull Iterable segments, @NotNull Metada
// If we know that there's Extended XMP chunks, look for them.
if (extendedXMPGUID != null &&
- segmentBytes.length >= extensionPreambleLength &&
- XMP_EXTENSION_JPEG_PREAMBLE.equalsIgnoreCase(new String(segmentBytes, 0, extensionPreambleLength))) {
+ segment.getReader().getLength() >= extensionPreambleLength &&
+ isExtendedXmpSegment(segment)) {
- extendedXMPBuffer = processExtendedXMPChunk(metadata, segmentBytes, extendedXMPGUID, extendedXMPBuffer);
+ extendedXMPBuffer = processExtendedXMPChunk(metadata, segment.getReader().toArray(), extendedXMPGUID, extendedXMPBuffer);
}
}
@@ -125,6 +137,35 @@ public void readJpegSegments(@NotNull Iterable segments, @NotNull Metada
}
}
+ private static boolean isXmpSegment(JpegSegment segment) throws IOException
+ {
+ // NOTE we expect the full preamble here, but some images (such as that reported on GitHub #102)
+ // start with "XMP\0://ns.adobe.com/xap/1.0/" which appears to be an error but is easily recovered
+ // from. In such cases, the actual XMP data begins at the same offset.
+ return segment.getReader().startsWith(jpegSegmentPreambleBytes) ||
+ segment.getReader().startsWith(xmpStringBytes);
+ }
+
+ private static boolean isExtendedXmpSegment(JpegSegment segment) throws IOException
+ {
+ return segment.getReader().startsWith(jpegSegmentPreambleExtensionBytes);
+ }
+
+ /**
+ * Performs the XMP data extraction, adding found values to the specified instance of {@link Metadata}.
+ *
+ * The extraction is done with Adobe's XMPCore library.
+ */
+ public void extract(@NotNull ReaderInfo reader, @NotNull Metadata metadata) throws IOException
+ {
+ extract(reader.Clone().toArray(), metadata);
+ }
+
+ public void extract(@NotNull ReaderInfo reader, @NotNull Metadata metadata, @Nullable Directory parentDirectory) throws IOException
+ {
+ extract(reader.Clone().toArray(), metadata, parentDirectory);
+ }
+
/**
* Performs the XMP data extraction, adding found values to the specified instance of {@link Metadata}.
*
@@ -168,13 +209,13 @@ public void extract(@NotNull final byte[] xmpBytes, int offset, int length, @Not
xmpMeta = XMPMetaFactory.parse(buffer.getByteStream());
}
- directory.setXMPMeta(xmpMeta);
+ directory.setXMPMeta(xmpMeta);
} catch (XMPException e) {
directory.addError("Error processing XMP data: " + e.getMessage());
}
if (!directory.isEmpty())
- metadata.addDirectory(directory);
+ metadata.addDirectory(directory);
}
/**
@@ -261,7 +302,7 @@ private static String getExtendedXMPGUID(@NotNull Metadata metadata)
@Nullable
private static byte[] processExtendedXMPChunk(@NotNull Metadata metadata, @NotNull byte[] segmentBytes, @NotNull String extendedXMPGUID, @Nullable byte[] extendedXMPBuffer)
{
- final int extensionPreambleLength = XMP_EXTENSION_JPEG_PREAMBLE.length();
+ final int extensionPreambleLength = JPEG_SEGMENT_PREAMBLE_EXTENSION.length();
final int segmentLength = segmentBytes.length;
final int totalOffset = extensionPreambleLength + EXTENDED_XMP_GUID_LENGTH + EXTENDED_XMP_INT_LENGTH + EXTENDED_XMP_INT_LENGTH;
@@ -276,9 +317,9 @@ private static byte[] processExtendedXMPChunk(@NotNull Metadata metadata, @NotNu
* - The offset of this portion as a 32-bit unsigned integer
* - The portion of the ExtendedXMP
*/
- final SequentialReader reader = new SequentialByteArrayReader(segmentBytes);
+ ReaderInfo reader = ReaderInfo.createFromArray(segmentBytes);
reader.skip(extensionPreambleLength);
- final String segmentGUID = reader.getString(EXTENDED_XMP_GUID_LENGTH);
+ final String segmentGUID = reader.getString(EXTENDED_XMP_GUID_LENGTH, Charsets.UTF_8);
if (extendedXMPGUID.equals(segmentGUID)) {
final int fullLength = (int)reader.getUInt32();
diff --git a/Source/com/drew/tools/ExtractJpegSegmentTool.java b/Source/com/drew/tools/ExtractJpegSegmentTool.java
index e62c8763e..c430fd541 100644
--- a/Source/com/drew/tools/ExtractJpegSegmentTool.java
+++ b/Source/com/drew/tools/ExtractJpegSegmentTool.java
@@ -24,6 +24,7 @@
import com.drew.imaging.jpeg.JpegSegmentData;
import com.drew.imaging.jpeg.JpegSegmentReader;
import com.drew.imaging.jpeg.JpegSegmentType;
+import com.drew.imaging.jpeg.JpegSegment;
import com.drew.lang.Iterables;
import com.drew.lang.annotations.NotNull;
@@ -67,7 +68,7 @@ public static void main(String[] args) throws IOException, JpegProcessingExcepti
for (int i = 1; i < args.length; i++) {
JpegSegmentType segmentType = JpegSegmentType.valueOf(args[i].toUpperCase());
- if (!segmentType.canContainMetadata) {
+ if (!JpegSegmentType.canContainMetadata(segmentType)) {
System.err.printf("WARNING: Segment type %s cannot contain metadata so it may not be necessary to extract it%n", segmentType);
}
segmentTypes.add(segmentType);
@@ -80,7 +81,7 @@ public static void main(String[] args) throws IOException, JpegProcessingExcepti
System.out.println("Reading: " + filePath);
- JpegSegmentData segmentData = JpegSegmentReader.readSegments(new File(filePath), segmentTypes);
+ JpegSegmentData segmentData = JpegSegmentReader.readSegments(new File(filePath), segmentTypes, true);
saveSegmentFiles(filePath, segmentData);
}
@@ -88,7 +89,7 @@ public static void main(String[] args) throws IOException, JpegProcessingExcepti
public static void saveSegmentFiles(@NotNull String jpegFilePath, @NotNull JpegSegmentData segmentData) throws IOException
{
for (JpegSegmentType segmentType : segmentData.getSegmentTypes()) {
- List segments = Iterables.toList(segmentData.getSegments(segmentType));
+ List segments = Iterables.toList(segmentData.getSegments(segmentType));
if (segments.size() == 0) {
continue;
}
@@ -97,12 +98,12 @@ public static void saveSegmentFiles(@NotNull String jpegFilePath, @NotNull JpegS
for (int i = 0; i < segments.size(); i++) {
String outputFilePath = String.format("%s.%s.%d", jpegFilePath, segmentType.toString().toLowerCase(), i);
System.out.println("Writing: " + outputFilePath);
- FileUtil.saveBytes(new File(outputFilePath), segments.get(i));
+ FileUtil.saveBytes(new File(outputFilePath), segments.get(i).getReader().toArray());
}
} else {
String outputFilePath = String.format("%s.%s", jpegFilePath, segmentType.toString().toLowerCase());
System.out.println("Writing: " + outputFilePath);
- FileUtil.saveBytes(new File(outputFilePath), segments.get(0));
+ FileUtil.saveBytes(new File(outputFilePath), segments.get(0).getReader().toArray());
}
}
}
@@ -114,7 +115,7 @@ private static void printUsage()
System.out.print("Where is zero or more of:");
for (JpegSegmentType segmentType : JpegSegmentType.class.getEnumConstants()) {
- if (segmentType.canContainMetadata) {
+ if (JpegSegmentType.canContainMetadata(segmentType)) {
System.out.print(" " + segmentType.toString());
}
}
diff --git a/Source/com/drew/tools/ProcessAllImagesInFolderUtility.java b/Source/com/drew/tools/ProcessAllImagesInFolderUtility.java
index 613b2df15..7e3df977e 100644
--- a/Source/com/drew/tools/ProcessAllImagesInFolderUtility.java
+++ b/Source/com/drew/tools/ProcessAllImagesInFolderUtility.java
@@ -29,6 +29,7 @@
import com.drew.imaging.FileTypeDetector;
import com.drew.imaging.ImageMetadataReader;
import com.drew.imaging.jpeg.JpegProcessingException;
+import com.drew.lang.RandomAccessStream;
import com.drew.lang.StringUtil;
import com.drew.lang.annotations.NotNull;
import com.drew.lang.annotations.Nullable;
@@ -439,10 +440,15 @@ private static PrintWriter openWriter(@NotNull File file) throws IOException
writer.write("FILE: " + file.getName() + NEW_LINE);
// Detect file type
- BufferedInputStream stream = null;
+ //BufferedInputStream stream = null;
+ //FileInputStream stream = null;
+ RandomAccessFile stream = null;
try {
- stream = new BufferedInputStream(new FileInputStream(file));
- FileType fileType = FileTypeDetector.detectFileType(stream);
+ //stream = new BufferedInputStream(new FileInputStream(file));
+ //stream = new FileInputStream(file);
+ stream = new RandomAccessFile(file, "r");
+ //FileType fileType = FileTypeDetector.detectFileType(new RandomAccessStream(stream, file.length()).createReader());
+ FileType fileType = FileTypeDetector.detectFileType(new RandomAccessStream(stream).createReader());
writer.write(String.format("TYPE: %s" + NEW_LINE, fileType.toString().toUpperCase()));
writer.write(NEW_LINE);
} finally {
diff --git a/Source/com/drew/tools/ProcessUrlUtility.java b/Source/com/drew/tools/ProcessUrlUtility.java
index 8308e7ac7..970730b56 100644
--- a/Source/com/drew/tools/ProcessUrlUtility.java
+++ b/Source/com/drew/tools/ProcessUrlUtility.java
@@ -56,6 +56,8 @@ public static void main(String[] args) throws IOException, JpegProcessingExcepti
private static void processUrl(URL url) throws IOException
{
URLConnection con = url.openConnection();
+ long contentLength = con.getContentLengthLong();
+
// con.setConnectTimeout(connectTimeout);
// con.setReadTimeout(readTimeout);
InputStream in = con.getInputStream();
@@ -63,7 +65,7 @@ private static void processUrl(URL url) throws IOException
// Read metadata
final Metadata metadata;
try {
- metadata = ImageMetadataReader.readMetadata(in);
+ metadata = ImageMetadataReader.readMetadata(in, contentLength);
} catch (ImageProcessingException e) {
// this is an error in the Jpeg segment structure. we're looking for bad handling of
// metadata segments. in this case, we didn't even get a segment.
diff --git a/Tests/com/drew/imaging/jpeg/JpegMetadataReaderTest.java b/Tests/com/drew/imaging/jpeg/JpegMetadataReaderTest.java
index cda6d5447..dfac0494d 100644
--- a/Tests/com/drew/imaging/jpeg/JpegMetadataReaderTest.java
+++ b/Tests/com/drew/imaging/jpeg/JpegMetadataReaderTest.java
@@ -50,7 +50,8 @@ public void testExtractMetadata() throws Exception
@Test
public void testExtractMetadataUsingInputStream() throws Exception
{
- validate(JpegMetadataReader.readMetadata(new FileInputStream((new File("Tests/Data/withExif.jpg")))));
+ File file = new File("Tests/Data/withExif.jpg");
+ validate(JpegMetadataReader.readMetadata(new FileInputStream(file), file.length()));
}
@Test
diff --git a/Tests/com/drew/imaging/jpeg/JpegSegmentDataTest.java b/Tests/com/drew/imaging/jpeg/JpegSegmentDataTest.java
index 7474b2b2c..2fc26db40 100644
--- a/Tests/com/drew/imaging/jpeg/JpegSegmentDataTest.java
+++ b/Tests/com/drew/imaging/jpeg/JpegSegmentDataTest.java
@@ -20,6 +20,7 @@
*/
package com.drew.imaging.jpeg;
+import com.drew.lang.ReaderInfo;
import org.junit.Test;
import static org.junit.Assert.*;
@@ -35,12 +36,13 @@ public void testAddAndGetSegment() throws Exception
{
JpegSegmentData segmentData = new JpegSegmentData();
- byte segmentMarker = (byte)12;
+ JpegSegmentType segmentType = JpegSegmentType.APP0;
byte[] segmentBytes = new byte[] { 1,2,3 };
- segmentData.addSegment(segmentMarker, segmentBytes);
- assertEquals(1, segmentData.getSegmentCount(segmentMarker));
- assertArrayEquals(segmentBytes, segmentData.getSegment(segmentMarker));
+ JpegSegment segment = new JpegSegment(segmentType, ReaderInfo.createFromArray(segmentBytes));
+ segmentData.addSegment(segment);
+ assertEquals(1, segmentData.getSegmentCount(segmentType));
+ assertArrayEquals(segmentBytes, segmentData.getSegment(segmentType).getReader().toArray());
}
@Test
@@ -48,14 +50,15 @@ public void testContainsSegment() throws Exception
{
JpegSegmentData segmentData = new JpegSegmentData();
- byte segmentMarker = (byte)12;
+ JpegSegmentType segmentType = JpegSegmentType.APP0;
byte[] segmentBytes = new byte[] { 1,2,3 };
- assertTrue(!segmentData.containsSegment(segmentMarker));
+ assertTrue(!segmentData.containsSegment(segmentType));
- segmentData.addSegment(segmentMarker, segmentBytes);
+ JpegSegment segment = new JpegSegment(segmentType, ReaderInfo.createFromArray(segmentBytes));
+ segmentData.addSegment(segment);
- assertTrue(segmentData.containsSegment(segmentMarker));
+ assertTrue(segmentData.containsSegment(segmentType));
}
@Test
@@ -63,17 +66,20 @@ public void testAddingMultipleSegments() throws Exception
{
JpegSegmentData segmentData = new JpegSegmentData();
- byte segmentMarker1 = (byte)12;
- byte segmentMarker2 = (byte)21;
+ JpegSegmentType segmentType1 = JpegSegmentType.APP0;
+ JpegSegmentType segmentType2 = JpegSegmentType.APP1;
byte[] segmentBytes1 = new byte[] { 1,2,3 };
byte[] segmentBytes2 = new byte[] { 3,2,1 };
- segmentData.addSegment(segmentMarker1, segmentBytes1);
- segmentData.addSegment(segmentMarker2, segmentBytes2);
- assertEquals(1, segmentData.getSegmentCount(segmentMarker1));
- assertEquals(1, segmentData.getSegmentCount(segmentMarker2));
- assertArrayEquals(segmentBytes1, segmentData.getSegment(segmentMarker1));
- assertArrayEquals(segmentBytes2, segmentData.getSegment(segmentMarker2));
+ JpegSegment segment1 = new JpegSegment(segmentType1, ReaderInfo.createFromArray(segmentBytes1));
+ JpegSegment segment2 = new JpegSegment(segmentType2, ReaderInfo.createFromArray(segmentBytes2));
+
+ segmentData.addSegment(segment1);
+ segmentData.addSegment(segment2);
+ assertEquals(1, segmentData.getSegmentCount(segmentType1));
+ assertEquals(1, segmentData.getSegmentCount(segmentType2));
+ assertArrayEquals(segmentBytes1, segmentData.getSegment(segmentType1).getReader().toArray());
+ assertArrayEquals(segmentBytes2, segmentData.getSegment(segmentType2).getReader().toArray());
}
@Test
@@ -81,16 +87,19 @@ public void testSegmentWithMultipleOccurrences() throws Exception
{
JpegSegmentData segmentData = new JpegSegmentData();
- byte segmentMarker = (byte)12;
+ JpegSegmentType segmentType = JpegSegmentType.APP0;
byte[] segmentBytes1 = new byte[] { 1,2,3 };
byte[] segmentBytes2 = new byte[] { 3,2,1 };
- segmentData.addSegment(segmentMarker, segmentBytes1);
- segmentData.addSegment(segmentMarker, segmentBytes2);
- assertEquals(2, segmentData.getSegmentCount(segmentMarker));
- assertArrayEquals(segmentBytes1, segmentData.getSegment(segmentMarker));
- assertArrayEquals(segmentBytes1, segmentData.getSegment(segmentMarker, 0));
- assertArrayEquals(segmentBytes2, segmentData.getSegment(segmentMarker, 1));
+ JpegSegment segment1 = new JpegSegment(segmentType, ReaderInfo.createFromArray(segmentBytes1));
+ JpegSegment segment2 = new JpegSegment(segmentType, ReaderInfo.createFromArray(segmentBytes2));
+
+ segmentData.addSegment(segment1);
+ segmentData.addSegment(segment2);
+ assertEquals(2, segmentData.getSegmentCount(segmentType));
+ assertArrayEquals(segmentBytes1, segmentData.getSegment(segmentType).getReader().toArray());
+ assertArrayEquals(segmentBytes1, segmentData.getSegment(segmentType, 0).getReader().toArray());
+ assertArrayEquals(segmentBytes2, segmentData.getSegment(segmentType, 1).getReader().toArray());
}
@Test
@@ -98,20 +107,23 @@ public void testRemoveSegmentOccurrence() throws Exception
{
JpegSegmentData segmentData = new JpegSegmentData();
- byte segmentMarker = (byte)12;
+ JpegSegmentType segmentType = JpegSegmentType.APP0;
byte[] segmentBytes1 = new byte[] { 1,2,3 };
byte[] segmentBytes2 = new byte[] { 3,2,1 };
- segmentData.addSegment(segmentMarker, segmentBytes1);
- segmentData.addSegment(segmentMarker, segmentBytes2);
+ JpegSegment segment1 = new JpegSegment(segmentType, ReaderInfo.createFromArray(segmentBytes1));
+ JpegSegment segment2 = new JpegSegment(segmentType, ReaderInfo.createFromArray(segmentBytes2));
+
+ segmentData.addSegment(segment1);
+ segmentData.addSegment(segment2);
- assertEquals(2, segmentData.getSegmentCount(segmentMarker));
+ assertEquals(2, segmentData.getSegmentCount(segmentType));
- assertArrayEquals(segmentBytes1, segmentData.getSegment(segmentMarker, 0));
+ assertArrayEquals(segmentBytes1, segmentData.getSegment(segmentType, 0).getReader().toArray());
- segmentData.removeSegmentOccurrence(segmentMarker, 0);
+ segmentData.removeSegmentOccurrence(segmentType, 0);
- assertArrayEquals(segmentBytes2, segmentData.getSegment(segmentMarker, 0));
+ assertArrayEquals(segmentBytes2, segmentData.getSegment(segmentType, 0).getReader().toArray());
}
@Test
@@ -119,21 +131,24 @@ public void testRemoveSegment() throws Exception
{
JpegSegmentData segmentData = new JpegSegmentData();
- byte segmentMarker = (byte)12;
+ JpegSegmentType segmentType = JpegSegmentType.APP0;
byte[] segmentBytes1 = new byte[] { 1,2,3 };
byte[] segmentBytes2 = new byte[] { 3,2,1 };
- segmentData.addSegment(segmentMarker, segmentBytes1);
- segmentData.addSegment(segmentMarker, segmentBytes2);
+ JpegSegment segment1 = new JpegSegment(segmentType, ReaderInfo.createFromArray(segmentBytes1));
+ JpegSegment segment2 = new JpegSegment(segmentType, ReaderInfo.createFromArray(segmentBytes2));
+
+ segmentData.addSegment(segment1);
+ segmentData.addSegment(segment2);
- assertEquals(2, segmentData.getSegmentCount(segmentMarker));
- assertTrue(segmentData.containsSegment(segmentMarker));
+ assertEquals(2, segmentData.getSegmentCount(segmentType));
+ assertTrue(segmentData.containsSegment(segmentType));
- assertArrayEquals(segmentBytes1, segmentData.getSegment(segmentMarker, 0));
+ assertArrayEquals(segmentBytes1, segmentData.getSegment(segmentType, 0).getReader().toArray());
- segmentData.removeSegment(segmentMarker);
+ segmentData.removeSegment(segmentType);
- assertTrue(!segmentData.containsSegment(segmentMarker));
- assertEquals(0, segmentData.getSegmentCount(segmentMarker));
+ assertTrue(!segmentData.containsSegment(segmentType));
+ assertEquals(0, segmentData.getSegmentCount(segmentType));
}
}
diff --git a/Tests/com/drew/imaging/jpeg/JpegSegmentReaderTest.java b/Tests/com/drew/imaging/jpeg/JpegSegmentReaderTest.java
index edea9ab1a..f4601ca1a 100644
--- a/Tests/com/drew/imaging/jpeg/JpegSegmentReaderTest.java
+++ b/Tests/com/drew/imaging/jpeg/JpegSegmentReaderTest.java
@@ -39,39 +39,39 @@ public class JpegSegmentReaderTest
@Test
public void testReadAllSegments() throws Exception
{
- JpegSegmentData segmentData = JpegSegmentReader.readSegments(new File("Tests/Data/withExifAndIptc.jpg"), null);
+ JpegSegmentData segmentData = JpegSegmentReader.readSegments(new File("Tests/Data/withExifAndIptc.jpg"), null, true);
assertEquals(1, segmentData.getSegmentCount(JpegSegmentType.APP0));
assertArrayEquals(
FileUtil.readBytes("Tests/Data/withExifAndIptc.jpg.app0"),
- segmentData.getSegment(JpegSegmentType.APP0));
+ segmentData.getSegment(JpegSegmentType.APP0).getReader().toArray());
assertNull(segmentData.getSegment(JpegSegmentType.APP0, 1));
assertEquals(2, segmentData.getSegmentCount(JpegSegmentType.APP1));
assertArrayEquals(
FileUtil.readBytes("Tests/Data/withExifAndIptc.jpg.app1.0"),
- segmentData.getSegment(JpegSegmentType.APP1, 0));
+ segmentData.getSegment(JpegSegmentType.APP1, 0).getReader().toArray());
assertArrayEquals(
FileUtil.readBytes("Tests/Data/withExifAndIptc.jpg.app1.1"),
- segmentData.getSegment(JpegSegmentType.APP1, 1));
+ segmentData.getSegment(JpegSegmentType.APP1, 1).getReader().toArray());
assertNull(segmentData.getSegment(JpegSegmentType.APP1, 2));
assertEquals(1, segmentData.getSegmentCount(JpegSegmentType.APP2));
assertArrayEquals(
FileUtil.readBytes("Tests/Data/withExifAndIptc.jpg.app2"),
- segmentData.getSegment(JpegSegmentType.APP2));
+ segmentData.getSegment(JpegSegmentType.APP2).getReader().toArray());
assertNull(segmentData.getSegment(JpegSegmentType.APP2, 1));
assertEquals(1, segmentData.getSegmentCount(JpegSegmentType.APPD));
assertArrayEquals(
FileUtil.readBytes("Tests/Data/withExifAndIptc.jpg.appd"),
- segmentData.getSegment(JpegSegmentType.APPD));
+ segmentData.getSegment(JpegSegmentType.APPD).getReader().toArray());
assertNull(segmentData.getSegment(JpegSegmentType.APPD, 1));
assertEquals(1, segmentData.getSegmentCount(JpegSegmentType.APPE));
assertArrayEquals(
FileUtil.readBytes("Tests/Data/withExifAndIptc.jpg.appe"),
- segmentData.getSegment(JpegSegmentType.APPE));
+ segmentData.getSegment(JpegSegmentType.APPE).getReader().toArray());
assertNull(segmentData.getSegment(JpegSegmentType.APPE, 1));
assertEquals(0, segmentData.getSegmentCount(JpegSegmentType.APP3));
@@ -99,7 +99,8 @@ public void testReadSpecificSegments() throws Exception
{
JpegSegmentData segmentData = JpegSegmentReader.readSegments(
new File("Tests/Data/withExifAndIptc.jpg"),
- Arrays.asList(JpegSegmentType.APP0, JpegSegmentType.APP2));
+ Arrays.asList(JpegSegmentType.APP0, JpegSegmentType.APP2),
+ true);
assertEquals(1, segmentData.getSegmentCount(JpegSegmentType.APP0));
assertEquals(0, segmentData.getSegmentCount(JpegSegmentType.APP1));
@@ -123,10 +124,10 @@ public void testReadSpecificSegments() throws Exception
assertArrayEquals(
FileUtil.readBytes("Tests/Data/withExifAndIptc.jpg.app0"),
- segmentData.getSegment(JpegSegmentType.APP0));
+ segmentData.getSegment(JpegSegmentType.APP0).getReader().toArray());
assertArrayEquals(
FileUtil.readBytes("Tests/Data/withExifAndIptc.jpg.app2"),
- segmentData.getSegment(JpegSegmentType.APP2));
+ segmentData.getSegment(JpegSegmentType.APP2).getReader().toArray());
}
@Test
diff --git a/Tests/com/drew/imaging/png/PngChunkReaderTest.java b/Tests/com/drew/imaging/png/PngChunkReaderTest.java
index d9ba01b1c..bdb3a1de4 100644
--- a/Tests/com/drew/imaging/png/PngChunkReaderTest.java
+++ b/Tests/com/drew/imaging/png/PngChunkReaderTest.java
@@ -21,9 +21,10 @@
package com.drew.imaging.png;
import com.drew.lang.Iterables;
-import com.drew.lang.StreamReader;
+import com.drew.lang.RandomAccessStream;
import org.junit.Test;
+import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.List;
@@ -37,10 +38,12 @@ public class PngChunkReaderTest
{
public static List processFile(String filePath) throws PngProcessingException, IOException
{
+ File file = new File(filePath);
+
FileInputStream inputStream = null;
try {
- inputStream = new FileInputStream(filePath);
- return Iterables.toList(new PngChunkReader().extract(new StreamReader(inputStream), null));
+ inputStream = new FileInputStream(file);
+ return Iterables.toList(new PngChunkReader().extract(new RandomAccessStream(inputStream, file.length()).createReader(), null));
} finally {
if (inputStream != null) {
inputStream.close();
@@ -56,22 +59,22 @@ public void testExtractMspaint() throws Exception
assertEquals(6, chunks.size());
assertEquals(PngChunkType.IHDR, chunks.get(0).getType());
- assertEquals(13, chunks.get(0).getBytes().length);
+ assertEquals(13, chunks.get(0).getReader().getLength()); //.getBytes().length);
assertEquals(PngChunkType.sRGB, chunks.get(1).getType());
- assertEquals(1, chunks.get(1).getBytes().length);
+ assertEquals(1, chunks.get(1).getReader().getLength());
assertEquals(PngChunkType.gAMA, chunks.get(2).getType());
- assertEquals(4, chunks.get(2).getBytes().length);
+ assertEquals(4, chunks.get(2).getReader().getLength());
assertEquals(PngChunkType.pHYs, chunks.get(3).getType());
- assertEquals(9, chunks.get(3).getBytes().length);
+ assertEquals(9, chunks.get(3).getReader().getLength());
assertEquals(PngChunkType.IDAT, chunks.get(4).getType());
- assertEquals(17, chunks.get(4).getBytes().length);
+ assertEquals(17, chunks.get(4).getReader().getLength());
assertEquals(PngChunkType.IEND, chunks.get(5).getType());
- assertEquals(0, chunks.get(5).getBytes().length);
+ assertEquals(0, chunks.get(5).getReader().getLength());
}
@Test
@@ -82,18 +85,18 @@ public void testExtractPhotoshop() throws Exception
assertEquals(5, chunks.size());
assertEquals(PngChunkType.IHDR, chunks.get(0).getType());
- assertEquals(13, chunks.get(0).getBytes().length);
+ assertEquals(13, chunks.get(0).getReader().getLength());
assertEquals(PngChunkType.tEXt, chunks.get(1).getType());
- assertEquals(25, chunks.get(1).getBytes().length);
+ assertEquals(25, chunks.get(1).getReader().getLength());
assertEquals(PngChunkType.iTXt, chunks.get(2).getType());
- assertEquals(802, chunks.get(2).getBytes().length);
+ assertEquals(802, chunks.get(2).getReader().getLength());
assertEquals(PngChunkType.IDAT, chunks.get(3).getType());
- assertEquals(130, chunks.get(3).getBytes().length);
+ assertEquals(130, chunks.get(3).getReader().getLength());
assertEquals(PngChunkType.IEND, chunks.get(4).getType());
- assertEquals(0, chunks.get(4).getBytes().length);
+ assertEquals(0, chunks.get(4).getReader().getLength());
}
}
diff --git a/Tests/com/drew/imaging/png/PngMetadataReaderTest.java b/Tests/com/drew/imaging/png/PngMetadataReaderTest.java
index 6bf880932..2efe92ac9 100644
--- a/Tests/com/drew/imaging/png/PngMetadataReaderTest.java
+++ b/Tests/com/drew/imaging/png/PngMetadataReaderTest.java
@@ -22,10 +22,12 @@
import com.drew.lang.KeyValuePair;
import com.drew.lang.annotations.NotNull;
+import com.drew.lang.RandomAccessStream;
import com.drew.metadata.Metadata;
import com.drew.metadata.png.PngDirectory;
import org.junit.Test;
+import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.text.SimpleDateFormat;
@@ -44,10 +46,11 @@ public class PngMetadataReaderTest
@NotNull
private static Metadata processFile(@NotNull String filePath) throws PngProcessingException, IOException
{
+ File file = new File(filePath);
FileInputStream inputStream = null;
try {
- inputStream = new FileInputStream(filePath);
- return PngMetadataReader.readMetadata(inputStream);
+ inputStream = new FileInputStream(file);
+ return PngMetadataReader.readMetadata(new RandomAccessStream(inputStream, file.length()).createReader());
} finally {
if (inputStream != null) {
inputStream.close();
diff --git a/Tests/com/drew/lang/ByteArrayReaderTest.java b/Tests/com/drew/lang/ByteArrayReaderTest.java
index 01403c97e..d41a8ea73 100644
--- a/Tests/com/drew/lang/ByteArrayReaderTest.java
+++ b/Tests/com/drew/lang/ByteArrayReaderTest.java
@@ -29,15 +29,15 @@
public class ByteArrayReaderTest extends RandomAccessTestBase
{
@Override
- protected RandomAccessReader createReader(byte[] bytes)
+ protected ReaderInfo createReader(byte[] bytes)
{
- return new ByteArrayReader(bytes);
+ return ReaderInfo.createFromArray(bytes);
}
@SuppressWarnings({ "ConstantConditions" })
@Test(expected = NullPointerException.class)
public void testConstructWithNullBufferThrows()
{
- new ByteArrayReader(null);
+ ReaderInfo.createFromArray(null);
}
}
diff --git a/Tests/com/drew/lang/RandomAccessFileReaderTest.java b/Tests/com/drew/lang/RandomAccessFileReaderTest.java
index 173cdeea1..995839167 100644
--- a/Tests/com/drew/lang/RandomAccessFileReaderTest.java
+++ b/Tests/com/drew/lang/RandomAccessFileReaderTest.java
@@ -41,7 +41,7 @@ public class RandomAccessFileReaderTest extends RandomAccessTestBase
private RandomAccessFile _randomAccessFile;
@Override
- protected RandomAccessReader createReader(byte[] bytes)
+ protected ReaderInfo createReader(byte[] bytes)
{
try {
// Unit tests can create multiple readers in the same test, as long as they're used one after the other
@@ -50,7 +50,7 @@ protected RandomAccessReader createReader(byte[] bytes)
_tempFile = File.createTempFile("metadata-extractor-test-", ".tmp");
FileUtil.saveBytes(_tempFile, bytes);
_randomAccessFile = new RandomAccessFile(_tempFile, "r");
- return new RandomAccessFileReader(_randomAccessFile);
+ return new RandomAccessStream(_randomAccessFile).createReader();
} catch (IOException e) {
fail("Unable to create temp file");
return null;
@@ -80,6 +80,6 @@ public void deleteTempFile() throws IOException
@Test(expected = NullPointerException.class)
public void testConstructWithNullBufferThrows() throws IOException
{
- new RandomAccessFileReader(null);
+ ReaderInfo.createFromArray(null);
}
}
diff --git a/Tests/com/drew/lang/RandomAccessStreamReaderTest.java b/Tests/com/drew/lang/RandomAccessStreamReaderTest.java
index 8295965c7..25b9f3bb8 100644
--- a/Tests/com/drew/lang/RandomAccessStreamReaderTest.java
+++ b/Tests/com/drew/lang/RandomAccessStreamReaderTest.java
@@ -23,8 +23,6 @@
import org.junit.Test;
-import java.io.ByteArrayInputStream;
-
/**
* @author Drew Noakes https://drewnoakes.com
*/
@@ -34,12 +32,12 @@ public class RandomAccessStreamReaderTest extends RandomAccessTestBase
@Test(expected = NullPointerException.class)
public void testConstructWithNullBufferThrows()
{
- new RandomAccessStreamReader(null);
+ ReaderInfo.createFromArray(null);
}
@Override
- protected RandomAccessReader createReader(byte[] bytes)
+ protected ReaderInfo createReader(byte[] bytes)
{
- return new RandomAccessStreamReader(new ByteArrayInputStream(bytes));
+ return ReaderInfo.createFromArray(bytes);
}
}
diff --git a/Tests/com/drew/lang/RandomAccessTestBase.java b/Tests/com/drew/lang/RandomAccessTestBase.java
index 809c2e2a4..2bc4674d9 100644
--- a/Tests/com/drew/lang/RandomAccessTestBase.java
+++ b/Tests/com/drew/lang/RandomAccessTestBase.java
@@ -36,7 +36,7 @@
*/
public abstract class RandomAccessTestBase
{
- protected abstract RandomAccessReader createReader(byte[] bytes);
+ protected abstract ReaderInfo createReader(byte[] bytes);
@Test
public void testDefaultEndianness()
@@ -48,7 +48,7 @@ public void testDefaultEndianness()
public void testGetInt8() throws Exception
{
byte[] buffer = new byte[]{0x00, 0x01, (byte)0x7F, (byte)0xFF};
- RandomAccessReader reader = createReader(buffer);
+ ReaderInfo reader = createReader(buffer);
assertEquals((byte)0, reader.getInt8(0));
assertEquals((byte)1, reader.getInt8(1));
@@ -60,7 +60,7 @@ public void testGetInt8() throws Exception
public void testGetUInt8() throws Exception
{
byte[] buffer = new byte[]{0x00, 0x01, (byte)0x7F, (byte)0xFF};
- RandomAccessReader reader = createReader(buffer);
+ ReaderInfo reader = createReader(buffer);
assertEquals(0, reader.getUInt8(0));
assertEquals(1, reader.getUInt8(1));
@@ -72,7 +72,7 @@ public void testGetUInt8() throws Exception
public void testGetUInt8_OutOfBounds()
{
try {
- RandomAccessReader reader = createReader(new byte[2]);
+ ReaderInfo reader = createReader(new byte[2]);
reader.getUInt8(2);
fail("Exception expected");
} catch (IOException ex) {
@@ -86,7 +86,7 @@ public void testGetInt16() throws Exception
assertEquals(-1, createReader(new byte[]{(byte)0xff, (byte)0xff}).getInt16(0));
byte[] buffer = new byte[]{0x00, 0x01, (byte)0x7F, (byte)0xFF};
- RandomAccessReader reader = createReader(buffer);
+ ReaderInfo reader = createReader(buffer);
assertEquals((short)0x0001, reader.getInt16(0));
assertEquals((short)0x017F, reader.getInt16(1));
@@ -103,7 +103,7 @@ public void testGetInt16() throws Exception
public void testGetUInt16() throws Exception
{
byte[] buffer = new byte[]{0x00, 0x01, (byte)0x7F, (byte)0xFF};
- RandomAccessReader reader = createReader(buffer);
+ ReaderInfo reader = createReader(buffer);
assertEquals(0x0001, reader.getUInt16(0));
assertEquals(0x017F, reader.getUInt16(1));
@@ -120,7 +120,7 @@ public void testGetUInt16() throws Exception
public void testGetUInt16_OutOfBounds()
{
try {
- RandomAccessReader reader = createReader(new byte[2]);
+ ReaderInfo reader = createReader(new byte[2]);
reader.getUInt16(1);
fail("Exception expected");
} catch (IOException ex) {
@@ -134,7 +134,7 @@ public void testGetInt32() throws Exception
assertEquals(-1, createReader(new byte[]{(byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff}).getInt32(0));
byte[] buffer = new byte[]{0x00, 0x01, (byte)0x7F, (byte)0xFF, 0x02, 0x03, 0x04};
- RandomAccessReader reader = createReader(buffer);
+ ReaderInfo reader = createReader(buffer);
assertEquals(0x00017FFF, reader.getInt32(0));
assertEquals(0x017FFF02, reader.getInt32(1));
@@ -155,7 +155,7 @@ public void testGetUInt32() throws Exception
assertEquals(4294967295L, createReader(new byte[]{(byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff}).getUInt32(0));
byte[] buffer = new byte[]{0x00, 0x01, (byte)0x7F, (byte)0xFF, 0x02, 0x03, 0x04};
- RandomAccessReader reader = createReader(buffer);
+ ReaderInfo reader = createReader(buffer);
assertEquals(0x00017FFFL, reader.getUInt32(0));
assertEquals(0x017FFF02L, reader.getUInt32(1));
@@ -174,7 +174,7 @@ public void testGetUInt32() throws Exception
public void testGetInt32_OutOfBounds()
{
try {
- RandomAccessReader reader = createReader(new byte[3]);
+ ReaderInfo reader = createReader(new byte[3]);
reader.getInt32(0);
fail("Exception expected");
} catch (IOException ex) {
@@ -186,7 +186,7 @@ public void testGetInt32_OutOfBounds()
public void testGetInt64() throws IOException
{
byte[] buffer = new byte[]{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, (byte)0xFF};
- RandomAccessReader reader = createReader(buffer);
+ ReaderInfo reader = createReader(buffer);
assertEquals(0x0001020304050607L, reader.getInt64(0));
assertEquals(0x01020304050607FFL, reader.getInt64(1));
@@ -201,14 +201,14 @@ public void testGetInt64() throws IOException
public void testGetInt64_OutOfBounds() throws Exception
{
try {
- RandomAccessReader reader = createReader(new byte[7]);
+ ReaderInfo reader = createReader(new byte[7]);
reader.getInt64(0);
fail("Exception expected");
} catch (IOException ex) {
assertEquals("Attempt to read from beyond end of underlying data source (requested index: 0, requested count: 8, max index: 6)", ex.getMessage());
}
try {
- RandomAccessReader reader = createReader(new byte[7]);
+ ReaderInfo reader = createReader(new byte[7]);
reader.getInt64(-1);
fail("Exception expected");
} catch (IOException ex) {
@@ -223,7 +223,7 @@ public void testGetFloat32() throws Exception
assertTrue(Float.isNaN(Float.intBitsToFloat(nanBits)));
byte[] buffer = new byte[]{0x7f, (byte)0xc0, 0x00, 0x00};
- RandomAccessReader reader = createReader(buffer);
+ ReaderInfo reader = createReader(buffer);
assertTrue(Float.isNaN(reader.getFloat32(0)));
}
@@ -235,7 +235,7 @@ public void testGetFloat64() throws Exception
assertTrue(Double.isNaN(Double.longBitsToDouble(nanBits)));
byte[] buffer = new byte[]{(byte)0xff, (byte)0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01};
- RandomAccessReader reader = createReader(buffer);
+ ReaderInfo reader = createReader(buffer);
assertTrue(Double.isNaN(reader.getDouble64(0)));
}
@@ -244,7 +244,7 @@ public void testGetFloat64() throws Exception
public void testGetNullTerminatedString() throws Exception
{
byte[] bytes = new byte[]{0x41, 0x42, 0x43, 0x44, 0x00, 0x45, 0x46, 0x47};
- RandomAccessReader reader = createReader(bytes);
+ ReaderInfo reader = createReader(bytes);
assertEquals("", reader.getNullTerminatedString(0, 0, Charsets.UTF_8));
assertEquals("A", reader.getNullTerminatedString(0, 1, Charsets.UTF_8));
@@ -265,7 +265,7 @@ public void testGetNullTerminatedString() throws Exception
public void testGetString() throws Exception
{
byte[] bytes = new byte[]{0x41, 0x42, 0x43, 0x44, 0x00, 0x45, 0x46, 0x47};
- RandomAccessReader reader = createReader(bytes);
+ ReaderInfo reader = createReader(bytes);
assertEquals("", reader.getString(0, 0, Charsets.UTF_8));
assertEquals("A", reader.getString(0, 1, Charsets.UTF_8));
@@ -285,7 +285,7 @@ public void testGetString() throws Exception
@Test
public void testIndexPlusCountExceedsIntMaxValue()
{
- RandomAccessReader reader = createReader(new byte[10]);
+ ReaderInfo reader = createReader(new byte[10]);
try {
reader.getBytes(0x6FFFFFFF, 0x6FFFFFFF);
@@ -297,7 +297,7 @@ public void testIndexPlusCountExceedsIntMaxValue()
@Test
public void testOverflowBoundsCalculation()
{
- RandomAccessReader reader = createReader(new byte[10]);
+ ReaderInfo reader = createReader(new byte[10]);
try {
reader.getBytes(5, 10);
@@ -311,7 +311,7 @@ public void testGetBytesEOF() throws Exception
{
createReader(new byte[50]).getBytes(0, 50);
- RandomAccessReader reader = createReader(new byte[50]);
+ ReaderInfo reader = createReader(new byte[50]);
reader.getBytes(25, 25);
try {
@@ -325,7 +325,7 @@ public void testGetInt8EOF() throws Exception
{
createReader(new byte[1]).getInt8(0);
- RandomAccessReader reader = createReader(new byte[2]);
+ ReaderInfo reader = createReader(new byte[2]);
reader.getInt8(0);
reader.getInt8(1);
diff --git a/Tests/com/drew/lang/SequentialAccessTestBase.java b/Tests/com/drew/lang/SequentialAccessTestBase.java
index 57e4b5e95..152188d3c 100644
--- a/Tests/com/drew/lang/SequentialAccessTestBase.java
+++ b/Tests/com/drew/lang/SequentialAccessTestBase.java
@@ -35,7 +35,7 @@
*/
public abstract class SequentialAccessTestBase
{
- protected abstract SequentialReader createReader(byte[] bytes);
+ protected abstract ReaderInfo createReader(byte[] bytes);
@Test
public void testDefaultEndianness()
@@ -47,7 +47,7 @@ public void testDefaultEndianness()
public void testGetInt8() throws IOException
{
byte[] buffer = new byte[]{0x00, 0x01, (byte)0x7F, (byte)0xFF};
- SequentialReader reader = createReader(buffer);
+ ReaderInfo reader = createReader(buffer);
assertEquals((byte)0, reader.getInt8());
assertEquals((byte)1, reader.getInt8());
@@ -59,7 +59,7 @@ public void testGetInt8() throws IOException
public void testGetUInt8() throws IOException
{
byte[] buffer = new byte[]{0x00, 0x01, (byte)0x7F, (byte)0xFF};
- SequentialReader reader = createReader(buffer);
+ ReaderInfo reader = createReader(buffer);
assertEquals(0, reader.getUInt8());
assertEquals(1, reader.getUInt8());
@@ -71,7 +71,7 @@ public void testGetUInt8() throws IOException
public void testGetUInt8_OutOfBounds()
{
try {
- SequentialReader reader = createReader(new byte[1]);
+ ReaderInfo reader = createReader(new byte[1]);
reader.getUInt8();
reader.getUInt8();
fail("Exception expected");
@@ -86,7 +86,7 @@ public void testGetInt16() throws IOException
assertEquals(-1, createReader(new byte[]{(byte)0xff, (byte)0xff}).getInt16());
byte[] buffer = new byte[]{0x00, 0x01, (byte)0x7F, (byte)0xFF};
- SequentialReader reader = createReader(buffer);
+ ReaderInfo reader = createReader(buffer);
assertEquals((short)0x0001, reader.getInt16());
assertEquals((short)0x7FFF, reader.getInt16());
@@ -102,7 +102,7 @@ public void testGetInt16() throws IOException
public void testGetUInt16() throws IOException
{
byte[] buffer = new byte[]{0x00, 0x01, (byte)0x7F, (byte)0xFF};
- SequentialReader reader = createReader(buffer);
+ ReaderInfo reader = createReader(buffer);
assertEquals(0x0001, reader.getUInt16());
assertEquals(0x7FFF, reader.getUInt16());
@@ -118,7 +118,7 @@ public void testGetUInt16() throws IOException
public void testGetUInt16_OutOfBounds()
{
try {
- SequentialReader reader = createReader(new byte[1]);
+ ReaderInfo reader = createReader(new byte[1]);
reader.getUInt16();
fail("Exception expected");
} catch (IOException ex) {
@@ -132,7 +132,7 @@ public void testGetInt32() throws IOException
assertEquals(-1, createReader(new byte[]{(byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff}).getInt32());
byte[] buffer = new byte[]{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07};
- SequentialReader reader = createReader(buffer);
+ ReaderInfo reader = createReader(buffer);
assertEquals(0x00010203, reader.getInt32());
assertEquals(0x04050607, reader.getInt32());
@@ -150,7 +150,7 @@ public void testGetUInt32() throws IOException
assertEquals(4294967295L, createReader(new byte[]{(byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff}).getUInt32());
byte[] buffer = new byte[]{(byte)0xFF, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06};
- SequentialReader reader = createReader(buffer);
+ ReaderInfo reader = createReader(buffer);
assertEquals(0xFF000102L, reader.getUInt32());
assertEquals(0x03040506L, reader.getUInt32());
@@ -166,7 +166,7 @@ public void testGetUInt32() throws IOException
public void testGetInt32_OutOfBounds()
{
try {
- SequentialReader reader = createReader(new byte[3]);
+ ReaderInfo reader = createReader(new byte[3]);
reader.getInt32();
fail("Exception expected");
} catch (IOException ex) {
@@ -178,7 +178,7 @@ public void testGetInt32_OutOfBounds()
public void testGetInt64() throws IOException
{
byte[] buffer = new byte[]{(byte)0xFF, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07};
- SequentialReader reader = createReader(buffer);
+ ReaderInfo reader = createReader(buffer);
assertEquals(0xFF00010203040506L, reader.getInt64());
@@ -192,7 +192,7 @@ public void testGetInt64() throws IOException
public void testGetInt64_OutOfBounds()
{
try {
- SequentialReader reader = createReader(new byte[7]);
+ ReaderInfo reader = createReader(new byte[7]);
reader.getInt64();
fail("Exception expected");
} catch (IOException ex) {
@@ -207,7 +207,7 @@ public void testGetFloat32() throws IOException
assertTrue(Float.isNaN(Float.intBitsToFloat(nanBits)));
byte[] buffer = new byte[]{0x7f, (byte)0xc0, 0x00, 0x00};
- SequentialReader reader = createReader(buffer);
+ ReaderInfo reader = createReader(buffer);
assertTrue(Float.isNaN(reader.getFloat32()));
}
@@ -219,7 +219,7 @@ public void testGetFloat64() throws IOException
assertTrue(Double.isNaN(Double.longBitsToDouble(nanBits)));
byte[] buffer = new byte[]{(byte)0xff, (byte)0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01};
- SequentialReader reader = createReader(buffer);
+ ReaderInfo reader = createReader(buffer);
assertTrue(Double.isNaN(reader.getDouble64()));
}
@@ -248,7 +248,8 @@ public void testGetString() throws IOException
assertEquals(bytes.length, expected.length());
for (int i = 0; i < bytes.length; i++) {
- assertEquals("ABCDEFG".substring(0, i), createReader(bytes).getString(i));
+ //assertEquals("ABCDEFG".substring(0, i), createReader(bytes).getString(i));
+ assertEquals("ABCDEFG".substring(0, i), createReader(bytes).getString(i, Charsets.UTF_8));
}
}
@@ -258,7 +259,7 @@ public void testGetBytes() throws IOException
byte[] bytes = {0, 1, 2, 3, 4, 5};
for (int i = 0; i < bytes.length; i++) {
- SequentialReader reader = createReader(bytes);
+ ReaderInfo reader = createReader(bytes);
byte[] readBytes = reader.getBytes(i);
for (int j = 0; j < i; j++) {
assertEquals(bytes[j], readBytes[j]);
@@ -269,7 +270,7 @@ public void testGetBytes() throws IOException
@Test
public void testOverflowBoundsCalculation()
{
- SequentialReader reader = createReader(new byte[10]);
+ ReaderInfo reader = createReader(new byte[10]);
try {
reader.getBytes(15);
@@ -283,7 +284,7 @@ public void testGetBytesEOF() throws Exception
{
createReader(new byte[50]).getBytes(50);
- SequentialReader reader = createReader(new byte[50]);
+ ReaderInfo reader = createReader(new byte[50]);
reader.getBytes(25);
reader.getBytes(25);
@@ -298,7 +299,7 @@ public void testGetInt8EOF() throws Exception
{
createReader(new byte[1]).getInt8();
- SequentialReader reader = createReader(new byte[2]);
+ ReaderInfo reader = createReader(new byte[2]);
reader.getInt8();
reader.getInt8();
@@ -315,7 +316,7 @@ public void testSkipEOF() throws Exception
{
createReader(new byte[1]).skip(1);
- SequentialReader reader = createReader(new byte[2]);
+ ReaderInfo reader = createReader(new byte[2]);
reader.skip(1);
reader.skip(1);
@@ -324,7 +325,8 @@ public void testSkipEOF() throws Exception
reader.skip(1);
reader.skip(1);
fail("Expecting exception");
- } catch (EOFException ignored) {}
+ } catch (BufferBoundsException ignored) {}
+ //} catch (EOFException ignored) {}
}
@Test
@@ -332,7 +334,7 @@ public void testTrySkipEOF() throws Exception
{
assertTrue(createReader(new byte[1]).trySkip(1));
- SequentialReader reader = createReader(new byte[2]);
+ ReaderInfo reader = createReader(new byte[2]);
assertTrue(reader.trySkip(1));
assertTrue(reader.trySkip(1));
assertFalse(reader.trySkip(1));
diff --git a/Tests/com/drew/lang/SequentialByteArrayReaderTest.java b/Tests/com/drew/lang/SequentialByteArrayReaderTest.java
index 44ab50490..d05a0cccf 100644
--- a/Tests/com/drew/lang/SequentialByteArrayReaderTest.java
+++ b/Tests/com/drew/lang/SequentialByteArrayReaderTest.java
@@ -31,12 +31,12 @@ public class SequentialByteArrayReaderTest extends SequentialAccessTestBase
@Test(expected = NullPointerException.class)
public void testConstructWithNullStreamThrows()
{
- new SequentialByteArrayReader(null);
+ ReaderInfo.createFromArray(null);
}
@Override
- protected SequentialReader createReader(byte[] bytes)
+ protected ReaderInfo createReader(byte[] bytes)
{
- return new SequentialByteArrayReader(bytes);
+ return ReaderInfo.createFromArray(bytes);
}
}
diff --git a/Tests/com/drew/lang/StreamReaderTest.java b/Tests/com/drew/lang/StreamReaderTest.java
index 537a88834..f1d6f28ee 100644
--- a/Tests/com/drew/lang/StreamReaderTest.java
+++ b/Tests/com/drew/lang/StreamReaderTest.java
@@ -22,8 +22,6 @@
import org.junit.Test;
-import java.io.ByteArrayInputStream;
-
/**
* @author Drew Noakes https://drewnoakes.com
*/
@@ -33,12 +31,12 @@ public class StreamReaderTest extends SequentialAccessTestBase
@Test(expected = NullPointerException.class)
public void testConstructWithNullStreamThrows()
{
- new StreamReader(null);
+ ReaderInfo.createFromArray(null);
}
@Override
- protected SequentialReader createReader(byte[] bytes)
+ protected ReaderInfo createReader(byte[] bytes)
{
- return new StreamReader(new ByteArrayInputStream(bytes));
+ return ReaderInfo.createFromArray(bytes);
}
}
diff --git a/Tests/com/drew/metadata/adobe/AdobeJpegReaderTest.java b/Tests/com/drew/metadata/adobe/AdobeJpegReaderTest.java
index d3b1dfe23..29d03d8cc 100644
--- a/Tests/com/drew/metadata/adobe/AdobeJpegReaderTest.java
+++ b/Tests/com/drew/metadata/adobe/AdobeJpegReaderTest.java
@@ -22,7 +22,6 @@
package com.drew.metadata.adobe;
import com.drew.imaging.jpeg.JpegSegmentType;
-import com.drew.lang.SequentialByteArrayReader;
import com.drew.lang.annotations.NotNull;
import com.drew.metadata.Metadata;
import com.drew.tools.FileUtil;
@@ -31,6 +30,7 @@
import java.io.IOException;
import static com.drew.lang.Iterables.toList;
+import com.drew.lang.ReaderInfo;
import static org.junit.Assert.*;
/**
@@ -42,7 +42,7 @@ public class AdobeJpegReaderTest
public static AdobeJpegDirectory processBytes(@NotNull String filePath) throws IOException
{
Metadata metadata = new Metadata();
- new AdobeJpegReader().extract(new SequentialByteArrayReader(FileUtil.readBytes(filePath)), metadata);
+ new AdobeJpegReader().extract(ReaderInfo.createFromArray(FileUtil.readBytes(filePath)), metadata);
AdobeJpegDirectory directory = metadata.getFirstDirectoryOfType(AdobeJpegDirectory.class);
assertNotNull(directory);
diff --git a/Tests/com/drew/metadata/bmp/BmpReaderTest.java b/Tests/com/drew/metadata/bmp/BmpReaderTest.java
index 10fc40e4a..020a2218c 100644
--- a/Tests/com/drew/metadata/bmp/BmpReaderTest.java
+++ b/Tests/com/drew/metadata/bmp/BmpReaderTest.java
@@ -21,13 +21,12 @@
package com.drew.metadata.bmp;
-import com.drew.lang.StreamReader;
+import com.drew.lang.RandomAccessStream;
import com.drew.lang.annotations.NotNull;
import com.drew.metadata.Metadata;
import org.junit.Test;
-import java.io.FileInputStream;
-import java.io.InputStream;
+import java.io.RandomAccessFile;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
@@ -42,9 +41,9 @@ public class BmpReaderTest
public static BmpHeaderDirectory processBytes(@NotNull String file) throws Exception
{
Metadata metadata = new Metadata();
- InputStream stream = new FileInputStream(file);
- new BmpReader().extract(new StreamReader(stream), metadata);
- stream.close();
+ RandomAccessFile raf = new RandomAccessFile(file, "r");
+ new BmpReader().extract(new RandomAccessStream(raf).createReader(), metadata);
+ raf.close();
BmpHeaderDirectory directory = metadata.getFirstDirectoryOfType(BmpHeaderDirectory.class);
assertNotNull(directory);
diff --git a/Tests/com/drew/metadata/eps/EpsReaderTest.java b/Tests/com/drew/metadata/eps/EpsReaderTest.java
index 6c3d9aa53..641b52e9a 100644
--- a/Tests/com/drew/metadata/eps/EpsReaderTest.java
+++ b/Tests/com/drew/metadata/eps/EpsReaderTest.java
@@ -1,6 +1,7 @@
package com.drew.metadata.eps;
import com.drew.lang.annotations.NotNull;
+import com.drew.lang.RandomAccessStream;
import com.drew.metadata.Metadata;
import org.junit.Test;
@@ -17,12 +18,13 @@
public class EpsReaderTest
{
@NotNull
- public static EpsDirectory processBytes(@NotNull String file) throws Exception
+ public static EpsDirectory processBytes(@NotNull String filePath) throws Exception
{
Metadata metadata = new Metadata();
- InputStream stream = new FileInputStream(new File(file));
+ File file = new File(filePath);
+ InputStream stream = new FileInputStream(file);
try {
- new EpsReader().extract(stream, metadata);
+ new EpsReader().extract(new RandomAccessStream(stream, file.length()).createReader(), metadata);
} catch (Exception e) {
stream.close();
throw e;
diff --git a/Tests/com/drew/metadata/exif/ExifDirectoryTest.java b/Tests/com/drew/metadata/exif/ExifDirectoryTest.java
index 2e80651a9..b1482210c 100644
--- a/Tests/com/drew/metadata/exif/ExifDirectoryTest.java
+++ b/Tests/com/drew/metadata/exif/ExifDirectoryTest.java
@@ -21,6 +21,7 @@
package com.drew.metadata.exif;
import com.drew.imaging.jpeg.JpegProcessingException;
+import com.drew.imaging.jpeg.JpegSegmentType;
import com.drew.lang.GeoLocation;
import com.drew.metadata.Directory;
import com.drew.metadata.Metadata;
@@ -63,7 +64,7 @@ public void testGetDirectoryName() throws Exception
@Test
public void testDateTime() throws JpegProcessingException, IOException, MetadataException
{
- Metadata metadata = ExifReaderTest.processBytes("Tests/Data/nikonMakernoteType2a.jpg.app1");
+ Metadata metadata = ExifReaderTest.processSegmentBytes("Tests/Data/nikonMakernoteType2a.jpg.app1", JpegSegmentType.APP1);
ExifIFD0Directory exifIFD0Directory = metadata.getFirstDirectoryOfType(ExifIFD0Directory.class);
ExifSubIFDDirectory exifSubIFDDirectory = metadata.getFirstDirectoryOfType(ExifSubIFDDirectory.class);
@@ -100,7 +101,7 @@ public void testDateTime() throws JpegProcessingException, IOException, Metadata
@Test
public void testResolution() throws JpegProcessingException, IOException, MetadataException
{
- Metadata metadata = ExifReaderTest.processBytes("Tests/Data/withUncompressedRGBThumbnail.jpg.app1");
+ Metadata metadata = ExifReaderTest.processSegmentBytes("Tests/Data/withUncompressedRGBThumbnail.jpg.app1", JpegSegmentType.APP1);
ExifThumbnailDirectory thumbnailDirectory = metadata.getFirstDirectoryOfType(ExifThumbnailDirectory.class);
assertNotNull(thumbnailDirectory);
@@ -114,7 +115,7 @@ public void testResolution() throws JpegProcessingException, IOException, Metada
@Test
public void testGeoLocation() throws IOException, MetadataException
{
- Metadata metadata = ExifReaderTest.processBytes("Tests/Data/withExifAndIptc.jpg.app1.0");
+ Metadata metadata = ExifReaderTest.processSegmentBytes("Tests/Data/withExifAndIptc.jpg.app1.0", JpegSegmentType.APP1);
GpsDirectory gpsDirectory = metadata.getFirstDirectoryOfType(GpsDirectory.class);
assertNotNull(gpsDirectory);
@@ -126,7 +127,7 @@ public void testGeoLocation() throws IOException, MetadataException
@Test
public void testGpsDate() throws IOException, MetadataException
{
- Metadata metadata = ExifReaderTest.processBytes("Tests/Data/withPanasonicFaces.jpg.app1");
+ Metadata metadata = ExifReaderTest.processSegmentBytes("Tests/Data/withPanasonicFaces.jpg.app1", JpegSegmentType.APP1);
GpsDirectory gpsDirectory = metadata.getFirstDirectoryOfType(GpsDirectory.class);
assertNotNull(gpsDirectory);
diff --git a/Tests/com/drew/metadata/exif/ExifIFD0DescriptorTest.java b/Tests/com/drew/metadata/exif/ExifIFD0DescriptorTest.java
index 8b1ca9a19..3b5cd0ac2 100644
--- a/Tests/com/drew/metadata/exif/ExifIFD0DescriptorTest.java
+++ b/Tests/com/drew/metadata/exif/ExifIFD0DescriptorTest.java
@@ -21,6 +21,7 @@
package com.drew.metadata.exif;
+import com.drew.imaging.jpeg.JpegSegmentType;
import com.drew.lang.Rational;
import org.junit.Test;
@@ -59,7 +60,7 @@ public void testYResolutionDescription() throws Exception
@Test
public void testWindowsXpFields() throws Exception
{
- ExifIFD0Directory directory = ExifReaderTest.processBytes("Tests/Data/windowsXpFields.jpg.app1", ExifIFD0Directory.class);
+ ExifIFD0Directory directory = ExifReaderTest.processSegmentBytes("Tests/Data/windowsXpFields.jpg.app1", JpegSegmentType.APP1, ExifIFD0Directory.class);
assertEquals("Testing artist\0", directory.getString(TAG_WIN_AUTHOR, "UTF-16LE"));
assertEquals("Testing comments\0", directory.getString(TAG_WIN_COMMENT, "UTF-16LE"));
diff --git a/Tests/com/drew/metadata/exif/ExifReaderTest.java b/Tests/com/drew/metadata/exif/ExifReaderTest.java
index 1bf4cebfd..804eba1bb 100644
--- a/Tests/com/drew/metadata/exif/ExifReaderTest.java
+++ b/Tests/com/drew/metadata/exif/ExifReaderTest.java
@@ -21,8 +21,9 @@
package com.drew.metadata.exif;
import com.drew.imaging.jpeg.JpegSegmentType;
-import com.drew.lang.ByteArrayReader;
+import com.drew.imaging.jpeg.JpegSegment;
import com.drew.lang.Rational;
+import com.drew.lang.ReaderInfo;
import com.drew.lang.annotations.NotNull;
import com.drew.metadata.Directory;
import com.drew.metadata.Metadata;
@@ -42,18 +43,22 @@
public class ExifReaderTest
{
@NotNull
- public static Metadata processBytes(@NotNull String filePath) throws IOException
+ public static Metadata processSegmentBytes(@NotNull String filePath, JpegSegmentType type) throws IOException
{
Metadata metadata = new Metadata();
byte[] bytes = FileUtil.readBytes(filePath);
- new ExifReader().extract(new ByteArrayReader(bytes), metadata, ExifReader.JPEG_SEGMENT_PREAMBLE.length(), null);
+ JpegSegment segment = new JpegSegment(type, ReaderInfo.createFromArray(bytes), ExifReader.JPEG_SEGMENT_ID);
+ ArrayList segments = new ArrayList();
+ segments.add(segment);
+
+ new ExifReader().readJpegSegments(segments, metadata);
return metadata;
}
@NotNull
- public static T processBytes(@NotNull String filePath, @NotNull Class directoryClass) throws IOException
+ public static T processSegmentBytes(@NotNull String filePath, JpegSegmentType type, @NotNull Class directoryClass) throws IOException
{
- T directory = processBytes(filePath).getFirstDirectoryOfType(directoryClass);
+ T directory = processSegmentBytes(filePath, type).getFirstDirectoryOfType(directoryClass);
assertNotNull(directory);
return directory;
}
@@ -63,7 +68,7 @@ public static T processBytes(@NotNull String filePath, @No
public void testExtractWithNullDataThrows() throws Exception
{
try{
- new ExifReader().readJpegSegments(null, new Metadata(), JpegSegmentType.APP1);
+ new ExifReader().readJpegSegments(null, null);
fail("Exception expected");
} catch (NullPointerException npe) {
// passed
@@ -73,7 +78,7 @@ public void testExtractWithNullDataThrows() throws Exception
@Test
public void testLoadFujifilmJpeg() throws Exception
{
- ExifSubIFDDirectory directory = ExifReaderTest.processBytes("Tests/Data/withExif.jpg.app1", ExifSubIFDDirectory.class);
+ ExifSubIFDDirectory directory = ExifReaderTest.processSegmentBytes("Tests/Data/withExif.jpg.app1", JpegSegmentType.APP1, ExifSubIFDDirectory.class);
final String description = directory.getDescription(ExifSubIFDDirectory.TAG_ISO_EQUIVALENT);
assertNotNull(description);
@@ -87,9 +92,10 @@ public void testReadJpegSegmentWithNoExifData() throws Exception
{
byte[] badExifData = new byte[]{ 1,2,3,4,5,6,7,8,9,10 };
Metadata metadata = new Metadata();
- ArrayList segments = new ArrayList();
- segments.add(badExifData);
- new ExifReader().readJpegSegments(segments, metadata, JpegSegmentType.APP1);
+ JpegSegment badExifSegment = new JpegSegment(JpegSegmentType.APP1, ReaderInfo.createFromArray(badExifData));
+ ArrayList segments = new ArrayList();
+ segments.add(badExifSegment);
+ new ExifReader().readJpegSegments(segments, metadata); //, JpegSegmentType.APP1);
assertEquals(0, metadata.getDirectoryCount());
assertFalse(metadata.hasErrors());
}
@@ -100,7 +106,7 @@ public void testCrashRegressionTest() throws Exception
// This image was created via a resize in ACDSee.
// It seems to have a reference to an IFD starting outside the data segment.
// I've noticed that ACDSee reports a Comment for this image, yet ExifReader doesn't report one.
- ExifSubIFDDirectory directory = ExifReaderTest.processBytes("Tests/Data/crash01.jpg.app1", ExifSubIFDDirectory.class);
+ ExifSubIFDDirectory directory = ExifReaderTest.processSegmentBytes("Tests/Data/crash01.jpg.app1", JpegSegmentType.APP1, ExifSubIFDDirectory.class);
assertTrue(directory.getTagCount() > 0);
}
@@ -108,7 +114,7 @@ public void testCrashRegressionTest() throws Exception
@Test
public void testDateTime() throws Exception
{
- ExifIFD0Directory directory = ExifReaderTest.processBytes("Tests/Data/manuallyAddedThumbnail.jpg.app1", ExifIFD0Directory.class);
+ ExifIFD0Directory directory = ExifReaderTest.processSegmentBytes("Tests/Data/manuallyAddedThumbnail.jpg.app1", JpegSegmentType.APP1, ExifIFD0Directory.class);
assertEquals("2002:11:27 18:00:35", directory.getString(ExifIFD0Directory.TAG_DATETIME));
}
@@ -116,7 +122,7 @@ public void testDateTime() throws Exception
@Test
public void testThumbnailXResolution() throws Exception
{
- ExifThumbnailDirectory directory = ExifReaderTest.processBytes("Tests/Data/manuallyAddedThumbnail.jpg.app1", ExifThumbnailDirectory.class);
+ ExifThumbnailDirectory directory = ExifReaderTest.processSegmentBytes("Tests/Data/manuallyAddedThumbnail.jpg.app1", JpegSegmentType.APP1, ExifThumbnailDirectory.class);
Rational rational = directory.getRational(ExifThumbnailDirectory.TAG_X_RESOLUTION);
assertNotNull(rational);
@@ -127,7 +133,7 @@ public void testThumbnailXResolution() throws Exception
@Test
public void testThumbnailYResolution() throws Exception
{
- ExifThumbnailDirectory directory = ExifReaderTest.processBytes("Tests/Data/manuallyAddedThumbnail.jpg.app1", ExifThumbnailDirectory.class);
+ ExifThumbnailDirectory directory = ExifReaderTest.processSegmentBytes("Tests/Data/manuallyAddedThumbnail.jpg.app1", JpegSegmentType.APP1, ExifThumbnailDirectory.class);
Rational rational = directory.getRational(ExifThumbnailDirectory.TAG_Y_RESOLUTION);
assertNotNull(rational);
@@ -138,7 +144,7 @@ public void testThumbnailYResolution() throws Exception
@Test
public void testThumbnailOffset() throws Exception
{
- ExifThumbnailDirectory directory = ExifReaderTest.processBytes("Tests/Data/manuallyAddedThumbnail.jpg.app1", ExifThumbnailDirectory.class);
+ ExifThumbnailDirectory directory = ExifReaderTest.processSegmentBytes("Tests/Data/manuallyAddedThumbnail.jpg.app1", JpegSegmentType.APP1, ExifThumbnailDirectory.class);
assertEquals(192, directory.getInt(ExifThumbnailDirectory.TAG_THUMBNAIL_OFFSET));
}
@@ -146,7 +152,7 @@ public void testThumbnailOffset() throws Exception
@Test
public void testThumbnailLength() throws Exception
{
- ExifThumbnailDirectory directory = ExifReaderTest.processBytes("Tests/Data/manuallyAddedThumbnail.jpg.app1", ExifThumbnailDirectory.class);
+ ExifThumbnailDirectory directory = ExifReaderTest.processSegmentBytes("Tests/Data/manuallyAddedThumbnail.jpg.app1", JpegSegmentType.APP1, ExifThumbnailDirectory.class);
assertEquals(2970, directory.getInt(ExifThumbnailDirectory.TAG_THUMBNAIL_LENGTH));
}
@@ -154,7 +160,7 @@ public void testThumbnailLength() throws Exception
@Test
public void testCompression() throws Exception
{
- ExifThumbnailDirectory directory = ExifReaderTest.processBytes("Tests/Data/manuallyAddedThumbnail.jpg.app1", ExifThumbnailDirectory.class);
+ ExifThumbnailDirectory directory = ExifReaderTest.processSegmentBytes("Tests/Data/manuallyAddedThumbnail.jpg.app1", JpegSegmentType.APP1, ExifThumbnailDirectory.class);
// 6 means JPEG compression
assertEquals(6, directory.getInt(ExifThumbnailDirectory.TAG_COMPRESSION));
@@ -167,7 +173,7 @@ public void testStackOverflowOnRevisitationOfSameDirectory() throws Exception
// repeatedly. Thanks to Alistair Dickie for providing the sample data used in this
// unit test.
- Metadata metadata = processBytes("Tests/Data/recursiveDirectories.jpg.app1");
+ Metadata metadata = processSegmentBytes("Tests/Data/recursiveDirectories.jpg.app1", JpegSegmentType.APP1);
// Mostly we're just happy at this point that we didn't get stuck in an infinite loop.
@@ -180,7 +186,7 @@ public void testDifferenceImageAndThumbnailOrientations() throws Exception
// This metadata contains different orientations for the thumbnail and the main image.
// These values used to be merged into a single directory, causing errors.
// This unit test demonstrates correct behaviour.
- Metadata metadata = processBytes("Tests/Data/repeatedOrientationTagWithDifferentValues.jpg.app1");
+ Metadata metadata = processSegmentBytes("Tests/Data/repeatedOrientationTagWithDifferentValues.jpg.app1", JpegSegmentType.APP1);
ExifIFD0Directory ifd0Directory = metadata.getFirstDirectoryOfType(ExifIFD0Directory.class);
ExifThumbnailDirectory thumbnailDirectory = metadata.getFirstDirectoryOfType(ExifThumbnailDirectory.class);
diff --git a/Tests/com/drew/metadata/exif/NikonType1MakernoteTest.java b/Tests/com/drew/metadata/exif/NikonType1MakernoteTest.java
index 94e99cdd4..a1d88e08a 100644
--- a/Tests/com/drew/metadata/exif/NikonType1MakernoteTest.java
+++ b/Tests/com/drew/metadata/exif/NikonType1MakernoteTest.java
@@ -20,6 +20,7 @@
*/
package com.drew.metadata.exif;
+import com.drew.imaging.jpeg.JpegSegmentType;
import com.drew.lang.Rational;
import com.drew.metadata.Metadata;
import com.drew.metadata.exif.makernotes.NikonType1MakernoteDirectory;
@@ -53,7 +54,7 @@ public class NikonType1MakernoteTest
@Before
public void setUp() throws Exception
{
- Metadata metadata = ExifReaderTest.processBytes("Tests/Data/nikonMakernoteType1.jpg.app1");
+ Metadata metadata = ExifReaderTest.processSegmentBytes("Tests/Data/nikonMakernoteType1.jpg.app1", JpegSegmentType.APP1);
_nikonDirectory = metadata.getFirstDirectoryOfType(NikonType1MakernoteDirectory.class);
_exifSubIFDDirectory = metadata.getFirstDirectoryOfType(ExifSubIFDDirectory.class);
diff --git a/Tests/com/drew/metadata/exif/NikonType2MakernoteTest1.java b/Tests/com/drew/metadata/exif/NikonType2MakernoteTest1.java
index a8685efde..f5ad74034 100644
--- a/Tests/com/drew/metadata/exif/NikonType2MakernoteTest1.java
+++ b/Tests/com/drew/metadata/exif/NikonType2MakernoteTest1.java
@@ -20,6 +20,7 @@
*/
package com.drew.metadata.exif;
+import com.drew.imaging.jpeg.JpegSegmentType;
import com.drew.metadata.MetadataException;
import com.drew.metadata.exif.makernotes.NikonType2MakernoteDescriptor;
import com.drew.metadata.exif.makernotes.NikonType2MakernoteDirectory;
@@ -43,7 +44,7 @@ public void setUp() throws Exception
{
Locale.setDefault(new Locale("en", "GB"));
- _nikonDirectory = ExifReaderTest.processBytes("Tests/Data/nikonMakernoteType2a.jpg.app1", NikonType2MakernoteDirectory.class);
+ _nikonDirectory = ExifReaderTest.processSegmentBytes("Tests/Data/nikonMakernoteType2a.jpg.app1", JpegSegmentType.APP1, NikonType2MakernoteDirectory.class);
assertNotNull(_nikonDirectory);
diff --git a/Tests/com/drew/metadata/exif/NikonType2MakernoteTest2.java b/Tests/com/drew/metadata/exif/NikonType2MakernoteTest2.java
index a77c3992a..b7c06b5c2 100644
--- a/Tests/com/drew/metadata/exif/NikonType2MakernoteTest2.java
+++ b/Tests/com/drew/metadata/exif/NikonType2MakernoteTest2.java
@@ -20,6 +20,7 @@
*/
package com.drew.metadata.exif;
+import com.drew.imaging.jpeg.JpegSegmentType;
import com.drew.lang.Rational;
import com.drew.metadata.Metadata;
import com.drew.metadata.exif.makernotes.NikonType2MakernoteDirectory;
@@ -45,7 +46,7 @@ public class NikonType2MakernoteTest2
@Before
public void setUp() throws Exception
{
- _metadata = ExifReaderTest.processBytes("Tests/Data/nikonMakernoteType2b.jpg.app1");
+ _metadata = ExifReaderTest.processSegmentBytes("Tests/Data/nikonMakernoteType2b.jpg.app1", JpegSegmentType.APP1);
_nikonDirectory = _metadata.getFirstDirectoryOfType(NikonType2MakernoteDirectory.class);
_exifIFD0Directory = _metadata.getFirstDirectoryOfType(ExifIFD0Directory.class);
diff --git a/Tests/com/drew/metadata/exif/PanasonicMakernoteDescriptorTest.java b/Tests/com/drew/metadata/exif/PanasonicMakernoteDescriptorTest.java
index e71f941c4..2639b6642 100644
--- a/Tests/com/drew/metadata/exif/PanasonicMakernoteDescriptorTest.java
+++ b/Tests/com/drew/metadata/exif/PanasonicMakernoteDescriptorTest.java
@@ -21,6 +21,7 @@
package com.drew.metadata.exif;
+import com.drew.imaging.jpeg.JpegSegmentType;
import com.drew.metadata.Age;
import com.drew.metadata.Face;
import com.drew.metadata.exif.makernotes.PanasonicMakernoteDirectory;
@@ -40,7 +41,7 @@ public class PanasonicMakernoteDescriptorTest
@Before
public void setUp() throws Exception
{
- _panasonicDirectory = ExifReaderTest.processBytes("Tests/Data/withPanasonicFaces.jpg.app1", PanasonicMakernoteDirectory.class);
+ _panasonicDirectory = ExifReaderTest.processSegmentBytes("Tests/Data/withPanasonicFaces.jpg.app1", JpegSegmentType.APP1, PanasonicMakernoteDirectory.class);
}
@Test
diff --git a/Tests/com/drew/metadata/exif/SonyType1MakernoteTest.java b/Tests/com/drew/metadata/exif/SonyType1MakernoteTest.java
index 38466a954..f470cae6d 100644
--- a/Tests/com/drew/metadata/exif/SonyType1MakernoteTest.java
+++ b/Tests/com/drew/metadata/exif/SonyType1MakernoteTest.java
@@ -21,6 +21,7 @@
package com.drew.metadata.exif;
+import com.drew.imaging.jpeg.JpegSegmentType;
import com.drew.metadata.exif.makernotes.SonyType1MakernoteDescriptor;
import com.drew.metadata.exif.makernotes.SonyType1MakernoteDirectory;
import org.junit.Test;
@@ -34,7 +35,7 @@ public class SonyType1MakernoteTest
{
@Test public void testSonyType1Makernote() throws Exception
{
- SonyType1MakernoteDirectory directory = ExifReaderTest.processBytes("Tests/Data/sonyType1.jpg.app1", SonyType1MakernoteDirectory.class);
+ SonyType1MakernoteDirectory directory = ExifReaderTest.processSegmentBytes("Tests/Data/sonyType1.jpg.app1", JpegSegmentType.APP1, SonyType1MakernoteDirectory.class);
assertNotNull(directory);
assertFalse(directory.hasErrors());
diff --git a/Tests/com/drew/metadata/exif/SonyType6MakernoteTest.java b/Tests/com/drew/metadata/exif/SonyType6MakernoteTest.java
index eca2ee19c..118e1fa38 100644
--- a/Tests/com/drew/metadata/exif/SonyType6MakernoteTest.java
+++ b/Tests/com/drew/metadata/exif/SonyType6MakernoteTest.java
@@ -21,6 +21,7 @@
package com.drew.metadata.exif;
+import com.drew.imaging.jpeg.JpegSegmentType;
import com.drew.metadata.exif.makernotes.SonyType6MakernoteDescriptor;
import com.drew.metadata.exif.makernotes.SonyType6MakernoteDirectory;
import org.junit.Test;
@@ -34,7 +35,7 @@ public class SonyType6MakernoteTest
{
@Test public void testSonyType6Makernote() throws Exception
{
- SonyType6MakernoteDirectory directory = ExifReaderTest.processBytes("Tests/Data/sonyType6.jpg.app1.0", SonyType6MakernoteDirectory.class);
+ SonyType6MakernoteDirectory directory = ExifReaderTest.processSegmentBytes("Tests/Data/sonyType6.jpg.app1.0", JpegSegmentType.APP1, SonyType6MakernoteDirectory.class);
assertNotNull(directory);
assertFalse(directory.hasErrors());
diff --git a/Tests/com/drew/metadata/gif/GifReaderTest.java b/Tests/com/drew/metadata/gif/GifReaderTest.java
index 08fbd481f..218c76c62 100644
--- a/Tests/com/drew/metadata/gif/GifReaderTest.java
+++ b/Tests/com/drew/metadata/gif/GifReaderTest.java
@@ -21,11 +21,12 @@
package com.drew.metadata.gif;
-import com.drew.lang.StreamReader;
import com.drew.lang.annotations.NotNull;
+import com.drew.lang.RandomAccessStream;
import com.drew.metadata.Metadata;
import org.junit.Test;
+import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
@@ -37,11 +38,12 @@
public class GifReaderTest
{
@NotNull
- public static GifHeaderDirectory processBytes(@NotNull String file) throws Exception
+ public static GifHeaderDirectory processBytes(@NotNull String filePath) throws Exception
{
Metadata metadata = new Metadata();
+ File file = new File(filePath);
InputStream stream = new FileInputStream(file);
- new GifReader().extract(new StreamReader(stream), metadata);
+ new GifReader().extract(new RandomAccessStream(stream, file.length()).createReader(), metadata);
stream.close();
GifHeaderDirectory directory = metadata.getFirstDirectoryOfType(GifHeaderDirectory.class);
diff --git a/Tests/com/drew/metadata/icc/IccReaderTest.java b/Tests/com/drew/metadata/icc/IccReaderTest.java
index 04dd6bcc6..55d8cb692 100644
--- a/Tests/com/drew/metadata/icc/IccReaderTest.java
+++ b/Tests/com/drew/metadata/icc/IccReaderTest.java
@@ -21,14 +21,17 @@
package com.drew.metadata.icc;
+import com.drew.imaging.jpeg.JpegSegment;
import com.drew.imaging.jpeg.JpegSegmentType;
-import com.drew.lang.ByteArrayReader;
+import com.drew.lang.ReaderInfo;
import com.drew.metadata.Metadata;
import com.drew.testing.TestHelper;
import com.drew.tools.FileUtil;
+import java.util.ArrayList;
import org.junit.Test;
import java.util.Arrays;
+import java.util.List;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
@@ -48,7 +51,7 @@ public void testExtract_InvalidData() throws Exception
byte[] icc = TestHelper.skipBytes(app2Bytes, 14);
Metadata metadata = new Metadata();
- new IccReader().extract(new ByteArrayReader(icc), metadata);
+ new IccReader().extract(ReaderInfo.createFromArray(icc), metadata);
IccDirectory directory = metadata.getFirstDirectoryOfType(IccDirectory.class);
@@ -59,10 +62,10 @@ public void testExtract_InvalidData() throws Exception
@Test
public void testReadJpegSegments_InvalidData() throws Exception
{
- byte[] app2Bytes = FileUtil.readBytes("Tests/Data/iccDataInvalid1.jpg.app2");
-
Metadata metadata = new Metadata();
- new IccReader().readJpegSegments(Arrays.asList(app2Bytes), metadata, JpegSegmentType.APP2);
+ List jpegSegments = new ArrayList();
+ jpegSegments.add(new JpegSegment(JpegSegmentType.APP2, ReaderInfo.createFromArray(FileUtil.readBytes("Tests/Data/iccDataInvalid1.jpg.app2")), IccReader.JPEG_SEGMENT_ID));
+ new IccReader().readJpegSegments(jpegSegments, metadata);
IccDirectory directory = metadata.getFirstDirectoryOfType(IccDirectory.class);
@@ -73,10 +76,10 @@ public void testReadJpegSegments_InvalidData() throws Exception
@Test
public void testExtract_ProfileDateTime() throws Exception
{
- byte[] app2Bytes = FileUtil.readBytes("Tests/Data/withExifAndIptc.jpg.app2");
-
Metadata metadata = new Metadata();
- new IccReader().readJpegSegments(Arrays.asList(app2Bytes), metadata, JpegSegmentType.APP2);
+ List jpegSegments = new ArrayList();
+ jpegSegments.add(new JpegSegment(JpegSegmentType.APP2, ReaderInfo.createFromArray(FileUtil.readBytes("Tests/Data/withExifAndIptc.jpg.app2")), IccReader.JPEG_SEGMENT_ID));
+ new IccReader().readJpegSegments(jpegSegments, metadata);
IccDirectory directory = metadata.getFirstDirectoryOfType(IccDirectory.class);
diff --git a/Tests/com/drew/metadata/iptc/IptcReaderTest.java b/Tests/com/drew/metadata/iptc/IptcReaderTest.java
index 23e058130..d31402464 100644
--- a/Tests/com/drew/metadata/iptc/IptcReaderTest.java
+++ b/Tests/com/drew/metadata/iptc/IptcReaderTest.java
@@ -20,7 +20,7 @@
*/
package com.drew.metadata.iptc;
-import com.drew.lang.SequentialByteArrayReader;
+import com.drew.lang.ReaderInfo;
import com.drew.lang.annotations.NotNull;
import com.drew.metadata.Metadata;
import com.drew.metadata.Tag;
@@ -44,7 +44,7 @@ public static IptcDirectory processBytes(@NotNull String filePath) throws IOExce
{
Metadata metadata = new Metadata();
byte[] bytes = FileUtil.readBytes(filePath);
- new IptcReader().extract(new SequentialByteArrayReader(bytes), metadata, bytes.length);
+ new IptcReader().extract(ReaderInfo.createFromArray(bytes), metadata);
IptcDirectory directory = metadata.getFirstDirectoryOfType(IptcDirectory.class);
assertNotNull(directory);
return directory;
diff --git a/Tests/com/drew/metadata/jfif/JfifReaderTest.java b/Tests/com/drew/metadata/jfif/JfifReaderTest.java
index 3fb4b4928..822ea55df 100644
--- a/Tests/com/drew/metadata/jfif/JfifReaderTest.java
+++ b/Tests/com/drew/metadata/jfif/JfifReaderTest.java
@@ -21,7 +21,7 @@
package com.drew.metadata.jfif;
-import com.drew.lang.ByteArrayReader;
+import com.drew.lang.ReaderInfo;
import com.drew.metadata.Metadata;
import com.drew.metadata.Tag;
import org.junit.Test;
@@ -46,7 +46,7 @@ public class JfifReaderTest
final Metadata metadata = new Metadata();
final JfifReader reader = new JfifReader();
- reader.extract(new ByteArrayReader(jfifData), metadata);
+ reader.extract(ReaderInfo.createFromArray(jfifData), metadata);
assertEquals(1, metadata.getDirectoryCount());
JfifDirectory directory = metadata.getFirstDirectoryOfType(JfifDirectory.class);
diff --git a/Tests/com/drew/metadata/jpeg/JpegDhtReaderTest.java b/Tests/com/drew/metadata/jpeg/JpegDhtReaderTest.java
index 1bda3fe5a..7d76b82a6 100644
--- a/Tests/com/drew/metadata/jpeg/JpegDhtReaderTest.java
+++ b/Tests/com/drew/metadata/jpeg/JpegDhtReaderTest.java
@@ -23,7 +23,7 @@
import com.drew.imaging.jpeg.JpegSegmentData;
import com.drew.imaging.jpeg.JpegSegmentReader;
import com.drew.imaging.jpeg.JpegSegmentType;
-import com.drew.lang.SequentialByteArrayReader;
+import com.drew.imaging.jpeg.JpegSegment;
import com.drew.lang.annotations.NotNull;
import com.drew.metadata.Metadata;
import com.drew.metadata.jpeg.HuffmanTablesDirectory.HuffmanTable.HuffmanTableClass;
@@ -47,9 +47,9 @@ public static HuffmanTablesDirectory processBytes(String filePath) throws Except
new File(filePath),
Collections.singletonList(JpegSegmentType.DHT));
- Iterable segments = segmentData.getSegments(JpegSegmentType.DHT);
- for (byte[] segment : segments) {
- new JpegDhtReader().extract(new SequentialByteArrayReader(segment), metadata);
+ Iterable segments = segmentData.getSegments(JpegSegmentType.DHT);
+ for (JpegSegment segment : segments) {
+ new JpegDhtReader().extract(segment.getReader(), metadata);
}
diff --git a/Tests/com/drew/metadata/jpeg/JpegReaderTest.java b/Tests/com/drew/metadata/jpeg/JpegReaderTest.java
index 766de5f2f..6104cf2a7 100644
--- a/Tests/com/drew/metadata/jpeg/JpegReaderTest.java
+++ b/Tests/com/drew/metadata/jpeg/JpegReaderTest.java
@@ -22,7 +22,9 @@
import com.drew.imaging.jpeg.JpegProcessingException;
import com.drew.imaging.jpeg.JpegSegmentType;
+import com.drew.imaging.jpeg.JpegSegment;
import com.drew.lang.annotations.NotNull;
+import com.drew.lang.ReaderInfo;
import com.drew.metadata.Metadata;
import com.drew.tools.FileUtil;
import org.junit.Before;
@@ -42,7 +44,8 @@ public class JpegReaderTest
public static JpegDirectory processBytes(String filePath) throws IOException
{
Metadata metadata = new Metadata();
- new JpegReader().extract(FileUtil.readBytes(filePath), metadata, JpegSegmentType.SOF0);
+ JpegSegment sof0 = new JpegSegment(JpegSegmentType.SOF0, ReaderInfo.createFromArray(FileUtil.readBytes(filePath)));
+ new JpegReader().extract(sof0, metadata);
JpegDirectory directory = metadata.getFirstDirectoryOfType(JpegDirectory.class);
assertNotNull(directory);
diff --git a/Tests/com/drew/metadata/photoshop/PsdReaderTest.java b/Tests/com/drew/metadata/photoshop/PsdReaderTest.java
index 8d77df008..17bfe746b 100644
--- a/Tests/com/drew/metadata/photoshop/PsdReaderTest.java
+++ b/Tests/com/drew/metadata/photoshop/PsdReaderTest.java
@@ -21,8 +21,8 @@
package com.drew.metadata.photoshop;
-import com.drew.lang.StreamReader;
import com.drew.lang.annotations.NotNull;
+import com.drew.lang.RandomAccessStream;
import com.drew.metadata.Metadata;
import org.junit.Test;
@@ -39,12 +39,13 @@
public class PsdReaderTest
{
@NotNull
- public static PsdHeaderDirectory processBytes(@NotNull String file) throws Exception
+ public static PsdHeaderDirectory processBytes(@NotNull String filePath) throws Exception
{
Metadata metadata = new Metadata();
- InputStream stream = new FileInputStream(new File(file));
+ File file = new File(filePath);
+ InputStream stream = new FileInputStream(file);
try {
- new PsdReader().extract(new StreamReader(stream), metadata);
+ new PsdReader().extract(new RandomAccessStream(stream, file.length()).createReader(), metadata);
} catch (Exception e) {
stream.close();
throw e;
diff --git a/Tests/com/drew/metadata/xmp/XmpReaderTest.java b/Tests/com/drew/metadata/xmp/XmpReaderTest.java
index f83d31636..9fb70f61a 100644
--- a/Tests/com/drew/metadata/xmp/XmpReaderTest.java
+++ b/Tests/com/drew/metadata/xmp/XmpReaderTest.java
@@ -21,6 +21,8 @@
package com.drew.metadata.xmp;
import com.drew.imaging.jpeg.JpegSegmentType;
+import com.drew.imaging.jpeg.JpegSegment;
+import com.drew.lang.ReaderInfo;
import com.drew.metadata.Metadata;
import com.drew.tools.FileUtil;
import org.junit.Before;
@@ -41,9 +43,10 @@ public class XmpReaderTest
public void setUp() throws Exception
{
Metadata metadata = new Metadata();
- List jpegSegments = new ArrayList();
- jpegSegments.add(FileUtil.readBytes("Tests/Data/withXmpAndIptc.jpg.app1.1"));
- new XmpReader().readJpegSegments(jpegSegments, metadata, JpegSegmentType.APP1);
+
+ List jpegSegments = new ArrayList();
+ jpegSegments.add(new JpegSegment(JpegSegmentType.APP1, ReaderInfo.createFromArray(FileUtil.readBytes("Tests/Data/withXmpAndIptc.jpg.app1.1")), "Exif"));
+ new XmpReader().readJpegSegments(jpegSegments, metadata);
Collection xmpDirectories = metadata.getDirectoriesOfType(XmpDirectory.class);