Context
PR #3206 replaced the QProcess + powershell Compress-Archive / tar czf support-bundle path with an in-process stored (uncompressed) ZIP via the new writeStoredZip() helper in src/core/ZipArchive.cpp. The PowerShell removal was a hard requirement for Microsoft Store certification — WACK's "Blocked executables" finding flagged the subprocess import.
The compression side of the change was a code-simplicity decision by the author, not a Store requirement. Microsoft Store and WACK don't care about the compression method of files the app writes at runtime to user-writable storage — those files are never inside the MSIX, so WACK's "Archive files usage" rule doesn't apply.
Cost of staying with stored ZIP
Support bundles are dominated by text logs which compress 5–10× with deflate. A user with 50 MB of accumulated logs now produces a 50 MB bundle vs ~5 MB before #3206. Discord uploads, email attachments, and GitHub issue attachments hit size limits much sooner.
Proposal
Add a deflate variant to the shared ZipArchive helper. Same bundled zlib that already powers the inflate-on-read path — no new dep, no new process launch, no new MSIX content, all #3206's Store-compliance wins preserved.
Sketch:
// ZipArchive.h
QByteArray writeStoredZip(const QList<ZipEntryData>& entries);
QByteArray writeDeflatedZip(const QList<ZipEntryData>& entries); // new
Or fold into a single API with a compression parameter — author's choice.
The writeDeflatedZip body mirrors writeStoredZip with:
method field in local + central headers set to 8 instead of 0
data payload run through deflate with raw-deflate window bits (deflateInit2(&z, Z_DEFAULT_COMPRESSION, Z_DEFLATED, -MAX_WBITS, 8, Z_DEFAULT_STRATEGY)) — same negative-window-bits trick the existing inflateInit2(&z, -MAX_WBITS) uses to skip the zlib header that ZIP doesn't use
- compressed-size + uncompressed-size fields in headers set independently (currently both are
data.size())
SupportBundle::writeSupportBundleZip switches to writeDeflatedZip. ProfileTransfer can stay on stored (per-file profile data is small and stored is fine).
Test coverage in tests/zip_archive_test.cpp:
- Round-trip a multi-entry deflated ZIP
- Verify local-header
method byte == 8
- Verify the existing
readZipEntries path (which already handles method 8 via inflateRawDeflate) round-trips deflated entries cleanly — that's the implicit cross-check that the writer matches the reader
Scope
Small and self-contained — should land in a single PR. No public API breakage (additive).
References
73, Jeremy KK7GWY & Claude (AI dev partner)
Context
PR #3206 replaced the
QProcess + powershell Compress-Archive/tar czfsupport-bundle path with an in-process stored (uncompressed) ZIP via the newwriteStoredZip()helper in src/core/ZipArchive.cpp. The PowerShell removal was a hard requirement for Microsoft Store certification — WACK's "Blocked executables" finding flagged the subprocess import.The compression side of the change was a code-simplicity decision by the author, not a Store requirement. Microsoft Store and WACK don't care about the compression method of files the app writes at runtime to user-writable storage — those files are never inside the MSIX, so WACK's "Archive files usage" rule doesn't apply.
Cost of staying with stored ZIP
Support bundles are dominated by text logs which compress 5–10× with deflate. A user with 50 MB of accumulated logs now produces a 50 MB bundle vs ~5 MB before #3206. Discord uploads, email attachments, and GitHub issue attachments hit size limits much sooner.
Proposal
Add a deflate variant to the shared ZipArchive helper. Same bundled zlib that already powers the inflate-on-read path — no new dep, no new process launch, no new MSIX content, all #3206's Store-compliance wins preserved.
Sketch:
Or fold into a single API with a compression parameter — author's choice.
The
writeDeflatedZipbody mirrorswriteStoredZipwith:methodfield in local + central headers set to8instead of0datapayload run throughdeflatewith raw-deflate window bits (deflateInit2(&z, Z_DEFAULT_COMPRESSION, Z_DEFLATED, -MAX_WBITS, 8, Z_DEFAULT_STRATEGY)) — same negative-window-bits trick the existinginflateInit2(&z, -MAX_WBITS)uses to skip the zlib header that ZIP doesn't usedata.size())SupportBundle::writeSupportBundleZipswitches towriteDeflatedZip.ProfileTransfercan stay on stored (per-file profile data is small and stored is fine).Test coverage in
tests/zip_archive_test.cpp:methodbyte == 8readZipEntriespath (which already handles method 8 viainflateRawDeflate) round-trips deflated entries cleanly — that's the implicit cross-check that the writer matches the readerScope
Small and self-contained — should land in a single PR. No public API breakage (additive).
References
73, Jeremy KK7GWY & Claude (AI dev partner)