import sys from struct import pack, unpack class CabFormatError(Exception): def __init__(self, msg): super().__init__(msg) class PatchLengthError(Exception): def __init__(self, msg): super().__init__(msg) class Cab: def __init__(self, data): self.CFHEADER = CFHeader(data) self.CFFOLDER = CFFolder(data) self.CFFILE = CFFile(data) self.CFFDATA = CFFData(data, start=self.CFFILE.end_offset) @staticmethod def seek_null(data, start=0, chunk_size=24): chunk = data[start:start + chunk_size] index = chunk.find(b"\x00") return start + index if index > 0 else -1 def change_set_id(self, value: int): self.CFHEADER.setID = value def zero_out_signature(self): self.CFFDATA.csum = 0 def change_coff_cab_start(self, value: int): self.CFFOLDER.coffCabStart = value def change_ccfdata_count(self, value: int): self.CFFOLDER.cCFData = value def change_cffile_cbfile(self, value: int): self.CFFILE.cbFile = value def make_file_read_only(self): self.CFFILE.attribs |= 0x1 self.CFFILE.attribs |= 0x2 self.CFFILE.attribs |= 0x4 def change_bytes(self, offset, size, value): if len(value) < size: raise PatchLengthError _bytes = bytearray(self.to_bytes()) _bytes[offset:offset + size] = value[:size] return bytes(_bytes) def to_string(self): return rf""" CFHeader: {self.CFHEADER.to_string()} CFFolder: {self.CFFOLDER.to_string()} CFFile: {self.CFFILE.to_string()} CFFData: {self.CFFDATA.to_string()} """ def to_bytes(self): return self.CFHEADER.to_bytes() + self.CFFOLDER.to_bytes() + self.CFFILE.to_bytes() + self.CFFDATA.to_bytes() class CFHeader: def __init__(self, data): self.raw = data[:24] self.signature_display = data[:4].decode() self.signature = unpack("BBBB", data[:4]) if self.signature_display != "MSCF": raise CabFormatError("Unknown signature") self.reserved1 = unpack("