General Form

 

A Hex Workshop structure closely resembles a structure definition the C programming language, which is familiar to many developers and easily learned by others. Future versions of Hex Workshop will incorporate a structure building tool along with the ability to extract structures from existing C/C++ source files.

 

The following is an example of a Hex Workshop Structure definition. Both C++ comments ("// COMMENT") and C comments( "/* COMMENT */") are supported.

 

 /*

  * LocalFileHeader for a .ZIP compressed file.

  */

 struct LocalFileHeader

 {

    char Signature[4]; // PK<0x03><0x04>

#pragma verify match_var_int("Signature[0]", "0x50")

#pragma verify match_var_int("Signature[1]", "0x4B")

#pragma verify match_var_int("Signature[2]", "0x03")

#pragma verify match_var_int("Signature[3]", "0x04")

    WORD VersionNeededToExtract;

    WORD GeneralPurposeBitFlag;

    WORD CompressionMethod;

    DOSTIME LastModFileTime;

    DOSDATE LastModFileDate;

    DWORD Crc32;

    DWORD CompressedSize;

    DWORD UncompressedSize;

    WORD FileNameLength;

    WORD ExtraFieldLength;

 };

 

The general format of a structure is as follows:

 

struct <<STRUCTURE_NAME>>

    <<DATA_TYPES_AND_NAMES>>

};

  

A structure definition begins with the key word "struct" followed by the structure name. The structure name cannot contain any tabs or spaces. An opening brace "{" marks the beginning of the data declaration and a closing brace "}" marks its end. Lastly, a semicolon ";" marks the end of the structure definition.

 

Data Types

 

Data types are declared in the following form:

 

 <<DATA_TYPE>> <<VARIABLE_NAME>;

 

A trailing semicolon is required and variable names cannot contain tabs or spaces.

 

For a list of basic built-in data types, see Basic Structure Data Types. Additional data types are provided in the standard-type library included with Hex Workshop.

 

Arrays

 

To specify an array of a data type, indicate the desired repetition count of the array, in decimal, surrounded by brackets after the variable name. In the example below, 32 values of data type "int" are defined under the variable myArray:

 

 int myArray[32];

 

Users may also define variable length arrays within structures. A variable length character string is demonstrated below:

 

struct pstring16

{

    unsigned short len;  // 16 bits worth of length

    char content[len]; // Actual string content

};

 

Users can also perform simple calculations within array declarations. For example, consider the need to deserialize a 2-dimensional array of bytes:

 

 struct myByteArray

{

    unsigned short rows;

    unsigned short columns;

    __int8 data[rows*columns];

};

 

Nested Structures

 

You can nest one structure within another by using a command of the following form:

 

struct <<STRUCTURE_NAME>> <<VARIABLE_NAME>>;

 

In the following example, an ARGB structure is defined and followed by the definition of a palette structure, which as defined below contains an array of 256 ARGB structures.

 

struct ARGB

{

    BYTE alpha;

    BYTE red;

    BYTE green;

    BYTE blue;

};

 

struct palette

{

    struct ARGB entries[256];

};

 

Enumerated Types

 

Enumerated types allow users to couple human readable names with numeric values. When an enumeration is defined, Hex Workshop allows you to view and work with the human readable names within the editing environment.

 

Enumerated types are defined similarly to structures. The general form begins with the "enum" keyword, followed by the enumeration name, an opening brace "{", enumeration definitions, a closing brace "}", and a trailing semicolon ";". Enumeration values must be specified in decimal.

 

enum <<ENUM_NAME>>

{

    <<ENUM_DEFINITIONS>>

};

 

Examples:

 

enum _FINDEX_SEARCH_OPS

{

    FindExSearchNameMatch,          // Value: 0

    FindExSearchLimitToDirectories, // Value: 1

    FindExSearchLimitToDevices,     // Value: 2

    FindExSearchMaxSearchOp         // Value: 3

};

 

enum myOtherExample

{

    MY_STARTING_VALUE = 100, // Value: 100

    MY_NEXT_VALUE_1,         // Value: 101

    MY_NEXT_VALUE_2,         // Value: 102

    MY_RESET_VALUE = 200,    // Value: 200

    MY_NEXT_VALUE_3,         // Value: 203

};

 

 

Defining your own types (typedef)

 

The typedef keyword allows users to create and name new data types. Each new data type must map to a basic built-in data type or a pre-defined type. The following example creates two 8 bit signed integer data types named "BYTE" and "byte". The struct myTypedefExample then uses a basic type and the newly created data types to create a structure with three 8 bit signed values (b1, b2, and b3).

 

typedef signed __int8 BYTE;

typedef BYTE byte;

 

struct myTypedefExample

{

    signed __int8 b1;

    BYTE b2;

    byte b3;

} ;

 

Users can also typedef structures and enumerations. Typedef must be specified as part of the declaration. The example below defines a new data type POINT and LINE structure. The LINE structure defines the start and end points of the line by naming the full structure (struct tagPOINT) and the typedef name (POINT):

 

 typedef struct tagPOINT

