DEV Community

Cover image for Most teams can't open the file that prints their statements — parsing AFP in the browser
Preflight
Preflight

Posted on • Originally published at preflightdocs.com

Most teams can't open the file that prints their statements — parsing AFP in the browser

AFP — Advanced Function Presentation — predates the web. It came out of IBM in the 1980s, moves to production printers over IPDS, and still composes a huge share of the world's bank statements, insurance documents, and healthcare EOBs. If you work anywhere near transactional print, AFP files flow through your systems daily.

And yet: ask a team to answer "is this AFP batch structurally sane?" and watch what happens. The tooling that can even open the format is enterprise software — licensed per seat, installed somewhere specific, owned by another department. The format's documentation (MO:DCA — Mixed Object Document Content Architecture) is public via the AFP Consortium, but public and approachable are different things. Most vendors in this space sell conversion — AFP in, PDF out. Almost nobody just tells you whether the file is well-formed.

The format is friendlier than its reputation

An AFP file is a flat sequence of structured fields. Every field starts with a 0x5A carriage-control byte, then a two-byte big-endian length, a three-byte identifier (SFID), a flag byte, two reserved bytes, and payload. That's the whole framing story. No cross-references to resolve, no compression dictionary to bootstrap — you can walk an AFP file with a while loop.

Structure comes from Begin/End pairs. BDT…EDT wraps the document; BPG…EPG wraps each page; groups, presentation-text objects, and overlays nest inside in last-opened-first-closed order. Names inside the fields are EBCDIC — code page 500, another small museum piece — and resource references (fonts via MCF, overlays via IPO, page segments via IPS) are eight-character EBCDIC names pointing at objects that live outside the file, in a resource library on the production system.

What a structural validator can honestly check

Our free validator does four things, all derivable from the bytes alone:

  • Framing — every field opens with 0x5A, declares an in-bounds length, and the stream ends exactly at a field boundary. Truncation is the classic transfer failure; FTP in ASCII mode has ruined more AFP files than any parser bug.
  • Begin/End nesting — a plain stack.
  • The document envelope — exactly one BDT…EDT, pages nested inside.
  • Inventory — every structured field with its name, byte offset, and length, plus the page count and every referenced resource name.

Just as important is what it refuses to do. An SFID we don't recognize is reported as unknown — counted, located, flagged as a warning — not guessed at. Whether a referenced font or overlay actually exists in your resource library is not knowable from the file, so we say exactly that instead of implying it was verified. (My rule for the whole product: anything the tool can't actually determine is reported "not evaluable" — never silently passed.)

Why client-side was the whole point

AFP files are statements and EOBs — they carry names, addresses, account numbers, health information. The reason "just upload it to a converter site" never became the norm in this industry is that nobody responsible for that data should be uploading it anywhere casually. So the validator runs entirely in the browser: the parser is compiled into the page, the file is read locally, and there is no upload endpoint behind it. Parsing a structured-field stream is cheap — a multi-hundred-page statement run inventories in milliseconds on a laptop — and the file never touches a network.

Try it (free, no signup, there's a 20-second demo on the page): https://preflightdocs.com/tools/afp-validator?utm_source=devto&utm_medium=article&utm_campaign=afp

The MO:DCA reference is public via the AFP Consortium — if your team fights this format, the structural walk above is entirely buildable from spec, and honestly, more people should.

Top comments (0)