Excel radna sveska može nositi EMF i WMF slike, i uobičajen način da se nacrta jeste predati tok bajtova operativnom sistemu metafile plejeru. To je odluka vredna direktnog gledanja: metafajl je serijalizovan tok komandi za grafički API, i njegovo ponavljanje znači pustiti datoteku koja je stigla e-poštom da vozi grafički drajver. HotXLS ide drugim putem. XLSDecodeVectorScene raščlanjuje metafajl sam, validira zaglavlje, svaku veličinu zapisa, deklarisani ukupan broj zapisa i tačan smeštaj zapisa kraja datoteke, odbacuje escape zapise odmah, i vraća TXLSVectorScene primitivnih crtačkih komandi koje Canvas i SVG backend-i ponavljaju kroz svoj sopstveni kod. Nijedna reprodukcija drajvera nije uključena ni u jednom trenutku
Trampa je pokrivenost za obuzdavanje. Popis dozvoljenih komandi orijentisan na pravougaonike neće reprodukovati svaki metafajl koji dizajner može stvoriti, pa scena izveštava koliko crtačkih zapisa nije mogla predstaviti i pozivalac odlučuje šta s tim. Za serverski proces koji prikazuje dokumente koje nije stvorio, ta trampa je pravim smerom
Zašto je reprodukcija metafajla loš izbor za nepoverljiv ulaz?
Zato što format nije slika, to je program. EMF tok zapisa upravlja stekom stanja device konteksta, alocira i bira objekte iz tabele handle-ova, i može nositi escape zapise čiji se sadržaj prosleđuje drajveru uređaja. Njegovo ponavljanje vežba putanje u platformskom grafičkom steku napisane sa pretpostavkom da je metafajl došao od saradujuće aplikacije na istoj mašini. Kada je ulaz prilog tabele, ta pretpostavka je nestala, i nijedna količina pažnje unutar biblioteke tabele ne pomaže jer biblioteka nije komponenta koja raščlanjuje
Ovo je isto rasuđivanje koje upravlja slojem kontejnera. Radna sveska je ZIP arhiva, i HotXLS validira svoj centralni direktorijum umesto da veruje deklarisanim ofsetima, kao što je opisano u članku o validaciji ZIP kraja-centralnog-direktorijuma. Sadržaji metafajla sledeći su sloj istog problema
Šta dekoder proverava pre nego što nacrta bilo šta
Validacija je strukturna i dešava se unapred, jer parser koji počne crtati i validira dok ide već je postupao po podacima koje nije verifikovao. Zaglavlje mora odgovarati strogo, a ne uverljivo. Svaki zapis mora deklarisati veličinu koja staje unutar preostalog bafera i dovoljno je velika za sopstvena fiksna polja. Broj zapisa koji zaglavlje deklariše mora odgovarati zapisima stvarno prisutnim. Zapis kraja datoteke mora sedeti tačno gde tok prestaje, ne samo negde blizu, što zatvara trik pratećeg smeća koje krije drugi sadržaj iza valjane slike
Van strukture, dekoder je otkazujuće-zatvoren po semantici. Escape zapisi su odbijeni, ne preskočeni. Zapis koji menja stanje a dekoder ga ne modeluje uzrokuje otkazivanje dekodovanja umesto da bude ignorisan, jer ignorisanje izmene stanja znači da se svaka sledeća crtača komanda izvršava u stanju koje datoteka nije tražila, i rezultat je slika koja je pogrešna na način koji niko ne može predvideti. Crtački zapisi van podržanog skupa komandi drugo su pitanje: oni se broje i preskaču, jer nedostajući oblik vidljiv je, izveštavajući jaz umesto tihog oštećenja
Budžeti su deo ugovora formata
Vektorski formati imaju svoju verziju bombe dekompresije. Nekoliko kilobajta zapisa može deklarisati polilinije sa stotinama miliona tačaka, ili sliku čije se deklarisane dimenzije množe u terabajte. Granice dakle moraju biti eksplicitne konstante umesto onoga što mašina slučajno preživi
// Iz lxVectorScene: budžet dekodovanja, izjavljen umesto podrazumevan
XL_VECTOR_MAX_RECORDS = 1000000;
XL_VECTOR_MAX_HANDLES = 4096;
XL_VECTOR_MAX_DC_DEPTH = 32;
XL_VECTOR_MAX_COMMANDS = 100000;
XL_VECTOR_MAX_POINTS_PER_RECORD = 100000;
XL_VECTOR_MAX_TOTAL_POINTS = 2000000;
XL_VECTOR_MAX_TEXT_CHARS = 4096;
XL_VECTOR_MAX_TOTAL_TEXT_CHARS = 1000000;
XL_VECTOR_MAX_IMAGE_SIDE = 8192;
XL_VECTOR_MAX_IMAGE_PIXELS = 32 * 1024 * 1024;
XL_VECTOR_MAX_IMAGE_BYTES = 64 * 1024 * 1024;
XL_VECTOR_MAX_COORD = 1000000000;
Dva od ovih zaslužuju napomenu. Granica dubine device konteksta od 32 postoji jer se SaveDC i RestoreDC zapisi ugrađuju, i nebalansiran tok može gurati zauvek; 32 je velikodušno za stvarne metafajlove i jeftino za sprovođenje. Granica koordinata postoji jer se koordinate ulivaju u transformaciju, i vrednost blizu granica opsega celih brojeva proizvodi transformisan rezultat koji je ili beskonačan ili se savija, posle čega je svaki izračun okvirnog okvira nizvodno besmisao. Stezanje koordinata u vreme parsiranja mnogo je lakše za rasuđivanje nego brana svakom potrošaču geometrije
Korišćenje scene
Dekoder predaje nazad objekat koji vi posedujete, broj komandi, nominalnu veličinu, i broj crtačkih zapisa koje je izabrao da ne predstavi
uses
lxVectorScene;
var
Scene: TXLSVectorScene;
Error: WideString;
I: Integer;
begin
// Data drži sirovi sadržaj slike uzet iz radne sveske
if not XLSDecodeVectorScene(Data, xlsvfEmf, Scene, Error) then
begin
// Odbijeno: zaglavlje, granice, ukupni brojevi, EOF smeštaj ili budžet
LogReject('metafile rejected: ' + Error);
Exit;
end;
try
if Scene.SkippedDrawRecords > 0 then
LogWarning(Format('%d drawing records outside the safe subset',
[Scene.SkippedDrawRecords]));
for I := 0 to Scene.Count - 1 do
case Scene.Commands[I].Kind of
xlsvcRectangle: DrawRect(Scene.Commands[I]);
xlsvcEllipse: DrawEllipse(Scene.Commands[I]);
xlsvcPolyline,
xlsvcPolygon,
xlsvcBezier: DrawPath(Scene.Commands[I]);
xlsvcText: DrawText(Scene.Commands[I]);
xlsvcImage: DrawImage(Scene.Commands[I]);
end;
finally
Scene.Free;
end;
end;
Zapis komande nosi sve što backend traži i ništa što traži uređaj: prisustvo pera, boju, širinu i stil; prisustvo četke i boju; geometriju; i za tekst niz znakova, ime fonta, veličinu, stilove i poravnanje. To je ono što čini istu scenu upotrebljivom i od prikaza na ekranu canvas renderera i od SVG pisca, i zato vektorski put ne divergira između pregleda i izvoza. Prikaz na ekranu sadržaja radnog lista opšte pokriven je u članku o prikazu prilagođenog VCL grid-a
Odbijanje slike ne oštećuje radnu svesku
Važno svojstvo ovog dizajna je da odbijeno dekodovanje pogađa samo prikaz. Prvobitni sadržaj ostaje u modelu, pa radna sveska koja se otvori i ponovo sačuva iznosi svoje slike metafajla bajt po bajt, bez obzira da li ih bezbedni dekoder mogao nacrtati. Postojeći ograničeni rasterski put takođe ostaje dostupan kao rezerva. Drugim rečima, strog parser kapijara šta se izvršava, ne šta se čuva, što je razlika koja dopušta bezbednosno motivisanu promenu da izađe bez pretvaranja u promenu sa gubitkom podataka
Rukovanje crtačkim objektima opšte, uključujući delove modela objekata koji prežive povratne puteve netaknuti, pokriveno je u članku o grafikonima, slikama i crtežima
Gde ovo ostavlja serversko raspoređivanje
Ako prikazujete radne sveske otpremljene od korisnika u servisu, praktičan položaj sada je branjiv: slike metafajla raščlanjuje kod koji možete revizirati, ograničen konstantama koje možete pročitati, i nikad nije predat grafičkom drajveru. Poštena napomena je pokrivenost. Kompleksni metafajlovi proizvedeni crtačkim alatima pogodiće brojač preskočenih zapisa, i odgovor na to je izneti brojač na videlo umesto tiho proširiti popis dozvoljenih. Slika koja se prikaže delimično i kaže to jest razgovor podrške; slika koja se prikaže pogrešno i ne kaže ništa izveštaj je o grešci od kupca
HotXLS rukuje XLS, XLSX, ODS i CSV nativno u Delphi-ju i C++Builder-u bez instaliranog Excel-a, i ista filozofija ograničenog parsiranja prolazi kroz slojeve kontejnera, formula i crteža. Detalji formata i bezbednosti navedeni su na stranici proizvoda HotXLS Delphi spreadsheet component