How to skip a specific number of words and highlight the target location using a script or template?

Hi - I am new to 010 editor scripts and templates so please bear with me!

I am currently analyzing (i.e. reverse-engineering) a pretty complex file format. This format uses lots of “type“ “length“ “data…” - structures, i.e. the file is - at least in parts - a sequence of sections structured like “typeA“ “lengthA“ “data of lengthA here…” “typeB“ “lengthB“ “data of lengthB here…”. etc. The file format is 16-bit oriented. type-tags, length and data/payload are in 16-bit words (i.e. 2 bytes each in Little-Endian format).
While the total file length can be >64kB, the individual data sections are limited to 64K (much less actually), so the fact that lengths are 16 bit-values only is not an issue.

My “wish“ is as follows: While analzying this it would be very helpful, if I could hover over a length-word, run a command and it would somehow mark or highlight the subsequent -word. WIth this is would be much easier, quicker and less error-prone to step through those files instead of manually counting words.

Is that (easily) doable using a 010-script or -template?

There are some details to observe, e.g. the length-value includes the length word itself (i.e. the minimum length is 2 (just a length without data), the data’s actual length is thus length-2), but I guess these are details that can be tweaked once the basic mechanism exists.

I would very much appreciate if some kind soul could sketch out how to achieve that using a 010 template!

Nevermind - I asked Google Gemini and it generated me a suitable script:

int64 pos = GetCursorPos();

// Read 16-bit length at current cursor (Little Endian):
ushort nrWords = ReadShort(pos); 

if (nrWords < 2) {
    Warning("Invalid length word (%d) at offset 0x%LX", nrWords, pos);
} else {
    // 1 word = 2 bytes
    // Payload size = (len_words - 1) * 2 bytes
    int64 payloadBytes = (int64)(nrWords - 1) * 2; 
    
    // Set selection starting right AFTER the length word
    SetSelection(pos, payloadBytes);
}

010Editor allows you to describe your data as C variables etc. Without a sample of your data I can only guess.

// To hold this structure (little endian, type 1, length 3 bytes, data “123”)
// 00 01 00 03 31 32 33

// e.g.
typedef struct _record {
uint16 iType;
uint16 iLen;
byte cData[iLen];
};

LittleEndian();
FSeek(… put your file offset here);

// Create an array of items based on the _record format
_record aItem[1] <optimize=false>;

or for a more complete example, including source file:

==========================

/* Test file:

Test file (big endian):

10 20 30 40 50 60 70 80 00 02 00 02 00 03 00 01
00 05 30 31 32 33 34 00 02 00 0C 31 32 33 34 35
36 37 38 39 30 41 42 00 03 00 04 31 32 33 34 00
02 00 03 00 50 00 07 31 32 33 34 35 36 37 00 FF
00 02 31 32 00 FE 00 03 31 32 33 00 00 00 00 00

Test file (little endian):

10 20 30 40 50 60 70 80 02 00 02 00 03 00 01 00
05 00 30 31 32 33 34 02 00 0C 00 31 32 33 34 35
36 37 38 39 30 41 42 03 00 04 00 31 32 33 34 02
00 03 00 50 00 07 00 31 32 33 34 35 36 37 FF 00
02 00 31 32 FE 00 03 00 31 32 33 00 00 00 00 00

*/

// If you omit the colourisation in <> it will use the default

// Load the header (signature + numSections)
typedef struct _header {
byte signature[8] <format=hex,fgcolor=cLtRed>;
uint16 iSections <fgcolor=cLtYellow>;
};

// Record entry
typedef struct _triplet {
uint16 iType <bgcolor=cLtBlue,fgcolor=cWhite>;
uint16 iLen <bgcolor=cDkRed,fgcolor=cWhite>;
byte cData[iLen] <bgcolor=cLtYellow, fgcolor=cBlack>;
};

// Define a section (type, num Rec, array of recs)
typedef struct _section {
uint16 iType;
uint16 iRecs;
_triplet aItems[iRecs] <optimize=false>;
};

// uint16 are in BigEndian format
BigEndian();

_header stHeader;
_section stSections[stHeader.iSections] <optimize=false>;