# How ipatool Extracts IPA Packages from ZIP, 7z, and tar+zstd Archives

> Discover how ipatool extracts IPA packages from ZIP, 7z, and tar+zstd archives. Learn about its unified interface and Go library implementation for efficient single-file retrieval.

- Repository: [Majd/ipatool](https://github.com/majd/ipatool)
- Tags: internals
- Published: 2026-09-06

---

**ipatool implements a unified `archiveEntry` interface across three format-specific extractors in `internal/sap/unicorn`, enabling seamless single-file retrieval from ZIP, 7z, and tar+zstd containers using standard Go libraries and specialized packages like `bodgit/sevenzip` and `klauspost/compress`.**

The `majd/ipatool` repository provides a robust archive subsystem designed to handle various compression formats used for iOS application packages (IPAs). By abstracting ZIP, 7z, and tar+zstd extraction behind a common type in the `unicorn` package, the tool allows the rest of the codebase to retrieve specific payload files—such as `Info.plist` or executable binaries—without managing format-specific decompression logic.

## Unified Archive Abstraction

### The archiveEntry Struct

All extraction functions return a standardized `archiveEntry` type that decouples the consumer from compression implementation details. This struct is defined in the `unicorn` package and provides a consistent interface for reading decompressed data:

```go
type archiveEntry struct {
    reader io.Reader      // stream of the unpacked entry
    size   uint64         // uncompressed size
    close  func() error   // closes underlying resources
}

```

The `reader` field exposes the raw decompressed bytes, while the `close` function ensures proper cleanup of file handles and decoder states regardless of the original archive format.

## ZIP Archive Extraction

In [`internal/sap/unicorn/archive_zip.go`](https://github.com/majd/ipatool/blob/main/internal/sap/unicorn/archive_zip.go), the `openZIPEntry` function handles standard ZIP archives using Go's `archive/zip` standard library. The implementation calls `zip.OpenReader(path)` to access the archive, iterates through the `File` slice to locate the target entry by name, and invokes `candidate.Open()` to obtain a read stream.

The function returns an `archiveEntry` populated with the entry's uncompressed size and a cleanup closure that closes both the individual entry and the parent ZIP reader:

```go
entry, err := openZIPEntry(pathToIpa, "Payload/MyApp.app/Info.plist")
if err != nil {
    log.Fatalf("cannot find entry: %v", err)
}
defer entry.close()

data, err := io.ReadAll(entry.reader)
if err != nil {
    log.Fatal(err)
}
// data now holds the plist contents

```

## 7z Archive Extraction on Windows

For 7z archives, ipatool provides `open7zEntry` in [`internal/sap/unicorn/archive_7z_windows.go`](https://github.com/majd/ipatool/blob/main/internal/sap/unicorn/archive_7z_windows.go), utilizing the `github.com/bodgit/sevenzip` library. This Windows-specific implementation creates a reader via `sevenzip.OpenReader(path)`, scans the `Files` slice to match the requested entry path, and calls `file.Open()` to produce the decompression stream.

The resulting `archiveEntry` includes a specialized `close` function that releases the sevenzip reader resources, maintaining the same interface contract as the ZIP extractor:

```go
entry, err := open7zEntry(pathToIpa, "Payload/MyApp.app/Info.plist")
if err != nil {
    log.Fatalf("cannot find entry: %v", err)
}
defer entry.close()

plist, err := io.ReadAll(entry.reader)
if err != nil {
    log.Fatal(err)
}

```

## tar+zstd Archive Extraction

The `openTarZstdEntry` function in [`internal/sap/unicorn/archive_tar_zstd.go`](https://github.com/majd/ipatool/blob/main/internal/sap/unicorn/archive_tar_zstd.go) manages tar archives compressed with Zstandard. This implementation chains multiple readers: it opens the raw file with `os.Open`, wraps it in a Zstandard decoder via `zstd.NewReader` from `github.com/klauspost/compress/zstd`, and feeds the result into `tar.NewReader` from the standard library.

The function iterates through tar headers until locating the requested entry, then returns an `archiveEntry` whose `reader` is an `io.LimitReader` bound to the entry's uncompressed size. The `close` method simultaneously shuts down the Zstandard decoder and the underlying file descriptor:

```go
entry, err := openTarZstdEntry(pathToIpa, "Payload/MyApp.app/MyApp")
if err != nil {
    log.Fatalf("cannot find entry: %v", err)
}
defer entry.close()

binary, err := io.ReadAll(entry.reader)
if err != nil {
    log.Fatal(err)
}

```

## Summary

- **Unified Interface**: The `archiveEntry` struct abstracts ZIP, 7z, and tar+zstd formats behind a consistent `io.Reader` with explicit cleanup hooks.
- **Format-Specific Implementations**: `openZIPEntry` uses `archive/zip`, `open7zEntry` leverages `github.com/bodgit/sevenzip` for Windows platforms, and `openTarZstdEntry` combines `github.com/klauspost/compress/zstd` with `archive/tar`.
- **Resource Management**: Each extractor returns a `close` function that releases file handles and decoder resources, preventing leaks when processing large IPA files.
- **Single-File Extraction**: All three functions extract individual entries by name rather than decompressing entire archives, optimizing memory usage when only specific payload components are required.

## Frequently Asked Questions

### What is the archiveEntry type in ipatool?

The `archiveEntry` type is a struct defined in `internal/sap/unicorn` that standardizes access to decompressed archive contents. It contains an `io.Reader` for the data stream, a `uint64` size field, and a `close` function for resource cleanup. This abstraction allows the rest of the ipatool codebase to handle ZIP, 7z, and tar+zstd archives identically without implementing format-specific logic.

### How does ipatool handle 7z archives on non-Windows platforms?

Currently, ipatool's 7z extraction support is restricted to Windows through the [`internal/sap/unicorn/archive_7z_windows.go`](https://github.com/majd/ipatool/blob/main/internal/sap/unicorn/archive_7z_windows.go) file. This implementation is excluded from non-Windows builds via conditional compilation or platform-specific file naming. Users on Linux or macOS must extract 7z contents manually or convert the archive to a supported format like ZIP before processing with ipatool.

### Why does ipatool support tar+zstd for IPA packages?

While standard IPA files use ZIP compression, ipatool supports tar+zstd to handle alternative packaging formats or intermediate build artifacts that leverage Zstandard compression for faster decompression and superior compression ratios. The `openTarZstdEntry` function specifically addresses this combination, enabling the tool to process IPAs generated by diverse build pipelines or distribution systems.

### How does the archive system manage resource cleanup?

Each extraction function returns an `archiveEntry` with a dedicated `close` function encapsulating all necessary cleanup operations. For ZIP archives, this closes both the individual entry and the archive reader; for 7z, it releases the sevenzip reader; and for tar+zstd, it closes both the Zstandard decoder and the underlying file handle. Callers should always defer the `close` function immediately after successful extraction to prevent file descriptor leaks when processing multiple IPA packages.