New SEGAGAGA translation project in the works!

Place for discussing homebrew games, development, new releases and emulation.

Moderators: pcwzrd13, deluxux, VasiliyRS

User avatar
megavolt85
Developer
Posts: 1823

Re: New SEGAGAGA translation project in the works!

Post#71 » Sat Oct 29, 2022 11:31 am

ateam wrote:Are the .MRG container/archive files using compression for any of their assets?


yep

ateam wrote: If so, have you identified the algorithm?


This is some kind of LZSS. I removed the pseudo -cod through the dizassembler and corrected him that he would compile.

Code: Select all

#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>

uint8_t dictonary[40] =
{
   0x0C, 0x03, 0x0B, 0x03, 0x0A, 0x03, 0x09, 0x03,
   0x06, 0x03, 0x05, 0x03, 0x06, 0x02, 0x05, 0x02,
   0x08, 0x04, 0x07, 0x04, 0x80, 0x40, 0x20, 0x10,
   0x08, 0x04, 0x02, 0x01, 0xF0, 0x0F, 0x00, 0x00,
   0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01
};

uint32_t BE2LE16(uint8_t *src)
{
   return ((src[0] << 8) | src[1]);
}

uint32_t BE2LE32(uint8_t *src)
{
   return ((src[0] << 24) | (src[1] << 16) | (src[2] << 8) | src[3]);
}

uint32_t FUN_8c01a45a(uint8_t *buffer, uint32_t *offset)
{
   uint32_t ret;
   
   if (!(*offset & 1))
   {
      ret = buffer[*offset >> 1] >> 4;
   }
   else
   {
      ret = buffer[*offset >> 1];
   }
   
   *offset = *offset + 1;
   
   return ret & 0xf;
}

uint32_t FUN_8c01a480(uint8_t *buffer, uint32_t *offset)
{
   uint32_t tmp;
   uint32_t ret;
   
   if ((*offset & 1) == 0)
   {
      ret = buffer[*offset >> 1];
      *offset = *offset + 2;
   }
   else
   {
      tmp = FUN_8c01a45a(buffer, offset);
      ret = FUN_8c01a45a(buffer, offset);
      ret = tmp << 4 | ret;
   }
   
   return ret;
}

void FUN_8c01a4c0(uint8_t orval, uint8_t *dst, uint32_t *offset)
{
   uint8_t val = dst[*offset >> 1];
   
   if (!(*offset & 1))
   {
      val = (val & 0x0F) | ((orval & 0x0F) << 4);
   }
   else
   {
      val = (val & 0xF0) | (orval & 0xf);
   }
   
   dst[*offset >> 1] = val;
   *offset = *offset + 1;
}

uint32_t mrg_algo0(uint8_t *dst, uint8_t *src, uint32_t len, int param_4)
{
   uint8_t bVar1;
   uint8_t bVar2;
   uint8_t bVar3;
   uint32_t uVar7;
   uint32_t uVar8;
   int iVar9;
   uint8_t *pbVar10;
   uint16_t control_byte;
   uint32_t i;
   
   control_byte = 0x7F80;
   bVar1 = dictonary[param_4 << 1];
   bVar3 = dictonary[(param_4 << 1) + 1];
   i = 0;
   
   do
   {
      control_byte <<= 1;
      
      if (control_byte == 0xFF00)
      {
         control_byte =  (*src++ << 8) | 0xFF;
      }
      
      if (!(control_byte & 0x8000))
      {
         uVar7 = BE2LE16(src);
         uVar8 = -(uint)bVar1;
         
         if (bVar1 == 0)
         {
            uVar8 = (uVar7 & 0xffff) << (uVar8 & 0x1f);
         }
         else
         {
            uVar8 = (uVar7 & 0xffff) >> ((~uVar8 & 0x1f) + 1);
         }
         
         uVar8 = uVar8 + (int)(short)(uint16_t)bVar3;
         iVar9 = i - (uVar7 & ((1 << (bVar1 & 0x1f)) + 0xFFFF) & 0xffff);
         src += 2;
         
         while (iVar9 < 0)
         {
            iVar9++;
            dst[i] = 0;
            uVar8--;
            i++;
         }
         
         pbVar10 = dst + iVar9;
         
         while ((uVar8 & 0xffff) != 0)
         {
            uVar8--;
            bVar2 = *pbVar10;
            pbVar10++;
            dst[i] = bVar2;
            i++;
         }
      }
      else
      {
         dst[i++] = *src++;
      }
   }
   while (i < len);
   
   return i;
}

