سؤال

أتلقى بعض ملفات XML مع صور مضمنة BASE64 المشفرة ، والتي أحتاج إلى فك تشفيرها وحفظها كملفات.

يمكن تنزيل مثال غير معدّل (بخلاف مضغوط) لمثل هذا الملف أدناه:

20091123-125320.zip (60 كيلو بايت)

ومع ذلك ، أحصل على أخطاء مثل "الطول غير الصحيح لمصفوفة char base-64" و "الحرف غير صالح في سلسلة BASE-64". قمت بتمييز السطر في الكود حيث أحصل على الخطأ في الكود.

يمكن أن يبدو ملف هكذا:

<?xml version="1.0" encoding="windows-1252"?>
<mediafiles>
    <media media-type="image">
      <media-reference mime-type="image/jpeg"/>
      <media-object encoding="base64"><![CDATA[/9j/4AAQ[...snip...]P4Vm9zOR//Z=]]></media-object>
      <media.caption>What up</media.caption>
    </media>
</mediafiles>

والرمز لمعالجة مثل هذا:

var xd = new XmlDocument();
xd.Load(filename);
var nodes = xd.GetElementsByTagName("media");

foreach (XmlNode node in nodes)
        {
            var mediaObjectNode = node.SelectSingleNode("media-object");
            //The line below is where the errors occur
            byte[] imageBytes = Convert.FromBase64String(mediaObjectNode.InnerText);
            //Do stuff with the bytearray to save the image
        }

إن XML -Data من نظام صحيفة Enterprise ، لذلك أنا متأكد تمامًا من أن الملفات على ما يرام - ويجب أن يكون هناك شيء في طريقة معالجتها ، وهذا خطأ. ربما مشكلة في الترميز؟

لقد حاولت كتابة محتويات MediaObjectNode.innertext ، وهي البيانات المشفرة Base64 - وبالتالي فإن التنقل في XML -DOC ليس هو المشكلة.

لقد كنت googling ، binging ، stackoverflowing والبكاء - ولم أجد أي حل ... مساعدة!

تعديل:

تمت إضافة ملف مثال فعلي (ومكافأة). يرجى ملاحظة أن الملف القابل للتنزيل في مخطط مختلف بعض الشيء ، حيث قمت بتبسيطه في المثال أعلاه ، وإزالة الأشياء غير ذات الصلة ...

هل كانت مفيدة؟

المحلول

للحصول على لقطة أولى ، لم أستخدم أي لغة برمجة ، فقط Notepad ++

لقد فتحت ملف XML داخل ونسخ محتوى RAW BASE64 ولصقه في ملف جديد (بدون أقواس مربعة).

بعد ذلك اخترت كل شيء (Strg -A) واستخدمت ملحقات الخيار - أدوات MIME - Decode BASE64. ألقى هذا خطأ حول طول النص الخطأ (يجب أن يكون Mod 4). لذلك أضفت للتو علامتين متساويتين ('=') كعنصر نائب في النهاية للحصول على الطول الصحيح.

إعادة محاكمة أخرى وفك تشفيرها بنجاح في "شيء ما". ما عليك سوى حفظ الملف كـ .jpg ويفتح مثل سحر في أي عارض صورة.

لذلك أود أن أقول ، هناك خطأ ما في البيانات التي ستحصل عليها. ليس لديهم فقط الأرقام المناسبة من العلامات المتساوية في النهاية لملء عدد من العلامات التي يمكن أن تقسم حزم 4.

تتمثل الطريقة "السهلة" في إضافة العلامة المتساوية حتى لا يرمي فك التشفير خطأً. تتمثل الطريقة الأفضل في حساب عدد الأحرف (ناقص CR/LFS!) وإضافة تلك المطلوبة في خطوة واحدة.

تحقيقات أخرى

بعد بعض الترميز وقراءة وظيفة التحويل, ، المشكلة هي ارتباط خاطئ لعلامة متساوية من المنتج. ليس لدى Notepad ++ مشكلة مع طن من العلامات المتساوية ، ولكن وظيفة التحويل من MS تعمل فقط مع صفر أو علامة أو اثنين. لذلك إذا قمت بملء واحدة موجودة بالفعل مع علامات متساوية إضافية ، فستحصل على خطأ أيضًا! للحصول على هذا الشيء اللعين للعمل ، يجب عليك قطع جميع العلامات الموجودة ، وحساب المبلغ المطلوب وإضافتها مرة أخرى.

فقط من أجل المكافأة ، إليك الكود الخاص بي (ليس مثاليًا مطلقًا ، ولكن يكفي لنقطة انطلاق جيدة): ؛-)

    static void Main(string[] args)
    {
        var elements = XElement
            .Load("test.xml")
            .XPathSelectElements("//media/media-object[@encoding='base64']");
        foreach (XElement element in elements)
        {
            var image = AnotherDecode64(element.Value);
        }
    }

    static byte[] AnotherDecode64(string base64Decoded)
    {
        string temp = base64Decoded.TrimEnd('=');
        int asciiChars = temp.Length - temp.Count(c => Char.IsWhiteSpace(c));
        switch (asciiChars % 4)
        {
            case 1:
                //This would always produce an exception!!
                //Regardless what (or what not) you attach to your string!
                //Better would be some kind of throw new Exception()
                return new byte[0];
            case 0:
                asciiChars = 0;
                break;
            case 2:
                asciiChars = 2;
                break;
            case 3:
                asciiChars = 1;
                break;
        }
        temp += new String('=', asciiChars);

        return Convert.FromBase64String(temp);
    }

نصائح أخرى

سلسلة BASE64 غير صالحة كما قال أوليفر بالفعل ، يجب أن يكون طول السلسلة مضاعفات 4 بعد إزالة أحرف المساحة البيضاء. إذا نظرت إلى نهاية سلسلة Base64 (انظر أدناه) ، فسترى أن الخط أقصر من الباقي.

RRRRRRRRRRRRRRRRRRRRRRRRRRRRX//Z=

إذا قمت بإزالة هذا السطر ، فسيعمل البرنامج ، لكن الصورة الناتجة سيكون لها قسم مفقود في الركن الأيمن السفلي. تحتاج إلى وضع هذا الخط بحيث يكون طول السلسلة الكلي هو corect. من الحسابات الخاصة بي إذا كان لديك 3 أحرف يجب أن تعمل.

RRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRX//Z=

قم بإزالة آخر 2 حرفًا بينما الصورة غير صحيحة

public Image Base64ToImage(string base64String)
    {
        // Convert Base64 String to byte[]
        byte[] imageBytes=null;
        bool iscatch=true;
        while(iscatch)
        {
            try 
                {           
         imageBytes = Convert.FromBase64String(base64String);
         iscatch = false;

            }
            catch 
            {
                int length=base64String.Length;
                base64String=base64String.Substring(0,length-2);
            }
        }
        MemoryStream ms = new MemoryStream(imageBytes, 0,
          imageBytes.Length);

        // Convert byte[] to Image
        ms.Write(imageBytes, 0, imageBytes.Length);
        Image image = Image.FromStream(ms, true);
        pictureBox1.Image = image;
        return image;
    }

حاول استخدام LINQ إلى XML:

using System.Xml.XPath;

class Program
{
    static void Main(string[] args)
    {
        var elements = XElement
            .Load("test.xml")
            .XPathSelectElements("//media/media-object[@encoding='base64']");
        foreach (var element in elements)
        {
            byte[] image = Convert.FromBase64String(element.Value);
        }
    }
}

تحديث:

بعد تنزيل ملف XML وتحليل قيمة media-object العقدة من الواضح أنها ليست سلسلة أساسية صالحة:

string value = "PUT HERE THE BASE64 STRING FROM THE XML WITHOUT THE NEW LINES";
byte[] image = Convert.FromBase64String(value);

رمي أ System.FormatException القول بأن الطول ليس سلسلة قاعدة 64 صالحة. الحدث عندما أقوم بإزالة \n من السلسلة لا تعمل:

var elements = XElement
    .Load("20091123-125320.xml")
    .XPathSelectElements("//media/media-object[@encoding='base64']");
foreach (var element in elements)
{
    string value = element.Value.Replace("\n", "");
    byte[] image = Convert.FromBase64String(value);
}

رمي أيضا System.FormatException.

لقد واجهت أيضًا مشكلة في فك تشفير BASE64 المشفرة من مستند XML (على وجه التحديد وثيقة حزمة Office OpenXML).

اتضح أن السلسلة قد تم تطبيق ترميز إضافي: ترميز HTML ، لذلك قم بفك تشفير HTML الأول ثم فك تشفير BASE64 فعل الخدعة:

private static byte[] DecodeHtmlBase64String(string value)
{
    return System.Convert.FromBase64String(System.Net.WebUtility.HtmlDecode(value));
}

فقط في حالة تعثر شخص آخر على نفس القضية.

حسنًا ، كل شيء بسيط للغاية. CDATA هي عقدة نفسها ، لذلك mediaObjectNode.InnerText في الواقع ينتج <![CDATA[/9j/4AAQ[...snip...]P4Vm9zOR//Z=]]>, ، والتي من الواضح أنها غير صالحة للبيانات التي ترميزها BASE64.

لجعل الأشياء تعمل ، استخدم mediaObjectNode.ChildNodes[0].Value وتمرير هذه القيمة إلى Convert.FromBase64String'.

هل تشفير الحرف صحيح؟ يبدو الخطأ وكأن هناك مشكلة تسبب ظهور أحرف غير صالحة في الصفيف. حاول نسخ النص وفك التشفير يدويًا لمعرفة ما إذا كانت البيانات صالحة بالفعل.

(بالنسبة للسجل ، لا يكون Windows-1252 هو نفسه تمامًا مثل ISO-8859-1 ، بحيث يكون سبب مشكلة ما ، باستثناء مصادر الفساد الأخرى.)

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top