/* --------------------------------------------------------- * * __________ D E L T A S C R I P T * * (_________() * * / === / - A fast, dynamic scripting language * * | == | - Version 4.13.11.0 * * / === / - Developed by Adam R. Nelson * * | = = | - 2011-2013 * * / === / - Distributed under GNU LGPL v3 * * (________() - http://github.com/ar-nelson/deltascript * * * * --------------------------------------------------------- */ package com.sector91.delta.script.parser; import static com.sector91.util.StringTemplate.$; import java.io.Closeable; import java.io.IOException; import java.io.InputStream; import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.util.Arrays; import com.sector91.delta.script.DScriptContext; import com.sector91.delta.script.DeltaScript; import com.sector91.delta.script.instrs.DSInstr; import com.sector91.delta.script.instrs.InstrType; public class DScriptBinaryReader implements Closeable { /** * The byte order of multibyte numbers stored in compiled DeltaScript * files. */ public static final ByteOrder ORDER = ByteOrder.BIG_ENDIAN; private final InputStream in; public DScriptBinaryReader(InputStream is) {this.in = is;} private short readShort() throws IOException { final byte[] bytes = new byte[2]; in.read(bytes); return ByteBuffer.wrap(bytes).order(ORDER).getShort(); } private int readInt() throws IOException { final byte[] bytes = new byte[4]; in.read(bytes); return ByteBuffer.wrap(bytes).order(ORDER).getInt(); } private long readLong() throws IOException { final byte[] bytes = new byte[8]; in.read(bytes); return ByteBuffer.wrap(bytes).order(ORDER).getLong(); } public DSInstr read(DScriptContext context) throws IOException {return read(context, null);} public DSInstr read(DScriptContext context, String name) throws IOException { final byte[] header = new byte[DScriptBinaryWriter.FILE_HEADER.length]; in.read(header); if (!Arrays.equals(header, DScriptBinaryWriter.FILE_HEADER)) throw new IOException("Input does not have valid file header; not" + " a DeltaScript binary file."); final byte versionByte = (byte)in.read(); if (versionByte != DeltaScript.VERSION.majorVersion()) throw new IOException($("Input is a binary file from a different" + " major DeltaScript version. (Expected {}, got {}.)", DeltaScript.VERSION.majorVersion(), versionByte)); final long flags = readLong(); final boolean debug = (flags & DScriptBinaryWriter.FLAG_DEBUG) != 0; return readInstr(context, debug); } private DSInstr readInstr(DScriptContext context, boolean debug) throws IOException { final int opcode = in.read(); final InstrType type = InstrType.forOpcode(opcode); if (type == null) throw new IOException($("0x{} is not a valid DeltaScript" + " {} instruction opcode.", Integer.toHexString(opcode), DeltaScript.VERSION.majorVersion())); final int headLength = readInt(); final String head; if (headLength < 0) head = null; else { final byte[] headBytes = new byte[headLength]; final int read = in.read(headBytes); if (read < headLength) throw new IOException("Encountered EOF when attempting to" + " read instruction header string of length " + headLength + "."); head = new String(headBytes, DScriptBinaryWriter.CHARSET); } final int start; final short len; if (debug) { start = readInt(); len = readShort(); } else { start = -1; len = 0; } final int tailLength = readInt(); final DSInstr[] tail = new DSInstr[tailLength]; for (int i=0; i<tailLength; i++) tail[i] = readInstr(context, debug); return DSInstr.create(type, context, start, len, head, tail); } public void close() throws IOException {in.close();} }