يمكن لمصنف Excel أن يحمل صور EMF وWMF، والطريقة الاعتيادية لرسم واحدة تسليم مسار البايتات إلى مشغل الملفات التعريفية في نظام التشغيل. وذلك قرار يستحق النظر فيه مباشرة: الملف التعريفي مسار أوامر متسلسل لواجهة رسم، وإعادة تشغيله تعني ترك ملف وصل عبر البريد الإلكتروني يقود مشغل الرسوميات. يسلك HotXLS الطريق الآخر. يحلل XLSDecodeVectorScene الملف التعريفي بنفسه، ويتحقق من الترويسة وكل حجم سجل ومجموع السجلات المصرح به والموضع التام لسجل نهاية الملف، ويرفض سجلات escape قاطعة، ويعيد TXLSVectorScene من أوامر رسم أولية يعيد مسارا Canvas وSVG تشغيلها عبر كودهما الخاص. ولا تدخل عملية تشغيل بالمشغل في أي نقطة
المقايضة هي تغطية مقابل احتواء. قائمة أوامر سماح موجهة نحو المستطيلات لن تعيد إنتاج كل ملف تعريفي يستطيع مصمم إنشاؤه، فيفيد المشهد بعدد سجلات الرسم التي لم يستطع تمثيلها ويقرر المستدع ماذا يفعل بشأنها. وبالنسبة لعملية خادم تصير مستندات لم تنشئها، تلك المقايضة هي الاتجاه الصحيح
لماذا يعد تشغيل الملف التعريفي ملائما سيئا للمدخلات غير الموثوقة؟
لأن الصيغة ليست صورة بل برنامج. مسار سجلات EMF يتحكم في كومة حالة سياق جهاز، ويخصص ويختار كائنات من جدول مقابض، ويمكن أن يحمل سجلات escape تمر حمولتها إلى مشغل أجهزة. وإعادة تشغيله تجرب مسارات في كومة رسوميات المنصة كتبت على افتراض أن الملف التعريفي جاء من تطبيق متعاون على الجهاز نفسه. وعندما يكون المدخل مرفق جدول بيانات فذلك الافتراض زال، ولا تفيد أي درجة من العناية داخل مكتبة جداول البيانات لأن المكتبة ليست المكون الذي يحلل
هذا هو الاستدلال نفسه الذي يحكم طبقة الحاوية. المصنف أرشيف ZIP، ويتحقق HotXLS من دليله المركزي بدل الوثوق بالإزاحات المصرح بها، كما هو موصوف في مقال التحقق من نهاية الدليل المركزي لـ ZIP. وحمولات الملفات التعريفية هي الطبقة التالية من المشكلة نفسها
ماذا يفحص المفكك قبل أن يرسم شيئا
التحقق بنيوي ويحدث في البداية، لأن محللا يبدأ الرسم ويتحقق أثناء السير قد تصرف أصلا على بيانات لم يتحقق منها. يجب أن تطابق الترويسة بدقة لا بشكل معقول. وكل سجل يجب أن يصرح بحجم يتسع في المخزن المؤقت المتبقي وكبير بما يكفي لحقوله الثابتة الخاصة. وعدد السجلات الذي تصرح به الترويسة يجب أن يطابق السجلات الحاضرة فعلا. وسجل نهاية الملف يجب أن يجلس بالضبط حيث ينتهي المسار، لا في مكان قريب منه فقط، وهو ما يسد حيلة القمامة اللاحقة التي تخفي حمولة ثانية خلف صورة صحيحة
وفيما وراء البنية، المفكك يفشل بإغلاق في الدلالات. سجلات escape ترفض ولا تتخطى. وسجل يغير حالة لا يجسده المفكك يجعل الفك يفشل بدل تجاهله، لأن تجاهل تغيير حالة يعني أن كل أمر رسم لاحق ينفذ في حالة لم يطلبها الملف، والنتيجة صورة خاطئة بطريقة لا يستطيع أحد التنبؤ بها. أما سجلات الرسم خارج مجموعة الأوامر المدعومة فمختلفة: تلك تعد وتتخطى، لأن الشكل المفقود فجوة مرئية قابلة للإبلاغ لا فسادا صامتا
الميزانيات جزء من عقد الصيغة
صيغ المتجهات لها نسختها من قنبلة فك الضغط. بضعة كيلوبايتات من السجلات يمكن أن تصرح بخطوط متعددة بمئات ملايين النقاط، أو بصورة تتضاعف أبعادها المصرح بها إلى تيرابايتات. لذا يجب أن تكون الحدود ثوابت صريحة لا أي شيء يصمد عليه الجهاز مصادفة
// من lxVectorScene: ميزانية الفك، مصرح بها لا مضمرة
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;
اثنان من هذه يستحقان ملاحظة. سقف عمق سياق الجهاز البالغ 32 موجود لأن سجلات SaveDC وRestoreDC تتداخل، ومسار غير متوازن يمكن أن يدفع إلى الأبد؛ و32 سخية للملفات التعريفية الحقيقية ورخيصة الفرض. وسقف الإحداثيات موجود لأن الإحداثيات تغذي تحويلا، والقيمة قرب حدود المدى الصحيح تنتج نتيجة محولة لا نهائية أو ملتفة، وبعدها يكون كل حساب صندوق محيط لاحقا كلاما بلا معنى. وتثبيت الإحداثيات وقت التحليل أسهل في الاستدلال بكثير من الدفاع عن كل مستهلك للهندسة
استخدام المشهد
يسلّم المفكك كائنا تملكه، وعدد أوامر، وحجما اسميا، وعدد سجلات رسم اختار ألا يمثلها
uses
lxVectorScene;
var
Scene: TXLSVectorScene;
Error: WideString;
I: Integer;
begin
// تحمل Data حمولة الصورة الخام المأخوذة من المصنف
if not XLSDecodeVectorScene(Data, xlsvfEmf, Scene, Error) then
begin
// مرفوض: ترويسة أو حدود أو مجاميع أو موضع نهاية الملف أو ميزانية
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;
سجل الأمر يحمل كل ما يحتاجه مسار خلفي ولا شيء يتطلب جهازا: حضور القلم ولونه وعرضه ونمطه؛ وحضور الفرشاة ولونها؛ والهندسة؛ وللنص السلسلة واسم الخط والحجم والأنماط والمحاذاة. ذلك ما يجعل المشهد نفسه قابلا للاستخدام من مصيّر لوحة الرسم على الشاشة وكاتب SVG معا، وهو سبب عدم انحراف مسار المتجهات بين المعاينة والتصدير. والتصيير الشاشي لمحتوى أوراق العمل عموما مشمول في مقال تصيير شبكة VCL المخصصة
رفض صورة لا يضر المصنف
خاصية مهمة لهذا التصميم أن الفك المرفوض يؤثر في التصيير فقط. تبقى الحمولة الأصلية في النموذج، فيحمل المصنف الذي يفتح ويحفظ مرة أخرى صوره التعريفية بايتا ببايت، سواء استطاع المفكك الآمن رسمها أم لا. ويظل مسار الرسم النقطي المحدود القائم متاحا كبديل. بعبارة أخرى، المحلل الصارم يحصن ما ينفذ لا ما يحفظ، وهذا هو التمييز الذي يتيح لتغيير بدافع أمن أن يشحن دون أن يتحول إلى تغيير يفقد بيانات
معالجة كائنات الرسم عموما، بما فيها أجزاء نموذج الكائنات التي تنجو من ذهاب وإياب دون مساس، مشمولة في مقال المخططات والصور والرسومات
ماذا يترك هذا لنشر خادمي
إن كنت تصير مصنفات رفعتها المستخدمون في خدمة، فالموقف العملي صار قابلا للدفاع عنه: صور الملفات التعريفية تحلل بكود يمكنك تدقيقه، وتحد بثوابت يمكنك قراءتها، ولا تسلم أبدا إلى مشغل رسوميات. والتحذير الصادق هو التغطية. الملفات التعريفية المعقدة المنتجة بأدوات الرسم ستضرب عداد السجلات المتخطاة، والجواب عن ذلك إظهار العداد لا توسيع قائمة السماح بهدوء. صورة ترسم جزئيا وتقول ذلك محادثة دعم؛ وصورة ترسم خطأ ولا تقول شيئا تقرير عيب من عميل
يعالج HotXLS صيغ XLS وXLSX وODS وCSV أصليا في Delphi وC++Builder دون Excel مثبتا، ويفوق فلسفة التحليل المحدود نفسها طبقات الحاوية والصيغ والرسم لديه. وتفاصيل الصيغ والأمان مدرجة في صفحة منتج HotXLS Delphi spreadsheet component