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.
No description of the encryption was ever made available by WordPerfect or its later
owners (WordPerfect for DOS
Updated); libwpd’s method was worked out independently. It is not secure and is
easily reversed. libwpd handles a protected 4.2 file like this:
- The password is turned to upper case (letters a to z only).
- The checksum is built over the password’s characters: start at 0; for each character, rotate the 16-bit value right by one bit and XOR it with the character shifted left eight bits. A file is protected when its stored checksum is not 0, and the password is right when the checksums match.
- The first 6 bytes (the marker and the checksum) are not encrypted.
- The byte at position
iafter those 6 is XORed with the password characteri mod lengthand with the mask(length + 1 + i) mod 256.
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