FileMagic - Must be equal to "MicrosoftC/C++MSF7.00\\r\\n"
followed by the bytes 1A4453000000.

BlockSize - The block size of the internal file system. Valid values are
512, 1024, 2048, and 4096 bytes. Certain aspects of the MSF file layout vary
depending on the block sizes. For the purposes of LLVM, we handle only block
sizes of 4KiB, and all further discussion assumes a block size of 4KiB.

FreeBlockMapBlock - The index of a block within the file, at which begins
a bitfield representing the set of all blocks within the file which are “free”
(i.e. the data within that block is not used). This bitfield is spread across
the MSF file at BlockSize intervals.
Important: FreeBlockMapBlock can only be 1 or 2! This field
is designed to support incremental and atomic updates of the underlying MSF
file. While writing to an MSF file, if the value of this field is 1, you
can write your new modified bitfield to page 2, and vice versa. Only when
you commit the file to disk do you need to swap the value in the SuperBlock
to point to the new FreeBlockMapBlock.

NumBlocks - The total number of blocks in the file. NumBlocks*BlockSize
should equal the size of the file on disk.

NumDirectoryBytes - The size of the stream directory, in bytes. The stream
directory contains information about each stream’s size and the set of blocks
that it occupies. It will be described in more detail later.

BlockMapAddr - The index of a block within the MSF file. At this block is
an array of ulittle32_t‘s listing the blocks that the stream directory
resides on. For large MSF files, the stream directory (which describes the
block layout of each stream) may not fit entirely on a single block. As a
result, this extra layer of indirection is introduced, whereby this block
contains the list of blocks that the stream directory occupies, and the stream
directory itself can be stitched together accordingly. The number of
ulittle32_t‘s in this array is given by ceil(NumDirectoryBytes/BlockSize).

As may be clear by now, it is possible for a single field (whether it be a high
level record, a long string field, or even a single uint16) to begin and
end in separate blocks. For example, if the block size is 4096 bytes, and a
uint16 field begins at the last byte of the current block, then it would
need to end on the first byte of the next block. Since blocks are not
necessarily contiguously laid out in the file, this means that both the consumer
and the producer of an MSF file must be prepared to split data apart
accordingly. In the aforementioned example, the high byte of the uint16
would be written to the last byte of block N, and the low byte would be written
to the first byte of block N+1, which could be tens of thousands of bytes later
(or even earlier!) in the file, depending on what the stream directory says.