How can I create a dynamic array (ie length is based on recognising a terminator)?

I am reading a file that contains a dynamic array (length defined by a terminator) of variable length data structures, and I want the last element of the array to be marked as such in the template viewer. The data structure I’m reading is a bit more complicated but I came up with this as an example:

typedef enum <uint> { False, True} bool

int getTNameArraySize(){
    local int64 pos = FTell()
    local count = 0;	
    do {
        len = ReadUInt(pos)
        pos += len * sizeof(wchar_t) + sizeof(uint32);
        count++;
    } while(len > 0)
    return count;
}	

typedef struct {
    uint32    len;
    if(len == 0) {
        wchar_t  name = "EOF";                // Don't read any data
        bool     lastElement = True;
    }
    else {
        wchar_t  name[len]                          // Read len UTF-16 characters
        bool     lastElement = False;
    }
} TName;
 
TName names[getTNameArraySize()];

This code has a number of problems that mean it doesn’t/can’t work how should I approach it?

The array name[len] doesn’t ends up being the size of the first string.

You are not allowed to assign values to template variables, so I can’t set the name to EOF if it’s the last empty element. Is there any way round this?

I think I could make lastElement a local variable and then turn on local variables. Can I do it just for this one? I don’t want to see all ‘len’ for example?

This code ends up reading the data twice, is there any way round that so that the array ends with its size the way a string does? I could be dealing with a pretty big array.

Is there a “right” way to approach this?

Thanks

You can read the data in a single pass by rearranging your code. For example:

typedef enum <uint> { False, True} bool;

typedef struct {
    uint32    len;
    if( len > 0)
        wchar_t  name[len];                          // Read len UTF-16 characters
} TName <read=(len == 0 ? "EOF" : name)>;

do { 
	TName names;
} while( names.len > 0 );	

This code uses a custom <read> attribute to return EOF when the length is zero. It also builds the array using a while loop and a duplicate-array. In your original code you probably wanted to define lastElement as local but that is not needed in this code. Let us know if you have any questions on this.

Graeme
SweetScape Software

1 Like

Thank you, that’s great. I hadn’t realised one could create an array with a loop by just repeating the name.

Is there some way to make the EOF appear in a different colour? I tried adding <fgcolor=cRed> immediately after the “EOF” but that didn’t work.

To answer my own question: Yes by putting it in the right place.

typedef struct {
    uint32  len;
    if( len > 0)
        wchar_t  name[len];                          // Read len UTF-16 characters
} TName <read=(len == 0 ? “EOF” : name), fgcolor=(len == 0 ? cRed : cNone)>;

I also realised that some of what wasn’t working was fixed by setting <optimise=false>.

So if I use ‘Show Local Variables’ it will show local variables that are declared outside functions and then I can use <hidden=true> to hide any I don’t want to show up. That should allow me do something like the lastElement flag but you’re right it’s redundant in this case.

That also answers another question, I was trying to figure out how to make the object show it’s value as a string when not expanded.