Jump to content

[Psx] Devilman TIM compressed


Go to solution Solved by Rabatini,

Recommended Posts

Posted (edited)

Hello,

The Devilman PSX game doesn’t have much text, and I’d like to edit it. Most of the dialogue is audio and is stored in the PSOUND folder. These are .VAG files without header, so they’re easy to extract, edit, and reinsert.

I need some help with the game’s images. QDATA.BIN contains many .TIM images, but I don’t see any that contain Japanese text. The game script seems to be stored in .TIM images—I’ve been able to confirm this by analyzing RAM dumps—but when I look for those images in the ISO, I can’t find them. I’ve checked the files one by one with Tile Molester, but I still can’t see the text images that do appear in RAM.

They’re most likely compressed inside the HDATA or TDATA folders. I can see some data that looks like .TIM structures, but I haven’t been able to view any actual images.

Any help with this would be really appreciated.

Ram_TIMS.thumb.jpg.52b7b6d72003358b0a41e133e5b1e0ce.jpg

Attached are game files (without sound and video) and RAM dump.

https://www.mediafire.com/file/ce0sfz30qtob351/Devilman_psx_files.rar/file

https://www.mediafire.com/file/k54kjfbtf2isz15/RAM_dump.rar/file

Edited by JoseKenshin
  • Engineers
Posted (edited)
5 hours ago, JoseKenshin said:

Hello,

The Devilman PSX game doesn’t have much text, and I’d like to edit it. Most of the dialogue is audio and is stored in the PSOUND folder. These are .VAG files without header, so they’re easy to extract, edit, and reinsert.

I need some help with the game’s images. QDATA.BIN contains many .TIM images, but I don’t see any that contain Japanese text. The game script seems to be stored in .TIM images—I’ve been able to confirm this by analyzing RAM dumps—but when I look for those images in the ISO, I can’t find them. I’ve checked the files one by one with Tile Molester, but I still can’t see the text images that do appear in RAM.

They’re most likely compressed inside the HDATA or TDATA folders. I can see some data that looks like .TIM structures, but I haven’t been able to view any actual images.

Any help with this would be really appreciated.

Ram_TIMS.thumb.jpg.52b7b6d72003358b0a41e133e5b1e0ce.jpg

Attached are game files (without sound and video) and RAM dump.

https://www.mediafire.com/file/ce0sfz30qtob351/Devilman_psx_files.rar/file

https://www.mediafire.com/file/k54kjfbtf2isz15/RAM_dump.rar/file

It’s compressed using a custom LZSS algorithm with token counting.
Your files are both compressed and packed, so you will need to unpack and decompress them simultaneously.
Inside the TEX files, there are multiple TIM images.



HOPNTEX_BIN.decomp@0000000640.png.bd32f060468d40cdaff5700de845d454.png

file_00051000@0000001056.png.a0bee94871c03b711aea9840c0e269be.pngfile_0006F800@0000001056.png.49f0867c618c0e3a038e553a12333389.pngfile_0005F800@0000047616.png.0e85332ed3f173c8835b21cec9efb194.pngfile_0000B800@0000000608.png.c813eb5457b8941f189faaaf50f8d7e4.pngfile_0002D800@0000000064.png.74f01c6be973cb75d3e5ebba95b29741.pngfile_0003C800@0000000064.png.c189435fac7083b4b95be8d406a25912.png

Edited by Rabatini
  • Thanks 1
Posted (edited)

Amazing!

I’ve been trying to figure out the compression for several days.

Thank you! Could you explain a bit more about the custom LZSS algorithm?

Also, if you’d like, you could share the tools you used. 😁

Edited by JoseKenshin
  • Engineers
Posted
3 hours ago, JoseKenshin said:

Amazing!

I’ve been trying to figure out the compression for several days.

Thank you! Could you explain a bit more about the custom LZSS algorithm?

Also, if you’d like, you could share the tools you used. 😁

Yeah, I can do that. For the translation part, I’ll need to build a compression tool as well.
Which language are you planning to translate?

  • Engineers
Posted (edited)
4 hours ago, JoseKenshin said:

ok, thanks!
I want to translate it into Spanish. 

You already helped me with Granstream Saga. I owe you a bunch of coffees. 😄

 

Quote

image.png.aa0e2bbcaf8ea49bc93b7415d53d927a.pngThank you! Could you explain a bit more about the custom LZSS algorithm?

It’s a token-based LZSS/LZ77 stream.

Header (2 bytes, little-endian): this is NOT the output size. It is the number of commands/tokens to execute.

After the header, the data is processed in groups of 8 tokens:

Before each group, read 1 flag byte.

You consume its bits from MSB to LSB (bit 7 → bit 0).

Each bit decides what the next token is.

If the bit = 0 (literal token):

Read 1 byte from input and copy it directly to the output.

If the bit = 1 (reference token):

Read 2 bytes (byte1, byte2).

