Teknik Makale

HotXLS'te Güvenilmeyen EMF ve WMF'yi Güvenle Oynatmak

Bir Excel çalışma kitabı EMF ve WMF resimleri taşıyabilir ve birini çizmenin alışılmış yolu, bayt akışını işletim sisteminin metafile oynatıcısına teslim etmektir. Bu, doğrudan bakmaya değer bir karardır: bir metafile, bir grafik API'si için serileştirilmiş komut akışıdır ve birini oynatmak, e-postayla gelmiş bir dosyanın grafik sürücüsünü kullanmasına izin vermek demektir. HotXLS diğer yolu izler. XLSDecodeVectorScene metafile'ın kendisini ayrıştırır; başlığı, her kayıt boyutunu, bildirilen kayıt toplamını ve dosya sonu kaydının tam yerini doğrular, escape kayıtlarını düpedüz reddeder ve Canvas ile SVG arka uçlarının kendi kodlarıyla yeniden oynattığı ilkel çizim komutlarından oluşan bir TXLSVectorScene döndürür. Hiçbir noktada sürücü oynatımı devrede değildir

HotXLS, güvenilmeyen EMF ve WMF çalışma sayfası baytlarını XLSDecodeVectorScene ile GDI metafile oynatımı yerine bir TXLSVectorScene komut listesine ayrıştırır
HotXLS metafile'ın kendisini ayrıştırır ve Canvas ile SVG oynatımı için ilkel komutlar döndürür; alışılmış yol, bayt akışını grafik yığını üzerinde çalıştırır

Takas, kapsamın korunma karşılığında verilmesidir. Dikdörtgen yönelimli bir komut beyaz listesi, bir tasarımcının üretebileceği her metafile'ı yeniden üretmez; dolayısıyla sahne, temsil edemediği çizim kayıtlarının sayısını bildirir ve ne yapılacağına çağıran karar verir. Üretmediği belgeleri çizen bir sunucu işlemi için o takas, doğru yönde kurulmuş olandır

Metafile oynatımı güvenilmeyen girdiye neden uymaz?

Çünkü biçim bir resim değildir, bir programdır. Bir EMF kayıt akışı, aygıt bağlamı durum yığınını yönetir, tanıtıcı tablosundan nesneler ayırır ve seçer ve yükü bir aygıt sürücüsüne geçirilebilen escape kayıtları taşıyabilir. Onu oynatmak, metafile'ın aynı makinede işbirliği yapan bir uygulamadan geldiği varsayımıyla yazılmış platform grafik yığınındaki yolları çalıştırır. Girdi bir elektronik tablo eki olduğunda o varsayım yoktur ve elektronik tablo kitaplığının içindeki hiçbir özen yardımcı olmaz, çünkü ayrıştırmayı yapan bileşen kitaplık değildir

Bu, kapsayıcı katmanını yöneten akılın aynısıdır. Bir çalışma kitabı bir ZIP arşividir ve HotXLS, bildirilen ofsetlere güvenmek yerine merkezi dizini doğrular; ZIP merkezi dizin sonu doğrulaması makalesinde anlatıldığı gibi. Metafile yükleri, aynı sorunun sonraki katmanıdır

Kod çözücü hiçbir şey çizmeden önce neyi denetler

Doğrulama yapısaldır ve en başta gerçekleşir; çünkü çizmeye başlayıp gittiği yerde doğrulayan bir ayrıştırıcı, doğrulamadığı veri üzerine hareket etmiş olur. Başlık, inandırıcı olmak yerine kesin örtüşmelidir. Her kayıt, kalan tamponun içine sığan ve kendi sabit alanlarına yetecek kadar büyük bir boyut bildirmelidir. Başlığın bildirdiği kayıt sayısı, gerçekte bulunan kayıtlarla örtüşmelidir. Dosya sonu kaydı, akışın bittiği tam yerde oturmalıdır; yalnızca ona yakın bir yerde değil. Bu, geçerli bir resmin arkasına ikinci bir yük saklayan sondaki çöp hilesini kapatır

Yapının ötesinde kod çözücü, anlamda başarısız kapalıdır. Escape kayıtları atlanmaz, reddedilir. Kod çözücünün modellemediği durum değiştiren bir kayıt, yok sayılmak yerine kod çözmeyi başarısız kılar; çünkü bir durum değişikliğini yok saymak, sonraki her çizim komutunun dosyanın istemediği bir durumda çalıştırılması demektir ve sonuç, kimsenin öngöremeyeceği bir şekilde yanlış bir resimdir. Desteklenen komut kümesinin dışındaki çizim kayıtları başka konudur: onlar sayılır ve atlanır; çünkü eksik bir şekil, sessiz bir bozulma değil görünür ve bildirilebilir bir boşluktur

XLSDecodeVectorScene, başlığı, kayıt boyutlarını, toplamları ve EOF yerini en başta denetler; sonra escape kayıtlarını reddeder ve desteklenmeyen çizim kayıtlarını sayar
Yapısal denetimler en başta çalışır ve başarısız kapalı anlam, escape kayıtlarını reddeder; desteklenmeyen çizim kayıtları ise yalnızca sayılır ve atlanır

Bütçeler biçim sözleşmesinin parçasıdır