uint32_t mrg_algo1(uint8_t *dst, uint8_t *src, uint32_t len, int param_4)
{
   uint8_t bVar1;
   uint8_t bVar2;
   uint8_t bVar3;
   uint32_t uVar7;
   int n;
   uint32_t i;
   uint32_t uVar10;
   int iVar11;
   uint8_t *pbVar12;
   
   uVar10 = 0x7F80;
   bVar1 = dictonary[(param_4 << 1) + 8];
   bVar3 = dictonary[(param_4 << 1) + 9];
   n = 0;
   
   do
   {
      uVar10 = uVar10 << 1;
      
      if ((uVar10 & 0xFFFF) == 0xFF00)
      {
         bVar2 = *src;
         src++;
         uVar10 = 0xFF | (uint)bVar2 << 8;
      }
      
      if (!(uVar10 & 0x8000))
      {
         bVar2 = *src;
         iVar11 = n - ((uint)bVar2 & (int)(short)((short)(1 << ((uint)bVar1 & 0x1f)) + 0xFFFF));
         uVar7 = -(uint)bVar1;
         
         if (bVar1 == 0)
         {
            uVar7 = (uint)bVar2 << (uVar7 & 0x1f);
         }
         else
         {
            uVar7 = (uint)(bVar2 >> ((~uVar7 & 0x1f) + 1));
         }
         
         uVar7 = uVar7 + (int)(short)(uint16_t)bVar3;
         i = n;
         
         while (iVar11 < 0)
         {
            iVar11++;
            dst[i] = 0;
            uVar7--;
            i++;
         }
         
         pbVar12 = dst + iVar11;
         
         while ((uVar7 & 0xffff) != 0)
         {
            uVar7--;
            bVar2 = *pbVar12;
            pbVar12++;
            dst[i] = bVar2;
            i++;
         }
      }
      else
      {
         i = n + 1;
         dst[n] = *src;
      }
      
      src++;
      n = i;
   }
   while (i < len);
   
   return i;
}

uint32_t mrg_algo2(uint8_t *dst, uint8_t *src, uint32_t len, int param_4)
{
   uint8_t bVar1;
   uint32_t uVar3;
   uint32_t uVar4;
   uint32_t uVar5;
   uint32_t i;
   uint32_t local_30;
   uint32_t local_2c;
   uint16_t local_28;
   short local_24;
   
   bVar1 = dictonary[(param_4 << 1) + 12];
   uVar5 = 0x7F80;
   local_24 = (short)(1 << ((uint)bVar1 & 0x1f)) + 0xFFFF;
   local_28 = dictonary[(param_4 << 1) + 13];
   local_2c = 0;
   i = 0;
   
   do
   {
      uVar5 = uVar5 << 1;
      
      if ((uVar5 & 0xffff) == 0xFF00)
      {
         uVar5 = FUN_8c01a480(src, &local_2c);
         uVar5 = 0xFF | (uVar5 & 0xff) << 8;
      }
      
      if (!(uVar5 & 0x8000))
      {
         uVar3 = FUN_8c01a480(src, &local_2c);
         uVar3 = uVar3 & 0xff;
         uVar4 = -(uint)bVar1;
         
         if (bVar1 == 0)
         {
            uVar4 = uVar3 << (uVar4 & 0x1f);
         }
         else
         {
            uVar4 = uVar3 >> ((~uVar4 & 0x1f) + 1);
         }
         
         uVar4 = uVar4 + local_28;
         local_30 = i - (uVar3 & (int)local_24);
         
         while ((int)local_30 < 0)
         {
            FUN_8c01a4c0(0, dst, &i);
            uVar4--;
            local_30++;
         }
         
         while ((uVar4 & 0xffff) != 0)
         {
            uVar3 = FUN_8c01a45a(dst, &local_30);
            FUN_8c01a4c0(uVar3, dst, &i);
            uVar4--;
         }
      }
      else
      {
         uVar3 = FUN_8c01a45a(src, &local_2c);
         FUN_8c01a4c0(uVar3, dst, &i);
      }
   }
   while (i < len * 2);
   
   i++;
   
   if ((int)(i + 1) < 0)
   {
      i++;
   }
   
   return i >> 1;
}

uint32_t mrg_algo3(uint8_t *dst, uint8_t *src, uint32_t len, int param_4)
{
   uint8_t bVar1;
   uint32_t uVar2;
   uint32_t uVar3;
   uint32_t uVar4;
   uint32_t i;
   uint32_t local_30;
   uint32_t local_2c;
   short local_28;
   uint16_t local_24;
   
   uVar4 = 0x7F80;
   bVar1 = dictonary[(param_4 << 1) + 16];
   local_28 = (short)(1 << ((uint)bVar1 & 0x1f)) + 0xFFFF;
   local_24 = dictonary[(param_4 << 1) + 17];
   local_2c = 0;
   i = 0;
   
   do
   {
      uVar4 = uVar4 << 1;
      
      if ((uVar4 & 0xFFFF) == 0xFF00)
      {
         uVar4 = FUN_8c01a480(src, &local_2c);
         uVar4 = 0xFF | (uVar4 & 0xFF) << 8;
      }
      
      if (!(uVar4 & 0x8000))
      {
         uVar2 = FUN_8c01a45a(src, &local_2c);
         uVar3 = FUN_8c01a480(src, &local_2c);
         uVar3 = ((uVar2 & 0xFF) << 8) | (uVar3 & 0xFF);
         uVar2 = -(uint)bVar1;
         
         if (bVar1 == 0)
         {
            uVar2 = uVar3 << (uVar2 & 0x1F);
         }
         else
         {
            uVar2 = uVar3 >> ((~uVar2 & 0x1F) + 1);
         }
         
         uVar2 = uVar2 + (int)(short)local_24;
         local_30 = i - (uVar3 & (int)local_28);
         
         while ((int)local_30 < 0)
         {
            FUN_8c01a4c0(0, dst, &i);
            uVar2--;
            local_30++;
         }
         
         while ((uVar2 & 0xFFFF) != 0)
         {
            uVar3 = FUN_8c01a45a(dst, &local_30);
            FUN_8c01a4c0(uVar3, dst, &i);
            uVar2--;
         }
      }
      else
      {
         uVar2 = FUN_8c01a45a(src, &local_2c);
         FUN_8c01a4c0(uVar2, dst, &i);
      }
   }
   while (i < len * 2);
   
   i++;
   
   if ((int)(i + 1) < 0)
   {
      i++;
   }
   
   return i >> 1;
}

