Started parsing header data
This commit is contained in:
95
main.py
95
main.py
@@ -5,26 +5,77 @@ from pathlib import Path
|
|||||||
|
|
||||||
class BZZCompressor:
|
class BZZCompressor:
|
||||||
def decompress(self, input_file_path, input_file, output_folder="out/") -> bytes:
|
def decompress(self, input_file_path, input_file, output_folder="out/") -> bytes:
|
||||||
data = bitarray(endian="big")
|
data = bytes()
|
||||||
output_buffer = bytearray()
|
output_buffer = bytearray()
|
||||||
index = 0x800
|
overflow_buffer = bytearray()
|
||||||
|
|
||||||
# read the input file
|
# read the input file
|
||||||
try:
|
try:
|
||||||
with open(f"{input_file_path}/{input_file}", "rb") as infile:
|
with open(f"{input_file_path}/{input_file}", "rb") as infile:
|
||||||
data.fromfile(infile)
|
temp = bitarray(endian="big")
|
||||||
data = data.tobytes()
|
temp.fromfile(infile)
|
||||||
|
|
||||||
|
data = temp.tobytes()
|
||||||
except IOError:
|
except IOError:
|
||||||
print("Could not open input file...")
|
print("Could not open input file...")
|
||||||
raise
|
raise
|
||||||
|
|
||||||
if len(data) > 9:
|
##############################################################################
|
||||||
# Getting our method, this is likely imprecise, since I'm one dealing with one method type, but it gets what I want
|
#
|
||||||
|
# Reading the Headers from the file.
|
||||||
|
#
|
||||||
|
# This includes the version, some garbage 0s, the number of files, and the
|
||||||
|
# file list (probably), and finally a Checksum
|
||||||
|
#
|
||||||
|
##############################################################################
|
||||||
|
|
||||||
|
# This is always 1, 0, 0, 0. so I'm just having fun
|
||||||
|
bzz_version = f"v{data[0]}.{data[1]}.{data[2]}.{data[3]}"
|
||||||
|
game_id = "".join([str(int(bin(item)[2:], 2)) for item in data[4:8]])
|
||||||
|
|
||||||
|
num_files = 0
|
||||||
|
|
||||||
|
for item in data[8:12]:
|
||||||
|
num_files += int(bin(item)[2:].zfill(8), 2)
|
||||||
|
|
||||||
|
print(f"BZZ Version: {bzz_version}")
|
||||||
|
print(f"Game ID: {game_id}")
|
||||||
|
print(f"Number of Files: {num_files}")
|
||||||
|
|
||||||
|
files = []
|
||||||
|
|
||||||
|
for i in range(num_files):
|
||||||
|
tmp = (i) * 12
|
||||||
|
files.append(
|
||||||
|
{
|
||||||
|
"pt_a": data[12 + tmp : 12 + tmp + 4],
|
||||||
|
"pt_b": data[12 + tmp + 4 : 12 + tmp + 8],
|
||||||
|
"pt_c": data[12 + tmp + 8 : 12 + tmp + 12],
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
for i, file in enumerate(files):
|
||||||
|
print(f"File {i+1}'s Data: {file}")
|
||||||
|
|
||||||
|
checksum = data[0x7FC:0x800]
|
||||||
|
print(f"Checksum: {checksum}")
|
||||||
|
|
||||||
|
##############################################################################
|
||||||
|
#
|
||||||
|
# This is the File Loop, where we process
|
||||||
|
# individual files from the .bzz
|
||||||
|
#
|
||||||
|
##############################################################################
|
||||||
|
index = 0x800
|
||||||
|
|
||||||
|
# Getting our method, this is likely imprecise, since I'm one dealing with one
|
||||||
|
# method type, but it gets what I want
|
||||||
method = data[index]
|
method = data[index]
|
||||||
# We move on to the next byte in data
|
# We move on to the next byte in data
|
||||||
index = index + 1
|
index = index + 1
|
||||||
|
|
||||||
# Gathering variables based on the method according to https://problemkaputt.de/psxspx-cdrom-file-compression-bzz.htm
|
# Gathering variables based on the method according to
|
||||||
|
# https://problemkaputt.de/psxspx-cdrom-file-compression-bzz.htm
|
||||||
# Note: bin(int)[2:].zfill(8) converts a number to an 8-bit binary string
|
# Note: bin(int)[2:].zfill(8) converts a number to an 8-bit binary string
|
||||||
|
|
||||||
# `>> 3` is the same as dividing by 8
|
# `>> 3` is the same as dividing by 8
|
||||||
@@ -61,7 +112,7 @@ class BZZCompressor:
|
|||||||
print(f"Len Mask: {bin(len_mask)}")
|
print(f"Len Mask: {bin(len_mask)}")
|
||||||
print(f"Threshold: {threshold}")
|
print(f"Threshold: {threshold}")
|
||||||
print(f"Len Table: {len_table}")
|
print(f"Len Table: {len_table}")
|
||||||
print(f"Num Flags: {bin(num_flags)}")
|
print(f"Loops (based on num flags): {num_flags}")
|
||||||
|
|
||||||
# Adding 0x100 here means the bitarray is a length of 9, and the first item is always 1
|
# Adding 0x100 here means the bitarray is a length of 9, and the first item is always 1
|
||||||
# This means that later, when we need to gather more flag bits, we aren't losing any data, or
|
# This means that later, when we need to gather more flag bits, we aren't losing any data, or
|
||||||
@@ -69,15 +120,10 @@ class BZZCompressor:
|
|||||||
flag_bits = bitarray(bin(data[index] + 0x100)[2:])
|
flag_bits = bitarray(bin(data[index] + 0x100)[2:])
|
||||||
index = index + 1
|
index = index + 1
|
||||||
|
|
||||||
print(f"Starting flag_bits: {flag_bits}")
|
|
||||||
|
|
||||||
while num_flags > 0:
|
while num_flags > 0:
|
||||||
carry = flag_bits[-1]
|
carry = flag_bits[-1]
|
||||||
flag_bits = flag_bits >> 1
|
flag_bits = flag_bits >> 1
|
||||||
|
|
||||||
print(f"Carry: {carry}")
|
|
||||||
print(f"Flag Bits: {flag_bits}")
|
|
||||||
|
|
||||||
# if we are down to only 0 bits, we are out of file-driven data
|
# if we are down to only 0 bits, we are out of file-driven data
|
||||||
# Here we collect more flag bits and re-iterate the loop
|
# Here we collect more flag bits and re-iterate the loop
|
||||||
if int(flag_bits.to01(), 2) == 0x00:
|
if int(flag_bits.to01(), 2) == 0x00:
|
||||||
@@ -128,10 +174,10 @@ class BZZCompressor:
|
|||||||
)
|
)
|
||||||
return
|
return
|
||||||
|
|
||||||
print(f"Output Buffer Size {len(output_buffer)}")
|
# print(f"Output Buffer Size {len(output_buffer)}")
|
||||||
print(f"Distance Data: {distance_data}")
|
# print(f"Distance Data: {distance_data}")
|
||||||
print(f"Displacement: {displacement}")
|
# print(f"Displacement: {displacement}")
|
||||||
print(f"Length: {length}")
|
# print(f"Length: {length}")
|
||||||
|
|
||||||
# Here we copy bit by bit from earlier in the output buffer.
|
# Here we copy bit by bit from earlier in the output buffer.
|
||||||
# we use this instead of index slicing since the slice could lead to
|
# we use this instead of index slicing since the slice could lead to
|
||||||
@@ -152,12 +198,7 @@ class BZZCompressor:
|
|||||||
|
|
||||||
if len(data) > index:
|
if len(data) > index:
|
||||||
for item in data[index:]:
|
for item in data[index:]:
|
||||||
output_buffer.append(item)
|
overflow_buffer.append(item)
|
||||||
|
|
||||||
else:
|
|
||||||
# If the file is less than 9 bits, it's just output
|
|
||||||
for i in data:
|
|
||||||
output_buffer.append(i)
|
|
||||||
|
|
||||||
# This handoff is so I can change buffer logic without breaking write-out logic
|
# This handoff is so I can change buffer logic without breaking write-out logic
|
||||||
out_data = output_buffer
|
out_data = output_buffer
|
||||||
@@ -166,6 +207,12 @@ class BZZCompressor:
|
|||||||
with open(f"{output_folder}/{input_file}.file", "wb") as outfile:
|
with open(f"{output_folder}/{input_file}.file", "wb") as outfile:
|
||||||
outfile.write(out_data)
|
outfile.write(out_data)
|
||||||
print(f"File {output_folder}/{input_file}.file saved successfully!")
|
print(f"File {output_folder}/{input_file}.file saved successfully!")
|
||||||
|
|
||||||
|
with open(f"{output_folder}/{input_file}.overflow.file", "wb") as outfile:
|
||||||
|
outfile.write(overflow_buffer)
|
||||||
|
print(
|
||||||
|
f"File {output_folder}/{input_file}.overflow.file saved successfully!"
|
||||||
|
)
|
||||||
except IOError as e:
|
except IOError as e:
|
||||||
print(
|
print(
|
||||||
f"Unable to write file for {input_file_path}/{input_file}. Error: {e}"
|
f"Unable to write file for {input_file_path}/{input_file}. Error: {e}"
|
||||||
@@ -179,7 +226,7 @@ if __name__ == "__main__":
|
|||||||
print(f"{dirpath} | {', '.join(filenames)}")
|
print(f"{dirpath} | {', '.join(filenames)}")
|
||||||
|
|
||||||
for file in filenames:
|
for file in filenames:
|
||||||
if file[-4:] == ".bzz":
|
if file[-4:] == ".bzz" and file == "language.bzz":
|
||||||
output_folder_path = Path(f"out/{'/'.join(dirpath.split("/")[2:])}")
|
output_folder_path = Path(f"out/{'/'.join(dirpath.split("/")[2:])}")
|
||||||
output_folder_path.mkdir(parents=True, exist_ok=True)
|
output_folder_path.mkdir(parents=True, exist_ok=True)
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user