Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions .github/workflows/lint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,9 @@ jobs:
with:
submodules: true

- name: Install clang tools
run: make install_clang_tools
- run: make install_clang_tools

- run: make configure

- run: make fmt_check

Expand Down
38 changes: 6 additions & 32 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -28,14 +28,6 @@ configure: ## Configure cmake build (debug, with compile_commands.json)
-DCMAKE_CXX_COMPILER=clang++-$(CLANG_VERSION) \
-DCMAKE_CXX_FLAGS="--gcc-install-dir=$(GCC_INSTALL_DIR)"

build/compile_commands.json: CMakeLists.txt src/CMakeLists.txt
cmake -B build \
-DCMAKE_BUILD_TYPE=Debug \
-DCMAKE_EXPORT_COMPILE_COMMANDS=ON \
-DBUILD_MPQCLI=$(BUILD_MPQCLI) \
-DCMAKE_CXX_COMPILER=clang++-$(CLANG_VERSION) \
-DCMAKE_CXX_FLAGS="--gcc-install-dir=$(GCC_INSTALL_DIR)"

.PHONY: build
build: ## Build via cmake
cmake --build build
Expand Down Expand Up @@ -111,40 +103,22 @@ fmt: ## Auto-fix C++ formatting with clang-format
| xargs clang-format-$(CLANG_VERSION) -i

