JoseKenshin Posted January 6 Posted January 6 (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. 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 January 6 by JoseKenshin
Engineers Rabatini Posted January 6 Engineers Posted January 6 (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. 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. Edited January 6 by Rabatini 1
JoseKenshin Posted January 6 Author Posted January 6 (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 January 6 by JoseKenshin
Engineers Rabatini Posted January 6 Engineers Posted January 6 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?
JoseKenshin Posted January 6 Author Posted January 6 ok, thanks! I want to translate it into Spanish. You already helped me with Granstream Saga. I owe you a bunch of coffees. 😄
Engineers Rabatini Posted January 7 Engineers Posted January 7 (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 Thank 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. Edited January 7 by Rabatini
JoseKenshin Posted January 7 Author Posted January 7 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 Rabatini Posted January 7 Engineers Solution Posted January 7 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.
Engineers Rabatini Posted January 7 Engineers Posted January 7 Here the tool. Decompress and compress - unpack and repack DevilManTool.zip
JoseKenshin Posted January 7 Author Posted January 7 (edited) It works! Thanks a lot. 😁 Edited January 7 by JoseKenshin 1
Recommended Posts
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 accountSign in
Already have an account? Sign in here.
Sign In Now