# Zip_Normalizer

Strips macOS metadata from a release artifact and makes its modes readable.

***

* Full name: `\Linchpin_SatisPress\Helper\Zip_Normalizer`

## Constants

| Constant            | Visibility | Type   | Value                  |
|---------------------|------------|--------|------------------------|
| `APPLEDOUBLE_MAGIC` | private    | string | "\x00\x05\x16\x07"     |
| `DS_STORE_MAGIC`    | private    | string | "\x00\x00\x00\x01Bud1" |
| `DIR_MODE`          | private    | int    | 0755                   |
| `FILE_MODE`         | private    | int    | 0644                   |
| `EXECUTABLE_MODE`   | private    | int    | 0755                   |
| `DIR_REQUIRED`      | private    | int    | 0555                   |
| `FILE_REQUIRED`     | private    | int    | 0444                   |

## Methods

### normalize

Normalise an artifact in place.

```php
public static normalize(string $source): bool
```

Safe to call on anything: an archive that is already well formed, or one
this cannot read, is left exactly as it was found.

* This method is **static**.
**Parameters:**

| Parameter | Type       | Description                            |
|-----------|------------|----------------------------------------|
| `$source` | **string** | Absolute path to the zip to normalise. |

**Return Value:**

True when the archive was rewritten.

***

### inspect

Report what normalising an archive would change, without changing it.

```php
public static inspect(string $source): array<string,mixed>
```

* This method is **static**.
**Parameters:**

| Parameter | Type       | Description                          |
|-----------|------------|--------------------------------------|
| `$source` | **string** | Absolute path to the zip to inspect. |

**Return Value:**

Entry, junk and re-mode counts plus top-level
roots; empty when the archive cannot be read.

***

### read_entries

Describe every entry in the archive.

```php
private static read_entries(\ZipArchive $zip): array<int,array<string,mixed>>
```

* This method is **static**.
**Parameters:**

| Parameter | Type            | Description      |
|-----------|-----------------|------------------|
| `$zip`    | **\ZipArchive** | Archive to read. |

***

### is_junk

Is this entry macOS bookkeeping rather than part of the package?

```php
private static is_junk(\ZipArchive $zip, int $index, string $name, bool $is_dir): bool
```

The name alone is not enough to decide. `._name` is only conventionally an
AppleDouble resource fork, and nothing stops a package from shipping a
file or directory that happens to be named that way -- dropping one
silently would corrupt the package we are trying to repair. So a name is
treated as a candidate and the file's own header is what convicts it:
AppleDouble opens with the magic number 0x00051607, and a Finder
`.DS_Store` opens with 0x00000001 followed by "Bud1". Anything that does
not match is real content and is kept.

`__MACOSX/` needs no such check. It is a name Finder reserves for the
sidecar tree it writes beside an archive's real contents, it is the reason
an archive ends up double-rooted, and SatisPress's own
HiddenDirectoryValidator already treats its presence as fatal.

* This method is **static**.
**Parameters:**

| Parameter | Type            | Description                       |
|-----------|-----------------|-----------------------------------|
| `$zip`    | **\ZipArchive** | Archive being read.               |
| `$index`  | **int**         | Entry index.                      |
| `$name`   | **string**      | Entry name.                       |
| `$is_dir` | **bool**        | Whether the entry is a directory. |

***

### opens_with

Does an entry's content begin with this signature?

```php
private static opens_with(\ZipArchive $zip, int $index, string $magic): bool
```

Only the signature is read, not the whole entry.

* This method is **static**.
**Parameters:**

| Parameter | Type            | Description         |
|-----------|-----------------|---------------------|
| `$zip`    | **\ZipArchive** | Archive being read. |
| `$index`  | **int**         | Entry index.        |
| `$magic`  | **string**      | Signature to match. |

***

### normalised_attributes

Work out the external attributes an entry should carry instead.

```php
private static normalised_attributes(bool $is_dir, int $opsys, int $attr): int|null
```

* This method is **static**.
**Parameters:**

| Parameter | Type     | Description                                        |
|-----------|----------|----------------------------------------------------|
| `$is_dir` | **bool** | Whether the entry is a directory.                  |
| `$opsys`  | **int**  | Operating system the entry's attributes came from. |
| `$attr`   | **int**  | External attributes as stored.                     |

**Return Value:**

Replacement attributes, or null to leave the entry alone.

***

### rewrite

Write the kept entries out and put the result back at the source path.

```php
private static rewrite(\ZipArchive $zip, array<int,array<string,mixed>> $entries, string $source): bool
```

Entry bodies are buffered by ext-zip until close, which is why this only
ever runs for an archive that genuinely needs repair.

* This method is **static**.
**Parameters:**

| Parameter  | Type                               | Description               |
|------------|------------------------------------|---------------------------|
| `$zip`     | **\ZipArchive**                    | Archive being normalised. |
| `$entries` | **array<int,array<string,mixed>>** | Entries to carry over.    |
| `$source`  | **string**                         | Path to overwrite.        |

***

### add_entry

Copy one entry across, carrying its attributes.

```php
private static add_entry(\ZipArchive $zip, \ZipArchive $normalised, array<string,mixed> $entry): bool
```

* This method is **static**.
**Parameters:**

| Parameter     | Type                    | Description               |
|---------------|-------------------------|---------------------------|
| `$zip`        | **\ZipArchive**         | Archive being normalised. |
| `$normalised` | **\ZipArchive**         | Archive being written.    |
| `$entry`      | **array<string,mixed>** | Entry description.        |

***

### temporary_file

Reserve a scratch path alongside the artifact.

```php
private static temporary_file(string $source): string
```

* This method is **static**.
**Parameters:**

| Parameter | Type       | Description                |
|-----------|------------|----------------------------|
| `$source` | **string** | Artifact being normalised. |

**Return Value:**

Empty string when no temporary file could be created.

***
