<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Preflight</title>
    <description>The latest articles on DEV Community by Preflight (@preflight).</description>
    <link>https://dev.to/preflight</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4023200%2F8fe1786a-f300-4a4e-a7c1-b84151422136.png</url>
      <title>DEV Community: Preflight</title>
      <link>https://dev.to/preflight</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/preflight"/>
    <language>en</language>
    <item>
      <title>Most teams can't open the file that prints their statements — parsing AFP in the browser</title>
      <dc:creator>Preflight</dc:creator>
      <pubDate>Thu, 09 Jul 2026 20:14:48 +0000</pubDate>
      <link>https://dev.to/preflight/most-teams-cant-open-the-file-that-prints-their-statements-parsing-afp-in-the-browser-187k</link>
      <guid>https://dev.to/preflight/most-teams-cant-open-the-file-that-prints-their-statements-parsing-afp-in-the-browser-187k</guid>
      <description>&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;And yet: ask a team to answer &lt;strong&gt;"is this AFP batch structurally sane?"&lt;/strong&gt; 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 &lt;em&gt;conversion&lt;/em&gt; — AFP in, PDF out. Almost nobody just tells you whether the file is well-formed.&lt;/p&gt;

&lt;h2&gt;
  
  
  The format is friendlier than its reputation
&lt;/h2&gt;

&lt;p&gt;An AFP file is a flat sequence of &lt;strong&gt;structured fields&lt;/strong&gt;. Every field starts with a &lt;code&gt;0x5A&lt;/code&gt; 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.&lt;/p&gt;

&lt;p&gt;Structure comes from &lt;strong&gt;Begin/End pairs&lt;/strong&gt;. &lt;code&gt;BDT…EDT&lt;/code&gt; wraps the document; &lt;code&gt;BPG…EPG&lt;/code&gt; 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 &lt;code&gt;MCF&lt;/code&gt;, overlays via &lt;code&gt;IPO&lt;/code&gt;, page segments via &lt;code&gt;IPS&lt;/code&gt;) are eight-character EBCDIC names pointing at objects that live &lt;em&gt;outside&lt;/em&gt; the file, in a resource library on the production system.&lt;/p&gt;

&lt;h2&gt;
  
  
  What a structural validator can honestly check
&lt;/h2&gt;

&lt;p&gt;Our free validator does four things, all derivable from the bytes alone:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Framing&lt;/strong&gt; — every field opens with &lt;code&gt;0x5A&lt;/code&gt;, 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.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Begin/End nesting&lt;/strong&gt; — a plain stack.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The document envelope&lt;/strong&gt; — exactly one &lt;code&gt;BDT…EDT&lt;/code&gt;, pages nested inside.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Inventory&lt;/strong&gt; — every structured field with its name, byte offset, and length, plus the page count and every referenced resource name.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Just as important is what it refuses to do. An SFID we don't recognize is reported as &lt;strong&gt;unknown — counted, located, flagged as a warning&lt;/strong&gt; — 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.)&lt;/p&gt;

&lt;h2&gt;
  
  
  Why client-side was the whole point
&lt;/h2&gt;

&lt;p&gt;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 &lt;strong&gt;entirely in the browser&lt;/strong&gt;: 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.&lt;/p&gt;

&lt;p&gt;Try it (free, no signup, there's a 20-second demo on the page): &lt;a href="https://preflightdocs.com/tools/afp-validator?utm_source=devto&amp;amp;utm_medium=article&amp;amp;utm_campaign=afp" rel="noopener noreferrer"&gt;https://preflightdocs.com/tools/afp-validator?utm_source=devto&amp;amp;utm_medium=article&amp;amp;utm_campaign=afp&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;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.&lt;/p&gt;

</description>
      <category>parsing</category>
      <category>webdev</category>
      <category>printing</category>
      <category>showdev</category>
    </item>
    <item>
      <title>A structurally valid USPS barcode can still encode garbage — validating IMb from the bars</title>
      <dc:creator>Preflight</dc:creator>
      <pubDate>Thu, 09 Jul 2026 20:14:42 +0000</pubDate>
      <link>https://dev.to/preflight/a-structurally-valid-usps-barcode-can-still-encode-garbage-validating-imb-from-the-bars-5dle</link>
      <guid>https://dev.to/preflight/a-structurally-valid-usps-barcode-can-still-encode-garbage-validating-imb-from-the-bars-5dle</guid>
      <description>&lt;p&gt;Every piece of US commercial mail carries an Intelligent Mail barcode — 65 vertical bars, each in&lt;br&gt;
one of four states (full, ascender, descender, tracker). Encoded inside: a barcode ID, service&lt;br&gt;
type, mailer ID, serial number, and the delivery-point routing code. If it's wrong, mail gets&lt;br&gt;
misrouted, automation discounts evaporate, and assessments follow.&lt;/p&gt;

&lt;p&gt;Here's the part that surprised me when I built a validator: &lt;strong&gt;most "IMb checks" only verify that&lt;br&gt;
the bars look like an IMb.&lt;/strong&gt; Sixty-five bars, four valid states each, plausible geometry — pass.&lt;br&gt;
But the encoding pipeline between your data and those bars is long, and a bug anywhere in it&lt;br&gt;
produces a barcode that is structurally perfect and semantically garbage.&lt;/p&gt;

&lt;p&gt;The USPS spec (USPS-B-3200) defines the pipeline roughly like this:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The tracking + routing fields pack into a single large integer via positional arithmetic
(the routing code contributes up to ~10^11 of the space — this is effectively base conversion
with mixed radixes).&lt;/li&gt;
&lt;li&gt;An &lt;strong&gt;11-bit frame check sequence (CRC)&lt;/strong&gt; is computed over that integer's byte representation.&lt;/li&gt;
&lt;li&gt;The integer is converted into ten 3-digit codewords (more base conversion).&lt;/li&gt;
&lt;li&gt;Each codeword maps to a 13-bit &lt;strong&gt;constant-weight character&lt;/strong&gt; — every valid character has
exactly five bits set (weight 5) or two bits set (weight 2, selected by one FCS bit); the
remaining FCS bits flip specific character bits.&lt;/li&gt;
&lt;li&gt;The 130 character bits interleave onto the 65 bars (each bar's ascender/descender halves come
from different characters).&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;So validation has levels:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Level 0 — geometry:&lt;/strong&gt; 65 bars, valid states. Catches print defects, nothing else.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Level 1 — character validity:&lt;/strong&gt; de-interleave the bars and check that every 13-bit character
is in the constant-weight codebook. Catches some corruption; still passes many encoder bugs.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Level 2 — the FCS round-trip:&lt;/strong&gt; reverse the whole pipeline — characters → codewords → the big
integer (undoing the base conversion) — recompute the 11-bit CRC from the recovered payload,
and compare it against the FCS bits actually embedded in the characters. &lt;strong&gt;A mismatch proves
the barcode was produced by a broken encoder&lt;/strong&gt;, even though every bar and every character looks
valid.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Level 2 is the one that catches real production incidents: an off-by-one in codeword packing, a&lt;br&gt;
routing code that got truncated upstream, a library that silently handles 130-bit arithmetic&lt;br&gt;
wrong. All of those produce beautiful, scannable, &lt;em&gt;wrong&lt;/em&gt; barcodes.&lt;/p&gt;

&lt;p&gt;A few implementation notes for anyone building this:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You need exact big-integer arithmetic (the payload exceeds 64 bits — 10^11 × the tracking
fields). Any float contamination anywhere corrupts the round-trip.&lt;/li&gt;
&lt;li&gt;The reverse base conversion is the fiddly part: the spec is written encode-forward, so the
decode is "run the multiplications backwards as divisions and prove you get clean remainders."&lt;/li&gt;
&lt;li&gt;Test against the spec's published example vectors first, then against barcodes from encoders
you trust, then — the fun part — against deliberately corrupted ones. A validator that never
fails anything is just a mirror. (My rule for the whole product: anything the tool can't
actually determine gets reported "not evaluable" — never silently passed.)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I ship this as part of Preflight, a document-QC tool for print/mail — the free analyzer detects&lt;br&gt;
IMbs and validates structure in the browser: &lt;a href="https://preflightdocs.com/tools/imb-barcode-validator?utm_source=devto&amp;amp;utm_medium=article&amp;amp;utm_campaign=imb" rel="noopener noreferrer"&gt;https://preflightdocs.com/tools/imb-barcode-validator?utm_source=devto&amp;amp;utm_medium=article&amp;amp;utm_campaign=imb&lt;/a&gt;&lt;br&gt;
The full FCS round-trip and field decode run in the USPS module. But the algorithm above is all&lt;br&gt;
public spec (USPS-B-3200) — if you maintain mail software, you can build Level 2 yourself, and&lt;br&gt;
you probably should.&lt;/p&gt;

</description>
      <category>barcode</category>
      <category>printing</category>
      <category>algorithms</category>
      <category>showdev</category>
    </item>
  </channel>
</rss>
