Every Thumbs.db is a Microsoft Compound File, a small file system in one file. Microsoft documents it as MS-CFB, and older Office documents use the same container. All values are little-endian.
Layout
0Header 512 bytes, or 4,096 in version 4512…Sectors numbered from 0; sector n starts at byte (n + 1) × the sector sizevaries
Header
| Offset | Size | Name | Description |
|---|---|---|---|
| 0 | 8 | Signature | D0 CF 11 E0 A1 B1 1A E1 |
| 8 | 16 | Header CLSID | Reserved, zero. |
| 24 | 2 | Minor version | 0x3E when the file follows the specification. |
| 26 | 2 | Major version | 3 or 4. |
| 28 | 2 | Byte order | 0xFFFE, little-endian. |
| 30 | 2 | Sector shift | 9 (512-byte sectors, version 3) or 12 (4,096-byte sectors, version 4). |
| 32 | 2 | Mini sector shift | 6: 64-byte mini sectors. |
| 34 | 6 | Reserved | Zero. |
| 40 | 4 | Directory sectors | 0 in version 3. |
| 44 | 4 | FAT sectors | How many sectors the FAT takes. |
| 48 | 4 | First directory sector | Where the directory starts. |
| 52 | 4 | Transaction signature | Zero. |
| 56 | 4 | Mini stream cutoff | Always 4,096. |
| 60 | 4 | First mini FAT sector | Where the mini FAT starts. |
| 64 | 4 | Mini FAT sectors | How many sectors it takes. |
| 68 | 4 | First DIFAT sector | Where the chain of DIFAT sectors starts. |
| 72 | 4 | DIFAT sectors | How many there are. |
| 76 | 436 | DIFAT | The first 109 FAT sector numbers. |
Sectors
After the header come sectors, each the size the header says. Which structure a sector belongs to comes from following the chains from the header, not from its position; sectors of different streams are often mixed together.
FAT
The file allocation table: a 32-bit entry for each sector, giving the next sector of its chain or a special value.
| Value | Name | Meaning |
|---|---|---|
0xFFFFFFFF | FREESECT | Unused. |
0xFFFFFFFE | ENDOFCHAIN | The end of a chain. |
0xFFFFFFFD | FATSECT | A FAT sector. |
0xFFFFFFFC | DIFSECT | A DIFAT sector. |
DIFAT
The list of where the FAT sectors are: 109 entries in the header, then a chain of DIFAT sectors, each holding FAT sector numbers and, in its last entry, the next DIFAT sector. A small file needs no DIFAT sectors.
Directory
A list of 128-byte entries, the first being the root. Entries form a red-black tree of names.
| Offset | Size | Name | Description |
|---|---|---|---|
| 0 | 64 | Name | UTF-16, zero-terminated, at most 31 characters. |
| 64 | 2 | Name length | In bytes, including the terminator. |
| 66 | 1 | Object type | 0 unused, 1 storage, 2 stream, 5 root storage. |
| 67 | 1 | Colour | 0 red, 1 black. |
| 68 | 4 | Left sibling | An entry number, or 0xFFFFFFFF. |
| 72 | 4 | Right sibling | An entry number, or 0xFFFFFFFF. |
| 76 | 4 | Child | The tree of what a storage holds. |
| 80 | 16 | CLSID | A class ID for a storage. |
| 96 | 4 | State bits | Flags an application may set. |
| 100 | 8 | Created | FILETIME; zero for streams. |
| 108 | 8 | Modified | FILETIME; zero for streams. |
| 116 | 4 | Start sector | The first sector of a stream. For the root, the first sector of the mini stream. |
| 120 | 8 | Stream size | In bytes. |
Mini FAT
A FAT for mini sectors: one 32-bit entry for each, in the same form as the FAT.
Mini stream
Streams smaller than 4,096 bytes are kept in the mini stream, in mini sectors of 64 bytes. The mini stream is itself stored in ordinary sectors, on the root entry’s chain. Most thumbnails are small enough to live here.
Streams
Each stream is a chain of sectors, or mini sectors when it is below the cutoff. A reader joins them in chain order. Only the bytes up to the size in the directory entry belong to the stream; the rest of the last sector is slack. Since streams can be scattered, a thumbnail may need putting together before it can be shown.
Free sectors
Sectors marked FREESECT, and sectors no chain reaches, can still hold old
data. In a Thumbs.db that can include thumbnails from earlier saves.