diff --git a/PyCriCodecs/acb.py b/PyCriCodecs/acb.py index 8307729..557ec42 100644 --- a/PyCriCodecs/acb.py +++ b/PyCriCodecs/acb.py @@ -5,6 +5,7 @@ from .hca import HCA import os + # TODO revamp the whole ACB class. ACB is a lot more complex with those @UTF tables. class ACB(UTF): """ An ACB is basically a giant @UTF table. Use this class to extract any ACB. """ @@ -18,46 +19,47 @@ def __init__(self, filename) -> None: self.filename = filename self.acbparse(self.payload) # TODO check on ACB version. - + def acbparse(self, payload: list) -> None: """ Recursively parse the payload. """ for dict in range(len(payload)): for k, v in payload[dict].items(): if v[0] == UTFTypeValues.bytes: - if v[1].startswith(UTFType.UTF.value): #or v[1].startswith(UTFType.EUTF.value): # ACB's never gets encrypted? + if v[1].startswith( + UTFType.UTF.value): # or v[1].startswith(UTFType.EUTF.value): # ACB's never gets encrypted? par = UTF(v[1]).get_payload() payload[dict][k] = par self.acbparse(par) self.load_awb() - + def load_awb(self) -> None: # There are two types of ACB's, one that has an AWB file inside it, # and one with an AWB pair. if self.payload[0]['AwbFile'][1] == b'': if type(self.filename) == str: - awbObj = AWB(os.path.join(os.path.dirname(self.filename), self.payload[0]['Name'][1]+".awb")) + awbObj = AWB(os.path.join(os.path.dirname(self.filename), self.payload[0]['Name'][1] + ".awb")) else: - awbObj = AWB(self.payload[0]['Name'][1]+".awb") + awbObj = AWB(self.payload[0]['Name'][1] + ".awb") else: awbObj = AWB(self.payload[0]['AwbFile'][1]) self.awb = awbObj - + # revamping... - def exp_extract(self, decode: bool = False, key = 0): + def exp_extract(self, decode: bool = False, key=0): # There are two types of ACB's, one that has an AWB file inside it, # and one with an AWB pair. Or multiple AWB's. # TODO Add multiple AWB loading. if self.payload[0]['AwbFile'][1] == b'': if type(self.filename) == str: - awbObj = AWB(os.path.join(os.path.dirname(self.filename), self.payload[0]['Name'][1]+".awb")) + awbObj = AWB(os.path.join(os.path.dirname(self.filename), self.payload[0]['Name'][1] + ".awb")) else: - awbObj = AWB(self.payload[0]['Name'][1]+".awb") + awbObj = AWB(self.payload[0]['Name'][1] + ".awb") else: awbObj = AWB(self.payload[0]['AwbFile'][1]) pl = self.payload[0] - names = [] # Where all filenames will end up in. + names = [] # Where all filenames will end up in. # cuename > cue > block > sequence > track > track_event > command > synth > waveform # seems to be the general way to do it, some may repeat, and some may go back to other tables. # I will try to make this code go through all of them in advance. @@ -67,7 +69,7 @@ def exp_extract(self, decode: bool = False, key = 0): for i in pl["CueNameTable"]: cue_names_and_indexes.append((i["CueIndex"], i["CueName"])) srt_names = sorted(cue_names_and_indexes, key=lambda x: x[0]) - + """ Go through all cues and match wavforms or names. """ for i in cue_names_and_indexes: @@ -79,12 +81,15 @@ def exp_extract(self, decode: bool = False, key = 0): usememory: bool = wavform['Streaming'][1] == 0 if "Id" in wavform: - wavform["MemoryAwbId"] = wavform["Id"] # Old ACB's use "Id", so we default it to the new MemoryAwbId slot. + wavform["MemoryAwbId"] = wavform[ + "Id"] # Old ACB's use "Id", so we default it to the new MemoryAwbId slot. if usememory: - assert len(wavform['MemoryAwbId']) == len(srt_names) # Will error if not so. TODO add extracting without filenames references. - names = [y[1][1] for _,y in sorted(zip([x[1] for x in pl["WaveformTable"]], srt_names), key=lambda z: z[0])] - break # We break, since we did everything in the line above. I don't think ref_type changes between cues. + assert len(wavform['MemoryAwbId']) == len( + srt_names) # Will error if not so. TODO add extracting without filenames references. + names = [y[1][1] for _, y in + sorted(zip([x[1] for x in pl["WaveformTable"]], srt_names), key=lambda z: z[0])] + break # We break, since we did everything in the line above. I don't think ref_type changes between cues. else: # TODO @@ -96,7 +101,7 @@ def exp_extract(self, decode: bool = False, key = 0): elif ref_type == 3: sequence = pl['SequenceTable'][i[0]] - track_type = sequence['Type'][1] # Unused but will leave it here if needed. + track_type = sequence['Type'][1] # Unused but will leave it here if needed. for tr_idx in iter_unpack(">H", sequence['TrackIndex'][1]): # TODO I am here currently. pass @@ -107,7 +112,7 @@ def exp_extract(self, decode: bool = False, key = 0): else: raise NotImplementedError("Unknown ReferenceType inside ACB.") - + def parse_type1(self): pass @@ -138,24 +143,30 @@ def parse_commands(self): def parse_sequence(self): pass - def extract(self, decode: bool = False, key: int = 0, dirname: str = ""): - """ Extracts audio files in an AWB/ACB without preserving filenames. """ + def extract(self, decode: bool = False, key: int = 0, dirname: str = "", filename: str = ""): + """Extracts audio files in an AWB/ACB without preserving filenames.""" if dirname: os.makedirs(dirname, exist_ok=True) - filename = 0 - for i in self.awb.getfiles(): - Extension: str = self.get_extension(self.payload[0]['WaveformTable'][filename]['EncodeType'][1]) + + for fileIndex, i in enumerate(self.awb.getfiles()): + Extension = self.get_extension(self.payload[0]['WaveformTable'][fileIndex]['EncodeType'][1]) + + if filename: + file_prefix = f"{filename}-" + else: + file_prefix = "" + if decode and Extension == ".hca": - hca = HCA(i, key=key, subkey=self.awb.subkey).decode() - open(os.path.join(dirname, str(filename)+".wav"), "wb").write(hca) - filename += 1 + hca = HCA(i, key=key, subkey=self.awb.subkey).decode() + with open(os.path.join(dirname, f"{file_prefix}{fileIndex}.wav"), "wb") as f: + f.write(hca) else: - open(os.path.join(dirname, f"{filename}{Extension}"), "wb").write(i) - filename += 1 - + with open(os.path.join(dirname, f"{file_prefix}{fileIndex}{Extension}"), "wb") as f: + f.write(i) + def get_extension(self, EncodeType: int) -> str: if EncodeType == 0 or EncodeType == 3: - return ".adx" # Maybe 0 is ahx? + return ".adx" # Maybe 0 is ahx? elif EncodeType == 2 or EncodeType == 6: return ".hca" elif EncodeType == 7 or EncodeType == 10: @@ -175,6 +186,7 @@ def get_extension(self, EncodeType: int) -> str: else: return "" + # TODO Have to finish correct ACB extracting first. class ACBBuilder(UTFBuilder): - pass \ No newline at end of file + pass