package net.scapeemulator.cache.def;
import java.nio.ByteBuffer;
import java.util.HashMap;
import java.util.Map;
import net.scapeemulator.cache.util.ByteBufferUtils;
public final class ClientScript {
@SuppressWarnings("unchecked")
public static ClientScript decode(ByteBuffer buffer) {
ClientScript script = new ClientScript();
buffer.position(buffer.limit() - 2);
int trailerLength = buffer.getShort() & 0xFFFF;
int trailerPosition = buffer.limit() - 14 - trailerLength;
buffer.position(trailerPosition);
int ops = buffer.getInt();
script.intArgsCount = buffer.getShort() & 0xFFFF;
script.strArgsCount = buffer.getShort() & 0xFFFF;
script.intStackDepth = buffer.getShort() & 0xFFFF;
script.strStackDepth = buffer.getShort() & 0xFFFF;
int switches = buffer.get() & 0xFF;
script.switchTables = new HashMap[switches];
for (int i = 0; i < switches; i++) {
script.switchTables[i] = new HashMap<>();
int size = buffer.getShort() & 0xFFFF;
while (size-- > 0) {
int index = buffer.getInt();
int value = buffer.getInt();
script.switchTables[i].put(index, value);
}
}
buffer.position(0);
script.name = ByteBufferUtils.getString(buffer);
script.opcodes = new int[ops];
script.intOperands = new int[ops];
script.strOperands = new String[ops];
int op = 0;
while (buffer.position() < trailerPosition) {
int opcode = buffer.getShort() & 0xFFFF;
if (opcode == 3) {
script.strOperands[op] = ByteBufferUtils.getString(buffer);
} else if (opcode >= 100 || opcode == 21 || opcode == 38 || opcode == 39) {
script.intOperands[op] = buffer.get();
} else {
script.intOperands[op] = buffer.getInt();
}
script.opcodes[op++] = opcode;
}
return script;
}
private String name;
private int intArgsCount, strArgsCount, intStackDepth, strStackDepth;
private Map<Integer, Integer>[] switchTables;
private int[] opcodes, intOperands;
private String[] strOperands;
public String getName() {
return name;
}
public int getIntArgsCount() {
return intArgsCount;
}
public int getStrArgsCount() {
return strArgsCount;
}
public int getIntStackDepth() {
return intStackDepth;
}
public int getStrStackDepth() {
return strStackDepth;
}
public int getLength() {
return opcodes.length;
}
public int getOpcode(int index) {
return opcodes[index];
}
public int getIntOperand(int index) {
return intOperands[index];
}
public String getStrOperand(int index) {
return strOperands[index];
}
// TODO nicer interface for accessing this structure?
public Map<Integer, Integer>[] getSwitchTables() {
return switchTables;
}
}