A KF8 book is compiled from an EPUB-like source: XHTML files, CSS, SVG, images and
fonts. KindleGen joins all the text-like parts into one long UTF-8 string, compresses it
into the text records, and records how to cut it apart again in a flow table and two
indexes. Links between files become kindle: URLs. Amazon has not published
any of this; it follows KindleUnpack and calibre.
Text records
The text records follow record 0, as many as the PalmDOC header says. They work
exactly as in MOBI: each holds up to
4,096 bytes of text once decompressed, compressed with PalmDOC LZ77 (type 2), or rarely
not at all or with HUFF/CDIC; trailing entries named by
extraDataFlags must be removed from the end of each record first. Joined,
they give the raw text, textLength bytes long.
FDST: the flow table
The raw text is a series of flows, one after another. Flow 0 is all the book’s XHTML;
each further flow is one style sheet or SVG image. The FDST record, found
through the MOBI header’s fdstRecord, gives where each flow starts and
ends.
| Offset | Size | Type | Name | Description |
|---|---|---|---|---|
0 | 4 | char[4] | identifier | FDST. |
4 | 4 | UInt32 | tableOffset | Where the table starts in this record: 12. |
8 | 4 | UInt32 | flowCount | The number of flows; the same as the MOBI header’s fdstFlowCount. |
12 | 8 × n | UInt32 pairs | flows | For each flow, its start and end offsets in the raw text. The first starts at 0 and the last ends at textLength. |
When the header’s flow count is 1 or less, there is no FDST and the whole text is
flow 0. A flow’s type is not stored; readers recognise it from its content (an
<svg element, or CSS) and from the MIME type given in the
kindle:flow links that point to it.
Skeletons and fragments
Flow 0 does not hold the XHTML files as they were. Each file is split into a
skeleton, the file’s outer markup (the XML declaration,
html, head, body and so on) with the body’s
content taken out, and one or more fragments (also called chunks or
divs), the pieces of content that go into the skeleton. Flow 0 holds, for each file in
turn, its skeleton followed directly by its fragments.
The skeleton index gives, for each file, the skeleton’s start and length in flow 0 and how many fragments follow. The fragment index gives, for each fragment in order, its insert position, its file number, a sequence number, and its start and length. To rebuild file k:
- Take the skeleton’s bytes from flow 0.
- For each of its fragments, in order: take the fragment’s bytes, which follow the skeleton in flow 0, and insert them into the skeleton at the fragment’s insert position, minus the skeleton’s start in flow 0. The insert position counts in the text as it is built, so earlier fragments move later ones along.
- The result is the original XHTML file, apart from the attributes KindleGen added.
Splitting lets a Kindle load one part of a long chapter without reading the whole
file. KindleUnpack names the rebuilt files part0000.xhtml,
part0001.xhtml and so on, since the original names are not kept.
The aid attribute
KindleGen gives many elements an aid attribute holding a short base-32
number, unique in the book, such as <p aid="1A">. Fragment
boundaries fall at elements with an aid, and the fragment index refers to
them through CSS-like selectors such as P-//*[@aid='1A'], stored in the
index’s CNCX strings. Readers strip the attributes or turn the ones that are link
targets into ids. calibre writes cid in the same way.
kindle: links
All references in the text are rewritten to kindle: URLs. The numbers in
them are written in base 32 with the digits 0–9 and
A–V (upper case), padded with leading zeros.
| Form | Used for | Meaning |
|---|---|---|
kindle:pos:fid:XXXX:off:YYYYYYYYYY | Links between parts of the book (href) | XXXX is a fragment number from the fragment index (4 digits); YYYYYYYYYY is an offset from that fragment’s insert position (10 digits). The target is the element that starts at, or contains, that point; readers search back from it for the nearest id, name or aid. |
kindle:embed:XXXX | Images and fonts (src, xlink:href, CSS url()) | XXXX is a resource number counting from 1 at the MOBI header’s firstResourceRecord. An optional ?mime=image/jpeg or similar may follow. |
kindle:flow:XXXX?mime=type/subtype | Style sheets and SVG (link href, img src) | XXXX is a flow number from the FDST; the MIME type, such as text/css or image/svg+xml, says what the flow is. |
Example
<link href="kindle:flow:0001?mime=text/css" rel="stylesheet" type="text/css"/>
<img src="kindle:embed:0003?mime=image/jpeg"/>
<a href="kindle:pos:fid:000B:off:0000000040">Chapter 2</a>
- Flow 1 is a style sheet.
- The image is resource 3: record
firstResourceRecord+ 2. - The link goes to fragment 11 (
B), 128 bytes (40= 4 × 32) after its insert position.
What the XHTML may contain
KF8 supports most of HTML5 and a large part of CSS 3, including embedded fonts,
@media amzn-kf8 and @media amzn-mobi queries that pick rules
for KF8 or old MOBI readers, and the fixed-layout settings of the source OPF, which
end up in EXTH 122 to 128. Amazon’s Kindle Publishing Guidelines list what is
supported; the format itself does not restrict the markup.