{"id":50963334,"url":"https://github.com/yuk7/zipkirei","last_synced_at":"2026-06-18T17:02:46.245Z","repository":{"id":356526547,"uuid":"1214149903","full_name":"yuk7/zipkirei","owner":"yuk7","description":"Fix garbled or decomposed Unicode filenames, and OS junk entries in milliseconds.","archived":false,"fork":false,"pushed_at":"2026-06-05T04:01:45.000Z","size":5204,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-06-05T07:05:15.661Z","etag":null,"topics":["hangul-jamo","kana","linux","macos","nfc","patcher","unicode-normalization","windows","zip"],"latest_commit_sha":null,"homepage":"https://yuk7.dev/zipkirei","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/yuk7.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null},"funding":{"github":"yuk7","patreon":null,"open_collective":null,"ko_fi":null,"tidelift":null,"community_bridge":null,"liberapay":null,"issuehunt":null,"otechie":null,"custom":"https://paypal.me/yuk77"}},"created_at":"2026-04-18T07:20:28.000Z","updated_at":"2026-06-05T03:30:00.000Z","dependencies_parsed_at":null,"dependency_job_id":"0c8a9a86-cffa-4c6f-a005-f72bb6a529a0","html_url":"https://github.com/yuk7/zipkirei","commit_stats":null,"previous_names":["yuk7/zipkirei"],"tags_count":2,"template":false,"template_full_name":null,"purl":"pkg:github/yuk7/zipkirei","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yuk7%2Fzipkirei","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yuk7%2Fzipkirei/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yuk7%2Fzipkirei/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yuk7%2Fzipkirei/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/yuk7","download_url":"https://codeload.github.com/yuk7/zipkirei/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yuk7%2Fzipkirei/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34499413,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-18T02:00:06.871Z","response_time":128,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["hangul-jamo","kana","linux","macos","nfc","patcher","unicode-normalization","windows","zip"],"created_at":"2026-06-18T17:02:45.214Z","updated_at":"2026-06-18T17:02:46.236Z","avatar_url":"https://github.com/yuk7.png","language":"Rust","funding_links":["https://github.com/sponsors/yuk7","https://paypal.me/yuk77"],"categories":[],"sub_categories":[],"readme":"# zipkirei\n\nA fast CLI tool to repair problematic ZIP archives without extraction or recompression.\n\nFix mojibake, decomposed Unicode filenames, and OS junk entries in milliseconds.\n\n[![GitHub Workflow Status](https://img.shields.io/github/actions/workflow/status/yuk7/zipkirei/ci.yml?style=flat-square)](https://github.com/yuk7/zipkirei/actions/workflows/ci.yml)\n[![GitHub Release](https://img.shields.io/github/v/release/yuk7/zipkirei?style=flat-square)](https://github.com/yuk7/zipkirei/releases/latest)\n[![Crates.io Version](https://img.shields.io/crates/v/zipkirei?style=flat-square)](https://crates.io/crates/zipkirei)\n[![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg?style=flat-square)](http://makeapullrequest.com)\n![License](https://img.shields.io/github/license/yuk7/zipkirei.svg?style=flat-square)\n\n[日本語](README_ja.md)\n\n### [⬇ Download](https://github.com/yuk7/zipkirei/releases/latest)\n[⬇ GitHub Releases](https://github.com/yuk7/zipkirei/releases/latest)\n[📦 Crates.io](https://crates.io/crates/zipkirei)\n[🌐 Try it in the web browser](https://yuk7.dev/zipkirei)\n\n### Supported Platforms\n| OS      | Architecture                        |\n|---------|-------------------------------------|\n| Windows | x86 (i686), x86_64, aarch64         |\n| Linux   | x86_64, armv7 (armeabihf), aarch64     |\n| macOS   | x86_64, aarch64 (Apple Silicon)     |\n\n## Why?\n\nZIP archives can contain platform-specific metadata and filename conventions that become troublesome on other operating systems.\n\nThis is especially common with archives created on macOS, where differences in Unicode normalization and metadata handling may cause:\n\n- decomposed Unicode filenames\n- mojibake text\n- duplicate-looking names\n- unwanted metadata files\n\n`zipkirei` patches ZIP metadata structures directly, without touching compressed payload data.\n\nIf you've ever received a ZIP from a Mac user and seen garbled filenames or mysterious __MACOSX folders, this tool is for you.\n\n## What it fixes\n\n| What users see | Root cause | Fixed by zipkirei |\n|---|---|---|\n| Unicode filenames render as decomposed characters | macOS stores filenames in NFD form (decomposed) | Windows/Linux tools may show visually duplicated or broken names |\n| Mojibake filenames | ZIP UTF-8 flag is missing | Extractors decode names using the wrong encoding |\n| Junk files in archive | macOS / Windows metadata files included | Recipients see unnecessary files |\n\nBy default, `zipkirei`:\n\n- sets the ZIP UTF-8 flag (bit 11) for non-ASCII filenames\n- normalizes non-ASCII UTF-8 filenames from NFD → NFC\n- normalizes backslashes in entry paths to slashes\n- leaves other ASCII-only filenames untouched\n- removes `.DS_Store`, `__MACOSX`, `Thumbs.db`, and `desktop.ini`\n\n## Features\n\n- Pure in-place ZIP repair\n- No extraction or recompression\n- No temporary files required\n- Extremely small disk writes\n- ZIP64 support\n- Works with password-protected ZIPs because compressed/encrypted payloads are never modified.\n- Preserves compressed payloads and CRCs\n- UTF-8 NFC normalization\n- Skips unnecessary UTF-8 flag writes for ASCII-only filenames\n- `--dry-run` preview mode\n- `--new` compact rewrite mode\n\n## Performance\n\nTested with a 5GB ZIP archive (2 entries total).\n\nApple M1 / Internal APFS SSD\n\n### In-place cleaning\n\n| Tool | Execution Time | Disk Write |\n|---|---|---|\n| **zipkirei** | **23.2ms** | **~100KB** |\n| `zip -d` | 7.85s | 5GB |\n\n### Repacking (`--new` mode)\n\n| Tool | Execution Time |\n|---|---|\n| **zipkirei --new** | **5.09s** |\n| `unzip` + `zip -0` | 21.18s |\n\n## Installation\n\n### Download binary\n1. Download the latest binary from [Releases](https://github.com/yuk7/zipkirei/releases/latest).\n2. Extract the archive and add the executable to your `PATH`.\n\n### Using cargo\nIf you have Rust installed, you can install it via cargo:\n```bash\ncargo install zipkirei\n```\n\n## Usage\n\n```bash\nzipkirei [OPTIONS] \u003cfile.zip\u003e\n```\n\n### Options\n\n| Option                 | Description                                                  |\n| ---------------------- | ------------------------------------------------------------ |\n| `--dry-run`            | Show planned changes without modifying the archive           |\n| `--fast`               | Fast in-place mode that rewrites only the Central Directory  |\n| `--new \u003coutfile\u003e`      | Write a cleaned archive to a new file                        |\n| `--not-utf-8`          | Skip UTF-8 filename fixes                                    |\n| `--keep-backslashes`   | Keep backslashes in entry paths                              |\n| `--no-default-exclude` | Keep `.DS_Store`, `__MACOSX`, `Thumbs.db`, and `desktop.ini` |\n| `--exclude \u003cname\u003e`     | Also exclude entries matching `\u003cname\u003e`; repeatable           |\n| `-h`, `--help`         | Show help                                                    |\n\n## Examples\n\n### Preview changes\n\n```bash\nzipkirei --dry-run archive.zip\n```\n\nExample output:\n\n```text\n[exclude]  .DS_Store  (8192 B)\n[exclude]  __MACOSX/._README  (2048 B)\n[nfc]      にほんご.txt  →  にほんご.txt\n[bit11]    にほんご.txt\n[nfc]      한국어.txt  →  한국어.txt\n[bit11]    한국어.txt\n[bit11]    中文.txt\n\nSummary:\n  Excluded:     2 entries\n  NFC renamed:  2 entries\n  Path fixed:   0 entries\n  bit11 set:    3 entries\n```\n\n### Clean in place\n\n```bash\nzipkirei archive.zip\n```\n\nWindows users can also run it by dragging and dropping the zip file onto the zipkirei executable.\n\n### Fast Central Directory-only cleanup\n\n```bash\nzipkirei --fast archive.zip\n```\n\nThis mode updates only Central Directory metadata. It is faster on large archives, but local file headers are left unchanged, so compatibility with some ZIP tools may be reduced.\n\nIn `--fast --dry-run`, excluded entry sizes are reported as `? B` because local entry spans are not scanned.\n\n### Write a new cleaned archive\n\n```bash\nzipkirei --new archive_clean.zip archive.zip\n```\n\n### Only remove junk entries\n\n```bash\nzipkirei --not-utf-8 archive.zip\n```\n\n### Add a custom exclusion\n\n```bash\nzipkirei --exclude .gitkeep archive.zip\n```\n\n## Limitations\n\n* Multi-disk ZIP archives are not supported\n* Filename normalization requires valid UTF-8 names\n* `--exclude` matches basenames only\n* In-place mode modifies the archive directly\n\nIf filenames are not valid UTF-8, rerun with `--not-utf-8`.\n\n## Safety\n\n`zipkirei` never decompresses or recompresses file payloads.\n\n* compressed data remains untouched\n* CRCs are preserved\n* only ZIP metadata structures are rewritten\n\nIn-place mode directly modifies the archive, so `--dry-run` is recommended first.\n\nUse `--new` if you want to keep the original file unchanged.\n\n## How it works\n\n`zipkirei` was designed around pure in-place metadata patching from the beginning. It operates in two phases:\n\n1. Parse the Central Directory and build a patch plan\n2. Rewrite only the necessary ZIP metadata structures\n\nCompressed payload data is never recompressed.\n\n### NFC normalization\n\nmacOS may store filenames in Unicode NFD form (decomposed characters).\n\nFor example:\n\n```text\nか + ゙  →  が\nᄒ + ᅡ + ᆫ → 한\n```\n\n`zipkirei` normalizes filenames to NFC to avoid decomposed names rendering incorrectly across platforms.\n\nASCII-only filenames are already byte-for-byte compatible with UTF-8 and common legacy ZIP filename decoding. Apart from backslash-to-slash path normalization, `zipkirei` leaves them unchanged instead of setting bit 11, which avoids unnecessary metadata writes in in-place mode.\n\n### In-place patching\n\nUTF-8 NFC normalization of non-ASCII characters generally reduces the byte count, causing data to shift forward.\nThis maintains the invariant `writer offset \u003c reader offset`, enabling safe in-place repair without temporary files.\n\nFurthermore, by filling the freed bytes with ZIP extra fields (padding) whenever possible, `zipkirei` avoids shifting subsequent data blocks, which minimizes disk writes.\n\n- reuses freed bytes as ZIP extra fields (padding)\n- shifts structures forward only\n- incrementally updates offsets\n- preserves compressed payload data verbatim\n\nThis allows the archive to be repaired with extremely small disk writes and no temporary files.\n\n```text\nBefore (NFD):\n[LFH][filename........][extra][data]\n\nAfter NFC (shorter):\n[LFH][filename....][free][data]\n\nzipkirei (with padding):\n[LFH][filename][padding extra][data]\n```\n\n### Excluded entries\n\nIn `--new` mode, excluded entries are completely removed.\n\nIn in-place mode, excluded local entries may remain as unreachable orphan data after being detached from the Central Directory. Standard ZIP readers ignore them.\n\n## Development\n\nBuild from source:\n\n```bash\ncargo build --release\n```\n\nRun locally:\n\n```bash\ncargo run -- --help\n```\n\nTests:\n\n```bash\ncargo test --locked\n```\n\n## License\n\n[MIT](LICENSE)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fyuk7%2Fzipkirei","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fyuk7%2Fzipkirei","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fyuk7%2Fzipkirei/lists"}