Skip to content

Add deflate compression to writeStoredZip for support bundles #3218

Description

@ten9876

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)

Metadata

Metadata

Assignees

Labels

WindowsWindows-specific issueenhancementImprovement to existing featuremaintainer-reviewRequires maintainer review before any action is takenpriority: lowLow priority

Type

No type

Fields

No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions