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 00 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 01 00 00 00
0x3E, major version 3, byte order FFFE, sector shift 9, mini sector shift 6, one FAT sector, the directory at sector 0, cutoff 4,096, the mini FAT at sector 4 (one sector), no DIFAT chain, and the only FAT sector at sector 1Sectors
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 (0x200) and sector 10 at 5,632 (0x1600). 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.
00000400 05 00 00 00 FD FF FF FF FF FF FF FF FF FF FF FF
00000410 FE FF FF FF FE FF FF FF 08 00 00 00 06 00 00 00
00000420 09 00 00 00 FE FF FF FF 0B 00 00 00 0C 00 00 00
Contents stream starts 10, 11, 12To 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. In the Flash 8 document above the mini
stream is 1,920 bytes in sectors 7, 6, 8 and 9, and its Page 1 stream of
1,311 bytes starts at mini sector 9, byte 576 of the mini stream, which falls 64 bytes
into sector 6.
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. Flash CS4
documents saved again by Flash CS5.5 were seen with a zero class ID, and once with
{B4F235FE-DCA6-4803-B7B2-C25A453C836B}.
00000200 52 00 6F 00 6F 00 74 00 20 00 45 00 6E 00 74 00 R.o.o.t. .E.n.t.
00000210 72 00 79 00 00 00 00 00 00 00 00 00 00 00 00 00 r.y.............
…
00000240 16 00 05 00 FF FF FF FF FF FF FF FF 03 00 00 00
00000250 70 AA 7C 59 AA 72 CF 11 83 1E 52 41 53 48 00 00 p.|Y.r....RASH..
00000260 00 00 00 00 00 00 00 00 00 00 00 00 70 E7 DF 1B
00000270 F4 DC CA 01 07 00 00 00 80 07 00 00 00 00 00 00
00000280 43 00 6F 00 6E 00 74 00 65 00 6E 00 74 00 73 00 C.o.n.t.e.n.t.s.
ContentsStreams
Every stream of an FLA is a child of the root: Flash uses no storages. The streams are
Contents, one stream per scene, one per symbol and one 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 added a Save and Compact command that rewrites the whole file
without them (according to O’Reilly’s Flash Hacks); an ordinary save still leaves them.
So the free sectors of a document often hold earlier versions of its timelines and of
Contents, scripts included.
In the Flash 8 document above, sectors 2 and 3 are free, and an older copy of a
button’s on(release) handler, calling gotoAndStop(2) where
the current one calls _root.gotoAndStop(2), survives in a free sector
further on. 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.