Skip to content

Commit

Permalink
Add files via upload
Browse files Browse the repository at this point in the history
  • Loading branch information
Cracko298 authored Jun 19, 2024
1 parent 764f385 commit 98ce15e
Showing 1 changed file with 299 additions and 0 deletions.
299 changes: 299 additions & 0 deletions CATool.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,299 @@
import os, sys, re

def extrCombAudio():
def find_segments(file_path):
with open(file_path, 'rb') as f:
data = f.read()

segments = []
start_idx = 0
while True:
fsb5_start = data.find(b'FSB5', start_idx)
if fsb5_start == -1:
break

fsb5_end = data.find(b'FSB5', fsb5_start + 4)
if fsb5_end == -1:
fsb5_end = len(data)

segments.append(data[fsb5_start:fsb5_end])
start_idx = fsb5_end
return segments

def save_segments(segments):
os.makedirs('.\\out_path', exist_ok=True)
for i, segment in enumerate(segments):
with open(f'.\\out_path\\segment_{i}.fsb', 'wb') as f:
f.write(segment)

file_path = sys.argv[2]
file_path = file_path.replace("\\",'/')
segments = find_segments(file_path)
save_segments(segments)

def find_segment_name():
file_path = sys.argv[2]
search_pattern = b'\x00\x04\x00\x00\x00'
max_search_length = 0xFF

try:
with open(file_path, 'rb') as f:
segment = f.read(max_search_length)
except FileNotFoundError:
print(f"File not found: {file_path}")
return None
except IOError as e:
print(f"Error reading file: {e}")
return None

pattern_start = segment.find(search_pattern)
if pattern_start == -1:
print("Pattern not found")
return None

string_start = pattern_start + len(search_pattern)
string_end = string_start
while string_end < len(segment) and segment[string_end] != 0x00:
string_end += 1

segment_name = segment[string_start:string_end].decode('utf-8')
return segment_name

def rename_segment():
segment_file = sys.argv[2]
segment_name1 = find_segment_name()
seg_dir = os.path.dirname(segment_file)
os.rename(segment_file,f"{seg_dir}\\{segment_name1}.fsb")

def collect_header():
audio_file = sys.argv[2]
os.makedirs('.\\out_path', exist_ok=True)
with open(audio_file,'rb+') as f:
data = f.read(0x1A2C)
with open(f".\\out_path\\header_data.bin",'wb') as of:
of.write(data)

def rebCombAudio():
audio_files = sys.argv[2]
header = f"{audio_files}\\header_data.bin"
if os.path.exists(header) != True:
print(f"Please Extract the Header from your CombinedAudio.bin File.")
sys.exit(1)
if os.path.exists(f"{audio_files}\\segment_0.fsb") != True:
print(f"This Function Requires that the Audio Files are Named into the following scheme:\n 'segment_XXX.fsb' nothing else.")
sys.exit(1)

with open(header,'rb+') as header_file:
header_data = header_file.read()

with open('.\\ModifiedCombinedAudio.bin','wb+') as f:
f.write(header_data)
for i in range(558):
with open(f"{audio_files}\\segment_{i}.fsb",'rb+') as sf:
fsb_data = sf.read()
f.write(fsb_data)

def extractByName():
audio_path = sys.argv[2]
search_text = sys.argv[3]
search_text = search_text.lower()
file_names = os.path.basename(audio_path)
directory_name = os.path.dirname(__file__)

with open(audio_path, 'rb') as file:
content = file.read()

search_text_bytes = search_text.encode('utf-8')
fsb_magic = b'FSB5'
search_text_index = -1

while True:
search_text_index = content.find(search_text_bytes, search_text_index + 1)
if search_text_index == -1:
print(f"\nSearch text '{search_text}' not found surrounded by null bytes in file.\nDid you mistype the Sound-ID?")
sys.exit(1)

if content[search_text_index - 1] == 0x00 and content[search_text_index + len(search_text_bytes)] == 0x00:
break

closest_fsb_index = content.rfind(fsb_magic, 0, search_text_index)
if closest_fsb_index == -1:
print("\nFSB5 Magic String not found before the search text.\nAre you sure this is a Soundbank FSB Archive?\n")
sys.exit(1)

next_fsb_index = content.find(fsb_magic, closest_fsb_index + len(fsb_magic))
if next_fsb_index == -1:
next_fsb_index = len(content)

extracted_data = content[closest_fsb_index:next_fsb_index]

output_path = os.path.join(directory_name, f'{search_text}.fsb')
with open(output_path, 'wb') as output_file:
output_file.write(extracted_data)

print(f"\nExtracted Soundbank FSB From '{file_names}' Archive.\nTo Output PATH: '{output_path}'.\n")

def addPadding():
originalFile = sys.argv[2]
modifiedFile = sys.argv[3]
with open(originalFile, 'rb') as f:
originalData = f.read()
ogDataLen = len(originalData)

with open(modifiedFile,'rb') as mf:
modifiedData = mf.read()
modDataLen = len(modifiedData)
mf.close()

difference = ogDataLen-modDataLen
with open(modifiedFile,'ab') as of:
for i in range(difference):
of.write(b'\x00')