int decompress_mrg(uint8_t *dst, uint8_t *src)
{
   uint32_t encrypt_algo = (src[0] & 0x70) >> 4;

   if (!(src[0] & 0x80))
   {
      memset(dst, 0, BE2LE32(&src[4]));
      
      switch (encrypt_algo)
      {
         case 0:
            return (int) mrg_algo0(dst, &src[8], BE2LE32(&src[4]), src[0] & 0x0F);
            break;
         
         case 1:
            return (int) mrg_algo1(dst, &src[8], BE2LE32(&src[4]), src[0] & 0x0F);
            break;
         
         case 2:
            return (int) mrg_algo2(dst, &src[8], BE2LE32(&src[4]), src[0] & 0x0F);
            break;
         
         case 3:
            return (int) mrg_algo3(dst, &src[8], BE2LE32(&src[4]), src[0] & 0x0F);
            break;
      }
   }
   else
   {
      memset(dst, 0, BE2LE32(src) & 0xFFFFFF);
      
      switch (encrypt_algo)
      {
         case 0:
            return (int) mrg_algo0(dst, &src[4], BE2LE32(src) & 0xFFFFFF, src[0] & 0x0F);
            break;
         
         case 1:
            return (int) mrg_algo1(dst, &src[4], BE2LE32(src) & 0xFFFFFF, src[0] & 0x0F);
            break;
         
         case 2:
            return (int) mrg_algo2(dst, &src[4], BE2LE32(src) & 0xFFFFFF, src[0] & 0x0F);
            break;
         
         case 3:
            return (int) mrg_algo3(dst, &src[4], BE2LE32(src) & 0xFFFFFF, src[0] & 0x0F);
            break;
      }
   }
   
   return -1;
}

typedef struct
{
   uint32_t offset;
   uint32_t size;
} vFILE_t;

typedef struct
{
   uint32_t f_cnt;
   vFILE_t vFile[1024];
} mrg_s;

off_t fsize(const char *filename)
{
    struct stat st;

    if (stat(filename, &st) == 0)
    {
        return st.st_size;
   }

    return -1;
}

int main(int argc, char *argv[])
{
   FILE *fo, *fi;
   int i, i_sz, o_sz;
   uint8_t *in_buf, *out_buf;
   mrg_s *iMRG = NULL;
   char name[256];
   uint32_t tmp_sz;
   
   if (argc != 2)
   {
      printf("no input file\n");
      return 1;
   }
   
   if ((i_sz = fsize(argv[1])) == -1 || !(fi = fopen(argv[1], "rb")))
   {
      printf("ERROR: can't open %s\n", argv[1]);
      return 1;
   }
   
   if (!(in_buf = calloc(i_sz, 1)))
   {
      printf("ERROR: can't allocate %d bytes\n", i_sz);
      fclose(fi);
      return 1;
   }
   
   if (!(out_buf = calloc(i_sz, 1)))
   {
      printf("ERROR: can't allocate %d bytes\n", i_sz);
      fclose(fi);
      return 1;
   }
   
   fread(in_buf, 1, i_sz, fi);
   fclose(fi);
   
   iMRG = (mrg_s *) in_buf;
   
   for (i = 0; i < iMRG->f_cnt; i++)
   {
      tmp_sz = !(in_buf[iMRG->vFile[i].offset] & 0x80) ?   BE2LE32(&in_buf[iMRG->vFile[i].offset+4]) :
                                             (BE2LE32(&in_buf[iMRG->vFile[i].offset]) & 0xFFFFFF);
      out_buf = realloc(out_buf, tmp_sz);
      
      if ((o_sz = decompress_mrg(out_buf, &in_buf[iMRG->vFile[i].offset])) == -1)
      {
         printf("ERROR: can't decrypt file %d of %u\n", i, iMRG->f_cnt);
         continue;
      }
      
      
      
      
      uint32_t offset = !(strncmp((char *) out_buf, "PVRX", 4)) ? 0x24 : 0;
      
      if (offset == 0x24 || (!offset && !(strncmp((char *) out_buf, "GBIX", 4))))
      {
         sprintf(name, "%s_%d.pvr", argv[1], i);
      }
      else
      {
         sprintf(name, "%s_%d.bin", argv[1], i);
      }
      
      
      if (!(fo = fopen(name, "wb")))
      {
         printf("ERROR: can't open for write %s\n", name);
         continue;
      }
      
      fwrite(out_buf + offset, 1, o_sz - offset, fo);
      fclose(fo);
   }
   
   free(in_buf);
   free(out_buf);
   
   return 0;
}

