{"id":50919041,"url":"https://github.com/lovasoa/tinyzip","last_synced_at":"2026-06-16T18:01:19.783Z","repository":{"id":347381452,"uuid":"1193883669","full_name":"lovasoa/tinyzip","owner":"lovasoa","description":null,"archived":false,"fork":false,"pushed_at":"2026-03-28T01:22:52.000Z","size":2543,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-03-28T01:43:18.202Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/lovasoa.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"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}},"created_at":"2026-03-27T17:20:54.000Z","updated_at":"2026-03-28T01:22:55.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/lovasoa/tinyzip","commit_stats":null,"previous_names":["lovasoa/tinyzip"],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/lovasoa/tinyzip","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lovasoa%2Ftinyzip","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lovasoa%2Ftinyzip/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lovasoa%2Ftinyzip/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lovasoa%2Ftinyzip/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/lovasoa","download_url":"https://codeload.github.com/lovasoa/tinyzip/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lovasoa%2Ftinyzip/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34417416,"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-16T02:00:06.860Z","response_time":126,"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":[],"created_at":"2026-06-16T18:01:18.006Z","updated_at":"2026-06-16T18:01:19.775Z","avatar_url":"https://github.com/lovasoa.png","language":"Rust","funding_links":[],"categories":[],"sub_categories":[],"readme":"# tinyzip\n\n[![crates.io](https://img.shields.io/crates/v/tinyzip.svg)](https://crates.io/crates/tinyzip)\n[![docs.rs](https://img.shields.io/docsrs/tinyzip.svg)](https://docs.rs/tinyzip)\n\n`tinyzip` is a `no_std` low level ZIP navigation library for Rust.\nIt does not have any dependency and does not allocate memory.\n\nThis crate does not decompress data: you iterate\nover files in a ZIP archive, and get access to raw bytes.\nYou can decompress them with an external crate like [miniz_oxide](https://docs.rs/miniz_oxide) or [flate2](https://docs.rs/flate2).\n\n## About the ZIP format\n\nA ZIP archive has the following overall structure:\n\n```text\n[local file header 1] [file data 1]\n[local file header 2] [file data 2]\n...\n[central directory header 1]\n[central directory header 2]\n...\n[end of central directory record]\n```\n\n### Central directory vs. local headers\n\nEach file's metadata is stored **twice**: once in a _local file header_ immediately\nbefore the file data, and once in the _central directory_ near the end of the archive.\nThe central directory is the authoritative source. It contains the full metadata and a pointer (byte offset) to each local header.\n\n**This crate reads the central directory.** It uses local headers only to resolve the exact byte offset of file data (since the local header contains variable-length fields that can shift the data start). You should not rely on local header fields directly because some writers zero them out.\n\n### File name and path encoding\n\nFile names are represented as raw bytes. The ZIP specification originally required\n[IBM Code Page 437](https://en.wikipedia.org/wiki/Code_page_437) encoding, but\nmost archivers today write utf8 or whatever the local OS encoding is.\n\nIf **general purpose bit 11** (the \"Language Encoding Flag\", EFS) is set, the file name and comment are guaranteed to be **UTF-8**. You can check this with `Entry::path_is_utf8()`.\n\nPath separators are always forward slashes (`/`). Directory entries are indicated by a trailing `/`. There is no leading slash and no drive letter.\n\n### Important notes\n\n- The compression method can be `Stored` (no compression) or `Deflate` (by far the most common). Other values are rare and not supported by this crate.\n- File order in the archive is arbitrary.\n- For files larger than ~4 GB, **ZIP64** extensions are used. This crate handles ZIP64 transparently and exposes all integers as u64.\n\nThe full format specification is [APPNOTE.TXT](https://pkware.cachefly.net/webdocs/casestudies/APPNOTE.TXT), maintained by PKWARE.\n\n## Supported\n\n- Single-disk ZIP and ZIP64 archives\n- Leading prefix data and trailing junk\n- Central-directory iteration without buffering the directory\n- Lazy reading of variable-length metadata and local headers\n\n## Not Supported\n\n- Multi-disk ZIP archives\n- Decompression (use the deflate implementation of your choice)\n- Filename decoding: you can access the raw bytes and whether the file name is utf8 (it usually is).\n- Central-directory encryption or compressed central-directory structures\n- Automatic checksum verification (you get access to the checksum if you need it)\n\n## Core API\n\n### no_std\n\n```rust\n# fn main() {\n#     let file_bytes: \u0026[u8] = include_bytes!(\"tests/data/manual/go-archive-zip/test.zip\");\n#     run(file_bytes).unwrap();\n# }\n# fn run(file_bytes: \u0026[u8]) -\u003e Result\u003c(), tinyzip::Error\u003ctinyzip::SliceReaderError\u003e\u003e {\nuse tinyzip::{Archive, Compression};\nuse miniz_oxide::inflate::stream::{inflate, InflateState};\nuse miniz_oxide::{DataFormat, MZFlush};\n\nlet archive = Archive::open(file_bytes)?;\nlet entry = archive.find_file(b\"test.txt\")?;\nlet mut decompressed = [0u8; 1024];\nlet contents = match entry.compression()? {\n    Compression::Deflated =\u003e {\n        let mut chunks = entry.read_chunks::\u003c512\u003e()?;\n        let mut state = InflateState::new(DataFormat::Raw);\n        let mut out_pos = 0;\n        while let Some(chunk) = chunks.next() {\n            let result = inflate(\u0026mut state, chunk?,\n                \u0026mut decompressed[out_pos..], MZFlush::None);\n            out_pos += result.bytes_written;\n        }\n        \u0026decompressed[..out_pos]\n    }\n    Compression::Stored =\u003e { entry.read_to_slice(\u0026mut decompressed)? }\n};\nassert_eq!(contents, b\"This is a test text file.\\n\");\n# Ok(())\n# }\n```\n\n### `std` feature\n\nWhen `std` is available, this crate unlocks features that require `std` traits or heap allocation.\nThe core logic remains the same and does not allocate when opening a file or iterating through contents.\n\n```rust\n# fn main() -\u003e Result\u003c(), Box\u003cdyn core::error::Error\u003e\u003e {\n# #[cfg(feature = \"std\")] { // this test requires std\n# let zip_path = \"tests/data/manual/go-archive-zip/test.zip\";\nuse std::fs::File;\nuse std::io::{self, Read};\nuse tinyzip::{Archive, Compression};\nuse flate2::read::DeflateDecoder; // switch decompressor lib with crate features\n\nlet zip_file = File::open(zip_path)?;\nlet archive = Archive::try_from(zip_file)?;\nlet entry = archive.find_file(b\"test.txt\")?;\nlet mut writer = Vec::new(); // This could be be a `std::fs::File`\nlet size = entry.uncompressed_size();\nassert!(size \u003c 1024, \"file too large\"); // be careful with zip bombs\nmatch entry.compression()? {\n    Compression::Deflated =\u003e {\n        let mut decoder = DeflateDecoder::new(entry.reader()?).take(size);\n        io::copy(\u0026mut decoder, \u0026mut writer)?;\n    }\n    Compression::Stored =\u003e {\n        io::copy(\u0026mut entry.reader()?, \u0026mut writer)?;\n    }\n}\n# assert_eq!(writer, b\"This is a test text file.\\n\");\n# } Ok(()) }\n```\n\n## API details\n\nThe API stays low-level on purpose:\n\n`Reader` is a tiny random-access trait that can be implemented directly on top\nof immutable positioned reads.\n\nOnly small fixed-size archive metadata are loaded and stored in memory.\nVariable-length fields are read into caller-provided buffers.\n\nData location is resolved lazily from the local header only when needed.\n\n## Performance\n\nCompared against the [`zip`](https://crates.io/crates/zip) crate (v8) on equivalent operations\n(in-memory archive, ~2500 deflate-compressed files, realistic nested paths, including multi-MB binary files).\n\n| Operation | tinyzip | zip | Speedup |\n|-----------|---------|-----|---------|\n| [Find file by name](https://github.com/lovasoa/tinyzip/blob/main/benches/compare.rs#find_file) | 15 µs | 402 µs | 26x |\n| [Extract a small file](https://github.com/lovasoa/tinyzip/blob/main/benches/compare.rs#extract) | 54 µs | 443 µs | 8.2x |\n| **[Heap allocations](https://github.com/lovasoa/tinyzip/blob/main/benches/memory.rs)** | **0** | **9,862** | — |\n| **[Peak heap usage](https://github.com/lovasoa/tinyzip/blob/main/benches/memory.rs)** | **0 B** | **1.5 MB** | — |\n\ntinyzip uses [miniz_oxide](https://docs.rs/miniz_oxide) for decompression in the extract benchmark.\nReproduce with `cargo bench`.\n\n## Maintenance\n\npr welcome\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flovasoa%2Ftinyzip","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Flovasoa%2Ftinyzip","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flovasoa%2Ftinyzip/lists"}