Műszaki cikk

Nem megbízható EMF/WMF biztonságos visszajátszása HotXLS-ben

Egy Excel munkafüzet hordozhat EMF és WMF képeket, és a hagyományos mód annak kirajzolására az, hogy a bájtfolyamot az operációs rendszer metafájl-lejátszójára bízzák. Ez egy döntés, amelyet érdemes közvetlenül megnézni: egy metafájl egy grafikai API szerializált parancsfolyama, és egy visszajátszása azt jelenti, hogy egy e-mailen érkező fájl hajtja a grafikusillesztőt. A HotXLS a másik utat választja. A XLSDecodeVectorScene maga elemzi a metafájlt, szigorúan ellenőrzi a fejlécet, minden rekordméretet, a deklarált rekordösszesítést és a fájlvégi rekord pontos helyét, laposan elutasítja az escape rekordokat, és egy TXLSVectorScene primitív rajzolási parancsokat ad vissza, amelyeket a Canvas és SVG backendek a saját kódjukon keresztül játszanak vissza. Illesztővisszajátszás egyetlen ponton sem fordul elő

A HotXLS a nem megbízható EMF és WMF munkalap bájtokat az XLSDecodeVectorScene-mel TXLSVectorScene parancslistává elemzi GDI metafájl-visszajátszás helyett
A HotXLS maga elemzi a metafájlt, és primitív parancsokat ad vissza Canvas és SVG visszajátszáshoz; a hagyományos út a bájtfolyamot hajtja végre a grafikai veremen

Az alku a lefedettség a befoglalásért. Egy téglalap-orientált parancsfehérlista nem reprodukál minden metafájlt, amelyet egy tervező előállíthat, tehát a jelenet megmondja, hány rajzolási rekordot nem tudott ábrázolni, és a hívó dönt arról, mit tesz. Egy kiszolgálói folyamat számára, amely olyan dokumentumokat renderel, amelyeket nem ő hozott létre, az az alku a helyes irányú

Miért rosszul illik a metafájl-visszajátszás a nem megbízható bemenethez?

Mert a formátum nem kép, hanem program. Egy EMF rekordfolyam eszközkontextus állapotveremet manipulál, objektumokat foglal le és választ ki egy handletáblából, és hordozhat olyan escape rekordokat, amelyek hasznos terhe az eszközillesztőhöz továbbítódik. A visszajátszása olyan utakat gyakorol a platform grafikai veremében, amelyeket azzal a feltételezéssel írtak, hogy a metafájl együttműködő alkalmazástól származik ugyanazon a gépen. Amikor a bemenet egy táblázatmelléklet, az a feltételezés elvész, és a táblázatfüggvénytáron belüli gondosság semmilyen mennyisége sem segít, mert a függvénytár nem az a komponens, amely az elemzést végzi

Ez ugyanaz az érvelés, amely a tárolóréteget kormányozza. Egy munkafüzet ZIP archívum, és a HotXLS a központi könyvtárát ellenőrzi, nem a deklarált offsetekbe bízva, ahogyan azt a ZIP end-of-central-directory ellenőrzési cikk leírja. A metafájlhasznos terhek ugyanazon probléma következő rétege

Mit ellenőriz a dekódoló, mielőtt bármit rajzolna

Az ellenőrzés strukturális, és előre megtörténik, mert egy olyan elemző, amely elkezdi a rajzolást, és menet közben ellenőriz, már cselekedett olyan adatokon, amelyeket nem erősített meg. A fejlécnek szigorúan, nem hihetően kell egyeznie. Minden rekordnak olyan méretet kell deklarálnia, amely a maradék pufferbe belefér, és elég nagy a saját rögzített mezőihez. A fejléc által deklarált rekordszámnak egyeznie kell a ténylegesen jelen lévő rekordokkal. A fájlvégi rekordnak pontosan ott kell ülnie, ahol a folyam ér véget, nem csupán valahol a közelében, ami bezárja a záró szemét csínát, amely egy érvényes kép mögé rejt egy második hasznos terhet

A struktúrán túl a dekódoló a szemantika terén zártan hibázik. Az escape rekordok elutasításra kerülnek, nem kihagyásra. Egy állapotot változtató rekord, amelyet a dekódoló nem modellez, a dekódolás megbukását okozza, nem figyelmen kívül hagyásra kerül, mert egy állapotváltozás figyelmen kívül hagyása azt jelenti, hogy minden későbbi rajzolási parancs olyan állapotban hajtódik végre, amelyet a fájl nem kért, és az eredmény olyan kép, amely senki által előre nem látható módon rossz. A támogatott parancskészleten kívüli rajzolási rekordok más kérdés: azokat megszámolják és kihagyják, mert egy hiányzó alak látható, jelenthető rés, nem csendes rongálás

Az XLSDecodeVectorScene előre ellenőrzi a fejlécet, a rekordméreteket, az összesítéseket és az EOF helyét, majd elutasítja az escape rekordokat, és megszámolja a nem támogatott rajzrekordokat
A strukturális ellenőrzések előre futnak, és a zártan hibázó szemantika elutasítja az escape rekordokat, míg a nem támogatott rajzrekordokat csak megszámolják és kihagyják

