[video output=day454 member=cmuratori stream_platform=twitch stream_username=handmade_hero project=code title="Parsing ZLIB Headers" vod_platform=youtube id=nQ0ctmQPs-E annotator=Miblo]
[0:00][Welcome to the stream][:speech]
[0:21][Recap and set the stage for :parsing PNG IDAT data][:speech]
[1:18][:Run the program to look at our IDAT chunks][:parsing]
[3:58][Set up to parse IDAT chunks[ref
    site=W3C
    page="Portable Network Graphics (PNG) Specification (Second Edition)"
    url=https://w3.org/TR/2003/REC-PNG-20031110/]][:parsing :research]
[6:44][Prepare ReadEntireFile() and ConsumeSize() to read the .png file into a linked list of streaming_chunks][:"file io" :parsing]
[13:38][:Run it to see that it works][:"file io" :parsing]
[13:39][Enable ParsePNG() to build up a linked list of IDAT chunks, introducing AllocateChunk()][:memory :parsing]
[19:09][Describe this obtuse, single-expression singly linked list append][:memory :research]
[20:11][Enable ParsePNG() to parse the IDATHeader][:parsing]
[21:19][:Run it to see our decompressed IDAT chunks][:parsing]
[21:30][Make ParsePNG() print the IDAT chunk sizes][:parsing]
[21:45][:Run it see the sizes of the IDAT chunks and determine that GIMP is outputting in 8192-byte chunks][:parsing]
[23:30][Consult the PNG[ref
    site=W3C
    page="Portable Network Graphics (PNG) Specification (Second Edition)"
    url=https://w3.org/TR/2003/REC-PNG-20031110/] and ZLIB specs[ref
        site=IETF
        page="ZLIB Compressed Data Format Specification version 3.3"
        url=http://www.ietf.org/rfc/rfc1950.txt] to understand what we need to support][:compression :parsing :research]
[25:19][Further condense ParsePNG() to support :compression method 8 (DEFLATE) and no preset dictionary][:parsing]
[26:21][:Run it to see our "Supported" message][:parsing]
[26:27][Begin to make ParsePNG() decompress the IDAT data using DEFLATE[ref
    site=IETF
    page="DEFLATE Compressed Data Format Specification version 1.3"
    url=https://www.ietf.org/rfc/rfc1951.txt]][:compression :parsing]
[35:19][LZ-Style Compressors][:blackboard :compression]
[40:55][Run-Length Encoding as LZ Mode 2][:blackboard :compression]
[44:45][Enable ParsePNG() to LZ-decompress the IDAT data[ref
    site=IETF
    page="DEFLATE Compressed Data Format Specification version 1.3"
    url=https://www.ietf.org/rfc/rfc1951.txt]][:compression :parsing]
[49:37][Read about non-compressed and compressed blocks, including Huffman codes, in the DEFLATE spec[ref
    site=IETF
    page="DEFLATE Compressed Data Format Specification version 1.3"
    url=https://www.ietf.org/rfc/rfc1951.txt]][:compression :research]
[57:56][Implement ConsumeBits() and FlushByte() and enable ParsePNG() to parse BTYPE 00 chunks[ref
    site=IETF
    page="DEFLATE Compressed Data Format Specification version 1.3"
    url=https://www.ietf.org/rfc/rfc1951.txt]][:compression :memory :parsing]
[1:09:13][Step through ParsePNG() to see our consumed bits][:compression :memory :parsing :run]
[1:10:36][Read about dynamic Huffman codes (BTYPE 10)[ref
    site=IETF
    page="DEFLATE Compressed Data Format Specification version 1.3"
    url=https://www.ietf.org/rfc/rfc1951.txt]][:compression :parsing :research]
[1:13:13][Enable ParsePNG() to handle dynamic Huffman coded (BTYPE 10) chunks[ref
    site=IETF
    page="DEFLATE Compressed Data Format Specification version 1.3"
    url=https://www.ietf.org/rfc/rfc1951.txt]][:compression :parsing]
[1:32:44][Step through ParsePNG() to inspect our HLIT, HDIST and HCLEN, and realise that the code lengths are swizzled from most to least likely][:compression :parsing :run]
[1:36:25][Set up ParsePNG() to build up our Huffman table, introducing stubs for ComputeHuffman() and HuffmanDecode()[ref
    site=IETF
    page="DEFLATE Compressed Data Format Specification version 1.3"
    url=https://www.ietf.org/rfc/rfc1951.txt]][:compression :parsing]
[1:52:40][Q&A][:speech]
[1:53:41][@lorymaster][Q: I'm happy you're doing this. I've had problems making my inflate decoder (for fun) working, and you being a spec decoder works out perfectly][:compression]
[1:53:57][@ratchetfreak][Q: I believe the length for the LZ should be interpreted like u32 copy_length = length_table_base\[LitLen-257\] + ConsumeBits(length_table_extra_bits\[LitLen - 257\]); And the distance is similar with the other table(s)][:compression]
[1:54:47][@Brian][Q: How have you found the png and zlib specification, compared to other specifications you have read and implemented?]
[1:55:51][@gg_nate][Q: Any way to fix the pink flashing? It was fairly persistent today]
[1:56:09][@bigmofo1][Q: Will Yangtian iterate over the :art live?]
[1:56:46][@Brian][Q: What do you do when you have an incomplete specification? Is it then more just trial and error, or are there techniques on how to continue?]
[1:59:12][@jim0_o][Q: What ~4coder version are you using on stream?]
[1:59:56][@rationalcoder][Q: Just caught up with the stream, but I have had a question for a while: When you come up with a reusable data structure and want to share it between projects / other people, how do you deal with custom allocation? I have been writing some hybrid data structures, and I want to add custom allocation, but adding a template parameter seems like a bad solution to the problem][:memory]
[2:00:19][@jim0_o][Q: I see it in the *Message* window that you don't get at start up apparently]
[2:00:30][Custom :memory allocation in Granny][:speech]
[2:04:03][@snovind92][Q: Why does no one spec the simplest solution possible, so people can easily implement the parsers and exporters they need (in cases when space / speed does not matter)?]
[2:07:01][@flyinginthedark][Q: Are you going to do :audio formats next?]
[2:07:47][We're all done][:speech]
[/video]
