سؤال

أنا أعمل على حل ل سؤالي الآخر الذي يقرأ البيانات في قطع "ZTXT" من PNG. أنا بقدر تحديد موقع القطع في الملف، وقراءة الكلمة الرئيسية ZTXT. أواجه مشكلة في قراءة الجزء المضغوط من ZTXT. لم أعمل أبدا مع كائن Deflatestream من قبل، وأوجه بعض المتاعب معها. عند القراءة، يبدو أنه يتوقع أن تكون المعلمة الطول في بايت "غير مضغوط". ومع ذلك، في حالتي، أعرف فقط طول البيانات في بايت "مضغوط". نأمل أن نتجول في هذا، أضع كل البيانات التي تحتاج إلى إلغاء ضغطها في موعد للهاتف، ثم "قراءة إلى النهاية" مع deflatestream. الآن هذا مجرد خلفي، باستثناء أنه يرمي InvalidDataException مع الرسالة "طول الكتلة لا يتطابق مع تكمله." الآن ليس لدي أي فكرة عما يعنيه هذا. ماذا يمكن أن يحدث خطأ؟

تنسيق الجزء من قطعة 4 بايت للمعرف ("ZTXT")، وهو Intian 32 بت كبير لطول البيانات، والبيانات، وأخيرا المجموع الاختباري CRC32 الذي أتجاهىه الآن.

هو تنسيق جزء ZTXT هو أول (سلسلة ككلمة رئيسية)، ثم بايت واحدة لطريقة الضغط (دائما 0، طريقة الانفصال)، مع بقية البيانات التي يتم ضغط النص.

تأخذ طريقتي في Fresh FileStream، وإرجاع القاموس مع الكلمات الرئيسية ZTXT والبيانات.

هنا الوحش الآن:

public static List<KeyValuePair<string, string>> GetZtxt(FileStream stream)
{
    var ret = new List<KeyValuePair<string, string>>();
    try {
        stream.Position = 0;
        var br = new BinaryReader(stream, Encoding.ASCII);
        var head = br.ReadBytes(8); // The header is the same for all PNGs.
        if (!head.SequenceEqual(new byte[] { 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A })) return null; // Not a PNG.
        while (stream.Position < stream.Length) {
            int len; // Length of chunk data.
            if (BitConverter.IsLittleEndian)
                len = BitConverter.ToInt32(br.ReadBytes(4).Reverse().ToArray(), 0);
            else
                len = br.ReadInt32();

            char[] cName = br.ReadChars(4); // The chunk type.
            if (cName.SequenceEqual(new[] { 'z', 'T', 'X', 't' })) {
                var sb = new StringBuilder(); // Builds the null-terminated keyword associated with the chunk.
                char c = br.ReadChar();
                do {
                    sb.Append(c);
                    c = br.ReadChar();
                }
                while (c != '\0');
                byte method = br.ReadByte(); // The compression method.  Should always be 0. (DEFLATE method.)
                if (method != 0) {
                    stream.Seek(len - sb.Length + 3, SeekOrigin.Current); // If not 0, skip the rest of the chunk.
                    continue;
                }
                var data = br.ReadBytes(len - sb.Length - 1); // Rest of the chunk data...
                var ms = new MemoryStream(data, 0, data.Length); // ...in a MemoryStream...
                var ds = new DeflateStream(ms, CompressionMode.Decompress); // ...read by a DeflateStream...
                var sr = new StreamReader(ds); // ... and a StreamReader.  Yeesh.
                var str = sr.ReadToEnd(); // !!! InvalidDataException !!!
                ret.Add(new KeyValuePair<string, string>(sb.ToString(), str));
                stream.Seek(4, SeekOrigin.Current); // Skip the CRC check.
            }
            else {
                stream.Seek(len + 4, SeekOrigin.Current); // Skip the rest of the chunk.
            }
        }
    }
    catch (IOException) { }
    catch (InvalidDataException) { }
    catch (ArgumentOutOfRangeException) { }
    return ret;
}

بمجرد تناول هذا، سأحتاج إلى كتابة وظيفة تضيف قطع ZTXT هذه إلى الملف. لذلك نأمل أن أفهم كيف يعمل deflatestream مرة واحدة تم حل هذا.

شكرا جزيلا!!

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

المحلول

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

يرى صفحة ملاحظات هذه. وبعد (لم أقدم ذلك.)

أنا أتساءل الآن. قيمة هذين البايتين هي 0x78 و 0x9c على التوالي. إذا وجدت قيما بخلاف تلك، هل يجب أن أفشل الانكماش هو فشل؟

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