#!/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 [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()