在文件的一部分,你如何使用DeflateStream?如何使用、文件、DeflateStream

2023-09-04 00:59:41 作者:情感洁癖

我工作的一个解决方案,以我的其他问题被阅读在巴布亚新几内亚的zTXt块数据。我只要定位块在文件中,并读取zTXt的关键字。我有麻烦阅读zTXt的COM pressed部分。我从来没有过的DeflateStream对象之前,和我用起来有些麻烦。在读取时,它似乎期望长度参数是在uncom pressed'字节。就我而言不过,我只知道数据的COM pressed'字节长度。怀着希望去解决这个问题,我把所有需要的是DECOM pressed到MemoryStream,然后将数据读来结束'了DeflateStream。现在,这只是桃色,但它引发的消息的InvalidDataException块长度不与它的补相匹配。现在,我不知道这意味着什么。可能是什么问题呢?

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

在zTXt块的格式是第一个空值终止(字符串作为关键字),那么一个字节为COM pression方法(始终为0,放气的方法),以作为其他数据COM pressed文本。

我的方法需要在一个新的FileStream,并返回一个字典的zTXt关键字和数据。

下面是怪物现在:

 公共静态列表< KeyValuePair<字符串,字符串>> GetZtxt(的FileStream流)
{
    VAR RET =新的名单,其中,KeyValuePair<字符串,字符串>>();
    尝试 {
        stream.Position = 0;
        变种BR = BinaryReader在新的(流Encoding.ASCII);
        VAR头= br.ReadBytes(8); //标题是相同的所有PNG格式。
        如果返回NULL(head.SequenceEqual(新的byte [] {0x89上,为0x50,0x4E,0X47,0X0D,0x0A的,0x1A的,的0x0A})!); //不是PNG。
        而(stream.Position< stream.Length){
            INT LEN; //块数据的长度。
            如果(BitConverter.IsLittleEndian)
                的len = BitConverter.ToInt32(br.ReadBytes(4).Reverse()的ToArray(),0);
            其他
                的len = br.ReadInt32();

            的char [] CNAME = br.ReadChars(4); //该块类型。
            如果(cName.SequenceEqual(新[] {'Z','T','X','T'})){
                VAR SB =新的StringBuilder(); //构建与块相关联的空值终止的关键字。
                焦炭C = br.ReadChar();
                做 {
                    sb.Append(C);
                    C = br.ReadChar();
                }
                而(C ='\ 0'!);
                字节的方法= br.ReadByte(); //在COM pression方法。应该始终为0(DEFLATE方法。)
                如果(方法!= 0){
                    stream.Seek(LEN  -  sb.Length + 3,SeekOrigin.Current); //如果不为0,跳过块的其余部分。
                    继续;
                }
                VAR数据= br.ReadBytes(LEN  -  sb.Length  -  1); //休息组块数据的...
                VAR毫秒=新的MemoryStream(数据,0,data.Length); // ...在一个MemoryStream ...
                变种DS =新DeflateStream(MS,COM pressionMode.Decom preSS); // ...由DeflateStream读...
                VAR SR =新的StreamReader(DS); // ...和一个StreamReader。 Yeesh。
                VAR海峡= sr.ReadToEnd(); //! InvalidDataException!
                ret.Add(新KeyValuePair<字符串,字符串>(sb.ToString(),STR));
                stream.Seek(4,SeekOrigin.Current); //跳过CRC校验。
            }
            其他 {
                stream.Seek(LEN + 4,SeekOrigin.Current); //跳过块的其余部分。
            }
        }
    }
    赶上(IOException异常){}
    赶上(InvalidDataException){}
    赶上(ArgumentOutOfRangeException){}
    返回RET;
}
 

在这解决,我需要编写一个函数,将这些zTXt块到文件中。所以,希望我理解为D 解决方案

毕竟这一次,我终于发现了问题。该数据是ZLIB格式,它具有存储不仅仅是单独使用DEFLATE多一点的数据。该文件被正确读取,如果我只是在看右边的2个额外的字节之前我得到的COM pressed数据。

微信的一些实用功能,你知道吗

请参阅这种反馈页面。 (我没有提交的那一个。)

我想知道现在。这两个字节的值是0x78和为0x9c分别。如果我发现数值高于其他,我应该承担DEFLATE是要失败?

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?

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.

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.

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

Here is the monster now:

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

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 D

解决方案

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.)

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?