{

    LONG x;

    LONG y;

} POINT;

 

struct LINE

{

    struct tagPOINT start;

    POINT end;   

};

 

Including other files (#include)

 

By adding a #include directive to a structure library definition file, Hex Workshop will insert the literal contents of the designated structure library (#include parameter) into your current structure library file where the #include is defined. For example, all of the sample structure libraries included with Hex Workshop reference a common library (standard-types.hsl) that consists of common and standard data types. The #include directive used in the sample libraries is provided below.

 

 #include "standard-types.hsl"

 

Setting display name (#pragma displayname("'))

 

The displayname pragma defines the friendly name of the structure.  The friendly name is displayed on the structure viewer selection tool.

 

#pragma displayname("zip structures")

 

Setting file extensions (#pragma fileextensions("'))

 

The fileextensions pragma defines which document extensions are appropriate for the structure definition.  Multiple file extensions can be specified by using a semicolon a delimited.  If the structure definition is loaded/open, Hex Workshop will automatically select the library whenever a compatible document is in focus.

 

#pragma fileextensions(".zip;.jar")

 

Setting enum data size (#pragma enumsize(n))

 

By default an enumerate type is assumed to be a 4 byte (32 bit) data member. To define an enumeration for an 8 bit, 16 bit, or 64 bit enumerated type, use the #pragma directive to indicate the size. The #pragma directive sets the enumeration data size for all enumerations defined after the directive until a new #pragma is encountered.

 

#pragma enumsize(1) // Enums defined after here are 1 byte (8 bits)

 

<<enum definitions>>

 

#pragma enumsize(2) // Enums defined after here are 2 bytes (16 bits)

 

<<enum definitions>>

 

#pragma enumsize(4) // Enums defined after here are 4 bytes (32 bits)

 

<<enum definitions>>

 

#pragma enumsize(8) // Enums defined after here are 8 bytes (64 bits)

 

<<enum definitions>>

 

Setting maximum array length (#pragma maxarray(n))

 

By default, Hex Workshop limits the length of arrays to 1024 members. This setting imposes an upper limit to bound how much processing Hex Workshop performs when evaluation structures. If a structure definition contains expodential data structures (arrays of arrays) and is applied to a corrupt file, Hex Workshop may appear to hang while processing.

 

#pragma maxarray(2048); // Increase the max array length to 2048

 

Strings

 

The Hex Workshop structure view can accommodate three popular types of strings:

Example of the tree string types are shown below:

 

struct stringexample

{

    zstring null_terminated_str;

    char fixed_length_str[128];

    struct length_first_str

    {

        WORD length;

        char string[length];

    };

};

 

Setting the maximum string length (#pragma maxstring(n))

 

Like array lengths, Hex Workshop limits the maximum string length to avoid run-away processing of corrupt files. By default, strings are limited to 512 characters, however, users may increase the number of charcters to a max of 65,536 by using the maxstring #pragma. An example is shown below:

 

#pragma maxstring(128); // Decrease the max string length to 128

 

Bitfields

 

Hex Workshop v4.2 added basic support for C style bitfields. Bitfields allow users to view and edit a selection of consecutive bits as an independent integer. This reduces the need to count bits and convert binary to decimal. Hex Workshop supports 8, 16, 32, and 64 bit bitfields.

 

struct screenchar

{

    unsigned short character : 8;

    unsigned short color : 4;

    unsigned short underline : 1;

    unsigned short blink : 1;

};

 

In the example above, 16 bit value is broken into a 8-bit character, 4 bit color, and 1 bit flags for the underline and blink attributes.

 

Verifying Structure data (#pragma verify)

 

Using the verify #pragma allows users to verify basic pre-conditions on fixed-position structures (sanity checking).  If a verify pre-condition fails the user is alerted with a dialog and asked if they would like to apply the structure.  Using a .zip file LocalFileHeader example above, the user would be presented with the following:

 

 

Checks are only presented for fix-position structures.

 

The Syntax is as follows:

 

#pragma verify <<MATCHTYPE>>(<<VARIABLE>>, <<VALUE>>)

 

MATCHTYPE

Description

match_var_int

Compares a variable against the specified integer value.  8, 16, 32, and 64 bit values are supported.  The value can be declared in either decimal or hex.

 

Examples:

   #pragma verify match_var_int("Signature[0]", "0x50")

   #pragma verify match_var_int("Signature[1]", "0x4B")

   #pragma verify match_var_int("Signature[2]", "0x03")

   #pragma verify match_var_int("Signature[3]", "0x04")

 

   #pragma verify match_var_int("magic", "0xCAFEBABE")

 

match_var_str

Compares a variable against the specified string value.

 

Examples:

   #pragma verify match_var_str("method", "add")

 

 

 

See also Structure Viewer Overview, Adding a Structure, Removing a Structure and Basic Structure Data Types.