Skip to content
revbingo edited this page Sep 22, 2010 · 18 revisions

Spiff needs for you to have three things - a binary file to parse, a description of the file format, and some classes that will ultimately represent the contents of the file.

File formats are described in an .adf file (adf = Arbitrary Data Format). The formal grammar of the file is described in AdfGrammar. The .adf extension is a convention rather than a necessity.

##Primitives The most basic things you can do are to specify a list of datatypes, in the order in which they occur in the file, followed by a name to give to that field. The primitive datatypes map directly to Java primitives:

byte (1 byte)
short (2 bytes)
int (4 bytes)
long (8 bytes)
double (4 bytes)
float  (8 bytes)

There are also unsigned equivalents for integers:

ubyte
ushort
uint
ulong

Names for the fields will be used to find corresponding fields in bound classes, so identifiers use the java convention (alphanumeric starting with an alpha). For instance, the file header of a bitmap file looks like this:

short    bfType
int      bfSize
short    bfReserved1
short    bfReserved2
int      bfOffBits

##Comments Comments can be included in the file with the standard //. Multiline comments are not currently supported

##Strings Strings can be of two types, either fixed length or null terminated. In addition, you can specify an encoding to be used to decode the string. If no encoding is specified, the platform default is used. The four available syntax options are:

string    nullTerminatedWithDefaultEncoding
string(10)    stringThatIs10BytesLongWithDefaultEncoding
string(US-ASCII)    usAsciiStringThatIsNullTerminated
string(10, UTF-16)   utf16StringThatIsNullTerminated

Encodings can currently be one of UTF-8, UTF-16, UTF-16LE or US-ASCII. See also SettingDefaultOptions

##Flow of execution Most binary file formats also require some sort of logic. Spiff allows you to specify conditions and other instructions in amongst the datatypes to control the flow of execution. Instructions in adf files always start with a period ('.'). Blocks (such as conditionals or loops) are surrounded with curly braces ('{}'). Remember though that the "flow of execution" describes simply the order in which instructions are executed - the byte position of the "pointer" in the file only moves forward, unless you use a .jump or .skip to move it backwards (although why you'd want to parse the same data twice is up to you...)

Conditionals can be achieved with .if and .else . These work just like you'd expect them to:

.if(bfType == 1) {
   short   theDataIfBfTypeIs1
} .else {
   int  theDataisBfTypeIsNot1
}

Expressions passed as arguments can reference values from earlier instructions simply by using the identifier, and can also reference the byte position in the file of an earlier instruction by prefixing the name with an ampersand. For more detail on what you can specify in expressions, see ExpressionLanguage

Loops can be done using the .repeat instruction. Repeat takes an argument specifying how many times to repeat:

.repeat(bitmapWidth*bitmapHeight) {
     int    pixelData
}

Many file formats include pieces of data that are reserved for future use, or are simply bits of the file that you don't care about. You can change position in the file with the .skip and .jump instructions (no .hop though). The .jump instruction moves to an absolute position:

int    nextDataPosition
.jump nextDataPosition  

whereas the .skip instruction moves the "pointer" relative to the current position:

short   numberOfUnusedBytes
.skip numberOfUnusedBytes

##Setting Default Options There are two instructions that can be specified in the .adf file that determine how subsequent instructions work. The instructions can appear anywhere in the file, and will change the default option whenever the flow of execution passes through them.

The .setorder instruction determines the endianness of the data. Valid values are LITTLE-ENDIAN and BIG-ENDIAN

.setorder BIG-ENDIAN

The .setencoding instruction sets a default encoding for the file. This encoding will be used for all string datatypes, unless specified otherwise. Valid values are UTF-8, UTF-16, UTF-16LE and US-ASCII

.setencoding UTF-16
string    aStringThatWillBeDecodedUsingUTF-16
string(US-ASCII)   aStringThatWillBeDecodedUsingUSASCII
string    anotherStringThatWillBeDecodedUsingUTF-16
.setencoding UTF-8
string   thisStringWillNowBeDecodedUsingUTF-8

Clone this wiki locally