/*****************************************************************************
* Copyright (C) The Apache Software Foundation. All rights reserved. *
* ------------------------------------------------------------------------- *
* This software is published under the terms of the Apache Software License *
* version 1.1, a copy of which has been included with this distribution in *
* the LICENSE file. *
*****************************************************************************/
package jogamp.graph.font.typecast.ot;
/**
* @author <a href="mailto:davidsch@dev.java.net">David Schweinsberg</a>
* @version $Id: Disassembler.java,v 1.1.1.1 2004-12-05 23:14:25 davidsch Exp $
*/
public class Disassembler {
/**
* Advance the instruction pointer to the next executable opcode.
* This will be the next byte, unless the current opcode is a push
* instruction, in which case it will be the byte immediately beyond
* the last data byte.
* @param ip The current instruction pointer
* @return The new instruction pointer
*/
public static int advanceIP(final short[] instructions, int ip) {
// The high word specifies font, cvt, or glyph program
int i = ip & 0xffff;
int dataCount;
ip++;
if (Mnemonic.NPUSHB == instructions[i]) {
// Next byte is the data byte count
dataCount = instructions[++i];
ip += dataCount + 1;
} else if (Mnemonic.NPUSHW == instructions[i]) {
// Next byte is the data word count
dataCount = instructions[++i];
ip += dataCount*2 + 1;
} else if (Mnemonic.PUSHB == (instructions[i] & 0xf8)) {
dataCount = (short)((instructions[i] & 0x07) + 1);
ip += dataCount;
} else if (Mnemonic.PUSHW == (instructions[i] & 0xf8)) {
dataCount = (short)((instructions[i] & 0x07) + 1);
ip += dataCount*2;
}
return ip;
}
public static short getPushCount(final short[] instructions, final int ip) {
final short instr = instructions[ip & 0xffff];
if ((Mnemonic.NPUSHB == instr) || (Mnemonic.NPUSHW == instr)) {
return instructions[(ip & 0xffff) + 1];
} else if ((Mnemonic.PUSHB == (instr & 0xf8)) || (Mnemonic.PUSHW == (instr & 0xf8))) {
return (short)((instr & 0x07) + 1);
}
return 0;
}
public static int[] getPushData(final short[] instructions, final int ip) {
final int count = getPushCount(instructions, ip);
final int[] data = new int[count];
final int i = ip & 0xffff;
final short instr = instructions[i];
if (Mnemonic.NPUSHB == instr) {
for (int j = 0; j < count; j++) {
data[j] = instructions[i + j + 2];
}
} else if (Mnemonic.PUSHB == (instr & 0xf8)) {
for (int j = 0; j < count; j++) {
data[j] = instructions[i + j + 1];
}
} else if (Mnemonic.NPUSHW == instr) {
for (int j = 0; j < count; j++) {
data[j] = (instructions[i + j*2 + 2] << 8) | instructions[i + j*2 + 3];
}
} else if (Mnemonic.PUSHW == (instr & 0xf8)) {
for (int j = 0; j < count; j++) {
data[j] = (instructions[i + j*2 + 1] << 8) | instructions[i + j*2 + 2];
}
}
return data;
}
public static String disassemble(final short[] instructions, final int leadingSpaces) {
final StringBuilder sb = new StringBuilder();
int ip = 0;
while (ip < instructions.length) {
for (int i = 0; i < leadingSpaces; i++) {
sb.append(" ");
}
sb.append(ip).append(": ");
sb.append(Mnemonic.getMnemonic(instructions[ip]));
if (getPushCount(instructions, ip) > 0) {
final int[] data = getPushData(instructions, ip);
for(int j = 0; j < data.length; j++) {
if ((instructions[ip] == Mnemonic.PUSHW) ||
(instructions[ip] == Mnemonic.NPUSHW)) {
sb.append(" ").append((short) data[j]);
} else {
sb.append(" ").append(data[j]);
}
}
}
sb.append("\n");
ip = advanceIP(instructions, ip);
}
return sb.toString();
}
}