Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Multiple variant parts in a record

Tags:

delphi

I'm writing a small tool to do some manipulation of SWF files, using Delphi XE2. So far, I'm simply following the SWF specification, and now I've hit a small problem in implementing a data structure to represent shapes.

SWF shapes contain a number of shape records. Shape records may be edge records or non-edge records, and each of those two types have two additional subtypes.

Specifically, on page 135 of the specification, the two non-edge record types are described; EndShapeRecord and StyleChangeRecord. In the SWF file, the way to differentiate between these is to check if all five flag bits (after TypeFlag) are 0; if they are, it's an EndShapeRecord, otherwise it's a StyleChangeRecord.

To help me process the shape records later on, I would like to unify edge and non-edge records into a single record type, using a variant record. Distinguishing between the different kinds of records is easy enough; a nested variant record allows me to easily to this the edge records apart, and for the non-edge records, I can declare the 5 flags from the StyleChangeRecord and write a function IsEndRecord.

However, in the interest of making my source code reflect the specification as closely as possible, I'd like to go one step further. The presence of the other fields in a StyleChangeRecord are predicated on the values of these 5 flags, so I would like to be able to declare 5 variant records, one per flag, which contain the fields added by each flag. (I realize this will not affect the memory usage in any way, but that's not the point.)

Unfortunately, Delphi doesn't seem to allow more than one variant part per "level", and attempting to define these 5 variant parts at the same level just throws a ton of syntax errors.

TShapeRecord = record
  case EdgeRecord: Boolean of
    False: (
      case StateMoveTo: Boolean of
        True: (
          MoveBits: Byte;
          MoveDeltaX: Int32;
          MoveDeltaY: Int32;
        );
      case StateLineStyle: Boolean of // << Errors start here
        True: (LineStyle: UInt16);
      //Additional flags
    );
    //Fields for edge records
end;

In slightly simpler terms, the goal is to be able to formulate a record like so:

TNonEdgeRecord = record
    case StateMoveTo: Boolean of
      True: (
        MoveBits: Byte;
        MoveDeltaX: Int32;
        MoveDeltaY: Int32;
      );
    case StateLineStyle: Boolean of
      True: (LineStyle: UInt16);
end;

...without removing the variant parts of the record, and without nesting them (since nesting would imply an incorrect relation from a syntactical point of view).

Is there some other way I can declare multiple (non-nested) variant parts in a record, or should I just go back to not using variant records for the inner part?

like image 578
Michael Madsen Avatar asked Oct 31 '11 03:10

Michael Madsen


1 Answers

No. The Borland branch of Pascal only allows variant parts at the end of a record.

Nesting is the only way.

For some interesting examples and observations, see this article by Rudy Velthuis:

http://rvelthuis.de/articles/articles-convert.html (search for the "union" part)

like image 118
Marco van de Voort Avatar answered Oct 27 '22 00:10

Marco van de Voort