A binary FLA is a Microsoft compound file, the container that Microsoft specifies in [MS-CFB] and that old Word and Excel documents use too. It works like a small file system: the file is cut into sectors of equal size, tables chain the sectors into streams, and a directory gives each stream a name. This page describes the container as Flash uses it. All numbers are little-endian.
Header
The header is the first 512 bytes. Every FLA examined for this site is version 3, with 512-byte sectors.
| Offset | Size | Field | Value |
|---|---|---|---|
0x00 | 8 | Signature | D0 CF 11 E0 A1 B1 1A E1 |
0x08 | 16 | Header CLSID | All zero. |
0x18 | 2 | Minor version | 0x003E |
0x1A | 2 | Major version | 3 for 512-byte sectors, 4 for 4,096-byte sectors. |
0x1C | 2 | Byte order | 0xFFFE, stored FE FF: little-endian. |
0x1E | 2 | Sector shift | Sectors are 2 to this power bytes: 9 (512) in version 3, 12 (4,096) in version 4. |
0x20 | 2 | Mini sector shift | 6: mini sectors are 64 bytes. |
0x22 | 6 | Reserved | Zero. |
0x28 | 4 | Directory sectors | The number of directory sectors; 0 in version 3, which does not count them. |
0x2C | 4 | FAT sectors | The number of FAT sectors. |
0x30 | 4 | First directory sector | Where the directory’s chain starts. |
0x34 | 4 | Transaction signature | 0. |
0x38 | 4 | Mini stream cutoff | 4,096: streams smaller than this are kept in the mini stream. |
0x3C | 4 | First mini FAT sector | Where the mini FAT’s chain starts, or ENDOFCHAIN. |
0x40 | 4 | Mini FAT sectors | The number of mini FAT sectors. |
0x44 | 4 | First DIFAT sector | Where the chain of DIFAT sectors starts, or ENDOFCHAIN when the header’s own 109 entries are enough. |
0x48 | 4 | DIFAT sectors | The number of DIFAT sectors. |
0x4C | 436 | DIFAT | The sector numbers of the first 109 FAT sectors; unused entries are FFFFFFFF. |
A version 4 header fills a whole 4,096-byte sector, the rest of it zero.
00000000 D0 CF 11 E0 A1 B1 1A E1 00 00 00 00 00 00 00 00
00000010 00 00 00 00 00 00 00 00 3E 00 03 00 FE FF 09 00
00000020 06 00 00 00 00 00 00 00 00 00 00 00 01 00 00 00
00000030 02 00 00 00 00 00 00 00 00 10 00 00 04 00 00 00
00000040 01 00 00 00 FE FF FF FF 00 00 00 00 03 00 00 00
0x3E, major version 3, byte order FFFE, sector shift 9, mini sector shift 6, one FAT sector, the directory at sector 2, cutoff 4,096, the mini FAT at sector 4 (one sector), no DIFAT chain, and the only FAT sector at sector 3In this file, sectors 0 and 1 hold an older directory and an older FAT, both free; see Free sectors.
Sectors
After the header the file is a run of sectors, numbered from 0. Sector n
starts at byte (n + 1) × sector size, so in a version 3 file sector 0 is at
512 and sector 2 at 1,536 (0x600). Sectors can be in any order: a stream’s
sectors need not be next to each other, and FAT, directory and data sectors are mixed
together.
A sector number above 0xFFFFFFFA is not a sector but one of these
values:
| Value | Name | Meaning |
|---|---|---|
0xFFFFFFFA | MAXREGSECT | The highest regular sector number. |
0xFFFFFFFB | – | Reserved. |
0xFFFFFFFC | DIFSECT | In the FAT: this sector is a DIFAT sector. |
0xFFFFFFFD | FATSECT | In the FAT: this sector is a FAT sector. |
0xFFFFFFFE | ENDOFCHAIN | The last sector of a chain; also “none” in the header. |
0xFFFFFFFF | FREESECT | In the FAT: a free sector. |
Some files end part way through their last sector. Those examined were written by a SWF-to-FLA decompiler, and their data is complete: the last stream ends inside the partial sector.
DIFAT
The DIFAT lists the sectors that hold the FAT. Its first 109 entries are in the header,
at 0x4C, which covers a FAT of 109 sectors, enough for a file of about 7
MB with 512-byte sectors. A larger file adds DIFAT sectors, chained from the header’s
first DIFAT sector. Each holds (sector size ÷ 4 − 1) FAT sector numbers, 127 in a
version 3 file, and then the number of the next DIFAT sector, or
ENDOFCHAIN. The FAT marks each DIFAT sector DIFSECT.
FAT
The FAT (file allocation table) is an array of 4-byte sector numbers, one for every
sector in the file, spread over the FAT sectors in the order the DIFAT lists them. A
512-byte FAT sector holds 128 entries. Entry n gives the sector that follows
sector n in its chain, or ENDOFCHAIN if it is the last, or
FREESECT if the sector is not in use. FAT sectors themselves are marked
FATSECT.
To read a chain, start at its first sector, read it, look up its FAT entry for the
next, and repeat until ENDOFCHAIN. The directory, the mini FAT, the mini
stream and every stream of 4,096 bytes or more are chains of this kind.
Mini FAT
Small streams would waste most of a 512-byte sector, so streams below the cutoff of
4,096 bytes are stored in 64-byte mini sectors instead. The mini FAT is to mini sectors
what the FAT is to sectors: one 4-byte entry per mini sector, giving the next mini
sector of its chain, ENDOFCHAIN or FREESECT. The mini FAT
itself is an ordinary chain, starting at the header’s first mini FAT sector; a 512-byte
sector holds 128 entries.
One file examined gives a first mini FAT sector in its header while counting no mini FAT sectors. The explorer follows the chain the header points to.
Mini stream
The mini sectors live inside one ordinary stream, the mini stream, whose first sector and size are the start sector and size of the root entry. Mini sector n is at byte n × 64 of the mini stream. A small stream’s bytes are found by reading the mini stream through the FAT, then taking the stream’s mini sectors from it in the order the mini FAT gives.
Directory
The directory is a chain of 128-byte entries, four to a 512-byte sector, starting at the
header’s first directory sector. Entries are numbered from 0, and entry 0 is the root
storage, named Root Entry.
| Offset | Size | Field | Meaning |
|---|---|---|---|
| 0 | 64 | Name | UTF-16LE, ending with a zero character; at most 31 characters. |
| 64 | 2 | Name length | In bytes, including the zero at the end. |
| 66 | 1 | Object type | 0 unused, 1 storage, 2 stream, 5 root storage. |
| 67 | 1 | Colour | 0 red, 1 black: the entry’s colour in the red-black tree of names. |
| 68 | 4 | Left sibling | Entry number, or NOSTREAM (FFFFFFFF). |
| 72 | 4 | Right sibling | Entry number, or NOSTREAM. |
| 76 | 4 | Child | For a storage, the entry at the top of the tree of what it holds. |
| 80 | 16 | CLSID | A class ID for a storage. Flash sets the root’s to {597CAA70-72AA-11CF-831E-524153480000}. |
| 96 | 4 | State bits | 0 in FLA files. |
| 100 | 8 | Created | A Windows FILETIME; zero for streams. |
| 108 | 8 | Modified | A Windows FILETIME; zero for streams. |
| 116 | 4 | Start sector | The first sector of the stream, or its first mini sector if the stream is below the cutoff. For the root, the first sector of the mini stream. |
| 120 | 8 | Size | The stream’s size in bytes. Version 3 files use only the low 32 bits. |
The entries of a storage form a red-black tree ordered by name, shorter names first and names of the same length compared in upper case. A reader can walk the tree from the storage’s child, or simply read every entry in turn.
The class ID is stored as a Windows GUID: the first three groups little-endian, the
last eight bytes as written. Flash’s comes out as 70 AA 7C 59 AA 72 CF 11 83 1E
52 41 53 48 00 00, whose last bytes read RASH in ASCII.
00000600 52 00 6F 00 6F 00 74 00 20 00 45 00 6E 00 74 00 R.o.o.t. .E.n.t.
00000610 72 00 79 00 00 00 00 00 00 00 00 00 00 00 00 00 r.y.............
…
00000640 16 00 05 00 FF FF FF FF FF FF FF FF 01 00 00 00
00000650 70 AA 7C 59 AA 72 CF 11 83 1E 52 41 53 48 00 00 p.|Y.r....RASH..
00000660 00 00 00 00 00 00 00 00 00 00 00 00 30 7D 22 90
00000670 0E 1E C2 01 13 00 00 00 80 01 00 00 00 00 00 00
Root Entry, a name length of 22 bytes, type 5 (root), red, no siblings, child entry 1, Flash’s class ID, no state bits, no creation time, a modification time, and the mini stream starting at sector 19 (0x13) with 384 bytesStreams
Every stream of an FLA is a child of the root: Flash uses no storages. The streams are
Contents, one Page stream per scene, one Symbol
stream per symbol and one Media stream per imported bitmap or sound; see
Streams and their names. To read one:
- Find its entry in the directory and take its start sector and size.
- If the size is below the cutoff of 4,096 bytes, the start is a mini sector: follow the mini FAT from it, taking each 64-byte mini sector from the mini stream.
- Otherwise follow the FAT from the start sector, taking each 512-byte sector from the file.
- Join the pieces in order and stop at the stream’s size; the rest of the last sector is not part of the stream.
Free sectors
Flash saves incrementally. It writes the streams that changed into new sectors, points
the directory at them and marks the old sectors free in the FAT, but does not clear
them. Flash MX 2004 later added a Save and Compact command that rewrites the whole file
(according to O’Reilly’s Flash Hacks). So the free sectors of a document often hold
earlier versions of its timelines and of Contents, scripts included.
In the Flash MX document above, sectors 0 and 1 are an old directory and an old FAT. In
another Flash MX document, an older on (release) button handler and a frame
script holding #include "Script.as" survive only in free sectors. Some
files also hold sectors that the FAT marks as in use but that no chain reaches.
The explorer marks free and unreached sectors in the tree, and lists any scripts it finds in them separately, as older copies that are not part of the document. See ActionScript in FLA.