3 ms·
If the length comes last, how would you know how much data to read? Remember that chunks like tEXt are variable-length and not self-terminating; it relies on th
by nayuki 4y ago
If the length comes last, how would you know how much data to read? Remember that chunks like tEXt are variable-length and not self-terminating; it relies on the outer level to signal the end of data.
- dalke 4y agoThe length would still come first in the PNG datastream. My idea is that those 4 bytes could have been added to the CRC after processing the chunk tag and data. Here's an example: class BlockWriter: def __init__(self, output, chunk_type): self.output = output self._start = output.tell() output.write(b"\0\0\0\0") output.write(chunk_type) self._crc = zlib.crc32(chunk_type) self._chunk_length = 0 def write(self, data): self.output.write(data) self._crc = zlib.crc32(data, self._crc) self._chunk_length += len(data) def finish(self): chunk_length_bytes = self._chunk_length.to_bytes(4, "big") self._crc = zlib.crc32(chunk_length_bytes, self._crc) # !! NEW !! crc_bytes = self._crc.to_bytes(4, "big") self.output.write(crc_bytes) # Go back and update the length end = self.output.tell() self.output.seek(self._start) self.output.write(chunk_length_bytes) self.output.seek(end) It could be used like: writer = BlockWriter(png_f, b"IDAT") writer.write(b"shrdlu") writer.write(b"etaoin") writer.finish() which produces the correct block structure: '\x00\x00\x00\x0cIDATshrdluetaoin\xed?\xa6\xa4' |--------------| four byte length = 12 |--| four byte character code 'IDAT' |----------| = 12 bytes of payload |------------| = four byte CRC I'll show the CRC is in the order {tag}, {data}, {length}: >>> zlib.crc32(b"IDAT" + b"shrdluetaoin" + b"\x00\x00\x00\x0c" ).to_bytes(4, "big") b'\xed?\xa6\xa4'