Assign value to struct member during creation

typedef base128uint ReadUintBase128();

typedef struct
{
    uint8 flags;
    uint32 tag;
    base128uint origLength;
    base128uint transformLength;
} tableDirectoryEntry <optimize=false>;

uint32 ReadUIntBase128()
{
    local uint32 accum = 0;
    local uint16 i = 0;

    for (i = 0; i < 5; i++) {
        local uint8 data_byte = ReadByte();

        // No leading 0's
        if (i == 0 && data_byte == 0x80) return 0;

        // If any of top 7 bits are set then << 7 would overflow
        if (accum & 0xFE000000) return 0;

        accum = (accum << 7) | (data_byte & 0x7F);

        // Spin until most significant bit of data byte is false
        if ((data_byte & 0x80) == 0) {
            return accum;
        }
    }
    // UIntBase128 sequence exceeds 5 bytes
    return 0;
}

The above code will, of course, not run but I hope it’s complete enough to illustrate what I am trying to accomplish. Is there any way for struct members to be the result of a calculation without using local?

Is base128uint always 5 bytes or is it variable-sized?

Graeme
SweetScape Software

It’s variable size. It was implemented as a way to save space in the WOFF2 file.

For a variable sized array it would be easiest to define base123uint as a struct, then use one function to figure out how many bytes are in the array and another function to convert the datatype to a string. For example:

typedef struct {
    uint8 data[ CalculateUIntBase128Size() ];
} base128uint <read=ReadUIntBase128>;

typedef struct
{
    uint8 flags;
    uint32 tag;
    base128uint origLength;
    base128uint transformLength;
} tableDirectoryEntry <optimize=false>;

uint32 CalculateUIntBase128Size()
{
    local int64 pos = FTell();
    local int32 i;
    local uint8 data_byte;
    for( i = 0; i < 5; i++ )
    {
        data_byte = ReadUByte( pos+i );
        if ((data_byte & 0x80) == 0) 
        {
            i = i + 1;
            break;   
        }
    }    
    return i;
}

string ReadUIntBase128( base128uint &num )
{
    local uint32 accum = 0;
    local uint16 i = 0;
    local uint32 count = sizeof(num.data);
    local uint8 data_byte;

    for (i = 0; i < count; i++) {
        data_byte = num.data[i];

        // No leading 0's
        if (i == 0 && data_byte == 0x80) return "0";

        // If any of top 7 bits are set then << 7 would overflow
        if (accum & 0xFE000000) return "ERROR";

        accum = (accum << 7) | (data_byte & 0x7F);

        // Spin until most significant bit of data byte is false
        if ((data_byte & 0x80) == 0) {
            return Str( "%u", accum );
        }
    }
    // UIntBase128 sequence exceeds 5 bytes
    return "OVERFLOW";
}

We weren’t sure how the logic in the ‘CalculateUIntBase128Size’ function should work and you would have to fix that up. Let us know if you have any questions on this. Cheers!

Graeme
SweetScape Software