User avatar
ateam
Heroine Console
Posts: 482

Re: New SEGAGAGA translation project in the works!

Post#72 » Sat Oct 29, 2022 12:55 pm

megavolt85 wrote:This is some kind of LZSS. I removed the pseudo -cod through the dizassembler and corrected him that he would compile.


It's always some kind of LZ implementation (or so it seems) :lol:

I'd have to analyze the code, but I wonder if it's the same or similar to the one used with Rent-A-Hero and Cool Cool Toon. Both were very, very similar, the only difference being that 2-byte symbols were byte-swapped.

EDIT: Tested and works!

Image
Find me on...

DreamcastForever.com
GitHub
Reddit
SegaXtreme
Twitter
YouTube
• Discord: derek.ateam

madsheep
rebel
Posts: 20

Re: New SEGAGAGA translation project in the works!

Post#73 » Thu Nov 03, 2022 6:21 pm

ateam wrote:
megavolt85 wrote:This is some kind of LZSS. I removed the pseudo -cod through the dizassembler and corrected him that he would compile.


It's always some kind of LZ implementation (or so it seems) :lol:

I'd have to analyze the code, but I wonder if it's the same or similar to the one used with Rent-A-Hero and Cool Cool Toon. Both were very, very similar, the only difference being that 2-byte symbols were byte-swapped.

EDIT: Tested and works!

Image

So you have the tool ready for decompression/compression?

User avatar
ateam
Heroine Console
Posts: 482

Re: New SEGAGAGA translation project in the works!

Post#74 » Fri Nov 04, 2022 9:49 am

madsheep wrote:So you have the tool ready for decompression/compression?


All I did was compiled the C shared by megavolt85 here. As he said though, there's no compressor written yet. Here are the compiled binaries for the MRG archive extractor/decompressor.

mrg_extract.exe (Windows)
https://drive.google.com/uc?export=download&id=1_EnVv1Wpn2Ikta07q6jAW1w6lKjcKmSl

Code: Select all

.\mrg_extract.exe THE_FILE.MRG


mrg_extract (Linux)
https://drive.google.com/uc?export=download&id=1cabx6TVIqB_dGQ6R2t9qANSToZD9bZIE

Code: Select all

./mrg_extract THE_FILE.MRG


All files from archive will be extracted and decompressed within the same working directory from which you launch the executable.

EDIT: As per new code shared by megavolt85 here, here are the newer binaries.

mrg_extract_latest.exe (Windows)
https://drive.google.com/uc?export=download&id=1X6iCTsjP8J8WaMJJ4LjfAaEa-3wYoBjX

Code: Select all

.\mrg_extract_latest.exe THE_FILE.MRG


mrg_extract_latest (Linux)
https://drive.google.com/uc?export=download&id=1KvdjxVOFLfH8F_l7xL7H_C2BIsvCvAVA

Code: Select all

./mrg_extract_latest THE_FILE.MRG
Last edited by ateam on Tue Jan 17, 2023 9:35 am, edited 1 time in total.
Find me on...

DreamcastForever.com
GitHub
Reddit
SegaXtreme
Twitter
YouTube
• Discord: derek.ateam

madsheep
rebel
Posts: 20

Re: New SEGAGAGA translation project in the works!

Post#75 » Fri Nov 04, 2022 8:25 pm

i thought you have your code from Rent-A-Hero and Cool Cool Toon

nico7550
shadow
Posts: 10

Re: New SEGAGAGA translation project in the works!

Post#76 » Sat Nov 05, 2022 6:26 am

Hi, I'm a (old) newbie but I take a look into the files and there is a lot of them to work on, but I would like to help and I can handle some basic and repetive tasks.

    1. the MRG extract tool seems to have no effetc to the file located in the SOUND folder ?

    2. Using PVR Viewer (https://www.romhacking.net/utilities/1458/) to extract files, I use google lens to translate some images (but lens make a literal translation (kanji to prononciation), but within google lens when switching to google translate, it import the kanji and the translation to english works. (I try with the files in DATA\SHOOT\_SHT.MRG)

    3. Some kanji refere to a long word, example a simple symbol is translated by the word "Explosion" and it will be hard/not good looking to put the word explosion in the square used by the kanji but it's possible.

    4. I try some online tools to auto subtitle the video after extracting them (https://dreamcast-talk.com/forum/viewtopic.php?t=14382), it works but it will need:
      someone with japanese to english knowledge to correct the auto subtitles
      someone with timing knowdledge to correct the subtitles position
      someone with video/audio compression knowledge to repack all
      some money to have full access to the functionnality... (I try veed.io)

    5. How to deal with audio song in japanese ? SOUND/AKIBAM.ADX

    6. Is there a list of tools that show what to use for each type of extension ? (MAP, MLT, MOT, VMI, TTF, NJ, EFC, ARC, MES).

The GDI I use to test:
► Show Spoiler

User avatar
ateam
Heroine Console
Posts: 482

Re: New SEGAGAGA translation project in the works!

Post#77 » Sun Nov 06, 2022 10:33 am

madsheep wrote:i thought you have your code from Rent-A-Hero and Cool Cool Toon


Sorry, I haven't yet taken the time to compare.
Find me on...

DreamcastForever.com
GitHub
Reddit
SegaXtreme
Twitter
YouTube
• Discord: derek.ateam

User avatar
megavolt85
Developer
Posts: 1823

Re: New SEGAGAGA translation project in the works!

Post#78 » Mon Nov 07, 2022 4:41 pm

MRG containers contain both compressed and uncompressed files, sometimes even other MRG containers.

this code allows you to extract any MRG container.

Code: Select all

#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>

uint8_t dictonary[40] =
{
   0x0C, 0x03, 0x0B, 0x03, 0x0A, 0x03, 0x09, 0x03,
   0x06, 0x03, 0x05, 0x03, 0x06, 0x02, 0x05, 0x02,
   0x08, 0x04, 0x07, 0x04, 0x80, 0x40, 0x20, 0x10,
   0x08, 0x04, 0x02, 0x01, 0xF0, 0x0F, 0x00, 0x00,
   0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01
};

uint32_t BE2LE16(uint8_t *src)
{
   return ((src[0] << 8) | src[1]);
}

uint32_t BE2LE32(uint8_t *src)
{
   return ((src[0] << 24) | (src[1] << 16) | (src[2] << 8) | src[3]);
}

uint32_t FUN_8c01a45a(uint8_t *buffer, uint32_t *offset)
{
   uint32_t ret;
   
   if (!(*offset & 1))
   {
      ret = buffer[*offset >> 1] >> 4;
   }
   else
   {
      ret = buffer[*offset >> 1];
   }
   
   *offset = *offset + 1;
   
   return ret & 0xf;
}

uint32_t FUN_8c01a480(uint8_t *buffer, uint32_t *offset)
{
   uint32_t tmp;
   uint32_t ret;
   
   if ((*offset & 1) == 0)
   {
      ret = buffer[*offset >> 1];
      *offset = *offset + 2;
   }
   else
   {
      tmp = FUN_8c01a45a(buffer, offset);
      ret = FUN_8c01a45a(buffer, offset);
      ret = tmp << 4 | ret;
   }
   
   return ret;
}

void FUN_8c01a4c0(uint8_t orval, uint8_t *dst, uint32_t *offset)
{
   uint8_t val = dst[*offset >> 1];
   
   if (!(*offset & 1))
   {
      val = (val & 0x0F) | ((orval & 0x0F) << 4);
   }
   else
   {
      val = (val & 0xF0) | (orval & 0xf);
   }
   
   dst[*offset >> 1] = val;
   *offset = *offset + 1;
}

uint32_t mrg_algo0(uint8_t *dst, uint8_t *src, uint32_t len, int param_4)
{
   uint8_t bVar1;
   uint8_t bVar2;
   uint8_t bVar3;
   uint16_t uVar7;
   uint16_t uVar8;
   int iVar9;
   uint8_t *pbVar10;
   uint16_t control_byte;
   uint32_t i;
   
   control_byte = 0x7F80;
   bVar1 = dictonary[param_4 << 1];
   bVar3 = dictonary[(param_4 << 1) + 1];
   i = 0;
   
   do
   {
      control_byte <<= 1;
      
      if (control_byte == 0xFF00)
      {
         control_byte =  (*src++ << 8) | 0xFF;
      }
      
      if (!(control_byte & 0x8000))
      {
         uVar7 = BE2LE16(src);
         uVar8 = -bVar1;
         
         if (bVar1 == 0)
         {
            uVar8 = uVar7 << (uVar8 & 0x1f);
         }
         else
         {
            uVar8 = uVar7 >> ((~uVar8 & 0x1f) + 1);
         }
         
         uVar8 += bVar3;
         iVar9 = i - (uVar7 & ((1 << (bVar1 & 0x1f)) + 0xFFFF));
         src += 2;
         
         while (iVar9 < 0)
         {
            iVar9++;
            dst[i] = 0;
            uVar8--;
            i++;
         }
         
         pbVar10 = dst + iVar9;
         
         while (uVar8)
         {
            uVar8--;
            bVar2 = *pbVar10;
            pbVar10++;
            dst[i] = bVar2;
            i++;
         }
      }
      else
      {
         dst[i++] = *src++;
      }
   }
   while (i < len);
   
   return i;
}

uint32_t mrg_algo1(uint8_t *dst, uint8_t *src, uint32_t len, int param_4)
{
   uint8_t bVar1;
   uint8_t bVar2;
   uint8_t bVar3;
   uint32_t uVar7;
   int n;
   uint32_t i;
   uint32_t uVar10;
   int iVar11;
   uint8_t *pbVar12;
   
   uVar10 = 0x7F80;
   bVar1 = dictonary[(param_4 << 1) + 8];
   bVar3 = dictonary[(param_4 << 1) + 9];
   n = 0;
   
   do
   {
      uVar10 = uVar10 << 1;
      
      if ((uVar10 & 0xFFFF) == 0xFF00)
      {
         bVar2 = *src;
         src++;
         uVar10 = 0xFF | (uint)bVar2 << 8;
      }
      
      if (!(uVar10 & 0x8000))
      {
         bVar2 = *src;
         iVar11 = n - ((uint)bVar2 & (int)(short)((short)(1 << ((uint)bVar1 & 0x1f)) + 0xFFFF));
         uVar7 = -(uint)bVar1;
         
         if (bVar1 == 0)
         {
            uVar7 = (uint)bVar2 << (uVar7 & 0x1f);
         }
         else
         {
            uVar7 = (uint)(bVar2 >> ((~uVar7 & 0x1f) + 1));
         }
         
         uVar7 = uVar7 + (int)(short)(uint16_t)bVar3;
         i = n;
         
         while (iVar11 < 0)
         {
            iVar11++;
            dst[i] = 0;
            uVar7--;
            i++;
         }
         
         pbVar12 = dst + iVar11;
         
         while ((uVar7 & 0xffff) != 0)
         {
            uVar7--;
            bVar2 = *pbVar12;
            pbVar12++;
            dst[i] = bVar2;
            i++;
         }
      }
      else
      {
         i = n + 1;
         dst[n] = *src;
      }
      
      src++;
      n = i;
   }
   while (i < len);
   
   return i;
}

uint32_t mrg_algo2(uint8_t *dst, uint8_t *src, uint32_t len, int param_4)
{
   uint8_t bVar1;
   uint32_t uVar3;
   uint32_t uVar4;
   uint32_t uVar5;
   uint32_t i;
   uint32_t local_30;
   uint32_t local_2c;
   uint16_t local_28;
   short local_24;
   
   bVar1 = dictonary[(param_4 << 1) + 12];
   uVar5 = 0x7F80;
   local_24 = (short)(1 << ((uint)bVar1 & 0x1f)) + 0xFFFF;
   local_28 = dictonary[(param_4 << 1) + 13];
   local_2c = 0;
   i = 0;
   
   do
   {
      uVar5 = uVar5 << 1;
      
      if ((uVar5 & 0xffff) == 0xFF00)
      {
         uVar5 = FUN_8c01a480(src, &local_2c);
         uVar5 = 0xFF | (uVar5 & 0xff) << 8;
      }
      
      if (!(uVar5 & 0x8000))
      {
         uVar3 = FUN_8c01a480(src, &local_2c);
         uVar3 = uVar3 & 0xff;
         uVar4 = -(uint)bVar1;
         
         if (bVar1 == 0)
         {
            uVar4 = uVar3 << (uVar4 & 0x1f);
         }
         else
         {
            uVar4 = uVar3 >> ((~uVar4 & 0x1f) + 1);
         }
         
         uVar4 = uVar4 + local_28;
         local_30 = i - (uVar3 & (int)local_24);
         
         while ((int)local_30 < 0)
         {
            FUN_8c01a4c0(0, dst, &i);
            uVar4--;
            local_30++;
         }
         
         while ((uVar4 & 0xffff) != 0)
         {
            uVar3 = FUN_8c01a45a(dst, &local_30);
            FUN_8c01a4c0(uVar3, dst, &i);
            uVar4--;
         }
      }
      else
      {
         uVar3 = FUN_8c01a45a(src, &local_2c);
         FUN_8c01a4c0(uVar3, dst, &i);
      }
   }
   while (i < len * 2);
   
   i++;
   
   if ((int)(i + 1) < 0)
   {
      i++;
   }
   
   return i >> 1;
}

uint32_t mrg_algo3(uint8_t *dst, uint8_t *src, uint32_t len, int param_4)
{
   uint8_t bVar1;
   uint32_t uVar2;
   uint32_t uVar3;
   uint32_t uVar4;
   uint32_t i;
   uint32_t local_30;
   uint32_t local_2c;
   short local_28;
   uint16_t local_24;
   
   uVar4 = 0x7F80;
   bVar1 = dictonary[(param_4 << 1) + 16];
   local_28 = (short)(1 << ((uint)bVar1 & 0x1f)) + 0xFFFF;
   local_24 = dictonary[(param_4 << 1) + 17];
   local_2c = 0;
   i = 0;
   
   do
   {
      uVar4 = uVar4 << 1;
      
      if ((uVar4 & 0xFFFF) == 0xFF00)
      {
         uVar4 = FUN_8c01a480(src, &local_2c);
         uVar4 = 0xFF | (uVar4 & 0xFF) << 8;
      }
      
      if (!(uVar4 & 0x8000))
      {
         uVar2 = FUN_8c01a45a(src, &local_2c);
         uVar3 = FUN_8c01a480(src, &local_2c);
         uVar3 = ((uVar2 & 0xFF) << 8) | (uVar3 & 0xFF);
         uVar2 = -(uint)bVar1;
         
         if (bVar1 == 0)
         {
            uVar2 = uVar3 << (uVar2 & 0x1F);
         }
         else
         {
            uVar2 = uVar3 >> ((~uVar2 & 0x1F) + 1);
         }
         
         uVar2 = uVar2 + (int)(short)local_24;
         local_30 = i - (uVar3 & (int)local_28);
         
         while ((int)local_30 < 0)
         {
            FUN_8c01a4c0(0, dst, &i);
            uVar2--;
            local_30++;
         }
         
         while ((uVar2 & 0xFFFF) != 0)
         {
            uVar3 = FUN_8c01a45a(dst, &local_30);
            FUN_8c01a4c0(uVar3, dst, &i);
            uVar2--;
         }
      }
      else
      {
         uVar2 = FUN_8c01a45a(src, &local_2c);
         FUN_8c01a4c0(uVar2, dst, &i);
      }
   }
   while (i < len * 2);
   
   i++;
   
   if ((int)(i + 1) < 0)
   {
      i++;
   }
   
   return i >> 1;
}

int decompress_mrg(uint8_t *dst, uint8_t *src)
{
   uint32_t encrypt_algo = (src[0] & 0x70) >> 4;

   if (!(src[0] & 0x80))
   {
      memset(dst, 0, BE2LE32(&src[4]));
      
      switch (encrypt_algo)
      {
         case 0:
            return (int) mrg_algo0(dst, &src[8], BE2LE32(&src[4]), src[0] & 0x0F);
            break;
         
         case 1:
            return (int) mrg_algo1(dst, &src[8], BE2LE32(&src[4]), src[0] & 0x0F);
            break;
         
         case 2:
            return (int) mrg_algo2(dst, &src[8], BE2LE32(&src[4]), src[0] & 0x0F);
            break;
         
         case 3:
            return (int) mrg_algo3(dst, &src[8], BE2LE32(&src[4]), src[0] & 0x0F);
            break;
      }
   }
   else
   {
      memset(dst, 0, BE2LE32(src) & 0xFFFFFF);
      
      switch (encrypt_algo)
      {
         case 0:
            return (int) mrg_algo0(dst, &src[4], BE2LE32(src) & 0xFFFFFF, src[0] & 0x0F);
            break;
         
         case 1:
            return (int) mrg_algo1(dst, &src[4], BE2LE32(src) & 0xFFFFFF, src[0] & 0x0F);
            break;
         
         case 2:
            return (int) mrg_algo2(dst, &src[4], BE2LE32(src) & 0xFFFFFF, src[0] & 0x0F);
            break;
         
         case 3:
            return (int) mrg_algo3(dst, &src[4], BE2LE32(src) & 0xFFFFFF, src[0] & 0x0F);
            break;
      }
   }
   
   return -1;
}

typedef struct
{
   uint32_t offset;
   uint32_t size;
} vFILE_t;

typedef struct
{
   uint32_t f_cnt;
   vFILE_t vFile[1024];
} mrg_s;

off_t fsize(const char *filename)
{
    struct stat st;

    if (stat(filename, &st) == 0)
    {
        return st.st_size;
   }

    return -1;
}

int main(int argc, char *argv[])
{
   FILE *fo, *fi;
   int i, i_sz, o_sz;
   uint8_t *in_buf, *out_buf;
   mrg_s *iMRG = NULL;
   char name[256];
   uint32_t tmp_sz;
   
   if (argc != 2)
   {
      printf("no input file\n");
      return 1;
   }
   
   if ((i_sz = fsize(argv[1])) == -1 || !(fi = fopen(argv[1], "rb")))
   {
      printf("ERROR: can't open %s\n", argv[1]);
      return 1;
   }
   
   if (!(in_buf = calloc(i_sz, 1)))
   {
      printf("ERROR: can't allocate %d bytes\n", i_sz);
      fclose(fi);
      return 1;
   }
   
   if (!(out_buf = calloc(i_sz, 1)))
   {
      printf("ERROR: can't allocate %d bytes\n", i_sz);
      fclose(fi);
      return 1;
   }
   
   fread(in_buf, 1, i_sz, fi);
   fclose(fi);
   
   iMRG = (mrg_s *) in_buf;
   
   for (i = 0; i < iMRG->f_cnt; i++)
   {
      tmp_sz = 0;
      uint32_t offset = 0;
      
      if((in_buf[iMRG->vFile[i].offset+1] == 'S' || in_buf[iMRG->vFile[i].offset+1] == 's') &&
         (in_buf[iMRG->vFile[i].offset+2] == '8' || in_buf[iMRG->vFile[i].offset+2] == '4'))
      {
         tmp_sz = !(in_buf[iMRG->vFile[i].offset] & 0x80) ?   BE2LE32(&in_buf[iMRG->vFile[i].offset+4]) :
                                                (BE2LE32(&in_buf[iMRG->vFile[i].offset]) & 0xFFFFFF);
         out_buf = realloc(out_buf, tmp_sz);
         
         if ((o_sz = decompress_mrg(out_buf, &in_buf[iMRG->vFile[i].offset])) == -1)
         {
            printf("ERROR: can't decrypt file %d of %u\n", i+1, iMRG->f_cnt);
            continue;
         }
         
         offset = !(strncmp((char *) out_buf, "PVRX", 4)) ? 0x24 : 0;
         
         if (offset == 0x24 || (!offset && !(strncmp((char *) out_buf, "GBIX", 4))))
         {
            sprintf(name, "%s_%d.pvr", argv[1], i);
         }
         else if (!strncmp((char *) out_buf, "NJCM", 4))
         {
            sprintf(name, "%s_%d.njcm", argv[1], i);
         }
         else
         {
            sprintf(name, "%s_%d.bin", argv[1], i);
         }
      }
      else if (!strncmp((char *) &in_buf[iMRG->vFile[i].offset+33], "CRI", 3))
      {
         sprintf(name, "%s_%d.adx", argv[1], i);
      }
      else if (!strncmp((char *) &in_buf[iMRG->vFile[i].offset], "NJTL", 4))
      {
         sprintf(name, "%s_%d.nj", argv[1], i);
      }
      else if (!strncmp((char *) &in_buf[iMRG->vFile[i].offset], "NMDM", 4))
      {
         sprintf(name, "%s_%d.nm", argv[1], i);
      }
      else if (!strncmp((char *) &in_buf[iMRG->vFile[i].offset], "SMSB", 4))
      {
         sprintf(name, "%s_%d.smsb", argv[1], i);
      }
      else if (!strncmp((char *) &in_buf[iMRG->vFile[i].offset], "SOSB", 4))
      {
         sprintf(name, "%s_%d.sosb", argv[1], i);
      }
      else
      {   
         sprintf(name, "%s_%d.mrg", argv[1], i);
      }
      
      if (!(fo = fopen(name, "wb")))
      {
         printf("ERROR: can't open for write %s\n", name);
         continue;
      }
      
      if (tmp_sz)
      {
         fwrite(out_buf + offset, 1, o_sz - offset, fo);
      }
      else
      {
         fwrite(&in_buf[iMRG->vFile[i].offset], 1, iMRG->vFile[i].size, fo);
      }
      
      fclose(fo);
   }
   
   free(in_buf);
   free(out_buf);
   
   return 0;
}


I'm afraid to lose all the work done again, so here is the executable file with the current progress.
1_SGGG.7z
(793.09 KiB) Downloaded 123 times

User avatar
yzb
Developer
Posts: 130

Re: New SEGAGAGA translation project in the works!

Post#79 » Sat Nov 12, 2022 7:07 pm

Now that the decompression is completed, the compression can be replaced by other methods, as long as the identifier is inserted in the entry.

For example, the Chinese version is

r4 = Decompress data memory address

r5 = compressed data memory address


Code: Select all


8C019F78:
      !In the compressed data definition, the first byte is 0xff to indicate custom compression
            mov.b   @r5, r0           
            cmp/eq  #-1, r0         
            bt      custom_decompression
            jmp   Original_game_decompression
            nop

custom_decompression:
!You can use the often encountered prs decompression program

      add   #0x1, r5                !skip the first byte identifier
      mov.l   r8, @-r15
      mov.l   r4, @-r15
      mov     r5, r4
      mov.l   @r15, r5                  !r4 r5 swap positions
      mov.w   v_ff00, r3!  FFFFFF00
      mov.w   v_e000, r8!  FFFFE000
      mov.b   @r4+, r6
      bra   loc_002
      mov   #0x9, r7

loc_001:
      mov.b   @r4+, r1
      mov.b   r1, @r5
      add   #0x1, r5

loc_002:
      dt   r7
      bf/s   loc_003
      shlr   r6
      mov.b   @r4+, r6
      mov   #0x8, r7
      shlr   r6

loc_003:
      bt   loc_001
      dt   r7
      bf/s   loc_004
      shlr   r6
      mov.b   @r4+, r6
      mov   #0x8, r7
      shlr   r6

loc_004:
      bt   loc_009
      mov   #0x0, r0
      dt   r7
      bf/s   loc_005
      shlr   r6
      mov.b   @r4+, r6
      mov   #0x8, r7
      shlr   r6

loc_005:
      rotcl   r0
      dt   r7
      bf/s   loc_006
      shlr   r6
      mov.b   @r4+, r6
      mov   #0x8, r7
      shlr   r6

loc_006:
      mov.b   @r4+, r2
      rotcl   r0
      or   r3, r2

loc_007:
      add   #0x2, r0
      add   r5, r2

loc_008:
      mov.b   @r2+, r1
      dt   r0
      mov.b   r1, @r5
      bf/s   loc_008
      add   #0x1, r5
      bra   loc_002
      nop


loc_009:
      mov.b   @r4+, r0
      mov.b   @r4+, r1
      extu.b   r0, r2
      shll8   r1
      or   r1, r2
      tst   r2, r2
      bt   loc_end
      shlr2   r2
      shlr   r2
      and   #0x7, r0
      tst   r0, r0
      bf/s   loc_007
      or   r8, r2
      mov.b   @r4+, r0
      add   r5, r2
      extu.b   r0, r0
      bra   loc_008
      add   #0x1, r0

loc_end:            
      mov.l   @r15+, r1
      mov.l   @r15+, r8
      sub     r1, r5
      rts
      mov      r5, r0               !      Need to return the decompressed file size r0
      
      
v_ff00:
   .short   0xff00
v_e000:
   .short   0xe000


madsheep
rebel
Posts: 20

Re: New SEGAGAGA translation project in the works!

Post#80 » Sat Nov 26, 2022 5:30 pm

megavolt85 wrote:current progress:
+ used half wide font 12x24
+ supported only ASCII charset
+ translated few strings in main binary
- text pocessor have limit, 32 character per line, need fix it


any news on 32 char limit?

  • Similar Topics
    Replies
    Views
    Last post

Return to “New Releases/Homebrew/Emulation”

Who is online

Users browsing this forum: No registered users