def write_stream(self, stream): if not isinstance(stream, BinaryWriter): wtr = BinaryWriter(stream) else: wtr = stream wtr.write(self.original_header) wtr.seek(0) wtr.write(self.chunk_id) wtr.seek(0x31) wtr.write_uint8(self.loop_flag) wtr.write_uint8(self.channels) coding = self.coding if self.sample_rate == 32728: coding |= 4 elif self.sample_rate == 16364: coding |= 2 else: raise NotImplementedError() wtr.seek(0x100) buffer = self.buffer.copy() buffer = buffer.reshape((buffer.shape[0], buffer.shape[1] // 0x10, 0x10)) buffer = buffer.swapaxes(0, 1) wtr.write(buffer.tobytes()) size = wtr.tell() wtr.seek(0x40) wtr.write_uint32(size)
def decompress(data: bytes): rdr = BinaryReader(data) wtr = BinaryWriter() type = rdr.read_uint8() if type != 0x30: raise Exception("Tried to decompress commands that isn't RLE") ds = rdr.read_uint24() if ds == 0: rdr.read_uint32() while True: flag = rdr.read_uint8() if flag is None: break # we've hit the end compressed = (flag & 0x80) > 0 lenght = flag & 0x7f lenght += 3 if compressed else 1 if compressed: next = rdr.read_uint8() for i in range(lenght): wtr.write_uint8(next) else: wtr.write(rdr.read(lenght)) return wtr.data
def decompress(data: bytes) -> bytes: rdr = BinaryReader(data) wtr = BinaryWriter() compression_type = rdr.read_uint8() if compression_type == 0x24: blocksize = 4 elif compression_type == 0x28: blocksize = 8 else: raise Exception( "Tried to decompress something as huffman that isn't huffman") ds = rdr.read_uint24() if ds == 0: rdr.read_uint32() # Read the tree treesize = (rdr.read_uint8() + 1) * 2 tree_end = (rdr.c - 1) + treesize rootNode = HuffTreeNode.from_rdr(rdr, False, 5, tree_end) rdr.c = tree_end # Decompress with the tree bitsleft = 0 # amount of bits left to read from {commands} current_size = 0 currentNode = rootNode cashedbyte = -1 while current_size < ds: # Find next refrence to commands node while not currentNode.is_data: if bitsleft == 0: data = rdr.read_uint32() bitsleft = 32 bitsleft -= 1 nextIsOne = (data & (1 << bitsleft)) != 0 if nextIsOne: currentNode = currentNode.child1 else: currentNode = currentNode.child0 if blocksize == 8: current_size += 1 wtr.write_uint8(currentNode.data) elif blocksize == 4: if cashedbyte < 0: cashedbyte = currentNode.data else: cashedbyte |= currentNode.data << 4 wtr.write_uint8(cashedbyte) current_size += 1 cashedbyte = -1 currentNode = rootNode return wtr.data
def write(self, bw: BinaryWriter): bw.seek(0x40, io.SEEK_SET) bw.write(self.label) bw.write_uint32(self.unk1) bw.write_uint32(0xFF10) bw.write_uint32(0xFFFFFFB0) bw.write_uint16(0x1) bw.write_uint16(self.tpqn) bw.write_uint16(0xFF01) bw.write_uint8(self.num_tracks) bw.write_uint8(self.num_channels) bw.write_uint32(0x0F000000) bw.write_uint32(0xFFFFFFFF) bw.write_uint32(0x40000000) bw.write_uint32(0x00404000) bw.write_uint16(0x0200) bw.write_uint16(0x0800) bw.write_uint32(0xFFFFFF00) bw.write(b"\xFF" * 16)
def pcm16_to_adpcm(pcm16: np.ndarray): enc_sample = pcm16_to_adpcm_encode_sample # Uses BytesIO which is faster then concatination. wtr = BinaryWriter() wtr.write_uint16(pcm16[0]) sample, enc_index, enc_pred = enc_sample(pcm16[0], 0, 0) wtr.write_uint16(enc_index) for i in range(1, len(pcm16)): if sample is None: sample, enc_index, enc_pred = \ enc_sample(pcm16[0], enc_index, enc_pred) else: sample2, enc_index, enc_pred = \ enc_sample(pcm16[0], enc_index, enc_pred) wtr.write_byte(sample2 << 4 | sample) sample = None if sample is not None: wtr.write_uint8(sample) return wtr.data
def write_stream(self, stream: BinaryIO): if isinstance(stream, BinaryWriter): wtr = stream else: wtr = BinaryWriter(stream) wtr.write_uint32(0) # placeholder for file length for p in self.params: if isinstance(p, int): wtr.write_uint16(1) wtr.write_uint32(p) elif isinstance(p, float): wtr.write_uint16(2) wtr.write_float(p) elif isinstance(p, str): wtr.write_uint16(3) wtr.write_uint16(len(p) + 1) wtr.write_string(p) wtr.write_uint8(0) for c in self.commands: wtr.write_uint16(0) wtr.write_uint16(c.command) for p in c.params: if isinstance(p, int): wtr.write_uint16(1) wtr.write_uint32(p) elif isinstance(p, float): wtr.write_uint16(2) wtr.write_float(p) elif isinstance(p, str): wtr.write_uint16(3) wtr.write_uint16(len(p) + 1) wtr.write_string(p) wtr.write_uint8(0) wtr.write_uint16(0xc) wtr.seek(0) wtr.write_uint32(len(wtr.data) - 4)
def compress(input_data: bytes, datablock_size=None) -> bytes: if datablock_size is None: # Return the smallest we can return min(compress(input_data, 4), compress(input_data, 8), key=lambda x: len(x)) assert datablock_size in [4, 8] wtr = BinaryWriter() wtr.write_uint8(0x20 | datablock_size) # huffman identifier wtr.write_uint24(len(input_data) if len(input_data) < 0xffffff else 0) if len(input_data) > 0xffffff: wtr.write_uint32(len(input_data)) # build frequency table frequencies = [0 for _ in range(0x100 if datablock_size == 8 else 0x10)] for b in input_data: if datablock_size == 8: frequencies[b] += 1 else: b0, b1 = b & 0xf, b >> 4 frequencies[b0] += 1 frequencies[b1] += 1 # build the huffman tree node_count = 0 leaf_queue = [] node_queue = [] leaves: List[HuffTreeNode] = [ None for _ in range(0x100 if datablock_size == 8 else 0x10) ] for i in range(0x10 if datablock_size == 4 else 0x100): if frequencies[i] == 0: continue node = HuffTreeNode(True, data=i) leaves[i] = node leaf_queue.append((frequencies[i], node)) node_count += 1 if len(leaf_queue) < 2: # Add an unused node to make it posible node = HuffTreeNode(True, data=0) leaves[0] = node leaf_queue.append((1, node)) node_count += 1 def take_lowest( queue0: List[Tuple[int, HuffTreeNode]], queue1: List[Tuple[int, HuffTreeNode]]) -> Tuple[int, HuffTreeNode]: if queue0: lowest_queue0 = min(queue0, key=lambda x: x[0]) elif queue1: lowest_queue1 = min(queue1, key=lambda x: x[0]) queue1.remove(lowest_queue1) return lowest_queue1 else: raise ValueError("take_lowest() arg are empty sequences") if queue1: lowest_queue1 = min(queue1, key=lambda x: x[0]) else: queue0.remove(lowest_queue0) return lowest_queue0 if lowest_queue0[0] < lowest_queue1[0]: queue0.remove(lowest_queue0) return lowest_queue0 else: queue1.remove(lowest_queue1) return lowest_queue1 while len(leaf_queue) + len(node_queue) > 1: one_prio, one = take_lowest(leaf_queue, node_queue) two_prio, two = take_lowest(leaf_queue, node_queue) newnode = HuffTreeNode(False, child0=one, child1=two) node_queue.append((one_prio + two_prio, newnode)) node_count += 1 root: HuffTreeNode = node_queue[0][1] # write the huffman tree wtr.write_uint8((node_count - 1) // 2) root.to_wtr(wtr) datablock = 0 bits_left = 32 cached_byte = 0 for i in range(len(input_data) * (2 if datablock_size == 4 else 1)): if datablock_size == 4: if i & 1 == 0: cached_byte = input_data[i // 2] data = cached_byte & 0xf else: data = cached_byte >> 4 else: data = input_data[i] node = leaves[data] depth = node.depth path: List[bool] = [False for _ in range(depth)] for d in range(depth): path[depth - d - 1] = node.is_child1 node = node.parent for p in path: if bits_left == 0: wtr.write_uint32(datablock) datablock = 0 bits_left = 32 bits_left -= 1 if p: datablock |= 1 << bits_left if bits_left != 32: wtr.write_uint32(datablock) return wtr.getvalue()
def compress(data: bytes): rdr = BinaryReader(data) wtr = BinaryWriter() wtr.write_uint8(0x30) # rle identifier wtr.write_uint24(len(data) if len(data) < 0xffffff else 0) if len(data) > 0xffffff: wtr.write_uint32(len(data)) repCount = 1 currentBlockLenght = 0 dataBlock = [0 for _ in range(130)] while rdr.c < len(rdr.data): foundRepetition = False while (currentBlockLenght < 130 and rdr.c < len(rdr.data)): nextByte = rdr.read_uint8() dataBlock[currentBlockLenght] = nextByte currentBlockLenght += 1 if (currentBlockLenght > 1): if nextByte == dataBlock[currentBlockLenght - 2]: repCount += 1 else: repCount = 1 foundRepetition = repCount > 2 if foundRepetition: break if foundRepetition: numUncompToCopy = currentBlockLenght - 3 else: numUncompToCopy = min(currentBlockLenght, 130 - 2) if numUncompToCopy > 0: flag = numUncompToCopy - 1 wtr.write_uint8(flag) for i in range(numUncompToCopy): wtr.write_uint8(dataBlock[i]) for i in range(numUncompToCopy, currentBlockLenght): dataBlock[i - numUncompToCopy] = dataBlock[i] currentBlockLenght -= numUncompToCopy if foundRepetition: while currentBlockLenght < 130 and rdr.c < len(rdr.data): nextByte = rdr.read_uint8() dataBlock[currentBlockLenght] = nextByte currentBlockLenght += 1 if nextByte != dataBlock[0]: break else: repCount += 1 flag = 0x80 | (repCount - 3) wtr.write_uint8(flag) wtr.write_uint8(dataBlock[0]) if (repCount != currentBlockLenght): dataBlock[0] = dataBlock[currentBlockLenght - 1] currentBlockLenght -= repCount if currentBlockLenght > 0: flag = currentBlockLenght - 1 wtr.write_uint8(flag) for i in range(currentBlockLenght): wtr.write_uint8(dataBlock[i]) currentBlockLenght = 0 return wtr.data
def export_data(self, wtr): if not isinstance(wtr, BinaryWriter): wtr = BinaryWriter(wtr) wtr: BinaryWriter puzzle_text_section = BinaryWriter() puzzle_text_section.write_string(self.text, encoding=self.encoding) puzzle_correct_offset = puzzle_text_section.tell() puzzle_text_section.write_string(self.correct_answer, encoding=self.encoding) puzzle_incorrect_offset = puzzle_text_section.tell() puzzle_text_section.write_string(self.incorrect_answer, encoding=self.encoding) puzzle_hint1_offset = puzzle_text_section.tell() puzzle_text_section.write_string(self.hint1, encoding=self.encoding) puzzle_hint2_offset = puzzle_text_section.tell() puzzle_text_section.write_string(self.hint2, encoding=self.encoding) puzzle_hint3_offset = puzzle_text_section.tell() puzzle_text_section.write_string(self.hint3, encoding=self.encoding) wtr.write_uint16(self.number) wtr.write_uint16(112) wtr.write_string(self.title, encoding=self.encoding, size=0x30) wtr.write_uint8(self.tutorial_id) for picarat in self.picarat_decay: wtr.write_uint8(picarat) wtr.write_uint8(self._flags) wtr.write_uint8(self.location_id) wtr.write_uint8(self.type) wtr.write_uint8(self.bg_btm_id) wtr.write(self.original[0x3c:0x3e]) # UnkSoundId wtr.write_uint8(self.bg_top_id) wtr.write_uint8(self.reward_id) wtr.write_uint32(0) wtr.write_uint32(puzzle_correct_offset) wtr.write_uint32(puzzle_incorrect_offset) wtr.write_uint32(puzzle_hint1_offset) wtr.write_uint32(puzzle_hint2_offset) wtr.write_uint32(puzzle_hint3_offset) wtr.write(b"\x00" * 4 * 6) wtr.write(puzzle_text_section.data) return wtr
def write_stream(self, stream): if isinstance(stream, BinaryWriter): wtr = stream else: wtr = BinaryWriter(stream) wtr.write_uint16(len(self.images)) wtr.write_uint16(3 if self.colordepth == 4 else 4) for img in self.images: img_h, img_w = img.shape wtr.write_uint16(img_w) wtr.write_uint16(img_h) # number of parts wtr.write_uint16( calculate_power_of_2_steps(img_w) * calculate_power_of_2_steps(img_h)) wtr.write_zeros(2) w_left, h_left = img_w, img_h part_x, part_y = 0, 0 while h_left > 0: part_h = get_nearest_power_of_2(h_left) good_h = part_h h_left -= part_h w_left = img_w part_x = 0 while w_left > 0: part_w = get_nearest_power_of_2(w_left) w_left -= part_w part_h = good_h wtr.write_uint16(part_x) wtr.write_uint16(part_y) wtr.write_uint16(int(log(part_w, 2)) - 3) wtr.write_uint16(int(log(part_h, 2)) - 3) part = np.zeros((part_h, part_w), np.uint8) if part_x + part_w > img_w: part_w = img_w - part_x if part_y + part_h > img_h: part_h = img_h - part_y part[:part_h, :part_w] = img[part_y:part_y + part_h, part_x:part_x + part_w] if self.colordepth == 8: wtr.write(part.tobytes()) else: h, w = part.shape bufpart = part.reshape((w * h)) part_4bit = np.zeros((h * w // 2), np.uint8) part_4bit[:] = np.ndarray = bufpart[ 0::2] & 0xf | bufpart[1::2] << 4 wtr.write(part_4bit.tobytes()) part_x += part_w part_y += part_h wtr.write_uint32(256 if self.colordepth == 8 else 16) for color_i in range(256 if self.colordepth == 8 else 16): self.palette[color_i]: np.ndarray wtr.write_uint16(ndspy.color.pack255(*self.palette[color_i])) wtr.write_zeros(0x1e) wtr.write_uint32(len(self.animations)) for anim in self.animations: wtr.write_string(anim.name, 0x1e) for anim in self.animations: wtr.write_uint32(len(anim.frames)) wtr.write_uint32_array([frame.index for frame in anim.frames]) wtr.write_uint32_array([frame.duration for frame in anim.frames]) wtr.write_uint32_array( [frame.image_index for frame in anim.frames]) wtr.write_uint16(0x1234) # magic number probably variable_labels = list(self.variables) assert len(variable_labels) == 16 wtr.write_string_array(variable_labels, 16) for dat_i in range(8): for var_l in variable_labels: wtr.write_int16(self.variables[var_l][dat_i]) for anim in self.animations: wtr.write_uint16(anim.child_image_x) for anim in self.animations: wtr.write_uint16(anim.child_image_y) for anim in self.animations: wtr.write_uint8(anim.child_image_animation_index) wtr.write_string(self.child_image, 128) return stream
def write(self, bw: BinaryWriter): bw.seek(0, io.SEEK_SET) bw.write(self.magic) bw.write_uint32(0) bw.write_uint32(self.file_length) bw.write_uint16(self.version) bw.write_uint8(self.unk1) bw.write_uint8(self.unk2) bw.write_uint32(0) bw.write_uint32(0) bw.write_uint16(self.year) bw.write_uint8(self.month) bw.write_uint8(self.day) bw.write_uint8(self.hour) bw.write_uint8(self.minute) bw.write_uint8(self.second) bw.write_uint8(self.centisecond) if self.file_name[-1] != 0: self.file_name += b"\0" bw.write_string(self.file_name, size=16, encoding=None, pad=b"\xFF") bw.write_uint32(0x1) bw.write_uint32(0x1) bw.write_uint32(0xFFFFFFFF) bw.write_uint32(0xFFFFFFFF)
def write(self, bw: BinaryWriter): bw.write_uint8(self.track_id) bw.write_uint8(self.channel_id) bw.write_uint8(self.unk1) bw.write_uint8(self.unk2)
def compress(data: bytes): rdr = BinaryReader(data) wtr = BinaryWriter() wtr.write_uint8(0x30) # rle identifier wtr.write_uint24(len(data) if len(data) < 0xffffff else 0) if len(data) > 0xffffff: wtr.write_uint32(len(data)) rep_count = 1 current_block_length = 0 data_block = [0 for _ in range(130)] while rdr.c < len(rdr.data): found_repetition = False while current_block_length < 130 and rdr.c < len(rdr.data): next_byte = rdr.read_uint8() data_block[current_block_length] = next_byte current_block_length += 1 if current_block_length > 1: if next_byte == data_block[current_block_length - 2]: rep_count += 1 else: rep_count = 1 found_repetition = rep_count > 2 if found_repetition: break if found_repetition: num_uncomp_to_copy = current_block_length - 3 else: num_uncomp_to_copy = min(current_block_length, 130 - 2) if num_uncomp_to_copy > 0: flag = num_uncomp_to_copy - 1 wtr.write_uint8(flag) for i in range(num_uncomp_to_copy): wtr.write_uint8(data_block[i]) for i in range(num_uncomp_to_copy, current_block_length): data_block[i - num_uncomp_to_copy] = data_block[i] current_block_length -= num_uncomp_to_copy if found_repetition: while current_block_length < 130 and rdr.c < len(rdr.data): next_byte = rdr.read_uint8() data_block[current_block_length] = next_byte current_block_length += 1 if next_byte != data_block[0]: break else: rep_count += 1 flag = 0x80 | (rep_count - 3) wtr.write_uint8(flag) wtr.write_uint8(data_block[0]) if rep_count != current_block_length: data_block[0] = data_block[current_block_length - 1] current_block_length -= rep_count if current_block_length > 0: flag = current_block_length - 1 wtr.write_uint8(flag) for i in range(current_block_length): wtr.write_uint8(data_block[i]) return wtr.data