February 12Feb 12 Localization Hi, guys. Someone help me? I need extract and repack phyton script or quickbms script for this game file... Sample file here https://www.mediafire.com/file/5hoyfzm50m4w14u/Majin+and+Forsaken+Kingdom.rar/file Edited February 12Feb 12 by Sentinel
February 12Feb 12 Supporter Guess, this request is better addressed in compressed files forum. Anyways, using offzip I got a 2 MB dat file (besides 5 *.kap). The contents of the .dat ("gfxfontlibD"), a blurred picture, gives me a déjà-vu but I have no idea what exactly. Edited February 12Feb 12 by shak-otay
February 12Feb 12 Supporter 1 hour ago, shak-otay said: Guess, this request is better addressed in compressed files forum. Anyways, using offzip I got a 2 MB dat file (besides 5 *.kap). The contents of the .dat ("gfxfontlibD"), a blurred picture, gives me a déjà-vu but I have no idea what exactly. This file has only two compression blocks, both of which are zlib compressed. The first compressed block needs to use the -15 parameter, the second compressed block has a 78DA compression header and can be decompressed directly The first metadata contains multiple file name indexes, but there is only one compressed data. Could it be that the decompressed data contains multiple file data?
February 12Feb 12 Supporter 1 hour ago, wq223 said: The first compressed block needs to use the -15 parameter, the second compressed block has a 78DA compression header and can be decompressed directly What do you mean by "directly"? (78DA can be found 32 times in the pak, btw.) Edited February 12Feb 12 by shak-otay
February 12Feb 12 Supporter 37 minutes ago, shak-otay said: What do you mean by "directly"? (78DA can be found 32 times in the pak, btw.) My script includes 78DA in the compressed data 78DA is the best compression. It should have this compressed data part and can be decompressed directly without parameters, because there is no offset to prove whether the original file detached from this file starts with CFX, 78DA, or subsequent compressed data. But for the data starting with the first compressed data AC97, I must use parameters to decompress, otherwise my script cannot recognize that this is a zlib compressed data .
February 13Feb 13 Author Localization 8 hours ago, Rabatini said: kb_text_us.zip 113.96 kB · 2 downloads I think the localization files are inaccessible. The file seems to be encrypted.
February 13Feb 13 Supporter This is not encrypted: Quote Of critical importance to defeating the darkness is the trust between our hero and the Majin. Edited February 13Feb 13 by shak-otay
February 13Feb 13 Author Localization 7 hours ago, shak-otay said: This is not encrypted: Yes, he is a hero.
February 15Feb 15 Author Localization On 2/13/2026 at 4:40 AM, Rabatini said: kb_text_us.zip 113.96 kB · 3 downloads Could you make a tool for Localization?
February 17Feb 17 Localization I analyzed the text data blocks. Below you can see their structure, along with a simple Python preview tool. (The first few dozen entries are empty, so you have to scroll down quite a bit.) That's all I can help with. Structures: 4 MAGIC 2 padding 2 ID1 13 UNK 4 UNK2 8 UNK3 2 padding 2 ID2 5 UNK4 4 LENGTH (BE) TEXT (UTF-16LE) 2 00 00 8 FF import tkinter as tk from tkinter import filedialog, ttk import struct MAGIC = b"\x17\xD2\x25\xE3" class ParserGUI: def __init__(self, root): self.root = root self.root.title("Binary Text Parser") self.records = [] btn = tk.Button(root, text="Load File", command=self.load_file) btn.pack(pady=5) self.tree = ttk.Treeview(root, columns=("offset", "id1", "id2", "len"), show="headings") self.tree.heading("offset", text="OFFSET") self.tree.heading("id1", text="ID1") self.tree.heading("id2", text="ID2") self.tree.heading("len", text="TEXT LEN") self.tree.pack(fill="both", expand=True) self.tree.bind("<<TreeviewSelect>>", self.show_record) self.tabs = ttk.Notebook(root) self.tabs.pack(fill="both", expand=True) self.fields = {} for name in ["ID1", "UNK", "UNK2", "UNK3", "ID2", "UNK4", "TEXT"]: frame = ttk.Frame(self.tabs) self.tabs.add(frame, text=name) txt = tk.Text(frame, wrap="word") txt.pack(fill="both", expand=True) self.fields[name] = txt self.log = tk.Text(root, height=12, bg="black", fg="lime") self.log.pack(fill="both", expand=False) def log_print(self, msg): self.log.insert("end", msg + "\n") self.log.see("end") def load_file(self): path = filedialog.askopenfilename(title="Select a binary file") if not path: return with open(path, "rb") as f: data = f.read() self.records.clear() self.tree.delete(*self.tree.get_children()) self.log.delete("1.0", "end") self.parse(data) def parse(self, data): offset = 0 magic_count = 0 while True: pos = data.find(MAGIC, offset) if pos == -1: break magic_count += 1 self.log_print(f"\n--- MAGIC found @ 0x{pos:X} ---") try: cur = pos + 4 padding1 = data[cur:cur+2] cur += 2 id1 = data[cur:cur+2] cur += 2 hash1 = data[cur:cur+13] cur += 13 A = struct.unpack(">I", data[cur:cur+4])[0] cur += 4 hash2 = data[cur:cur+8] cur += 8 padding2 = data[cur:cur+2] cur += 2 id2 = data[cur:cur+2] cur += 2 hash3 = data[cur:cur+5] cur += 5 length = struct.unpack(">I", data[cur:cur+4])[0] cur += 4 self.log_print(f"ID1={id1.hex().upper()} ID2={id2.hex().upper()} LENGTH={length}") if length <= 0 or length > 10000: self.log_print("❌ Suspicious length — skipping record") offset = pos + 4 continue text_bytes = data[cur:cur + (length * 2)] cur += length * 2 text = text_bytes.decode("utf-16be", errors="ignore").replace("\x00", "") if data[cur:cur+2] == b"\x00\x00": cur += 2 if data[cur:cur+8] == b"\xFF"*8: cur += 8 record = { "offset": pos, "ID1": id1.hex().upper(), "UNK": hash1.hex().upper(), "UNK2": A, "UNK3": hash2.hex().upper(), "ID2": id2.hex().upper(), "UNK4": hash3.hex().upper(), "TEXT": text } self.records.append(record) except Exception as e: self.log_print(f"❌ Parsing error: {e}") offset = pos + 4 self.log_print(f"\nMAGIC occurrences found: {magic_count}") self.log_print(f"Records parsed: {len(self.records)}") for r in self.records: self.tree.insert("", "end", values=( hex(r["offset"]), r["ID1"], r["ID2"], len(r["TEXT"]) )) def show_record(self, event): sel = self.tree.selection() if not sel: return index = self.tree.index(sel[0]) record = self.records[index] for key in self.fields: self.fields[key].delete("1.0", "end") self.fields[key].insert("1.0", str(record[key])) if __name__ == "__main__": root = tk.Tk() root.geometry("1000x800") app = ParserGUI(root) root.mainloop()
February 17Feb 17 Author Localization 10 hours ago, zbirow said: I analyzed the text data blocks. Below you can see their structure, along with a simple Python preview tool. (The first few dozen entries are empty, so you have to scroll down quite a bit.) That's all I can help with. Structures: 4 MAGIC 2 padding 2 ID1 13 UNK 4 UNK2 8 UNK3 2 padding 2 ID2 5 UNK4 4 LENGTH (BE) TEXT (UTF-16LE) 2 00 00 8 FF import tkinter as tk from tkinter import filedialog, ttk import struct MAGIC = b"\x17\xD2\x25\xE3" class ParserGUI: def __init__(self, root): self.root = root self.root.title("Binary Text Parser") self.records = [] btn = tk.Button(root, text="Load File", command=self.load_file) btn.pack(pady=5) self.tree = ttk.Treeview(root, columns=("offset", "id1", "id2", "len"), show="headings") self.tree.heading("offset", text="OFFSET") self.tree.heading("id1", text="ID1") self.tree.heading("id2", text="ID2") self.tree.heading("len", text="TEXT LEN") self.tree.pack(fill="both", expand=True) self.tree.bind("<<TreeviewSelect>>", self.show_record) self.tabs = ttk.Notebook(root) self.tabs.pack(fill="both", expand=True) self.fields = {} for name in ["ID1", "UNK", "UNK2", "UNK3", "ID2", "UNK4", "TEXT"]: frame = ttk.Frame(self.tabs) self.tabs.add(frame, text=name) txt = tk.Text(frame, wrap="word") txt.pack(fill="both", expand=True) self.fields[name] = txt self.log = tk.Text(root, height=12, bg="black", fg="lime") self.log.pack(fill="both", expand=False) def log_print(self, msg): self.log.insert("end", msg + "\n") self.log.see("end") def load_file(self): path = filedialog.askopenfilename(title="Select a binary file") if not path: return with open(path, "rb") as f: data = f.read() self.records.clear() self.tree.delete(*self.tree.get_children()) self.log.delete("1.0", "end") self.parse(data) def parse(self, data): offset = 0 magic_count = 0 while True: pos = data.find(MAGIC, offset) if pos == -1: break magic_count += 1 self.log_print(f"\n--- MAGIC found @ 0x{pos:X} ---") try: cur = pos + 4 padding1 = data[cur:cur+2] cur += 2 id1 = data[cur:cur+2] cur += 2 hash1 = data[cur:cur+13] cur += 13 A = struct.unpack(">I", data[cur:cur+4])[0] cur += 4 hash2 = data[cur:cur+8] cur += 8 padding2 = data[cur:cur+2] cur += 2 id2 = data[cur:cur+2] cur += 2 hash3 = data[cur:cur+5] cur += 5 length = struct.unpack(">I", data[cur:cur+4])[0] cur += 4 self.log_print(f"ID1={id1.hex().upper()} ID2={id2.hex().upper()} LENGTH={length}") if length <= 0 or length > 10000: self.log_print("❌ Suspicious length — skipping record") offset = pos + 4 continue text_bytes = data[cur:cur + (length * 2)] cur += length * 2 text = text_bytes.decode("utf-16be", errors="ignore").replace("\x00", "") if data[cur:cur+2] == b"\x00\x00": cur += 2 if data[cur:cur+8] == b"\xFF"*8: cur += 8 record = { "offset": pos, "ID1": id1.hex().upper(), "UNK": hash1.hex().upper(), "UNK2": A, "UNK3": hash2.hex().upper(), "ID2": id2.hex().upper(), "UNK4": hash3.hex().upper(), "TEXT": text } self.records.append(record) except Exception as e: self.log_print(f"❌ Parsing error: {e}") offset = pos + 4 self.log_print(f"\nMAGIC occurrences found: {magic_count}") self.log_print(f"Records parsed: {len(self.records)}") for r in self.records: self.tree.insert("", "end", values=( hex(r["offset"]), r["ID1"], r["ID2"], len(r["TEXT"]) )) def show_record(self, event): sel = self.tree.selection() if not sel: return index = self.tree.index(sel[0]) record = self.records[index] for key in self.fields: self.fields[key].delete("1.0", "end") self.fields[key].insert("1.0", str(record[key])) if __name__ == "__main__": root = tk.Tk() root.geometry("1000x800") app = ParserGUI(root) root.mainloop() Thanks a lot
Create an account or sign in to comment