Technical Article

Håndtering av hybride referanse-PDF-er fra Office-applikasjoner i Delphi

\n

Hvis du noen gang har skrevet en PDF-parser, vet du at ISO 32000-1-spesifikasjonen er enorm, og den virkelige verdenen av PDF-generering er enda mer uoversiktlig. En av de mer subtile kompleksitetene moderne PDF-utviklere står overfor, er den hybride referanse-PDF-en. Denne strukturen genereres ofte av Microsoft Office-applikasjoner (Word, Excel) ved eksport av dokumenter til PDF, og blander eldre, tradisjonelle kryssreferansetabeller (XRef) med moderne komprimerte XRef-strømmer for å opprettholde bakoverkompatibilitet.

Mens denne hybride tilnærmingen er flott for eldre PDF-lesere, utgjør den en betydelig utfordring for analyseringsmotorer. Hvis din Delphi PDF-komponent antar at en fil strengt bruker det ene eller det andre referanseformatet, kan innlasting av en Office-generert PDF resultere i "manglende" objekter, korrupte sider eller stille krypteringsfeil. Her er et teknisk dypdykk i hvordan du riktig håndterer disse hybride strukturene.

Anatomien til en hybrid referanse-PDF

I et standard PDF 1.4-dokument er plasseringene til alle objekter lagret i en ren tekst XRef-tabell på slutten av filen. I PDF 1.5 introduserte Adobe Object Streams (ObjStm) og XRef Streams for å komprimere dokumentstrukturen, og beveget seg bort fra rene teksttabeller.

En fil med hybride referanser bruker begge deler. Filens primære trailer inneholder en /XRefStm-oppføring som peker til en XRef-strøm, men den legger også til en tradisjonell, ukomprimert XRef-tabell. En eldre PDF-leser vil ignorere /XRefStm-oppføringen, lese den tradisjonelle tabellen og laste inn en delmengde av dokumentet. En moderne leser må oppdage /XRefStm, slå sammen oppføringene fra både strømmen og den tradisjonelle tabellen, og løse dokumentobjektene deretter.

Fallgruvene ved å analysere hybride strukturer

Under utviklingen av HotPDF VCL-komponenten støtte vi på et fascinerende grensetilfelle. Innlasting av en hybrid referanse-PDF eksportert fra Excel så ut til å fungere (sidetallet var riktig), men forsøk på å lagre dokumentet med AES-256-kryptering kastet en EListError. Den underliggende årsaken var en kombinasjon av to distinkte feller i analyseringen.

1. For tidlige rutingbeslutninger

Når en parser hopper til byteforskyvningen indikert av nøkkelordet startxref, leser den de første få bytene. Hvis den ser den bokstavelige strengen xref, antar parseren typisk at dokumentet bruker en tradisjonell XRef-tabell. Imidlertid er den siste delen i en Office-generert hybrid-PDF ofte en avkortet tradisjonell tabell (for eksempel xref\n0 0). Den faktiske nyttelasten er definert i trailerens /XRefStm-ordbok.

Hvis parseren din stopper ved den tradisjonelle tabellen, vil den bare laste inn objektene som er oppført der, og ignorere størstedelen av dokumentet som er skjult i objektstrømmene. Dette kan skape en "glissen" dokumenttilstand der bare en brøkdel av objektene er lastet inn, selv om sidetreet fortsatt kan virke intakt fordi sideordbøkene tilfeldigvis var i den tradisjonelle tabellen.

2. Antagelsen om krypteringslokator

Den andre fellen innebærer å anta at et objekts indeks i din interne liste samsvarer med dets objektnummer (det vil si Index = ObjNum - 1). Dette er ofte sant for nylig forfattede dokumenter der objekter opprettes sekvensielt. Imidlertid, når du laster inn et hybrid dokument der objektnumrene er glisne (for eksempel ved å laste inn 19 objekter av totalt 118 definert i filen), bryter denne antagelsen sammen. Forsøk på å skrive /Encrypt-ordboken ved å referere til Items[MaxObjNum - 1] vil forårsake en feil utenfor grensene hvis listen er glissen.

Beste praksis for robust analysering

For å trygt konsumere og manipulere hybride referanse-PDF-er i dine Delphi-applikasjoner, ta i bruk følgende strategier:

  • Sjekk alltid traileren for /XRefStm: Selv om startxref peker på et tradisjonelt xref-nøkkelord, må du lese den tilknyttede trailerordboken. Hvis det finnes en /XRefStm-oppføring, må du rute parseren til å laste den moderne XRef-strømmen i stedet for å nøye deg med den eldre tabellen.
  • Slå sammen med "først sett vinner"-semantikk: Når et dokument har inkrementelle oppdateringer (flere XRef-seksjoner), analyser dem fra nyeste (slutten av filen) til eldste. Bruk en "først sett vinner"-regel. Viktigst av alt, hvis du støter på en ledig oppføring (Type 0) i en nyere seksjon, må den maskere eventuelle i-bruk-oppføringer for det samme objektnummeret i eldre seksjoner for å forhindre gjenoppliving av slettede objekter.
  • Vær oppmerksom på manglende /Filter-strømmer: ISO 32000-1-spesifikasjonen tillater at strømmer mangler en /Filter-oppføring hvis de er ukomprimerte. Sørg for at dekomprimeringsrutinene dine eksplisitt sjekker om et filter er til stede. Ubetinget sending av strømdata til en zlib/deflate-inflater når ingen filter er definert, vil stille ødelegge objektstrømmene dine.

Håndtering av PDF-er generert av de utallige verktøyene der ute, krever defensiv programmering. Ved å sikre at logikken for analyseringen din fullt ut respekterer hybride referanser og unngår antagelser om sekvensielle objektnumre, kan du garantere at dine Delphi-applikasjoner håndterer Office-genererte PDF-er like feilfritt som Adobe Acrobat.

Merk: Den robuste håndteringen av hybride referansestrukturer, objektstrømmer og AES-256-kryptering er innebygd direkte i HotPDF VCL Component.

\n
\n