WordPerfect 4.2 for DOS (1986) and the versions before it save a document as a plain
stream: ASCII text with function codes in between, no header, no code for the start or
end of the file and no end-of-file ^Z. This page follows WordPerfect
Corporation’s own document “WordPerfect File Information, Version 4.2” (1986), which
gives every code in octal; the hexadecimal values are shown here as well. Notes from
libwpd, which reads these files, are marked as such.
Byte ranges
| Bytes | Meaning |
|---|---|
0x00–0x1F | Control characters; see below. |
0x20–0x7F | ASCII text. |
0x80–0xBF (octal 200–277) | Single-byte functions. |
0xC0–0xF8 (octal 300–370) | Multiple-byte functions: the code, data, then the code again (the “open gate” and “closing gate”). |
0xFF (octal 377) | Separator inside variable-length functions; never a function on its own. |
| Byte | Meaning |
|---|---|
0x09 | Tab |
0x0A | Hard new line (hard return) |
0x0B | Soft new page |
0x0C | Hard new page |
0x0D | Soft new line (a wrapped line) |
In secondary merge files the end of a field is ^R (0x12)
and a hard return; the document names the end-of-record character too, but it is
lost from the published text. There is no start-of-field or start-of-record code.
Single-byte functions
| Hex | Octal | Function | Hex | Octal | Function |
|---|---|---|---|---|---|
80 | 200 | No-op (always deleted) | A0 | 240 | Hard space |
81 | 201 | Right justification on | A1 | 241 | Do subtotal |
82 | 202 | Right justification off | A2 | 242 | Subtotal entry |
83 | 203 | End of centred text | A3 | 243 | Do total |
84 | 204 | End of aligned or flush-right text | A4 | 244 | Total entry |
85 | 205 | Temporary start point for a maths calculation | A5 | 245 | Do grand total |
86 | 206 | Centre page top to bottom | A6 | 246 | Maths calculation column |
87 | 207 | Begin column mode | A7 | 247 | Begin maths mode |
88 | 210 | End column mode (at top of page) | A8 | 250 | End maths mode |
89 | 211 | Tab after the right margin | A9 | 251 | Hard hyphen in a line |
8A | 212 | Widow/orphan protection on | AA | 252 | Hard hyphen at end of line |
8B | 213 | Widow/orphan protection off | AB | 253 | Hard hyphen at end of page |
8C | 214 | Hard end of line and soft end of page | AC | 254 | Soft hyphen |
8D | 215 | Footnote number (only inside footnotes) | AD | 255 | Soft hyphen at end of line |
8E, 8F | 216, 217 | Reserved | AE | 256 | Soft hyphen at end of page |
90 | 220 | Redline on | AF | 257 | End of text columns and end of line |
91 | 221 | Redline off | B0 | 260 | End of text columns and end of page |
92 | 222 | Strikeout on | B1 | 261 | Negative number (N) in maths mode |
93 | 223 | Strikeout off | B2 | 262 | Italics on (not in the IBM PC version) |
94 | 224 | Underline on | B3 | 263 | Italics off (not in the IBM PC version) |
95 | 225 | Underline off | B4 | 264 | Shadow on (not in the IBM PC version) |
96 | 226 | Reverse video on (reserved) | B5 | 265 | Shadow off (not in the IBM PC version) |
97 | 227 | Reverse video off (reserved) | B6 | 266 | Outline on (not in the IBM PC version) |
98 | 230 | Table of contents placeholder | B7 | 267 | Outline off (not in the IBM PC version) |
99 | 231 | Overstrike | BC | 274 | Superscript |
9A | 232 | Cancel hyphenation of the following word | BD | 275 | Subscript |
9B | 233 | End of generated text | BE | 276 | Advance ½ line up |
9C | 234 | Bold off | BF | 277 | Advance ½ line down |
9D | 235 | Bold on | |||
9E | 236 | Hyphenation off | |||
9F | 237 | Hyphenation on |
0xB8 to 0xBB (octal 270–273) are not listed in the
document. Spelling and grammar checkers need to allow for the hyphen codes
A9–AE and the hard space A0.
Multiple-byte functions
A multiple-byte function is its code, its data and the code again. The length column is the whole function, both codes included; −1 means variable length, and a reader must scan for the closing code. Where data holds an “old value”, a writer may put zero; WordPerfect updates it. Margins and column positions are in character columns.
| Hex | Octal | Length | Function | Data between the codes |
|---|---|---|---|---|
C0 | 300 | 6 | Margin reset | old left, old right, new left, new right margin |
C1 | 301 | 4 | Spacing reset | old spacing, new spacing, in half lines |
C2 | 302 | 3 | Left margin release | number of spaces to go left |
C3 | 303 | 5 | Centre the following text | type (0 between margins, 1 round the current column), centre column, starting column; the text follows and ends with 83 |
C4 | 304 | 5 | Align or flush right | align character, align column, starting column; text follows, ends with 84. Align character 12 (octal, a new line) means flush right and the column is the right margin; otherwise the column is the next tab stop. High bit of the character set: with dot leader |
C5 | 305 | 6 | Reset hyphenation zone | old left, old right, new left, new right zone |
C6 | 306 | 4 | Page number position | old, new code: 0 none, 1 top left, 2 top centre, 3 top right, 4 top left and right, 5 bottom left, 6 bottom centre, 7 bottom right, 8 bottom left and right |
C7 | 307 | 6 | Set page number | old high, old low, new high, new low byte; low 15 bits are the number, high bit set means Roman numerals |
C8 | 310 | 8 | Page number column positions | old left, centre, right; new left, centre, right |
C9 | 311 | 42 | Set tabs (2.2–4.1; 4.2 uses F1) | old and new tab tables, 20 bytes each: one bit per column, bits 0–159 |
CA | 312 | 3 | Conditional end of page | number of single-spaced lines not to break |
CB | 313 | 6 | Pitch and/or font | old pitch, old font, new pitch, new font; a negative pitch is proportional |
CC | 314 | 4 | Temporary margin (indent) | old, new temporary margin |
CD | 315 | 3 | End of temporary margin (before 2.2) | temporary margin |
CE | 316 | 4 | Top margin | old, new, in half lines |
CF | 317 | 3 | Suppress page characteristics | flags, octal: 1 all, 2 page numbers, 4 page number to bottom, 10 all headers, 20 header A, 40 header B, 100 footer A, 200 footer B |
D0 | 320 | 6 | Form length | old form length, old text lines, new form length, new text lines; form length in 6-lines-per-inch lines, text lines in half lines |
D1 | 321 | −1 | Header or footer | see below |
D2 | 322 | −1 | Footnote (2.2–3.0; 4.0 on uses E2) | note number, half lines, FF, left margin, right margin, text |
D3 | 323 | 4 | Set footnote number (2.2–3.0; 4.0 on uses E4) | old, new number |
D4 | 324 | 4 | Advance to half-line number | old line, line to advance to |
D5 | 325 | 4 | Lines per inch | old, new code (only 6 or 8 lines per inch) |
D6 | 326 | 6 | Extended tabs | old start, old increment, new start, new increment; start at least column 160 |
D7 | 327 | −1 | Define maths columns | old column definition (24 bytes), four old calculations each ending with 0, FF, then the new definition and calculations |
D8 | 330 | 4 | Alignment character | old, new character |
D9 | 331 | 4 | Left margin release columns (2.2–3.0 only) | old, new number |
DA | 332 | 4 | Underline mode | old, new: 0 normal, 1 double, 2 single continuous, 3 double continuous |
DB | 333 | 4 | Sheet feeder bin | old, new bin number minus one |
DC | 334 | −1 | End of page (written by WordPerfect; changes with each version) | half lines at end of page (low 7 bits, high 7 bits), half lines for footnotes, pages for footnotes, footnotes on the page, conditional-end-of-page flag, suppress code; after the last column on a page, 23 more bytes (half lines of columns 1–23 and the line where columns start, 0 if none) |
DD | 335 | 24 | Define columns (2.2–4.1; 4.2 uses F3) | old count, five left/right pairs, new count, five pairs; count’s low 7 bits the number, high bit parallel columns |
DE | 336 | 4 | End of temporary margin | old left, old right temporary margin |
DF | 337 | −1 | Invisible characters (printer command) | 7-bit text; a character of octal 277 or more is written as 277 then the character minus 277 |
E0 | 340 | 4 | Left and right temporary margin | before 4.0: new right, new left; 4.0: 0 and the difference between old and new left margin (the document prints the opening code as 240, a slip) |
E1 | 341 | 3 | Extended character | one character |
E2 | 342 | −1 | Footnote or endnote (4.0 on) | see below |
E3 | 343 | 150 | Footnote options | old and new values, 74 bytes each; see below |
E4 | 344 | 6 | Set footnote number (4.0 on) | old high, old low, new high, new low: 14-bit numbers in two 7-bit bytes, high first |
E5 | 345 | 23 | Paragraph number definition (2.2–4.1; 4.2 uses EE) | old 7 level numbers, old 7 definition bytes, new 7 definition bytes |
E6 | 346 | 11 | Paragraph number (2.2–4.1; 4.2 uses EF) | new level (0 first), definition byte, old 7 numbers |
E7 | 347 | 3 | Begin marked text | definition/information byte; text follows, ended by E8 |
E8 | 350 | 3 | End marked text | definition/information byte |
E9 | 351 | −1 | Define marked text | definition/information byte, 5 definition bytes, concordance file name; see below |
EA | 352 | −1 | Index mark | heading, 0, subheading |
EB | 353 | 32 (the document); variable (libwpd) | Date or time | a 30-byte null-terminated format string. libwpd notes that the stated length of 32 is wrong in practice and scans for the closing code |
EC | 354 | 4 | Block protect | 0 on or 1 off, number of half lines in the block |
ED | 355 | −1 | Table of authorities entry | section number (0–15; 32 means short form only), 0, short form, 0, full form |
EE | 356 | 44 | Paragraph number definition (new) | old 7 level numbers (16-bit words), old 7 definition bytes, new 7 definition bytes, 7 starting numbers (words) |
EF | 357 | 18 | Paragraph number (new) | new level (0 first), definition byte, old 7 numbers (words) |
F0 | 360 | 6 | Line numbering | old interval, old position, new interval, new position; interval byte: bit 7 numbering on, bit 6 count text lines only, bit 5 restart each page, bits 0–4 interval 0–30; position in tenths of an inch from the paper’s left edge to the number’s right edge |
F1 | 361 | 106 | Tab reset | see below |
F2 | 362 | −1 | Comment or document summary | definition byte (bit 0: 0 comment, 1 summary), old cursor value, number of lines, 0, text. A summary’s text is creation date, author, typist and comments, each ended by a hard return |
F3 | 363 | 100 | Define columns | old count, 24 left/right pairs, new count, 24 pairs; count’s high bit means parallel |
F4 | 364 | 4 | Point size (not in the IBM PC version) | old, new size in points |
F5 | 365 | −1 | Picture | for the Macintosh: an 8-byte rectangle, a 4-byte type (PICT), a 2-byte identifier; the rest was undecided when the document was written |
F6 | 366 | 5 | Different character when hyphenated | definition byte (bit 0: hyphenation happens next to the function; bit 1: the function comes before the hyphen), character shown in the line, character shown when hyphenated (null shows nothing) |
F7 | 367 | −1 | Leading (Macintosh) | not described |
F8 | 370 | −1 | Kerning adjustment (Macintosh) | not described |
The document lists no codes above F8. libwpd treats
F9–FE as variable length.
Footnotes and endnotes
E2 def a b c d old-footnote-lines lines-page-1 … lines-page-n pages FF left right text… E2
Definition byte: bit 0 is 0 for numbers, 1 for characters; bit 1 is 0 for a
footnote, 1 for an endnote. With numbers, a b is the note number; with
characters, a is how many and b the character.
c d is the note’s number of lines. Both pairs are 14-bit numbers in two
7-bit bytes, high first. An endnote has only a null between d and
FF.
The 74 bytes of footnote options (E3), counted from 1:
| Byte | Meaning |
|---|---|
| 1 | Spacing in footnotes |
| 2 | Spacing between footnotes |
| 3 | Lines to keep together |
| 4 | Flags: n (1 numbering restarts each page); ft and en (footnotes, endnotes: 0 numbers, 1 characters, 2 letters); ln (separator: 0 none, 1 a 2-inch line, 2 margin to margin, 3 a 2-inch line and “Footnote continued”); b (0 footnotes after the text, 1 at the bottom of the page). The bits are given only as the order “b ln en ft n”. |
| 5 | Number of characters used instead of footnote numbers |
| 6–10 | Those characters (null-terminated if fewer than 5) |
| 11, 12–26 | Length and text of the footnote-text string |
| 27, 28–42 | Length and text of the endnote-text string |
| 43, 44–58 | Length and text of the footnote-note string |
| 59, 60–74 | Length and text of the endnote-note string |
Paragraph numbering
Each definition byte of E5 and EE has the numbering style
in its low nibble and the punctuation in its high nibble.
| Value | Style (low nibble) | Punctuation (high nibble) |
|---|---|---|
| 0 | Capital Roman | Nothing |
| 1 | Lower-case Roman | . after |
| 2 | Capital letter | ) after |
| 3 | Lower-case letter | ( before, ) after |
| 4 | Arabic | |
| 5 | Arabic with earlier levels, separated by . |
Marked text and generated lists
The definition/information byte of E7, E8 and
E9 has the definition in its high nibble and the information in its low
nibble: 0 table of contents (level 0–4), 1 index (E9 only; 0 no
concordance file, 1 a file name is included), 2 list (list 0–4), 3 table of
authorities (E9 only; section 0–15).
Definition bytes for contents, index and lists (contents uses all five, one per
level; index and lists only the first): 0 no page numbers, 1 page number after the
text after two spaces, 2 page number in brackets after one space, 3 page number flush
right, 4 flush right with dot leader. For a table of authorities only the first byte
counts, with bits xxxBxxDU: B a blank line between authorities, D dot
leaders, U underlining allowed.
Tab reset
F1 old-tab-table(32) old-type-table(20) new-tab-table(32) new-type-table(20) F1
Each bit of a tab table is one column, bits 0 to 250. Each nibble of a type table is the type of the corresponding set bit (the fifth nibble for the fifth tab), up to 40 tabs; the rest are type 0.
| Type | Tab | Type | Tab |
|---|---|---|---|
| 0 | Left | 4 | Left with dot leader |
| 1 | Centred | 5 | Not used |
| 2 | Right | 6 | Right with dot leader |
| 3 | Decimal | 7 | Decimal with dot leader |
Password protection
WordPerfect Corporation’s document describes unencrypted files only. libwpd
recognises a protected 4.2 file by its first four bytes FE FF 61 61,
followed by a 16-bit checksum of the password; the scrambled text starts at offset 6.
The checksum and scrambling are described on the
file header page.
No description of the encryption was ever made available by WordPerfect or its later
owners; libwpd’s method was worked out independently.
Recognising a 4.2 file
Without a header, libwpd checks the whole file: bytes below 0xC0 are
accepted; 0xFF on its own rejects the file; each code from
0xC0 must be closed by the same code after its fixed length, or later for
variable-length codes. Text that is valid UTF-8 is skipped, and a file with no
WordPerfect functions at all is not accepted, so plain text is not mistaken for a
document. libwpd tries the Macintosh 1.x layout first, which uses the same code
ranges but different lengths.
Sources
- WordPerfect File Information, Version 4.2 – WordPerfect Corporation, 1984–1986; the format’s own description, kept on the “WordPerfect for DOS Updated” site
- WordPerfect for DOS Updated: software and file formats – notes that no documentation of encrypted files was ever available from WordPerfect or its later owners
- libwpd source –
WP42FileStructure,WP42Parser,WP42Heuristics,WP42*GroupandWPDocument.cpp