BIFF8 was the first Excel format to store Unicode. To save space, a string whose characters all lie below U+0100 is stored “compressed”, one byte per character (the low byte of each UTF-16 unit); any other string is stored as UTF-16LE, two bytes per character. A flag byte says which. Cell text lives once in the shared string table and cells refer to it by number. Sections refer to [MS-XLS].
String structures
| Structure | Layout | Used in |
|---|---|---|
| ShortXLUnicodeString (2.5.240) | cch (1 byte), flags (1), characters | Sheet names, font names, PtgStr. |
| XLUnicodeString (2.5.294) | cch (2), flags (1), characters | Label, String, Format and many others. |
| XLUnicodeStringNoCch (2.5.296) | flags (1), characters; the count is given elsewhere | Defined names and others. |
| XLUnicodeStringMin2 (2.5.295) | cch (2), then an XLUnicodeStringNoCch only if cch > 0 | Some optional texts. |
| XLUnicodeRichExtendedString (2.5.293) | See below | The SST. |
In the flags byte, bit 0 fHighByte is 0 for one byte per character and
1 for two; the other bits are reserved, except in the rich form.
XLUnicodeRichExtendedString
| Field | Size | Meaning |
|---|---|---|
cch | 2 | Number of characters. |
| flags | 1 | Bit 0 fHighByte; bit 2 fExtSt, phonetic data follows; bit 3 fRichSt, formatting runs follow. |
cRun | 2 | Only if fRichSt: number of formatting runs. |
cbExtRst | 4 | Only if fExtSt: size of the phonetic data. |
rgb | cch or 2 × cch | The characters. |
rgRun | 4 × cRun | Formatting runs (FormatRun): first character index (2) and font index (2). A run starting at the string’s length applies to nothing. |
ExtRst | cbExtRst | Phonetic guide (furigana) data, below. |
ExtRst (2.5.109): 2 reserved bytes (1); cb (2), the
size of what follows; Phs (4): font index (2), then phType in bits 0–1
(0 narrow katakana, 1 wide katakana, 2 hiragana, 3 any) and alcH in bits
2–3 (0 general, 1 left, 2 centre, 3 distributed); RPHSSub: run count (2), character
count (2) and the phonetic text as a UTF-16 string with its own 2-byte length; then
one PhRuns of three signed 2-byte values per run: first phonetic character, first
base character, and number of base characters.
SST (0x00FC)
| Offset | Size | Field | Meaning |
|---|---|---|---|
0 | 4 | cstTotal | How many times strings from the table are used in the workbook. |
4 | 4 | cstUnique | Number of strings in the table. |
8 | varies | rgb | The strings, each an XLUnicodeRichExtendedString; no two are the same. |
A LabelSst cell holds a 0-based index into this list. The SST is in
the globals substream and is nearly always longer than 8,224 bytes, so it carries on
in Continue records.
Strings across Continue records
A string’s fixed fields (cch, flags, cRun,
cbExtRst) are never split. Its characters, runs and phonetic data may be.
When the characters are split, the Continue record’s data starts with a new flags
byte whose bit 0 gives the width of the characters that follow, which may differ from
the first part: a string can begin compressed and continue as UTF-16 or the other way
round. A two-byte character is never split between records. A reader therefore has
to count characters, not bytes, across the boundary (section 2.5.293).
ExtSST (0x00FF)
An index into the SST so a reader can find string n without reading the
ones before it. dsst (2) is the number of strings per bucket, at least 8
and normally cstUnique ÷ 128 + 1; then one ISSTInf (8 bytes) per bucket:
ib (4), the stream offset of the bucket’s first string;
cbOffset (2), its offset within the SST or Continue record that holds it;
2 reserved bytes.
Example
An SST with two strings, “Name” (compressed) and “Größe” (compressed too, since ö and ß are below U+0100), used three times in all:
FC 00 17 00 type 0x00FC, 23 bytes
03 00 00 00 02 00 00 00 cstTotal 3, cstUnique 2
04 00 00 4E 61 6D 65 cch 4, flags 0, "Name"
05 00 00 47 72 F6 DF 65 cch 5, flags 0, "Größe" in Latin-1 bytes
A cell showing “Größe” is then FD 00 0A 00 followed by row, column, XF
and the index 01 00 00 00.