The cross-reference table is the index of a PDF 1.0 to 1.4 file. For every object number it gives the byte offset at which the object starts, or says that the number is free. It is plain text, with lines of a fixed length, so a reader can find any entry without reading the others. The trailer that follows it tells the reader where the document starts. In these versions the table is the only way a file is indexed: every object is at a known offset of its own.
The table
A cross-reference section starts with the keyword xref alone on a
line. Then come one or more subsections, then the trailer. The first section of a
new file has one subsection, from object 0 to the last object:
xref
0 6
0000000003 65535 f
0000000017 00000 n
0000000081 00000 n
0000000000 00007 f
0000000331 00000 n
0000000409 00000 n
Subsections
Each subsection starts with a line of two integers: the first object number and the number of entries. The entries follow, one for each object number in turn. A section can have any number of subsections, and an incremental update usually has several, because it lists only the objects it changes:
xref
0 1
0000000000 65535 f
3 1
0000025325 00000 n
23 2
0000025518 00002 n
0000025635 00000 n
30 1
0000025777 00000 n
Subsections need not be in order of object number, and they should not overlap. Every section should include object 0.
Entries
Every entry is exactly 20 bytes, including its line end:
| Bytes | Field | In-use entry | Free entry |
|---|---|---|---|
| 0–9 | 10 digits | The byte offset of the object, from the start of the file | The object number of the next free object |
| 10 | space | 20 | |
| 11–15 | 5 digits | The generation number | The generation number to use if the object number is used again |
| 16 | space | 20 | |
| 17 | keyword | n | f |
| 18–19 | line end | Two bytes: space and CR, space and LF, or CR and LF | |
Numbers are padded with leading zeros. The offset is to the first digit of the
object’s n g obj line. The entry for object n in a subsection
that starts at object s is at 20 × (n − s) bytes after the
subsection’s header line.
The line end must be two bytes. A writer that ends entries with a single LF makes
entries of 19 bytes, which many readers accept by reading the table line by line
instead of by position. A reader should check that the offset really holds
n g obj before trusting an entry.
In the small PDF 1.3 file on the File
structure page, the fifth entry, 0000000022 00000 n, is object 4:
the first subsection starts at 0, and the entry says the object begins at byte 22,
just after the header and the binary comment.
The free list and generation numbers
Free entries form a linked list. Object 0 is always free, with generation 65,535,
and is the head of the list: its offset field holds the number of the first free
object, that entry holds the next, and so on. The last free entry points back at
object 0. In a new file with no free objects, object 0 points at itself:
0000000000 65535 f.
In the first example above, object 0 points at 3 and object 3 points back at 0.
Object 3’s generation is 7: it was used and freed before, and if the number is used
again the new object will be 3 7 obj.
- When an object is deleted in an update, its entry becomes free and its generation number goes up by one.
- A free entry with generation 65,535 must never be used again.
- A reference to a free object, or to a number beyond the table, is a reference to the null object.
Many writers do not keep the list linked and write every free entry as
0000000000 65535 f, or point the last one nowhere. Readers do not need
the list to read the file; it matters only to a program that adds objects.
The trailer
After the last subsection come the keyword trailer and a dictionary:
trailer
<< /Size 22
/Root 2 0 R
/Info 1 0 R
/ID [ <81b14aafa313db63dbd6f981e49f94f4> <81b14aafa313db63dbd6f981e49f94f4> ]
>>
startxref
18799
%%EOF
| Key | Type | Since | Meaning |
|---|---|---|---|
Size | integer | 1.0 | Required. The total number of entries in the file’s table, counting every section: one more than the highest object number. In an update’s trailer it is for the whole file, not the update |
Prev | integer | 1.0 | Present only if the file has more than one section: the byte offset of the previous section’s xref |
Root | reference | 1.0 | Required. The document catalog, which must be an indirect object |
Encrypt | dictionary | 1.1 | Required if the file is encrypted: the encryption dictionary, often as a reference |
Info | reference | 1.0 | The document information dictionary, an indirect object |
ID | array of two strings | 1.1 | The file identifier; required if Encrypt is present, recommended otherwise |
The trailer is not encrypted, even in an encrypted file, and its strings are written as they are.
The file identifier
ID holds two byte strings, usually 16 bytes each. The first is set
when the file is first made and never changes; the second is changed each time the
file is saved again. Together they let a program tell whether two files are the
same document and whether one is a later version. The references suggest making
them from an MD5 digest of the time, the file’s location and size, and the
Info values. The first string is also an input to the
encryption key.
startxref
After the trailer comes startxref, a line with the byte offset of the
xref keyword of the last section in the file, and %%EOF.
A reader reads the file from here: it finds %%EOF near the end,
reads the offset, and parses the section and trailer at that offset.
When there are several sections, it then follows Prev from trailer
to trailer. Entries from later sections replace earlier ones for the same object
number, so a reader reads the newest section first and keeps the first entry it
sees for each object. The Root, Info and
Encrypt of the newest trailer are the ones that count.
xref ← offset 0 of section 1
…
trailer << /Size 22 /Root 2 0 R >>
startxref 18799 %%EOF
… objects of the update …
xref ← offset 25100, section 2
…
trailer << /Size 24 /Root 2 0 R /Prev 18799 >>
startxref
25100
%%EOF
startxref points at the newest section, whose Prev points at the firstA reader should guard against a Prev chain that loops, and against
offsets beyond the end of the file.
When the table is wrong
Files with a damaged or missing table are common: cut short in a download, edited
by hand, or joined from parts. Readers then usually rebuild the index by scanning
the whole file for lines of the form n g obj, keeping the last copy of
each object number, and by finding the last trailer dictionary. This
repair is behaviour of readers, not part of the format, and a file that needs it
may show differently in different programs.