STOS MBK MAKER

From Atari Wiki
Jump to navigation Jump to search

This is the C source of a program for extracting STOS memorybanks and storing them as .MBK files from .BAS, .PRG, .MBS files. Compile it into a TTP and enter as arguments any fie you want to extract STOS memory banks from.

Note: a lot of STOS programs are packed with executable packers like ICE or Atomik. To extract STOS memorybanks from packed programs you will have to depack them first. A program like Synergy depack or Multi depack can be used for depacking packe files. Note 2: A lot of STOS demo's don't have the proper .PRG extension. As this program doesn't look at the extension but looks at the data inside the file it will find memorybanks anyway.

/*
** mbk creator
** read a file and try to extract STOS memory blocks from it
** make_mbk is a small utility to extra STOS memory banks,
** (.MBK files) from data or program files. Just drop a
** file on make_mbk.ttp and the program will analyze the
** file and extract STOS memorybanks from the file when
** any found. Note a lot of STOS demo's don't have the
** .PRG extension. The program doesn't care and will
** extract the memory banks anyway. Be aware a lot of STOS
** programs are packed with program packers like Atomik or
** Ice. You have to depack such programs first with a
** tool like Synergy depack or Multi depack.
**
** Placed in public domain, july 2007 Hans Wessels
*/

#include <stdlib.h>
#include <stdio.h>
#include <string.h>


#define FILE_NAAM8_3 /* undef for unrestricted filenames */

#define PRINT_INFO /* show processing status */

#define ATARI_MEMLIMIT (4L*1024L*1024L)
#define MAX_PATH 256 /* maximum path size for file */

#define MBS_HEADER_SIZE 78
#define MBK_HEADER_SIZE 18
#define BAS_HEADER_SIZE 78
#define PRG_HEADER_SIZE 106

unsigned long get_long(const unsigned char *p)
{
  unsigned long res;
  res=*p++;
  res<<=8;
  res+=*p++;
  res<<=8;
  res+=*p++;
  res<<=8;
  res+=*p;
  return res;
}

unsigned int get_word(const unsigned char *p)
{
  unsigned int res;
  res=*p++;
  res<<=8;
  res+=*p;
  return res;
}


void put_long(unsigned char* p, unsigned long data)
{
  p[3]=(unsigned char)(data&0xff);
  data>>=8;
  p[2]=(unsigned char)(data&0xff);
  data>>=8;
  p[1]=(unsigned char)(data&0xff);
  data>>=8;
  p[0]=(unsigned char)(data&0xff);
}

void make_filenaam(char* naam)
{
#ifdef FILE_NAAM8_3
  int len=(int)strlen(naam);
  int naam_start=len;
  int i;
  if(naam_start==0)
  {
    return;
  }
  while((naam_start!=0) && (naam[naam_start-1]!='\\'))
  { /* zoek einde van het path en begin van de file naam */
    naam_start--;
  }
  i=len;
  while(i>=naam_start)
  {
    if(naam[i]=='.')
    {
      naam[i]=0;
    }
    i--;
  }
  len=(int)strlen(naam);
  if((len-naam_start)>7)
  {
    naam[naam_start+7]=0;
  }
#else
  (void)naam;
#endif
}

void read_banks(char* naam, FILE* f, long size, long data, long bank_info)
{
  unsigned char* file;
  unsigned char header[18]="Lionpoubnk"; /* we will patch in bank no and size later */
  if(size>ATARI_MEMLIMIT)
  {
    return;
  }
  file=malloc(size);
  if(file==NULL)
  {
    printf("Out of memory.\n");
    return;
  }
  fseek(f, 0, SEEK_SET);
  fread(file, 1, size, f);
  {
    long i;
    char base_path[MAX_PATH];
    sprintf(base_path, naam);
    make_filenaam(base_path);
    for(i=0;i<15;i++)
    {
      long len;
      len=get_long(file+bank_info+4*i);
      if(len!=0)
      { /* memory bank gevonden */
        put_long(header+10, i+1);
        put_long(header+14, len);
        len=len&(0xffffffL); /* strip banktype */
        if((data+len)<=size)
        { /* within limits */
          FILE* dst;
          char path[MAX_PATH];
          sprintf(path, "%s%lx.mbk", base_path, i);
          #ifdef PRINT_INFO
          printf("output: %s\n", path);
          #endif
          dst=fopen(path, "wb");
          if(dst!=NULL)
          {
            fwrite(header, 1, 18, dst);
            fwrite(file+data, 1, len, dst);
            fclose(dst);
          }
        }
        data+=len;
      }
    }
  }
  free(file);
}

