From b8bb1f4070eec1ffd7f6148eb3839ce893f3bfe7 Mon Sep 17 00:00:00 2001 From: bluebear94 Date: Fri, 22 Jul 2016 15:06:11 -0400 Subject: Initial commit --- .gitignore | 2 ++ LICENSE | 20 +++++++++++ README.md | 16 +++++++++ repack.py | 115 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 153 insertions(+) create mode 100755 .gitignore create mode 100755 LICENSE create mode 100755 README.md create mode 100644 repack.py diff --git a/.gitignore b/.gitignore new file mode 100755 index 0000000..587a903 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +test*/ + diff --git a/LICENSE b/LICENSE new file mode 100755 index 0000000..8049bba --- /dev/null +++ b/LICENSE @@ -0,0 +1,20 @@ +The MIT License (MIT) +Copyright (c) 2016 kyarei + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md new file mode 100755 index 0000000..b6c9b91 --- /dev/null +++ b/README.md @@ -0,0 +1,16 @@ +## cripper + +the C program that rips your PH3 archives apart + +### Usage: + + # to compile it: + make + # to rip apart an archive: + ./cripper --verbose archive.dat path/to/destination + # same, but doesn't produce output: + ./cripper archive.dat path/to/destination + +### Further reading + +[Notes on the format](https://gist.github.com/bluebear94/f5a7afe5396b2626d63546bda400bffa) diff --git a/repack.py b/repack.py new file mode 100644 index 0000000..e4d7116 --- /dev/null +++ b/repack.py @@ -0,0 +1,115 @@ +#!/usr/bin/env python3 + +import argparse +import io +import pathlib +import zlib + +# The MIT License (MIT) +# Copyright (c) 2016 kyarei +# +# Permission is hereby granted, free of charge, to any person obtaining a copy of +# this software and associated documentation files (the "Software"), to deal in +# the Software without restriction, including without limitation the rights to +# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +# of the Software, and to permit persons to whom the Software is furnished to do +# so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + +# Usage: python3 repack.py + +# Parse the arguments + +parser = argparse.ArgumentParser(description='Repack Wizard101 WAD files.') +parser.add_argument('sourcePath', type=str, + help='the root directory of the files to be archived') +parser.add_argument('archivePath', type=str, + help='the path of the archive file to be made') +parser.add_argument('--verbose', '-v', type=bool, + help='if enabled, use diagnostics') + +args = parser.parse_args() + +# Get all files in the directory specified + +root = pathlib.Path(args.sourcePath) +files = root.glob("**/*"); +entries = [] +offset = 14 # Precalculate offset of data section in loop below + +# Make entries of all files + +for f in files: + if f.is_file(): + with f.open(mode="rb") as h: + contents = h.read(-1) + compressedContents = zlib.compress(contents) + uSize = len(contents) + zSize = len(compressedContents) + name = str(f.relative_to(root)) + isCompressed = zSize < uSize + crc = zlib.crc32(contents) + entry = { + "contents": contents, + "compressedContents": compressedContents, + "uSize": uSize, + "zSize": zSize, + "name": name, + "isCompressed": isCompressed, + "crc": crc + } + entries.append(entry) + offset += 22 + len(name) + if args.verbose: + print("> File %s acknowledged" % name) + +if args.verbose: + print("%d files acknowledged" % len(entries)) + +# Open the output file + +out = open(args.archivePath, "wb"); + +def writeByte(stream, val): + stream.write(bytes([val])) +def writeInt(stream, val): + stream.write(val.to_bytes(4, byteorder="little")) + +if args.verbose: + print("Opened output file; writing data...") + +# Write magic string +out.write(b"KIWAD") +# Write version +writeInt(out, 2) +# Write number of files +writeInt(out, len(entries)) +# Write dummy byte +writeByte(out, 1) +# Write file ENTRIES +for e in entries: + netSize = e["zSize"] if e["isCompressed"] else e["uSize"] + writeInt(out, offset) # Offset + writeInt(out, e["uSize"]) + writeInt(out, e["zSize"]) + writeByte(out, e["isCompressed"]) + writeInt(out, e["crc"]) + writeInt(out, len(e["name"].encode()) + 1) # includes terminating null + out.write(e["name"].encode()) + writeByte(out, 0) + offset += netSize + print("> Wrote ENTRY for %s" % e["name"]) +# Write file DATA +for e in entries: + out.write(e["compressedContents"] if e["isCompressed"] else e["contents"]) + print("> Wrote DATA for %s" % e["name"]) -- cgit v1.2.3