diff --git a/src/main/java/io/kaitai/struct/ArraySpan.java b/src/main/java/io/kaitai/struct/ArraySpan.java new file mode 100644 index 0000000..114a8c2 --- /dev/null +++ b/src/main/java/io/kaitai/struct/ArraySpan.java @@ -0,0 +1,67 @@ +/** + * Copyright 2015-2021 Kaitai Project: MIT license + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +package io.kaitai.struct; + +import java.util.ArrayList; +import java.util.List; + +/** + * Span that represents positional information of array field and each of it + * elements. Spans of items is available in the {@link #items} field. + * + * @since 0.10 + */ +public class ArraySpan extends Span { + /** Individual span of the each item in the array. */ + public final List items; + + /** + * Creates a span of array that starts at the current stream offset and + * ends at the unknown position. + * + * @param io the stream to get positional information + */ + public ArraySpan(KaitaiStream io) { + super(io); + items = new ArrayList(); + } + + public ArraySpan(KaitaiStream io, int size) { + super(io); + items = new ArrayList(size); + } + + /** + * Appends a new span of array item from current stream position to the end-of-stream + * to this span + * + * @param io Stream used to inquire current position + * @return A new span, added to the internal list of item spans + */ + public Span addItem(KaitaiStream io) { + final Span span = new Span(io); + items.add(span); + return span; + } +} diff --git a/src/main/java/io/kaitai/struct/ByteBufferKaitaiStream.java b/src/main/java/io/kaitai/struct/ByteBufferKaitaiStream.java index 9addcf9..f7fb034 100644 --- a/src/main/java/io/kaitai/struct/ByteBufferKaitaiStream.java +++ b/src/main/java/io/kaitai/struct/ByteBufferKaitaiStream.java @@ -63,6 +63,20 @@ public ByteBufferKaitaiStream(String fileName) throws IOException { * @param arr byte array to read from or write to */ public ByteBufferKaitaiStream(byte[] arr) { + this(arr, 0); + } + + /** + * Initializes a stream that will get data from the given byte array when read. + * Internally, ByteBuffer wrapping given array will be used. + * + * @param arr byte array to read + * @param offset offset from the root stream where this stream begins + * + * @since 0.11 + */ + public ByteBufferKaitaiStream(byte[] arr, long offset) { + super(offset); fc = null; bb = ByteBuffer.wrap(arr); } @@ -73,6 +87,19 @@ public ByteBufferKaitaiStream(byte[] arr) { * @param buffer {@link ByteBuffer} to read from or write to */ public ByteBufferKaitaiStream(ByteBuffer buffer) { + this(buffer, 0); + } + + /** + * Initializes a stream that will get data from given {@link ByteBuffer} on read. + * + * @param buffer ByteBuffer to read from + * @param offset offset from the root stream where this stream begins + * + * @since 0.11 + */ + public ByteBufferKaitaiStream(ByteBuffer buffer, long offset) { + super(offset); fc = null; bb = buffer; } @@ -221,8 +248,8 @@ public void seek(long newPos) { } @Override - public int pos() { - return bb.position() + ((bitsWriteMode && bitsLeft > 0) ? 1 : 0); + public long pos() { + return bb.position() + ((bitsWriteMode && bitsLeft > 0) ? 1L : 0L); } @Override diff --git a/src/main/java/io/kaitai/struct/KaitaiStream.java b/src/main/java/io/kaitai/struct/KaitaiStream.java index 76769c4..5bd907d 100644 --- a/src/main/java/io/kaitai/struct/KaitaiStream.java +++ b/src/main/java/io/kaitai/struct/KaitaiStream.java @@ -60,6 +60,12 @@ public abstract class KaitaiStream implements Closeable { protected int bitsLeft = 0; protected long bits = 0; + /** + * Offset from the root stream where this stream begins. + * + * @since 0.11 + */ + protected final long offset; protected boolean bitsLe = false; protected boolean bitsWriteMode = false; @@ -67,6 +73,18 @@ public abstract class KaitaiStream implements Closeable { protected List childStreams = new ArrayList<>(); + /** Initializes a stream with zero offset from the root stream. */ + public KaitaiStream() { this(0); } + + /** + * Initializes a stream with specified offset from the root stream. + * + * @param offset offset from the root stream where this stream begins + * + * @since 0.11 + */ + public KaitaiStream(long offset) { this.offset = offset; } + @Override abstract public void close() throws IOException; @@ -90,11 +108,21 @@ public abstract class KaitaiStream implements Closeable { */ abstract public void seek(long newPos); + /** + * Get position of a stream pointer relative to the root stream in the stream hierarchy. + * Root stream is a stream without parent stream. + * + * @return the pointer position, number of bytes from the beginning of the root stream + * + * @since 0.11 + */ + public long offset() { return this.offset; } + /** * Get current position of a stream pointer. * @return pointer position, number of bytes from the beginning of the stream */ - abstract public int pos(); + abstract public long pos(); /** * Get total size of the stream in bytes. diff --git a/src/main/java/io/kaitai/struct/PositionInfo.java b/src/main/java/io/kaitai/struct/PositionInfo.java new file mode 100644 index 0000000..027a9ec --- /dev/null +++ b/src/main/java/io/kaitai/struct/PositionInfo.java @@ -0,0 +1,55 @@ +/** + * Copyright 2015-2021 Kaitai Project: MIT license + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +package io.kaitai.struct; + +import java.util.Map; + +/** + * This interface is implemented by each {@link KaitaiStruct} successor, if + * class was generated with positional information. + *

+ * If you want to work with generated structures in the generic way, you can use + * following code snipped to deal with positions information: + * + * final KaitaiStruct struct = ...; + * // Generator generates classes, that implements this interface, + * // if debug mode/positions-info is enabled + * if (struct instanceof PositionInfo) { + * final PositionInfo info = (PositionInfo)struct; + * //... + * } + * + * + * @since 0.10 + */ +public interface PositionInfo { + /** + * Information about each struct field. If field is an array, then corresponding + * {@code Span} will be of {@link ArraySpan} instance. Map keys is equals to the + * names of the java methods/fields in the generated class. + * + * @return the map from field name to field span information. + */ + Map _spans(); +} diff --git a/src/main/java/io/kaitai/struct/RandomAccessFileKaitaiStream.java b/src/main/java/io/kaitai/struct/RandomAccessFileKaitaiStream.java index 5330241..ca36383 100644 --- a/src/main/java/io/kaitai/struct/RandomAccessFileKaitaiStream.java +++ b/src/main/java/io/kaitai/struct/RandomAccessFileKaitaiStream.java @@ -111,10 +111,9 @@ public void seek(long newPos) { } @Override - public int pos() { + public long pos() { try { - // FIXME cast - return (int) raf.getFilePointer() + ((bitsWriteMode && bitsLeft > 0) ? 1 : 0); + return raf.getFilePointer() + ((bitsWriteMode && bitsLeft > 0) ? 1L : 0L); } catch (IOException e) { throw new RuntimeException(e); } diff --git a/src/main/java/io/kaitai/struct/Span.java b/src/main/java/io/kaitai/struct/Span.java new file mode 100644 index 0000000..297816d --- /dev/null +++ b/src/main/java/io/kaitai/struct/Span.java @@ -0,0 +1,88 @@ +/** + * Copyright 2015-2021 Kaitai Project: MIT license + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +package io.kaitai.struct; + +/** + * Information about positions of parsed value in the streams. + * + * @since 0.10 + */ +public class Span { + /** Offset from begin of the root stream, for which that span was created. */ + public final long offset; + /** + * Offset from begin of the stream, from which value was parsed. This is relative + * position, to get an absolute position (relative to the root stream) use + * {@link #absoluteStart()}. That offset is always non-negative. + */ + public final long start; + /** + * Offset from begin of the stream, from which value was parsed. This is relative + * position, to get an absolute position (relative to the root stream) use + * {@link #absoluteEnd()}. + *

+ * If that offset is negative, then value wasn't parsed yet or exception was + * thrown while parsing value. + */ + public long end = -1; + + /** + * Creates a span that starts at the current stream offset and ends at + * the unknown position. + * + * @param io the stream to get the positional information + */ + public Span(KaitaiStream io) { + this(io.offset(), io.pos()); + } + private Span(long offset, long start) { + this.offset = offset; + this.start = start; + } + + /** + * Offset to the start of this span relative to the root stream. + * + * @return start offset from the root stream + */ + public long absoluteStart() { return offset + start; } + /** + * Offset to the end of this span relative to the root stream. + *

+ * If that offset is negative, then value wasn't parsed yet or exception was + * thrown while parsing value. + * + * @return start offset from the root stream or negative value if value not yet parsed + */ + public long absoluteEnd() { return end < 0 ? -1 : offset + end; } + /** + * Size of this span in bytes. + *

+ * If size is negative, then value wasn't parsed yet or exception was + * thrown while parsing value. + * + * @return size of the span in bytes + */ + public long size() { return end < 0 ? -1 : end - start; } +}