Skip to content

Instantly share code, notes, and snippets.

@takase1121
Last active November 7, 2020 01:44
Show Gist options
  • Save takase1121/4cc8f1ac1b710ae32ede15f41ecbc887 to your computer and use it in GitHub Desktop.
Save takase1121/4cc8f1ac1b710ae32ede15f41ecbc887 to your computer and use it in GitHub Desktop.
Extract Wallpaper Engine PKG file (PKGV0009 only)

Extract Wallpaper Engine PKG file (PKGV0009 only)

This is a plaintext description of the format:

// file is the "entry" point
[file]
0: u32 - header length
1: bytearray($0) - header
2: u32 - number of files in archive
n: dir - directory listing

[dir]
0: u32 - filename length
1: bytearray($0) - filename
2: u32 - file offset
3: u32 - file size

It's a simple format. A python script to extract it is included below.

import argparse
from pathlib import Path
# read little endian unsigned 32 bit integer
readLEU32 = lambda f: int.from_bytes(f.read(4), byteorder='little', signed=False)
class DirInfo:
"""A class that contains metadata for a file"""
def __init__(self, f):
dir_name_len = readLEU32(f)
self.name = f.read(dir_name_len).decode('utf-8')
self.offset = readLEU32(f)
self.size = readLEU32(f)
def __repr__(self):
return pprint.saferepr(self.__dict__)
class Archive:
"""A class that contains metadata for the whole file"""
def __init__(self, filename, f):
self.file = filename
header_len = readLEU32(f)
self.header = f.read(header_len).decode('utf-8')
self.dir_size = readLEU32(f)
self.contents = [DirInfo(f) for i in range(self.dir_size)]
self.metaend = f.tell()
def __repr__(self):
return pprint.saferepr(self.__dict__)
def read_meta(input_file_path):
"""Read metadata from file"""
input_file = Path(input_file_path)
with input_file.open('rb') as f:
return Archive(input_file, f)
def dump_file(meta, output_path):
"""Dump the archive into output_path"""
output = Path(output_path)
if output.exists() and not output.is_dir():
raise ValueError('Output directory cannot be created')
with meta.file.open('rb') as f:
for directory in meta.contents:
output_file_path = output / directory.name
output_file_path.parent.mkdir(parents=True, exist_ok=True)
f.seek(meta.metaend + directory.offset)
output_file_path.write_bytes(f.read(directory.size))
def main():
"""main function"""
parser = argparse.ArgumentParser(description='Dumps Wallpaper Engine pkg file into a directory. Supports PKGV0009 only.')
parser.add_argument('input_file')
parser.add_argument('output_path')
args = parser.parse_args()
archive = read_meta(args.input_file)
dump_file(archive, args.output_path)
if __name__ == '__main__':
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment