如何在文件的一部分上使用DeflateStream? [英] How do you use a DeflateStream on part of a file?

查看:179
本文介绍了如何在文件的一部分上使用DeflateStream?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在努力解决我的其他问题,这是一个阅读PNG的'zTXt'块中的数据。我只要在文件中找到这些块,并读取zTXt的关键字。我无法读取zTXt的压缩部分。我从来没有使用过DeflateStream对象,我有一些麻烦。当读取时,看起来期望length参数处于未压缩字节。然而,在我的情况下,我只知道数据的长度压缩字节。为了避免这种情况,我把所有需要解压缩的数据放入MemoryStream,然后用DeflateStream读取到结束。现在只是peachy,除了它抛出一个InvalidDataException与消息块长度不匹配其补码。现在我不知道这是什么意思。可能会出错?

I'm working on a solution to my other question which is reading the data in the 'zTXt' chunks of a PNG. I am as far as locating the chunks in the file, and reading the zTXt's keyword. I'm having trouble reading the compressed portion of zTXt. I've never worked with the DeflateStream object before, and am having some trouble with it. When reading, it appears to expect the length parameter to be in 'uncompressed' bytes. In my case however, I only know the length of the data in 'compressed' bytes. To hopefully get around this, I put all the data that needed to be decompressed into a MemoryStream, and then 'read to end' with a DeflateStream. Now that's just peachy, except it throws an InvalidDataException with the message "Block length does not match with its complement." Now I have no idea what this means. What could be going wrong?

一个块的格式是4个字节的ID(zTXt),一个大端序32位int数据长度,数据和最后一个我现在忽略的CRC32校验和。

The format of a chunk is 4 bytes for the ID ("zTXt"), a big-endian 32-bit int for the data length, the data, and finally a CRC32 checksum which I am ignoring for now.

zTXt块的格式首先是一个以null结束的字符串然后一个字节用于压缩方法(总是0,DEFLATE方法),其余数据是压缩文本。

The format of the zTXt chunk is first a null-terminated (string as a keyword), then one byte for the compression method (always 0, the DEFLATE method), with the rest of the data being compressed text.

我的方法接收一个新的FileStream,

My method takes in a fresh FileStream, and returns a dictionary with the zTXt keywords and data.

现在是怪物:

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;
}

一旦这个问题得到解决,我需要写一个函数ADDS这些zTXt块到文件。所以希望我能理解DeflateStream如何工作一旦这个问题解决了。

Once this is tackled, I'll need to write a function that ADDS these zTXt chunks to the file. So hopefully I'll understand how the DeflateStream works once this is solved.

谢谢,很多!!

推荐答案

毕竟这一次,我终于找到了问题。数据采用zlib格式,其中存储的数据比仅使用DEFLATE多一点。

After all this time, I've finally found the problem. The data is in zlib format, which has a bit more data stored than just using DEFLATE alone. The file is read properly if I just read the 2 extra bytes in right before I get the compressed data.

请参阅此反馈页面。 (我没有提交那个。)

See this feedback page. (I did not submit that one.)

我现在在想。这两个字节的值分别为0x78和0x9C。如果我发现除这些之外的值,我应该假设DEFLATE将失败?

I'm wondering now. The value of those two bytes are 0x78 and 0x9C respectively. If I find values other than those, should I assume the DEFLATE is going to fail?

这篇关于如何在文件的一部分上使用DeflateStream?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