Decode:

length = (byte1 >> 2) + 1 → range 1..64

offset = ((byte1 & 0x03) << 8') | byte2 → range 0..1023

distance = offset + 1 → range 1..1024

Copy length bytes from output position:

copy_pos = current_output_pos - distance

Copy forward (overlap allowed), like standard LZSS.

Stop condition: stops when you’ve executed exactly token_count tokens (each literal counts as 1 token, each reference also counts as 1 token), regardless of how many output bytes the references produce.

----------------------------------------------------------------------------------------------------------------------------------------------------

Good news.

Compressor is working, with good rate.

image.thumb.png.6df28c76deffd7198675d7de9b4b5354.png
 

Edited by Rabatini
Posted

I tried to find the compression with Ghidra and Chatgpt, analyzing SLPS_022.75. I think the FUN_80013a34 function is the one that manages the compression. Thank you for your explanations, they are very helpful.

Unfortunately, I don't know how to make a tool, so I need your help ;)

#Function extracted from Ghidra
void FUN_80013a34(ushort *param_1,undefined *param_2)

{
  undefined *puVar1;
  byte bVar2;
  ushort uVar3;
  uint uVar4;
  ushort *puVar5;
  int iVar6;
  uint uVar7;
  int in_t2;
  uint uVar8;
  
  uVar7 = 0;
  uVar3 = *param_1;
  param_1 = param_1 + 1;
  do {
    while( true ) {
      uVar4 = (uint)*(byte *)param_1;
      puVar5 = param_1;
      if ((uVar7 & 7) == 0) {
        puVar5 = (ushort *)((int)param_1 + 1);
        in_t2 = uVar4 << 0x18;
        uVar4 = (uint)*(byte *)puVar5;
      }
      param_1 = (ushort *)((int)puVar5 + 1);
      if (in_t2 < 0) break;
      *param_2 = (char)uVar4;
      param_2 = param_2 + 1;
      uVar7 = uVar7 + 1;
      in_t2 = in_t2 << 1;
      if (uVar7 == uVar3) {
        return;
      }
    }
    uVar8 = uVar4 >> 2;
    bVar2 = *(byte *)param_1;
    param_1 = puVar5 + 1;
    iVar6 = (int)param_2 - ((uVar4 & 3) << 8 | (uint)bVar2);
    do {
      puVar1 = (undefined *)(iVar6 + -1);
      iVar6 = iVar6 + 1;
      *param_2 = *puVar1;
      uVar8 = uVar8 - 1;
      param_2 = param_2 + 1;
    } while (-1 < (int)uVar8);
    uVar7 = uVar7 + 1;
    in_t2 = in_t2 << 1;
  } while (uVar7 != uVar3);
  return;
}

 

  • Engineers
  • Solution
Posted
43 minutes ago, JoseKenshin said:

I tried to find the compression with Ghidra and Chatgpt, analyzing SLPS_022.75. I think the FUN_80013a34 function is the one that manages the compression. Thank you for your explanations, they are very helpful.

Unfortunately, I don't know how to make a tool, so I need your help 😉

#Function extracted from Ghidra
void FUN_80013a34(ushort *param_1,undefined *param_2)

{
  undefined *puVar1;
  byte bVar2;
  ushort uVar3;
  uint uVar4;
  ushort *puVar5;
  int iVar6;
  uint uVar7;
  int in_t2;
  uint uVar8;
  
  uVar7 = 0;
  uVar3 = *param_1;
  param_1 = param_1 + 1;
  do {
    while( true ) {
      uVar4 = (uint)*(byte *)param_1;
      puVar5 = param_1;
      if ((uVar7 & 7) == 0) {
        puVar5 = (ushort *)((int)param_1 + 1);
        in_t2 = uVar4 << 0x18;
        uVar4 = (uint)*(byte *)puVar5;
      }
      param_1 = (ushort *)((int)puVar5 + 1);
      if (in_t2 < 0) break;
      *param_2 = (char)uVar4;
      param_2 = param_2 + 1;
      uVar7 = uVar7 + 1;
      in_t2 = in_t2 << 1;
      if (uVar7 == uVar3) {
        return;
      }
    }
    uVar8 = uVar4 >> 2;
    bVar2 = *(byte *)param_1;
    param_1 = puVar5 + 1;
    iVar6 = (int)param_2 - ((uVar4 & 3) << 8 | (uint)bVar2);
    do {
      puVar1 = (undefined *)(iVar6 + -1);
      iVar6 = iVar6 + 1;
      *param_2 = *puVar1;
      uVar8 = uVar8 - 1;
      param_2 = param_2 + 1;
    } while (-1 < (int)uVar8);
    uVar7 = uVar7 + 1;
    in_t2 = in_t2 << 1;
  } while (uVar7 != uVar3);
  return;
}

 

I've already did Tool, Just cant sente It now, because, i'am not at home.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
×
×
  • Create New...