
org.monte.media.binary.StructParser Maven / Gradle / Ivy
/*
* @(#)StructParser.java
*
* Copyright (c) 2000-2012 Werner Randelshofer, Goldau, Switzerland.
* All rights reserved.
*
* You may not use, copy or modify this file, except in compliance with the
* license agreement you entered into with Werner Randelshofer.
* For details see accompanying license terms.
*/
package org.monte.media.binary;
import org.monte.media.math.ExtendedReal;
import org.monte.media.io.ByteArrayImageInputStream;
import java.io.*;
import org.monte.media.ParseException;
import org.monte.media.io.StreamPosTokenizer;
import java.util.*;
import java.text.*;
import javax.imageio.stream.ImageInputStream;
import javax.imageio.stream.MemoryCacheImageInputStream;
/**
* Parses structured binary data using C-like data declarations.
*
* Syntax:
*
* Declarations ::= { MagicDeclaration | DescriptionDeclaration | EnumDeclaration | SetDeclaration | TypedefDeclaration } EOF
* MagicDeclaration ::= "magic" identifier ("ushort" hexLiteral[".." hexLiteral] | stringLiteral) ";"
* DescriptionDeclaration ::= "description" identifier stringLiteral "," stringLiteral ";"
* EnumDeclaration ::= EnumSpecifier identifier ";"
* SetDeclaration ::= SetSpecifier identifier ";"
* TypedefDeclaration ::= "typedef" TypeSpecifier identifier ";"
* EnumSpecifier ::= "enum" ( identifier | "{" identifier ["=" magicOrIntLiteral] {"," identifier ["=" intLiteral]} "}" )
* SetSpecifier ::= "set" ( identifier | "{" identifier "=" intLiteral {"," identifier "=" intLiteral} "}" )
* TypeSpecifier ::= ( StructSpecifier | (PrimitiveSpecifier [EnumSpecifier | SetSpecifier]) ) [ArrayList]
* StructSpecifier ::= "struct (identifier | "{" MemberDeclaration {"," MemberDeclaration } "}" )
* MemberDeclaration ::= TypeSpecifier identifier [ArrayList] ";"
* PrimitiveSpecifier ::= "uint1" | "uint2" | "uint4" | "uint5" | "uint8"
* | "uint12" | "uint16" | "uint31LE" | "uint32"
* | "int9" | "int16" | "int32"
* | "ubyte" | "byte" | "short"
* | "ushort" | "int" | "long" | "float" | "double"
* | "extended"
* | "char" | "charbyte" | "cstring" | "utf8" | "pstring"
* | "pstring32"
* | "utf16le" | "magic" | "mactimestamp" | "bcd2"
* | "bcd4"
* | "fixed16d16" | "fixed2d30" | "fixed8d8"
* | "ataricolor"
* ArrayList ::= "[" [ArraySize] "]" {"," identifier "[" [ArraySize] "]" }
* ArraySize ::= () | intLiteral [("-"|"+"|"=="|"!=") intLiteral]
*
* @author Werner Randelshofer, Hausmatt 10, CH-6405 Goldau, Swityerland
*
* @version $Id: StructParser.java 299 2013-01-03 07:40:18Z werner $
*/
public class StructParser extends Object {
protected static final long MAC_TIMESTAMP_EPOCH = new GregorianCalendar(1904, GregorianCalendar.JANUARY, 1).getTimeInMillis();
private Declarations declarations;
public StructParser() {
}
public StructParser(Reader r) throws IOException, ParseException {
parse(r);
}
public String getName(String magic) {
return getName((Object) magic);
}
public String getName(Object magic) {
MagicDeclaration md = (MagicDeclaration) declarations.magics.get(magic);
DescriptionDeclaration dd = (md == null) ? null : (DescriptionDeclaration) declarations.descriptions.get(md.identifier);
return (dd == null) ? null : dd.name;
}
public String getIdentifierName(String magic) {
MagicDeclaration md = (MagicDeclaration) declarations.magics.get(magic);
DescriptionDeclaration dd = (md == null) ? null : (DescriptionDeclaration) declarations.descriptions.get(md.identifier);
return (md == null) ? null : md.identifier;
}
public boolean isMagicDeclared(String magic) {
return isMagicDeclared((Object) magic);
}
public boolean isMagicDeclared(Object magic) {
MagicDeclaration md = (MagicDeclaration) declarations.magics.get(magic);
return md != null;
}
public boolean isTypeDeclared(String magic) {
return isTypeDeclared((Object) magic);
}
public boolean isTypeDeclared(Object magic) {
TypedefDeclaration typedef = null;
//DataInputStream in = new DataInputStream(new ByteArrayInputStream(data));
MagicDeclaration magicdef = (MagicDeclaration) declarations.magics.get(magic);
if (magicdef == null) {
return false;
}
typedef = (TypedefDeclaration) declarations.typedefs.get(magicdef.identifier);
return typedef != null;
}
public String getDescription(String magic) {
return getDescription((Object) magic);
}
public String getDescription(Object magic) {
MagicDeclaration md = (MagicDeclaration) declarations.magics.get(magic);
DescriptionDeclaration dd = (md == null) ? null : (DescriptionDeclaration) declarations.descriptions.get(md.identifier);
return (dd == null) ? null : dd.description;
}
public StructTableModel readStruct(String magic, byte[] data)
throws IOException {
return declarations.readStruct(magic, new ByteArrayImageInputStream(data));
}
public StructTableModel readStruct(int magic, byte[] data)
throws IOException {
return declarations.readStruct(magic, new ByteArrayImageInputStream(data));
}
public StructTableModel readStruct(String magic, InputStream data)
throws IOException {
if (data instanceof ImageInputStream) {
return declarations.readStruct(magic, (ImageInputStream) data);
} else {
return declarations.readStruct(magic, new MemoryCacheImageInputStream(data));
}
}
public StructTableModel readStruct(int magic, InputStream data)
throws IOException {
if (data instanceof ImageInputStream) {
return declarations.readStruct(magic, (ImageInputStream) data);
} else {
return declarations.readStruct(magic, new MemoryCacheImageInputStream(data));
}
}
/**
* Consumes the number of bytes needed by the specified struct from the
* input stream, and returns them as a byte array.
*/
private static String errorMsg(String text, StreamPosTokenizer scanner) {
StringBuffer b = new StringBuffer();
b.append("line ");
b.append(Integer.toString(scanner.lineno()));
/* b.append(' ');
b.append(Integer.toString(scanner.getStartPosition()));
b.append("..");
b.append(Integer.toString(scanner.getEndPosition()));*/
b.append(": ");
b.append(text);
b.append(" instead of ");
switch (scanner.ttype) {
case StreamPosTokenizer.TT_WORD:
b.append('\'');
b.append(scanner.sval);
b.append('\'');
break;
case StreamPosTokenizer.TT_EOF:
b.append("EOF");
break;
case StreamPosTokenizer.TT_EOL:
b.append("EOL");
break;
case StreamPosTokenizer.TT_NUMBER:
b.append(Double.toString(scanner.nval));
break;
case '"':
b.append('"');
b.append(scanner.sval);
b.append('"');
break;
default:
b.append('\'');
b.append((char) scanner.ttype);
b.append('\'');
b.append("(0x");
b.append(Integer.toHexString(scanner.ttype));
b.append(')');
break;
}
return b.toString();
}
protected void parse(Reader r)
throws IOException, ParseException {
StreamPosTokenizer scanner = new StreamPosTokenizer(r);
scanner.resetSyntax();
scanner.wordChars('a', 'z');
scanner.wordChars('A', 'Z');
scanner.wordChars(128 + 32, 255);
scanner.wordChars('_', '_');
scanner.whitespaceChars(0, ' ');
//scanner.commentChar('/');
scanner.quoteChar('"');
scanner.quoteChar('\'');
scanner.parseNumbers();
scanner.parseHexNumbers();
scanner.slashSlashComments(true);
scanner.slashStarComments(true);
scanner.ordinaryChar(';');
scanner.ordinaryChar('[');
scanner.ordinaryChar(']');
scanner.ordinaryChar('{');
scanner.ordinaryChar('}');
scanner.ordinaryChar('+');
scanner.ordinaryChar('-');
declarations = new Declarations(scanner);
}
/**
* Declarations expression.
*
*
* Declarations ::= { MagicDeclaration | DescriptionDeclaration | EnumDeclaration | SetDeclaration | TypedefDeclaration }
*
*/
protected static class Declarations {
public Hashtable magics = new Hashtable();
public Hashtable descriptions = new Hashtable();
public Hashtable enums = new Hashtable();
public Hashtable sets = new Hashtable();
public Hashtable typedefs = new Hashtable();
public Declarations(StreamPosTokenizer scanner)
throws IOException, ParseException {
while (scanner.nextToken() != StreamPosTokenizer.TT_EOF) {
if (scanner.ttype == StreamPosTokenizer.TT_WORD) {
if (scanner.sval.equals("magic")) {
scanner.pushBack();
MagicDeclaration md = new MagicDeclaration(scanner);
if (md.magic != null) {
magics.put(md.magic, md);
} else {
for (int i = md.ushortMagicFrom; i <= md.ushortMagicTo; i++) {
magics.put(i, md);
}
}
} else if (scanner.sval.equals("description")) {
scanner.pushBack();
DescriptionDeclaration dd = new DescriptionDeclaration(scanner);
descriptions.put(dd.identifier, dd);
} else if (scanner.sval.equals("enum")) {
scanner.pushBack();
EnumDeclaration ed = new EnumDeclaration(scanner);
enums.put(ed.identifier, ed);
} else if (scanner.sval.equals("set")) {
scanner.pushBack();
SetDeclaration sd = new SetDeclaration(scanner);
sets.put(sd.identifier, sd);
} else if (scanner.sval.equals("typedef")) {
scanner.pushBack();
TypedefDeclaration td = new TypedefDeclaration(scanner);
typedefs.put(td.identifier, td);
} else {
throw new ParseException(errorMsg("Declarations: Expected 'magic', 'description', 'enum', 'set' or 'typedef' ", scanner));
}
}
}
}
private StructTableModel readStruct(Object magic, ImageInputStream in)
throws IOException {
Vector result = new Vector();
TypedefDeclaration typedef = null;
//DataInputStream in = new DataInputStream(new ByteArrayInputStream(data));
MagicDeclaration magicdef = (MagicDeclaration) magics.get(magic);
if (magicdef == null) {
//System.out.println("StructParser.StructTableModel.readStruct() unknow magic:"+magic);
//new Exception().printStackTrace();
if (magic instanceof Integer) {
throw new IOException("unknown magic:" + Integer.toHexString((Integer) magic));
} else {
throw new IOException("unknown magic:" + magic);
}
}
typedef = (TypedefDeclaration) typedefs.get(magicdef.identifier);
if (typedef == null) {
//System.out.println("StructParser.StructTableModel.readStruct() typedef not found for magic:"+magic+" magicdef.identifier:"+magicdef.identifier);
throw new IOException("unknown type:" + magicdef.identifier);
}
try {
Object obj = typedef.read(in, typedef.identifier, this, result);
if (obj != null) {
StructTableModel.Value value = new StructTableModel.Value();
value.declaration = typedef.identifier;
value.value = obj;
result.addElement(value);
}
} catch (EOFException e) {
}
return new StructTableModel(typedef, result);
}
}
/**
* MagicDeclaration expression.
*
*
* MagicDeclaration ::= "magic" identifier ("ushort" hexLiteral[".." hexLiteral] | stringLiteral) ";"
*
*/
protected static class MagicDeclaration {
public String identifier;
/** If magic is null, then ushortMagicFrom/ushortMagicTo is used. */
public String magic;
public int ushortMagicFrom;
public int ushortMagicTo;
public MagicDeclaration(StreamPosTokenizer scanner)
throws IOException, ParseException {
if (scanner.nextToken() != StreamPosTokenizer.TT_WORD || !scanner.sval.equals("magic")) {
throw new ParseException(errorMsg("MagicDeclaration: 'magic' expected", scanner));
}
if (scanner.nextToken() != StreamPosTokenizer.TT_WORD) {
throw new ParseException(errorMsg("MagicDeclaration: identifier expected", scanner));
}
identifier = scanner.sval;
if (scanner.nextToken() == StreamPosTokenizer.TT_WORD
&& scanner.sval.equals("ushort")) {
if (scanner.nextToken() != StreamPosTokenizer.TT_NUMBER) {
throw new ParseException(errorMsg("MagicDeclaration: ushort literal expected", scanner));
}
ushortMagicFrom = (int) scanner.nval;
if (scanner.nextToken() == '.') {
if (scanner.nextToken() != '.') {
throw new ParseException(errorMsg("MagicDeclaration: interval literal expected", scanner));
}
if (scanner.nextToken() != StreamPosTokenizer.TT_NUMBER) {
throw new ParseException(errorMsg("MagicDeclaration: end interval literal expected", scanner));
}
ushortMagicTo = (int) scanner.nval;
} else {
ushortMagicTo = ushortMagicFrom;
scanner.pushBack();
}
} else {
if (scanner.ttype != '"') {
throw new ParseException(errorMsg("MagicDeclaration: string literal expected", scanner));
}
magic = scanner.sval;
}
if (scanner.nextToken() != ';') {
throw new ParseException(errorMsg("MagicDeclaration: ';' expected", scanner));
}
}
}
/*
private static int parseHexLiteral(StreamPosTokenizer scanner)
throws IOException, ParseException {
scanner.
if (scanner.nextToken() != StreamPosTokenizer.TT_NUMBER || scanner.nval != 0) {
throw new ParseException(errorMsg("MagicDeclaration: hex literal expected",scanner));
}
System.out.println("StructParser.MagicDeclaration nval::"+scanner.nval);
System.out.println("StructParser.MagicDeclaration next TOken:"+scanner.nextToken());
}*/
/**
* DescriptionDeclaration expression.
*
*
* DescriptionDeclaration ::= "description" identifier stringLiteral "," stringLiteral ";"
*
*/
protected static class DescriptionDeclaration {
public String identifier;
public String name;
public String description;
public DescriptionDeclaration(StreamPosTokenizer scanner)
throws IOException, ParseException {
if (scanner.nextToken() != StreamPosTokenizer.TT_WORD || !scanner.sval.equals("description")) {
throw new ParseException(errorMsg("DescriptionDeclaration: 'magic' expected", scanner));
}
if (scanner.nextToken() != StreamPosTokenizer.TT_WORD) {
throw new ParseException(errorMsg("DescriptionDeclaration: identifier expected", scanner));
}
identifier = scanner.sval;
if (scanner.nextToken() != '"') {
throw new ParseException(errorMsg("DescriptionDeclaration: string literal (title) expected", scanner));
}
name = scanner.sval;
if (scanner.nextToken() != ',') {
throw new ParseException(errorMsg("DescriptionDeclaration: ',' expected", scanner));
}
if (scanner.nextToken() != '"') {
throw new ParseException(errorMsg("DescriptionDeclaration: string literal (description) expected", scanner));
}
description = scanner.sval;
while (scanner.nextToken() == '+') {
if (scanner.nextToken() != '"') {
throw new ParseException(errorMsg("DescriptionDeclaration: string literal (description) after '+' expected", scanner));
}
description += scanner.sval;
}
scanner.pushBack();
if (scanner.nextToken() != ';') {
throw new ParseException(errorMsg("DescriptionDeclaration: ';' expected", scanner));
}
}
}
/**
* EnumDeclaration expression.
*
*
* EnumDeclaration ::= EnumSpecifier identifier ";"
*
*/
protected static class EnumDeclaration {
public EnumSpecifier enumSpecifier;
public String identifier;
public EnumDeclaration(StreamPosTokenizer scanner)
throws IOException, ParseException {
enumSpecifier = new EnumSpecifier(scanner);
if (scanner.nextToken() != StreamPosTokenizer.TT_WORD) {
throw new ParseException(errorMsg("EnumDeclaration: identifier expected", scanner));
}
identifier = scanner.sval;
if (scanner.nextToken() != ';') {
throw new ParseException(errorMsg("EnumDeclaration: ';' expected", scanner));
}
}
}
/**
* SetDeclaration expression.
*
*
* SetDeclaration ::= SetSpecifier identifier ";"
*
*/
protected static class SetDeclaration {
public SetSpecifier setSpecifier;
public String identifier;
public SetDeclaration(StreamPosTokenizer scanner)
throws IOException, ParseException {
setSpecifier = new SetSpecifier(scanner);
if (scanner.nextToken() != StreamPosTokenizer.TT_WORD) {
throw new ParseException(errorMsg("SetDeclaration: identifier expected", scanner));
}
identifier = scanner.sval;
if (scanner.nextToken() != ';') {
throw new ParseException(errorMsg("SetDeclaration: ';' expected", scanner));
}
}
}
/**
* TypedefDeclaration expression.
*
*
* TypedefDeclaration ::= "typedef" TypeSpecifier identifier ";"
*
*/
protected static class TypedefDeclaration {
public TypeSpecifier typeSpecifier;
public String identifier;
public TypedefDeclaration(StreamPosTokenizer scanner)
throws IOException, ParseException {
if (scanner.nextToken() != StreamPosTokenizer.TT_WORD || !scanner.sval.equals("typedef")) {
throw new ParseException(errorMsg("TypedefDeclaration: 'typedef' expected", scanner));
}
typeSpecifier = new TypeSpecifier(scanner);
if (scanner.nextToken() != StreamPosTokenizer.TT_WORD) {
throw new ParseException(errorMsg("TypedefDeclaration: identifier expected", scanner));
}
identifier = scanner.sval;
if (scanner.nextToken() != ';') {
throw new ParseException(errorMsg("TypedefDeclaration: ';' expected", scanner));
}
//System.out.println("typedef "+typeSpecifier+" "+identifier+";");
}
private int getResolvedType(Declarations declarations) throws IOException {
return typeSpecifier.getResolvedPrimitiveType(declarations);
}
private Object read(ImageInputStream in, String parentIdentifier, Declarations declarations, Vector result)
throws IOException {
return typeSpecifier.read(in, parentIdentifier, declarations, identifier, result);
}
}
/**
* EnumSpecifier expression.
*
*
* EnumSpecifier ::= "enum" ( identifier | "{" identifier ["=" intLiteral] {"," identifier ["=" intLiteral]} "}" )
*
*/
protected static class EnumSpecifier {
public Hashtable members;
public String identifier;
public boolean isMagicEnum;
public EnumSpecifier(StreamPosTokenizer scanner)
throws IOException, ParseException {
if (scanner.nextToken() != StreamPosTokenizer.TT_WORD || !scanner.sval.equals("enum")) {
throw new ParseException(errorMsg("EnumSpecifier: 'enum' expected", scanner));
}
if (scanner.nextToken() == StreamPosTokenizer.TT_WORD) {
identifier = scanner.sval;
} else if (scanner.ttype == '{') {
String name;
int value = -1;
members = new Hashtable();
do {
if (scanner.nextToken() == '}') {
break;
}
if (scanner.ttype != StreamPosTokenizer.TT_WORD
&& scanner.ttype != '"') {
throw new ParseException(errorMsg("EnumSpecifier: enumeration name expected", scanner));
}
name = scanner.sval;
if (scanner.nextToken() == '=') {
MagicOrIntLiteral literal = new MagicOrIntLiteral(scanner);
value = literal.intValue();
isMagicEnum = literal.isMagic();
} else {
value++;
scanner.pushBack();
}
members.put(new Integer(value), name);
} while (scanner.nextToken() == ',');
if (scanner.ttype != '}') {
throw new ParseException(errorMsg("EnumSpecifier: '}' expected", scanner));
}
} else {
throw new ParseException(errorMsg("EnumSpecifier: identifier or '{' expected", scanner));
}
identifier = scanner.sval;
}
public String toEnumString(int value, Declarations declarations) {
if (identifier != null) {
EnumDeclaration enumDecl = (EnumDeclaration) declarations.enums.get(identifier);
if (enumDecl == null) {
throw new InternalError("Enum Declaration missing for " + identifier);
}
return enumDecl.enumSpecifier.toEnumString(value, declarations);
} else {
StringBuffer buf = new StringBuffer();
Integer intValue = new Integer(value);
if (isMagicEnum) {
buf.append('"');
buf.append(MagicOrIntLiteral.toMagic(value));
buf.append('"');
} else {
buf.append(Integer.toString(value));
/*
buf.append("0x");
buf.append(Integer.toHexString(value));*/
}
buf.append(" {");
if (members.get(intValue) != null) {
buf.append(members.get(intValue).toString());
}
buf.append('}');
return buf.toString();
}
}
public String toEnumString(String value, Declarations declarations) {
if (identifier != null) {
EnumDeclaration enumDecl = (EnumDeclaration) declarations.enums.get(identifier);
if (enumDecl == null) {
throw new InternalError("Enum Declaration missing for " + identifier);
}
return enumDecl.enumSpecifier.toEnumString(value, declarations);
} else {
if (value == null || value.length() != 4 || !isMagicEnum) {
return value;
} else {
return toEnumString(MagicOrIntLiteral.toInt(value), declarations);
}
}
}
}
/**
* SetSpecifier expression.
*
*
* SetSpecifier ::= "set" ( identifier | "{" identifier "=" intLiteral {"," identifier "=" intLiteral} "}" )
*
*/
protected static class SetSpecifier {
public Hashtable members;
public String identifier;
public SetSpecifier(StreamPosTokenizer scanner)
throws IOException, ParseException {
if (scanner.nextToken() != StreamPosTokenizer.TT_WORD || !scanner.sval.equals("set")) {
throw new ParseException(errorMsg("SetSpecifier: 'set' expected", scanner));
}
if (scanner.nextToken() == StreamPosTokenizer.TT_WORD) {
identifier = scanner.sval;
} else if (scanner.ttype == '{') {
String name;
int value = 0;
members = new Hashtable();
do {
if (scanner.nextToken() != StreamPosTokenizer.TT_WORD && scanner.ttype!='"') {
throw new ParseException(errorMsg("SetSpecifier: set name expected", scanner));
}
name = scanner.sval;
if (scanner.nextToken() == '=') {
value = (new IntLiteral(scanner)).intValue();
} else {
value = (value == 0) ? 1 : value << 1;
scanner.pushBack();
}
members.put(new Integer(value), name);
} while (scanner.nextToken() == ',');
if (scanner.ttype != '}') {
throw new ParseException(errorMsg("SetSpecifier: '}' expected", scanner));
}
} else {
throw new ParseException(errorMsg("SetSpecifier: identifier or '{' expected", scanner));
}
identifier = scanner.sval;
}
public String toSetString(int value, Declarations declarations) {
if (identifier != null) {
SetDeclaration setDecl = (SetDeclaration) declarations.sets.get(identifier);
if (setDecl == null) {
throw new InternalError("Set Declaration missing for " + identifier);
}
return setDecl.setSpecifier.toSetString(value, declarations);
} else {
StringBuffer buf = new StringBuffer();
buf.append("0x");
buf.append(Integer.toHexString(value));
buf.append(" {");
Enumeration enm = members.keys();
boolean isFirst = true;
while (enm.hasMoreElements()) {
Object key = enm.nextElement();
int intKey = ((Number) key).intValue();
if ((intKey == 0 && value == 0) || ((intKey & value) == intKey)) {
if (isFirst) {
isFirst = false;
} else {
buf.append(", ");
}
buf.append(members.get(key).toString());
}
}
buf.append('}');
return buf.toString();
}
}
}
/**
* TypeSpecifier expression.
*
*
* TypeSpecifier ::= ( StructSpecifier | (PrimitiveSpecifier [EnumSpecifier | SetSpecifier]) ) [ArrayList]
* ArrayList ::= "[" [ArraySize] "]" {"," identifier "[" [ArraySize] "]" }
*
*/
protected static class TypeSpecifier {
public StructSpecifier structSpecifier;
public PrimitiveSpecifier primitiveSpecifier;
public EnumSpecifier enumSpecifier;
public SetSpecifier setSpecifier;
public Vector arrayList;
public TypeSpecifier(StreamPosTokenizer scanner)
throws IOException, ParseException {
if (scanner.nextToken() == StreamPosTokenizer.TT_WORD && scanner.sval.equals("struct")) {
scanner.pushBack();
structSpecifier = new StructSpecifier(scanner);
} else {
scanner.pushBack();
primitiveSpecifier = new PrimitiveSpecifier(scanner);
scanner.nextToken();
if (scanner.ttype == StreamPosTokenizer.TT_WORD && scanner.sval.equals("enum")) {
scanner.pushBack();
enumSpecifier = new EnumSpecifier(scanner);
} else if (scanner.ttype == StreamPosTokenizer.TT_WORD && scanner.sval.equals("set")) {
scanner.pushBack();
setSpecifier = new SetSpecifier(scanner);
} else {
scanner.pushBack();
}
}
// ArrayList Begin
if (scanner.nextToken() == '[') {
arrayList = new Vector();
do {
arrayList.addElement(new ArraySize(scanner));
if (scanner.nextToken() != ']') {
throw new ParseException(errorMsg("MemberDeclaration: ']' expected", scanner));
}
} while (scanner.nextToken() == '[');
scanner.pushBack();
} else {
scanner.pushBack();
}
// ArrayList End
}
private int getResolvedPrimitiveType(Declarations declarations) throws IOException {
if (structSpecifier != null) {
return PrimitiveSpecifier.NON_PRIMITIVE;
} else if (primitiveSpecifier != null) {
return primitiveSpecifier.getResolvedPrimitveType(declarations);
} else {
return PrimitiveSpecifier.NON_PRIMITIVE;
}
}
private Object read(ImageInputStream in, String parentIdentifier, Declarations declarations, String identifier, Vector result)
throws IOException {
if (structSpecifier != null) {
if (arrayList != null) {
// ArrayList Begin
Enumeration enm = arrayList.elements();
while (enm.hasMoreElements()) {
ArraySize arraySize = (ArraySize) enm.nextElement();
int size = arraySize.getArraySize(declarations, result);
if (size == ArraySize.REMAINDER) {
try {
for (int i = 0;; i++) {
int loc = result.size();
structSpecifier.read(in, parentIdentifier, declarations, result);
for (int j = loc; j < result.size(); j++) {
StructTableModel.Value arrayValue = (StructTableModel.Value) result.elementAt(j);
arrayValue.index = (arrayValue.index == null) ? "[" + i + "]" : "[" + i + "]" + arrayValue.index;
}
}
} catch (EOFException e) {
}
} else {
for (int i = 0; i < size; i++) {
int loc = result.size();
structSpecifier.read(in, parentIdentifier, declarations, result);
for (int j = loc; j < result.size(); j++) {
StructTableModel.Value arrayValue = (StructTableModel.Value) result.elementAt(j);
arrayValue.index = (arrayValue.index == null) ? "[" + i + "]" : "[" + i + "]" + arrayValue.index;
}
}
}
}
return null;
} else {
structSpecifier.read(in, parentIdentifier, declarations, result);
return null;
}
} else if (primitiveSpecifier.getResolvedPrimitveType(declarations) == PrimitiveSpecifier.CHAR) {
if (arrayList != null) {
StringBuffer buf = new StringBuffer();
buf.append('\"');
boolean hasValue = false;
// ArrayList Begin
Enumeration enm = arrayList.elements();
while (enm.hasMoreElements()) {
ArraySize arraySize = (ArraySize) enm.nextElement();
int size = arraySize.getArraySize(declarations, result);
if (size == ArraySize.REMAINDER) {
try {
for (int i = 0;; i++) {
//if (i > 0) {
// buf.append(", ");
//}
Object value = readValue(in, parentIdentifier + "[" + i + "]", declarations, result);
if (value != null) {
hasValue = true;
if (value.toString().equals("0x20")) {
buf.append(' ');
} else {
buf.append(value.toString());
}
}
}
} catch (EOFException e) {
}
} else {
for (int i = 0; i < size; i++) {
//if (i > 0) {
// buf.append(", ");
//}
Object value = readValue(in, parentIdentifier + "[" + i + "]", declarations, result);
if (value != null) {
hasValue = true;
if (value.toString().equals("0x20")) {
buf.append(' ');
} else {
buf.append(value.toString());
}
}
}
}
}
// ArrayList End
if (hasValue) {
buf.append('\"');
return buf.toString();
} else {
return null;
}
} else {
return readValue(in, parentIdentifier, declarations, result);
}
} else if (primitiveSpecifier.getResolvedPrimitveType(declarations) == PrimitiveSpecifier.UBYTE) {
if (arrayList != null) {
StringBuffer buf = new StringBuffer();
ByteArrayOutputStream bout = new ByteArrayOutputStream();
buf.append("0x");
boolean hasValue = false;
// ArrayList Begin
Enumeration enm = arrayList.elements();
while (enm.hasMoreElements()) {
ArraySize arraySize = (ArraySize) enm.nextElement();
int size = arraySize.getArraySize(declarations, result);
if (size == ArraySize.REMAINDER) {
try {
for (int i = 0;; i++) {
//if (i > 0) {
// buf.append(", ");
//}
Integer value = (Integer) readValue(in, parentIdentifier + "[" + i + "]", declarations, result);
if (value != null) {
hasValue = true;
String str = Integer.toHexString(value & 0xff);
if (str.length() == 1) {
buf.append('0');
}
buf.append(str);
bout.write(value);
}
}
} catch (EOFException e) {
}
} else {
for (int i = 0; i < size; i++) {
//if (i > 0) {
// buf.append(", ");
//}
Integer value = (Integer) readValue(in, parentIdentifier + "[" + i + "]", declarations, result);
if (value != null) {
hasValue = true;
String str = Integer.toHexString(value & 0xff);
if (str.length() == 1) {
buf.append('0');
}
buf.append(str);
bout.write(value);
}
}
}
}
// ArrayList End
if (hasValue) {
if (true) {
return bout.toByteArray();
}
//buf.append('}');
return buf.toString();
} else {
return null;
}
} else {
return readValue(in, parentIdentifier, declarations, result);
}
} else {
if (arrayList != null) {
StringBuffer buf = new StringBuffer();
buf.append('{');
boolean hasValue = false;
// ArrayList Begin
Enumeration enm = arrayList.elements();
while (enm.hasMoreElements()) {
ArraySize arraySize = (ArraySize) enm.nextElement();
int size = arraySize.getArraySize(declarations, result);
if (size == ArraySize.REMAINDER) {
try {
for (int i = 0;; i++) {
if (i > 0) {
buf.append(", ");
}
Object value = readValue(in, parentIdentifier + "[" + i + "]", declarations, result);
if (value != null) {
hasValue = true;
buf.append(value.toString());
}
}
} catch (EOFException e) {
}
} else {
for (int i = 0; i < size; i++) {
if (i > 0) {
buf.append(", ");
}
Object value;
if (arraySize.type == ArraySize.EQUAL || arraySize.type == ArraySize.NOT_EQUAL) {
value = readValue(in, parentIdentifier, declarations, result);
} else {
value = readValue(in, parentIdentifier + "[" + i + "]", declarations, result);
}
if (value != null) {
hasValue = true;
buf.append(value.toString());
}
}
}
}
// ArrayList End
if (hasValue) {
buf.append('}');
return buf.toString();
} else {
return null;
}
} else {
return readValue(in, parentIdentifier, declarations, result);
}
}
}
private Object readValue(ImageInputStream in, String parentIdentifier, Declarations declarations, Vector result)
throws IOException {
Object value = primitiveSpecifier.read(in, parentIdentifier, declarations, result);
if (value != null) {
if (value instanceof Number) {
int intValue = ((Number) value).intValue();
if (enumSpecifier != null) {
value = enumSpecifier.toEnumString(intValue, declarations);
} else if (setSpecifier != null) {
value = setSpecifier.toSetString(intValue, declarations);
}
} else if (value instanceof String) {
if (enumSpecifier != null) {
value = enumSpecifier.toEnumString((String) value, declarations);
}
}
}
return value;
}
@Override
public String toString() {
StringBuffer buf = new StringBuffer();
buf.append("TypeSpecifier ");
buf.append("" + structSpecifier);
buf.append("" + primitiveSpecifier);
buf.append("" + enumSpecifier);
buf.append("" + setSpecifier);
buf.append("" + arrayList);
return buf.toString();
}
}
/**
* StructSpecifier expression.
*
*
* StructSpecifier ::= "struct (identifier | "{" MemberDeclaration { MemberDeclaration } "}" )
*
*/
protected static class StructSpecifier {
public String identifier;
public Vector members;
public StructSpecifier(StreamPosTokenizer scanner)
throws IOException, ParseException {
if (scanner.nextToken() != StreamPosTokenizer.TT_WORD || !scanner.sval.equals("struct")) {
throw new ParseException(errorMsg("StructSpecifier: 'struct' expected", scanner));
}
scanner.nextToken();
if (scanner.ttype == StreamPosTokenizer.TT_WORD) {
identifier = scanner.sval;
} else if (scanner.ttype == '{') {
members = new Vector();
while (scanner.nextToken() != '}') {
scanner.pushBack();
members.addElement(new MemberDeclaration(scanner));
}
} else {
throw new ParseException(errorMsg("StructSpecifier: identifier or '{' expected", scanner));
}
}
private void read(ImageInputStream in, String parentIdentifier, Declarations declarations, Vector result)
throws IOException {
//try {
Enumeration enm = members.elements();
while (enm.hasMoreElements()) {
MemberDeclaration aMember = (MemberDeclaration) enm.nextElement();
aMember.read(in, parentIdentifier, declarations, result);
}
/*
} catch (IOException e) {
System.out.println("StructParser.StructSpecifier.read(...) IOException @ "+identifier);
e.printStackTrace();
throw e;
}*/
}
}
/**
* MemberDeclaration expression.
*
*
* MemberDeclaration ::= TypeSpecifier identifier [ArrayList] ";"
* ArrayList ::= "[" [ArraySize] "]" {"," identifier "[" [ArraySize] "]" }
*
*/
protected static class MemberDeclaration {
public TypeSpecifier typeSpecifier;
public String identifier;
public Vector arrayList;
public MemberDeclaration(StreamPosTokenizer scanner)
throws IOException, ParseException {
typeSpecifier = new TypeSpecifier(scanner);
if (scanner.nextToken() != StreamPosTokenizer.TT_WORD) {
throw new ParseException(errorMsg("MemberDeclaration: identifier expected", scanner));
}
identifier = scanner.sval;
// ArrayList Begin
if (scanner.nextToken() == '[') {
arrayList = new Vector();
do {
arrayList.addElement(new ArraySize(scanner));
if (scanner.nextToken() != ']') {
throw new ParseException(errorMsg("MemberDeclaration: ']' expected", scanner));
}
} while (scanner.nextToken() == '[');
scanner.pushBack();
} else {
scanner.pushBack();
}
// ArrayList End
if (scanner.nextToken() == ';') {
} else if (scanner.ttype == '}') {
scanner.pushBack();
} else {
throw new ParseException(errorMsg("MemberDeclaration: ';' expected", scanner));
}
}
private void read(ImageInputStream in, String parentIdentifier, Declarations declarations, Vector result)
throws IOException {
if (arrayList != null) {
// ArrayList Begin
Enumeration enm = arrayList.elements();
while (enm.hasMoreElements()) {
ArraySize arraySize = (ArraySize) enm.nextElement();
int size = arraySize.getArraySize(declarations, result);
if (size == ArraySize.REMAINDER) {
try {
for (int i = 0;; i++) {
int loc = result.size();
Object obj = typeSpecifier.read(in, parentIdentifier + "." + identifier + "[" + i + "]", declarations, identifier, result);
if (obj != null) {
StructTableModel.Value value = new StructTableModel.Value();
value.qualifiedIdentifier = parentIdentifier + "." + identifier;
value.declaration = identifier;
value.value = obj;
result.addElement(value);
}
}
} catch (EOFException e) {
}
} else {
for (int i = 0; i < size; i++) {
int loc = result.size();
Object obj = typeSpecifier.read(in, parentIdentifier + "." + identifier + "[" + i + "]", declarations, identifier, result);
if (obj != null) {
StructTableModel.Value value = new StructTableModel.Value();
value.qualifiedIdentifier = parentIdentifier + "." + identifier+ "[" + i + "]";
value.declaration = identifier;
value.value = obj;
result.addElement(value);
}
}
}
}
// ArrayList End
} else {
Object obj = typeSpecifier.read(in, parentIdentifier + "." + identifier, declarations, identifier, result);
if (obj != null) {
StructTableModel.Value value = new StructTableModel.Value();
value.qualifiedIdentifier = parentIdentifier + "." + identifier;
value.declaration = identifier;
value.value = obj;
result.addElement(value);
}
}
}
}
/**
* PrimitiveSpecifier expression.
*
*
* PrimitiveSpecifier ::= "uint" n | "ubyte" | "byte" | "short" | "ushort" |
* | "int" | "long" | "float" | "double" | "extended"
* | "char" | "charbyte" | "cstring" | "utf8" | "pstring"
* | "pstring32"
* | "utf16le" |"magic" | "mactimestamp"
* | "bcd2" | "bcd4"
*
*/
protected static class PrimitiveSpecifier {
private final static int NON_PRIMITIVE = -1;
private final static char[] HEX = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
/* 8 bits signed. */
public final static int BYTE = 0;
/* 8 bits unsigned. */
public final static int UBYTE = 1;
/* 16 bits signed big endian. */
public final static int SHORT = 2;
/* 16 bits unsigned big endian. */
public final static int USHORT = 3;
/* 32 bits signed big endian. */
public final static int INT = 4;
/* 32 bits unsigned big endian. */
public final static int UINT = 5;
/* 64 bits signed big endian. */
public final static int LONG = 6;
/* 32 bits IEEE 754. */
public final static int FLOAT = 7;
/* 64 bits IEEE 754. */
public final static int DOUBLE = 8;
/* 80 bits IEEE 754. */
public final static int EXTENDED = 9;
/* 8 bits ASCII. */
public final static int CHARBYTE = 10;
/* 16 bits UTF-16. */
public final static int CHAR = 11;
/* C-Style Zero terminated ASCII String. */
public final static int CSTRING = 12;
/* Pascal Style String. Starting with an 8 or 16 bit long length value. */
public final static int PSTRING = 13;
/* Pascal Style String. Starting with an 8 or 16 bit long length value.
padded to 32 bytes. */
public final static int PSTRING32 = 30;
/* UTF-8 zero terminated string. */
public final static int UTF8 = 32;
/* UTF-16 little endian zero terminated string. */
public final static int UTF16LE = 29;
/* 4 ASCII characters in 4 subsequent bytes. */
public final static int MAGIC = 14;
/* 32 bit signed count of seconds since 1904. */
public final static int MAC_TIMESTAMP = 15;
/* A typedef type. */
public final static int TYPEDEF_TYPE = 16;
/* 16 bits signed little endian. */
public final static int SHORTLE = 17;
/* 16 bits unsigned little endian. */
public final static int USHORTLE = 18;
/* 32 bits signed little endian. */
public final static int INTLE = 19;
/* 32 bits unsigned little endian. */
public final static int UINTLE = 20;
/* 64 bits signed little endian. */
public final static int LONGLE = 21;
/* 2 Digits Binary Coded Decimal (=1 byte). */
public final static int BCD2 = 22;
/* 4 Digits Binary Coded Decimal (=2 bytes). */
public final static int BCD4 = 23;
/* 32-bit fixed decimal divided by 16.16 (=4 bytes). */
public final static int FIXED_16D16 = 24;
/* 32-bit fixed decimal divided by 2.30 (=4 bytes). */
public final static int FIXED_2D30 = 25;
/* 16-bit fixed decimal divided by 8.8 (=2 bytes). */
public final static int FIXED_8D8 = 26;
/* 1 bit unsigned. Does not need to start at byte boundaries. */
public final static int UINT1 = 34;
/* 2 bits unsigned. Does not need to start at byte boundaries. */
public final static int UINT2 = 35;
/* 3 bits unsigned. Does not need to start at byte boundaries. */
public final static int UINT3 = 36;
/* 4 bits unsigned. Does not need to start at byte boundaries. */
public final static int UINT4 = 27;
/* 5 bits unsigned. Does not need to start at byte boundaries. */
public final static int UINT5 = 37;
/* 5 bits unsigned. Does not need to start at byte boundaries. */
public final static int UINT9 = 41;
/* 8 bits unsigned. Does not need to start at byte boundaries. */
public final static int UINT8 = 33;
/* 16 bits unsigned. Does not need to start at byte boundaries. */
public final static int UINT12 = 38;
/* 16 bits unsigned. Does not need to start at byte boundaries. */
public final static int UINT16 = 39;
/* 31 bits unsigned. Does not need to start at byte boundaries. */
public final static int UINT31LE = 42;
/* 9 bits signed. Does not need to start at byte boundaries. */
public final static int INT9 = 40;
/* Atari 16 bit color value with 3 bits per channel:
* RGB 00000rrr0ggg0bbb
*/
public final static int ATARI_COLOR = 31;
public int type;
public String typedef;
public PrimitiveSpecifier(StreamPosTokenizer scanner)
throws IOException, ParseException {
if (scanner.nextToken() != StreamPosTokenizer.TT_WORD) {
throw new ParseException(errorMsg("PrimitiveSpecifier: primitive type name expected", scanner));
}
if (scanner.sval.equals("ataricolor")) {
type = ATARI_COLOR;
} else if (scanner.sval.equals("byte")) {
type = BYTE;
} else if (scanner.sval.equals("ubyte")) {
type = UBYTE;
} else if (scanner.sval.equals("uint8")) {
type = UINT8;
} else if (scanner.sval.equals("short")) {
type = SHORT;
} else if (scanner.sval.equals("int16")) {
type = SHORT;
} else if (scanner.sval.equals("ushort")) {
type = USHORT;
} else if (scanner.sval.equals("uint16")) {
type = UINT16;
} else if (scanner.sval.equals("int")) {
type = INT;
} else if (scanner.sval.equals("uint")) {
type = UINT;
} else if (scanner.sval.equals("uint32")) {
type = UINT;
} else if (scanner.sval.equals("long")) {
type = LONG;
} else if (scanner.sval.equals("float")) {
type = FLOAT;
} else if (scanner.sval.equals("double")) {
type = DOUBLE;
} else if (scanner.sval.equals("extended")) {
type = EXTENDED;
} else if (scanner.sval.equals("char")) {
type = CHAR;
} else if (scanner.sval.equals("charbyte")) {
type = CHARBYTE;
} else if (scanner.sval.equals("cstring")) {
type = CSTRING;
} else if (scanner.sval.equals("utf8")) {
type = UTF8;
} else if (scanner.sval.equals("utf16le")) {
type = UTF16LE;
} else if (scanner.sval.equals("pstring")) {
type = PSTRING;
} else if (scanner.sval.equals("pstring32")) {
type = PSTRING32;
} else if (scanner.sval.equals("magic")) {
type = MAGIC;
} else if (scanner.sval.equals("mactimestamp")) {
type = MAC_TIMESTAMP;
} else if (scanner.sval.equals("shortLE")) {
type = SHORTLE;
} else if (scanner.sval.equals("ushortLE")) {
type = USHORTLE;
} else if (scanner.sval.equals("intLE")) {
type = INTLE;
} else if (scanner.sval.equals("uintLE")) {
type = UINTLE;
} else if (scanner.sval.equals("longLE")) {
type = LONGLE;
} else if (scanner.sval.equals("bcd2")) {
type = BCD2;
} else if (scanner.sval.equals("bcd4")) {
type = BCD4;
} else if (scanner.sval.equals("fixed16d16")) {
type = FIXED_16D16;
} else if (scanner.sval.equals("fixed2d30")) {
type = FIXED_2D30;
} else if (scanner.sval.equals("fixed8d8")) {
type = FIXED_8D8;
} else if (scanner.sval.equals("uint1")) {
type = UINT1;
} else if (scanner.sval.equals("uint2")) {
type = UINT2;
} else if (scanner.sval.equals("uint3")) {
type = UINT3;
} else if (scanner.sval.equals("uint4")) {
type = UINT4;
} else if (scanner.sval.equals("uint5")) {
type = UINT5;
} else if (scanner.sval.equals("uint9")) {
type = UINT9;
} else if (scanner.sval.equals("uint12")) {
type = UINT12;
} else if (scanner.sval.equals("int9")) {
type = INT9;
} else if (scanner.sval.equals("uint31LE")) {
type = UINT31LE;
} else {
type = TYPEDEF_TYPE;
typedef = scanner.sval;
}
}
private int getResolvedPrimitveType(Declarations declarations) throws IOException {
switch (type) {
case TYPEDEF_TYPE:
TypedefDeclaration typedefDeclaration = (TypedefDeclaration) declarations.typedefs.get(typedef);
if (typedefDeclaration == null) {
throw new IOException("typedef not found for:" + typedef);
}
return typedefDeclaration.getResolvedType(declarations);
default:
return type;
}
}
private Object read(ImageInputStream in, String parentIdentifier, Declarations declarations, Vector result)
throws IOException {
switch (type) {
case BYTE:
return new Byte(in.readByte());
case UBYTE: {
int b = in.read();
if (b == -1) {
throw new EOFException();
}
return new Integer(b);
}
case SHORT:
return new Short(in.readShort());
case USHORT:
return new Integer(in.readShort() & 0xffff);
case INT:
return new Integer(in.readInt());
case UINT:
return new Long(in.readInt() & 0xffffffffL);
case LONG:
return new Long(in.readLong());
case FLOAT:
return new Float(in.readFloat());
case DOUBLE:
return new Double(in.readDouble());
case EXTENDED: {
byte[] bits = new byte[10];
in.readFully(bits);
return new ExtendedReal(bits);
}
case CHARBYTE: {
char ch = (char) (in.readByte() & 0xff);
if (ch <= 0x20 || Character.isIdentifierIgnorable(ch)) {
return "0x" + Integer.toHexString(ch);
} else {
return new Character(ch);
}
}
case CHAR:
return new Character(in.readChar());
case CSTRING: {
StringBuffer buf = new StringBuffer();
int ch;
while ((ch = in.read()) > 0) {
buf.append((char) ch);
}
return buf.toString();
}
case UTF8: {
ByteArrayOutputStream buf = new ByteArrayOutputStream();
int ch1;
while ((ch1 = in.read()) > 0) {
buf.write(ch1);
}
return new String(buf.toByteArray(), "UTF-8");
}
case UTF16LE: {
StringBuffer buf = new StringBuffer();
int ch1;
while ((ch1 = in.read()) > 0) {
int ch2 = in.read();
buf.append((char) (ch1 | (ch2 << 8)));
}
return buf.toString();
}
case PSTRING: {
int size = in.read();
if (size == 0) {
size = in.read();
in.read(); // why do we skip two bytes here?
in.read();
}
if (size < 0) {
return "";
}
byte[] bytes = new byte[size];
//in.readFully(bytes);
int n = 0;
while (n < size) {
int count = in.read(bytes, n, size - n);
if (count < 0) {
System.out.println("StructParser.PrimitiveSpecifier.read not enough bytes for pstring. Expected size:" + size + " actual size:" + n);
break;
//throw new EOFException();
}
n += count;
}
return new String(bytes);
}
case PSTRING32: {
int used = 1;
int size = in.read();
if (size == 0) {
size = in.read();
in.read();
in.read();
used += 2;
}
if (size > 32 - used) {
size = 32 - used;
}
byte[] bytes = new byte[size];
//in.readFully(bytes);
int n = 0;
while (n < size) {
int count = in.read(bytes, n, size - n);
if (count < 0) {
System.out.println("StructParser.PrimitiveSpecifier.read not enough bytes for pstring. Expected size:" + size + " actual size:" + n);
break;
//throw new EOFException();
}
n += count;
}
used += size;
if (used < 32) {
in.skipBytes(32 - used);
}
return new String(bytes);
}
case MAGIC: {
int magic = in.readInt();
byte[] bytes = new byte[4];
bytes[0] = (byte) (magic >>> 24);
bytes[1] = (byte) (magic >>> 16);
bytes[2] = (byte) (magic >>> 8);
bytes[3] = (byte) (magic >>> 0);
return new String(bytes);
}
case MAC_TIMESTAMP: {
long timestamp = ((long) in.readInt()) & 0xffffffffL;
DateFormat fmt = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Date date = new Date(MAC_TIMESTAMP_EPOCH + timestamp * 1000);
return fmt.format(date);
}
case TYPEDEF_TYPE: {
TypedefDeclaration typedefDeclaration = (TypedefDeclaration) declarations.typedefs.get(typedef);
if (typedefDeclaration == null) {
throw new IOException("typedef not found for:" + typedef);
}
return typedefDeclaration.read(in, parentIdentifier, declarations, result);
}
case SHORTLE: {
int b0 = in.read();
int b1 = in.read();
if (b1 == -1) {
throw new EOFException();
}
return new Short((short) (b0 & 0xff | (b1 & 0xff) << 8));
}
case USHORTLE: {
int b0 = in.read();
int b1 = in.read();
if (b1 == -1) {
throw new EOFException();
}
return new Integer(b0 & 0xff | ((b1 & 0xff) << 8));
}
case INTLE: {
int b0 = in.read();
int b1 = in.read();
int b2 = in.read();
int b3 = in.read();
if (b3 == -1) {
throw new EOFException();
}
return new Integer(b0 & 0xff | ((b1 & 0xff) << 8) | ((b2 & 0xff) << 16) | ((b3 & 0xff) << 24));
}
case UINTLE: {
int b0 = in.read();
int b1 = in.read();
int b2 = in.read();
int b3 = in.read();
if (b3 == -1) {
throw new EOFException();
}
return new Long(((long) (b0 & 0xff | ((b1 & 0xff) << 8) | ((b2 & 0xff) << 16) | ((b3 & 0xff) << 24))) & 0x00ffffffff);
}
case LONGLE: {
int b0 = in.read();
int b1 = in.read();
int b2 = in.read();
int b3 = in.read();
int b4 = in.read();
int b5 = in.read();
int b6 = in.read();
int b7 = in.read();
if (b7 == -1) {
throw new EOFException();
}
return new Long(
(long) b0 & 0xff | ((long) (b1 & 0xff) << 8) | ((long) (b2 & 0xff) << 16) | ((long) (b3 & 0xff) << 24) | ((long) (b4 & 0xff) << 32) | ((long) (b5 & 0xff) << 40) | ((long) (b6 & 0xff) << 48) | ((long) (b7 & 0xff) << 56));
}
case BCD2: {
int b0 = in.read();
return new Integer(
((b0 & 0xf0) >> 4) * 10
+ (b0 & 0x0f));
}
case BCD4: {
int b0 = in.read();
int b1 = in.read();
return new Integer(
((b0 & 0xf0) >> 4) * 1000
+ (b0 & 0x0f) * 100
+ ((b1 & 0xf0) >> 4) * 10
+ (b1 & 0x0f));
}
case FIXED_16D16: {
int wholePart = in.readUnsignedShort();
int fractionPart = in.readUnsignedShort();
return new Double(wholePart + fractionPart / 65536.0);
}
case FIXED_2D30: {
int fixed = in.readInt();
int wholePart = fixed >>> 30;
int fractionPart = fixed & 0x3fffffff;
return new Double(wholePart + fractionPart / (double) 0x3fffffff);
}
case FIXED_8D8: {
int fixed = in.readUnsignedShort();
int wholePart = fixed >>> 8;
int fractionPart = fixed & 0xff;
return new Float(wholePart + fractionPart / 256f);
}
case UINT1: {
return in.readBit();
}
case UINT2: {
return (int) in.readBits(2);
}
case UINT3: {
return (int) in.readBits(3);
}
case UINT4: {
return (int) in.readBits(4);
}
case UINT5: {
return (int) in.readBits(5);
}
case UINT9: {
return (int) in.readBits(9);
}
case UINT8: {
return (int) in.readBits(8);
}
case UINT12: {
return (int) in.readBits(12);
}
case UINT16: {
return (int) in.readBits(16);
}
case UINT31LE: {
int value= (int)in.readBits(31);
return ((value&0xff)<<24)|((value&0xff00)<<8)|((value&0xff0000)>>>8)|((value&0xff000000)>>>24);
}
case INT9: {
int value = (int) in.readBits(9);
if ((value & 0x256) != 0) {
value |= 0xffffff00;
}
return value;
}
case ATARI_COLOR: {
int clr = in.readUnsignedShort();
int red = (clr & 0x700) >> 8;
int green = (clr & 0x70) >> 4;
int blue = (clr & 0x7);
StringBuilder buf = new StringBuilder();
String hex = Integer.toHexString(clr);
buf.append("0x");
for (int i = 0; i < 4 - hex.length(); i++) {
buf.append('0');
}
buf.append(hex);
buf.append(" {rgb:0x");
int rgb = ((red << 5) | (red << 2) | (red >>> 1)) << 16//
| ((green << 5) | (green << 2) | (green >>> 1)) << 8
| ((blue << 5) | (blue << 2) | (blue >>> 1));
hex = Integer.toHexString(rgb);
for (int i = 0; i < 6 - hex.length(); i++) {
buf.append('0');
}
buf.append(hex);
buf.append(", rgb:");
buf.append((red << 5) | (red << 2) | (red >>> 1));
buf.append(' ');
buf.append((green << 5) | (green << 2) | (green >>> 1));
buf.append(' ');
buf.append((blue << 5) | (blue << 2) | (blue >>> 1));
buf.append('}');
return new String(buf);
}
default:
throw new InternalError("invalid type:" + type);
}
}
}
/**
* ArraySize expression.
*
*
* ArraySize ::= () | intLiteral ["-" intLiteral]
*
*/
protected static class ArraySize {
public final static int REMAINDER = -1;
public final static int LITERAL = 0;
public final static int VARIABLE = 1;
public final static int NEGATIVE_VARIABLE = 2;
public final static int EQUAL = 3;
public final static int NOT_EQUAL = 4;
public int type = LITERAL;
public int size;
public String variable;
public int offset;
public Object equal;
public ArraySize(StreamPosTokenizer scanner)
throws IOException, ParseException {
if (scanner.nextToken() == ']') {
scanner.pushBack();
type = REMAINDER;
} else if (scanner.ttype == StreamPosTokenizer.TT_WORD) {
variable = scanner.sval;
if (scanner.nextToken() == '-') {
offset = new IntLiteral(scanner).intValue() * -1;
type = VARIABLE;
} else if (scanner.ttype == '+') {
offset = new IntLiteral(scanner).intValue();
type = VARIABLE;
} else if (scanner.ttype == '=') {
if (scanner.nextToken() != '=') {
throw new ParseException(errorMsg("== expected", scanner));
}
if (scanner.nextToken() == '"') {
equal = scanner.sval;
} else {
scanner.pushBack();
equal = new IntLiteral(scanner).intValue();
}
type = EQUAL;
} else if (scanner.ttype == '!') {
if (scanner.nextToken() != '=') {
throw new ParseException(errorMsg("!= expected", scanner));
}
if (scanner.nextToken() == '"') {
equal = scanner.sval;
} else {
int sign;
if (scanner.ttype=='-') {
sign=-1;
}else {
sign=1;
scanner.pushBack();
}
equal = new IntLiteral(scanner).intValue()*sign;
}
type = NOT_EQUAL;
} else {
type = VARIABLE;
scanner.pushBack();
}
} else {
scanner.pushBack();
size = new IntLiteral(scanner).intValue();
if (scanner.nextToken() == '-') {
offset = size;
size = 0;
if (scanner.nextToken() != StreamPosTokenizer.TT_WORD) {
throw new ParseException(errorMsg("Variable name expected", scanner));
}
variable = scanner.sval;
type = NEGATIVE_VARIABLE;
} else if (scanner.ttype == '+') {
offset = size;
size = 0;
if (scanner.nextToken() != StreamPosTokenizer.TT_WORD) {
throw new ParseException(errorMsg("Variable name expected", scanner));
}
variable = scanner.sval;
type = VARIABLE;
} else if (scanner.ttype == '=') {
if (scanner.nextToken() != '=') {
throw new ParseException(errorMsg("== expected", scanner));
}
offset = size;
size = 0;
if (scanner.nextToken() != StreamPosTokenizer.TT_WORD) {
throw new ParseException(errorMsg("Variable name expected", scanner));
}
variable = scanner.sval;
type = EQUAL;
} else if (scanner.ttype == '!') {
if (scanner.nextToken() != '=') {
throw new ParseException(errorMsg("== expected", scanner));
}
offset = size;
size = 0;
if (scanner.nextToken() != StreamPosTokenizer.TT_WORD) {
throw new ParseException(errorMsg("Variable name expected", scanner));
}
variable = scanner.sval;
type = NOT_EQUAL;
} else {
type = LITERAL;
scanner.pushBack();
}
}
}
public int getArraySize(Declarations declarations, Vector result) {
switch (type) {
case LITERAL:
return size;
case VARIABLE:
case NEGATIVE_VARIABLE:
int sign = type == NEGATIVE_VARIABLE ? -1 : 1;
// Search for variable with the same name
for (int i = result.size() - 1; i > -1; i--) {
StructTableModel.Value value = (StructTableModel.Value) result.elementAt(i);
if (value.declaration.equals(variable)) {
int variableValue = ((Number) value.value).intValue();
return variableValue * sign + offset;
}
}
// Search for fully qualified variable with the same name
for (int i = result.size() - 1; i > -1; i--) {
StructTableModel.Value value = (StructTableModel.Value) result.elementAt(i);
if (value.qualifiedIdentifier.equals(variable)) {
int variableValue = ((Number) value.value).intValue();
return variableValue * sign + offset;
}
}
// Search for fully qualified variable with the same name ending
for (int i = result.size() - 1; i > -1; i--) {
StructTableModel.Value value = (StructTableModel.Value) result.elementAt(i);
if (value.qualifiedIdentifier.endsWith(variable)) {
int variableValue = ((Number) value.value).intValue();
return variableValue * sign + offset;
}
}
throw new InternalError("Invalid ArraySize variable:" + variable);
case EQUAL:
case NOT_EQUAL:
int trueValue = type == EQUAL ? 1 : 0;
int falseValue = 1 - trueValue;
// Search for variable with the same name
for (int i = result.size() - 1; i > -1; i--) {
StructTableModel.Value value = (StructTableModel.Value) result.elementAt(i);
if (value.declaration.equals(variable)) {
return ((Number)equal).intValue()==value.intValue? trueValue : falseValue;
}
}
// Search for fully qualified variable with the same name
for (int i = result.size() - 1; i > -1; i--) {
StructTableModel.Value value = (StructTableModel.Value) result.elementAt(i);
if (value.qualifiedIdentifier.equals(variable)) {
return ((Number)equal).intValue()==((Number)value.value).intValue() ? trueValue : falseValue;
}
}
// Search for fully qualified variable with the same name ending
for (int i = result.size() - 1; i > -1; i--) {
StructTableModel.Value value = (StructTableModel.Value) result.elementAt(i);
if (value.qualifiedIdentifier.endsWith(variable)) {
return ((Number)equal).intValue()==((Number)value.value).intValue() ? trueValue : falseValue;
}
}
throw new InternalError("Invalid ArraySize variable:" + variable);
case REMAINDER:
return -1;
default:
throw new InternalError("Invalid ArraySize type:" + type);
}
}
}
/**
* IntLiteral expression.
*
*
* IntLiteral ::= intLiteral | hexLiteral
*
*/
protected static class IntLiteral {
public int value;
public IntLiteral(StreamPosTokenizer scanner)
throws IOException, ParseException {
if (scanner.nextToken() != StreamPosTokenizer.TT_NUMBER) {
throw new ParseException(errorMsg("IntLiteral: numeric value expected", scanner));
}
value = (int)((long) scanner.nval);// Must cast like this to get proper signs
if (scanner.nval == 0.0) {
if (scanner.nextToken() == StreamPosTokenizer.TT_WORD && scanner.sval.startsWith("x")) {
value = Integer.valueOf(scanner.sval.substring(1), 16).intValue();
} else {
scanner.pushBack();
}
}
}
public int intValue() {
return value;
}
}
/**
* MagicOrIntLiteral expression.
*
*
* MagicOrIntLiteral ::= magicLiteral | intLiteral | hexLiteral
*
*/
protected static class MagicOrIntLiteral {
public int intValue;
public String magicValue;
public MagicOrIntLiteral(StreamPosTokenizer scanner)
throws IOException, ParseException {
switch (scanner.nextToken()) {
case StreamPosTokenizer.TT_NUMBER:
intValue = (int) scanner.nval;
if (scanner.nval == 0.0) {
if (scanner.nextToken() == StreamPosTokenizer.TT_WORD && scanner.sval.startsWith("x")) {
intValue = Integer.valueOf(scanner.sval.substring(1), 16).intValue();
} else {
scanner.pushBack();
}
}
break;
case '-':
if (scanner.nextToken() != StreamPosTokenizer.TT_NUMBER) {
throw new ParseException(errorMsg("MagicOrIntLiteral: numeric value expected", scanner));
}
intValue = -(int) scanner.nval;
break;
case '"':
if (scanner.sval.length() != 4) {
throw new ParseException(errorMsg("MagicOrIntLiteral: magic with length of 4 characters expected", scanner));
}
magicValue = scanner.sval;
intValue = toInt(magicValue);
break;
default:
throw new ParseException(errorMsg("MagicOrIntLiteral: numeric value expected", scanner));
}
}
public boolean isMagic() {
return magicValue != null;
}
public int intValue() {
return intValue;
}
public String stringValue() {
return (magicValue == null) ? Integer.toString(intValue) : magicValue;
}
public static int toInt(String magic) {
return ((magic.charAt(0) & 0xff) << 24) | ((magic.charAt(1) & 0xff) << 16) | ((magic.charAt(2) & 0xff) << 8) | ((magic.charAt(3) & 0xff) << 0);
}
public static String toMagic(int value) {
byte[] buf = new byte[4];
buf[0] = (byte) ((value & 0xff000000) >>> 24);
buf[1] = (byte) ((value & 0xff0000) >>> 16);
buf[2] = (byte) ((value & 0xff00) >>> 8);
buf[3] = (byte) (value & 0xff);
try {
return new String(buf, "ASCII");
} catch (UnsupportedEncodingException e) {
InternalError error = new InternalError(e.getMessage());
error.initCause(e);
throw error;
}
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy