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.
130 lines
4.3 KiB
130 lines
4.3 KiB
#!/usr/bin/env python3 |
|
""" |
|
Example: List files in an MPQ archive with detailed information |
|
""" |
|
|
|
from pystorm import MPQArchive |
|
from pathlib import Path |
|
import sys |
|
|
|
|
|
def format_size(size_bytes): |
|
"""Format size in bytes to human-readable format""" |
|
for unit in ['B', 'KB', 'MB', 'GB']: |
|
if size_bytes < 1024.0: |
|
return f"{size_bytes:.2f} {unit}" |
|
size_bytes /= 1024.0 |
|
return f"{size_bytes:.2f} TB" |
|
|
|
|
|
def list_archive_files(archive_path, pattern="*", detailed=False): |
|
""" |
|
List files in an MPQ archive |
|
|
|
Args: |
|
archive_path: Path to the MPQ archive |
|
pattern: Pattern to match files (default: "*") |
|
detailed: Show detailed information (default: False) |
|
""" |
|
archive_path = Path(archive_path) |
|
|
|
if not archive_path.exists(): |
|
print(f"Error: Archive not found: {archive_path}") |
|
return False |
|
|
|
print(f"Archive: {archive_path}") |
|
print(f"Pattern: {pattern}\n") |
|
|
|
try: |
|
with MPQArchive(str(archive_path)) as archive: |
|
# Find files |
|
files = archive.find_files(pattern) |
|
|
|
if not files: |
|
print("No files found matching pattern") |
|
return True |
|
|
|
print(f"Found {len(files)} file(s)\n") |
|
|
|
# Calculate totals |
|
total_size = sum(f['size'] for f in files) |
|
total_compressed = sum(f['compressed_size'] for f in files) |
|
|
|
if detailed: |
|
# Detailed listing |
|
print(f"{'Name':<50} {'Size':<12} {'Compressed':<12} {'Ratio':<8} {'Flags'}") |
|
print("=" * 100) |
|
|
|
for file_info in sorted(files, key=lambda x: x['name']): |
|
name = file_info['name'] |
|
size = file_info['size'] |
|
compressed = file_info['compressed_size'] |
|
flags = file_info['flags'] |
|
|
|
# Calculate compression ratio |
|
if size > 0: |
|
ratio = (1 - compressed / size) * 100 |
|
else: |
|
ratio = 0 |
|
|
|
# Format flags |
|
flag_str = [] |
|
if flags & 0x00000200: # MPQ_FILE_COMPRESS |
|
flag_str.append("C") |
|
if flags & 0x00010000: # MPQ_FILE_ENCRYPTED |
|
flag_str.append("E") |
|
if flags & 0x01000000: # MPQ_FILE_SINGLE_UNIT |
|
flag_str.append("S") |
|
flag_display = "".join(flag_str) or "-" |
|
|
|
print(f"{name:<50} {format_size(size):<12} {format_size(compressed):<12} " |
|
f"{ratio:>6.1f}% {flag_display}") |
|
else: |
|
# Simple listing |
|
for file_info in sorted(files, key=lambda x: x['name']): |
|
print(f" {file_info['name']}") |
|
|
|
# Print summary |
|
print("\n" + "=" * 100) |
|
print(f"Total files: {len(files)}") |
|
print(f"Total size: {format_size(total_size)}") |
|
print(f"Total compressed: {format_size(total_compressed)}") |
|
|
|
if total_size > 0: |
|
overall_ratio = (1 - total_compressed / total_size) * 100 |
|
print(f"Overall compression ratio: {overall_ratio:.1f}%") |
|
|
|
return True |
|
|
|
except Exception as e: |
|
print(f"Error reading archive: {e}") |
|
return False |
|
|
|
|
|
def main(): |
|
"""Main entry point""" |
|
if len(sys.argv) < 2: |
|
print("Usage: python list_files.py <archive.mpq> [pattern] [--detailed]") |
|
print("\nExample:") |
|
print(" python list_files.py game.mpq") |
|
print(" python list_files.py game.mpq '*.txt'") |
|
print(" python list_files.py game.mpq '*' --detailed") |
|
sys.exit(1) |
|
|
|
archive_path = sys.argv[1] |
|
pattern = "*" |
|
detailed = False |
|
|
|
# Parse arguments |
|
for arg in sys.argv[2:]: |
|
if arg == "--detailed" or arg == "-d": |
|
detailed = True |
|
elif not arg.startswith('-'): |
|
pattern = arg |
|
|
|
success = list_archive_files(archive_path, pattern, detailed) |
|
sys.exit(0 if success else 1) |
|
|
|
|
|
if __name__ == "__main__": |
|
main()
|
|
|