# `Cauldron3D.Formats.Files`
[🔗](https://github.com/jaman/cauldron/blob/v0.3.3/cauldron_3d_formats/lib/cauldron_3d/formats/files.ex#L1)

A game's files, gathered from one or more directories: the files loose in each, those in
its numbered `pak0.pak`, `pak1.pak`, … archives, and those in its `.pk3` zip archives,
including `.pk3` archives held inside them. Names are matched without regard to case.

    {:ok, files} = Cauldron3D.Formats.Files.open("/games/quake", within: "id1")
    Cauldron3D.Formats.Files.read(files, "maps/e1m1.bsp")

    {:ok, files} = Cauldron3D.Formats.Files.open(["/games/half-life/valve", "/mods/freehl"])

Within a directory, `.pak` archives come first in number order, then `.pk3` archives in
name order, then loose files; a later source overrides an earlier one, and a later
directory overrides an earlier directory.

## Options

  * `:within` — a subdirectory to use instead of a given directory that holds no
    archives, as a game's data directory beneath its install (`"id1"`, say)

# `entry`

```elixir
@type entry() ::
  {:pak, Path.t(), non_neg_integer(), non_neg_integer()}
  | {:zip, source(), charlist()}
  | {:loose, Path.t()}
```

# `source`

```elixir
@type source() :: Path.t() | {:inner, binary()}
```

# `t`

```elixir
@type t() :: %Cauldron3D.Formats.Files{
  dirs: [Path.t()],
  entries: %{required(String.t()) =&gt; entry()}
}
```

# `exists?`

```elixir
@spec exists?(t(), String.t()) :: boolean()
```

Whether file `name` is there.

# `list`

```elixir
@spec list(t(), String.t()) :: [String.t()]
```

The names of the files, lower case, that begin with `prefix`, sorted.

# `open`

```elixir
@spec open(Path.t() | [Path.t()], keyword()) ::
  {:ok, t()} | {:error, :no_game_directory | :not_a_pak}
```

The files of the directory or directories `paths`.

# `open!`

```elixir
@spec open!(Path.t() | [Path.t()], keyword()) :: t()
```

As `open/2`, raising `ArgumentError` on failure.

# `package`

```elixir
@spec package(t(), String.t()) :: String.t() | nil
```

The package file `name` comes from: the archive's file name for a file in a `.pak` or
`.pk3` (the outer archive for one inside another), or the directory's own name for a
loose file; `nil` when there is no such file.

# `read`

```elixir
@spec read(t(), String.t()) :: binary() | nil
```

The file `name`'s bytes, or `nil` when there is none.

# `read!`

```elixir
@spec read!(t(), String.t()) :: binary()
```

As `read/2`, raising `KeyError` when the file is missing.

---

*Consult [api-reference.md](api-reference.md) for complete listing*
