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?
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)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With