From 1d7a13e2c58c397ca54a4a1f3db93f8f80d76e76 Mon Sep 17 00:00:00 2001 From: Correl Roush Date: Tue, 10 Aug 2010 09:40:01 -0400 Subject: [PATCH] Initial commit --- Makefile | 8 + Makefile.mingw | 8 + blocks.cpp | 33 + blocks.h | 40 + build.mak | 43 + config.mak | 4 + db | 1 + frames.cpp | 75 + frames.h | 60 + icon.cpp | 80 + icon.h | 27 + memcard.cpp | 120 + memcard.h | 28 + psxicontool.cpp | 92 + psxicontool.h | 81 + qt-gui/BA.png | Bin 0 -> 252 bytes qt-gui/BE.png | Bin 0 -> 284 bytes qt-gui/BJ.png | Bin 0 -> 248 bytes qt-gui/main.cpp | 50 + qt-gui/psxicon.cpp | 31 + qt-gui/psxicon.h | 12 + qt-gui/psxmemcard.cpp | 108 + qt-gui/psxmemcard.h | 18 + qt-gui/psxsavewidget.cpp | 39 + qt-gui/psxsavewidget.h | 18 + qt-gui/qt-gui.pro | 13 + qt-test-cli/db | 1 + qt-test-cli/main.cpp | 97 + qt-test-cli/qt.pro | 14 + test.cpp | 84 + testdata/ALUNDRA2 FILE1 Cabin.mcs | Bin 0 -> 8320 bytes testdata/CHRONO CROSS 01.mcs | Bin 0 -> 8320 bytes testdata/CHRONO CROSS 02.mcs | Bin 0 -> 8320 bytes testdata/CHRONO CROSS 03.mcs | Bin 0 -> 8320 bytes testdata/CHRONO CROSS 04.mcs | Bin 0 -> 8320 bytes testdata/CHRONO CROSS 05.mcs | Bin 0 -> 8320 bytes testdata/CHRONO CROSS 06.mcs | Bin 0 -> 8320 bytes testdata/CHRONO CROSS 07.mcs | Bin 0 -> 8320 bytes testdata/CHRONO CROSS 08.mcs | Bin 0 -> 8320 bytes testdata/CHRONO CROSS 09.mcs | Bin 0 -> 8320 bytes testdata/DW7 01 Phoe L01 0 00.mcs | Bin 0 -> 8320 bytes testdata/FF7 SAVE01 64 05.mcs | Bin 0 -> 8320 bytes testdata/FF7 SAVE01 64 23.mcs | Bin 0 -> 8320 bytes testdata/FF7 SAVE02 32 17.mcs | Bin 0 -> 8320 bytes testdata/FF7 SAVE02 47 20.mcs | Bin 0 -> 8320 bytes testdata/FF7 SAVE03 65 03.mcs | Bin 0 -> 8320 bytes testdata/FF8 01 14 05.mcs | Bin 0 -> 8320 bytes testdata/FF9 FILE01 14 01.mcs | Bin 0 -> 8320 bytes testdata/FF9 FILE06 58 04.mcs | Bin 0 -> 8320 bytes testdata/FFT FILE01 02 28 48.mcs | Bin 0 -> 8320 bytes testdata/FFT FILE01 13 01 48.mcs | Bin 0 -> 8320 bytes testdata/GRANDIA 1 Gadwin s House 272 07.mcs | Bin 0 -> 8320 bytes testdata/Intelligent Qube.mcs | Bin 0 -> 8320 bytes testdata/Legend of Legaia 01 Time 09 53.mcs | Bin 0 -> 8320 bytes testdata/MGS EZ 01 40 U Grnd Pssge.mcs | Bin 0 -> 8320 bytes testdata/MGS EZ 04 45 Spply Rte.mcs | Bin 0 -> 8320 bytes testdata/MGS NM 00 29 Cell.mcs | Bin 0 -> 8320 bytes testdata/MGS NM 08 21 U Grnd Base 3.mcs | Bin 0 -> 8320 bytes testdata/MGS VR Training Data.mcs | Bin 0 -> 8320 bytes testdata/Saiyuki01 Lv23 Ch 2 19 43 Map.mcs | Bin 0 -> 8320 bytes testdata/Saiyuki02 Lv25 Ch 2 20 53 In B.mcs | Bin 0 -> 8320 bytes testdata/Saiyuki03 Lv26 Ch 2 21 05 In B.mcs | Bin 0 -> 8320 bytes testdata/THE KING OF FIGHTERS 99.mcs | Bin 0 -> 8320 bytes testdata/VALKYRIE PROFILE No 1 LV 18.mcs | Bin 0 -> 16512 bytes testdata/WO3 CFG.mcs | Bin 0 -> 8320 bytes testdata/WO3 Venom PortKr Pirna 1 45 06.mcs | Bin 0 -> 16512 bytes testdata/Wild Arms FILE01 LV13.mcs | Bin 0 -> 8320 bytes testdata/Wild Arms FILE01 LV14.mcs | Bin 0 -> 8320 bytes testdata/db | 10107 ++++++++++++++++ testdata/dbase.ps1 | 10110 +++++++++++++++++ testdata/epsxe000.mcr | Bin 0 -> 131072 bytes testdata/ff7.mcs | Bin 0 -> 8320 bytes 72 files changed, 21402 insertions(+) create mode 100644 Makefile create mode 100644 Makefile.mingw create mode 100644 blocks.cpp create mode 100644 blocks.h create mode 100644 build.mak create mode 100644 config.mak create mode 120000 db create mode 100644 frames.cpp create mode 100644 frames.h create mode 100644 icon.cpp create mode 100644 icon.h create mode 100644 memcard.cpp create mode 100644 memcard.h create mode 100644 psxicontool.cpp create mode 100644 psxicontool.h create mode 100644 qt-gui/BA.png create mode 100644 qt-gui/BE.png create mode 100644 qt-gui/BJ.png create mode 100644 qt-gui/main.cpp create mode 100644 qt-gui/psxicon.cpp create mode 100644 qt-gui/psxicon.h create mode 100644 qt-gui/psxmemcard.cpp create mode 100644 qt-gui/psxmemcard.h create mode 100644 qt-gui/psxsavewidget.cpp create mode 100644 qt-gui/psxsavewidget.h create mode 100644 qt-gui/qt-gui.pro create mode 120000 qt-test-cli/db create mode 100644 qt-test-cli/main.cpp create mode 100644 qt-test-cli/qt.pro create mode 100644 test.cpp create mode 100644 testdata/ALUNDRA2 FILE1 Cabin.mcs create mode 100644 testdata/CHRONO CROSS 01.mcs create mode 100644 testdata/CHRONO CROSS 02.mcs create mode 100644 testdata/CHRONO CROSS 03.mcs create mode 100644 testdata/CHRONO CROSS 04.mcs create mode 100644 testdata/CHRONO CROSS 05.mcs create mode 100644 testdata/CHRONO CROSS 06.mcs create mode 100644 testdata/CHRONO CROSS 07.mcs create mode 100644 testdata/CHRONO CROSS 08.mcs create mode 100644 testdata/CHRONO CROSS 09.mcs create mode 100755 testdata/DW7 01 Phoe L01 0 00.mcs create mode 100755 testdata/FF7 SAVE01 64 05.mcs create mode 100644 testdata/FF7 SAVE01 64 23.mcs create mode 100644 testdata/FF7 SAVE02 32 17.mcs create mode 100755 testdata/FF7 SAVE02 47 20.mcs create mode 100755 testdata/FF7 SAVE03 65 03.mcs create mode 100644 testdata/FF8 01 14 05.mcs create mode 100755 testdata/FF9 FILE01 14 01.mcs create mode 100755 testdata/FF9 FILE06 58 04.mcs create mode 100755 testdata/FFT FILE01 02 28 48.mcs create mode 100755 testdata/FFT FILE01 13 01 48.mcs create mode 100644 testdata/GRANDIA 1 Gadwin s House 272 07.mcs create mode 100755 testdata/Intelligent Qube.mcs create mode 100755 testdata/Legend of Legaia 01 Time 09 53.mcs create mode 100755 testdata/MGS EZ 01 40 U Grnd Pssge.mcs create mode 100755 testdata/MGS EZ 04 45 Spply Rte.mcs create mode 100755 testdata/MGS NM 00 29 Cell.mcs create mode 100755 testdata/MGS NM 08 21 U Grnd Base 3.mcs create mode 100755 testdata/MGS VR Training Data.mcs create mode 100755 testdata/Saiyuki01 Lv23 Ch 2 19 43 Map.mcs create mode 100755 testdata/Saiyuki02 Lv25 Ch 2 20 53 In B.mcs create mode 100755 testdata/Saiyuki03 Lv26 Ch 2 21 05 In B.mcs create mode 100755 testdata/THE KING OF FIGHTERS 99.mcs create mode 100755 testdata/VALKYRIE PROFILE No 1 LV 18.mcs create mode 100755 testdata/WO3 CFG.mcs create mode 100755 testdata/WO3 Venom PortKr Pirna 1 45 06.mcs create mode 100755 testdata/Wild Arms FILE01 LV13.mcs create mode 100755 testdata/Wild Arms FILE01 LV14.mcs create mode 100644 testdata/db create mode 100644 testdata/dbase.ps1 create mode 100755 testdata/epsxe000.mcr create mode 100755 testdata/ff7.mcs diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..8e8ef0a --- /dev/null +++ b/Makefile @@ -0,0 +1,8 @@ +include config.mak + +OUTPUT = $(PROG) +CC = g++ +LD = $(CC) +AR = ar + +include build.mak diff --git a/Makefile.mingw b/Makefile.mingw new file mode 100644 index 0000000..3f4fc01 --- /dev/null +++ b/Makefile.mingw @@ -0,0 +1,8 @@ +include config.mak + +OUTPUT = $(PROG).exe +CC = /opt/cross/bin/i386-mingw32msvc-g++ +LD = $(CC) +AR = /opt/cross/bin/i386-mingw32msvc-ar + +include build.mak diff --git a/blocks.cpp b/blocks.cpp new file mode 100644 index 0000000..a183aa2 --- /dev/null +++ b/blocks.cpp @@ -0,0 +1,33 @@ +#include "blocks.h" +#include + +Frame* Block::getFrame( int index ) { return index >= 0 && index < 64 ? &frames[index] : 0; } + +IdentificationFrame* DirectoryBlock::IDFrame() { return (IdentificationFrame*)&frames[0]; } +DirectoryFrame* DirectoryBlock::Directory( int index ) { return index < 15 && index >= 0 ? (DirectoryFrame*)&frames[index + 1] : 0; } +void DirectoryBlock::Directory( int index, DirectoryFrame *frame ) { memcpy( &frames[index], frame, sizeof( DirectoryFrame ) ); } +Frame* DirectoryBlock::Reserved( int index ) { return index < 20 && index >= 0 ? &frames[index + 16] : 0; } +Frame* DirectoryBlock::Unused( int index ) { return index < 27 && index >= 0 ? &frames[index + 36] : 0; } +Frame* DirectoryBlock::WriteTest() { return &frames[63]; } +int DirectoryBlock::nextOpenBlock() { + for( int i = 0; i < 15; i++ ) { + int type = Directory( i )->blockType(); + if( type >= 160 && type <= 163 ) { return i + 1; } + } + return 0; +} +SaveHeaderFrame* InitialBlock::Header() { return (SaveHeaderFrame*)&frames[0]; } +Icon* InitialBlock::getIcon( int index ) { + //return index < 3 && index >= 0 ? &frames[index + 1] : 0; + SaveHeaderFrame *header = Header(); + IconFrame *frame = (IconFrame*)&frames[index + 1]; + Icon *icon = new Icon(); + for( int y = 0; y < 16; y++ ) { + icon->paletteColor( y, header->paletteColor( y ) ); + for( int x = 0; x < 16; x++ ) { + icon->pixel( x, y, frame->colorAt( x, y ) ); + } + } + return icon; +} + diff --git a/blocks.h b/blocks.h new file mode 100644 index 0000000..82771c6 --- /dev/null +++ b/blocks.h @@ -0,0 +1,40 @@ +#ifndef BLOCKS_H +#define BLOCKS_H + +#include "frames.h" + +class Block { + protected: + Frame frames[64]; + public: + Frame* getFrame( int index ); + enum blockType { + PSX_BLOCK_INITIAL = 81, + PSX_BLOCK_MEDIAL = 82, + PSX_BLOCK_FINAL = 83, + PSX_BLOCK_FORMATTED = 160, + PSX_BLOCK_DELETED_INITIAL = 161, + PSX_BLOCK_DELETED_MEDIAL = 162, + PSX_BLOCK_DELETED_FINAL = 163, + PSX_BLOCK_RESERVED = 0xFFFFFFFF + }; +}; + +class DirectoryBlock : protected Block { + public: + IdentificationFrame* IDFrame(); + DirectoryFrame* Directory( int index ); + void Directory( int index, DirectoryFrame *frame ); + Frame* Reserved( int index ); + Frame* Unused( int index ); + Frame* WriteTest(); + int nextOpenBlock(); +}; + +class InitialBlock : protected Block { + public: + SaveHeaderFrame* Header(); + Icon* getIcon( int index ); +}; + +#endif // BLOCKS_H diff --git a/build.mak b/build.mak new file mode 100644 index 0000000..0697bab --- /dev/null +++ b/build.mak @@ -0,0 +1,43 @@ +CFLAGS = -g -Wall +LDFLAGS = -L. + +LIBVERSIONMAJOR = 0 +LIBVERSIONMINOR = 0.1 + +OBJS = blocks.o \ + frames.o \ + memcard.o \ + icon.o + +.PHONY: clean lib-static static lib-shared shared qtdir + +all: clean static +qt: clean lib-shared qtdir + +qtdir: + make -C qt-test-cli clean all + +clean: + rm -f *.o *.a *.so* $(OUTPUT) + +lib-static: $(OBJS) + $(AR) rcs lib$(LIB).a $(OBJS) + +lib-shared: $(OBJS) +ifeq ($(CC),g++) + $(LD) -shared -Wl,-soname,lib$(LIB).so.$(LIBVERSIONMAJOR) -o lib$(LIB).so.$(LIBVERSIONMAJOR).$(LIBVERSIONMINOR) $(OBJS) + ln -fs lib$(LIB).so.$(LIBVERSIONMAJOR).$(LIBVERSIONMINOR) lib$(LIB).so.$(LIBVERSIONMAJOR) + ln -fs lib$(LIB).so.$(LIBVERSIONMAJOR).$(LIBVERSIONMINOR) lib$(LIB).so +else + $(LD) -shared -Wl,-soname,lib$(LIB).so.$(LIBVERSIONMAJOR) -o lib$(LIB).dll $(OBJS) +endif + +static: lib-static + $(LD) $(LDFLAGS) -static $(PROG).cpp -l$(LIB) -o $(OUTPUT) + +shared: lib-shared $(PROG).o + $(LD) $(LDFLAGS) -l$(LIB) $(PROG).o -o $(OUTPUT) + +%.o: %.cpp + $(CC) $(CFLAGS) -c $< + diff --git a/config.mak b/config.mak new file mode 100644 index 0000000..fb0fec8 --- /dev/null +++ b/config.mak @@ -0,0 +1,4 @@ +PROG = test +LIB = psxsave +LIBVERSIONMAJOR = 0 +LIBVERSIONMINOR = 0.1 diff --git a/db b/db new file mode 120000 index 0000000..fac75c1 --- /dev/null +++ b/db @@ -0,0 +1 @@ +testdata/db \ No newline at end of file diff --git a/frames.cpp b/frames.cpp new file mode 100644 index 0000000..6a9bf10 --- /dev/null +++ b/frames.cpp @@ -0,0 +1,75 @@ +#include "frames.h" +#include + +char* Frame::getString( int offset, int length ) { + char* data = new char[length]; + strncpy( data, &bytes[offset], length ); + data[length] = 0; // Properly terminate the returned string + return data; +} + +int Frame::getInt32( int offset ) { + return *reinterpret_cast( &bytes[offset] ); +} +int Frame::getInt16( int offset ) { + return *reinterpret_cast( &bytes[offset] ); +} +void Frame::putInt32( int offset, int value ) { + for( int i = 0; i < 4; i++ ) { + bytes[offset + i] = ( value & ( 0xFF << ( 8 * i ) ) ) >> ( 8 * i ); + } +} +void Frame::putInt16( int offset, int value ) { + for( int i = 0; i < 2; i++ ) { + bytes[offset + i] = ( value & ( 0xFF << ( 8 * i ) ) ) >> ( 8 * i ); + } +} +void Frame::putString( int offset, char* value, int maxLen ) { + maxLen = maxLen < 0 ? strlen( value ) : 0; + maxLen = (unsigned int)maxLen > strlen( value ) ? strlen( value ) : 0; + strncpy( &bytes[offset], value, maxLen ); + //bytes[offset+maxLen] = 0; +} +void Frame::putChar( int offset, char value ) { + bytes[offset] = value; +} + +bool XORFrame::getXOR() { + char x = 0; + for( int i = 0; i < 128; i++ ) x ^= bytes[i]; + if( x == 0 ) return true; + return false; +} + +void XORFrame::setXOR() { + char x = 0; + for( int i = 0; i < 127; i++ ) x ^= bytes[i]; + bytes[127] = x; +} + +bool IdentificationFrame::isValid() { + if( strcmp( id(), "MC" ) == 0 ) { + return true; + } else { + return false; + } +} + +RGB SaveHeaderFrame::paletteColor( int index ) { + index = index < 0 || index >= 16 ? 0 : index; + char triplet[2] = { bytes[0x60 + ( index * 2 )], bytes[0x60 + ( index * 2 + 1 )] }; + RGB color; + color.r = ( triplet[0] & 31 ) << 3; + color.g = ( ( triplet[0] & 224 ) >> 2 ) + ( ( triplet[1] & 3 ) << 6 ); + color.b = ( triplet[1] & 124 ) << 1; + return color; +} + +int IconFrame::colorAt( int x, int y ) { + int offset = x / 2; + if( x % 2 == 0 ) { + return bytes[(y*8)+offset] & 15; + } else { + return ( bytes[(y*8)+offset] & 240 ) >> 4; + } +} diff --git a/frames.h b/frames.h new file mode 100644 index 0000000..c57bd12 --- /dev/null +++ b/frames.h @@ -0,0 +1,60 @@ +#ifndef FRAMES_H +#define FRAMES_H + +#include "icon.h" + +class Frame { + protected: + char bytes[128]; + public: + char* getData( int offset ) { return &bytes[offset]; } + char* getString( int offset, int length ); + int getInt32( int offset ); + int getInt16( int offset ); + void putInt32( int offset, int value ); + void putInt16( int offset, int value ); + void putString( int offset, char* value, int maxLen = -1 ); + void putChar( int offset, char value ); +}; + +class XORFrame : protected Frame { + public: + bool getXOR(); + void setXOR(); +}; + +class IdentificationFrame : public XORFrame { + public: + // I might put a byte-for-byte check here for safety and completeness, but the XOR is fine for now. + char* id() { return getString( 0x00, 2 ); } + bool isValid(); +}; + +class DirectoryFrame : public XORFrame { + public: + int blockType() { return getInt32( 0x00 ); } + void blockType( int value ) { putInt32( 0x00, value ); } + int size() { return getInt32( 0x04 ); } + void size( int size ) { putInt32( 0x04, size ); } + int nextBlock() { return getInt16( 0x08 ); } + char* territoryCode() { return getString( 0x0A, 2 ); } + char* licenseCode() { return getString( 0x0C, 10 ); } + char* saveCode() { return getString( 0x16, 8 ); } + +}; + +class SaveHeaderFrame : protected Frame { + public: + char* magicNumber() { return getString( 0x00, 2 ); } + int iconDisplayType() { return bytes[0x02]; } + int blocksUsed() { return bytes[0x03]; } + char* SJISSaveTitle() { return getString( 0x04, 64 ); } + RGB paletteColor( int index ); +}; + +class IconFrame : protected Frame { + public: + int colorAt( int x, int y ); +}; + +#endif // FRAMES_H diff --git a/icon.cpp b/icon.cpp new file mode 100644 index 0000000..7607ded --- /dev/null +++ b/icon.cpp @@ -0,0 +1,80 @@ +#include "icon.h" +#include + +using namespace std; + +Icon::Icon() { + for( int x = 0; x < 16; x++ ) { + palette[x] = RGB(); + for( int y = 0; y < 16; y++ ) { + pixels[x][y] = 0; + } + } +} + +int Icon::pixel( int x, int y ) { + x = x < 0 || x >= 16 ? 0 : x; + y = y < 0 || y >= 16 ? 0 : y; + return pixels[x][y]; +} + +RGB Icon::pixelRGB( int x, int y ) { + x = x < 0 || x >= 16 ? 0 : x; + y = y < 0 || y >= 16 ? 0 : y; + return paletteColor( pixels[x][y] ); +} + +void Icon::pixel( int x, int y, int colorIndex ) { + x = x < 0 || x >= 16 ? 0 : x; + y = y < 0 || y >= 16 ? 0 : y; + pixels[x][y] = colorIndex; +} + +RGB Icon::paletteColor( int index ) { + index = index < 0 || index >= 16 ? 0 : index; + return palette[index]; +} + +void Icon::paletteColor( int index, RGB color ) { + index = index < 0 || index >= 16 ? 0 : index; + palette[index] = color; +} + +bool Icon::exportXPM( char* fileName ) { + FILE *xpm = fopen( fileName, "w" ); + if( xpm < 0 ) { + return false; + } + + fprintf( xpm, "/* XPM */\n" ); + fprintf( xpm, "static char *psx[] = {\n" ); + fprintf( xpm, "/* columns rows colors chars-per-pixel */\n" ); + fprintf( xpm, "\"16 16 16 1\",\n" ); + + // Palette Conversion + + char paletteXPM[17] = " .XoO+@#$%&*=-;:"; + for( int i = 0; i < 16; i++ ) { + RGB col = paletteColor( i ); + fprintf( xpm, "\"%c c #%.2x%.2x%.2x\",\n", paletteXPM[i], col.r, col.g, col.b ); + } + + fprintf( xpm, "/* pixels */\n" ); + + // Pixel Conversion + + for( int y = 0; y < 16; y++ ) { + fprintf( xpm, "\"" ); + for( int x = 0; x < 16; x++ ) { + fprintf( xpm, "%c", paletteXPM[ pixel( x, y ) ] ); + } + if( y < 15 ) { + fprintf( xpm, "\",\n" ); + } else { + fprintf( xpm, "\"\n}" ); + } + } + + fclose( xpm ); + return true; +} diff --git a/icon.h b/icon.h new file mode 100644 index 0000000..7683a60 --- /dev/null +++ b/icon.h @@ -0,0 +1,27 @@ +#ifndef ICON_H +#define ICON_H + +struct RGB { + int r; + int g; + int b; + RGB( int r = 0, int g = 0, int b = 0 ) { this->r = r; this->g = g; this->b = b; } +}; + +class Icon { + private: + char pixels[16][16]; + RGB palette[16]; + public: + Icon(); + int pixel( int x, int y ); + RGB pixelRGB( int x, int y ); + void pixel( int x, int y, int colorIndex ); + RGB paletteColor( int index ); + void paletteColor( int index, RGB color ); + + bool exportXPM( char* fileName ); +}; + +#endif // ICON_H + diff --git a/memcard.cpp b/memcard.cpp new file mode 100644 index 0000000..8663983 --- /dev/null +++ b/memcard.cpp @@ -0,0 +1,120 @@ +#include +#include +#include "memcard.h" + +using namespace std; + +MemoryCard::MemoryCard() { + for( int i = 0; i < 16; i++ ) { + this->blocks[i] = new Block(); + } +} + +bool MemoryCard::loadFile( char *fileName ) { + fstream file; + file.open( fileName, ios::in | ios::binary ); + if( !file.is_open() ) { + cout << "'" << fileName << "' could not be opened for input, exiting.\n"; + return false; + } + + for( int i = 0; i < 16; i++ ) { + /* + blocks[i] = new Block(); + file.read( reinterpret_cast( blocks[i] ), sizeof( Block ) ); + if( file.gcount() != sizeof( Block ) ) { + cout << "Error reading block " << i << ", read count less than initial block size\n"; + return false; + } + */ + this->loadBlockFromFile( fileName, i ); + } + file.close(); + + return true; +} + +bool MemoryCard::loadBlockFromFile( char *fileName, int srcBlock, int dstBlock, int offset ) { + srcBlock = srcBlock > 15 || srcBlock < 0 ? 0 : srcBlock; + dstBlock = dstBlock > 15 || dstBlock < 0 ? srcBlock : dstBlock; + fstream file; + file.open( fileName, ios::in | ios::binary ); + if( !file.is_open() ) { + return false; + } + + file.seekg( srcBlock * sizeof( Block ) + offset ); + this->blocks[dstBlock] = new Block(); + file.read( reinterpret_cast( this->blocks[dstBlock] ), sizeof( Block ) ); + if( file.gcount() != sizeof( Block ) ) { + cout << "Error reading block " << srcBlock << ", read count less than initial block size\n"; + return false; + } + file.close(); + + return true; +} + +bool MemoryCard::loadMCS( char* fileName, int dstBlock ) { + if( dstBlock <= 0 ) { + dstBlock = this->directory()->nextOpenBlock(); + if( dstBlock <= 0 ) { return false; } + } + fstream file; + file.open( fileName, ios::in | ios::binary ); + if( !file.is_open() ) { + return false; + } + DirectoryFrame *dirEntry = new DirectoryFrame(); + file.read( reinterpret_cast( dirEntry ), sizeof( DirectoryFrame ) ); + file.close(); + + if( file.gcount() == sizeof( DirectoryFrame ) ) { + this->loadBlockFromFile( fileName, 0, dstBlock, sizeof( DirectoryFrame ) ); + this->directory()->Directory( dstBlock, dirEntry ); + } + return true; +} + +bool MemoryCard::saveFile( char* fileName, fileFormatCard format ) { + fstream file; + file.open( fileName, ios::out | ios::binary ); + if( !file.is_open() ) { + return false; + } + switch( format ) { + case FORMAT_RAW: + default: + for( int i = 0; i < 16; i++ ) { + file.write( reinterpret_cast( blocks[i] ), sizeof( Block ) ); + } + } + file.close(); + return true; +} + +bool MemoryCard::saveBlockToFile( char* fileName, int block, fileFormatSingle format ) { + fstream file; + file.open( fileName, ios::out | ios::binary ); + if( !file.is_open() ) { + return false; + } + switch( format ) { + case FORMAT_MCS: + default: + file.write( reinterpret_cast( directory()->Directory( block - 1 ) ), sizeof( Frame ) ); + file.write( reinterpret_cast( blocks[block] ), sizeof( Block ) ); + break; + } + file.close(); + return true; +} + +Block* MemoryCard::getBlock( int index = 0 ) { + index = index > 15 || index < 0 ? 0 : index; + return blocks[index]; +} + +DirectoryBlock* MemoryCard::directory() { + return (DirectoryBlock*)this->blocks[0]; +} diff --git a/memcard.h b/memcard.h new file mode 100644 index 0000000..2502130 --- /dev/null +++ b/memcard.h @@ -0,0 +1,28 @@ +#ifndef MEMCARD_H +#define MEMCARD_H + +#include "blocks.h" + +class MemoryCard { + private: + Block *blocks[16]; + public: + MemoryCard(); + + enum fileFormatCard { + FORMAT_RAW + }; + enum fileFormatSingle { + FORMAT_MCS + }; + + bool loadFile( char* fileName ); + bool loadBlockFromFile( char *fileName, int srcBlock, int dstBlock = -1, int offset = 0 ); + bool loadMCS( char* fileName, int dstBlock = -1 ); + bool saveFile( char* fileName, fileFormatCard format = FORMAT_RAW ); + bool saveBlockToFile( char *fileName, int block, fileFormatSingle format = FORMAT_MCS ); + Block* getBlock( int index ); + DirectoryBlock* directory(); +}; + +#endif // MEMCARD_H diff --git a/psxicontool.cpp b/psxicontool.cpp new file mode 100644 index 0000000..ea6055e --- /dev/null +++ b/psxicontool.cpp @@ -0,0 +1,92 @@ +#include "psxicontool.h" +#include +#include + +using namespace std; + +PSXIconTool::PSXIconTool() { + this->error[0] = 0; +} + +bool PSXIconTool::loadMCS( char* filename ) { + fstream savefile; + savefile.open( filename, ios::in ); + if( !savefile.is_open() ) { + sprintf( this->error, "Unable to open file \"%s\" for reading", filename ); + return false; + } + savefile.read( reinterpret_cast( &PSX_Save ), sizeof( _PSX_Save ) ); + savefile.close(); + + // Convert icon data + + for( int i = 0; i < 16; i++ ) { + icon.palette[i].red = ( PSX_Save.save_header.palette[i][0] & 31 ) << 3; + icon.palette[i].green = ( ( PSX_Save.save_header.palette[i][0] & 224 ) >> 2 ) + ( ( PSX_Save.save_header.palette[i][1] & 3 ) << 6 ); + icon.palette[i].blue = ( PSX_Save.save_header.palette[i][1] & 124 ) << 1; + } + for( int y = 0; y < 16; y++ ) { + for( int x = 0; x < 8; x++ ) { + icon.pixels[y][x * 2] = PSX_Save.save_header.icons[0][y][x] & 15; + icon.pixels[y][x * 2 + 1] = ( PSX_Save.save_header.icons[0][y][x] & 240 ) >> 4; + } + } + +} + +bool PSXIconTool::exportXPM( char* filename ) { + FILE *xpm = fopen( filename, "w" ); + if( xpm < 0 ) { + sprintf( this->error, "Unable to open file \"%s\" for writing", filename ); + return false; + } + + fprintf( xpm, "/* XPM */\n" ); + fprintf( xpm, "static char *psx[] = {\n" ); + fprintf( xpm, "/* columns rows colors chars-per-pixel */\n" ); + fprintf( xpm, "\"16 16 16 1\",\n" ); + + // Palette Conversion + + char palette[17] = " .XoO+@#$%&*=-;:"; + for( int i = 0; i < 16; i++ ) { + fprintf( xpm, "\"%c c #%.2x%.2x%.2x\",\n", palette[i], icon.palette[i].red, icon.palette[i].green, icon.palette[i].blue ); + } + + fprintf( xpm, "/* pixels */\n" ); + + // Pixel Conversion + + for( int y = 0; y < 16; y++ ) { + fprintf( xpm, "\"" ); + for( int x = 0; x < 16; x++ ) { + fprintf( xpm, "%c", palette[ icon.pixels[y][x] ] ); + } + if( y < 15 ) { + fprintf( xpm, "\",\n" ); + } else { + fprintf( xpm, "\"\n}" ); + } + } + + fclose( xpm ); + return true; +} + +char* PSXIconTool::errorMessage() { + return error; +} + +void PSXIconTool::printInfo() { + char* var; + + printf( "Block Type: %d\n", PSX_Save.block_header.block_type ); + printf( "Save Size: %d\n", PSX_Save.block_header.save_size ); + printf( "Next Block: %d\n", PSX_Save.block_header.next_block ); + strncpy( var, PSX_Save.block_header.territory_code, 2 ); var[2] = 0; + printf( "Territory Code: %s\n", var ); + strncpy( var, PSX_Save.block_header.license_code, 10 ); var[10] = 0; + printf( "License Code: %s\n", var ); + strncpy( var, PSX_Save.block_header.save_code, 8 ); var[8] = 0; + printf( "Save Code: %s\n", var ); +} diff --git a/psxicontool.h b/psxicontool.h new file mode 100644 index 0000000..20f68a8 --- /dev/null +++ b/psxicontool.h @@ -0,0 +1,81 @@ + +/** + Stores the header data from the first block of + playstation save data +*/ +struct PSX_Save_Block_Header { + int block_type; + int save_size; + short next_block; + char territory_code[2]; + char license_code[10]; + char save_code[8]; + char code_end; + char unused[94]; + char xor_code; +}; + +/** + Stores the header data from the first frame of + playstation save data +*/ +struct PSX_Save_Header { + char magic_number[2]; //!< "SC" + char icon_display; //!< 17 - static (1 frame), 18 - animated (2 frames), 19 - animated (3 frames) + char blocks_used; + char sjis_save_title[64]; //!< Save title in Shift-JIS character set, kanji only + char padding[28]; + char palette[16][2]; //!< Stored as BBBBBGGGGGRRRRR + char icons[3][16][8]; //!< Three icons, sixteen rows of 8 bytes (4 bits per pixel) +}; + +/** + Structure for holding parsed icon data +*/ +struct Icon { + struct _RGB { + int red; + int blue; + int green; + }; + _RGB palette[16]; + char pixels[16][16]; +}; + + +class PSXIconTool { +private: + struct _PSX_Save { + PSX_Save_Block_Header block_header; + PSX_Save_Header save_header; + } PSX_Save; + Icon icon; + char error[2048]; + +public: + + + /** Constructor */ + PSXIconTool(); + + /** + * Load an MCS file (raw block data for a single playstation save file) + * @param filename + * @return True on success, False on failure. + * Use errorMessage() to determine the error that occurred upon failure. + */ + bool loadMCS( char* filename ); + + bool exportXPM( char* filename ); + bool exportPCX( char* filename ); + + Icon *getIcon() { return &icon; } + + void printInfo(); + /** + * + * @return The message from the last error to occur. + */ + char* errorMessage(); +}; + diff --git a/qt-gui/BA.png b/qt-gui/BA.png new file mode 100644 index 0000000000000000000000000000000000000000..865e458781540b88bc5ecc2ed1aeb096c9f8e73f GIT binary patch literal 252 zcmeAS@N?(olHy`uVBq!ia0vp^d?3uh3?wzC-F*zCq)J>PN?cNllZ!G7N;32F7<>~` zQWeTGOEMJPJ$(bdh8S)Js$wtk^mS#wz{SU}Az~5tO>_%)r1c1j3A$?$-SQ z3bLd-`Z_W&Z0zU$lgJ9>O9c3Yxc+D0Xz}V1;ONOtUi&{e`Tg_v|9e`NEBmq6nRBvvxlmc(> zWKSS=V9yLFd>jxy?Lta2+f#u=v#TPiY{Bjeb|(7qC^|VrnYK0ta%Sucl3@54EqHUg SPN?cNllZ!G7N;32F7<>~` zQWeTGOEMJPJ$(bdh8S)Js$wtk^mS#wz{SU}Az*K;@D3=%S>O>_%)r1c1j3A$?$-SQ z3bLd-`Z_W&Z0zU$lgJ9>O9c3Yxc>Y1=ijv(|N1BVTQL9M!w3JWEB`UE{F9KV-yiiE zsK(aQ#WAGfR_i%WJ_ZF2W`}FP{>!g+bmcpCPi+FzMf+u0ng=^X7 +#include + +#include "psxsavewidget.h" +#include "memcard.h" +#include "psxmemcard.h" + +int main( int argc, char *argv[] ) { + QApplication app( argc, argv ); + + MemoryCard *memCard = new MemoryCard(); + if( argc > 1 ) { + memCard->loadFile( argv[1] ); + if( argc > 2 ) { + for( int i = 2; i < argc; i++ ) { + memCard->loadMCS( argv[i] ); + } + } + } else { + std::cout << "No filename provided, exiting.\n"; + return 1; + } + + QMap games; + QWidget *mainWidget = new QWidget; + QVBoxLayout *vlayout = new QVBoxLayout; + QHBoxLayout *hlayout = new QHBoxLayout; + + PSXMemoryCardModel *memCardModel = new PSXMemoryCardModel( memCard ); + QTreeView *tv = new QTreeView(); + tv->setModel( memCardModel ); + tv->setColumnHidden( 0, true ); + for( int i = 1; i < 5; i++ ) tv->resizeColumnToContents( i ); + vlayout->addWidget( tv ); + + QWidget *listContainer = new QWidget; + listContainer->setLayout( vlayout ); + hlayout->addWidget( listContainer ); + PSXSaveWidget *saveWidget = new PSXSaveWidget( memCard ); + hlayout->addWidget( saveWidget ); + + QObject::connect( + tv, SIGNAL( clicked( const QModelIndex & ) ), + saveWidget, SLOT( setBlockFromModel( const QModelIndex & ) ) ); + + mainWidget->setLayout( hlayout ); + mainWidget->resize( 900, 400 ); + mainWidget->show(); + return app.exec(); +} diff --git a/qt-gui/psxicon.cpp b/qt-gui/psxicon.cpp new file mode 100644 index 0000000..a8ae92f --- /dev/null +++ b/qt-gui/psxicon.cpp @@ -0,0 +1,31 @@ +#include "psxicon.h" +#include + +PSXIcon::PSXIcon( Icon *icon, QWidget *parent ) : QWidget( parent ) { + this->icon = icon; + setFixedSize( 64, 64 ); +} + +void PSXIcon::setIcon( Icon *icon ) { + this->icon = icon; +} + +void PSXIcon::paintEvent( QPaintEvent *event ) { + QImage image( 16, 16, QImage::Format_Indexed8 ); + image.setNumColors( 16 ); + for( int i = 0; i < 16; i++ ) { + RGB col = this->icon->paletteColor( i ); + QRgb rgb = QColor::fromRgb( col.r, col.g, col.b ).rgb(); + image.setColor( i, rgb ); + } + for( int x = 0; x < 16; x++ ) { + for( int y = 0; y < 16; y++ ) { + image.setPixel( x, y, icon->pixel( x, y ) ); + } + } + QRectF target(0.0, 0.0, 64.0, 64.0); + QRectF source(0.0, 0.0, 16.0, 16.0); + QPainter painter( this ); + painter.drawImage(target, image, source); + +} diff --git a/qt-gui/psxicon.h b/qt-gui/psxicon.h new file mode 100644 index 0000000..9a8c0b0 --- /dev/null +++ b/qt-gui/psxicon.h @@ -0,0 +1,12 @@ +#include +#include "memcard.h" + +class PSXIcon : public QWidget { + private: + Icon *icon; + protected: + void paintEvent( QPaintEvent *event ); + public: + PSXIcon( Icon *icon, QWidget *parent = 0 ); + void setIcon( Icon *icon ); +}; diff --git a/qt-gui/psxmemcard.cpp b/qt-gui/psxmemcard.cpp new file mode 100644 index 0000000..e4da930 --- /dev/null +++ b/qt-gui/psxmemcard.cpp @@ -0,0 +1,108 @@ +#include "psxmemcard.h" +#include "psxicon.h" +#include +#include +using namespace std; + +PSXMemoryCardModel::PSXMemoryCardModel( MemoryCard *memCard, QObject *parent ) : QAbstractTableModel( parent ) { + this->memCard = memCard; + for( int i = 1; i < 16; i++ ) { + DirectoryFrame *directory = memCard->directory()->Directory( i - 1 ); + int type = directory->blockType(); + if( type == Block::PSX_BLOCK_INITIAL ) { + this->blocks.append( memCard->getBlock( i ) ); + this->blockId.append( i ); + } + } +} + +int PSXMemoryCardModel::rowCount( const QModelIndex &parent ) const { + if( parent.isValid() ) { return 0; } + return this->blocks.count(); +} + +int PSXMemoryCardModel::columnCount( const QModelIndex &parent ) const { + if( parent.isValid() ) { return 0; } + return 5; +} + +QVariant PSXMemoryCardModel::data( const QModelIndex & index, int role ) const { + if( !index.isValid() ) { return QVariant(); } + InitialBlock *block = (InitialBlock*)blocks[index.row()]; + + switch( index.column() ) { + case 0: + if( role != Qt::DisplayRole ) { return QVariant(); } + return blockId[ index.row() ]; + case 1: + if( role == Qt::DisplayRole ) { + QTextCodec *codec = QTextCodec::codecForName("Shift-JIS"); + if( codec == 0 ) { return QVariant(); } + return codec->toUnicode( block->Header()->SJISSaveTitle() ); + } else if ( role == Qt::DecorationRole ) { + Icon *icon = block->getIcon( 0 ); + QImage image( 16, 16, QImage::Format_Indexed8 ); + image.setNumColors( 16 ); + for( int i = 0; i < 16; i++ ) { + RGB col = icon->paletteColor( i ); + QRgb rgb = QColor::fromRgb( col.r, col.g, col.b ).rgb(); + image.setColor( i, rgb ); + } + for( int x = 0; x < 16; x++ ) { + for( int y = 0; y < 16; y++ ) { + image.setPixel( x, y, icon->pixel( x, y ) ); + } + } + return QPixmap::fromImage( image ); + } else { + return QVariant(); + } + break; + case 2: + if( role == Qt::DisplayRole ) { + return QString( this->memCard->directory()->Directory( blockId[ index.row() ] - 1 )->licenseCode() ); + } else if ( role == Qt::DecorationRole ) { + QString image = QString( this->memCard->directory()->Directory( blockId[ index.row() ] - 1 )->territoryCode() ); + image.append( ".png" ); + return QPixmap::fromImage( QImage( image ) ); + } else { + return QVariant(); + } + case 3: + if( role != Qt::DisplayRole ) { return QVariant(); } + return QString( this->memCard->directory()->Directory( blockId[ index.row() ] - 1 )->saveCode() ); + case 4: + if( role != Qt::DisplayRole ) { return QVariant(); } + return ( (InitialBlock*)blocks[ index.row() ] )->Header()->blocksUsed(); + } + return QVariant(); +} + +QVariant PSXMemoryCardModel::headerData( int section, Qt::Orientation orientation, int role ) const { + if( role != Qt::DisplayRole ) { return QVariant(); } + switch( section ) { + case 0: + return tr( "Id" ); + case 1: + return tr( "Save Title" ); + case 2: + return tr( "License Code" ); + case 3: + return tr( "Save Code" ); + case 4: + return tr( "Blocks" ); + default: + return QVariant(); + } +} + +QString unicodeToAscii( QString text ) { + for( int i = 0xff01; i < 0xff5f; i++ ) { + text.replace( QChar( i ), QChar( i - 0xff00 + 0x0020 ) ); + } + for( int i = 0; i < text.length(); i++ ) { + if( text[i].unicode() > 0x7f ) { text[i] = 0x5f; } + } + return text.toAscii(); +} + diff --git a/qt-gui/psxmemcard.h b/qt-gui/psxmemcard.h new file mode 100644 index 0000000..7423112 --- /dev/null +++ b/qt-gui/psxmemcard.h @@ -0,0 +1,18 @@ +#include +#include "memcard.h" + +class PSXMemoryCardModel : public QAbstractTableModel { + private: + MemoryCard *memCard; + QList blocks; + QList blockId; + public: + PSXMemoryCardModel( MemoryCard *memCard, QObject *parent = 0 ); + int rowCount( const QModelIndex & parent = QModelIndex() ) const; + int columnCount( const QModelIndex & parent = QModelIndex() ) const; + QVariant data( const QModelIndex & index, int role = Qt::DisplayRole ) const; + QVariant headerData( int section, Qt::Orientation orientation, int role = Qt::DisplayRole ) const; +}; + +QString unicodeToAscii( QString text ); + diff --git a/qt-gui/psxsavewidget.cpp b/qt-gui/psxsavewidget.cpp new file mode 100644 index 0000000..4950f73 --- /dev/null +++ b/qt-gui/psxsavewidget.cpp @@ -0,0 +1,39 @@ +#include "psxsavewidget.h" +#include +#include +#include +using namespace std; + +PSXSaveWidget::PSXSaveWidget( MemoryCard *memCard, int block, QWidget *parent ) : QFrame( parent ) { + this->memCard = memCard; + QVBoxLayout *mainLayout = new QVBoxLayout; + Icon *icon = new Icon; + QFrame *iconContainer = new QFrame; + iconContainer->setFrameStyle( QFrame::StyledPanel | QFrame::Sunken ); + QVBoxLayout *iconLayout = new QVBoxLayout; + iconWidget = new PSXIcon( icon ); + iconLayout->addWidget( iconWidget ); + iconContainer->setLayout( iconLayout ); + mainLayout->addWidget( iconContainer ); + mainLayout->addStretch(); + label = new QLabel(); mainLayout->addWidget( label ); + this->setLayout( mainLayout ); + this->setFrameStyle(QFrame::StyledPanel | QFrame::Raised); + this->setEnabled( false ); + if( block != 0 ) { this->setBlock( block ); } +} + +void PSXSaveWidget::setBlock( int id ) { + InitialBlock *block = (InitialBlock*)memCard->getBlock( id ); + QTextCodec *codec = QTextCodec::codecForName("Shift-JIS"); + QString saveTitle = codec->toUnicode( block->Header()->SJISSaveTitle() ); + //this->label->setText( saveTitle ); + this->iconWidget->setIcon( block->getIcon( 0 ) ); + this->iconWidget->update(); + this->setEnabled( true ); +} + +void PSXSaveWidget::setBlockFromModel( const QModelIndex &index ) { + this->setBlock( index.model()->index( index.row(), 0 ).data().toInt() ); +} + diff --git a/qt-gui/psxsavewidget.h b/qt-gui/psxsavewidget.h new file mode 100644 index 0000000..a253b7e --- /dev/null +++ b/qt-gui/psxsavewidget.h @@ -0,0 +1,18 @@ +#include +#include +#include +#include "memcard.h" +#include "psxicon.h" + +class PSXSaveWidget : public QFrame { + Q_OBJECT + private: + MemoryCard *memCard; + PSXIcon *iconWidget; + QLabel *label; + public: + PSXSaveWidget( MemoryCard *memCard = 0, int block = 0, QWidget *parent = 0 ); + public slots: + void setBlock( int id ); + void setBlockFromModel( const QModelIndex &index ); +}; diff --git a/qt-gui/qt-gui.pro b/qt-gui/qt-gui.pro new file mode 100644 index 0000000..a5fb2d0 --- /dev/null +++ b/qt-gui/qt-gui.pro @@ -0,0 +1,13 @@ +###################################################################### +# Automatically generated by qmake (2.01a) Thu Dec 6 10:48:15 2007 +###################################################################### + +TEMPLATE = app +TARGET = +DEPENDPATH += . +INCLUDEPATH += . .. +LIBS += -L.. -lpsxsave + +# Input +HEADERS += psxsavewidget.h psxicon.h psxmemcard.h +SOURCES += main.cpp psxsavewidget.cpp psxicon.cpp psxmemcard.cpp diff --git a/qt-test-cli/db b/qt-test-cli/db new file mode 120000 index 0000000..94744d5 --- /dev/null +++ b/qt-test-cli/db @@ -0,0 +1 @@ +../testdata/db \ No newline at end of file diff --git a/qt-test-cli/main.cpp b/qt-test-cli/main.cpp new file mode 100644 index 0000000..0a039c0 --- /dev/null +++ b/qt-test-cli/main.cpp @@ -0,0 +1,97 @@ +#include +#include +#include +#include +#include + +using namespace std; + +#include "memcard.h" + +char* decode_sjis( char* sjis ) { + QTextCodec *codec = QTextCodec::codecForName("Shift-JIS"); + if( codec == 0 ) { return "Shift-JIS Not Supported"; } + QString unicode = codec->toUnicode( sjis ); + return unicode.toUtf8().data(); +} + +int main( int argc, char * argv[] ) +{ + QCoreApplication app( argc, argv ); + char* filename; + char buffer[256]; + string name; + string code; + map games; + + if( argc > 1 ) { + filename = argv[1]; + } else { + cout << "No filename provided, exiting.\n"; + return 1; + } + + fstream db; + db.open( "db", ios::in ); + while( !db.eof() ) { + db.getline( buffer, 256 ); + code = buffer; + int offset = code.find( ";" ); + if( offset > 0 ) { + name = code.substr( offset + 1 ); + code = code.substr( 0, offset ); + games[code] = name; + } + } + db.close(); + + MemoryCard *memCard = new MemoryCard(); + memCard->loadFile( filename ); + if( argc > 2 ) { + for( int i = 2; i < argc; i++ ) { + cout << "Loading MCS (" << argv[i] << ")\n"; + memCard->loadMCS( argv[i] ); + } + } + + DirectoryBlock *directory = (DirectoryBlock*)memCard->getBlock( 0 ); + cout << "Loaded " << games.size() << " unique entries from the game database.\n"; + cout << "================================================================================\n"; + cout << "Initial block\n"; + cout << "================================================================================\n"; + cout << "ID Frame\n"; + cout << "--------------------------------------------------------------------------------\n"; + printf( "ID: %s\n", directory->IDFrame()->id() ); + printf( "XOR Valid: %s\n", directory->IDFrame()->getXOR() ? "Yes" : "No" ); + printf( "Block Valid: %s\n", directory->IDFrame()->isValid() ? "Yes" : "No" ); + for( int i = 1; i < 16; i++ ) { + cout << "================================================================================\n"; + cout << "Block " << i << "\n"; + cout << "================================================================================\n"; + SaveHeaderFrame *h = ( ( (InitialBlock*)memCard->getBlock( i ) )->Header() ); + DirectoryFrame *dir = directory->Directory( i - 1 ); + string code = dir->licenseCode(); + if( code.size() > 5 ) { code.replace( 4, 1, "-" ); } + printf( "Type: %d\n", dir->blockType() ); + printf( "Size: %d\n", dir->size() ); + printf( "Next Block: %d\n", dir->nextBlock() ); + printf( "Territory: %s\n", dir->territoryCode() ); + printf( "License: %s (%s)\n", dir->licenseCode(), games[code].c_str() ); + printf( "Save: %s\n", dir->saveCode() ); + printf( "XOR Valid: %s\n", dir->getXOR() ? "Yes" : "No" ); + switch( dir->blockType() ) { + case 81: + cout << "--------------------------------------------------------------------------------\n"; + printf( "Magic Number: %s\n", h->magicNumber() ); + printf( "Icon Display Type: %d\n", h->iconDisplayType() ); + printf( "Blocks Used: %d\n", h->blocksUsed() ); + printf( "SJIS Save Title: %s\n", decode_sjis( h->SJISSaveTitle() ) ); + break; + } + } + cout << "\n\nNext Open Block: " << directory->nextOpenBlock() << "\n"; + memCard->saveFile( "test.mcr" ); + memCard->saveBlockToFile( "test.mcs", 4 ); + ( (InitialBlock*)memCard->getBlock( 4 ) )->getIcon( 0 )->exportXPM( "test.xpm" ); + return 0; +} diff --git a/qt-test-cli/qt.pro b/qt-test-cli/qt.pro new file mode 100644 index 0000000..339f0d3 --- /dev/null +++ b/qt-test-cli/qt.pro @@ -0,0 +1,14 @@ +###################################################################### +# Automatically generated by qmake (2.01a) Tue Dec 4 17:27:04 2007 +###################################################################### + +TEMPLATE = app +#QT -= gui +TARGET = qtpsx +DEPENDPATH += . +INCLUDEPATH += . .. +LIBS += -L.. -lpsxsave + + +# Input +SOURCES += main.cpp diff --git a/test.cpp b/test.cpp new file mode 100644 index 0000000..92ae434 --- /dev/null +++ b/test.cpp @@ -0,0 +1,84 @@ +#include +#include +#include +#include + +using namespace std; + +#include "memcard.h" + +char* decode_sjis( char* sjis ) { + return sjis; +} + +int main( int argc, char * argv[] ) +{ + char* filename; + char buffer[256]; + string name; + string code; + map games; + + if( argc > 1 ) { + filename = argv[1]; + } else { + cout << "No filename provided, exiting.\n"; + return 1; + } + + fstream db; + db.open( "db", ios::in ); + while( !db.eof() ) { + db.getline( buffer, 256 ); + code = buffer; + int offset = code.find( ";" ); + if( offset > 0 ) { + name = code.substr( offset + 1 ); + code = code.substr( 0, offset ); + games[code] = name; + } + } + db.close(); + + MemoryCard *memCard = new MemoryCard(); + memCard->loadFile( filename ); + if( argc > 2 ) { + cout << "Loading MCS (" << argv[2] << ")\n"; + memCard->loadMCS( argv[2], 4 ); + } + + DirectoryBlock *directory = (DirectoryBlock*)memCard->getBlock(0); + cout << "Loaded " << games.size() << " unique entries from the game database.\n"; + cout << "================================================================================\n"; + cout << "Initial block\n"; + cout << "================================================================================\n"; + cout << "ID Frame\n"; + cout << "--------------------------------------------------------------------------------\n"; + printf( "ID: %s\n", directory->IDFrame()->id() ); + printf( "XOR Valid: %s\n", directory->IDFrame()->getXOR() ? "Yes" : "No" ); + printf( "Block Valid: %s\n", directory->IDFrame()->isValid() ? "Yes" : "No" ); + for( int i = 1; i < 16; i++ ) { + cout << "================================================================================\n"; + cout << "Block " << i << "\n"; + cout << "================================================================================\n"; + SaveHeaderFrame *h = ( ( (InitialBlock*)memCard->getBlock( i ) )->Header() ); + DirectoryFrame *dir = directory->Directory( i - 1 ); + printf( "Type: %d\n", dir->blockType() ); + printf( "Size: %d\n", dir->size() ); + printf( "Next Block: %d\n", dir->nextBlock() ); + printf( "Territory: %s\n", dir->territoryCode() ); + printf( "License: %s (%s)\n", dir->licenseCode(), games[dir->licenseCode()].c_str() ); + printf( "Save: %s\n", dir->saveCode() ); + printf( "XOR Valid: %s\n", dir->getXOR() ? "Yes" : "No" ); + switch( dir->blockType() ) { + case 81: + cout << "--------------------------------------------------------------------------------\n"; + printf( "Magic Number: %s\n", h->magicNumber() ); + printf( "Icon Display Type: %d\n", h->iconDisplayType() ); + printf( "Blocks Used: %d\n", h->blocksUsed() ); + printf( "SJIS Save Title: %s\n", decode_sjis( h->SJISSaveTitle() ) ); + break; + } + } + return 0; +} diff --git a/testdata/ALUNDRA2 FILE1 Cabin.mcs b/testdata/ALUNDRA2 FILE1 Cabin.mcs new file mode 100644 index 0000000000000000000000000000000000000000..0adaae5750b07ed9c0f993c6c42bb5aa30f697cd GIT binary patch literal 8320 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 literal 0 HcmV?d00001 diff --git a/testdata/CHRONO CROSS 01.mcs b/testdata/CHRONO CROSS 01.mcs new file mode 100644 index 0000000000000000000000000000000000000000..f0a62bffab98370ea7e47c8f252be4bcf46fb9dd GIT binary patch literal 8320 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 HyuiN!GA~vQ literal 0 HcmV?d00001 diff --git a/testdata/CHRONO CROSS 02.mcs b/testdata/CHRONO CROSS 02.mcs new file mode 100644 index 0000000000000000000000000000000000000000..a5de98a7db947c2d08f359af6cf4863f54080e27 GIT binary patch literal 8320 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 literal 0 HcmV?d00001 diff --git a/testdata/CHRONO CROSS 05.mcs b/testdata/CHRONO CROSS 05.mcs new file mode 100644 index 0000000000000000000000000000000000000000..e52d65a12bc9e3c010534d7608cbaa718a70a19d GIT binary patch literal 8320 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 Lxv180kPH6>rYXks literal 0 HcmV?d00001 diff --git a/testdata/CHRONO CROSS 06.mcs b/testdata/CHRONO CROSS 06.mcs new file mode 100644 index 0000000000000000000000000000000000000000..6640d5691e8f8bd84e2d44a657cf9fea7e744902 GIT binary patch literal 8320 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 ModD*|t62d43(85^L;wH) literal 0 HcmV?d00001 diff --git a/testdata/CHRONO CROSS 07.mcs b/testdata/CHRONO CROSS 07.mcs new file mode 100644 index 0000000000000000000000000000000000000000..6b3da405a2d93b38e7cce55d9d81c1061bcc418d GIT binary patch literal 8320 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 literal 0 HcmV?d00001 diff --git a/testdata/CHRONO CROSS 08.mcs b/testdata/CHRONO CROSS 08.mcs new file mode 100644 index 0000000000000000000000000000000000000000..3c681185154c87e54183373a23a4d7b626b39aa7 GIT binary patch literal 8320 zcmeHM3s@7^odvp$B4WF7#=Emxpk6&LXDd85Uv#)LA+{}1&h|ArIQ$5 zwOAfvvFg1M0dcRksQB2T-zF#)TdmZ}x>wPLsx4~OwA#D)T{U|q$&j=>nQ0%>bqBWNU{2MN*v9 zK_QWBQ5dnGd_YR3s)DPhK9-GsY2)nHr0WaEzxvJ}{`Jk8^mWfH7iL5hP5rkAmJ1uB zQf2qLE!THNOs&4Yb9wOzKkxeU>7}**JTqcj_l~qtZI524nBntr;00F=o zEPdA42S6;~V2}WW7-CN3|>*LDC1M^742bGzi z2cV=Efa6m%&n=HJ@Cfk_!n~iINM_BdTyipfVp$HOL0WPK_OwinGa0QP%sY$Ap6c)(}p#O zfqb$fs_F6W!*|+&MS@vof%KOizVr~$x?FUDGAIpJ&Ugs~4l#iV;JxW?K#rip&2XUG z|EJh9knLIyO7JrtX_nuWnK_=|0CnwvZ{>Kn!{VbC4g*u&gdDh-G zb!ILgkXOKWB=g*X&A{AU;5GXL_0H+Nt_AEp7T|3`;r*XAU!iOI8~}VQrmCPy=q21A zLuqNI>sIBH9K)jsT6Ss$$9;oOfCfLB88m+d|B$$=IrwhJQ8XST&&<2jN!+aWigSzY z3Tggk`CZXAJSQ{Oy#0b^SM==S^s4D!q;HpekUzQg$ocuTQ|p4%dq2ImyY=m7q2I@J z&A%v#xOcwjrq9EjQMvL8X>eNL7hZvX-cIveZ|>NV^XS8xA?w4;>Hm7$dgXA)%sBqI zwtWI25sMi~QwZO4UgDlkzR(>(CK9;Ny;wo(cjEYFO0B{PPee`=LOfIh;)zlW)f#R} zaU9!Xpj1K})0`uvIN^@SND_xU4M_+wOiSsd1RPN$0f`#we|N?wP&y()duCM7EA=Yl z-oWy))7EsK)Qp<*#jcs_ALzUljY?lh8YYOLNsX4{Nh^O|BPAwrcMU~S@FqY21*{L0UvCzC ztLaW=(Nh|fVjojM3|V010S2pVkh!k8c5Fm{UmjZn|E|@oVCCbjz;?A+=w}UY(B_+o zjSXXX`896#Xqopf`vgZ8GaKp)>~Hx;tT|?3O)Sjn3%raln7>C1#sJgUUu8J_m0}oJ z>tD$cW7fIc%pIZ!oyXSvLpACT(pIeh`s%|WzUL*pD3mEKcVTn(^E zbqVLzE|uvBo@@S9D*J*U#KmXByA(RR+GB_~)b<5xXIBjT&n;zE008sZWeqWHTM$rv7W`6T*l~xmmLYTySw-=tj$Gh|ani}YTy=wA zY3M9EG>Gum9mITEl>7DjifNSR>fYp(szIzUB$LBe1$*laA=*!F?MJ}uQ15)9dY?ns z{6b;752M2uZhaATjE6yISYA5|M%w4vzvry-%ZAkoV&e(5gW4CT+u7g>*Zz@VOh5b? zh)zhJd|Km$6aWJ%L;P?NUh#vmUE@o1MlUNfyL4z#7a#vpzw8Si#zw6Tt(>-(D)CH3 zQ=U{zG+?13GX38VDT;lOuPzH}Ws^Rykz8J_OjKQ9KG#Rs)K06Fe%-D#Z75~(H!O!{ zWehA}IYajbXJ0u(%Q%mDEz?~0- zi%z{wg?8rcIbDkJme=ky8erx*b)Zt*j=wu$R-KatJJho->RB*QW>AWHTtE4@{b(@I zJ(8IYrs$xV9KK>5)L~HvJDu|^7*>2BQ|0AE+vtP`LKExa77GT-3`6&vkx{*4gAJ`Oxw*_(qli8tyYdM}Pu24xn2&F?OGUi3Ki1 zL_=2GiSgH;)oEf9<9ORoe<{nC?yAVHiYeR0OGdv6%J8qc7@zs>;_%w73UrlHSXv#o zO+7<2E{=Pe_xpgd>W&@K$v|7e|2Ii==6_R9@Q06jp{S_&|QqiGWQf{m#r#-tV27G|JX zeoD2^$1PP}qpb5w)J5)3l3ZR@v}kw2Bp(SRQUOW))Ui9_o<6!b>$%xjGQsi!^h3#n z!oD8vgiTL}M-F=qx#4LexljM}!K#C6Znm_#MYg<6*leW`4e3qAQjVj2wb;#xQZ2`*dk=f#!;IA6y zZVzAj*|tOmM6bN0<0S{otqsp;(*=)eOxqE;vTfVBs>ZobnOpzotq=M6*gm4+<~EH0 zz0)hDokI@wrVaB9+c~?KQ&%;(3o6PgLrkJ+1mg>Bn|khJV>W<^S{+Xil751oxVhLv zG;>2A5bH|4{a>z)(TI!Q^#z#Jz^rBppo|4(Su~bJu}T;0L1|9B31S9RlwlY(peO)GP=#uYkdz;93ay0Uxl(jiiO1X@Kh&I zui8$|6eR-YcA}#ip=KY=%g9B?z+VZ%@{PP?wcN{K!U9zqo~%%Hpwqq` z%~-(drEW?X+b1SnuoV6dt8N?B1YD`;Q|F3gLV0xO!2&aI-)s)CqKg zB7u%*5S$fe5eiI>D=-C~Wj~g=7ZD9aBl(^5yT!BL4kVBVqW{= z_Jp%>y|KNqjZ&R7OPUp=2vvl_t3P{Wi4^{h(}v`tEZY&p^l&7Ui{t|9DUb`q0!AZC tm?c^Uk1XLbh_ZwVfdcZZCn2{T%m|_^cLgEG<#>^>LEsAW)-B|M{{$FNA{qby literal 0 HcmV?d00001 diff --git a/testdata/CHRONO CROSS 09.mcs b/testdata/CHRONO CROSS 09.mcs new file mode 100644 index 0000000000000000000000000000000000000000..69f47d47f318a9b69c6d2f388a41fabcaf139bba GIT binary patch literal 8320 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 QVtZd$nJ{lZOYOja1KWT+Y5)KL literal 0 HcmV?d00001 diff --git a/testdata/DW7 01 Phoe L01 0 00.mcs b/testdata/DW7 01 Phoe L01 0 00.mcs new file mode 100755 index 0000000000000000000000000000000000000000..baefd5513346d580c74f9327b9fde05739f79e57 GIT binary patch literal 8320 zcmeHLeQ;FO6+h>`&wcyx_U&%6d7JFpkC%i^NF>>WWTgq4kQh;@2??PDt%*o!#m=b1 zNElnqvJDuA7A%g4P*l{;Fjy<&prlR31yQS_f?6FdLbNJ=@DULtz>?SdNKygqOl#Xe zI_A9WJ@=e@?z!jw?s@m!n;AeU2w)gfYFnnawltNLMoTK{XH*uql$4ll|66KqsZ%g{ zZE{g^){>fJW3p*UL-K}XPjY2)DV483tEpM?Po88WwQfu{o*N=UU32|;fp5HRZfwV` zpOR49v+BaGtgb4%kY{w|T()c~0&L#e_p?r~q9}cReU+Vxa?|qOKKIR?H}&=OEWi1Q zzO9tcUf9yt*K9tug`C8Z4J+FXsFK*Q&wN!Kp$EfhLH{o1qS57_@F#s z7_!qam_+*5OwEyN;){&|qbojO#I@9cpljLf>dz0>$+4mLn2v3yV=IiVdgVmt%#0J2 z^~%tsnB$@#z_N&w)q*Abw%UFsp1@RGlm`RlY2#ApHvkaWWG4EG6SGXn<|ViyssdsP zXYruIZb1Yql^G~C)#s5HrZVR${O1baqJGPv*WbBhkbNtiw>P~D)_uvQ(!YBrEe1}q zL+Q2er0*~$P;^dL5`0dCTODRp0Ec)8)&!f*8SN!rtYqH3k@p00zy`Z%%Tx%{@@>ci zQ6q$<#M^}79vplIX#nTir*DWD#(3Za@Y(@fJGis$ZNp#;+k)fNAvQ`8I!19BA$7F! z6&F{BEalWH5IV^j?E@yB9Z+tLYDK~V6cQi`q=19~5=1?Y2*GFW5ZQ8A02NROkHHQH zNo6sISJ1u-zVbUnc;=|_L$c*ByVA!8jRU=V4h$s_+KY!L`4Qa;YFsREi8IYT`}f12jRA%^ zys{SPRH#L20zd`;MJw_90>Y0v{_b)L>8U6=`6~P>hMOMT^r=i!c9f2o73L3ykvT$k z8z)=Qea_PSH-Ix=j1>G0;EzJi?*08~gH=8l5U1Yx!eITWj%#4Bt9$p;VCXj*uctN| z@!pT0p$Q1#%>b(=(Vle6k-?ctC%#=M!&yV$D1sJ;jN_5MO_caIXM>;SvvB|7TLS$w zz58Cq>R^(_&Tr@SyB>;%ZnEz>W`D)gDU%-qs&D2I0b{*v}b_W-;IU%+!v^tE`@ z=roTSZKb~^RgW}OX_duVWqY|9uSOpg$`^tvYn7@NQOiL$xBP^t5Z+xP# zCeWhmG>}y)MW`y`p*{8MKr<26)M%9|dmP%;nc_eFNYsm=CwYFR9`Ja#0KlMs)O?pwY7# zWopz-r(#CM)1nI8K)(u_X;$NeAR&-ZTRyeKTrh)=e)zHghV3Pw_z1%sigfD4SD@Q^)C{ombHQxhog+JuASyunN}0Tc*eJ$PPlKkK(NKX# zF*{PL$!BXenBoO9iGua9YBQc%gVQv6Msn~=skKB*-tPnLDT=HT2xj;LLDtkM{(y4# z)zqXp(ec2W612l*&f# zeC9MhfG|feCoeI>90J>E{-{B3Mz$6vkMUR2dZzoW+o(xVqGQ9(kyE+p>p!42ddmJL z8ofy-S0wL9t}!h}H6xJUxqh!NN6n6$piRCN*FEtDNACadz~{Rn?uy6hT^y?7aoYfZEgk6VanNX;tYeIz7+Rf=>M;rM)JBafWSv{{i? zm^=|#JL3_MwK7hscd~0Gu-gd=zzbMK{jkgi0XYkEr5$-U*)D=8viAxgT1ck^lB6+F zXpk*46mYS^GAj`s{GBw5MYh%g0?(!FVCRKtcC=c#E(vTr*CbPY#=AktB1{DxUEvK2 zIt5{q1L?Q5MgR*Z7r$P|=kkcZDHWv6uPKp5@r*1;2nPfkp^7(v@Od4`qYk6{guxkj0%D z6eZ_cH%htoMinKWG9@2EvVFD>g`llNM%H6plu6@sU!DhHIlsFA>OD#{2yRiS@j(Gb8!u-wd2r}qwXle zEN9EMTxjEs)MS)vK%q#IoQJE4Cei;mQTlpmYKJ`Ur$g_nE#|jujK&ZcLtqSnF$BgC U7(-wTfiVQe5Ew(?yMe&p0ru0t{r~^~ literal 0 HcmV?d00001 diff --git a/testdata/FF7 SAVE01 64 05.mcs b/testdata/FF7 SAVE01 64 05.mcs new file mode 100755 index 0000000000000000000000000000000000000000..6048a2795cfa97bb0c03bd622aab1324f31fc64a GIT binary patch literal 8320 zcmeHK32>9g6@I&``?SCZwvaDzSjGnHur1p%lCUH!uq|v^reLr!G0?;?Eu>(|Q5%<# znLwfKw8Nxi1}GE)w37rH2;jsCX|BeUwhTRz+D?W^p@HCZ(h16d{P+F8Y!%EgLzs3l zsop<3yZheTx8HvM+kf}31(Zwxj+@~QR)m82B{p-B)#oeD4;Gkt+kaQ=!3rJeT7pl* zrlzh{U5mO_ceQo}y5?Xn)D_(1!*)FnVex8nL8(v|2=$&aL+3V!p%a`~?kk45ebZ0P zIMEcGZ=V`Ad{%O8-qn@I4BJbd+$b}19b8h@n$I|n8(3(0Wa)c-k%6a{wzoI*MFK0o zId*;ag-B?oZqxMapGO9gbjO-j)rFt4n5VQHZIA3IUYy+W__FZ1Wv4AKtvMa(S##ys z)f4ZAJ5K1$x=VkKbTrz{x+{N)^c+5+Ghg{z?er6ncWcg+ukY75gOlrl=mKr}Y`;sC9FOeUvpghRv$xgdhAnqMb%lN!no z+^R`n-hMeG^sj@W-UVRZy#chSH{EOp8;+gh0hqXNE>va=K-y~`LrOpgZq!?_corSv z!wYg_Apo)Y11`5|Toe%DvfXuc-g*R#9+Q)>0wsi?KrpY>t<~)&y9wXnTaV2b$6^hK zeBjD72Y|W){#n%yJqW8KwKl&G;o>A1Eq%NKIAbHc4JDvK)$~M?C2Y~VQ-w)@fW_+p zyUAqY0~RoR7dZq}AQjBb+Gg$Z%r=;uS5(hG>9RY zV5%TtD9Dr&Z+d*1q2Ko5*h9bVcCNDRTXG; zv{z8Ps?yQp7e!EvSoxf^V&U`CjOAA0_ad+7_bXqImc#hHk-4gBW>(v9ZxYOR^0d+K z5w->YE*es#nOspL{1Vjo5cre)r%96_LD&~HDmDAncW__yNWr|K3}%IA!CXf!1lHui z6hw^60}~b=U&^2k>ZiO2p`lZEsE+(nh*~HqmC< zNjK9c=ob1E-9~>vx6_?;7k!5Ap-1Qo^aMRgPtk7rI(>t_OV83j&_B}i^aAap{q#e6 zkq*-9G)!;O2&Gc7SSnRA71J^uOJ?I(D$8V9%*b-tR5p!SnT-`QJ9Dsd=44bN5}BEp z+9ad-j`zR147f3mOQz&NZu=y#VM>-?Fu>#`I?%LD0{xgRP`C$RJeHi<*-*OH26+@{ z9=L>jPDFnPmh3Hwpvog)|L#PPC;0_i%?rz+5N*|U*}|8-^!0kcqd+)MtXR+fjUH-G zw}I_&8B}%823}V*T+FX1z~)~O+cU1(U9t98m&rJ?uOkEajRtXQDtNk!z%b7O=IlbS z^k6P%lX?b7m(39X^^}V#Ro23~fdH(F6OY znAb#Q<3F1|;9F-q&hpo1kjq>q$Pn>O;c~J6?bdb3t#GC)X7cJgB|6nKF-9*qc#Y%w zhIR}7cX|SBws%UUmx#Pg1nE#jwRo)KJQA&y9HPM?zs?Es?lvr@bFclo6l65*lhonM zPs}p9feC>^GJ6KZ+M(b7!Wq54kMbPJdm|3F+*M za8DTCxY!Es_4H(jT#rUCb;4NsEy7vV(uISdmhg&IYX0^uG$Yquae|%y9k@-5m4S)? z#}Ocz@-tEk_y|aOkV@F8e6~s z7>LPRTK;sszr2a&zwTo*^!iooq~F*{YCjiu9o*IOPU_ECMaUz} z^GxqQAZyw7>nlv_OaoK46fMm4OvB-eKePc)Z}s;a!ZyC=gg@yx%`pxab`Oc>4{tOI z9xwMeKOLOlyoWbHq)Gaz7XD+;V4(V_{R8nPB{Xl?s)To@T_%`jK*dPi-Cn;Pe|{f8 zGUXEG8RfBC$j&lPi=ewMN@{{~>W}oPjt4 baR%ZH#2JV)5N9CHK%9X%191kv)(rd`)+Es9 literal 0 HcmV?d00001 diff --git a/testdata/FF7 SAVE01 64 23.mcs b/testdata/FF7 SAVE01 64 23.mcs new file mode 100644 index 0000000000000000000000000000000000000000..f83a80e13d519e3d211e3ce0bcb5f0ca173201f7 GIT binary patch literal 8320 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 literal 0 HcmV?d00001 diff --git a/testdata/FF7 SAVE03 65 03.mcs b/testdata/FF7 SAVE03 65 03.mcs new file mode 100755 index 0000000000000000000000000000000000000000..838c53577128b7115e2506590b5affefbce11bce GIT binary patch literal 8320 zcmeHK3s98T6+ZXg-G863EW#qJu)vD42=drn$J74NqttU&ZO0ureiRW`ijOSv`w8!>lk#b)mDL+=_nbIzvuo78xqkZz?Tgx%w>Py{w|lWw*Iv8M#p~RKadbSWQ{7&@&h=myCpBy<|H;Do^0#N|tNxOE zWAXmyf8$t|u;GR3q=AWIt05$KCuzYgZ+KR zgi}N5XH!h8lU^F?>Nc1pr*|BVJbNAjq^>_B&>N&kp|55+d$R6MDr@hzv z7WVk!Zl+)F?C9}z-aORVU)OWv`n0~z{(tw}=;%D$*&idCI)^>|{k8}D{_U6M^#c?G zRhlcR>q^DX*V_=@7*S5H(33ya!>3yqSgLB=rB0Y$?X4|ydaJXEfiSL@ zIvs3SW^P{t$#W7R+qVE1>JVh@&!WJ-!~jwGHgKR$7IG=_C>7~Z&tC3v6sJt&cCjTU zI=o(IEjo-!QzNm+(m)+#NYcpg$nXQ?05=UQ_1nn@pUAn|Ls4-k04?#%si>M|1Zj1w z*5-DhyEqA2j+>;87q#=@eaMAST-A%=Es^UWU(y_kxk#hE8i+zYJMs+VS$i|@@oDnL zC!l`IAt*q3?B8zz!;&D6l5Q~oOGr&C$cc-T77FA*g464+;ZC4ZnIOV&wgy@tNfLVm zk6KIl!CxH}%KK zamj~YhaD!1c0D`}$IAfJS#@QlF2{6f5{x^mb8ea2TP^v}DkwpePMBZ%t`>B9>XUqU zSF5LQU6uilMIMt@WFDWH$YY70Mc&WPE-$}K2d)7qODgBOt85q#1mm4;GQ08g@+ncd zK1vZUM$d;M5Q0AnO4(V%6f#vh7uQ1W((a>pF0R{Q_7H>6mMKu=*#^^aXg)HZk4G~1 zFY3GvYNI}ax_@1`XYZP-P>Cu<5J)%`WLh~Dw2FzU2#s1R3)vfbN*57E!-WY#gb+*P zXrg+mkW4MgENY9e(`?xcnk&nr`E*v3Q$3rO32s_0n`^WMqj5p=s|jj{+=G8Z_}gnI6XFVK(aC3=|- z(A#v74$-@mD&%s7Lc_F7$Mnp=CbDQYiN&)7W@agDI!kAn%*t$R2FqauY$hw@mq3vI zFA#8aDIj-RGNi1S0z46!c`g>FHtVH$HHL2h`woCf$a%+WA#bG(QYp|>C<44nAOg7n zIdMaTq@VMA5~w2GP>Ow3hn7GXmX+SbKn}fo0$~h;D;OS@q+kt$jI64P-U-k%R zcB&;`#sX*=S|Po~bJ2Lx?nj_}upAyKNP+6-QUmraIKFKAb%=4?h6z~De4{xa8*3|A z4 ztr-D%D#qjJoR#Y}kP?Sy>Nz9CUQq@5N9F&^ax}L__n;MXR?eIV4B&gWcyQjZ33fF7 z5<-~;vk#q@L9)s z1f7-ar!~WFeIYy=&>gShSoseHC}~Vz^hokEo|4pu0f9u~yL#oi;XnSW(4W6cq6hq4 zu(CaECI$QuZ#e=T-$PY2L_m-;lWI9%mQAwzeSE*M!Iw@7uWf#7b5HO44X=V=9_)=y z9bPR8MJO4EUKe{-3%C)F3-5`>+v+xmW1kIn4Z_LGP4Ks_E|aWiu|KJk#?ohrXbn+3 zHUJ^gE-nq>Ig3=i+uvCTIr!!9MKYIFmsDeF4`XRIx%7S(yh zc|~$l6B;70SG`wlP#IKNO-+QL;U%hfbVbS^g}V5Qfh#;&ASdtX?BlyKruP)q|GJwM8;wiZ5x2RG zcy7tt_ibxD6a5R;dN(?A=a!6g?a!Yo`nark=$P-HknrTD+fQ3oS$d~!$bKxPG#!UO ze#r(L-paKF(lH)m{fpHfw|0n3#D(35{PDwuW=Z3nF7dO0$%XgP2DrOW@re#Tmzx-9 zudKKzU#EeFH5)Z>CjD9$h8a*fLO0&_=ghsY?ePThDnWBhaaoO#%}<~I>KUV`f))Oc z!!dndRc&i?6!CjVCKnV+m0F_>3DvcI)u5m}h(Hj5AOb-If(Qf=2qF+fAc#N^fgl3k HVg&vJL_pH6 literal 0 HcmV?d00001 diff --git a/testdata/FF8 01 14 05.mcs b/testdata/FF8 01 14 05.mcs new file mode 100644 index 0000000000000000000000000000000000000000..7f74f328bf5fb21cc4f75041fbba962178807e49 GIT binary patch literal 8320 zcmeHK3v3j}8UAN)_ik@@?{3eJ^V>c@@FN)axBxXNRA9{6f!5FCC6S)(^Me?lbFp3X zXch0dh$7XcZh?fRPHUw}Lr|oZ&hz?z=bXM;%6tYp{6tf`SbF7iDJ^y%!;&cFYC`dz5H^) zWpJ1FJjs9gA-m-hI4t;HiX$ z;nD6Rw%P&Spk8iJi>P4K_wW8+2NxDKsReO{vwNhcBTro&{74l)d zLUJ2=328h?${u|>aJV%q@MLSLGUPh|?iQY$FXx$MTjhbI9fNzGk;j%ik)^C2t%Ud6 ztCg^|GW$D z;1If&GLOHmv#q|>i+XQ97Q}7jr(-A-E)-PYf~F;HTBFJue5$-%EuM~M59MSX-511R zUl-_z}Uo zML`_)b$1^_+ZUg2cZc88LizaRieLN`3;bR~G^me7*M2;%r6Z7v}6d~El%A*cR5bm()%v<$|O0CcpqkWd^C zH%wm_DA#t!k~c;s!M>1lsGr8DV*p;KN=V{kiNWAxQ!@2we7>cCPqzrVA|cPnn`~^V zC56j2pL4TDJH&t)Xo> zq-nWgrWYVdI>HZ2-;)lCsgglTl`5nWQ9)FvOcT;6)1W00w}s+z;_h&GIT3T6Q9Y3s9}8Qh55*h81R_h86y)d?!DiZTDmN*T&BV%l2-hp< z{=srQJX*d2$Q4*2MIXN;lS|X-bp}3B=inrcMqI4SPwr9iMd1;_flQ5vw}c8r<`(HL z?l+ym@`^bbr=d`~k*~|;0Bmen1;FBz|j?czbvEp`ii!lZD{=oUwCS0|A}MM_4#D9K+#zTR4fd#SNJdxrbfwSAlu z`Q^B4Ik zzE3DJ{tNf7$oQbK*m%xZhfhB4>IA0AppdX=O>AHtHU(>JqOGyfnV%lV>735=IDuoe zN#`3kpKU(hPm}G_gqcC9##}}i9n0wryipJ({Jd4a^Me%KW`B#fOZx%*0(Xw+>~Hs z&yZ&B>&D0IC&;fzx2==caiU&gO`Msr=#Fs5m?5%{^l&94pJX%7lAn`)!jYemCkzAZ zVbVVTbqyY_Xt^K*^#4m(_G=2K{Wl5QXszAJS@liJY4zsc!^9KNQhz|Zl61Ig97|tw zZO>TG58)(A47FhpR@ExF1mp10)X|$MYRyOA{P)U_$Ke9nCa=G`CJzU=T+52B$vm8O zV{XUxF!MBoajnHyDi6u{v*3BdcQ}@`*4>8q$7lX!qlUxeVWdg zBDBH*8Lo0y-u_1DyF~*paJcG(+=ziexP*m9^`~#ZdZY}prhOtu&TicztElHd3PU{> zFZ6#k`hTLx%vk_YncY8Y^|Q_Qu0M;eCtxYOMDFPW?%pSkdVb~@c<%ZwHS@fxp1SqW z%pJYMDi%BbB~eSm0Cp8K6~Ng80JCpaAOQHovNr(A+<60YO?R;T`ohKEj9+?{y!PAQ zy?*(PH-CTS4}W~?Pgmc5=iNVF`^&^%|91Vo;0!c7Qn{G(g)^FRAI0g-_u+gOuJnBo cl_&#I2BHi^8Hh3vWgyBxlz}J%|1Spq168MebN~PV literal 0 HcmV?d00001 diff --git a/testdata/FF9 FILE01 14 01.mcs b/testdata/FF9 FILE01 14 01.mcs new file mode 100755 index 0000000000000000000000000000000000000000..c6521b1926cbae4894726e85f1857e96904e1015 GIT binary patch literal 8320 zcmeHKYiu0V6+Y+A&hG5&V_y53wY?9o0}D>bVsDa79238YQxPRbj*FAJZlcmQhzLa? zA!#Kl$FdY!Xp2fq>l6vAC{hzO5+qPH1=1x2N~ByO;Fl{#*NR?qA#ALA8$l&fP0T8G0`r1LsekUwt}4{$8uOgb=jL^d z^?5CsZ!P3k$6E8twdy6;t>7iuSAPwd^#BOd{jIL9F50|L1TLmdbOwvg?x8uA_?xC zqy5rclM^$?F+#2A^b{nUW&rPmOsJP3{MIMh+-_2$+q)d#DYXci@Qw-_O}uI=z6Xn;EUy?T@t6?pAC=YU+Fl|r!(woE&V z(A=j_S7(&!5j?b=#rr0TDF?;JtGa)A!aYm=P3+9-|G()VR!ed~x%y2$xN~?|goe>|K>QELeVm6Ji9~#gWvbqgdHH!L ziYf2&JW(7O<$TYMQBiedD{#C=l*Efv9D=3rhT|8i=_OK}qK@PT6r4`sbE>HqU6s&^ zB8Kd^GlBY^m>a;yM?Vy{&us>Uof0KVM{HTj43ru8?`A+c$UdEZ@afFNYdziwP>E}x zFQVcvrL|-nvC3Fn7e|A4N6+5pBxr^uun;!PA|;!J3?!4&{v_4G zPS}too1{Ot7Cyd5b{4)C%S%_|-%hWJa zw%-T_h0idPk#r>u|I*H$y(a()&<^wFz+>0Z>U9tjwzRmj=#)~X3U(rEgIdZJ0BT)U zZt>!LGv_((wt9#kjp^{ifGYiteI1HXh(1hLN5oD?RU_mRzDPI`YMD>7<#+Y`>XaAS zpcQK8zynZv>_jyrY|YLj5)ev2cIuRMautB(wie0~a0i_Nx(}*b^MytMh|BsLDS(Hh zMKENmSh8T-#E+FQEByhFe=W6HRYvUg#Wddh{^rAf2HLB7xC(A?CY+&&6ywv55)!+X zd?}xov~URWN?=kOsj9dk+?-#P6C1|ex}P5D6kA0NDl1vApP?))Y=`5T?o&^(7E!jJ zZlf;gdv1C3G#NrOpJM2za zE}N$pQr^sRG+bp9tPA=oAhv;GSGTJ)-3l7Qr^VudpY~Fh8}I1Z|CH?TlccDgEtCh+ zr7V;v2_ux#uTF#%-N=xo9ZX~hnjncOdNow$n(NwHxY5AF{uc=6U-3$KUQ+|YZj3SSH#nP z&EpY1+m71V*9k?O;<<>F;Jd-=r1_T#nb+$Tp9JE&%|jdMq~aGbwc#pt8VkQAk85Y~ zoc4a;yz5=h+rf8~fA}xp2kr?sq6-zKqrprJu`nhvg=wtErML_ma3!|0Rjh-pmo~7k z$lqj}*;Z*AyB&An_wa7KAAiPv?i$3s_zSilAHhR-3{T>V_zLcV*Ikp^&Qc^^1k!Ss zFOmT%w}d_^0scVob18Dy%XG}wt-E9PSSC)Nv(PK{O3z&=029{a64sFMHSvK97guPYwE>i=bu5z99JIKp~0#OwgTzm?!XK z9RpSB`T)8jRv`*8)moi}d8(1CfVgU%tbr=k45dJ}O7r`=HT2thI)iG;TwV!o!#|** zE9CFi(H-wiOVIX!zhI-w)>c=8?f2&l^uz-Lv`R|pHo>Qsj+C$_$hlC^JxIpv*v-f&U8z{s~Ms5a0j+ literal 0 HcmV?d00001 diff --git a/testdata/FF9 FILE06 58 04.mcs b/testdata/FF9 FILE06 58 04.mcs new file mode 100755 index 0000000000000000000000000000000000000000..b5cb2262b0f1550723f04e7cf5ae09e19f43f517 GIT binary patch literal 8320 zcmeHLeQ;FO6+h>`&waaZKi?*Ko8)bFHy<0w%CZC!AtAdV4M=Q-AQjO1x2YJY$6>Y=U~Un2R}F09NoI6+pIG`FxwAq?^$9VGq)S~#BuZ4UAqz7yE@nJz5~F$ zv2)k18Q^Z%w(VCN*Gto9Y}r0?#>S>6M!vLZEkT2vFFs^QWy&<;=1_|lwd$e6t+B(*VHS@i)jz7X z_-Zp{@$~$S9+vH+;@{AX_H}G6N0uWE->TIeTLZwEc!$T~b}(kyHfNgIDZW+z3?cG_ z9((QWCC{8t;hR={58vH$-kzSj%>m@{KdT(@XBqBr+OtDH6QL*>+IgCpS4Fvs+dW;> zf(76Jt7jC1seA`YKsFfTiA0CgJ3@d@p@$Y_@#deGn`VETAVIDQ;C)`m_CJ)xq*oQd z+5H)xpjY|I0<4!#wZ4{sydb1kl2$NuOfV;RS+KT1r8TP^84u8p0rNlxSO_4^^uvfy z^un)Yz7nRv5aR>qrLoh#F?+I+`D536w&R7Lbn)Y_mJTmbJK<%si{lQ>O98zKy?kZ>fFFR+O0Owr;;A`)sIAeci06}MM)_`YATtPdjt9{~L6-h!Q-dwWdY^I?}f zYW^!n8@gMrfTJ_pc5VhUGTnS5({9#n*#80rAcP+WxQ{lABGYuaz@6zye>bPT{vbRI zZB7?fsCijC;#(7-@F;+^>7|f_ zrL?QGoR*o`YF7+&L%@9u_PQ0;Tf?AEI&DJ(VkJQ?8nR@;0sTtcPI_~D+ZD^7tA_yY zg7r}G^|ta2B++Qp3svK%Oa{Gx^ygkvCPa+Q-cBpTcRIVFR`6}e@a)t6H;C>$!FX@7jzSzjO>-I6Y zMV(7Miqu;}$rpr=KUx^6^5qp&+2?}4EI)Yja8k*icm1Yq0Bx|4GMG&yIE%c5K{?4R zEXfN4q6L&L=m|Rfsw}U6Dfi{52h=w}FE5U4`3b3%&YQOJMLVp9hv5-Q^3EnL3KJ<3$C#XS)NG#Zw|^<>FS$>h9&KVZjlJLU)x` z0|m5Nk--I;PBLDOGIlDn7l%EtT7_eFg+?nUYbdw!zP#c@C|pqPu=?^MF=O2gGRj!XisH)M5=nEIoQn6 z>PG{-%8dt+SG-oeR0A)NKl!2jkjL#+ELosH&yOA= zXGoOtov+CM9PpX#kn}lrU2w$z z_p+}7U-bL3=&<9c@elrB#j%nec3kbopURhrQ&2@8YM8@vaWxcS2qX9wma~4?ALE$7 z!QA;c6o+9A*5YtXvU)ZG8(1Tb#8G$wj%H2lLL9@IaUy@YI7z$_Tey|@B3{F;W!G_2 zxoPYc?pFRb?oOP^(p)RvjlX4ch5PXVwty|<7YU1nhuFioge~Ql;Ro2xI&dvMDLlp2 zvGv>rwh`%$!`{G`*ekddx8rNL1B-DN?!ivn%iiPOcYcVE!anwKV1Muv{($;vzZ1o~ z(S`5gP884C>COV`|D4@cS4STJ)YJtXU9>Ir)cuF=E5G9acjDq(-E>0FpWlM%bQ&=a z+%dYwDbVtG5FA5bEDsWIdtC#C#|{A$#=fry6w7?d29hXbR8U2!NkzL|n5lq66vntn?%!Pmd5jxEvwK9- zhHgpfaH8yCNeSpaZ>p#$P9p$@tX^iI8kD_0@XPkYh3NGor`!`@BhAP2>PE_4c|;R+b3smWZF zgYLC{vMgTeMz>&Z)Y0pA%?v}aM;#PEHP5*x7YZfJNaP_*r zKv|DH917JzThd>_!eF*d+(1$=D S0(}VdA<&0F9|AuJ1pWnMtJ5$5 literal 0 HcmV?d00001 diff --git a/testdata/FFT FILE01 02 28 48.mcs b/testdata/FFT FILE01 02 28 48.mcs new file mode 100755 index 0000000000000000000000000000000000000000..8ef0a1bc2720480dccae564b42cedb46a5422740 GIT binary patch literal 8320 zcmeHLdr*{B6#w0QunRs6&X{s5MvVWR#$S})%wcGh%AG9kk!O@Vjv-jRT_k8!9 z-#zEvJ?F~o{&9}@HY`i{oXXSdmI%z@PiHuR1r_|5I%$j>GdsCWD{Y})`sJJm_ zgO3I;cyvdh^;l!e9K)QFn#PvXg+&FY3hP?O%&-=I+f>sU`tVz`>ps}k+LTvS)Uu|r z>2&oE^DnP#JawA8TK-G1b>vBWSX^9O8SoRzsQ;CnM0IiT##8JdP*Sq7f!_-fXsFy* z190c|R{mZ?-S<1okMHLqBMwxRFKopqMf@a%?TUkJu;q%GuaD&1b|a)EF{(2W-J!c< z=j?m^15DoNIbzxEog>9lW?-KaR=*K_H~L)9_&o96uD>~M*s#%2QHg9+WG<%(N(|QO zk_=&?p(A)rL;x2#LY2zL=td3?ii_leqXUD6r9_Sx9ps>UG(p+{!$nsLLoQ6S%s#*g zM*gg87Ot5Dv0fj~`({m(Y+A`?=d#rXb_tL`ZjuOIXeZae$>_Qd4-eJoqO;%X#Id;1# zS(N#ZJzgGoLfrH+doY7ZrK~LlDd0NrnLO42yg8jk!UH?t@vH!WIDpkygr#_uK4n-y zpO^4HR^kg35qCX3ScRWaLUL`L1=>%h0A&YnQ{R3go!J!|EUoD=YACky_& z=!H)X6!#8hgu{J2GawH&cm>NLMg)$ap0I7lvsgt~t>nL*gdK$aI2s&spOTlmmh)GR zSKc2Rt+U;yR_PS6+QVM>%#v&vm7U^K@ZW5vje8Lgya$aopd z=Z&uXvpI+`W{R^WhF+FyX9)Ez6}NtV9r-mn)wfv4o|9^05laGY=BJ z!&C>A5~2fCC#{Svn zFOIj@2aMyTt24v%ICY+b^oDGZiWm{KLQki1h;Ho;{Kus?!4%i}TYWoTqn!cb1g7(U zq>lx^(P5*o1g+RkLKq3}NrdXysn6MWNZj03(B*kl1dVTt-Fla}hpy3GG`gF5zo;-sr&X5bO_PGbtvQd z7%Ba;Bp8e z6(2{+oNseTQy$q*a_YY|y;PT;nqy4MFc{qW fIbBXhR+u3xH`C24(B-7&PtTa<<_wJnW(WQSDI4Bs literal 0 HcmV?d00001 diff --git a/testdata/FFT FILE01 13 01 48.mcs b/testdata/FFT FILE01 13 01 48.mcs new file mode 100755 index 0000000000000000000000000000000000000000..825a4cbe6a619b279525b23540988a8bb57c053e GIT binary patch literal 8320 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 literal 0 HcmV?d00001 diff --git a/testdata/GRANDIA 1 Gadwin s House 272 07.mcs b/testdata/GRANDIA 1 Gadwin s House 272 07.mcs new file mode 100644 index 0000000000000000000000000000000000000000..ae225f151252e2c3b46039a7329ddff7d8993d25 GIT binary patch literal 8320 zcmeHLdr(wW82=6|vJmRMfWuQn({P$J$9!N9T^=iqk*qAMlS2tYh>fi%3Rbw>y-`7p z%8WHi%xE=@SxzNWV~$~fzU30!w~%NT1~1XGLDWon-KvRa@P zt9i}})#5Zk=2WZH4Qh?L)>)*khh&kuPJK^ZufBo)9CfZb$2n8YQs+`u-zhRm%TD*2 zcvY?Ty0eifXF39vU?oziQ>HtoY`MB4_n_ACu4=Iw%#%?qADhi)$sB9xG=l>@%vrN+ zv33eQNv-knF&R+u!In72=>^wtPMhrZ7EW6ojyA!&T!NPm&bFB$mt;AIQ#yWJr%g>d zl~ZgsgT)%D;~Rkgp_we8z!wzwWU+p&zyd2NnNe5bD1wHT5dCW)f4o8BZ zb~pY7m%x*bw&}E~*$dwtKgTC;d=mJ&9`VYO41B3!xZH?5Nav2Wor{Bb*Ll}YB%)!6 z-9Ds|Nv%5_j>coMw7;PR_%YJk4KCovO0mcnr?S*^D90=k$>ZlU<)z~C>V)PgVez6} z9vt8NrrsbI(Qz9ka5qy1Z)X&-4|~=?U5SRFr_=UC?VGtUBKmYxbctjf(jHP9tYlqe zls<|?3&UnehKsJDM9q&8sVPKf=Mgy^+$Ci!&$kyY&QD!glAgaJpD5y#5-1dScsc=G zz*9d!@z@Mwtj8iFzp#97^@6U%YWpWMK&Wt2Z1pl;?2}7ABjo2TFk`;pL)$&!GeK z9ktOF`j#b8D3!4!mP)JG^Q?r@+55E6y&?gDSPOT-$~>?f?CwFcXcj#}acE=Q_%Uvq z;q;v7@x2!`i0GSPx*{~xU|_5lKNI+$(w}sdqF4dyQdY{cP;*i1=_mSwUJx^2L2kz& z@L8ZwtDfpH`%(&KOK22oZ+Tcmuk%JD;`9;!3gCYR{3|q?6`^LawXBS-Ve`>j!`@+^ zvm5~xh!{Ktp^MWiGE-(UTR>xJ0&*~}=gsigaf)HVk)T~a^8L(DsL;@$pz!iKz5w8D zbeO)Uv)KBXYysQGN>GJizlT0r7a|qhC3TLhq)M7ilc|X8@MP;ZhO<0vVIfh}bx2oA zk{f@6j=zpt=nFc5H!qqMvutMdfzJYZ6M!DyYV_qIBQvscM4ycI4C=roGA@DQDth-1 zQTW!nI%ELmZ%`|3rw$5av1}*mF4Td%^xc2KMA6)4+oM%fh4{zg4VZru{0L(_om|w{ zZNw+lE9VLPne;0)P$z}3r&u{^E$S240cCy7fz>yDY$vh)`)5^91zBh+)zCELAbEg^ z50>R&eCvho)mJbxbK=C9nD9EA4GREyIUS*|=r0Oozp%xqOHlW)ANry9p7R_+yRK=X z&A6;}Yk&W|6l`}Z*Z3+=wo{jqZ1SZZK;9kJR~V%9a3u-_AIPKE5_=?6&7w!@Tsm_G z1YSdbtb&IL?bapHIHI|EFow(K!FAn}(y$c}`Du_tMcHUY zgzv_0kV~NB(LDZh;XBdo|03u{H_z?3j^pvZXAT~l0O+`U2Pn7WbM?%N``~>G=2#6I zj-83dZDvExl`1gnZees_k{_~W7BmCbN|M%8^ r|IqJ7{`;8!e#-Cf{`m)*%oQ4;gr3~aYa=I zlw0s1F3~8bHpg@MSE2R!)kRBb&sjS82AD(7$COZ6Lo^-a8XpB9%>b9TxzJCq3#e@c}pFYy<63|>R0g%(lg zza*zJ#4qIKoJjmClbJMPmqtmal9{n-(%I>FG^X*#g3*E>G;m{|U)xV{MjlABdR|H_ z={!YVK@5fD@ZuM~f3N~mW#L-NboEk`mHtib#mO?==QkFMgUC+b8S5sEuH(Up|DaPy4DFg4Y#Lg zcZKB=ZS2ui;a}x#ZXDXvMb9|4<4)W`zjs5!%MpO1*<#6xcOd%g{{7ZaSfREDFv+om z9h9YRF{u=UQI zoBMS04}WF9-lD~jG|rv6p3p6z8or{1B8TY~j07n!{a@C_AkgB)PYy{ zmn&c84sow@y|zKVk2}J@#a*VkcaS4v_-PRW;RZ`}USsR+6S=mO@X{YKrgVJV+Frgb+JI#U_49mOLiR^n_;!BZ{4*>u#nV__Te|;joLpQ9@}N{#qKi4ZCgT|`1!F{=$aB+ zCyH+gU7{#HE*6A`SQeBB!jta`Ity+If?yL15dPThdpdjVE?>|e=n26l0GcXWUtzOa zE3IuU@I8!G01ZX9VLLDszGsRC)?|Wia6=!eBeavgN&|ce+o2cr1pSC2`sco*J<6`w z^R-W@g3H%6t*B`FD+ZhbS>DGetK@};1IGgDOG8J@)~^);lvx4DUQm4XD?T?qhtn8> z;a+*3Jx602pdD!QA53f0V4IjsVA}W|+r*c6WK?O!S}`VcHSAW=g)2eqxKqQ$IoO4y zhnUD&O_z|heY1qdx8Z=(+iI<{6(tKJbb{_iHu8fL`k@gjpbF|SA3@YV0|8()J+lY; z`FJck|12q#EW#A?2+J6P&Ik8FAc zcH++o9T@32X*Xg7sge-@lZF!vd^8?gXpTq;3orr>sxU&Hg>X86yUtV!KmPuUIyiEI z#bS~8Lc)*|^2};$=2x^KV&<fS`UE*&!jbI3Yg3e+Vb2b`|@x%UnhqBuK5LYv9G?bTG|g zoS^N6453vszP?hgiW%wntr$>~`};~15-Ti~5Zc2~VNSV3jpJQ*9M8WW^K!_C)tIjX zg3mtEzY%iZ`}jB2XqhU9?(6IRu6cO-Q)iQLIiZc literal 0 HcmV?d00001 diff --git a/testdata/MGS EZ 01 40 U Grnd Pssge.mcs b/testdata/MGS EZ 01 40 U Grnd Pssge.mcs new file mode 100755 index 0000000000000000000000000000000000000000..a4a700a1c365d0b4cce0616c6af87a7d2207599c GIT binary patch literal 8320 zcmeHJUr1A76hHTF=HGO?&PbBlodyOO8?Koowdt<6K%F`VRu2_O1(k*Q5*cmR!Vy?# zYW5vD*)pJ7v4WX|M8CQu3c#o4?A;DVLOUN?XVsx~#M)*F&u#x8hUkL)D63 z@nPH^@*>}>+*592c13xBPnU9MeftuPk1c89#gdohj_NO#cJa-=a#wCv!1Tn zM1CM3Ic?Sv0{*=Kg(KvJhX=Q9gv@4w=oBy)1KvVm40*{}Xr3jF0dJ|z{DU;07pRw< zf+#Fe@34(5lLl|81Iy5JHsJ|+r&wejBgBI=_mmK`*FT0{t)iAOdCJ>`gMMvS&a zc2->Y_8q_l4q)Mvz>mus%tJ|p*W7kopH{p!a^Onm;A;AyX+Bls9-_nYKUr3cJQIy} zy8vf20#1xpVSu9PTRa3Y3j$11Otqm5+%v!wo}79fCU8KIQmH+t1;9)WO@b>nARxj` zQk)zw$C!sh-=<^}OX}7%vZ%G9x&>9=X0;T{{U@Iw*QdZ@ut*?}7YV=*3 z%4((K)|%sWvW~Ts)q4C*QX_bD?76E}YCI8Fh}441D@pZD#~OW}CVix@$y4R4gG87< zXp2Uyf7D(a>mSvok@b%W?=kBi6UwqdkoAun6pocK1(*Vxr~vC9|5i-aKWYlH{*m>M jYu_c-Kd!A!@(k-Alh=$@Fa?+bo2>xrA2(akWas+@S?K2D literal 0 HcmV?d00001 diff --git a/testdata/MGS EZ 04 45 Spply Rte.mcs b/testdata/MGS EZ 04 45 Spply Rte.mcs new file mode 100755 index 0000000000000000000000000000000000000000..4a12ce35acdfe06f866e8314de82853ac6554619 GIT binary patch literal 8320 zcmeHJUuauZ82_D{TsyP1O=7DpE0TYMRve@xOIDpTS(9!f&H5(^i__H!MGDhZt2mUY z$qizV6|8Q>Q7FCBbuw1BiJ%XKcGxF}W9&iP=3wF;e3AJe(oVbUckazyZ+#FUhz!nm za?bbrzVn@P&-tBm!q*2951?t=;+gJTW@9k8sUy5S7!Ger4a9lpe=0+nP8U;NP@Y#t zim~F0%AoRk@jx-A^eCBPmy%Jkgh!P3sT@|05q?=YqP$Z~{QEU|?I#-6c=vC-*wNl~ ztKn7ecWoV!2iE1BUp6!~?rENF&gGI}pGVb@*#P)e?c2D7m`~NNu7x-3Cfl1!_}%BI zKNF>C~3g z6Df)MJg|YZ{o3%-n{TjQ`$KF>g3V56N)zG=PO&D6@uQC7Y9Z5SuHb7H(0xugv7Sl* ztWq>>HPSShX5u%bhAN|Kh)nVK)BFsbEv^3Ve*lIUaN{Rn_XT6Ywb*NbO52S4K-h<|^(|sm4IRwk{mi(NSCn#$=k2o8!E`i*eE% zwqSEZ*|xZN=ubd)@_-h7mmFbqbQH+f=@?N`W&SHu%cacldwIdYz>bU$-e$sT5 zILRclZJQrA&_A@NzWN2HNqETVPxL@;&CSfscvlVEN~^nxF~;QU!5zOHUkXVw>XE`8 zq}Q2&^x*=>F9mCX^OAnzX5Zhm$7<`_w>mi9r#q(fmYRtPOyCF=Qv6pDvQgo^+w|cC ziD}TCGN3A{PFj&HNlca*Y1u9lk|D`9GHjA8F^Nn)rrfL#3f`R@`0+_hPfzRa0XopG zg!u)qpY;R2YyZ!{y}Y`acqHt17?uWf&sz6J;i_=?Tn{;w^%Z-phR7eSY*dRy{#Y%8V!U8LFi<@MB7dxwLy_hFi)t! zb`c5DD9JsNf=Y}G0?Z5E0ZmshWIpgth(S@=nQ7BIVI^Z@6UK$_jFp^Rl!3IfvXP09 z(8YJoE-osHN)O&SJG-bDF+P5043suzeDIFZ*;q-Lal<qbOaiZ5 zlm(3#nFKB}7%3|=FfnXoP*h}6U}6w-5mIDy6k-r`;9_9d^7WnOU+wBe*?{?dKZ1OP%28en_1`ht;Za-`9um-SvxB(Od3jYTJ1_mB54Pt`; zGXpb_FA1>>Y%mK@gc-;JX@RKu{~y5ui7>&%Ve$}Bgu679Z`@&E$N<{;;4uTkZ8wMv z#AOIoAQnjM4A44XHXxh5NdP7*1eJsFvCur2Vsd6s|1)9AF&u!4%>cQVf#C?)9}K`~ z00ufk14x=5L@+R10@95TCJqu5LZg6sA%HDykZ5`XiR$U7T#Sx(QNb!`?!lh}VD=n< zF^HjoB^oY}!eGa^R>DU%4Onu(04qa>aD;S$c!4-fWRxBafzc2ct|7o`?(FCr;NXgwC7%3qz+I}49 Gm<9mBB9jOJ literal 0 HcmV?d00001 diff --git a/testdata/MGS NM 08 21 U Grnd Base 3.mcs b/testdata/MGS NM 08 21 U Grnd Base 3.mcs new file mode 100755 index 0000000000000000000000000000000000000000..6b4cfe22a09ddabac168f85365833e43c90cb03f GIT binary patch literal 8320 zcmeHJT}&KR6#nj=8CYsfmt|?7v~~ZY)daKbB3lxqJM3<|Wck?w4Om+QgN;U7@h7Ga zSa*kNlwu<`8ZcClw8BHN)E6}|g0Vg|YI)G8@qwh88k25JeYpe-68&7s=(#3j5i7iiP|xH=9m5!Y*e4!zD1Qi*xJG zVRycdaqAp>ZZ|m2!0F@;j{LCA$y6KigKL0+UvthpBo1Q%=8l%!bgZtjibs|Mt>@Zf z?XkVFJ+TL4Rk8bH0Mo-9kXz4Pf3D}p?%b;zzT}W(iqMAm7N0T?U9lThD0I&j@|R;) zl+fd$Y(`NrW}d~gaKdHMTvCbD5QXycXn%&uk}d9Uz6TzqQsyrJ?NpVJV%$qnAtDb@ zu>pl-KfKd|McD$oGCiV~h{=0?r%X;N@(@5d59Ur(M z!E^q3js(pTP-l&-9IgzBih;9w?V#jR3ME817l(zpybeer!7kdtE)d;B z{Pt4up5F+4vyIA(_x1Hr^cbn`=$SfZ1PIol*{^gX2HIW7FIzr44jg}xU1fWbjvWKfK088j{er^NgnVNQ__4`WyW^il~!!pH59B}HM3 z6yzuhHwFkJV8Xd1ay~B5mv{lY?f^aW+wxAIo|u@R`61F!I31v4|D<1VcK$y*wm%mZ z(j^$=rMXS&WC%WVPP|n_4EcYn_7h-oxlChndK$P*raW;>hK=bJS8i|%{XqibtcX6p ztT@L9$nQcmd!=Zbd~JM<2Aw zSSHD|CIcn|w-f_PAf(pEYa(@ZOJ!RF^^safU2VgTC9Eq@uQsGKugNF?48ZE93oGOMG323o5&N7W1hI0B6=YN)Yc3At50vwsvfXZDXog4sW2KVq|g z%u=xmj@du10;%SfCIcn|D`ddzA6H1&Khn+qQBY#`k3@pmKW4uUvwzG|u?mjaKdu6) V=9VS{CIc&E!0aDaNZ5a#{uhhdE))O& literal 0 HcmV?d00001 diff --git a/testdata/MGS VR Training Data.mcs b/testdata/MGS VR Training Data.mcs new file mode 100755 index 0000000000000000000000000000000000000000..b630117d9e9f0b1e83814880f2d23edd2296ba35 GIT binary patch literal 8320 zcmeHMy-OTH6rbI*h+r`@u}QZxYX}y~Wp5R1#M8q{3IhR1XNYcH5w{PB?w=-|w?##aV%`<@|5&~ef zT$`A#^%aW)L+MPB%1D_S|7&?v8&iQ>bkE&VeZ;+UukrfEZMwQ!bsN8E88!1LZ@Kz? zJTVw2r1OQe<&lAqpZgm zZNe~1ZDM0(&MGFU#KFf_s*{qIO&?1W>mc)?(blMzPhxAVX?dZvw85D#rCJ(s>V>h| zh^AM{24T?f7E4eNSt-_97DPh^LL@JSJ6{377kog8ydUZ7Ex<6+EK-EDdjoKReEUu& zJ8C06)!+YN6QWG|PsquR`qF57eBJJY>Q$_-pbd>ZfkZZwsQ>T-;0SqMr!g*3NB5Fn z)HmHvzEB(4=l+tM`$9G(=i}zQ=L%rq1pPV$nEDQYArM`6FPG!N@!;>HJ=b`?@cO~) zDgR&if6Ms?=VP3oa=y;{7v9gc_no}IZRf^0CcyFFcrYHs_!#4bjGr=|%y=^6>%Y$( d7*A$AIX{QWIh|!OzRvhM61oH2>_g_m4n{>8#b7nKd5P`M-bf zv%j;?-sf=-|9HS+22hj~%fyVy6XW6sJTP>?$oP1n|K&^KL~A$6`MlHNbUS6|O6Ow4 zan3A9vU8?$m2b0TS9^l{J?Xe3;*KqWR@V3(A_y3g+%^wq1B`dSi3r2ez}9`%Pb!_fgf^zuo_j z=km&{&c^mq-nf`vb!kSgC(e{1em=wZS$bL3C8fFfhY!cqqRX15#-^H=RsUC1|5sH1 zYi`p21@>>d!2WF)*uU+{3|aWMUHRN2{M)Xu|AHDUO^v5;6g6eF_^!skM~%N$jen0C z{~k5|S~dP!HU6rz9Dmi>e^C6kvwdQfhP-kc#@`3yw_Q^GUsC<6@r#t_pF;l%7HJ>Y z3z~~Ar=D*I&y%Zd9P-+rkqbeM?0WOJy!7;6dE zQmkvSuEV+!>sG99V%?5)-JoFmn^-Hc9>97W>wL!=$2!Lb$5w~e;d4|t03-?Y@X&}c zQ=SxK!?N>O(F-&3X5$-38q##KWF_QkOj1(zQ?&cKA+pw;s!swb?5nLkGp)mr@F>d-D2D!%=!M>*Ar56N zJaZqww_yN1AOvMSxX?Z=5+DlhLP-y^`y;x(LP26~Dg z;6XjWF-(UJ|3pT{8vr(o^!%u-e{qFr-Ht%{e9J|jKls9PKWe^75x2(;7p)PDl1a~u z_Pn)tDy}m?K-cvse&;5Pw zGY8|on_K;EU$Nfn6kGWgQ?dOdh7zN}zc9J}`12)Rd1KE~=x$BROi7J+$S^A4L4!d* zO#zJ@DM6gH1-j|Ht27kogDrFQ9_I?Np%F?S0dwScBa^rU2Kl0McD9v)!4!_+@cqY1tX;00+GNZPO* z%fVyI>RWkz1y8hKrn^U`r%oJY%FxB?!^5%-WBO|ii{Fu8l=K2<^wBw%V@G$Ebl`~= z97>Piw6UYd7^4El>J9pb!w285(|9&ZFh<${THS3qmXja3SDgBu$Js~t6Dj8gzYglJ~wNQrT`E zL<@i^2A&=>X^aVvtVpb(@PGz%T_t!&nhQp4zuXi|=2c!S5~u|rAhQ4Hq_hzMBlW!v z{lbPC2PS9@Cq`-@QJM`V-2lv|So*5JUVR9?7oV7%5)yi0=q(n}Da z83J50_PmllXeuMrQ|2*7zL*(kwWX(HKU!y^1z>oO z=)8&7STAQZxLyq3w-(OJgGhimv|gg4l;J6(EP60tP7Ih&#YyMFozgl`v~Nwbyi18O zi@_@7593Dm;3y?|P*Rd$2rmA3E+Sq(DFbg3p?d<%!c}eZ5%$+hME11rfKT3Xj;?f1CKJ5{HdmW>op91MaPmb3da*(QP#z!WmiX8CQa7+vy)5aBRc6r*8pfY1i38E=)cFWEd0&#EA+IUV;# zFROVvUPWZ98Lu)6Jc4>AB(MirCZ$~89u9M7 zeO;uS`8C0vM+xj~>BrrK{_bIVDuah1iaivsA(M-_1Ufw7kuYpM!HamIN6F15%kdV4 zlIvxHsdEU{;#WXa`YsaqITKC8NYcDW;Bgb2UQSTK!@V$-r24f4i+uzhKf&Q9f)+e0 zu7xxlKRRr^1C2-jZ zJnTsAES@9s;t_zod=p1d&U2K32LvkDb0~=%-$I`7I8Mmaon+$Wz=}D$l^jt9?i{2q zQ-e+<$;HcN4m+yn^tip$CUc*ql_V7-AL;#;5j?`91|CZj&q{SYwbk%UyBG@AkWyVs zHJlzBw*fo)s*X%tEV)WaTEtx!7myUngdm;(w~hPchyuPMNn(PV!M})rn%dKVu^LSQDIifoJc!a4d zZ6Htw=>3Ewe*i%gcV^}IN_h}6FH?+C&}~Nu0zTus!($xVT zVP(WVvfR#_t8^YoYv&Wh^2oMw?4_JK4-e4ADL)cHmhSBY9yY1s$(hUp4BAR2$AVR&Fz{^RtadvI^tAMEs;`ls+NCKWXxq}DbS+RS`#AhQ=cgKz( zl1h0jJ$X9R^mu&S#>xOYNuRJ%=CLe2Ny<%3Z#Y3xF-tx+spQOOF>h@pnW!GzyaQ(8 zZ5u<8*|LJ;^D$vE6Kb=_FNW2EXEB{CGIxCk}u zw2Fa^bqasIXX$_PDH7Ae7k{o#{_dV0?R$^OyQ8ZDSIbQcOTFdpLjNFt+Iug>`X=ZM z(0KbiX;=K}`k?xL^1P-JkE@{2=O5*N9ihcciaVzp#urKD!y!O>c} z49QGQH)o`eO>5NvJUJxOGI3Js1o}{~s`m`eOr4P3j)?j%29Hcl&6+fN!Z^#MRfg`#CAH6pUN4JKP>J4ZKczy06;{SeTk+_UXDd$z0h```cL zcmI$3_`YERV2cG%)zp-UVngb)cDvkOx8h#wUXJt* z_XJn6d#?L=_XPJO9L;ijThHIl ze<-)K;#6EO^~E!p6=&!4n)Ou)(vx!nA7_?SoK+hee|-OrYIIrEP~TAXq~^ax^WUQR zUw?)EPYeH!)55>wwD9j}nWJ$3j+T=??%&ZO{O4C;Yp6egQB;*w<5)TJ&B`%rpE4Eslh1iR* z7h~UmeIxcQ*tcPS1^cVmHx3GQzJk3R`y1Hb#lG0J-nG%S*|p8(cLiK!E&xdaBiueL zYwEo`Hf%eOtbAln?tC19q$9~?HmrnLoh%KXHoN-GV`QivSiR~|fz=y~onj@#T3~qc zm}%M1?c9C%xT=;Pc;?|bb93h}P)$tk3=8NOLh<-_YyxWzvHUF7dKqkJnDu9|VVA*% z+q!gy#dIZoS1D!e^!xHw?Ar6zJ15l2nl%eW%n@B9zx?Wpug_qef52WS0ep}BH66g$ zdKB<{uWs{u>+y8p;-{>-q0tbFqo<1lzCgh1Y4$=8{(MbScb~U(ldrPMSJ}*VaPzz3 z03y+_rw;6qF(zDCTpx3Y$--pFuY9>Zep@eyK}&$5Sb&i|0eZo;V1g*f$^cl0vL28C z1`ObVn*qKJ2j~uAs5io~YXF+>}mMn?21rcRl@FFklVtwQTz!(HavT6BENa zv_&r$oG88~_-=Q9^Q+eF5QxMj3`a={4fctwDE5@7LJ+>QSP zxP>dU#^q-}2UuQosF1Ej44JJ6Ry<0`*4w8+0v~TqNk0X zke(4`WsxB_nG#KXRM06=5)74IfvyJQ{Zn?X++Dt+Qk>-*c$Qp)@pcQFG;ZQ(lgXB3 z%98IiT5pzg?grN8GN;Rvh``8UPjp+2bc?hTyejL6i&wB*S|Lk zgUN7XcJkiWc`4hi1J?k^F>rs@q%0Y)tSIbO7^nk77YSaM76Q}9=cHmWFW~S_1=0YR zqsC_pA2rOJZtQJ}4rk{sf`w86gct^Aryf61 ze<4oVXIuj?q+3|-?4Q_Y@9X$J`=Paox}+cg+hXi;Pj%MB(NlO`Y;-FOTut}FYr1L(LdJF2hDq8u4VSPQuNS>Ot+gV+O8Yd4;O>A{@oZH5x88 z!-U>=enwDT9dUbJ--nn>aEW#`{q~WmGQJ}C?S=l95N^115BmGdj5Knjb|=ys9Rb$> z5H70|+-^c#g1fbcI^wp`=^{oG?iY0_`Ae0?gQ|ZeCk?-Autm_5&L7tR5H6z=9064E zNzo2>TMu=@pb;Z^C9T-apt{Llk#s%!+nl4VgTT>w;2HqJrTm+?+pipV*;^iC>8$;) z;8J_4k3Kju+l;qM7d(UEp!#SXcIn^7dqON8KE-($$}{E~0A0J*#-O5UyZ4(Xj%*GD zDt&>nXO%!ZJ6)S0_wh&U0VNnZv$Xi*yblta>1{_J5*=Q8Xw}yE*C*#V;p5iE@j3So z`ufA=LzXHv8y{;!bR5OBW805g#ay-^=X9y}xorVz^+)zf7pg!5^51Gt^ioL&b=!wx ztN2>FmN*xIH@vEDOc*t-GCF0_WMgnza?yeu(EJzsecO$PMkH@lzuOHrHZ_-2Ztwq+ z@1;5GpRate%*Wk^TJT}Tj<0k21jA2LyfW}Tg*^nj2|I86izE~~FFeC8V>e^(m>a%G zuq92~TDilg1Okfi&*ucmhEUyHKD@Z8Dvto9TRO4e@qyI86AK$zBz0oZg)D}5Vu9sE zFXKD0=t>rMc484p77IJExQZ+u>BJ(6EFSB`0>i}rFQ6T-Ddo;F7aIP=CX2NwL5oWb zaOHGlu|`;2K(-B3)j}5dMr>U*t>0RvU!p8s>&RPEFxa0Kizh+9B`p>YL&g_rv3M4&b^Bw}0hGZ0*wJ`b zS<+%LbVIMSSUd|BB`tOwz!D^P0Tc{oycX4ZW|PiCQ3kW=&V%2|Z2A@`Qkc!q0)ZxG zGq%7H1GAZ0;9U!|u@=xTVK(_ZtSMkN^Lc1`g4ysGDhC<(0BS=StVdG8U;`dUKLaeh zXEB3PfX_c+fZO5lA_g1L1OZs`#3lxt5w0+J5lJnBEkyX~Js8SlJpDI%n2g(P?&nOt z7T}u0OpXU|)-w5b0Kr5irvludFnKKg&OtI2z=!1b0MQ4TJP&`OuV=CY;7ksamtrM` zF?l6^Ty0`9hWq%-%#Oi(*E2hA`PH{Edn|_gB(vWPFns~D-wLpykl9o48b8DAW6+<0 z*{1+B3}NKB>-g}W-kCZJ)PMVOmhRXV@AsZZoWpopqnqw z!3H;9oMxT7H(xlPyEh6STk^%^;HS zAdydQA|h1~S@aAMkCTWGGj5x#-x=ckcsNn`O#+e9Pl$}cJ%hqc9wJFzB1VKR~1~he$cz2WT<|7Z1rQq4OmX=fT>baDi}CJDoVMpNJynEG{Rm5b6>c{RVL=%Q{laaRAaQlC z5%CBQABqx~g$JL&Rc#hHu`0!W;%e{>f^LiJh-d-&KO`<_CK4?sOB4AOi^&u`t%&0d ziQ^CvWf_t6BC;wx$*3#+E0G~z5LqTtIVenUE^bmQYE~$O0kJ9$;m?m30h-hdA>t7p z>JAcDC}Q!}5;s(2tF7&Jk#|{f|#Uhq&VmY+(_yR&F zgk~pk9}1x&VktOA!j}ZR?kI7Ef(rg^}u0+o>_sPC~z+SPAet)(_zS=3PE^W-lJ1V;v^ygm4*@qFgr+HV#3tpfjl6)1ma H^Q3`Ujfpig1M}KS8Vaa^qTwwSu_xWs((sbI;n<=xqvcE* zqGHZB3aP0vL+iHgs$2p!%RzY%@=GyTushD=P0lw8laoGy<`acy#~ zLH>wqf^)cQzUyVzc-Lg?&2qV&BV6OLH{O-y9EIbPu>Yj10G~5|Jj8<$-P49H%#KmU zP3`ltA#%cAc|*(sDLnB-iyvlN^YZeF^YL+oDw`Uw(-l`TPS2>%sL$VApV2t>bmNNp z?#0FRW9wHGH=c?qZY;|GD6ipE<8w3eiyMpc7awS}UwV2@ePjKH_KQ~&=DeKyamB@d z-hb`s+>(lmz2oVtmoqA^%!{9Op&0qud4bO|iYuVR(JyMM>s~YMXs-9E*x2XPG zRR3FU)Bh#m-+oE>w_g(e?Je^Z=HK3O*2nzYTZI4oDr^n)XE2JY;%e-x`5#pCuU7Lv zsOEoA&A(dBzgo?|;-bjE;^H-)zx`s*-n1^a#E$v*#Qg17RR330|7!lM3L?%d+s=G@^db^4tFXPFZ~l0Xj+C6Af< z1d9#ZzLV>g%*$PfJ&-h9bBhftAyy+x!=}xye&;kdq(?Wb|Bb+Eb@~pm5@Jm-YiPy+ZC=}is5*IHDt ze1FmEx95u^fvH!RHA7>;hP~�bd~CaW{J)2!Fh@sjJUZvfWo%<*RHadzty8y#b=o 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 literal 0 HcmV?d00001 diff --git a/testdata/THE KING OF FIGHTERS 99.mcs b/testdata/THE KING OF FIGHTERS 99.mcs new file mode 100755 index 0000000000000000000000000000000000000000..be91b58550aef43524d13c8a3706fed0de207c74 GIT binary patch literal 8320 zcmeHKZA_b06n@^XQrH+}z=DHr-C%Rk%oLWj68UIXnnB8Unc(ISv{anBfv7=)v%DC? z*T{&`fB_-R9Q*)>AxmV51LOF$kj)<^%(zIRbNa*R#+ETZR?mIk78vml!I>?-=k}g+ z?sLvPIrqHneNT%)WC8+#J$85AKKD*@%C23h4E#^%HMb+0lk4T@Wlxh$J|x%3FUwxi z4$IZVt7+{eTfOX&>*QCOY)xLdTrOWxW>cZ-kFWrt5mw88=rXoptp; z@tqsk%3~{)prl4{?a(X4yXD>5O9c z=V@l+_=Yj#k58IWgm7m}|#aTHK|WGuxZ{>M~O5viQ^G(=+?8S#WE@ zdZD<}!Y7%h_D(A&n3+B#{KH8&fD=XH0MD2}PJ*DUIbPHoOg7(g$%6%AE*$LRjUfQqRlmmw@%&D1o#zV0x+i&^V7JS zz5s@n(kO;TM}ajWxvBS1VsOLU9bQkjk`I0^KCmRn7Jmn=JjmpZ#b=2({So@(sa1hF z!X&iBuwmQm;~-QLqS8fP;Mql}l9w(d9(b}v03EkCwTdEHC?GE3OD-8EB*8%Ub0DB6eJN%@0*z$y=E%x; zXas`96E4yWqbbl-Ng}^+iqByvVMo%;w?GZ0GW$JHL0K_+2#=AK5%UA=*oZiiX7F)FObbR2BfaHsB^YAI} z7yG2@rQ@Y;mN9Tn$sOdplT1El4#PW4T#o{p;Nz}_0najkXah~YNKt_tBh|N&l287f z&=1Qg&7$V!X0pCVQ&AL81ycLwUt9~bB68~>#Ds)6lGR8Gk>^!N7z<%bm=RuXOO)7D0Uk%;SU=ej#P28cR325b$t zzv({sk!qv7D0>qv65?)VD%c5yaDpvVojB8I{mEy)03$Sjk7>|ngy|C_6C+zlE>b3C z_X8R^PW<3%&W-W}GyOY>f(!fMS!-ioL?UVmd;)Z+HATV}&d2hUiHfT-#5vePYEW{) z9w)egp_PhhU=it60CaT$y1xeyKnjl4z zc$I+(1{2N;%;&8756TS0Dtm$2*{twWrv?WHX?>KYBRgoIWB(*9==XuL{;&D@U>a)i zwEpovcq&>7S_S@Z70~*})jn~pe`FQZ`bR2));})%n6&aGI%cI`OoPiu4;wprL|%S=-+otIbK{7czn>@H{bR%M(G`iJerA15 z{q*{2^|R`4s=vN|%AB(L?<4oU`l%>Qmu1v^xBk94mGvWH`RVmDQ8S|c%8P|FsA5!Q z2f?3=gw#P-eUhJ>v7U$10cELj^R(jHZBw8YhGz;YIhGOj~K)7q`+)5jwH z)z&T_jz#gQHJ*um^L>RC3q2D{f}XAgi_^9?6;^~cta)l{)39*CrnQTk2JLCuv+d}* ze<1(Le=YyYia7uB%D*;#slj6b%Bu`f1TibJWKuXsEY0#xUOG!(dOsbheKdNaVo~(E z++Rhv?^+X`^ZJgcxZ%O*bw}!>X+KJe8Xr>h^mn!Bv`@@vPHRzB_VWD7B$ITUyn({X;=D$9aBg%rwle2zk zEY0E*wVBb+!2dho-_(Kso#3y7e;W87>A*h+{IlmD9GC5?x%M~3t1GL(fAg}fcV~lt z_QHDu;O`uA)QoIDZeEgCQ~uyr@xKK8(NN6qSe$IZ*LYRbD^%)d4~K-7hDCYRlw1OD5= ze+&380RMXM*WcI?4S@f&HvDtWAAfYn^88^#<{zA4xN0iyEnYo$$jMsCUvKBXE6%^6 z^|(17{4c$je_a3P@Gp%X0{^Sq_zUoNPJ1wVdmH}&9r$Or7Dd~}U#&y`cSHYe_*Y5% zG5#g(;|G5^{wKeV|G%yM9l1#V|6Kdq0{+L&v;Tjh{dJEHF<^hk{)P4z$Nz7)KOfP@ z;YxDA5R2HWTT}TmL1krSbeGv`9(Rqd`*P#wwWhg#=O$$beXJiYZha>G^~~1UXg?!b zGoPgaBh-D_QW_DdGMn|=J(=&+%3OQcQ@h^$R_j~OFxlIyzCOJv^?1S8zx{jOR4|FX zq-Y9>1DBBSO(4<#Dl(Rm($_&Ehj_F}tdLUH_HSt+v7AYNlh{VQhu9$g4Y8B7pA*|j zbHwT&AV$VV?4qC|pWK}|kvN%FmJw%>;wG*m7Q`yCl{g~i@;w|D%XqvPAQEEL5Af%# zi|*o0?kax7Q;0d%bO`YW#8--0JX?0YgBP$>)bc5`y^MH{6qcWsJa{?rJkYq8cqsA9 z#F@keVg+AAJel|z?jar|&J{26X5!U+1&=5G0r55BexAuWkfcyN#ofVq74Z_{V%|u+ zj(8>U?}@h(gnAPqKfn-nfEX{r7(qmk+4ff@EG*a}tO5ywVhCNZDzh@6PKoCfi%{C@ z(N^G1tOMT0NQK$$QCSfxUJ1%jihI&{pGkQZiJnza0SZvmXndSphbI8T%UB>Z13$XT zO13N}o6;g-(w)RR8c9`YWb17^i7QDh8%Ery6T3;>Y(9(b>!8Ux3N~lnRnKJYoj_{K znVVh$+1|u+TVXq6N?J_|rMLxIuADdc%#PUvG5LK_R$D8%XOL#Lh358*On-c?P)HA*OcVd+8S|j5$|OIUkZ3XIoNck+;zA9Iq_uqFI!pc-YLrv!O<44dvu!WP zl$skas5x6y$ljPiqtBLQMzX0jwmV^py?ZH6*s9M>f-6@)2}tC3us z=CsY(%2v|eCQVwVCR~b2n#U6#Zh^!Lgr!2igR!Mx;hS<2j9$MiwgO^(!0MG9Tjyfa zKS=RmO4vu*A#gDi)hQsSQXDC6pxzKiCyz=x#tHmX5VUkK94xeMp^{PnUwR6R{&XCS zW?W99l(;@7HXyzBd?aU)wq6d$2sVVEaIgXsg{*Ki4J!lYa+IJQ6*_}EBzR-~CiM?S z6EjJy3X-_~zv0PwGfCVSThB%kR}ue=5L3S|>+SP`!a@@&7Bavq zp_X>W3g#g>E5vLJ?$}Mv#$Cm8V-q2?rNOY^+{j=p)PbN)dO6GsP7V#u zhgD^JJ50EkNlJMj)_vk-6rWP~TfB|5-K6!G^DNtvoDM@Ms@Bjj)7z%8R14WUP9fI# z6tWbHi;QPS-UntY%@^r~*tx7WyDN!6_3pdRVK)Hs$vEx|bSKd-lG_zLz5;zOuy?wE zem0hY82WNzh621W6B*BnaWnQvB&iggKlw-TLlRjXRXE7q^=lNjeXL| zm=2kZbO|`Z4g6ZtQR)k@o7Y;vFwtO*09st_kBYsfa8QV}^C~Vl8V6bj;c#~5b8o=wUsgGHSwE}V6k z1UeD;4?$pbg@dxh7Eb+ruP5Jo;)7p2@l&GU=*N%#^cAF|mT#H=IMK+4_gj97bHUKq zWm{G}N$zJBZwC_V3<3o7|O6O+Q-mqGiVHP1~Zg*9?6&`p0$AAFP>; zpMGTR-=nxs-oQfB>}B@ID;ebSsMHAnt5hl zS=N2U0|v?d-!l8iGIuM!v{;sl&4IFv_!^=>#CN^F8X9cRD!uU4FE3pAmF-UFmV=1N zcS!PR0dn}3{gq8Gu4L7`^pyHmOSe5OO|6BHLHKGHpt-7^H**in`Wv1hJYbV}RQwYzusT)}XLdYN9y4@1*q0xub z0;Mck|NV$*_9PAG3pjf7ZqQ=y$Hy>NoJ*|_1rrLZhoHYQFTP;bof*}ze?R@nY*v(G_m$&Q z3dTr{y@`^DfL7g#9{863A0Ghe=>qY^4*FR!FMoXb5tsCXws2gg%I{4xxh**Cn#;zC z9aQswfuD4YM*1_+A1vuR_aA66RnK3Vt=0FxdaCkt%{6qYcJ9vgWQJ#$|I@h4EM5Kn zMi?N4o*`N=06lT)3tPJ{_<0u36YCr0j?JLQSJ{cx_e5i4S9`?PWvl1L=trJ}JDCK37T zBWZ!moYXR2vB)M-h_D=OYym#k2bL19v6+Zhe6vA zGHpzu-XS+pa@RiLOHy;vWLsknP47GMkpz0%X63RZqb;SL z!_hJ=yC5SJ3_In!v~X_vu72jId-P)dJSF}&Ui{$FQB2X zTWTQ1<4%)xzEDc~ErZY``6ts~e4S__T}O8iw$T>`FEHrQR*8K=0DChe{(?jdMM|aP zQ9_A?RUsgomANSk$7f09h1Gen^;0i+ZyT;A*tZh!vBXpA6$X*C9^r70#AJu8^LGyi zH(ieYUGJN=<`oMqqy_W{y(KB07km+#0ArECPxhf<47u~yaZ%DnOR90nOUl=^JHXt9+baVM%C3U zebb;xbQuk&TO^C~0?x2vIz-x@YuBlSBOIaAMZOXuXe-<|Jtm@RwHo5w&R*{`BEd>) zjpJ08Y>0SD-3nkosad(9%=8?)tV_-6(dC63L9y?=Yaic9w1i%wVYKQzS!5wx6q)6V zz?LTvjnDx`*pL6%MX+#se8Up(l@|dmS2*CJhpe*G!(?@r@MET`*=Se5C@faoqyr?_>ef9_I}z2>Jj6^oYrs?zeam_9qa90 zaREO6DaEGJQaAvWl$P3?iR>+a#`{Wn-CrqUe9q?v-G+gB3XPiMb z&t#IlAB|LTpC;io9~mky$7LO%%r#hb8l(I|PZL30E-)fhqA!*B*LHCr851=x{k^(Io1)%Ixyd%gCGbXL14^U&8x`3hNZ zCo(}^op?wgO);ucSWEQcdX&X$Z}hO1`xWL5+AF&?(0*~*jI=1LgmBd20p zkjfsfYiEf3&J2Gx_3Gk%Ac=5;w?V^I5UnMF92UpY6i~>pW>YBSUDt!GnR>p9omzIN z7e#%JvJ|#vx}Qq|WqrJx-I}e+&)y_gZHT&h9DUN*k?P!+LKzlr#7!TCW zl42QZXN$|aDG4aK7bUXM)iK=9Mw(}EHU(XdacOMHve&p+_1SJshMb8*x>3lLJ+}u{ z`aA_$lxX#orBN40nmwOwp?&aI} z%(^9AmaH6d-?{IcbHC^N{d_*>d(M6ABNUw|ncNxaYWsRubtu%Zc~fKaE^hztmmOV= zLD$gHp{IsAza1WWeCQiP{h#loFaPr4zkYregRVT3po`3!T-JBu@4+D2(W6QpQJ(X~ zZoE%D`PQn$vH9}EqseloKHoWU@y@l;)8qHb6L*qVuTC{iTznRVA0K~;==Hvdi+mq= zV&Y-~V@EKKpU>h(QBrMRey%9N-Su+)=*C$( zrSSk1_Ak}8)$`e(`%;F)Fkck*k9^OXJA?L^BLJbxMFD(twCrt)wf5@N(Y9ZY_w1$I zXr#L}s_Z;lLFB=Gd-I~<$&CaG(AL=DG&VF4vH$InxYKs%Yea5*i?ufH*{@ogb1i!v zP4T8q)piSQY%dmhShWyM=2-UlS-Wv-z_J(7dm?Rntj9;IEqk%1);4?G<%g_sJ(2yf zCe`>LT=n8U+Nno%HSzL;M44!Vy_R@elj-956_&k7TO?-N8_2ip?cUqfWZN4pu`6?Ig;l%)gZFk@d`Jw64_NU^3<8H7{2V@t%hUOI0zNapl8-Be>3j?>x9mww zUs`9`lNc;)Q~DE{+`Lo8D=_eZLDpYH@bM<*V5}q`yTK*Y)|HhX|l@Ay8Y34&>`YnZ@#GnegGUFAw zy&5^&j9291#}s~&kEp^=^6`ekPx6t3CR6#iWbeO1cqInM zai->YB_GF19ed6@$+Xg+)Z`zrr=;?69C5HcsqwEU{3Hgi;9ZUJlNb!_wBnT*oWz=8 z{YgG_g`eajNA15-lP}o%6MQ_a@RRR2wbe>5LX+Rb`&;UHBM1I*yb=Q+RBY)bjvlKF z+wX58M|=!i%>7*O@fQ4Jdy^8UjY&(o$@Gw zF&g>!sP@r`nRHKX9O+n<$9)nipUG zp^;1`jagh?S5)JE{{Rhm`|y8{ZSyq0P0J4!tX#R$ z;OpqI=Z%t*5+ij?_VU1rOMiIZ2uF4rM~*&cl$Mrao?Y4?<|!Sk7^Y#Otjt2P?XV56 zt3^A5{%eOn2~UP`Hu4ua{c9@MI{lO3@x#{+6BQL^61P`9u-^2=r=Fi5n8AokVNa3Q zzj{rjQLa~*{XCbZe4w%1v0V6&z07CMVfzNZ#!APC3Mq@&C%)u!+lMQLH=*B`nQcDj zQP|9frb6=-Q>#}L6zB8!R6K$OSu1U<7?&O4NZOddio9YQD;pP^n}Y8A!Q6gutp$lW z<9_C__goP@RR2ibBemuqbKrnjM_KF?ShP{PyXEt*EPTHMrl+tVHc~?b8NXXFc~0PT{{R8YT^GSZBui>hKHT zU-h@$>zKm%oIGyg_SRk7jSFW_I{hESrViZg#Tne~rJtYruG#lwf49@04F4tkK@9rx zWzgC$uQ6(>A24{F&()<3`fF%@e12|xe0x8Z`;rmb@SvgVy0L0iY1)`FQ4Y%%PysdfUC?XJ+vjqvs@hCMcQOpX>X^``4(hCSBgwr-KzAO+|rcxM;^pPo#A zq6KxO@BZAz+mgu|a9j1$`*SP%Q@Oo6TjqZIR^grZwHfVg_l#Ej@s-&c-1prrb6=oI v*Fo2eb`DqHLVkvh`nPC*bM{7HE$YA1j283dXKeRO&joNH$1IgEFarMs;C@UI literal 0 HcmV?d00001 diff --git a/testdata/WO3 Venom PortKr Pirna 1 45 06.mcs b/testdata/WO3 Venom PortKr Pirna 1 45 06.mcs new file mode 100755 index 0000000000000000000000000000000000000000..53bba013e18f371e0fff1fd0149be4bacc5186fe GIT binary patch literal 16512 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 literal 0 HcmV?d00001 diff --git a/testdata/Wild Arms FILE01 LV13.mcs b/testdata/Wild Arms FILE01 LV13.mcs new file mode 100755 index 0000000000000000000000000000000000000000..82a8445368c16f5e68c5b941d5cd27f6760f8ed0 GIT binary patch literal 8320 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