void make_ext(char* naam)
{
#ifdef FILE_NAAM8_3
  int len=(int)strlen(naam);
  int naam_start=len;
  int i;
  if(naam_start==0)
  {
    return;
  }
  while((naam_start!=0) && (naam[naam_start-1]!='\\'))
  { /* zoek einde van het path en begin van de file naam */
    naam_start--;
  }
  i=len;
  while(i>=naam_start)
  {
    if(naam[i]=='.')
    {
      naam[i]=0;
    }
    i--;
  }
#else
  (void)naam;
#endif
}


void write_mbk(char* naam, FILE* f, long size)
{
  unsigned char* file;
  if(size>ATARI_MEMLIMIT)
  {
    return;
  }
  file=malloc(size);
  if(file==NULL)
  {
    printf("Out of memory.\n");
    return;
  }
  fseek(f, 0, SEEK_SET);
  fread(file, 1, size, f);
  {
    char path[MAX_PATH];
    FILE* dst;
    sprintf(path, naam);
    make_ext(path);
    sprintf(path, "%s.mbk", path);
    #ifdef PRINT_INFO
    printf("output: %s\n", path);
    #endif
    dst=fopen(path, "wb");
    if(dst!=NULL)
    {
       fwrite(file, 1, size, dst);
       fclose(dst);
    }
  }
  free(file);
}


void read_mbk(char * naam)
{
  unsigned char *file;
  FILE* f;
  long int len;
  file=malloc(2048);
  if(file==NULL)
  {
    printf("Out of memory.");
    return;
  }
  f=fopen(naam, "rb");
  if(f==NULL)
  {
    printf("Can not open file!");
  }
  else
  {
    len=fread(file, 1, 256, f);
    if(len!=256)
    {
      printf("File too small: %li", len);
    }
    if((strncmp("Lionpoubnk", file, 10)==0) && (get_long(file+10)==0))
    { /* STOS MBS */
      long size;
      long start_data;
      long bank_info;
      size=get_long(file+14)+MBS_HEADER_SIZE;
      start_data=MBS_HEADER_SIZE;
      bank_info=18;
      read_banks(naam, f, size, start_data, bank_info);
    }
    else if((strncmp("Lionpoubnk", file, 10)==0) && (get_long(file+10)<16))
    { /* STOS MBK with wrong extension? save as mbk */
      long size;
      size=(get_long(file+14)&0xffffffL)+MBK_HEADER_SIZE;
      write_mbk(naam, f, size);
    }
    else if(strncmp("Lionpoulos", file, 10)==0)
    { /* STOS BAS */
      long size;
      long start_data;
      long bank_info;
      size=get_long(file+10)+BAS_HEADER_SIZE;
      start_data=get_long(file+14)+BAS_HEADER_SIZE;
      bank_info=18;
      read_banks(naam, f, size, start_data, bank_info);
    }
    else if((get_word(file)==0x601a) && ((get_long(file+112)==0x53746f73L) || (get_long(file+112)==0x53544f53L)))
    { /* STOS program, allowing for Stos and STOS header */
      long size;
      long start_data;
      long bank_info;
      size=get_long(file+30)+PRG_HEADER_SIZE;
      start_data=get_long(file+34)+98;
      bank_info=38;
      read_banks(naam, f, size, start_data, bank_info);
    }
    fclose(f);
  }
  free(file);
}


int main(int argc, const char *argv[])
{
  while(--argc>0)
  {
    #ifdef PRINT_INFO
    printf("Processing: %s :\n", (char *)argv[argc]);
    #endif
    #ifdef PRINT_INFO
    read_mbk((char *)argv[argc]);
    #endif
  }
  return 0;
}

--Nyh 16:12, 10 July 2007 (EDT)