Vektör biçimlerinin sıkıştırma bombasının kendi sürümü vardır. Birkaç kilobaytlık kayıt, yüz milyonlarca noktalı çoklu çizgiler ya da bildirilen boyutları terabaytlara çarpan bir görüntü beyan edebilir. Bu nedenle sınırlar, makinenin tesadüfen dayanabildiği şey değil açık sabitler olmak zorundadır

// lxVectorScene'den: kod çözme bütçesi, ima edilmek yerine açıkça
// belirtilmiş
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;

Bunlardan ikisi notu hak eder. 32'lik aygıt bağlamı derinlik sınırı, SaveDC ile RestoreDC kayıtlarının iç içe geçmesi ve dengesiz bir akışın sonsuza dek itebileceği için vardır; 32 gerçek metafile'lar için cömerttir ve uygulamaya alması ucuzdur. Koordinat sınırı, koordinatların bir dönüşümü beslemesi ve tamsayı aralığının sınırlarına yakın bir değerin ya sonsuz ya da taşan bir dönüştürülmüş sonuç üretmesi ve ondan sonra aşağı akıştaki her sınırlayıcı kutu hesabının saçmalaması için vardır. Koordinatları ayrıştırma anında sıkıştırmak, geometrinin her tüketicisini savunmaktan çok daha kolay akıl yürütülebilir olandır

HotXLS lxVectorScene'de kayıtlar, tanıtıcılar, DC derinliği, komutlar, noktalar, metin, görüntü boyutu ve koordinat sıkıştırma için kod çözme bütçesi sabitleri
Her sınır, ayrıştırma sırasında uygulanan adlandırılmış bir sabittir; DC derinlik sınırı ve koordinat sıkıştırması en çok dikkat hak eder

Sahneyi kullanmak

Kod çözücü, size ait bir nesneyi, bir komut sayısını, nominal bir boyutu ve temsil etmeyi seçmediği çizim kayıtlarının sayısını geri verir

uses
  lxVectorScene;

var
  Scene: TXLSVectorScene;
  Error: WideString;
  I: Integer;
begin
  // Data, çalışma kitabından alınan ham resim yükünü tutar
  if not XLSDecodeVectorScene(Data, xlsvfEmf, Scene, Error) then
  begin
    // Reddedildi: başlık, sınırlar, toplamlar, EOF yeri ya da bir bütçe
    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;

Komut kaydı, bir arka ucun ihtiyaç duyduğu her şeyi taşır ve bir aygıt gerektiren hiçbir şey taşımaz: kalem varlığı, renk, genişlik ve stil; fırça varlığı ve rengi; geometri; ve metin için dize, font adı, boyut, stiller ve hizalama. Aynı sahneyi hem ekran üstü canvas çizicinin hem SVG yazıcının kullanılabilir kılan budur ve vektör yolunun önizleme ile dışa aktarma arasında ayrışmamasının nedeni de budur. Çalışma sayfası içeriğinin ekran çizimi genel olarak özel VCL grid çizimi makalesinde kapsanır

Bir resmi reddetmek çalışma kitabına zarar vermez

Bu tasarımın önemli bir özelliği, reddedilen kod çözmünün yalnızca çizimi etkilemesidir. Özgün yük modelde kalır; dolayısıyla açılıp yeniden kaydedilen bir çalışma kitabı, metafile resimlerini güvenli kod çözücü çizebilse de çizemese de bayt bayt taşır. Mevcut sınırlı raster yolu da bir geri düşme olarak kullanılabilir kalmaya devam eder. Başka bir deyişle katı ayrıştırıcı, yürütüleni değil saklananı kapılar; bu, güvenlik motivasyonlu bir değişikliğin veri kaybı değişikliğine dönüşmeden gönderilebilmesini sağlayan ayrımdır

Gidiş dönüşleri dokunulmadan atlatan nesne modeli bölümleri dahil, çizim nesnesi ele alma genel olarak grafikler, görüntüler ve çizimler makalesinde kapsanır

Bunun bir sunucu dağıtımında bıraktığı yer

Kullanıcı yüklemeli çalışma kitaplarını bir hizmette çiziyorsanız pratik konum artık savunulabilirdir: metafile resimleri denetleyebileceğiniz kodla ayrıştırılır, okuyabileceğiniz sabitlerle sınırlanır ve hiçbir zaman bir grafik sürücüsüne teslim edilmez. Dürüst uyarı kapsamdır. Çizim araçlarının ürettiği karmaşık metafile'lar atlanan kayıt sayacına takılacaktır ve bunun cevabı, beyaz listeyi sessizce genişletmek değil sayacı görünür kılmaktır. Kısmen çizilen ve bunu söyleyen bir resim bir destek görüşmesidir; yanlış çizilen ve hiçbir şey söylemeyen bir resim müşteriden bir hata raporudur

HotXLS, XLS, XLSX, ODS ve CSV'yi Excel kurulu olmadan Delphi ve C++Builder'da yerel olarak ele alır ve aynı sınırlı ayrıştırma felsefesi kapsayıcı, formül ve çizim katmanlarında boyunca akar. Biçim ve güvenlik ayrıntıları HotXLS Delphi spreadsheet component ürün sayfasında listelenir