Mercurial > touhou
changeset 780:1ada4036ab88
Remove now-unneeded PBG3 Python implementation
| author | Link Mauve <linkmauve@linkmauve.fr> |
|---|---|
| date | Sat, 08 Nov 2025 19:42:16 +0100 |
| parents | ee09657d3789 |
| children | 5b43c42fa680 |
| files | pytouhou/formats/pbg3.py pytouhou/utils/bitstream.pxd pytouhou/utils/bitstream.pyx pytouhou/utils/lzss.pyx |
| diffstat | 4 files changed, 0 insertions(+), 313 deletions(-) [+] |
line wrap: on
line diff
deleted file mode 100644 --- a/pytouhou/formats/pbg3.py +++ /dev/null @@ -1,155 +0,0 @@ -# -*- encoding: utf-8 -*- -## -## Copyright (C) 2011 Thibaut Girka <thib@sitedethib.com> -## -## This program is free software; you can redistribute it and/or modify -## it under the terms of the GNU General Public License as published -## by the Free Software Foundation; version 3 only. -## -## This program is distributed in the hope that it will be useful, -## but WITHOUT ANY WARRANTY; without even the implied warranty of -## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -## GNU General Public License for more details. -## - -"""PBG3 archive files handling. - -This module provides classes for handling the PBG3 file format. -The PBG3 format is the archive format used by Touhou: EoSD. - -PBG3 files are merely a bitstream composed of a header, -a file table, and LZSS-compressed files. -""" - -from collections import namedtuple -from io import BytesIO - -from pytouhou.utils.bitstream import BitStream -from pytouhou.utils import lzss - -from pytouhou.utils.helpers import get_logger - -from pytouhou.formats import WrongFormatError - -logger = get_logger(__name__) - - -class PBG3BitStream(BitStream): - """Helper class to handle strings and integers in PBG3 bitstreams.""" - - def read_int(self): - """Read an integer from the bitstream. - - Integers have variable sizes. They begin with a two-bit value indicating - the number of (non-aligned) bytes to read. - """ - - size = self.read(2) - return self.read((size + 1) * 8) - - - def read_string(self, maxsize): - """Read a string from the bitstream. - - Strings are stored as standard NULL-termianted sequences of bytes. - The only catch is that they are not byte-aligned. - """ - - string = [] - for i in range(maxsize): - byte = self.read(8) - if byte == 0: - break - string.append(byte) - return ''.join(chr(byte) for byte in string) - - - -PBG3Entry = namedtuple('PBG3Entry', 'unknown1 unknown2 checksum offset size') - - - -class PBG3: - """Handle PBG3 archive files. - - PBG3 is a file archive format used in Touhou 6: EoSD. - This class provides a representation of such files, as well as functions to - read and extract files from a PBG3 archive. - - Instance variables: - entries -- list of PBG3Entry objects describing files present in the archive - bitstream -- PBG3BitStream object - """ - - def __init__(self, entries=None, bitstream=None): - self.entries = entries or {} - self.bitstream = bitstream #TODO - - - def __enter__(self): - return self - - - def __exit__(self, type, value, traceback): - return self.bitstream.__exit__(type, value, traceback) - - - @classmethod - def read(cls, file): - """Read a PBG3 file. - - Raise an exception if the file is invalid. - Return a PBG3 instance otherwise. - """ - - magic = file.read(4) - if magic != b'PBG3': - raise WrongFormatError(magic) - - bitstream = PBG3BitStream(file) - entries = {} - - nb_entries = bitstream.read_int() - offset = bitstream.read_int() - bitstream.seek(offset) - for i in range(nb_entries): - unknown1 = bitstream.read_int() - unknown2 = bitstream.read_int() - checksum = bitstream.read_int() # Checksum of *compressed data* - offset = bitstream.read_int() - size = bitstream.read_int() - name = bitstream.read_string(255) - entries[name] = PBG3Entry(unknown1, unknown2, checksum, offset, size) - - return PBG3(entries, bitstream) - - - def list_files(self): - """List files present in the archive.""" - return self.entries.keys() - - - def get_file(self, filename, check=False): - """Extract a given file. - - If “filename” is in the archive, extract it and return its contents. - Otherwise, raise an exception. - - By default, the checksum of the file won't be verified, - you can however force the verification using the “check” argument. - """ - - unkwn1, unkwn2, checksum, offset, size = self.entries[filename] - self.bitstream.seek(offset) - data = lzss.decompress(self.bitstream, size) - if check: - # Verify the checksum - compressed_size = self.bitstream.io.tell() - offset - self.bitstream.seek(offset) - value = 0 - for c in self.bitstream.io.read(compressed_size): - value += c - value &= 0xFFFFFFFF - if value != checksum: - logger.warning('corrupted data!') - return BytesIO(data)
deleted file mode 100644 --- a/pytouhou/utils/bitstream.pxd +++ /dev/null @@ -1,10 +0,0 @@ -cdef class BitStream: - cdef public object io - cdef unsigned int bits - cdef unsigned char byte - - cdef bint read_bit(self) except -1 - cpdef unsigned int read(self, unsigned int nb_bits) except? 4242 - cpdef write_bit(self, bint bit) - cpdef write(self, unsigned int bits, unsigned int nb_bits) - cpdef flush(self)
deleted file mode 100644 --- a/pytouhou/utils/bitstream.pyx +++ /dev/null @@ -1,83 +0,0 @@ -# -*- encoding: utf-8 -*- -## -## Copyright (C) 2011 Thibaut Girka <thib@sitedethib.com> -## -## This program is free software; you can redistribute it and/or modify -## it under the terms of the GNU General Public License as published -## by the Free Software Foundation; version 3 only. -## -## This program is distributed in the hope that it will be useful, -## but WITHOUT ANY WARRANTY; without even the implied warranty of -## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -## GNU General Public License for more details. -## - -cdef class BitStream: - def __init__(self, io): - self.io = io - self.bits = 0 - self.byte = 0 - - - def __enter__(self): - return self - - - def __exit__(self, type, value, traceback): - return self.io.__exit__(type, value, traceback) - - - def seek(self, offset, whence=0): - self.io.seek(offset, whence) - self.byte = 0 - self.bits = 0 - - - cdef bint read_bit(self) except -1: - cdef bytes byte - if not self.bits: - byte = self.io.read(1) - self.byte = (<unsigned char*>byte)[0] - self.bits = 8 - self.bits -= 1 - return (self.byte >> self.bits) & 0x01 - - - cpdef unsigned int read(self, unsigned int nb_bits) except? 4242: - cdef unsigned int value = 0, read = 0 - cdef unsigned int nb_bits2 = nb_bits - cdef bytes byte - - while nb_bits2: - if not self.bits: - byte = self.io.read(1) - self.byte = (<unsigned char*>byte)[0] - self.bits = 8 - read = self.bits if nb_bits2 > self.bits else nb_bits2 - nb_bits2 -= read - self.bits -= read - value |= (self.byte >> self.bits) << nb_bits2 - return value & ((1 << nb_bits) - 1) - - - cpdef write_bit(self, bint bit): - if self.bits == 8: - self.io.write(chr(self.byte)) - self.bits = 0 - self.byte = 0 - self.byte &= ~(1 << (7 - self.bits)) - self.byte |= bit << (7 - self.bits) - self.bits += 1 - - - cpdef write(self, unsigned int bits, unsigned int nb_bits): - for i in range(nb_bits): - self.write_bit(bits >> (nb_bits - 1 - i) & 0x01) - - - cpdef flush(self): - self.io.write(chr(self.byte)) - self.bits = 0 - self.byte = 0 - self.io.flush() -
deleted file mode 100644 --- a/pytouhou/utils/lzss.pyx +++ /dev/null @@ -1,65 +0,0 @@ -# -*- encoding: utf-8 -*- -## -## Copyright (C) 2011 Thibaut Girka <thib@sitedethib.com> -## -## This program is free software; you can redistribute it and/or modify -## it under the terms of the GNU General Public License as published -## by the Free Software Foundation; version 3 only. -## -## This program is distributed in the hope that it will be useful, -## but WITHOUT ANY WARRANTY; without even the implied warranty of -## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -## GNU General Public License for more details. -## - -cimport cython -from libc.stdlib cimport calloc, malloc, free - -from .bitstream cimport BitStream - - -@cython.cdivision(True) -cpdef bytes decompress(BitStream bitstream, - Py_ssize_t size, - unsigned int dictionary_size=0x2000, - unsigned int offset_size=13, - unsigned int length_size=4, - unsigned int minimum_match_length=3): - cdef Py_ssize_t ptr, length - cdef unsigned int dictionary_head - cdef unsigned char byte - cdef char *out_data - cdef char *dictionary - - out_data = <char*> malloc(size) - dictionary = <char*> calloc(dictionary_size, 1) - dictionary_head, ptr = 1, 0 - - while ptr < size: - if bitstream.read_bit(): - # The `flag` bit is set, indicating the upcoming chunk of data is a literal - # Add it to the uncompressed file, and store it in the dictionary - byte = bitstream.read(8) - dictionary[dictionary_head] = byte - dictionary_head = (dictionary_head + 1) % dictionary_size - out_data[ptr] = byte - ptr += 1 - else: - # The `flag` bit is not set, the upcoming chunk is a (offset, length) tuple - offset = bitstream.read(offset_size) - length = bitstream.read(length_size) + minimum_match_length - if ptr + length > size: - raise Exception - if offset == 0 and length == 0: - break - for i in range(offset, offset + length): - out_data[ptr] = dictionary[i % dictionary_size] - dictionary[dictionary_head] = dictionary[i % dictionary_size] - dictionary_head = (dictionary_head + 1) % dictionary_size - ptr += 1 - - _out_data = out_data[:size] - free(out_data) - free(dictionary) - return _out_data -
