Teknisk artikkel

Teknisk artikkel: PDFlibPas Compliance and Signing Workbench in Delphi på norsk

Denne lokaliserte versjonen går rett inn i Building a Compliance and Signing Workbench in Delphi with PDFlibPas og bruker den oppdaterte engelske artikkelen som teknisk grunnlag for team som arbeider med Delphi, PDF og dokumentprogramvare

Siden gjør den oppdaterte basisartikkelen om til konkrete kontrollpunkter for design, implementering og validering

Hva som ble synkronisert fra den engelske artikkelen

Den engelske basisartikkelen er utvidet med praktisk kontekst, tekniske beslutninger og konkrete eksempler, så denne siden bør leses som en arbeidsveiledning og ikke som et kort sammendrag

Viktige deler i den oppdaterte basisartikkelen:

  • Bruk små reproduserbare inndatafiler før funksjonen kobles til produksjonsdata
  • Behold produktnavn, API-navn, filnavn og literalverdier uendret
  • Lagre validatorutdata og versjonsinformasjon sammen med den genererte prøvefilen

Praktiske valg i implementeringen

Start med filtypen, forventet resultat og feiltilstanden brukeren skal se. Knytt deretter hvert API-kall til et kontrollerbart resultat, slik at validering, logging og støtte kan gjenskape kundens scenario

  • Bruk små reproduserbare inndatafiler før funksjonen kobles til produksjonsdata
  • Behold produktnavn, API-navn, filnavn og literalverdier uendret
  • Lagre validatorutdata og versjonsinformasjon sammen med den genererte prøvefilen

Kode og API-punkter

Kodeeksemplene beholdes uendret slik at utviklere kan sammenligne dem direkte med Delphi-, C++Builder- og Lazarus/FPC-prosjekter

var
  PDF: TPDFlib;
  ListID, I: Integer;
begin
  PDF := TPDFlib.Create;
  try
    ListID := PDF.CheckFileCompliance('invoice-fixed.pdf', '', 1, 0);  // 1 = PDF/A
    if ListID = 0 then
    begin
      if PDF.LastErrorCode <> 0 then
        raise Exception.Create('Preflight could not read the file')
      else
        Writeln('No PDF/A findings');
    end
    else
    begin
      for I := 0 to PDF.GetStringListCount(ListID) - 1 do
        Writeln(PDF.GetStringListItem(ListID, I));
      PDF.ReleaseStringList(ListID);
    end;
  finally
    PDF.Free;
  end;
end;
ProcessID := PDF.NewSignProcessFromFile('invoice-fixed.pdf', '');
if ProcessID = 0 then
  raise Exception.Create('Cannot open source for signing');
PDF.SetSignProcessField(ProcessID, 'ApprovalSig');
PDF.SetSignProcessPFXFromFile(ProcessID, 'company.pfx', PfxPassword);
PDF.SetSignProcessInfo(ProcessID, 'Invoice approval', 'Berlin', 'billing@example.com');
PDF.SetSignProcessCustomSubFilter(ProcessID, 'ETSI.CAdES.detached');  // PAdES baseline
PDF.SetSignProcessDigestAlgorithm(ProcessID, 2);                      // SHA-256
PDF.SetSignProcessReserveContentsBytes(ProcessID, 8192);              // room for a later timestamp
PDF.EndSignProcessToFile(ProcessID, 'invoice-signed.pdf');
if PDF.GetSignProcessResult(ProcessID) <> 1 then
  Writeln('Sign failed, code ', PDF.GetSignProcessResult(ProcessID));
PDF.ReleaseSignProcess(ProcessID);
var
  Doc: TPDFlibSignDoc;
  Names: TStringList;
  FS: TFileStream;
  I: Integer;
  SourceSize, RangeStart, GapStart, TailStart, TailLen: Int64;