.PHONY: lint_cpp
lint_cpp: build/compile_commands.json ## Run clang-tidy static analysis
clang-tidy-$(CLANG_VERSION) \
--quiet -p build --header-filter="$(CURDIR)/src/.*" src/*.cpp
lint_cpp: ## Run clang-tidy static analysis (requires: make configure)
clang-tidy-$(CLANG_VERSION) --quiet -p build \
--header-filter="$(CURDIR)/src/.*" src/*.cpp 2>&1 \
| grep -v " warnings generated"; \
exit $${PIPESTATUS[0]}

.PHONY: lint
lint: fmt_check lint_cpp ## Run all C++ linters

.PHONY: ci
ci: fmt_check lint_cpp test ## Run all CI checks locally
ci: configure build fmt_check lint_cpp test ## Run all CI checks locally

# CLEAN
.PHONY: clean
clean: build_clean test_clean ## Remove all build and test artifacts

# SUBMODULES
.PHONY: bump_stormlib
bump_stormlib: ## Bump StormLib submodule to latest remote
@read -rp "[*] Bump StormLib? (y/N) " yn; \
case $$yn in \
[yY] ) git submodule update --init --remote extern/StormLib;; \
* ) echo "[*] Skipping...";; \
esac

.PHONY: bump_cli11
bump_cli11: ## Bump CLI11 submodule to latest remote
@read -rp "[*] Bump CLI11? (y/N) " yn; \
case $$yn in \
[yY] ) git submodule update --init --remote extern/CLI11;; \
* ) echo "[*] Skipping...";; \
esac

.PHONY: bump_submodules
bump_submodules: bump_stormlib bump_cli11 ## Bump all submodules to latest remote

# GET
.PHONY: get_project_version
get_project_version: ## Print the project version from CMakeLists.txt
Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

![Release Version](https://img.shields.io/github/v/release/thegraydot/mpqcli?style=flat)

![Release downloads](https://img.shields.io/github/downloads/thegraydot/mpqcli/total?label=release_downloads) ![Package downloads](https://img.shields.io/badge/package_downloads-845-green)
![Release downloads](https://img.shields.io/github/downloads/thegraydot/mpqcli/total?label=release_downloads) ![Package downloads](https://img.shields.io/badge/package_downloads-894-green)

A command-line tool to create, add, remove, list, extract, read, and verify MPQ archives using the [StormLib library](https://github.com/ladislav-zezula/StormLib).

Expand All @@ -19,7 +19,7 @@ A command-line tool to create, add, remove, list, extract, read, and verify MPQ
- Pipe the output to `grep` or other tools to search, filter, or process files
- Redirect output to files or other commands for further automation

If you require an MPQ tool with a graphical interface (GUI) and explicit support for more MPQ archive versions I would recommend using [Ladik's MPQ Editor](http://www.zezula.net/en/mpq/download.html).
If you require an MPQ tool with a graphical interface (GUI) and explicit support for more MPQ archive versions, I would recommend using [Ladik's MPQ Editor](http://www.zezula.net/en/mpq/download.html).

## Releases

Expand Down
2 changes: 2 additions & 0 deletions docs/SUMMARY.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
- [Commands](./commands_list.md)
- [version](./commands/version.md)
- [about](./commands/about.md)
- [completion](./commands/completion.md)
- [info](./commands/info.md)
- [create](./commands/create.md)
- [add](./commands/add.md)
Expand All @@ -13,6 +14,7 @@
- [extract](./commands/extract.md)
- [read](./commands/read.md)
- [verify](./commands/verify.md)
- [compact](./commands/compact.md)
- [Advanced Examples](./advanced.md)
- [Building](./building.md)
- [Contributing](./contributing.md)
Expand Down
31 changes: 31 additions & 0 deletions docs/changelog.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,36 @@
# Changelog

## 0.10.0 - 2026-06-07

### Added

- Compact subcommand to compress MPQ archive after creation/editing
- Support passing multiple files to the `add` and `remove` subcommands
- Support reading file paths from stdin in the `add` and `remove` subcommands
- Support adding entire directories with the `add` subcommand
- Add an update flag to the `add` subcommand to skip files whose archived size matches the on-disk size

### Fixed

- `extract` command now reports an error when the output directory cannot be created
- Path traversal guard in `extract` uses fully resolved paths, closing a potential bypass
- Crash when reading strong signatures from malformed or truncated archives
- Docker glibc image updated to ubuntu:24.04
- Adding files is now ordered and operating system agnostic
- `add` subcommand now returns non-zero exit codes on failure
- Error messages now include StormLib error codes
- Duplicate error messages removed
- Makefile build targets corrected in `CONTRIBUTING.md`

### Changed

- `--filename-in-archive` and `--directory-in-archive` replaced by a unified `--path` flag
- The path flag on add now acts as an archive path prefix when a directory is given

### Thanks

- Thanks to @sjoblomj for the contributions in this release

## 0.9.9 - 2026-04-05

### Fixed
Expand Down
3 changes: 0 additions & 3 deletions docs/commands.md

This file was deleted.

2 changes: 1 addition & 1 deletion docs/commands/about.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ Print information about the tool.
```bash
$ mpqcli about
Name: mpqcli
Version: 0.9.8-041480a92e698514d7938426587e93582b336b7d
Version: 0.10.0-30601b2cdf0c1a1c918709bca2e7416ab88bfa18
Author: Thomas Laurenson
License: MIT
GitHub: https://github.com/thegraydot/mpqcli
Expand Down
49 changes: 49 additions & 0 deletions docs/commands/completion.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
# completion

Print a shell completion script to stdout.

## Supported Shells

- bash
- zsh
- fish
- PowerShell

## Bash

Write the completion script to a file and source it from your shell profile.

```bash
$ mpqcli completion bash > ~/.bash_completion.d/mpqcli
$ source ~/.bash_completion.d/mpqcli
```

Alternatively, write the script to a system-wide completions directory (requires root):

```bash
$ mpqcli completion bash > /etc/bash_completion.d/mpqcli
```

## Zsh

Write the completion script to a directory that is on your `$fpath`.

```zsh
$ mpqcli completion zsh > "${fpath[1]}/_mpqcli"
```

## PowerShell

Append the completion script to your PowerShell profile so it loads automatically.

```powershell
PS> mpqcli completion powershell >> $PROFILE
```

## Fish

Write the completion script to the fish completions directory.

```fish
$ mpqcli completion fish > ~/.config/fish/completions/mpqcli.fish
```
10 changes: 10 additions & 0 deletions docs/commands/extract.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,16 @@ Extract files to a specific target directory, which will be created if it doesn'
$ mpqcli extract -o patch-1.10 wow-patch.mpq
```

## Extract all files keeping the folder structure

Use the `-k` or `--keep` flag to preserve the directory structure from the archive when extracting. Without this flag, all files are placed flat in the output directory, with only the filename retained.

```bash
$ mpqcli extract -k wow-patch.mpq
[*] Extracted: Interface/FrameXML/BlizzardFrameXML.lua
[*] Extracted: Interface/FrameXML/BlizzardFrameXML.xml
```

## Extract all files with an external listfile

Older MPQ archives do not contain (complete) file paths of their content. By providing an external listfile that lists the content of the MPQ archive, the extracted files will have the correct names and paths. Listfiles can be downloaded on [Ladislav Zezula's site](http://www.zezula.net/en/mpq/download.html).
Expand Down
2 changes: 1 addition & 1 deletion docs/commands/version.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,5 @@ Print the tool version number.

```bash
$ mpqcli version
0.9.8-041480a92e698514d7938426587e93582b336b7d
0.10.0-30601b2cdf0c1a1c918709bca2e7416ab88bfa18
```
2 changes: 2 additions & 0 deletions docs/commands_list.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ The `mpqcli` program has the following subcommands:
|---|---|
| [`version`](./commands/version.md) | Print the tool version number |
| [`about`](./commands/about.md) | Print information about the tool |
| [`completion`](./commands/completion.md) | Print shell completion script to stdout |
| [`info`](./commands/info.md) | Print information about MPQ archive properties |
| [`create`](./commands/create.md) | Create an MPQ archive from a target directory or a single file |
| [`add`](./commands/add.md) | Add a file to an existing MPQ archive |
Expand All @@ -17,3 +18,4 @@ The `mpqcli` program has the following subcommands:
| [`extract`](./commands/extract.md) | Extract one or all files from a target MPQ archive |
| [`read`](./commands/read.md) | Read a specific file to stdout |
| [`verify`](./commands/verify.md) | Verify a target MPQ archive signature |
| [`compact`](./commands/compact.md) | Compact (defragment) an MPQ archive |
2 changes: 1 addition & 1 deletion docs/introduction.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Introduction

A command-line tool to create, add, remove, list, extract, read, and verify MPQ archives using the [StormLib library](https://github.com/ladislav-zezula/StormLib).
A command-line tool to create, add, remove, list, extract, read, verify, and compact MPQ archives using the [StormLib library](https://github.com/ladislav-zezula/StormLib).

> ⚠️ **Warning:** This project is under active development and will change functionality between released versions until version 1.0.0.

Expand Down
20 changes: 19 additions & 1 deletion src/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,21 @@
# Configure version header
configure_file(mpqcli.h.in "${CMAKE_BINARY_DIR}/mpqcli.h")

# Embed completion scripts into generated headers.
# Declare the script files as configure-time dependencies so CMake re-generates
# completion_data.h whenever the bash or zsh source scripts are edited.
set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS
"${CMAKE_CURRENT_SOURCE_DIR}/completion/mpqcli.bash"
"${CMAKE_CURRENT_SOURCE_DIR}/completion/mpqcli.zsh"
"${CMAKE_CURRENT_SOURCE_DIR}/completion/mpqcli.ps1"
"${CMAKE_CURRENT_SOURCE_DIR}/completion/mpqcli.fish"
)
file(READ "${CMAKE_CURRENT_SOURCE_DIR}/completion/mpqcli.bash" BASH_COMPLETION_SCRIPT)
file(READ "${CMAKE_CURRENT_SOURCE_DIR}/completion/mpqcli.zsh" ZSH_COMPLETION_SCRIPT)
file(READ "${CMAKE_CURRENT_SOURCE_DIR}/completion/mpqcli.ps1" PS_COMPLETION_SCRIPT)
file(READ "${CMAKE_CURRENT_SOURCE_DIR}/completion/mpqcli.fish" FISH_COMPLETION_SCRIPT)
configure_file(completion_data.h.in "${CMAKE_BINARY_DIR}/completion_data.h")

# Set output directory for the executable
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin")

Expand All @@ -14,6 +29,7 @@ endif()
add_executable(mpqcli
main.cpp
commands.cpp
completion.cpp
mpq.cpp
helpers.cpp
locales.cpp
Expand All @@ -24,8 +40,10 @@ add_executable(mpqcli
add_dependencies(mpqcli storm)

# Include directories
target_include_directories(mpqcli PRIVATE
target_include_directories(mpqcli SYSTEM PRIVATE
"${CMAKE_SOURCE_DIR}/extern/StormLib/src"
)
target_include_directories(mpqcli PRIVATE
"${CMAKE_BINARY_DIR}"
)

Expand Down
21 changes: 21 additions & 0 deletions src/completion.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
#include "completion.h"

#include <iostream>

#include "completion_data.h"

void HandleCompletionBash() {
std::cout << BashCompletionScript;
}

void HandleCompletionZsh() {
std::cout << ZshCompletionScript;
}

void HandleCompletionPs() {
std::cout << PsCompletionScript;
}

void HandleCompletionFish() {
std::cout << FishCompletionScript;
}
9 changes: 9 additions & 0 deletions src/completion.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
#ifndef COMPLETION_H
#define COMPLETION_H

void HandleCompletionBash();
void HandleCompletionZsh();
void HandleCompletionPs();
void HandleCompletionFish();

#endif // COMPLETION_H
Loading