JUnzip and JZipView Updated After Almost 10 Years
Tue, Dec 16, 2025 in post c programming open source AI artificial intelligence
I released the JUnzip library back in 2014 as a minimalistic C library for reading ZIP files without heavy dependencies. It worked well for simple cases, but had a long-standing limitation: it couldn't handle "streaming" ZIP files where file sizes weren't known upfront. These ZIPs set bit 3 in the general purpose flag and store sizes in a "data descriptor" after the file data instead of the header. I was not aware of this exact nature of the problem until last week, just that many zips, annoyingly those including Google Photos generated ones, just failed when I tried to view them with JZipView that uses my JUnzip library as well.
Fast forward to December 2025, and with help from ChatGPT 5.2 and OpenAI Codex, I finally fixed this issue. It feels great to breathe new life into a project that's been dormant for so long!
What Changed in JUnzip
The core fix was improving support for ZIP data descriptors. When a ZIP entry has bit 3 set in generalPurposeBitFlag, the local file header contains zeros for CRC, compressed size, and uncompressed size. The actual values come in a data descriptor that follows the file data. My library was assuming both local headers and end file data contain all needed data, and thus failed when encountering these zips.
The key changes:
- A new
jzReadDataDescriptor()function that reads the optional descriptor (handling both signature-present and signature-absent variants) - Modified
jzReadLocalFileHeader()to preserve sizes from the central directory when the local header has zeros - Updated
jzReadData()to automatically consume the data descriptor when present
This was an API-breaking change — the callback signature for jzReadCentralDirectory() now includes a void *user_data parameter. Additionally, the library uses a JZFile abstraction instead of raw FILE* pointers.
Here's how you now wrap a file:
FILE *zipFile = fopen("archive.zip", "rb");
JZFile *zip = jzfile_from_stdio_file(zipFile);
You can check out the included examples, most notably junzip_demo.c to see how it now works.
JZipView Also Updated
JZipView is an ultra-simple zipped JPEG viewer I wrote back in 2015. It internally uses JUnzip, and previously I just copied the source files into the project. With the API changes, I took the opportunity to do things properly:
- JUnzip is now a git submodule instead of copied files
- Updated to use the new
JZFile*API - The callback functions now use the new signature with
user_data
To get started with the submodule after cloning:
git submodule update --init --recursive
Once (A)I was done with the API updates, jzipview now happily opens all those previously unreadable zip files!
Spare time advances courtesy of ChatGPT 5.2 and Codex CLI
I was honestly really surprised how short work GPT 5.2 made of the issue. I had postponed debugging this thing for a long time, as I had a working fork in my Github issues (without a PR, so I needed to do it myself), but was quite certain I'd need to go through the failing files with the zip spec in one hand and hex editor in the other. However, just pasting the error of my demo app to ChatGPT let it identify the culprit and suggest a change to fix it. Wow. And it actually worked on the first go, which was a rare sight in my vibe debugging journey so far. And JZipView fix proceeded in a similar smooth manner.
It's a great example of how AI can help revive old projects. The fix wasn't trivial — it required understanding the ZIP format deeply and making coordinated changes across the library. But with AI assistance, I could tackle it in a few hours instead of shelving it for another decade.
Check out the projects:
- JUnzip: https://github.com/jokkebk/junzip
- JZipView: https://github.com/jokkebk/jzipview
Notice: First version of this post was co-written with Claude Opus 4.5 using Claude Code. Original parts (prose) was about 50 % rewritten by hand. The code changes were done with ChatGPT 5.2 and OpenAI Codex.