Sonic and Sega Retro Message Board: Lightning - Viewing Profile - Sonic and Sega Retro Message Board

Jump to content

Hey there, Guest!  (Log In · Register) Help

Group:
Tech Member: Tech Members
Active Posts:
130 (0.03 per day)
Most Active In:
Engineering & Reverse Engineering (29 posts)
Joined:
13-December 04
Profile Views:
1637
Last Active:
User is offline Private
Currently:
Offline

My Information

Member Title:
indeed
Age:
Age Unknown
Birthday:
Birthday Unknown
Gender:
Male Male
Location:
the internet

Contact Information

E-mail:
Private
Website:
Website  http://localhost/

Previous Fields

Project:
yes
National Flag:
None

Latest Visitors

Topics I've Started

  1. ssr-one-util - program to list, extract, and create Sonic and the Secr

    01 February 2008 - 06:04 PM

    originally posted at http://forums.sonic-...?showtopic=3602

    Quote

    Over the past few days, I've written a program to handle the new .one archive format found in Sonic and the Secret Rings.
    Sources can be found here: http://lightning.h4xopolis.net/devel/sonic...-util-0.4.0.one

    ... or http://lightning.h4xopolis.net/devel/sonic...il-0.4.0.tar.gz, as you probably don't have the means to extract .one archives yet. =P

    You'll need gcc or equivalent to build the program. If you don't have make, the program can be compiled with gcc alone by running gcc -O2 -Wall one.c prs.c ssr-one-util.c -o ssr-one-util.exe in the folder where the sources are. (.exe if you're on Microsoft Windows, that is. Otherwise it probably won't matter what you name the executable). If you do have make, compilation is easy enough, just type make in the source folder.

    The terms I've given in the README are GPL-ish. Feel free to make any modifications, frontends, or anything else using this source code. I'd appreciate if you credited me (and fuzziqer for his PRS routines) though =P Also make sure that any modifications done to the code are released in source form as well.

    Hope you find these useful.
    Bug reports welcome!
  2. Sonic Rush E3 ROM

    05 January 2007 - 06:00 PM

    download, mirror, etc.
    Released on my birthday, too =P It's a one-level demo. I personally prefer the music in this over that in the final, which is quite different, if I recall.
    It works on my M3 SD. The ROM boots in the emulator DeSmuME 0.5, but the title screen is in Japanese (not so on the real hardware), the graphics are garbled, and it locks up before the game is playable. If you have a means of playing backups on your own DS, however, check it out =)
    Have fun.
  3. PRS compression related stuff (for programmers)

    12 November 2005 - 03:53 PM

    I finally decided that after having been inches from completion for almost a month now, I may as well show everyone what I have. The prs::decompress() worked for every .PRS I fed to it, so it's still useful for that. If any of you happen to plan on making a hacking program in C++ that uses files that are compressed in .PRS or .ONE, you're more than welcome to use this stuff.

    Anyway, can anyone suggest any changes to prs::compress() and its related functions that might make it work properly? I can't seem to get it right, and I've rewritten the fucntions quite a few times with the same result, so I figure that it's just some logical misconception in my head. I normally don't do this, but I kind of need to have this done or I might fail for this marking quarter. =P

    A note: using prs::compress(PRS_MODE_STORAGE) works fine, but it doesn't "compress" it, really. If anyone wants to use the program for the PC games or can easily rebuild the filesystem or change pointers for the newer generation games, this can be used =P Because this works, the constant PRS_MODE_DEFAULT represents PRS_MODE_STORAGE.

    /*
                    .PRS compression class written by Lightning.
                  For use with modern Sega games' compressed data.
    
       Many thanks go to Nemesis; without him, this wouldn't have been possible.
                  His .PRS program was a huge help in this project.
      In fact, in many ways, the decompression aspects of this program mirror his.
    */
    
    // 11/12/2005 - Brick wall on progress on compress() between 10/19/2005 and now
    // 10/18/2005 - Implemented a saucerful of subroutines, mainly for compress()
    // 10/15/2005 - Added delete_this_buffer() functions for garbage collection
    // 10/14/2005 - Simplified decompression code
    // 10/12/2005 - Made some minor revisions for efficiency
    // 10/03/2005 - First private release
    
    #ifndef __PRS__
    #define __PRS__
    
    #include <fstream>
    
    typedef unsigned char byte;
    typedef unsigned short int word;
    typedef unsigned long int dword;
    
    #define PRS_MODE 	 byte
    #define PRS_MODE_STORAGE	0x1
    #define PRS_MODE_OFFSETCPY	0x2
    #define PRS_MODE_EXTENDCPY	0x4
    #define PRS_MODE_ALIGNED	0x8
    #define PRS_MODE_DEFAULT	0x1 // replace with 0xF when compression works
    
    #define min(a, b) ((a) < (b) ? (a) : (b))
    
    class prs
    {
    private:
    
    	byte *cmp_buffer;
    	byte *dec_buffer;
    	dword cmp_size, cmp_index;
    	dword dec_size, dec_index;
    
    	bool tag_reposition;
    	byte tag_byte;
    	byte tag_bits;
    	dword tag_index;
    
    	byte min_length;
    	dword offset_count;
    	word offset;
    
    	bool compressed;
    	bool decompressed;
    	byte compression;
    	byte decompression;
    public:
    	prs(void);
    	~prs(void);
    	void reset(void);
    	void delete_cmp_buffer(void);
    	void delete_dec_buffer(void);
    private:
    	byte cmp_get_byte(void);
    	byte dec_get_byte(void);
    	void cmp_put_byte(byte value);
    	void dec_put_byte(byte value);
    public:
    	bool decompress(PRS_MODE mode);
    	bool decompress(void);
    private:
    	bool dec_get_bit(void);
    	bool dec_extended_copy(void);
    	bool dec_offset_copy(void);
    	bool dec_copy(void);
    public:
    	bool compress(PRS_MODE mode);
    	bool compress(void);
    private:
    	void cmp_put_bit(bool bit);
    	PRS_MODE cmp_find_best(PRS_MODE mode);
    public:
    	bool read_cmp_file(const char *filename);
    	bool read_dec_file(const char *filename);
    	void read_cmp_buffer(const byte *new_buffer, const dword new_size);
    	void read_dec_buffer(const byte *new_buffer, const dword new_size);
    	bool write_cmp_file(const char *filename);
    	bool write_dec_file(const char *filename);
    	void write_cmp_buffer(byte *new_buffer);
    	void write_dec_buffer(byte *new_buffer);
    	dword get_cmp_size(void);
    	dword get_dec_size(void);
    };
    
    
    
    
    
    prs::prs(void)
    {
    	reset();
    	delete_cmp_buffer();
    	delete_dec_buffer();
    }
    prs::~prs(void)
    {
    	delete_cmp_buffer();
    	delete_dec_buffer();
    }
    
    void prs::reset(void)
    {
    	cmp_index = 0;
    	dec_index = 0;
    	tag_reposition = true;
    	tag_byte = 0;
    	tag_bits = 8;
    	tag_index = 0;
    	min_length = 2;
    	offset_count = 0;
    	offset = 0;
    	compression = PRS_MODE_DEFAULT;
    	decompression = PRS_MODE_DEFAULT;
    }
    
    void prs::delete_cmp_buffer(void)
    {
    	cmp_index = 0;
    	if(!cmp_buffer)
      delete(cmp_buffer);
    	cmp_size = 0;
    	compressed = false;
    }
    void prs::delete_dec_buffer(void)
    {
    	dec_index = 0;
    	if(!dec_buffer)
      delete(dec_buffer);
    	dec_size = 0;
    	decompressed = false;
    }
    
    byte prs::cmp_get_byte(void)
    {
    	return(cmp_buffer[cmp_index++]);
    }
    byte prs::dec_get_byte(void)
    {
    	return(dec_buffer[dec_index++]);
    }
    void prs::cmp_put_byte(byte value)
    {
    	cmp_buffer[cmp_index++] = value;
    }
    void prs::dec_put_byte(byte value)
    {
    	dec_buffer[dec_index++] = value;
    }
    
    bool prs::decompress(PRS_MODE mode)
    {
    	if(decompressed && decompression == mode)
      return(decompressed);
    
    	reset();
    	if(!cmp_size || !cmp_buffer)
      return(false);
    
    	decompression = mode;
    
    	delete_dec_buffer();
    	dec_buffer = new byte[dec_size = cmp_size << 8];
    	memset(dec_buffer, 0x00, dec_size);
    
    	tag_byte = cmp_get_byte();
    	while(cmp_index < cmp_size - 1)
    	{
      if(dec_get_bit() && mode & PRS_MODE_STORAGE)
      {
     	 dec_put_byte(cmp_get_byte());
      }
      else
      {
     	 if(dec_get_bit() && mode & PRS_MODE_EXTENDCPY)
     	 {
        if(!dec_extended_copy())
        {
       	 dec_size = dec_index;
       	 return(decompressed = false);
        }
     	 }
     	 else if(mode & PRS_MODE_OFFSETCPY)
     	 {
        if(!dec_offset_copy())
        {
       	 dec_size = dec_index;
       	 return(decompressed = false);
        }
     	 }
      }
    	}
    
    	dec_size = dec_index;
    
    	return(decompressed = true);
    }
    bool prs::decompress(void)
    {
    	if(!decompressed)
      return(decompress(PRS_MODE_DEFAULT));
    	return(decompressed);
    }
    
    bool prs::dec_get_bit(void)
    {
    	bool bit;
    
    	if(!tag_bits)
    	{
      tag_byte = cmp_get_byte();
      tag_bits = 8;
    	}
    	tag_bits--;
    	bit = tag_byte & 0x01;
    	tag_byte >>= 1;
    
    	return(bit);
    }
    
    bool prs::dec_extended_copy(void)
    {
    	byte pair[2] = { cmp_get_byte(), cmp_get_byte() };
    
    	if(!(pair[0] || pair[1]))
      return(true);
    
    	offset_count = pair[0] & 0x07 ? (pair[0] & 0x07) + min_length : cmp_get_byte() + 1;
    	offset = 0xE000 | (pair[1] << 5) | (pair[0] >> 3);
    
    	return(dec_copy());
    }
    bool prs::dec_offset_copy(void)
    {
    	offset_count = (((byte)dec_get_bit() << 1) | (byte)dec_get_bit()) + min_length;
    	offset = 0xFF00 | cmp_get_byte();
    
    	return(dec_copy());
    }
    bool prs::dec_copy(void)
    {
    	if(dec_index < (offset = ~offset + 1))
      return(false);
    
    	while(offset_count--)
      dec_buffer[dec_index] = dec_buffer[dec_index++ - offset];
    
    	return(true);
    }
    
    bool prs::compress(PRS_MODE mode)
    {
    	if(compressed && compression == mode)
      return(compressed);
    
    	reset();
    	if(!dec_size || !dec_buffer)
      return(false);
    
    	compression = mode;
    
    	delete_cmp_buffer();
    	cmp_buffer = new byte[cmp_size = dec_size << 2];
    	memset(cmp_buffer, 0x00, cmp_size);
    
    	tag_index = 0;
    	cmp_index = 1;
    	tag_reposition = false;
    
    	while(dec_index < dec_size)
    	{
    // PROBABLY SOMETHING WRONG HERE
      switch(cmp_find_best(mode))
      {
      case PRS_MODE_EXTENDCPY:
     	 cmp_put_bit(0);
     	 cmp_put_bit(1);
    
     	 byte pair[2];
     	 pair[0] = offset << 3;
     	 pair[1] = offset >> 5;
    
     	 if(offset_count < 8)
        pair[0] |= offset_count;
    
     	 cmp_put_byte(pair[0]);
     	 cmp_put_byte(pair[1]);
    
     	 if(offset_count >= 8)
        cmp_put_byte(offset_count - 1);
    
     	 dec_index += offset_count;
     	 break;
      case PRS_MODE_OFFSETCPY:
     	 cmp_put_bit(0);
     	 cmp_put_bit(0);
    
     	 cmp_put_bit(!!((offset_count - min_length) & 2));
     	 cmp_put_bit(!!((offset_count - min_length) & 1));
     	 cmp_put_byte(offset + 1);
    
     	 dec_index += offset_count;
     	 break;
      default:
     	 cmp_put_bit(1);
     	 cmp_put_byte(dec_get_byte());
     	 break;
      }
    
      if(tag_reposition)
      {
     	 tag_index = cmp_index++;
     	 tag_reposition = false;
      }
    	}
    
    	while(!tag_reposition)
    	{
      cmp_put_bit(0);
      cmp_put_bit(1);
      cmp_put_byte(0);
    	}
    
    	if(mode & PRS_MODE_ALIGNED)
      while(cmp_index % 4)
     	 cmp_put_byte(0);
    
    	cmp_size = cmp_index;
    	return(compressed = true);
    }
    bool prs::compress(void)
    {
    	if(!compressed)
      return(compress(PRS_MODE_DEFAULT));
    	return(compressed);
    }
    
    void prs::cmp_put_bit(bool bit)
    {
    	tag_bits--;
    	tag_byte |= (byte)bit << 7;
    	if(!tag_bits)
    	{
      cmp_buffer[tag_index] = tag_byte;
      tag_byte = 0;
      tag_bits = 8;
      tag_reposition = true;
    	}
    	tag_byte >>= 1;
    }
    
    PRS_MODE prs::cmp_find_best(PRS_MODE mode)
    {
    	if((mode & PRS_MODE_EXTENDCPY) || (mode & PRS_MODE_OFFSETCPY))
    	{
    // PROBABLY SOMETHING WRONG HERE
      if(dec_index > min_length)
      {
     	 dword max_index = dec_index;
     	 dword max_count = min_length;
     	 bool found = false;
    
     	 for(offset = min(dec_index, (mode & PRS_MODE_EXTENDCPY) ? 0x2000 : 0x100);
     	 offset;
     	 offset--)
     	 {
        for(offset_count = 0;
        dec_index - offset + offset_count < dec_index - min_length
        && dec_index + offset_count < dec_size
        && offset_count < ((mode & PRS_MODE_EXTENDCPY) ? 0x100 : min_length + 4);
        offset_count++)
        {
       	 if(dec_buffer[dec_index + offset_count] != dec_buffer[dec_index - offset + offset_count])
       	 {
          if(offset_count >= max_count)
          {
         	 max_index = offset;
         	 max_count = offset_count;
         	 found = true;
          }
          break;
       	 }
        }
     	 }
    
     	 if(found)
     	 {
        offset = max_index;
        offset_count = max_count - 1;
    
        if(offset < 0x100 && offset_count < min_length + 4)
        {
       	 offset ^= 0xFF;
       	 return(PRS_MODE_OFFSETCPY);
        }
        else
        {
       	 offset ^= 0xFFFF;
       	 return(PRS_MODE_EXTENDCPY);
        }
     	 }
      }
    	}
    
    	return(mode & PRS_MODE_STORAGE);
    }
    
    bool prs::read_cmp_file(const char *filename)
    {
    	std::fstream cmp_file;
    
    	cmp_file.open(filename, std::ios::in | std::ios::binary);
    	if(!cmp_file.good())
      return(false);
    
    	delete_cmp_buffer();
    
    	cmp_file.seekg(0, std::ios::end);
    	cmp_size = cmp_file.tellg();
    	cmp_file.seekg(0, std::ios::beg);
    
    	cmp_buffer = new byte[cmp_size];
    	cmp_file.read((char *)cmp_buffer, cmp_size);
    	cmp_file.close();
    
    	decompressed = false;
    	return(compressed = true);
    }
    bool prs::read_dec_file(const char *filename)
    {
    	std::fstream dec_file;
    
    	dec_file.open(filename, std::ios::in | std::ios::binary);
    	if(!dec_file.good())
      return(false);
    
    	delete_dec_buffer();
    
    	dec_file.seekg(0, std::ios::end);
    	dec_size = dec_file.tellg();
    	dec_file.seekg(0, std::ios::beg);
    
    	dec_buffer = new byte[dec_size];
    	dec_file.read((char *)dec_buffer, dec_size);
    	dec_file.close();
    
    	compressed = false;
    	return(decompressed = true);
    }
    
    void prs::read_cmp_buffer(const byte *new_buffer, const dword new_size)
    {
    	delete_cmp_buffer();
    	cmp_buffer = new byte[cmp_size = new_size];
    	memcpy(cmp_buffer, new_buffer, new_size);
    
    	cmp_index = 0;
    	compressed = true;
    	decompressed = false;
    }
    void prs::read_dec_buffer(const byte *new_buffer, const dword new_size)
    {
    	delete_dec_buffer();
    	dec_buffer = new byte[dec_size = new_size];
    	memcpy(dec_buffer, new_buffer, new_size);
    
    	dec_index = 0;
    	compressed = false;
    	decompressed = true;
    }
    
    bool prs::write_cmp_file(const char *filename)
    {
    	std::fstream cmp_file;
    
    	if(!compress())
      return(false);
    
    	cmp_file.open(filename, std::ios::out | std::ios::binary);
    	if(!cmp_file.good())
      return(false);
    
    	cmp_file.write((char *)cmp_buffer, cmp_size);
    	cmp_file.close();
    	return(true);
    }
    bool prs::write_dec_file(const char *filename)
    {
    	std::fstream dec_file;
    
    	if(!decompress())
      return(false);
    
    	dec_file.open(filename, std::ios::out | std::ios::binary);
    	if(!dec_file.good())
      return(false);
    
    	dec_file.write((char *)dec_buffer, dec_size);
    	dec_file.close();
    
    	return(true);
    }
    
    void prs::write_cmp_buffer(byte *new_buffer)
    {
    	if(compress())
      memcpy(new_buffer, cmp_buffer, cmp_size);
    }
    void prs::write_dec_buffer(byte *new_buffer)
    {
    	if(decompress())
      memcpy(new_buffer, dec_buffer, dec_size);
    }
    
    dword prs::get_cmp_size(void)
    {
    	if(compress())
      return(cmp_size);
    	return(0);
    }
    dword prs::get_dec_size(void)
    {
    	if(decompress())
      return(dec_size);
    	return(0);
    }
    
    #endif // __PRS__
    


    Also, this is the .ONE file class that I created around the .PRS class. This can be used for Sonic Heroes PC, obviously =P A few .ONE files use a slightly different format, but this supports most of them.

    /*
                    .ONE file handling class written by Lightning.
          For use with Sonic Heroes' and any other applicable games' archives.
    
                   Many thanks go to Nemesis; without him, the .PRS
                 aspects of this program wouldn't have been possible.
    */
    
    // 11/12/2005 - Released alongside the buggy PRS class
    // 10/15/2005 - Added delete_this_buffer() functions for garbage collection
    // 10/14/2005 - Added a call to int mkdir(char*) in bool extract_archive(char*)
    // 10/12/2005 - Fixed a minor design flaw involving buffer sizes
    // 10/03/2005 - First private release
    
    #ifndef __ONE__
    #define __ONE__
    
    #include <fstream>
    
    #ifndef WIN32
    
    #include <unistd.h>
    #include <sys/types.h>
    #include <sys/stat.h>
    
    #ifndef _DIR_SLASH_CHAR
    #define _DIR_SLASH_CHAR "/"
    #endif
    
    #else
    
    #include <direct.h>
    
    #ifndef _DIR_SLASH_CHAR
    #define _DIR_SLASH_CHAR "\\"
    #endif
    
    #endif
    
    #include "prs.h"
    
    #define RW_VERSION 0x1400FFFF
    
    class one
    {
    private:
    	struct one_entry
    	{
      dword number;
      dword size;
      dword version;
    	} entry;
    
    	std::fstream one_file;
    	char *one_filename;
    	prs prs_data;
    
    	dword size;
    	dword version;
    
    	byte *file_buffer;
    	char *string_table;
    	dword string_entries;
    public:
    	one(void);
    	one(const char *filename);
    	~one(void);
    	void delete_file_buffer(void);
    	void delete_string_table(void);
    	void delete_one_filename(void);
    private:
    	void read_entry(void);
    	void write_entry(void);
    public:
    	bool open_file(const char *filename);
    	void close_file(void);
    
    	dword get_index(const char *entryname);
    	char *get_entryname(dword index);
    	char *get_entrynames(void);
    	dword get_offset(dword index);
    	dword get_offset(const char *entryname);
    	dword get_size(dword index);
    	dword get_size(const char *entryname);
    	char *get_filename(void);
    
    	bool extract_file(dword index, const char *filename);
    	bool extract_file(const char *entryname, const char *filename);
    	void extract_buffer(dword index, byte *buffer);
    	void extract_buffer(const char *entryname, byte *buffer);
    	bool extract_archive(void);
    	bool extract_archive(const char *directory);
    
    	bool create_archive(const char *onename, const char *listname);
    };
    
    one::one(void)
    {
    }
    one::one(const char *filename)
    {
        open_file(filename);
    }
    one::~one(void)
    {
    	if(one_file.is_open())
      one_file.close();
    }
    void one::delete_file_buffer(void)
    {
    	if(!file_buffer)
      delete(file_buffer);
    }
    void one::delete_string_table(void)
    {
    	if(!string_table)
      delete(string_table);
    }
    void one::delete_one_filename(void)
    {
    	if(!one_filename)
      delete(one_filename);
    }
    
    void one::read_entry(void)
    {
    	one_file.read((char *)&entry, sizeof(entry));
    }
    void one::write_entry(void)
    {
    	one_file.write((char *)&entry, sizeof(entry));
    }
    
    bool one::open_file(const char *filename)
    {
    	close_file();
    
    	char *temp = new char[strlen(filename) + 2];
    	strcpy(temp + 2, filename);
    	if(!(temp[2] == '.' || temp[3] == ':'))
      memcpy(temp, "."_DIR_SLASH_CHAR, 2);
    	else
      temp += 2;
    
    	one_file.open(temp, std::ios::in | std::ios::out | std::ios::binary);
    	if(!one_file.good())
      return(false);
    
    	read_entry();
    	if(!entry.number)
      size = entry.size + sizeof(one_entry);
    	else
    	{
      one_file.seekg(0, std::ios::end);
      size = one_file.tellg();
      one_file.seekg(0, std::ios::beg);
    	}
    
    	version = entry.version;
    	read_entry();
    
    	delete_string_table();
    	string_table = new char[entry.size];
    	string_entries = entry.size >> 6;
    	one_file.read(string_table, entry.size);
    
    	one_filename = temp;
    
    	return(true);
    }
    void one::close_file(void)
    {
    	if(one_file.is_open())
      one_file.close();
    }
    
    dword one::get_index(const char *entryname)
    {
    	for(register dword I = 0; I < string_entries; I++)
      if(!strcmp(string_table + (I << 6), entryname))
     	 return(I);
    
    	return(0);
    }
    char *one::get_entryname(dword index)
    {
    	char *temp = new char[0x40];
    
    	strcpy(temp, string_table + (index << 6));
    
    	if(!*temp)
      if(index == 0)
     	 temp = "one_file.dat";
      else if(index == 1)
     	 temp = "string_table.dat";
    
    	return(temp);
    }
    char *one::get_entrynames(void)
    {
    	char *temp = new char[string_entries << 6];
    	*temp = '\0';
    
    	for(register dword I = 2; *get_entryname(I); I++)
    	{
      strcat(temp, get_entryname(I));
      strcat(temp, "\n");
    	}
    
    	return(temp);
    }
    dword one::get_offset(dword index)
    {
    	one_file.seekg(sizeof(one_entry), std::ios::beg);
    
    	while((dword)one_file.tellg() < size)
    	{
      read_entry();
      if(entry.number == index)
     	 return(one_file.tellg());
    
      one_file.seekg(entry.size, std::ios::cur);
    	}
    
    	one_file.seekg(0, std::ios::beg);
    	read_entry();
    
    	return(one_file.tellg());
    }
    dword one::get_offset(const char *entryname)
    {
    	return(get_offset(get_index(entryname)));
    }
    dword one::get_size(dword index)
    {
    	get_offset(index);
    
    	delete_file_buffer();
    	file_buffer = new byte[entry.size];
    
    	one_file.read((char *)file_buffer, entry.size);
    	prs_data.read_cmp_buffer(file_buffer, entry.size);
    
    	return(prs_data.get_dec_size());
    }
    dword one::get_size(const char *entryname)
    {
    	return(get_size(get_index(entryname)));
    }
    char *one::get_filename(void)
    {
    	return(one_filename);
    }
    
    bool one::extract_file(dword index, const char *filename)
    {
    	get_offset(index);
    
    	delete_file_buffer();
    	file_buffer = new byte[entry.size];
    
    	one_file.read((char *)file_buffer, entry.size);
    	prs_data.read_cmp_buffer(file_buffer, entry.size);
    
    	return(prs_data.write_dec_file(filename));
    }
    bool one::extract_file(const char *entryname, const char *filename)
    {
    	return(extract_file(get_index(entryname), filename));
    }
    void one::extract_buffer(dword index, byte *buffer)
    {
    	get_offset(index);
    
    	delete_file_buffer();
    	file_buffer = new byte[entry.size];
    
    	one_file.read((char *)file_buffer, entry.size);
    	prs_data.read_cmp_buffer(file_buffer, entry.size);
    
    	prs_data.write_dec_buffer(buffer);
    }
    void one::extract_buffer(const char *entryname, byte *buffer)
    {
    	extract_buffer(get_index(entryname), buffer);
    }
    bool one::extract_archive(void)
    {
    	for(register dword I = 2; *get_entryname(I); I++)
      if(!extract_file(I, get_entryname(I)))
     	 return(false);
    
    	return(true);
    }
    bool one::extract_archive(const char *directory)
    {
    	mkdir(directory);
    
    	char *temp = new char[strlen(directory) + 0x48];
    	char *end;
    
    	strcpy(temp, directory);
    	if(strrchr(temp, *_DIR_SLASH_CHAR) - temp != strlen(temp) - 1)
      strcat(temp, _DIR_SLASH_CHAR);
    
    	end = strrchr(temp, *_DIR_SLASH_CHAR) + 1;
    	for(register dword I = 2; *get_entryname(I); I++)
    	{
      memset(end + 1, '\0', 0x46);
      strcpy(end, get_entryname(I));
    
      if(!extract_file(I, temp))
     	 return(false);
    	}
    	delete(temp);
    
    	return(true);
    }
    
    bool one::create_archive(const char *onename, const char *listname)
    {
    	std::fstream list_file;
    	dword list_size;
    	dword entries = 2;
    	register dword I;
    	char list_strings[0x100][0x400];
    	char *temp;
    
    	close_file();
    	one_file.open(onename, std::ios::in | std::ios::out | std::ios::binary);
    	list_file.open(listname, std::ios::in);
    	list_file.seekg(0, std::ios::end);
    	list_size = list_file.tellg();
    	list_file.seekg(0, std::ios::beg);
    
    	entry.version = version = RW_VERSION;
    	entry.number = 0;
    	entry.size = 0x7FFFFFFF;
    	write_entry();
    
    	entry.number++;
    	entry.size = 0x4000;
    	write_entry();
    
    	for(I = 0; I < 0x100; I++)
      memset(list_strings[I], '\0', 0x400);
    
    	while(list_file.tellg() < list_size - 1)
      list_file.getline(list_strings[entries++], 0x400);
    
    	list_file.close();
    
    	delete_string_table();
    	string_table = new char[0x4000];
    	memset(string_table, '\0', 0x4000);
    
    	for(I = 2; I < 0x100; I++)
      if(temp = strrchr(list_strings[I], '\\'))
     	 strcpy(string_table + (I << 6), ++temp);
      else
     	 strcpy(string_table + (I << 6), list_strings[I]);
    	one_file.write(string_table, 0x4000);
    
    	for(entry.number = 2; entry.number < entries; entry.number++)
    	{
      if(!prs_data.read_dec_file(list_strings[entry.number]))
     	 return(false);
      if(!prs_data.compress())
     	 return(false);
    
      entry.size = prs_data.get_cmp_size();
      write_entry();
    
      delete_file_buffer();
      file_buffer = new byte[entry.size];
    
      prs_data.write_cmp_buffer(file_buffer);
      one_file.write((char *)file_buffer, entry.size);
    	}
    
    	entry.number = 0;
    	entry.size = size = (dword)one_file.tellp() - sizeof(one_entry);
    	one_file.seekp(0, std::ios::beg);
    	write_entry();
    
    	delete_one_filename();
    	one_filename = new char[strlen(onename)];
    	strcpy(one_filename, onename);
    	return(true);
    }
    
    #endif // __ONE__
    


    Finally, here's a simple program that uses these classes to make a simple command-line .ONE archive tool.

    #include <iostream>
    #include "one.h"
    
    using namespace std;
    
    const char *_ARG_FILENAME = "--filename";
    const char *_ARG_EXTRACT = "--extract";
    const char *_ARG_CREATE = "--create";
    
    #ifndef _DIR_SLASH_CHAR
    #ifndef WIN32
    #define _DIR_SLASH_CHAR "/"
    #else
    #define _DIR_SLASH_CHAR "\\"
    #endif
    #endif
    
    char *get_parameter(int argc, char *argv[], const char *parameter);
    
    int main(int argc, char *argv[])
    {
    	one one_file;
    	char *filename;
    	char *temp;
    
    	if(filename = get_parameter(argc, argv, _ARG_FILENAME))
    	{
      if(temp = get_parameter(argc, argv, _ARG_EXTRACT))
      {
     	 if(!one_file.open_file(filename))
        return(1);
     	 if(!one_file.extract_archive(temp))
        return(1);
      }
      else if(temp = get_parameter(argc, argv, _ARG_CREATE))
      {
     	 if(!one_file.create_archive(filename, temp))
        return(1);
      }
      else
      {
     	 if(!one_file.open_file(filename))
        return(1);
     	 cout << one_file.get_entrynames();
      }
      one_file.close_file();
    	}
    	else
    	{
      if(strrchr(argv[0], *_DIR_SLASH_CHAR))
     	 argv[0] = strrchr(argv[0], *_DIR_SLASH_CHAR) + 1;
      cout
     	 << "Usage:"	<< "\n\t"
     	 << argv[0]	<< "\n\t"
     	 << "   "	<< _ARG_FILENAME	<< " <file.one>"	<< "  "	<< "\n\t"
     	 << " [ "	<< _ARG_EXTRACT  << " <directory>"	<< " ]"	<< "\n\t"
     	 << " [ "	<< _ARG_CREATE 	 << " <list.txt>"	<< " ]"	<< "\n\t"
     	 << endl;
      return(0);
    	}
    	return(0);
    }
    


    So, erm, any ideas? I didn't really put many comments in the program, but I tried to make the code easy to understand. Any suggestions are welcome, of course =P
  4. EDIT: Sonic Gems stuff

    26 August 2005 - 09:06 PM

    Download / Mirror
    Found this whilst doing some RAM dumps of Sonic Gems. The Genesis ROM is loaded into 0x8101B280, by the way =P All the other games are normal copies of known ROMs.
    EDIT: Turned out to just be Sonic the Hedgehog 2 (W) [!].bin with a byte or two different. =\

    As a side note, I loaded Crackers into the Gamecube's RAM and it worked like a charm =P Unfortunately, the same can't be said about our Sonic 2 Beta... It runs fine, but all it produces in the way of sound is screeching.
  5. Sonic Heroes team mixups

    13 December 2004 - 09:52 PM

    Right, I'll just post what I wrote at SCARZ...

    Quote

    Posted Image
    Posted Image
    Posted Image
    Posted Image

    The Shadow in Team Sonic one was just something I did out of boredom hacking around with the .ONE files' table of contents, then I looked at the format a little more and saw it was just .PRS clumped together, and made a few utilities for the format (making the rest incredibly easy).  First hacks I've seen of their kind, so I figured I'd post them  =P

    They can be downloaded here:
    http://lightning.cjb...ash/SHPC%20Hax/
    The tools I made for .ONE are here:
    http://lightning.cjb...ngSHPCTools.rar

    To use the unpacker, run it from the command line with all the .ONEs you want to unpack after it (or drag and drop all the files onto the program's icon).  The repacker works in a similar way, but overwrites the files given to it as arguments (so you may want to make backups.  It keeps the table of contents there though, and it can fix files it breaks anyway).  If there's an error, it complains about not being able to get a .PRS file, and the one it couldn't get is the last in the list it gives.  Not too hard to use.  =P

    What I did for most of the hacks was extract all the .PRSes from the two characters' .ONE files (_anm and _dff), rename those from the one I want to replace the other with to match the other's filenames (this can be done really easily by doing a simple "ren SH_* SN_*" in DOS), fix a few of the things different about the filenames (Because Sonic Team is oh so consistent  e_e), and make a few copies and replacements to make up for models and animations one has that the other doesn't, and repack the .ONEs of the character I want to replace.  Then I copied the texture file and renamed it (easy part).  Sometimes it works, others it freezes.  Tails is a bitch to replace in my own experience  =P
    Also, let it be noted that two of those hacks are my friend Mike's after I showed him how and gave him the tools  =P

    Overall, it was easier than I thought it would be.  Now if I could just get a license for those Renderware exporter plugins..  ;_;

    Well have fun.  =P

Friends

Lightning hasn't added any friends yet.