begin
  // Capture the size before Open: the audit object holds a share lock on the file
  FS := TFileStream.Create('invoice-signed.pdf', fmOpenRead or fmShareDenyNone);
  SourceSize := FS.Size;
  FS.Free;
  Doc := TPDFlibSignDoc.Create;
  Names := TStringList.Create;
  try
    if not Doc.Open('invoice-signed.pdf', '', False) then Exit;
    Doc.GetSignatureFieldNames(Names);
    for I := 0 to Names.Count - 1 do
      if Doc.GetSignatureValueObjNum(Names[I]) > 0 then  // > 0 means the field is signed
      begin
        RangeStart := StrToInt64(string(Doc.GetSignatureValueByName(Names[I], 11)));
        GapStart   := StrToInt64(string(Doc.GetSignatureValueByName(Names[I], 12)));
        TailStart  := StrToInt64(string(Doc.GetSignatureValueByName(Names[I], 13)));
        TailLen    := StrToInt64(string(Doc.GetSignatureValueByName(Names[I], 14)));
        if (RangeStart = 0) and (TailStart + TailLen = SourceSize) then
          Writeln(Names[I], ': signature covers the file to EOF')
        else
          Writeln(Names[I], ': earlier revision, or unusual ByteRange layout');
      end;
    Doc.Close;
  finally
    Names.Free;
    Doc.Free;
  end;
end;

Kontroll før publisering

Kontroller utdatafilen med de samme verktøyene som kunden eller arkivet vil bruke. Noter komponentversjon, testdata, validatorversjon og observert resultat slik at en senere regresjon kan spores presist

Supplerende teknisk gjennomgang

Denne utvidede delen knytter an til artikkelen Teknisk artikkel: PDFlibPas Compliance and Signing Workbench in Delphi på norsk og utdyper den samme arbeidsflyten fra perspektivet til et team som må kunne spore beslutninger i generatoren, i valideringen og i det lagrede resultatet senere. Den engelske basisartikkelen på den tilknyttede siden via hreflang viser hvorfor det ikke holder å bare oversette overskriftene; det viktige er å forklare hvorfor dokumentet først er ferdig når regler, utdata og kontrollspor faktisk henger sammen

I implementasjonsartikler er det nyttig å skille design fra verifisering. Først fastsettes filtypen, forventet resultat og feiltilstanden brukeren skal se, og deretter kobles hvert API-kall til et resultat som kan testes på nytt i samme scenario. Dette gjelder både PDF-arbeidsflyter og regnearkfunksjoner: kodeeksemplene forblir uendret, men brødteksten må forklare hvorfor komponentversjon, mal-id, inndata og valideringsstatus bør logges sammen

Det er også viktig å beholde produktnavn, API-navn, filnavn og literalverdier nøyaktig slik de står i den engelske kilden. Da bevares den felles referanserammen for utvikling, support og kvalitetssikring, og risikoen reduseres for at den lokale versjonen bare blir en løs parafrase uten konkret teknisk innhold. Hvis artikkelen inneholder kode, skal kommentarene og tokenene stå urørt, fordi det nettopp er de som kobler teksten til det virkelige prosjektet

Når siden leses etter publisering, er det nyttig å tenke på den som en del av en sporbar kjede. En god valideringsnote beskriver hva som ble testet, hvilket verktøy som vurderte resultatet, hvilke versjoner som var involvert, og hvor beviset for treff eller avvik er lagret. Når en regresjon dukker opp senere, er den arkiverte rapporten og den tilhørende inndatafilen langt mer verdifulle enn bare inntrykket av at "det gikk den gangen"

For denne lokaliserte grenen gjelder derfor en enkel regel: hold de sentrale beslutningene, verifiseringspunktene og kodekonteksten samlet, slik at artikkelen forblir nyttig ikke bare ved første lesning, men også ved senere feilsøking, revisjon og versjonssammenligning. Det er forskjellen mellom et kort sammendrag og et arbeidsdokument som fortsatt har verdi etter flere utgivelser.

  • Bruk først små reproduserbare inndatafiler
  • Behold produktnavn, API-navn, filnavn og literalverdier uendret
  • Lagre komponentversjon, validatorresultat og inndata sammen
  • Bevar kodeblokker og kommentarer nøyaktig slik de står i kilden

Relatert lesing