HotPDF sukompiliuoja ir dirba Free Pascal 3.2.2 su Lazarus, ir sąžininga to perkeliamumo santrauka yra du sakiniai. Dokumentų kūrimas, įkėlimas, įrašymas, glaudinimas, išglaudinimas, šifravimas ir iššifravimas visi veikia tik ant Pascal posistemių, todėl Lazarus programa gali gaminti ir vartoti tikrą PDF be jokios C priklausomybės. Pasirinktiniai savieji atvaizdų kodekai — ne, nes paruošti Win64 objektai naudoja COFF atmainą, kurią neįgyvendina nė vienas Free Pascal linkeris, todėl toje įrankių grandinėje įėjimo taškai išsiskleidžia į saugiai stringančias iškaras (fail closed)
Nuėjimas nuo „sukompiliuojasi“ iki „veikia“ pareikalavo konkretaus pataisymų rinkinio, ir kiekvienas iš jų yra spąstai, kurie ras bet kokią kitą Delphi kodų bazę, keliančią į Free Pascal. Verta juos užsirašyti ta tvarka, kuria jie skaudėjo
Kodėl modulio sukompiliavimas nieko neįrodo?
Nes Pascal modulis gali nurodyti simbolį, kuris niekada nedarys nieko naudingo, ir vis tiek patenkinti kompiliatorių. Tuo metu, kai visi 113 bibliotekos modulių švariai pastatyti Free Pascal aplinkoje, archyvo konteinerių apdorotojai tikrai veikė, patikrinti dūmų testo, atvėrusio CBZ ir pavertusio jį PDF. XFA formų suplovinimas apskritai neveikė, nes suplovinimui reikia išglaudinti suglaudintą /XFA paketo srautą, o deflate įėjimo taškas dar buvo iškarpa. Statymo išvestyje niekas tų dviejų atvejų neperskiria
Iš to kylanti taisyklė trumpa. Prieš rašant išleidimo pastaboje, kad savybė veikia naujoje įrankių grandinėje, parašykite vykdymo laiko zondą, kuris šią savybę perbėga nuo galo iki galo toje grandinėje. Kompiliavimo dengimas yra prielaida, niekada ne įrodymas. Platesnį vaizdą, ką dengia perkeliamumas, duoda Free Pascal ir Lazarus Win64 palaikymo pastabos
Išimtis, mesta cdecl iškarpos viduje, nepasiekia iškviečiančiojo
Šis nusipelno savo skyriaus, nes simptomas toks apgaulingas. Iškarpų moduliai atveria C įėjimo taškus taip, kaip darytų statinė biblioteka, todėl iškarpa atrodo taip
// Atrodo pagrįstai. Nėra.
function inflate(Strm: Pointer; Flush: Integer): PtrUInt; cdecl;
public name 'inflate';
begin
raise ENotSupportedException.Create('codec unavailable');
end;
Free Pascal Win64 ta išimtis neplinta iki iškviečiančiojo. Nėra try..except apdorojusiojo, kuris ją matytų, nes atsitiesimas per taip deklaruotą cdecl ribą nešasi Pascal išimčių kadro; procesas baigiasi su išėjimo kodu 217. Programos pusėje nėra jokios klaidos, jokio pranešimo ir jokios žurnalo eilutės — tik programa, dingsanti. Tai griežtai blogiau nei neteisingas atsakymas, nes neteisingą atsakymą galima apdoroti
Viliojanti pataisa — padaryti, kad iškarpa vietoj to grąžintų nesėkmės kodą, ir inflate atveju tai teisinga, nes zlib turi aiškiai apibrėžtą klaidos grąžą. Apibendrintai tai neteisinga: jpeg_read_header iškarpa, grąžinanti nulį, sako iškviečiančiajam tęsti su struktūra, kurią niekas neinicijavo. Patvari pataisa — užtverti prie Pascal įėjimo taško, o ne C formos iškarpos viduje, naudojant tą nesėkmės konvenciją, kurią ta API jau turi
function TryDecodeJPEG(const Data: TBytes; out Bitmap: TBitmap): Boolean;
begin
{$IFDEF FPC}
// Atsisakykite dar prieš pasiekiant iškarpą, naudodami šios API
// pačios nesėkmės konvenciją, o ne išimtį per cdecl
Bitmap := nil;
Result := False;
Exit;
{$ENDIF}
Result := DecodeJPEGNative(Data, Bitmap);
end;
paszlib nėra zlib, ir skirtumas — dvi dokumentų klasės
Prieinamas Free Pascal Pascal deflate įgyvendinimas moka dvi apvyniojimo formas: zlib įvyniojimą ir žaliąjį deflate. Jis nemoka gzip apvyniojimo, kurį zlib pasirenka per windowBits reikšmes nuo 16 iki 31, ir nemoka automatinio atpažinimo režimo, kurį pasirenka reikšmės nuo 32 iki 47. HotPDF reikia abiejų. Saugus SVG importo kelias prašo 31, o įkėliklis turi atsarginių kopėčių, prašančių 47, kai srauto apvyniojimas dvišalis. Praleidus bet kurį iš jų, visa dokumentų šeima nustoja atsidaryti, su dekodavimo klaida, rodančia į srautą, o ne į dingusį apvyniojimą
Yra antras, aštresnis nesuderinamumas. z_stream įrašas, kurį deklaruoja paszlib, neturi tos pačios atminties išdėstymo kaip C variantas: jo msg laukas yra trumpa eilutė, o ne rodyklė, o total_in ir total_out yra 64 bitų ten, kur C ABI turi mašininius žodžius. Iškviečiančiojo įrašas todėl negali būti perduodamas tiesiai. Veikiantis išdėstymas — laikyti paszlib būseną už state rodyklės, kurią viešasis įrašas jau rezervuoja, ir kopijuoti viešuosius laukus į vidų ir išorę aplink kiekvieną iškvietimą. Gzip CRC ir aštuonių baitų ilgio priedas apskaitomi tame pačiame suderinamajame sluoksnyje, kuris yra natūrali jų vieta, nes jis jau valdo apvyniojimo sprendimą
Dinaminio masyvo perdavimas netipizuotam var parametrui
Tai klaida, kuri šiuo metu labiausiai tikėtina, kad sėdi jūsų kode. Kai perduodate dinaminį masyvą netipizuotam var parametrui, tai, ką gauna iškviečiamasis, yra masyvo kintamojo adresas — tai rodyklės adresas, o ne turinio (payload) adresas. Taigi skaitymas į jį perrašo patį kintamąjį ir tai, kas greta jo
var
FBuffer: TBytes;
begin
SetLength(FBuffer, 65536);
// Neteisinga: atiduoda FBuffer kintamojo adresą
FStream.Read(FBuffer, Length(FBuffer));
// Teisinga: atiduoda pirmojo turinio baito adresą
FStream.Read(FBuffer[0], Length(FBuffer));
end;
Delphi neteisinga forma dažnai atrodo veikianti, nes tai, ką ji sugadina, yra gretimas krūvos langelis, į kurį niekas vėliau neskaitys. Free Pascal ta pati eilutė pirmuoju naudojimu gauna segmentavimo pažeidimą. Kodėl ją taip sunku pastebėti akimi — todėl, kad statiniai masyvai tokios problemos neturi: statinio masyvo kintamasis yra pats savo turinys, todėl abiejos rašybos tame pačiame faile gali būti teisingos, priklausomai nuo deklaracijos už kelių šimtų eilučių
ZIP konteineriai be System.Zip
Free Pascal neturi RTL zip modulio atitikmens, o prieinama alternatyva turi ir kitokį API paviršių, ir jokio palaikymo senajai šifravimo schemai, kurią vis dar naudoja senesni konteinerių formatai, todėl nedidelis bibliotekos vidinis skaitytuvas pasirodė trumpesnis nei prisitaikymas prie jos. Dvi formato detalės kainavo laiko ir lengvai padaromos klaidingai
Pirmoji — šifravimo antraštės tikrinimo baitas. Jo dvyliktas baitas įprastai yra CRC aukštasis baitas, bet kai bendrosios paskirties vėliavėlės 3 bitas nustatytas — tai reiškia, kad dydžiai gyvena galiniame duomenų deskriptoriuje ir CRC dar nežinomas, — tikrinimo baitas imamas iš keitimo laiko aukštojo baito. Įgyvendinus tik CRC formą, kiekvienas srautinio režimo parašytas archyvas atmeta teisingą slaptažodį. Antroji — ZIP64 papildomas laukas: jo trys 64 bitų laukai pasirodo fiksuota tvarka, bet rašomi tik tada, kai atitinkamas 32 bitų laukas prisotintas, todėl jų skaitymas fiksuotuose poslinkiuose veikia išbandytuose archyvuose ir nepavyksta kitame. Analizuokite juos poziciškai pagal tai, kurie 32 bitų laukai prisotinti
Vienas patogumas, vertas žinoti: Free Pascal išglaudinimo srautas priima antrąjį konstruktoriaus argumentą, praleidžiantį zlib antraštę — būtent to reikia ZIP įrašams, nes jie saugo žaliąjį deflate. Tas kelias apskritai neliečia bibliotekos zlib suderinamojo sluoksnio, todėl jo neveikia dingęs C posistemis
Spalvotų glifų permatomumas po LCL
Rastruoto spalvoto glifo alfa kanalo skaitymas yra ta viena grafikos detalė, neturinti tiesioginio atitikmens. LCL PNG klasės nėra eilučių prieigos metodo, atveriančio alfa, o PNG priskyrimas bitmap jį išmeta, todėl spalvotas emoji atkeliauja visiškai nepermatomas ir sudedamas su juoda dėže už jo. Veikiantis kelias yra sąsajos atvaizdas: sukurti jį iš PNG, paskui skaityti pikselius per spalvų prieigos metodą, atsimenant, kad jo komponentės yra 16 bitų ir jas reikia pastumti aštuoniais žemyn, kad taptų baitais. Tas paviršius irgi naudoja natūralią viršaus žemyn eiliškumą, todėl Height - 1 - Y apvertimas, kurio reikia VCL eilučių kodui, turi būti pašalintas, o ne perkeltas
Dvi statymo sistemos pastabos prieš pranešant klaidą
Pilnas perkompiliavimas kartais nepavyksta su neapibrėžtu simboliu, kurio vardas baigiasi $crc priedėliu ir šešioliktaine reikšme. Tas priedėlis skaičiuojamas iš parametrų tipų ir nesutampa, kai vienas statymas toje pačioje sekoje sukompiliuoja modulį pagal dvi skirtingas sąsajos versijas. Pakartotinai paleistas statymas tai išvalo; parašas nėra neteisingas
Antra, Free Pascal 3.2.2 neturi anoniminių metodų, todėl ten, kur biblioteka naudojo uždarymus (closure) lygiagrečiam konvejeriui sujungti, Free Pascal statymas vietoj to ima deterministinį nuoseklųjį atsarginį kelią. Išvestis identiška, pralaidumas — ne; jeigu priklausote nuo lygiagrečio puslapių atvaizdavimo, tai priežastis kol kas likti Delphi, o konvejerio projektas aprašytas lygiagretaus atvaizdavimo konvejerio straipsnyje. Atvaizdų kodekų situacija yra kita vieta, kur įrankių grandinės pasirinkimas keičia galimybes, o ne tik spartą, todėl Lazarus diegimui verta planuoti atvaizdų formatus atitinkamai; esama pagal įrankių grandinę matrica yra HotPDF Delphi PDF component produkto puslapyje