Comment utilisez-vous un DeflateStream sur une partie d’un fichier?

Je travaille sur une solution à mon autre question qui consiste à lire les données dans les morceaux ‘zTXt’ d’un fichier PNG. Je suis aussi loin que de localiser les morceaux dans le fichier et de lire le mot clé du zTXt. Je ne parviens pas à lire la partie compressée de zTXt. Je n’avais jamais travaillé avec l’object DeflateStream auparavant et j’ai des problèmes avec cet object. Lors de la lecture, il semble que le paramètre de longueur soit en octets “non compressés”. Dans mon cas cependant, je ne connais que la longueur des données en octets “compressés”. Pour espérer résoudre ce problème, je mets toutes les données devant être décompressées dans un MemoryStream, puis «read to end» avec un DeflateStream. Il ne s’agit plus que de la pêche, sauf qu’il génère une exception InvalidDataException avec le message “La longueur du bloc ne correspond pas à son complément”. Maintenant, je n’ai aucune idée de ce que cela signifie. Qu’est-ce qui pourrait mal tourner?

Le format d’un morceau est de 4 octets pour l’ID (“zTXt”), un int de 32 bits big-endian pour la longueur des données, les données, et enfin une sum de contrôle CRC32 que j’ignore pour le moment.

Le format du bloc zTXt est d’abord une chaîne terminée par un zéro (chaîne en tant que mot-clé), puis un octet pour la méthode de compression (toujours 0, la méthode DEFLATE), le rest des données étant du texte compressé.

Ma méthode utilise un nouveau FileStream et renvoie un dictionnaire avec les mots-clés et les données zTXt.

Voici le monstre maintenant:

public static List<KeyValuePair> GetZtxt(FileStream stream) { var ret = new List<KeyValuePair>(); 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(sb.ToSsortingng(), 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; } 

Une fois que cela sera résolu, je devrai écrire une fonction qui ajoute ces morceaux zTXt au fichier. J’espère donc comprendre le fonctionnement de DeflateStream une fois le problème résolu.

Merci beaucoup!!

Après tout ce temps, j’ai enfin trouvé le problème. Les données sont au format zlib, qui contient un peu plus de données que la simple utilisation de DEFLATE. Le fichier est lu correctement si je lis juste les 2 octets supplémentaires juste avant d’obtenir les données compressées.

Voir cette page de commentaires . (Je n’ai pas soumis celui-là.)

Je me demande maintenant. La valeur de ces deux octets est 0x78 et 0x9C respectivement. Si je trouve des valeurs autres que celles-ci, devrais-je supposer que DEFLATE va échouer?