A korlátok a formátumszerződés részei

A vektorformátumoknak megvan a kitömörítési bombának a saját változata. Néhány kilobájt rekord százzmilliós pontszámú vonalláncokat deklarálhat, vagy olyan képet, amelynek deklarált méretei terabájtokká szorzódnak. A határoknak ezért explicit konstansoknak kell lenniük, nem pedig annak, amivel a gép éppen túléli

// Az lxVectorScene-ből: a dekódolási korlát, kimondva, nem sugallva
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;

Kettő közülük megjegyzést érdemel. Az eszközkontextus 32-es mélységi korlátja azért létezik, mert a SaveDC és RestoreDC rekordok egymásba ágyazódnak, és egy kiegyensúlyozatlan folyam örökké tolhat; 32 nagylelkű a valós metafájlokra és olcsó érvényesíteni. A koordinátakorlát azért létezik, mert a koordináták transzformációt táplálnak, és az egész tartomány határaihoz közeli érték végtelenné vagy körbefordulóvá vált transzformált eredményt ad, amely után minden lefelé irányuló befoglaló doboz számítás értelmetlen. A koordináták elemzéskori szorítása sokkal könnyebben átgondolható, mint a geometria minden fogyasztójának megvédése

Dekódolási korlát konstansok a HotXLS lxVectorScene-ben: rekordok, handelek, DC mélység, parancsok, pontok, szöveg, kép méret és koordináta-szorítás
Minden határ nevesített konstans, amelyet az elemzés során érvényesítenek; a DC mélységi korlát és a koordináta-szorítás érdemli a legtöbb figyelmet

A jelenet használata

A dekódoló egy Ön birtokába kerülő objektumot ad vissza, parancsszámot, névleges méretet, és azoknak a rajzolási rekordoknak a számát, amelyeket nem választott ábrázolásra

uses
  lxVectorScene;

var
  Scene: TXLSVectorScene;
  Error: WideString;
  I: Integer;
begin
  // A Data hordozza a munkafüzetből vett nyers képhasznos terhet
  if not XLSDecodeVectorScene(Data, xlsvfEmf, Scene, Error) then
  begin
    // Elutasítva: fejléc, határok, összesítések, EOF hely vagy korlát
    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;

A parancsrekord mindent hordoz, amire egy backendnek szüksége van, és semmit, ami eszközt igényelne: toll jelenlétét, színét, szélességét és stílusát; ecset jelenlétét és színét; a geometriát; és szövegre a karakterláncot, a betűnevet, a méretet, a stílusokat és az igazítást. Az teszi ugyanazt a jelenetet használhatóvá a képernyővászon-renderelő és az SVG író számára egyaránt, és ez az ok, amiért a vektorút nem ágazik szét előnézet és export között. A munkalaptartalom képernyőrenderelését általában a egyéni VCL rács renderelési cikk tárgyalja

Egy kép elutasítása nem rongálja a munkafüzetet

Ennek a tervnek fontos tulajdonsága az, hogy egy elutasított dekódolás csak a renderelést érinti. Az eredeti hasznos teher a modellben marad, tehát egy megnyitott és újból mentett munkafüzet a metafájlképeit bájtonként viszi ki, akár tudta őket rajzolni a biztonságos dekódoló, akár nem. A meglévő határolt raszteres út is elérhető marad tartalékként. Más szóval a szigorú elemző azt kapuzza, ami végrehajtódik, nem azt, ami megőrződik, és ez az a megkülönböztetés, amely lehetővé teszi, hogy egy biztonsági motivációjú változtatás adatvesztéssé válás nélkül kerüljön kiadásra

A rajzobjektumok kezelése általában, beleértve az objektummodell azon részeit, amelyek érintetlenül élik túl az oda-vissza utakat, a diagramok, képek és rajzok cikkben van tárgyalva

Hol hagyja ezt egy kiszolgálói telepítést

Ha felhasználók által feltöltött munkafüzeteket renderel szolgáltatásban, a gyakorlati álláspont most védhető: a metafájlképeket olyan kód elemzi, amelyet auditálhat, olyan konstansok határolnak, amelyeket elolvashat, és soha nem kerül grafikusillesztőre bízásra. Az őszinte megjegyzés a lefedettség. A rajzeszközök által előállított összetett metafájlok a kihagyott rekord számlálójának fognak nekimenni, és arra a válasz az, hogy a számlálót hozza felszínre, nem pedig csendben szélesítse a fehérlistát. Egy kép, amely részben renderel és ezt elmondja, támogatási beszélgetés; egy kép, amely rosszul renderel és nem szól, ügyfél hibajelentés

A HotXLS natívan kezeli az XLS, XLSX, ODS és CSV formátumokat Delphi és C++Builder alatt Excel telepítése nélkül, és ugyanaz a határolt elemzési filozófia fut át a tároló-, képlet- és rajzrétegein. A formátum- és biztonsági részletek a HotXLS Delphi spreadsheet component terméklapon találhatók