def info_help():
print("""\n
python CATool.py
--eca, extract-ca [CombinedAudioPATH] > Extracts All FSB Soundbank Files from the CombinedAudio.bin Archive.
--fn, find-sn [SegmentFilePATH] > Find the Segment Name from an Extracted FSB Soundbank File via --eca Flag.
--rs, rename-s [SegmentFilePATH] > Rename a Segment File FSB Soundbank File back to it's Original Filename.
--gh, get-header [CombinedAudioPATH] > Extracts the Header from the CombinedAudio.bin Archive.
--rca, rebuild-ca [SegmentOutFolderPATH] > Rebuilds the CombinedAudio.bin Archive via Segment Files.
--ap, add-padding [OriginalFilePATH] [ModifiedFilePATH] > Adds padding to set the Modified File Equal to the Original File Size.
--ne, name-extract [CombinedAudioPATH] [Sound Name/ID] > Extracts a FSB Soundbank File from the CombinedAudio.bin Archive via Name/SoundID.
--ra, rename-all [SegmentFolderPATH] > Renames all Segment Files back to their original FSB Soundbank Filename(s).
--gsid, get-soundid [CombinedAudioPATH] > Gets all Sound Names/ID's and Dumps them to a *.txt File.
--gssg, get-size-seg [SegmentOutFolderPATH] > Gets the size of all Segment Soundbank FSB Files.
--gs, get-size [SegmentFilePATH] > Gets the size of a specific Segment Soundbank FSB File.
--h, help > Displays this Message.\n\n\n""")
os.system('pause')

def getSoundId():
filename = sys.argv[2]
with open(filename, "rb") as file:
data = file.read()

fsb5_tag = b"FSB5"
byte_array = b"\x00\x04\x00\x00\x00"
null_byte = b"\x00"
fsb5_positions = []
start = 0
while True:
pos = data.find(fsb5_tag, start)
if pos == -1:
break
fsb5_positions.append(pos)
start = pos + len(fsb5_tag)

with open('.\\ExtractedSoundIDs.txt','w') as f:
for fsb5_pos in fsb5_positions:
search_limit = fsb5_pos + 0xFF
if search_limit > len(data):
search_limit = len(data)

array_pos = data.find(byte_array, fsb5_pos, search_limit)
if array_pos != -1:
string_start = array_pos + len(byte_array)
string_end = data.find(null_byte, string_start)
if string_end != -1:
extracted_string = data[string_start:string_end].decode('utf-8', errors='replace')
print(f"Extracted string: {extracted_string}")
f.write(f"{extracted_string}\n")

def renameSegments():
directory = sys.argv[2]
files = [f for f in os.listdir(directory) if f.startswith("segment_") and f.endswith(".fsb")]
i = 0
for file_name in files:
file_path = os.path.join(directory, file_name)
with open(file_path, 'rb') as file:
data = file.read(0xFF)

target_sequence = b'\x00\x04\x00\x00\x00'
index = data.find(target_sequence)
if index != -1:
start_index = index + 5
end_index = start_index
while end_index < len(data) and data[end_index] != 0x00:
end_index += 1

new_name = data[start_index:end_index].decode('utf-8')
new_file_name = new_name + '.fsb'
new_file_path = os.path.join(directory, new_file_name)
count = 1
while os.path.exists(new_file_path):
new_file_name = f"{new_name}({count}).fsb"
new_file_path = os.path.join(directory, new_file_name)
count += 1

try:
os.rename(file_path, new_file_path)
print(f'Renamed "{file_name}" to "{new_file_name}".')

except FileExistsError:
pass

def getSize():
directory = sys.argv[2]
output_file = ".\\ExtractedAudioSizes.txt"
with open(output_file, 'w') as out:
for filename in os.listdir(directory):
if filename.startswith("segment_") and filename.endswith(".fsb"):
with open(f"{directory}\\{filename}",'rb') as f:
data_length = len(f.read())
out.write(f"Filename: {filename} | Bytes: {data_length}.\n")
print(f"Wrote: {filename} with {data_length} Bytes, to file: '{output_file}'.")

def getSizeFile():
audioFile = sys.argv[2]
baseFile = os.path.basename(audioFile)
if '.fsb' not in baseFile:
print(f"Error: File provided '{baseFile}' isn't *.fsb File.")
sys.exit(1)
baseFileName = baseFile.replace('.fsb','')
outFile = f".\\Extracted{baseFileName}Size.txt"
with open(audioFile,'rb') as f:
data_length = len(f.read())
with open(outFile,'w') as of:
of.write(f"Filename: {baseFileName} | Bytes: {data_length}.\n")
print(f"Wrote: {baseFileName} with {data_length} Bytes, to file: '{outFile}'.")

if __name__ == '__main__':
try:
callable = sys.argv[1]
if callable == 'extract-ca' or callable == '--eca':
extrCombAudio()

if callable == 'find-sn' or callable == '--fn':
print(find_segment_name())

if callable == 'rename-s' or callable == '--rs':
rename_segment()

if callable == 'get-header' or callable == '--gh':
collect_header()

if callable == 'rebuild-ca' or callable == '--rca':
rebCombAudio()

if callable == 'add-padding' or callable == '--ap':
addPadding()

if callable == "name-extract" or callable == '--ne':
extractByName()

if callable == 'help' or callable == '--h':
info_help()

if callable == 'get-soundid' or callable == '--gsid':
getSoundId()

if callable == 'rename-all' or callable == '--ra':
renameSegments()

if callable == 'get-size' or callable == '--gs': # New
getSize()

if callable == 'get-size-seg' or callable == '--gssg': # New
getSizeFile()
except IndexError:
info_help()

0 comments on commit 98ce15e

Please sign in to comment.