diff options
Diffstat (limited to 'src/main/model/asn1/parsing/BytesReader.java')
-rw-r--r-- | src/main/model/asn1/parsing/BytesReader.java | 105 |
1 files changed, 105 insertions, 0 deletions
diff --git a/src/main/model/asn1/parsing/BytesReader.java b/src/main/model/asn1/parsing/BytesReader.java new file mode 100644 index 0000000..3e11ea6 --- /dev/null +++ b/src/main/model/asn1/parsing/BytesReader.java @@ -0,0 +1,105 @@ +package model.asn1.parsing; + +import model.asn1.ASN1Length; +import model.asn1.Tag; +import model.asn1.exceptions.ParseException; + +/** + * A mutable model represents a one-way pipe of reading the input DER bytes. It keeps track of the total input and the + * current location, and it provides useful methods of requiring one or more bytes to present in the next. + */ +public class BytesReader { + private final Byte[] rawInput; + private int index; + + /** + * EFFECTS: Initialize the reader with the given input and index set to 0. + * REQUIRES: rawInput.length > 0 + */ + public BytesReader(Byte[] rawInput) { + this.rawInput = rawInput; + this.index = 0; + } + + /** + * EFFECTS: Calculate the number of bytes remaining to read. + */ + public int bytesRemaining() { + return rawInput.length - index; + } + + /** + * EFFECTS: Copy the given number of bytes from the [getIndex(), getIndex() + size) and optionally mark as read. + * MODIFIES: this (if markAsRead == true) + * REQUIRES: size <= bytesRemaining(), size > 0 + */ + public Byte[] read(int size, boolean markAsRead) { + Byte[] result = new Byte[size]; + System.arraycopy(rawInput, index, result, 0, size); + if (markAsRead) { + index += size; + } + return result; + } + + /** + * EFFECTS: Copy the given number of bytes from [getIndex(), getIndex() + size) and optionally mark as read. + * Throws {@link ParseException} if size > bytesRemaining(). + * MODIFIES: this (if markAsRead == true) + * REQUIRES: size > 0 + */ + public Byte[] require(int size, boolean markAsRead) throws ParseException { + validateSize(size); + return read(size, markAsRead); + } + + /** + * EFFECTS: Check if size <= bytesRemaining(). + * Throws {@link ParseException if not}. + * REQUIRES: size > 0 + */ + public void validateSize(int size) throws ParseException { + if (size > bytesRemaining()) { + throw new ParseException(String.format("%d required at location %d, but only has %d before EOF.", + size, + index, + bytesRemaining())); + } + } + + /** + * EFFECTS: Check if the next byte has the desired tag, without changing the index. + * Throws {@link ParseException} if the input is illegal (not even a tag or EOF). + */ + public boolean detectTag(Tag desired) throws ParseException { + final int i = index; + final Tag t = new Tag(this); + index = i; + return t.getCls() == desired.getCls() + && t.isConstructive() == desired.isConstructive() + && t.getNumber() == desired.getNumber(); + } + + /** + * EFFECTS: Get the current tag or the tag immediately following (inner) without changing the index. + * Throws {@link ParseException} if the input is illegal (not even a tag or EOF). + */ + public Tag getTag(boolean inner) throws ParseException { + final int i = index; + Tag t = new Tag(this); + if (inner) { + new ASN1Length(this); + t = new Tag(this); + } + index = i; + return t; + } + + public Byte[] getRawInput() { + return rawInput; + } + + public int getIndex() { + return index; + } +} |