You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
Matteo Benedetto 7f0d4210dc Initial commit: PyStorm library (without assets) 1 month ago
.github Initial commit: PyStorm library (without assets) 1 month ago
examples Initial commit: PyStorm library (without assets) 1 month ago
pystorm Initial commit: PyStorm library (without assets) 1 month ago
.gitignore Initial commit: PyStorm library (without assets) 1 month ago
ASSET_EXTRACTION.md Initial commit: PyStorm library (without assets) 1 month ago
BUILD.md Initial commit: PyStorm library (without assets) 1 month ago
CONTRIBUTING.md Initial commit: PyStorm library (without assets) 1 month ago
LICENSE Initial commit: PyStorm library (without assets) 1 month ago
MANIFEST.in Initial commit: PyStorm library (without assets) 1 month ago
MPQ_INSPECTOR_README.md Initial commit: PyStorm library (without assets) 1 month ago
README.md Initial commit: PyStorm library (without assets) 1 month ago
STARCRAFT_ASSETS.md Initial commit: PyStorm library (without assets) 1 month ago
TESTING.md Initial commit: PyStorm library (without assets) 1 month ago
VERIFICATION.md Initial commit: PyStorm library (without assets) 1 month ago
build_stormlib.py Initial commit: PyStorm library (without assets) 1 month ago
create_sample_mpq.py Initial commit: PyStorm library (without assets) 1 month ago
debug_starcraft.py Initial commit: PyStorm library (without assets) 1 month ago
demo_assets.py Initial commit: PyStorm library (without assets) 1 month ago
example_game_engine.py Initial commit: PyStorm library (without assets) 1 month ago
extract_starcraft_assets.py Initial commit: PyStorm library (without assets) 1 month ago
install.sh Initial commit: PyStorm library (without assets) 1 month ago
mpq_inspector.py Initial commit: PyStorm library (without assets) 1 month ago
pyproject.toml Initial commit: PyStorm library (without assets) 1 month ago
setup.py Initial commit: PyStorm library (without assets) 1 month ago
test_gui.py Initial commit: PyStorm library (without assets) 1 month ago

README.md

PyStorm - Python Bindings for StormLib

PyStorm provides Python bindings for StormLib, a library for reading and writing MPQ (MoPaQ) archives used by Blizzard Entertainment games.

Features

  • Read MPQ archives: Open and extract files from MPQ archives
  • Write MPQ archives: Create new archives and add files
  • Modify archives: Add, remove, and rename files in existing archives
  • File search: Find files in archives using wildcards
  • Archive verification: Verify archive integrity
  • High-level and low-level APIs: Choose the interface that suits your needs
  • Cross-platform: Works on Windows, Linux, and macOS
  • 🎮 Asset Extraction: Tools for extracting and organizing game assets
  • 🖼 GUI Inspector: Visual MPQ archive browser

Requirements

  • Python 3.7 or higher
  • StormLib shared library (libstorm.so, StormLib.dll, or libstorm.dylib)

Installation

1. Install StormLib

First, you need to install the StormLib C library:

Linux/macOS

# Clone the repository
git clone https://github.com/ladislav-zezula/StormLib.git
cd StormLib

# Build and install
mkdir build && cd build
cmake ..
make
sudo make install

# Update library cache (Linux)
sudo ldconfig

Windows

Download pre-built binaries from the StormLib releases or build from source using Visual Studio.

2. Install PyStorm

pip install pystorm

Or install from source:

git clone https://github.com/enne2/pystorm.git
cd pystorm
pip install -e .

Quick Start

from pystorm import MPQArchive

# Open an existing archive
with MPQArchive("example.mpq") as archive:
    # Check if a file exists
    if archive.has_file("path/to/file.txt"):
        # Read a file
        with archive.open_file("path/to/file.txt") as mpq_file:
            content = mpq_file.read()
            print(content.decode('utf-8'))
    
    # Extract a file
    archive.extract_file("path/to/file.txt", "output.txt")
    
    # List all files
    files = archive.find_files("*")
    for file_info in files:
        print(f"{file_info['name']}: {file_info['size']} bytes")

# Create a new archive
with MPQArchive("new_archive.mpq", flags=MPQ_CREATE_ARCHIVE_V2) as archive:
    # Add a file
    archive.add_file("local_file.txt", "archived_name.txt")
    
    # Remove a file
    archive.remove_file("old_file.txt")
    
    # Rename a file
    archive.rename_file("old_name.txt", "new_name.txt")
    
    # Flush changes to disk
    archive.flush()

Low-Level API

from pystorm import (
    SFileOpenArchive, SFileCloseArchive, SFileOpenFileEx,
    SFileReadFile, SFileCloseFile, SFileGetFileSize,
    SFILE_OPEN_FROM_MPQ
)

# Open archive
archive_handle = SFileOpenArchive("example.mpq")

try:
    # Open file
    file_handle = SFileOpenFileEx(archive_handle, "file.txt", SFILE_OPEN_FROM_MPQ)
    
    try:
        # Get file size
        file_size = SFileGetFileSize(file_handle)
        
        # Read file
        data = SFileReadFile(file_handle, file_size)
        print(data.decode('utf-8'))
    finally:
        SFileCloseFile(file_handle)
finally:
    SFileCloseArchive(archive_handle)

API Reference

MPQArchive Class

High-level wrapper for MPQ archive operations.

Methods

  • __init__(path, flags=0, priority=0): Open an MPQ archive
  • close(): Close the archive
  • has_file(filename): Check if a file exists
  • open_file(filename, search_scope=SFILE_OPEN_FROM_MPQ): Open a file
  • extract_file(filename, output_path, search_scope=SFILE_OPEN_FROM_MPQ): Extract a file
  • add_file(local_path, archived_name, flags=MPQ_FILE_COMPRESS, compression=MPQ_COMPRESSION_ZLIB): Add a file
  • remove_file(filename, search_scope=SFILE_OPEN_FROM_MPQ): Remove a file
  • rename_file(old_name, new_name): Rename a file
  • find_files(mask="*"): Find files matching a pattern
  • flush(): Flush changes to disk
  • compact(listfile=None): Compact the archive
  • verify(): Verify archive integrity

MPQFile Class

High-level wrapper for file operations within an MPQ archive.

Methods

  • __init__(archive, filename, search_scope=SFILE_OPEN_FROM_MPQ): Open a file
  • close(): Close the file
  • get_size(): Get file size
  • read(size=None): Read data from the file
  • seek(offset, whence=FILE_BEGIN): Seek to a position

Constants

Open Flags

  • MPQ_OPEN_NO_LISTFILE: Don't load the listfile
  • MPQ_OPEN_NO_ATTRIBUTES: Don't load attributes
  • MPQ_OPEN_READ_ONLY: Open in read-only mode

Create Flags

  • MPQ_CREATE_LISTFILE: Create with listfile
  • MPQ_CREATE_ATTRIBUTES: Create with attributes
  • MPQ_CREATE_ARCHIVE_V1: Create version 1 archive (max 4GB)
  • MPQ_CREATE_ARCHIVE_V2: Create version 2 archive
  • MPQ_CREATE_ARCHIVE_V3: Create version 3 archive
  • MPQ_CREATE_ARCHIVE_V4: Create version 4 archive

File Flags

  • MPQ_FILE_COMPRESS: Compress the file
  • MPQ_FILE_ENCRYPTED: Encrypt the file
  • MPQ_FILE_FIX_KEY: Use fixed encryption key
  • MPQ_FILE_SINGLE_UNIT: Store as single unit
  • MPQ_FILE_DELETE_MARKER: File is marked for deletion
  • MPQ_FILE_SECTOR_CRC: File has sector CRCs

Compression Types

  • MPQ_COMPRESSION_HUFFMANN: Huffman compression
  • MPQ_COMPRESSION_ZLIB: ZLIB compression
  • MPQ_COMPRESSION_PKWARE: PKWARE compression
  • MPQ_COMPRESSION_BZIP2: BZIP2 compression
  • MPQ_COMPRESSION_SPARSE: Sparse compression
  • MPQ_COMPRESSION_ADPCM_MONO: ADPCM mono compression
  • MPQ_COMPRESSION_ADPCM_STEREO: ADPCM stereo compression
  • MPQ_COMPRESSION_LZMA: LZMA compression

Tools Included

🎮 Asset Extraction Tool

Extract and organize game assets for engine development:

python extract_starcraft_assets.py

Automatically categorizes files into:

  • audio/ - Sound effects, music
  • graphics/ - Sprites, images
  • video/ - Cinematics
  • data/ - Game data tables
  • And more...

See ASSET_EXTRACTION.md for complete guide.

🖼 MPQ Inspector (GUI)

Visual MPQ archive browser with tkinter:

python mpq_inspector.py

Features:

  • Browse and open MPQ archives visually
  • View file listings with compression details
  • Extract individual files or entire archives
  • Verify archive integrity
  • File information viewer

See MPQ_INSPECTOR_README.md for full documentation.

📊 Asset Demo Tool

Explore and analyze extracted assets:

python demo_assets.py

Features:

  • List assets by category
  • Analyze audio/graphics files
  • Search functionality
  • Interactive menu

Examples

More examples can be found in the examples/ directory.

Extract All Files from an Archive

from pystorm import MPQArchive
from pathlib import Path

def extract_all(archive_path, output_dir):
    output_dir = Path(output_dir)
    output_dir.mkdir(parents=True, exist_ok=True)
    
    with MPQArchive(archive_path) as archive:
        files = archive.find_files("*")
        for file_info in files:
            filename = file_info['name']
            output_path = output_dir / filename
            output_path.parent.mkdir(parents=True, exist_ok=True)
            
            try:
                archive.extract_file(filename, str(output_path))
                print(f"Extracted: {filename}")
            except Exception as e:
                print(f"Failed to extract {filename}: {e}")

extract_all("game.mpq", "extracted_files")

Create an Archive from a Directory

from pystorm import MPQArchive, MPQ_CREATE_ARCHIVE_V2, MPQ_FILE_COMPRESS
from pathlib import Path

def create_archive_from_dir(source_dir, archive_path):
    source_dir = Path(source_dir)
    
    with MPQArchive(archive_path, flags=MPQ_CREATE_ARCHIVE_V2) as archive:
        for file_path in source_dir.rglob("*"):
            if file_path.is_file():
                # Get relative path for archived name
                archived_name = str(file_path.relative_to(source_dir))
                # Replace backslashes with forward slashes
                archived_name = archived_name.replace("\\", "/")
                
                archive.add_file(str(file_path), archived_name)
                print(f"Added: {archived_name}")
        
        archive.flush()

create_archive_from_dir("my_files", "output.mpq")

Verify Archive Integrity

from pystorm import MPQArchive

with MPQArchive("example.mpq") as archive:
    result = archive.verify()
    if result == 0:
        print("Archive is valid!")
    else:
        print(f"Archive verification failed with code: {result}")

Troubleshooting

Library Not Found Error

If you get an error about not finding the StormLib library:

  1. Make sure StormLib is installed on your system
  2. Check that the library is in your system's library path
  3. On Linux, try running sudo ldconfig after installation
  4. Alternatively, copy the library file to the pystorm package directory

Permission Errors

Some operations (like creating or modifying archives) require write permissions. Make sure you have the necessary permissions for the files and directories you're working with.

Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

License

This project is licensed under the MIT License - see the LICENSE file for details.

Credits

  • StormLib: Created and maintained by Ladislav Zezula
  • PyStorm: Python bindings by Matteo Benedetto