Skip to content
View in the app

A better way to browse. Learn more.

ResHax

A full-screen app on your home screen with push notifications, badges and more.

To install this app on iOS and iPadOS
  1. Tap the Share icon in Safari
  2. Scroll the menu and tap Add to Home Screen.
  3. Tap Add in the top-right corner.
To install this app on Android
  1. Tap the 3-dot menu (⋮) in the top-right corner of the browser.
  2. Tap Add to Home screen or Install app.
  3. Confirm by tapping Install.
Help us keep the site running.
Zero Tolerance for Disrespect

Hayarigami 1.2.3 Switch .Dat

Featured Replies

Solved by zbirow

  • Localization
  • Solution
import tkinter as tk
from tkinter import filedialog, messagebox, scrolledtext
import struct
import os
import threading

class GameArchiveExtractor:
    def __init__(self, root):
        self.root = root
        self.root.title("Game Archive Extractor")
        self.root.geometry("600x500")
        self.root.resizable(False, False)

        self.file_path = tk.StringVar()
        self.output_path = tk.StringVar()

        self._create_widgets()

    def _create_widgets(self):
        file_frame = tk.LabelFrame(self.root, text="Input File (.dat)", padx=10, pady=10)
        file_frame.pack(fill="x", padx=10, pady=5)

        tk.Entry(file_frame, textvariable=self.file_path, state='readonly', width=50).pack(side="left", padx=5)
        tk.Button(file_frame, text="Browse...", command=self._browse_file).pack(side="left")

        out_frame = tk.LabelFrame(self.root, text="Output Directory", padx=10, pady=10)
        out_frame.pack(fill="x", padx=10, pady=5)

        tk.Entry(out_frame, textvariable=self.output_path, state='readonly', width=50).pack(side="left", padx=5)
        tk.Button(out_frame, text="Browse...", command=self._browse_output).pack(side="left")

        btn_frame = tk.Frame(self.root, pady=10)
        btn_frame.pack(fill="x", padx=10)
        self.extract_btn = tk.Button(btn_frame, text="Analyze and Extract", command=self._start_extraction_thread, height=2, bg="#dddddd")
        self.extract_btn.pack(fill="x")

        log_frame = tk.LabelFrame(self.root, text="Analyzer Log", padx=10, pady=10)
        log_frame.pack(fill="both", expand=True, padx=10, pady=5)

        self.log_text = scrolledtext.ScrolledText(log_frame, state='disabled', font=("Consolas", 9))
        self.log_text.pack(fill="both", expand=True)

    def _browse_file(self):
        filename = filedialog.askopenfilename(filetypes=[("DAT Files", "*.dat"), ("All Files", "*.*")])
        if filename:
            self.file_path.set(filename)

    def _browse_output(self):
        dirname = filedialog.askdirectory()
        if dirname:
            self.output_path.set(dirname)

    def _log(self, message):
        self.log_text.config(state='normal')
        self.log_text.insert(tk.END, message + "\n")
        self.log_text.see(tk.END)
        self.log_text.config(state='disabled')

    def _start_extraction_thread(self):
        if not self.file_path.get() or not self.output_path.get():
            messagebox.showwarning("Error", "Please select both input file and output directory.")
            return
        
        self.extract_btn.config(state='disabled')
        self.log_text.config(state='normal')
        self.log_text.delete(1.0, tk.END)
        self.log_text.config(state='disabled')
        
        threading.Thread(target=self._process_archive, daemon=True).start()

    def _process_archive(self):
        dat_path = self.file_path.get()
        out_dir = self.output_path.get()

        try:
            with open(dat_path, 'rb') as f:
                header = f.read(16)
                magic = header[:8]
                file_count = struct.unpack('<H', header[8:10])[0]
                
                self._log(f"Magic Header: {magic}")
                self._log(f"File Count: {file_count}")
                self._log("-" * 65)
                self._log(f"{'FILENAME':<35} | {'OFFSET':<12} | {'SIZE':<10}")
                self._log("-" * 65)

                if magic != b'PS_FS_V1':
                    self._log("WARNING: Magic header mismatch!")

                files_to_extract = []

                for _ in range(file_count):
                    entry_data = f.read(64)
                    if len(entry_data) < 64:
                        break

                    raw_name = entry_data[:48]
                    file_name = raw_name.split(b'\x00')[0].decode('ascii', errors='ignore')
                    
                    file_size = struct.unpack('<I', entry_data[48:52])[0]
                    file_offset = struct.unpack('<I', entry_data[56:60])[0]

                    if not file_name:
                        continue

                    self._log(f"{file_name:<35} | {hex(file_offset):<12} | {file_size:<10}")
                    
                    files_to_extract.append({
                        'name': file_name,
                        'offset': file_offset,
                        'size': file_size
                    })

                self._log("-" * 65)
                self._log(f"Starting extraction of {len(files_to_extract)} files...")

                for item in files_to_extract:
                    f.seek(item['offset'])
                    data = f.read(item['size'])
                    
                    full_path = os.path.join(out_dir, item['name'])
                    os.makedirs(os.path.dirname(full_path), exist_ok=True)
                    
                    with open(full_path, 'wb') as out_f:
                        out_f.write(data)
                
                self._log("Extraction completed successfully.")
                messagebox.showinfo("Success", "Extraction completed!")

        except Exception as e:
            self._log(f"Error: {str(e)}")
            messagebox.showerror("Error", str(e))
        finally:
            self.extract_btn.config(state='normal')

if __name__ == "__main__":
    root = tk.Tk()
    app = GameArchiveExtractor(root)
    root.mainloop()

 

  • Author

Tried using QuickBMS but doesn't seem to work it seems to be giving an command line error when extracting but i'm stupid and its a python GUI lol Thank you so much for this!!

Create an account or sign in to comment

Account

Navigation

Search

Search

Configure browser push notifications

Chrome (Android)
  1. Tap the lock icon next to the address bar.
  2. Tap Permissions → Notifications.
  3. Adjust your preference.
Chrome (Desktop)
  1. Click the padlock icon in the address bar.
  2. Select Site settings.
  3. Find Notifications and adjust your preference.