From c3b0fa04a663fe233765b83d3be41a42aa08c25d Mon Sep 17 00:00:00 2001 From: "Juan J. Martinez" Date: Mon, 3 May 2021 08:21:10 +0100 Subject: Initial import for public release --- tools/iDSK/src/Basic.cpp | 350 +++++++++++++ tools/iDSK/src/Basic.h | 8 + tools/iDSK/src/BitmapCPC.cpp | 264 ++++++++++ tools/iDSK/src/BitmapCPC.h | 46 ++ tools/iDSK/src/Dams.cpp | 184 +++++++ tools/iDSK/src/Dams.h | 8 + tools/iDSK/src/Desass.cpp | 532 +++++++++++++++++++ tools/iDSK/src/Desass.h | 8 + tools/iDSK/src/GestDsk.cpp | 1183 ++++++++++++++++++++++++++++++++++++++++++ tools/iDSK/src/GestDsk.h | 168 ++++++ tools/iDSK/src/Main.cpp | 284 ++++++++++ tools/iDSK/src/Main.h | 19 + tools/iDSK/src/MyType.h | 19 + tools/iDSK/src/Outils.cpp | 165 ++++++ tools/iDSK/src/Outils.h | 19 + tools/iDSK/src/ViewFile.cpp | 36 ++ tools/iDSK/src/ViewFile.h | 13 + tools/iDSK/src/endianPPC.cpp | 20 + tools/iDSK/src/endianPPC.h | 22 + tools/iDSK/src/getopt_pp.cpp | 307 +++++++++++ tools/iDSK/src/getopt_pp.h | 745 ++++++++++++++++++++++++++ 21 files changed, 4400 insertions(+) create mode 100644 tools/iDSK/src/Basic.cpp create mode 100644 tools/iDSK/src/Basic.h create mode 100644 tools/iDSK/src/BitmapCPC.cpp create mode 100644 tools/iDSK/src/BitmapCPC.h create mode 100644 tools/iDSK/src/Dams.cpp create mode 100644 tools/iDSK/src/Dams.h create mode 100644 tools/iDSK/src/Desass.cpp create mode 100644 tools/iDSK/src/Desass.h create mode 100644 tools/iDSK/src/GestDsk.cpp create mode 100644 tools/iDSK/src/GestDsk.h create mode 100644 tools/iDSK/src/Main.cpp create mode 100644 tools/iDSK/src/Main.h create mode 100644 tools/iDSK/src/MyType.h create mode 100644 tools/iDSK/src/Outils.cpp create mode 100644 tools/iDSK/src/Outils.h create mode 100644 tools/iDSK/src/ViewFile.cpp create mode 100644 tools/iDSK/src/ViewFile.h create mode 100644 tools/iDSK/src/endianPPC.cpp create mode 100644 tools/iDSK/src/endianPPC.h create mode 100644 tools/iDSK/src/getopt_pp.cpp create mode 100644 tools/iDSK/src/getopt_pp.h (limited to 'tools/iDSK/src') diff --git a/tools/iDSK/src/Basic.cpp b/tools/iDSK/src/Basic.cpp new file mode 100644 index 0000000..4aeb314 --- /dev/null +++ b/tools/iDSK/src/Basic.cpp @@ -0,0 +1,350 @@ +#include +using namespace std; +#include +#include +#include +#include + +#include "MyType.h" +#include "Basic.h" + + +//static char ConvCpcFr[ 128 ] = " !\"#$%&'()*+,-./0123456789:;<=>?àABCDEFGHIJKLMNOPQRSTUVWXYZ[ç]^_`abcdefghijklmnopqrstuvwxyzéùè~"; + + +// +// Tableau de décryptage d'un programme en basic protégé +// +static BYTE DproBasic[ 128 ] = + { + 0xAB, 0x2C, 0xED, 0xEA, 0x6C, 0x37, 0x3F, 0xEC, + 0x9B, 0xDF, 0x7A, 0x0C, 0x3B, 0xD4, 0x6D, 0xF5, + 0x04, 0x44, 0x03, 0x11, 0xDF, 0x59, 0x8F, 0x21, + 0x73, 0x7A, 0xCC, 0x83, 0xDD, 0x30, 0x6A, 0x30, + 0xD3, 0x8F, 0x02, 0xF0, 0x60, 0x6B, 0x94, 0xE4, + 0xB7, 0xF3, 0x03, 0xA8, 0x60, 0x88, 0xF0, 0x43, + 0xE8, 0x8E, 0x43, 0xA0, 0xCA, 0x84, 0x31, 0x53, + 0xF3, 0x1F, 0xC9, 0xE8, 0xAD, 0xC0, 0xBA, 0x6D, + 0x93, 0x08, 0xD4, 0x6A, 0x2C, 0xB2, 0x07, 0x27, + 0xC0, 0x99, 0xEE, 0x89, 0xAF, 0xC3, 0x53, 0xAB, + 0x2B, 0x34, 0x5C, 0x2F, 0x13, 0xEE, 0xAA, 0x2C, + 0xD9, 0xF4, 0xBC, 0x12, 0xB3, 0xC5, 0x1C, 0x68, + 0x01, 0x20, 0x2C, 0xFA, 0x77, 0xA6, 0xB5, 0xA4, + 0xFC, 0x9B, 0xF1, 0x32, 0x5B, 0xC3, 0x70, 0x77, + 0x85, 0x36, 0xBE, 0x5B, 0x8C, 0xC8, 0xB5, 0xC2, + 0xF0, 0x0B, 0x98, 0x0F, 0x36, 0x9D, 0xD8, 0x96 + }; + + +BYTE GetByte( BYTE * BufFile, int Pos, int Deprotect ) +{ + //BYTE b = ( BYTE )( BufFile[ Pos ] ^ ( DproBasic[ Pos & 0x7F ] * Deprotect ) ); + //cout << "GetByte:"<", "=", ">=", "<", "<>", + "<=", "+", "-", "*", "/", "^", "\\ ", "AND", "MOD", "OR", "XOR", "NOT", + "#FF" + }; + + static const char * Fcts[ 0x80 ] = + { + "ABS", "ASC", "ATN", "CHR$", "CINT", "COS", "CREAL", "EXP", "FIX", + "FRE", "INKEY", "INP", "INT", "JOY", "LEN", "LOG", "LOG10", "LOWER$", + "PEEK", "REMAIN", "SGN", "SIN", "SPACE$", "SQ", "SQR", "STR$", "TAN", + "UNT", "UPPER$", "VAL", "", "", "", "", "", "", "", "", "", "", "", + "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", + "", "", "", "", "", "", "EOF", "ERR", "HIMEM", "INKEY$", "PI", "RND", + "TIME", "XPOS", "YPOS", "DERR", "", "", "", "", "", "", "", "", "", "", + "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", + "", "", "", "", "", "", "", "", "", "", "", "BIN$", "DEC$", "HEX$", + "INSTR", "LEFT$", "MAX", "MIN", "POS", "RIGHT$", "ROUND", "STRING$", + "TEST", "TESTR", "COPYCHR$", "VPOS" + }; + + + * Listing = 0; + Token = GetByte( BufFile, 0, Deprotect ); + for ( ;; ) + { + //cout << "Listing : " < 0x7F && Token < 0xFF ) + { + // #### Traitement particulier du ':' avant le ELSE + if ( Listing[ strlen( Listing ) - 1 ] == ':' + && Token == 0x97 + ) + Listing[ strlen( Listing ) - 1 ] = 0; + + strcat( Listing + , MotsClefs[ Token & 0x7F ] + ); + } + else + if ( Token >= 0x0E && Token <= 0x18 ) + strcat( Listing + , Nbre[ Token - 0x0E ] + ); + else + if ( Token >= 0x20 && Token < 0x7C ) + { + Tmp[ 0 ] = ( char )Token; + Tmp[ 1 ] = 0; + strcat( Listing, Tmp ); + if ( Token == '"' ) + DansChaine ^= 1; + } + else + { + //cout << "Token:" << Token < 80 caractères + // + EndLigne = strlen( &Listing[ StartLigne ] ); + while( EndLigne > 80 ) + { + memmove( &Listing[ StartLigne + 82 ] + , &Listing[ StartLigne + 80 ] + , EndLigne + ); + memcpy( &Listing[ StartLigne + 80 ], "\r\n", 2 ); + StartLigne += 82; + EndLigne -= 80; + } + } + strcat( Listing, "\r\n" ); + StartLigne = strlen( Listing ); + } + // Conversion des caractères accentués si nécessaire + + for ( int i = strlen( Listing); i--; ) + { + //cout << i << " "; + + if ( ! isprint(Listing[ i ]) && Listing[ i ] != '\n' && Listing[ i ] != '\r' ) Listing[ i ] = '?'; + } +} diff --git a/tools/iDSK/src/Basic.h b/tools/iDSK/src/Basic.h new file mode 100644 index 0000000..bb99181 --- /dev/null +++ b/tools/iDSK/src/Basic.h @@ -0,0 +1,8 @@ +#ifndef BASIC_H +#define BASIC_H + + +void Basic( unsigned char * BufFile, char * Listing, bool IsBasic, bool CrLf ); + + +#endif diff --git a/tools/iDSK/src/BitmapCPC.cpp b/tools/iDSK/src/BitmapCPC.cpp new file mode 100644 index 0000000..19b39a6 --- /dev/null +++ b/tools/iDSK/src/BitmapCPC.cpp @@ -0,0 +1,264 @@ +#include +#include +#include "MyType.h" +#include "BitmapCPC.h" +#include "GestDsk.h" +#include +#include +using namespace std; + + +// +// Couleurs du CPC converties en composantes r, v, b +// +static StRVB RgbCPC[ 27 ] = + { + { 0x00, 0x00, 0x00, 0x00 }, + { 0x7F, 0x00, 0x00, 0x00 }, + { 0xFF, 0x00, 0x00, 0x00 }, + { 0x00, 0x00, 0x7F, 0x00 }, + { 0x7F, 0x00, 0x7F, 0x00 }, + { 0xFF, 0x00, 0x7F, 0x00 }, + { 0x00, 0x00, 0xFF, 0x00 }, + { 0x7F, 0x00, 0xFF, 0x00 }, + { 0xFF, 0x00, 0xFF, 0x00 }, + { 0x00, 0x7F, 0x00, 0x00 }, + { 0x7F, 0x7F, 0x00, 0x00 }, + { 0xFF, 0x7F, 0x00, 0x00 }, + { 0x00, 0x7F, 0x7F, 0x00 }, + { 0x7F, 0x7F, 0x7F, 0x00 }, + { 0xFF, 0x7F, 0x7F, 0x00 }, + { 0x00, 0x7F, 0xFF, 0x00 }, + { 0x7F, 0x7F, 0xFF, 0x00 }, + { 0xFF, 0x7F, 0xFF, 0x00 }, + { 0x00, 0xFF, 0x00, 0x00 }, + { 0x7F, 0xFF, 0x00, 0x00 }, + { 0xFF, 0xFF, 0x00, 0x00 }, + { 0x00, 0xFF, 0x7F, 0x00 }, + { 0x7F, 0xFF, 0x7F, 0x00 }, + { 0xFF, 0xFF, 0x7F, 0x00 }, + { 0x00, 0xFF, 0xFF, 0x00 }, + { 0x7F, 0xFF, 0xFF, 0x00 }, + { 0xFF, 0xFF, 0xFF, 0x00 } + }; + + +int GetRgbCPC( int Coul ) +{ + if ( Coul >= 0 && Coul < 27 ) + { + StRVB i = RgbCPC[ Coul ]; + return( ( i.b << 16 ) + ( i.v << 8 ) + i.r ); + } + return( -1 ); +} + + +StRVB GetPalCPC( int Coul ) +{ + if ( Coul >= 0 && Coul < 27 ) + return( RgbCPC[ Coul ] ); + + return( RgbCPC[ 0 ] ); +} + + +void InitPalette( unsigned char NewPal[ 16 ], bool SetNewPal ) +{ + /* + Si sauvegard� avec ConvImgCpc, alors la palette se trouve + dans l'image... + */ + int i; + if ( BitmapCPC[ 0x7D0 ] == 0x3A + && BitmapCPC[ 0x7D1 ] == 0xD0 + && BitmapCPC[ 0x7D2 ] == 0xD7 + && BitmapCPC[ 0x7D3 ] == 0xCD + ) + { + Mode = BitmapCPC[ 0x17D0 ]; + for ( i = 0; i < 16; i++ ) + Palette[ i ] = BitmapCPC[ 0x17D1 + i ]; + } + if ( SetNewPal ) + for ( i = 0; i < 16; i++ ) + Palette[ i ] = NewPal[ i ]; +} + + +// +// D�compacter une image au format OCP +// +void DepactOCP( void ) +{ + static unsigned char BufTmp[ 0x4000 ]; + int PosIn = 0, PosOut = 0; + int LgOut, CntBlock = 0; + int c,i; + unsigned char a; + memcpy( BufTmp, BitmapCPC, sizeof( BufTmp ) ); + memset( BitmapCPC, 0, 0x4000 ); + while( PosOut < 0x4000 ) + { + if ( ! strncmp( ( char * )&BufTmp[ PosIn ], "MJH", 3 ) ) + { + PosIn += 3; + LgOut = BufTmp[ PosIn++ ]; + LgOut += ( BufTmp[ PosIn++ ] << 8 ); + CntBlock = 0; + while( CntBlock < LgOut ) + { + if ( ! strncmp( ( char * )&BufTmp[ PosIn ], "MJH", 3 ) ) + break; + + a = BufTmp[ PosIn++ ]; + if ( a == MARKER_OCP ) + { + c = BufTmp[ PosIn++ ]; + a = BufTmp[ PosIn++ ]; + if ( ! c ) + c = 0x100; + + for ( i = 0; i < c && CntBlock < LgOut; i++ ) + { + BitmapCPC[ PosOut++ ] = a; + CntBlock++; + } + } + else + { + BitmapCPC[ PosOut++ ] = a; + CntBlock++; + } + } + } + else + PosOut = 0x4000; + } +} + + +bool LireImage( char * Nom, StRVB * Bitmap ) +{ + static unsigned char Entete[ 0x80 ]; + bool Ret = FALSE; + //DWORD Nb; + FILE* hFile; + + + if ( (hFile=fopen(Nom,"rb"))!=NULL ) + { + fread(Entete,sizeof(Entete),1,hFile); + // ReadFile( hFile, Entete, sizeof( Entete ), &Nb, NULL ); + if ( CheckAmsdos( Entete ) ) + { + fread(BitmapCPC,sizeof( BitmapCPC ),1,hFile); + // ReadFile( hFile, BitmapCPC, sizeof( BitmapCPC ), &Nb, NULL ); + if ( ! strncmp( ( char * )BitmapCPC, "MJH", 3 ) ) + DepactOCP(); + + InitPalette( NULL, FALSE ); + Ret = TRUE; + } + // CloseHandle( hFile ); + fclose(hFile); + if ( Ret ) + Render( Bitmap, 1 ); + } + return( Ret ); + +} + + +// +// Affiche l'image � l'�cran +// +void Render( StRVB * Bitmap, bool Flat ) +{ + int AdrCPC = 0, i, p0, p1, p2, p3; + int y,x,AdrBitmap; + unsigned char Octet; + for ( y = 0; y < NbLignes; y++ ) + { + AdrBitmap = TAILLE_CPC_X * ( y + ( ( 200 - NbLignes ) >> 1 ) ) + + ( ( ( 80 - NbCol ) >> 1 ) << 3 ); + for ( x = 0; x < NbCol; x++ ) + { + Octet = BitmapCPC[ AdrCPC + x ]; + switch( Mode ) + { + case 0 : + case 3 : // Mode 3 = Mode 0 + p0 = ( Octet >> 7 ) + + ( ( Octet & 0x20 ) >> 3 ) + + ( ( Octet & 0x08 ) >> 2 ) + + ( ( Octet & 0x02 ) << 2 ); + p1 = ( ( Octet & 0x40 ) >> 6 ) + + ( ( Octet & 0x10 ) >> 2 ) + + ( ( Octet & 0x04 ) >> 1 ) + + ( ( Octet & 0x01 ) << 3 ); + Bitmap[ AdrBitmap++ ] = GetPalCPC( Palette[ p0 ] ); + Bitmap[ AdrBitmap++ ] = GetPalCPC( Palette[ p0 ] ); + Bitmap[ AdrBitmap++ ] = GetPalCPC( Palette[ p0 ] ); + Bitmap[ AdrBitmap++ ] = GetPalCPC( Palette[ p0 ] ); + Bitmap[ AdrBitmap++ ] = GetPalCPC( Palette[ p1 ] ); + Bitmap[ AdrBitmap++ ] = GetPalCPC( Palette[ p1 ] ); + Bitmap[ AdrBitmap++ ] = GetPalCPC( Palette[ p1 ] ); + Bitmap[ AdrBitmap++ ] = GetPalCPC( Palette[ p1 ] ); + break; + + case 1 : + p0 = ( ( Octet >> 7 ) & 1 ) + ( ( Octet >> 2 ) & 2 ); + p1 = ( ( Octet >> 6 ) & 1 ) + ( ( Octet >> 1 ) & 2 ); + p2 = ( ( Octet >> 5 ) & 1 ) + ( ( Octet >> 0 ) & 2 ); + p3 = ( ( Octet >> 4 ) & 1 ) + ( ( Octet << 1 ) & 2 ); + Bitmap[ AdrBitmap++ ] = GetPalCPC( Palette[ p0 ] ); + Bitmap[ AdrBitmap++ ] = GetPalCPC( Palette[ p0 ] ); + Bitmap[ AdrBitmap++ ] = GetPalCPC( Palette[ p1 ] ); + Bitmap[ AdrBitmap++ ] = GetPalCPC( Palette[ p1 ] ); + Bitmap[ AdrBitmap++ ] = GetPalCPC( Palette[ p2 ] ); + Bitmap[ AdrBitmap++ ] = GetPalCPC( Palette[ p2 ] ); + Bitmap[ AdrBitmap++ ] = GetPalCPC( Palette[ p3 ] ); + Bitmap[ AdrBitmap++ ] = GetPalCPC( Palette[ p3 ] ); + break; + + case 2 : + for ( i = 8; i--; ) + Bitmap[ AdrBitmap++ ] = GetPalCPC( Palette[ ( Octet >> i ) & 1 ] ); + break; + } + } + if ( Flat ) + AdrCPC += NbCol; + else + { + AdrCPC += 0x800; + if ( AdrCPC > 0x3FFF ) + AdrCPC -= 0x3FB0; + } + } +} + + +void SetBitmapCPC( unsigned char * BitmapSource ) +{ + memcpy( BitmapCPC, BitmapSource, 0x4000 ); + if ( ! strncmp( ( char * )BitmapCPC, "MJH", 3 ) ) + DepactOCP(); + + InitPalette( NULL, FALSE ); +} + + +void SetNbCol( int n ) +{ + if ( n > 0 && n <= 80 ) + NbCol = n; +} + + +void SetNbLignes( int n ) +{ + if ( n > 0 && n <= 200 ) + NbLignes = n; +} diff --git a/tools/iDSK/src/BitmapCPC.h b/tools/iDSK/src/BitmapCPC.h new file mode 100644 index 0000000..2af2bab --- /dev/null +++ b/tools/iDSK/src/BitmapCPC.h @@ -0,0 +1,46 @@ +#ifndef BITMAPCPC_H +#define BITMAPCPC_H + + +#define TAILLE_CPC_X 640 + +#define TAILLE_CPC_Y 200 + +#define MARKER_OCP 1 // Marker pour compression RLE +int Mode, NbCol, NbLignes; +unsigned char BitmapCPC[ 0x4000 ]; +unsigned char Palette[ 16 ]; +typedef struct + { + unsigned char b, v, r, a; + } StRVB; + + + +void CBitmapCPC( void ) { NbCol = 80; NbLignes = 200; } +bool LireImage( char * Nom, StRVB * Bitmap ); +void Render( StRVB * Bitmap, bool Flat ); +void SetBitmapCPC( unsigned char * BitmapSource ); +unsigned char * GetBitmapCPC( void ) { return( BitmapCPC ); } +void SetMode( int m ) { Mode = m; } +void InitPalette( unsigned char Pal[ 16 ], bool SetPal ); +unsigned char * GetPalette( void ) { return( Palette ); } +int GetMode( void ) { return( Mode ); } +void SetNbCol( int n ); +void SetNbLignes( int n ); + + +void DepactOCP( void ); +void LisseBitmap( StRVB * Bitmap ); + + + + + + +StRVB GetPalCPC( int Coul ); + +int GetRgbCPC( int Coul ); + + +#endif diff --git a/tools/iDSK/src/Dams.cpp b/tools/iDSK/src/Dams.cpp new file mode 100644 index 0000000..9b24813 --- /dev/null +++ b/tools/iDSK/src/Dams.cpp @@ -0,0 +1,184 @@ +#include +#include +#include +using namespace std; + + +// +// Convertir le buffer en listing au format Dams +// Adaptation des sources de Thierry JOUIN ( Ramlaid ) +// +void Dams( unsigned char * BufFile, int TailleFic, char * Listing ) +{ + const char * MotCleDams[ 0x80 ] = + { + "LD","INC","DEC","ADD","ADC","SUB","SBC","AND","XOR","OR","CP", + "PUSH","POP","BIT","RES","SET","RLC","RRC","RL","RR","SLA","SRA", + "SRL","IN","OUT","RST","DJNZ","EX","IM","JR","CALL","RET","JP", + "NOP","RLCA","RRCA","RLA","RRA","DAA","CPL","SCF","CCF","HALT", + "EXX","DI","EI","NEG","RETN","RETI","RRD","RLD","LDI","CPI","INI", + "OUTI","LDD","CPD","IND","OUTD","LDIR","CPIR","INIR","OTIR","LDDR", + "CPDR","INDR","OTDR","DB","DW","DM","DS","EQU","ORG","ENT", + "IF","ELSE","END" + }; + char Tmp[ 32 ]; + int PosFile = 0; + int PosDest = 0; + unsigned char c; + + * Listing = 0; + c = BufFile[ PosFile++ ]; + while( c ) + { + if ( c == 0xFF ) + { + // Commentaire ligne + Listing[ PosDest++ ] = ';'; + c = BufFile[ PosFile++ ]; + while( c != 0x0D && PosFile < TailleFic ) + { + Listing[ PosDest++ ] = c; + c = BufFile[ PosFile++ ]; + } + Listing[ PosDest++ ] = '\r'; + Listing[ PosDest++ ] = '\n'; + } + else + { + if ( c >= 0x80 && c != 0x0D ) + { + // Mnemonique sans label + // ENT + if ( c == 0xC9 ) + Listing[ PosDest++ ] = ';'; + + sprintf( Tmp, "\t%s\t", MotCleDams[ c & 0x7F ] ); + int l = strlen( Tmp ); + memcpy( &Listing[ PosDest ], Tmp, l ); + PosDest += l; + // DS ?,? + if ( c == 0xC6 ) + { + c = BufFile[ PosFile++ ]; + // Fin de ligne + while( c != 0x0D && PosFile < TailleFic ) + { + if ( c == ',' ) + { + while( c != 0x0D && c != 0xFF && PosFile < TailleFic ) + c = BufFile[ PosFile++ ]; + } + if ( c != 0x0D ) + { + if ( c == 0xFF ) + Listing[ PosDest++ ] = '\t'; + else + Listing[ PosDest++ ] = c; + + c = BufFile[ PosFile++ ]; + } + } + } + else + { + c = BufFile[ PosFile++ ]; + // Fin de ligne + while( c != 0x0D && PosFile < TailleFic ) + { + if ( c == 0xFF ) + Listing[ PosDest++ ] = '\t'; + else + Listing[ PosDest++ ] = c; + + c = BufFile[ PosFile++ ]; + } + } + Listing[ PosDest++ ] = '\r'; + Listing[ PosDest++ ] = '\n'; + } + else + { + // Label + while( c < 0x80 && c != 0x0D && PosFile < TailleFic ) + { + Listing[ PosDest++ ] = c; + c = BufFile[ PosFile++ ]; + } + if ( c != 0x0D ) + { + // Mnemonique apres label + // ENT + if ( c == 0xC9 ) + Listing[ PosDest++ ] = ';'; + + if ( c != 0xFF ) + { + sprintf( Tmp, "\t%s\t", MotCleDams[ c & 0x7F ] ); + int l = strlen( Tmp ); + memcpy( &Listing[ PosDest ], Tmp, l ); + PosDest += l; + } + else + { + Listing[ PosDest++ ] = '\t'; + Listing[ PosDest++ ] = '\t'; + Listing[ PosDest++ ] = '\t'; + } + // DS ?,? + if ( c == 0xC6 ) + { + c = BufFile[ PosFile++ ]; + // Fin de ligne + while( c != 0x0D && PosFile < TailleFic ) + { + if ( c == ',' ) + { + while( c != 0x0D && c != 0xFF && PosFile < TailleFic ) + c = BufFile[ PosFile++ ]; + } + if ( c != 0x0D ) + { + if ( c == 0xFF ) + { + Listing[ PosDest++ ] = '\t'; + Listing[ PosDest++ ] = ';'; + } + else + Listing[ PosDest++ ] = c; + + c = BufFile[ PosFile++ ]; + } + } + } + else + { + c = BufFile[ PosFile++ ]; + // Fin de ligne + while( c != 0x0D && PosFile < TailleFic ) + { + if ( c == 0xFF ) + { + Listing[ PosDest++ ] = '\t'; + Listing[ PosDest++ ] = ';'; + } + else + Listing[ PosDest++ ] = c; + + c = BufFile[ PosFile++ ]; + } + } + Listing[ PosDest++ ] = '\r'; + Listing[ PosDest++ ] = '\n'; + } + else + { + Listing[ PosDest++ ] = '\r'; + Listing[ PosDest++ ] = '\n'; + } + } + } + c = BufFile[ PosFile++ ]; + if ( PosFile > TailleFic ) + break; + } +} diff --git a/tools/iDSK/src/Dams.h b/tools/iDSK/src/Dams.h new file mode 100644 index 0000000..6610ef7 --- /dev/null +++ b/tools/iDSK/src/Dams.h @@ -0,0 +1,8 @@ +#ifndef DAMS_H +#define DAMS_H + + +void Dams( unsigned char * BufFile, int TailleFic, char * Listing ); + + +#endif diff --git a/tools/iDSK/src/Desass.cpp b/tools/iDSK/src/Desass.cpp new file mode 100644 index 0000000..a2030a0 --- /dev/null +++ b/tools/iDSK/src/Desass.cpp @@ -0,0 +1,532 @@ +#include +#include +#include + +#include "Outils.h" +using namespace std; + + +// +// Tableau des OP-Codes Z80... +// +const char * TabInstrCB[ 256 ] = + { + "RLC B","RLC C","RLC D","RLC E", + "RLC H","RLC L","RLC (HL)","RLC A", + "RRC B","RRC C","RRC D","RRC E", + "RRC H","RRC L","RRC (HL)","RRC A", + "RL B","RL C","RL D","RL E", + "RL H","RL L","RL (HL)","RL A", + "RR B","RR C","RR D","RR E", + "RR H","RR L","RR (HL)","RR A", + "SLA B","SLA C","SLA D","SLA E", + "SLA H","SLA L","SLA (HL)","SLA A", + "SRA B","SRA C","SRA D","SRA E", + "SRA H","SRA L","SRA (HL)","SRA A", + "SLL B","SLL C","SLL D","SLL E", + "SLL H","SLL L","SLL (HL)","SLL A", + "SRL B","SRL C","SRL D","SRL E", + "SRL H","SRL L","SRL (HL)","SRL A", + "BIT 0,B","BIT 0,C","BIT 0,D","BIT 0,E", + "BIT 0,H","BIT 0,L","BIT 0,(HL)","BIT 0,A", + "BIT 1,B","BIT 1,C","BIT 1,D","BIT 1,E", + "BIT 1,H","BIT 1,L","BIT 1,(HL)","BIT 1,A", + "BIT 2,B","BIT 2,C","BIT 2,D","BIT 2,E", + "BIT 2,H","BIT 2,L","BIT 2,(HL)","BIT 2,A", + "BIT 3,B","BIT 3,C","BIT 3,D","BIT 3,E", + "BIT 3,H","BIT 3,L","BIT 3,(HL)","BIT 3,A", + "BIT 4,B","BIT 4,C","BIT 4,D","BIT 4,E", + "BIT 4,H","BIT 4,L","BIT 4,(HL)","BIT 4,A", + "BIT 5,B","BIT 5,C","BIT 5,D","BIT 5,E", + "BIT 5,H","BIT 5,L","BIT 5,(HL)","BIT 5,A", + "BIT 6,B","BIT 6,C","BIT 6,D","BIT 6,E", + "BIT 6,H","BIT 6,L","BIT 6,(HL)","BIT 6,A", + "BIT 7,B","BIT 7,C","BIT 7,D","BIT 7,E", + "BIT 7,H","BIT 7,L","BIT 7,(HL)","BIT 7,A", + "RES 0,B","RES 0,C","RES 0,D","RES 0,E", + "RES 0,H","RES 0,L","RES 0,(HL)","RES 0,A", + "RES 1,B","RES 1,C","RES 1,D","RES 1,E", + "RES 1,H","RES 1,L","RES 1,(HL)","RES 1,A", + "RES 2,B","RES 2,C","RES 2,D","RES 2,E", + "RES 2,H","RES 2,L","RES 2,(HL)","RES 2,A", + "RES 3,B","RES 3,C","RES 3,D","RES 3,E", + "RES 3,H","RES 3,L","RES 3,(HL)","RES 3,A", + "RES 4,B","RES 4,C","RES 4,D","RES 4,E", + "RES 4,H","RES 4,L","RES 4,(HL)","RES 4,A", + "RES 5,B","RES 5,C","RES 5,D","RES 5,E", + "RES 5,H","RES 5,L","RES 5,(HL)","RES 5,A", + "RES 6,B","RES 6,C","RES 6,D","RES 6,E", + "RES 6,H","RES 6,L","RES 6,(HL)","RES 6,A", + "RES 7,B","RES 7,C","RES 7,D","RES 7,E", + "RES 7,H","RES 7,L","RES 7,(HL)","RES 7,A", + "SET 0,B","SET 0,C","SET 0,D","SET 0,E", + "SET 0,H","SET 0,L","SET 0,(HL)","SET 0,A", + "SET 1,B","SET 1,C","SET 1,D","SET 1,E", + "SET 1,H","SET 1,L","SET 1,(HL)","SET 1,A", + "SET 2,B","SET 2,C","SET 2,D","SET 2,E", + "SET 2,H","SET 2,L","SET 2,(HL)","SET 2,A", + "SET 3,B","SET 3,C","SET 3,D","SET 3,E", + "SET 3,H","SET 3,L","SET 3,(HL)","SET 3,A", + "SET 4,B","SET 4,C","SET 4,D","SET 4,E", + "SET 4,H","SET 4,L","SET 4,(HL)","SET 4,A", + "SET 5,B","SET 5,C","SET 5,D","SET 5,E", + "SET 5,H","SET 5,L","SET 5,(HL)","SET 5,A", + "SET 6,B","SET 6,C","SET 6,D","SET 6,E", + "SET 6,H","SET 6,L","SET 6,(HL)","SET 6,A", + "SET 7,B","SET 7,C","SET 7,D","SET 7,E", + "SET 7,H","SET 7,L","SET 7,(HL)","SET 7,A" + }; + + +const char * TabInstrED[ 256 ] = + { + 0,0,0,0, + 0,0,0,0, + 0,0,0,0, + 0,0,0,0, + 0,0,0,0, + 0,0,0,0, + 0,0,0,0, + 0,0,0,0, + 0,0,0,0, + 0,0,0,0, + 0,0,0,0, + 0,0,0,0, + 0,0,0,0, + 0,0,0,0, + 0,0,0,0, + 0,0,0,0, + "IN B,(C)","OUT (C),B","SBC HL,BC","LD (nnnn),BC", + "NEG","RETN","IM 0","LD I,A", + "IN C,(C)","OUT (C),C","ADC HL,BC","LD BC,(nnnn)", + 0,"RETI",0,"LD R,A", + "IN D,(C)","OUT (C),D","SBC HL,DE","LD (nnnn),DE", + 0,0,"IM 1","LD A,I", + "IN E,(C)","OUT (C),E","ADC HL,DE","LD DE,(nnnn)", + 0,0,"IM 2","LD A,R", + "IN H,(C)","OUT (C),H","SBC HL,HL",0, + 0,0,0,"RRD", + "IN L,(C)","OUT (C),L","ADC HL,HL",0, + 0,0,0,"RLD", + 0,"OUT (C),0","SBC HL,SP","LD (nnnn),SP", + 0,0,0,0, + "IN A,(C)","OUT (C),A","ADC HL,SP","LD SP,(nnnn)", + 0,0,0,0, + 0,0,0,0, + 0,0,0,0, + 0,0,0,0, + 0,0,0,0, + 0,0,0,0, + 0,0,0,0, + 0,0,0,0, + 0,0,0,0, + "LDI","CPI","INI","OUTI", + 0,0,0,0, + "LDD","CPD","IND","OUTD", + 0,0,0,0, + "LDIR","CPIR","INIR","OTIR", + 0,0,0,0, + "LDDR","CPDR","INDR","OTDR", + 0,0,0,0, + 0,0,0,0, + 0,0,0,0, + 0,0,0,0, + 0,0,0,0, + 0,0,0,0, + 0,0,0,0, + 0,0,0,0, + 0,0,0,0, + 0,0,0,0, + 0,0,0,0, + 0,0,0,0, + 0,0,0,0, + 0,0,0,0, + 0,0,0,0, + 0,0,0,0, + 0,0,0,0 + }; + + +const char * TabInstrDD[ 256 ] = + { + 0,0,0,0, + 0,0,0,0, + 0,"ADD IX,BC",0,0, + 0,0,0,0, + 0,0,0,0, + 0,0,0,0, + 0,"ADD IX,DE",0,0, + 0,0,0,0, + 0,"LD IX,nnnn","LD (nnnn),IX","INC IX", + "INC IXh","DEC IXh","LD IXh,nn",0, + 0,"ADD IX,HL","LD IX,(nnnn)","DEC IX", + "INC IXl","DEC IXl","LD IXl,nn",0, + 0,0,0,0, + "INC (IX+nn)","DEC (IX+nn)","LD (IX+nn),nn",0, + 0,"ADD IX,SP",0,0, + 0,0,0,0, + 0,0,0,0, + "LD B,IXh","LD B,IXl","LD B,(IX+nn)",0, + 0,0,0,0, + "LD C,IXh","LD C,IXl","LD C,(IX+nn)",0, + 0,0,0,0, + "LD D,IXh","LD D,IXl","LD D,(IX+nn)",0, + 0,0,0,0, + "LD E,IXh","LD E,IXl","LD E,(IX+nn)",0, + "LD IXh,B","LD IXh,C","LD IXh,D","LD IXh,E", + "LD IXh,IXh","LD IXh,IXl","LD H,(IX+nn)","LD IXh,A", + "LD IXl,B","LD IXl,C","LD IXl,D","LD IXl,E", + "LD IXl,IXh","LD IXl,IXl","LD L,(IX+nn)","LD IXl,A", + "LD (IX+nn),B","LD (IX+nn),C","LD (IX+nn),D","LD (IX+nn),E", + "LD (IX+nn),H","LD (IX+nn),L",0,"LD (IX+nn),A", + 0,0,0,0, + "LD A,IXh","LD A,IXl","LD A,(IX+nn)",0, + 0,0,0,0, + "ADD A,IXh","ADD A,IXl","ADD A,(IX+nn)",0, + 0,0,0,0, + "ADC A,IXh","ADC A,IXl","ADC A,(IX+nn)",0, + 0,0,0,0, + "SUB IXh","SUB IXl","SUB (IX+nn)",0, + 0,0,0,0, + "SBC A,IXh","SBC A,IXl","SBC A,(IX+nn)",0, + 0,0,0,0, + "AND IXh","AND IXl","AND (IX+nn)",0, + 0,0,0,0, + "XOR IXh","XOR IXl","XOR (IX+nn)",0, + 0,0,0,0, + "OR IXh","OR IXl","OR (IX+nn)",0, + 0,0,0,0, + "CP IXh","CP IXl","CP (IX+nn)",0, + 0,0,0,0, + 0,0,0,0, + 0,0,0,0, + 0,0,0,0, + 0,0,0,0, + 0,0,0,0, + 0,0,0,0, + 0,0,0,0, + 0,"POP IX",0,"EX (SP),IX", + 0,"PUSH IX",0,0, + 0,"JP (IX)",0,0, + 0,0,0,0, + 0,0,0,0, + 0,0,0,0, + 0,"LD SP,IX",0,0, + 0,0,0,0 + }; + + +const char * TabInstrDDCB[ 256 ] = + { + 0,0,0,0,0,0,"RLC (IX+nn)",0, + 0,0,0,0,0,0,"RRC (IX+nn)",0, + 0,0,0,0,0,0,"RL (IX+nn)",0, + 0,0,0,0,0,0,"RR (IX+nn)",0, + 0,0,0,0,0,0,"SLA (IX+nn)",0, + 0,0,0,0,0,0,"SRA (IX+nn)",0, + 0,0,0,0,0,0,"SLL (IX+nn)",0, + 0,0,0,0,0,0,"SRL (IX+nn)",0, + 0,0,0,0,0,0,"BIT 0,(IX+nn)",0, + 0,0,0,0,0,0,"BIT 1,(IX+nn)",0, + 0,0,0,0,0,0,"BIT 2,(IX+nn)",0, + 0,0,0,0,0,0,"BIT 3,(IX+nn)",0, + 0,0,0,0,0,0,"BIT 4,(IX+nn)",0, + 0,0,0,0,0,0,"BIT 5,(IX+nn)",0, + 0,0,0,0,0,0,"BIT 6,(IX+nn)",0, + 0,0,0,0,0,0,"BIT 7,(IX+nn)",0, + 0,0,0,0,0,0,"RES 0,(IX+nn)",0, + 0,0,0,0,0,0,"RES 1,(IX+nn)",0, + 0,0,0,0,0,0,"RES 2,(IX+nn)",0, + 0,0,0,0,0,0,"RES 3,(IX+nn)",0, + 0,0,0,0,0,0,"RES 4,(IX+nn)",0, + 0,0,0,0,0,0,"RES 5,(IX+nn)",0, + 0,0,0,0,0,0,"RES 6,(IX+nn)",0, + 0,0,0,0,0,0,"RES 7,(IX+nn)",0, + 0,0,0,0,0,0,"SET 0,(IX+nn)",0, + 0,0,0,0,0,0,"SET 1,(IX+nn)",0, + 0,0,0,0,0,0,"SET 2,(IX+nn)",0, + 0,0,0,0,0,0,"SET 3,(IX+nn)",0, + 0,0,0,0,0,0,"SET 4,(IX+nn)",0, + 0,0,0,0,0,0,"SET 5,(IX+nn)",0, + 0,0,0,0,0,0,"SET 6,(IX+nn)",0, + 0,0,0,0,0,0,"SET 7,(IX+nn)",0 + }; + + +const char * TabInstrFD[ 256 ] = + { + 0,0,0,0,0,0,0,0, + 0,"ADD IY,BC",0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,"ADD IY,DE",0,0,0,0,0,0, + 0,"LD IY,nnnn","LD (nnnn),IY","INC IY","INC IYh","DEC IYh","LD IYh,nn",0, + 0,"ADD IY,HL","LD IY,(nnnn)","DEC IY","INC IYl","DEC IYl","LD IYl,nn",0, + 0,0,0,0,"INC (IY+nn)","DEC (IY+nn)","LD (IY+nn),nn",0, + 0,"ADD IY,SP",0,0,0,0,0,0, + 0,0,0,0,"LD B,IYh","LD B,IYl","LD B,(IY+nn)",0, + 0,0,0,0,"LD C,IYh","LD C,IYl","LD C,(IY+nn)",0, + 0,0,0,0,"LD D,IYh","LD D,IYl","LD D,(IY+nn)",0, + 0,0,0,0,"LD E,IYh","LD E,IYl","LD E,(IY+nn)",0, + "LD IYh,B","LD IYh,C","LD IYh,D","LD IYh,E","LD IYh,IYh","LD IYh,IYl","LD H,(IY+nn)","LD IYh,A", + "LD IYl,B","LD IYl,C","LD IYl,D","LD IYl,E","LD IYl,IYh","LD IYl,IYl","LD L,(IY+nn)","LD IYl,A", + "LD (IY+nn),B","LD (IY+nn),C","LD (IY+nn),D","LD (IY+nn),E","LD (IY+nn),H","LD (IY+nn),L",0,"LD (IY+nn),A", + 0,0,0,0,"LD A,IYh","LD A,IYl","LD A,(IY+nn)",0, + 0,0,0,0,"ADD A,IYh","ADD A,IYl","ADD A,(IY+nn)",0, + 0,0,0,0,"ADC A,IYh","ADC A,IYl","ADC A,(IY+nn)",0, + 0,0,0,0,"SUB IYh","SUB IYl","SUB (IY+nn)",0, + 0,0,0,0,"SBC A,IYh","SBC A,IYl","SBC A,(IY+nn)",0, + 0,0,0,0,"AND IYh","AND IYl","AND (IY+nn)",0, + 0,0,0,0,"XOR IYh","XOR IYl","XOR (IY+nn)",0, + 0,0,0,0,"OR IYh","OR IYl","OR (IY+nn)",0, + 0,0,0,0,"CP IYh","CP IYl","CP (IY+nn)",0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,"POP IY",0,"EX (SP),IY",0,"PUSH IY",0,0, + 0,"JP (IY)",0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,"LD SP,IY",0,0,0,0,0,0 + }; + + +const char * TabInstrFDCB[ 256 ] = + { + 0,0,0,0,0,0,"RLC (IY+nn)",0, + 0,0,0,0,0,0,"RRC (IY+nn)",0, + 0,0,0,0,0,0,"RL (IY+nn)",0, + 0,0,0,0,0,0,"RR (IY+nn)",0, + 0,0,0,0,0,0,"SLA (IY+nn)",0, + 0,0,0,0,0,0,"SRA (IY+nn)",0, + 0,0,0,0,0,0,"SLL (IY+nn)",0, + 0,0,0,0,0,0,"SRL (IY+nn)",0, + 0,0,0,0,0,0,"BIT 0,(IY+nn)",0, + 0,0,0,0,0,0,"BIT 1,(IY+nn)",0, + 0,0,0,0,0,0,"BIT 2,(IY+nn)",0, + 0,0,0,0,0,0,"BIT 3,(IY+nn)",0, + 0,0,0,0,0,0,"BIT 4,(IY+nn)",0, + 0,0,0,0,0,0,"BIT 5,(IY+nn)",0, + 0,0,0,0,0,0,"BIT 6,(IY+nn)",0, + 0,0,0,0,0,0,"BIT 7,(IY+nn)",0, + 0,0,0,0,0,0,"RES 0,(IY+nn)",0, + 0,0,0,0,0,0,"RES 1,(IY+nn)",0, + 0,0,0,0,0,0,"RES 2,(IY+nn)",0, + 0,0,0,0,0,0,"RES 3,(IY+nn)",0, + 0,0,0,0,0,0,"RES 4,(IY+nn)",0, + 0,0,0,0,0,0,"RES 5,(IY+nn)",0, + 0,0,0,0,0,0,"RES 6,(IY+nn)",0, + 0,0,0,0,0,0,"RES 7,(IY+nn)",0, + 0,0,0,0,0,0,"SET 0,(IY+nn)",0, + 0,0,0,0,0,0,"SET 1,(IY+nn)",0, + 0,0,0,0,0,0,"SET 2,(IY+nn)",0, + 0,0,0,0,0,0,"SET 3,(IY+nn)",0, + 0,0,0,0,0,0,"SET 4,(IY+nn)",0, + 0,0,0,0,0,0,"SET 5,(IY+nn)",0, + 0,0,0,0,0,0,"SET 6,(IY+nn)",0, + 0,0,0,0,0,0,"SET 7,(IY+nn)",0 + }; + + +const char * TabInstr[ 256 ] = + { + "NOP","LD BC,nnnn","LD (BC),A","INC BC", + "INC B","DEC B","LD B,nn","RLCA", + "EX AF,AF","ADD HL,BC","LD A,(BC)","DEC BC", + "INC C","DEC C","LD C,nn","RRCA", + "DJNZ eeee","LD DE,nnnn","LD (DE),A","INC DE", + "INC D","DEC D","LD D,nn","RLA", + "JR eeee","ADD HL,DE","LD A,(DE)","DEC DE", + "INC E","DEC E","LD E,nn","RRA", + "JR NZ,eeee","LD HL,nnnn","LD (nnnn),HL","INC HL", + "INC H","DEC H","LD H,nn","DAA", + "JR Z,eeee","ADD HL,HL","LD HL,(nnnn)","DEC HL", + "INC L","DEC L","LD L,nn","CPL", + "JR NC,eeee","LD SP,nnnn","LD (nnnn),A","INC SP", + "INC (HL)","DEC (HL)","LD (HL),nn","SCF", + "JR C,eeee","ADD HL,SP","LD A,(nnnn)","DEC SP", + "INC A","DEC A","LD A,nn","CCF", + "LD B,B","LD B,C","LD B,D","LD B,E", + "LD B,H","LD B,L","LD B,(HL)","LD B,A", + "LD C,B","LD C,C","LD C,D","LD C,E", + "LD C,H","LD C,L","LD C,(HL)","LD C,A", + "LD D,B","LD D,C","LD D,D","LD D,E", + "LD D,H","LD D,L","LD D,(HL)","LD D,A", + "LD E,B","LD E,C","LD E,D","LD E,E", + "LD E,H","LD E,L","LD E,(HL)","LD E,A", + "LD H,B","LD H,C","LD H,D","LD H,E", + "LD H,H","LD H,L","LD H,(HL)","LD H,A", + "LD L,B","LD L,C","LD L,D","LD L,E", + "LD L,H","LD L,L","LD L,(HL)","LD L,A", + "LD (HL),B","LD (HL),C","LD (HL),D","LD (HL),E", + "LD (HL),H","LD (HL),L","HALT","LD (HL),A", + "LD A,B","LD A,C","LD A,D","LD A,E", + "LD A,H","LD A,L","LD A,(HL)","LD A,A", + "ADD A,B","ADD A,C","ADD A,D","ADD A,E", + "ADD A,H","ADD A,L","ADD A,(HL)","ADD A,A", + "ADC A,B","ADC A,C","ADC A,D","ADC A,E", + "ADC A,H","ADC A,L","ADC A,(HL)","ADC A,A", + "SUB B","SUB C","SUB D","SUB E", + "SUB H","SUB L","SUB (HL)","SUB A", + "SBC A,B","SBC A,C","SBC A,D","SBC A,E", + "SBC A,H","SBC A,L","SBC A,(HL)","SBC A,A", + "AND B","AND C","AND D","AND E", + "AND H","AND L","AND (HL)","AND A", + "XOR B","XOR C","XOR D","XOR E", + "XOR H","XOR L","XOR (HL)","XOR A", + "OR B","OR C","OR D","OR E", + "OR H","OR L","OR (HL)","OR A", + "CP B","CP C","CP D","CP E", + "CP H","CP L","CP (HL)","CP A", + "RET NZ","POP BC","JP NZ,nnnn","JP nnnn", + "CALL NZ,nnnn","PUSH BC","ADD A,nn","RST 00", + "RET Z","RET","JP Z,nnnn",0, + "CALL Z,nnnn","CALL nnnn","ADC A,nn","RST 08", + "RET NC","POP DE","JP NC,nnnn","OUT (nn),A", + "CALL NC,nnnn","PUSH DE","SUB nn","RST 10", + "RET C","EXX","JP C,nnnn","IN A,(nn)", + "CALL C,nnnn",0,"SBC A,nn","RST 18", + "RET PE","POP HL","JP PE,nnnn","EX (SP),HL", + "CALL PE,nnnn","PUSH HL","AND nn","RST 20", + "RET PO","JP (HL)","JP PO,nnnn","EX DE,HL", + "CALL PO,nnnn",0,"XOR nn","RST 28", + "RET P","POP AF","JP P,nnnn","DI", + "CALL P,nnnn","PUSH AF","OR nn","RST 30", + "RET M","LD SP,HL","JP M,nnnn","EI", + "CALL M,nnnn",0,"CP nn","RST 38" + }; + + +// +// Convertir le buffer en listing d�sassembl� +// +void Desass( unsigned char * Prg, char * Listing, int Longueur ) +{ + int i, Instr, Inst2 = 0, Inst3 = 0, Inst4 = 0, Ad16; + const char * Chaine; + char *p; + char Inst[ 1024 ]; + + int Adr, OldAdr, PosD = 0; + char Ad8; + + * Listing = 0; + for ( Adr = 0; Adr < Longueur; ) + { + OldAdr = Adr; + Instr = Prg[ Adr++ ]; + Chaine = TabInstr[ Instr ]; + if ( Instr == 0xCB ) + { + Inst2 = Prg[ Adr++ ]; + Chaine = TabInstrCB[ Inst2 ]; + } + else + if ( Instr == 0xDD ) + { + Inst2 = Prg[ Adr++ ]; + if ( Inst2 == 0xCB ) + { + Inst3 = Prg[ Adr++ ]; + Inst4 = Prg[ Adr++ ]; + Chaine = TabInstrDDCB[ Inst4 ]; + strcpy( Inst, Chaine ); + p = strstr( Inst, "nn" ); + if ( p ) + { + if ( Inst3 < 0x80 ) + Hex( p, Inst3, 2 ); + else + { + Hex( p, -Inst3, 2 ); + p[ -1 ] = '-'; + } + } + Chaine = Inst; + } + else + Chaine = TabInstrDD[ Inst2 ]; + } + else + if ( Instr == 0xED ) + { + Inst2 = Prg[ Adr++ ]; + Chaine = TabInstrED[ Inst2 ]; + } + else + if ( Instr == 0xFD ) + { + Inst2 = Prg[ Adr++ ]; + if ( Inst2 == 0xCB ) + { + Ad8 = Prg[ Adr++ ]; + Inst3 = Prg[ Adr++ ]; + Chaine = TabInstrFDCB[ Inst3 ]; + if ( Chaine ) + { + strcpy( Inst, Chaine ); + Chaine = Inst; + p = strstr( Inst, "nn" ); + if ( p ) + Hex( p, Ad8, 2 ); + } + } + else + Chaine = TabInstrFD[ Inst2 ]; + } + if ( Chaine ) + { + strcpy( Inst, Chaine ); + p = strstr( Inst, "nnnn" ); + Ad16 = Prg[ Adr++ ]; + Ad16 += Prg[ Adr ] << 8; + Ad8 = ( char ) Ad16; + if ( p ) + { + Hex( p, Ad16, 4 ); + Adr++; + } + else + { + p = strstr( Inst, "nn" ); + if ( p ) + { + Hex( p, Ad16, 2 ); + p = strstr( Inst, "nn" ); + if ( p ) + Hex( p, Ad16 >> 8, 2 ); + } + else + { + p = strstr( Inst, "eeee" ); + if ( p ) + Hex( p, Adr + Ad8, 4 ); + else + Adr--; + } + } + } + else + sprintf( Inst, "%02X %02X %02X ????", Instr, Inst2, Inst3 ); + + Hex( &Listing[ PosD ], OldAdr, 4 ); + Listing[ PosD + 4 ] = ' '; + PosD += 5; + for ( i = OldAdr; i < Adr; i++ ) + { + Hex( &Listing[ PosD ], Prg[ i ], 2 ); + Listing[ PosD + 2 ] = ' '; + PosD += 3; + } + for ( i = 0; i < 5 - Adr + OldAdr; i++ ) + { + Listing[ PosD ] = Listing[ PosD + 1 ] = Listing[ PosD + 2 ] = ' '; + PosD += 3; + } + char * p = Inst; + while( * p ) + Listing[ PosD++ ] = * p++; + + Listing[ PosD++ ] = '\r'; + Listing[ PosD++ ] = '\n'; + } +} diff --git a/tools/iDSK/src/Desass.h b/tools/iDSK/src/Desass.h new file mode 100644 index 0000000..647f535 --- /dev/null +++ b/tools/iDSK/src/Desass.h @@ -0,0 +1,8 @@ +#ifndef DESASS_H +#define DESASS_H + + +void Desass( unsigned char * Prg, char * Desass, int Longueur ); + + +#endif diff --git a/tools/iDSK/src/GestDsk.cpp b/tools/iDSK/src/GestDsk.cpp new file mode 100644 index 0000000..f1063cd --- /dev/null +++ b/tools/iDSK/src/GestDsk.cpp @@ -0,0 +1,1183 @@ +#include +#include +#include +#include +#include +#include + +#include "MyType.h" +#include "GestDsk.h" +#include "endianPPC.h" +#include "Outils.h" +#include + +#ifdef _MSC_VER +#define snprintf _snprintf +#endif + +using namespace std; + +char Listing[ 0x280000 ]; +unsigned char BufFile[ 0x10000 ]; +int TailleFic, CurLigne; + + +// +// Verifie si en-tete AMSDOS est valide +// +bool CheckAmsdos( unsigned char * Buf ) { + int i, Checksum = 0; + bool ModeAmsdos = false; + unsigned short CheckSumFile; + CheckSumFile = Buf[ 0x43 ] + Buf[ 0x43 +1 ] *256; + for ( i = 0; i < 67; i++ ) + Checksum += Buf[ i ]; + + if ( ( CheckSumFile == ( unsigned short )Checksum ) && Checksum ) + ModeAmsdos = true; + + return( ModeAmsdos ); +} + + + +// +// Cre une en-tte AMSDOS par dfaut +// +StAmsdos * CreeEnteteAmsdos( char * NomFic, unsigned short Longueur ) { + static char NomReel[ 256 ]; + static StAmsdos Entete; + static char Nom[ 12 ]; + int i; + + strcpy( NomReel, NomFic ); + memset( &Entete, 0, sizeof( Entete ) ); + memset( Nom, ' ', sizeof( Nom ) ); + char * p = NULL; + do { + p = strchr( NomReel, '/' ); //Sous linux c'est le / qu'il faut enlever ... + if ( p ) + strcpy( NomReel, ++p ); + } while( p ); + p = strchr( NomReel, '.' ); + if ( p ) + * p++ = 0; + + int l = strlen( NomReel ); + if ( l > 8 ) + l = 8; + + for ( int i = 0; i < l; i++ ) + Nom[ i ] = ( char )toupper( NomReel[ i ] ); + + if ( p ) + for ( i = 0; i < 3; i++ ) + Nom[ i + 8 ] = ( char )toupper( p[ i ] ); + + memcpy( Entete.FileName, Nom, 11 ); + Entete.Length = 0; //Non renseign par AMSDos !! + Entete.RealLength = Entete.LogicalLength = Longueur; + Entete.FileType = 2; //Fichier binaire + + SetChecksum(&Entete); + + return( &Entete ); +} + + +// +// Calcule et positionne le checksum AMSDOS +// +void SetChecksum( StAmsdos * pEntete ) { + int i, Checksum = 0; + unsigned char * p = ( unsigned char * )pEntete; + for ( i = 0; i < 67; i++ ) + Checksum += * (p+i); + + pEntete->CheckSum = ( unsigned short )Checksum; +} + + +// +// Effectue un "nettoyage" de l'en-tete Amsdos : +// remet a zero les octets inutilises +// +void ClearAmsdos( unsigned char * Buf ) { + if ( CheckAmsdos( Buf ) ) { + int i, Checksum = 0; + StAmsdos * pEntete = ( StAmsdos * )Buf; + memset( pEntete->Unused, 0, sizeof( pEntete->Unused ) ); + memset( pEntete->Unused2, 0, sizeof( pEntete->Unused2 ) ); + for ( i = 0; i < 67; i++ ) + Checksum += Buf[ i ]; + + Buf[ 0x43 ] = ( unsigned short )Checksum; + } +} + +// +// Recherche le plus petit secteur d'une piste +// +int DSK::GetMinSect( void ) { + int Sect = 0x100; + CPCEMUTrack * tr = ( CPCEMUTrack * )&ImgDsk[ sizeof( CPCEMUEnt ) ]; + for ( int s = 0; s < tr->NbSect; s++ ) + if ( Sect > tr->Sect[ s ].R ) + Sect = tr->Sect[ s ].R; + + return( Sect ); +} + + +// +// Retourne la position d'un secteur dans le fichier DSK +// +int DSK::GetPosData( int track, int sect, bool SectPhysique ) { + // Recherche position secteur + int Pos = sizeof( CPCEMUEnt ); + CPCEMUTrack * tr = ( CPCEMUTrack * )&ImgDsk[ Pos ]; + short SizeByte; + for ( int t = 0; t <= track; t++ ) { + Pos += sizeof( CPCEMUTrack ); + for ( int s = 0; s < tr->NbSect; s++ ) { + if ( t == track ) { + if ( ( ( tr->Sect[ s ].R == sect ) && SectPhysique ) + || ( ( s == sect ) && ! SectPhysique ) + ) + break; + } + SizeByte = tr->Sect[ s ].SizeByte ; + if (SizeByte) + Pos += SizeByte; + else + Pos += ( 128 << tr->Sect[ s ].N ); + } + } + return( Pos ); +} + + +// +// Recherche un bloc libre et le remplit +// +int DSK::RechercheBlocLibre( int MaxBloc ) { + for ( int i = 2; i < MaxBloc; i++ ) + if ( ! Bitmap[ i ] ) { + Bitmap[ i ] = 1; + return( i ); + } + return( 0 ); +} + + +// +// Recherche une entre de rpertoire libre +// +int DSK::RechercheDirLibre( void ) { + for ( int i = 0; i < 64; i++ ) { + StDirEntry * Dir = GetInfoDirEntry( i ); + if ( Dir->User == USER_DELETED ) + return( i ); + } + return( -1 ); +} + + +// +// Retourne les donnes "brutes" de l'image disquette +// +unsigned char * DSK::GetRawData( int Pos ) { + return( &ImgDsk[ Pos ] ); +} + + +// +// Ecriture de donnes "brutes" dans l'image disquette +// +void DSK::WriteRawData( int Pos, unsigned char * Data, int Longueur ) { + memcpy( &ImgDsk[ Pos ], Data, Longueur ); +} + + +// +// Retourne la taille du fichier image +// +int DSK::GetTailleDsk( void ) { + CPCEMUEnt * Infos = ( CPCEMUEnt * )ImgDsk; + int NbTracks = Infos->NbTracks; + int Pos = sizeof( CPCEMUEnt ); + CPCEMUTrack * tr = ( CPCEMUTrack * )&ImgDsk[ Pos ]; + for ( int t = 0; t < NbTracks; t++ ) { + Pos += sizeof( CPCEMUTrack ); + for ( int s = 0; s < tr->NbSect; s++ ) { + if ( tr->Sect[ s ].SizeByte ) + Pos += tr->Sect[ s ].SizeByte; + else + Pos += ( 128 << tr->Sect[ s ].N ); + } + } + return( Pos ); +} + + +// +// Retourne le nombre de pistes de la disquette +// +int DSK::GetNbTracks( void ) { + CPCEMUEnt * Infos = ( CPCEMUEnt * )ImgDsk; + return( Infos->NbTracks ); +} + + +// +// Lecture d'un bloc AMSDOS (1 block = 2 secteurs) +// +unsigned char * DSK::ReadBloc( int bloc ) { + static unsigned char BufBloc[ SECTSIZE * 2 ]; + int track = ( bloc << 1 ) / 9; + int sect = ( bloc << 1 ) % 9; + int MinSect = GetMinSect(); + if ( MinSect == 0x41 ) + track += 2; + else + if ( MinSect == 0x01 ) + track++; + + int Pos = GetPosData( track, sect + MinSect, true ); + memcpy( BufBloc, &ImgDsk[ Pos ], SECTSIZE ); + if ( ++sect > 8 ) { + track++; + sect = 0; + } + + Pos = GetPosData( track, sect + MinSect, true ); + memcpy( &BufBloc[ SECTSIZE ], &ImgDsk[ Pos ], SECTSIZE ); + return( BufBloc ); +} + + +// +// Formatter une piste +// +void DSK::FormatTrack( CPCEMUEnt * Infos, int t, int MinSect, int NbSect ) { + CPCEMUTrack * tr = ( CPCEMUTrack * )&ImgDsk[ sizeof( CPCEMUEnt ) + t * Infos->DataSize ]; + memset( &ImgDsk[ sizeof( CPCEMUEnt ) + + sizeof( CPCEMUTrack ) + + ( t * Infos->DataSize ) + ] + , 0xE5 + , 0x200 * NbSect + ); + strcpy( tr->ID, "Track-Info\r\n" ); + tr->Track = ( unsigned char )t; + tr->Head = 0; + tr->SectSize = 2; + tr->NbSect = ( unsigned char )NbSect; + tr->Gap3 = 0x4E; + tr->OctRemp = 0xE5; + int ss = 0; + // + // Gestion "entrelacement" des secteurs + // + for ( int s = 0; s < NbSect; ) { + tr->Sect[ s ].C = ( unsigned char )t; + tr->Sect[ s ].H = 0; + tr->Sect[ s ].R = ( unsigned char )( ss + MinSect ); + tr->Sect[ s ].N = 2; + tr->Sect[ s ].SizeByte = 0x200; + ss++; + if ( ++s < NbSect ) { + tr->Sect[ s ].C = ( unsigned char )t; + tr->Sect[ s ].H = 0; + tr->Sect[ s ].R = ( unsigned char )( ss + MinSect + 4 ); + tr->Sect[ s ].N = 2; + tr->Sect[ s ].SizeByte = 0x200; + s++; + } + } +} + + +// +// Ecriture d'un bloc AMSDOS (1 block = 2 secteurs) +// +void DSK::WriteBloc( int bloc, unsigned char BufBloc[ SECTSIZE * 2 ] ) { + int track = ( bloc << 1 ) / 9; + int sect = ( bloc << 1 ) % 9; + int MinSect = GetMinSect(); + if ( MinSect == 0x41 ) + track += 2; + else + if ( MinSect == 0x01 ) + track++; + + // + // Ajuste le nombre de pistes si dpassement capacit + // + CPCEMUEnt * Entete = ( CPCEMUEnt * )ImgDsk; + if ( track > Entete->NbTracks - 1 ) { + Entete->NbTracks = ( unsigned char )( track + 1 ); + FormatTrack( Entete, track, MinSect, 9 ); + } + + int Pos = GetPosData( track, sect + MinSect, true ); + memcpy( &ImgDsk[ Pos ], BufBloc, SECTSIZE ); + if ( ++sect > 8 ) { + track++; + sect = 0; + } + Pos = GetPosData( track, sect + MinSect, true ); + memcpy( &ImgDsk[ Pos ], &BufBloc[ SECTSIZE ], SECTSIZE ); +} + + +// +// Ecriture d'un secteur +// +void DSK::WriteSect( int Track, int Sect, unsigned char * Buff, int AmsdosMode ) { + int MinSect = AmsdosMode ? GetMinSect() : 0; + if ( ( MinSect == 0x41 ) && AmsdosMode ) + Track += 2; + else + if ( ( MinSect == 0x01 ) && AmsdosMode ) + Track++; + + int Pos = GetPosData( Track, Sect + MinSect, AmsdosMode ); + memcpy( &ImgDsk[ Pos ], Buff, SECTSIZE ); +} + + +// +// Lecture d'un secteur +// +unsigned char * DSK::ReadSect( int Track, int Sect, int AmsdosMode ) { + int MinSect = AmsdosMode ? GetMinSect() : 0; + if ( ( MinSect == 0x41 ) && AmsdosMode ) + Track += 2; + else + if ( ( MinSect == 0x01 ) && AmsdosMode ) + Track++; + + int Pos = GetPosData( Track, Sect + MinSect, AmsdosMode ); + return( &ImgDsk[ Pos ] ); +} + + +// +// Retourne les informations d'une piste +// +CPCEMUTrack * DSK::GetInfoTrack( int Track ) { + int Pos = sizeof( CPCEMUEnt ); + CPCEMUTrack * tr = ( CPCEMUTrack * )&ImgDsk[ Pos ]; + for ( int t = 0; t < Track; t++ ) { + Pos += sizeof( CPCEMUTrack ); + + for ( int s = 0; s < tr->NbSect; s++ ) { + if ( tr->Sect[ s ].SizeByte ) + Pos += tr->Sect[ s ].SizeByte; + else + Pos += ( 128 << tr->Sect[ s ].N ); + } + } + return( ( CPCEMUTrack * )&ImgDsk[ Pos ] ); +} + +// +// Remplit un "bitmap" pour savoir o il y a des fichiers sur la disquette +// Retourne galement le nombre de Ko utiliss sur la disquette +// +int DSK::FillBitmap( void ) { + int NbKo = 0; + + memset( Bitmap, 0, sizeof( Bitmap ) ); + Bitmap[ 0 ] = Bitmap[ 1 ] = 1; + for ( int i = 0; i < 64; i++ ) { + StDirEntry * Dir = GetInfoDirEntry( i ); + if ( Dir->User != USER_DELETED ) { + for ( int j = 0; j < 16; j++ ) { + int b = Dir->Blocks[ j ]; + if ( b > 1 && ( ! Bitmap[ b ] ) ) { + Bitmap[ b ] = 1; + NbKo++; + } + } + } + } + return( NbKo ); +} + + +// +// Positionne une entre dans le rpertoire +// +void DSK::SetInfoDirEntry( int NumDir, StDirEntry * Dir ) { + int MinSect = GetMinSect(); + int s = ( NumDir >> 4 ) + MinSect; + int t = ( MinSect == 0x41 ? 2 : 0 ); + if ( MinSect == 1 ) + t = 1; + + for (int i =0; i<16; i++) + memcpy( &ImgDsk[ ( ( NumDir & 15 ) << 5 ) + GetPosData( t, s, true ) ] + , Dir + , sizeof( StDirEntry ) + ); +} + + +// +// Vrifie l'existente d'un fichier, retourne l'indice du fichier si existe, +// -1 sinon +// +int DSK::FileExist( char * Nom ) { + int i; + for ( i = 0; i < 64; i++ ) { + StDirEntry * Dir = GetInfoDirEntry( i ); + for(int q=0;q<12;q++) + Dir->Nom[q]=Dir->Nom[q]&127; // Avoid missing hidden files + if ( Dir->User != USER_DELETED + && ! strncmp( Nom, ( char * )Dir->Nom, 11 ) // 11 = 8+3 car le point est enlev + ) + return( i ); + } + return( -1 ); +} + + +StDirEntry * DSK::GetNomDir( string NomFic ) { + static StDirEntry DirLoc; + int i; + + memset( &DirLoc, 0, sizeof( DirLoc ) ); + memset( DirLoc.Nom, ' ', 8 ); + memset( DirLoc.Ext, ' ', 3 ); + size_t p = NomFic.find('.'); + if ( p!=std::string::npos ) + { + NomFic.copy( DirLoc.Nom, std::min((int)p,8), 0); + p++; + NomFic.copy( DirLoc.Ext, std::min( (int)(NomFic.size()-p), 3 ), p ); + } + else + NomFic.copy( DirLoc.Nom, std::min((int)NomFic.size(), 8 ),0); + + for ( i = 0; i < 11; i++ ) + DirLoc.Nom[ i ] = ( unsigned char )toupper( DirLoc.Nom[ i ] ); + + return( &DirLoc ); +} + + +int DSK::FileIsIn( string FileName ) { + StDirEntry * DirLoc = GetNomDir( FileName ); + return FileExist( ( char*) DirLoc->Nom ); +} + +// +// Copie un fichier sur le DSK +// +// la taille est determine par le nombre de NbPages +// regarder pourquoi different d'une autre DSK +int DSK::CopieFichier( unsigned char * BufFile, char * NomFic, int TailleFic, int MaxBloc, int UserNumber, bool System_file, bool Read_only ) { + int j, l, Bloc, PosFile, NbPages = 0, PosDir, TaillePage; + FillBitmap(); + StDirEntry * DirLoc = GetNomDir( NomFic ); //Construit l'entre pour mettre dans le catalogue + for ( PosFile = 0; PosFile < TailleFic; ) { //Pour chaque bloc du fichier + PosDir = RechercheDirLibre(); //Trouve une entre libre dans le CAT + if ( PosDir != -1 ) { + DirLoc->User = UserNumber; //Remplit l'entre : User 0 + if(System_file) DirLoc->Nom[9]|=0x80; + if(Read_only) DirLoc->Nom[8]|=0x80; + DirLoc->NumPage = ( unsigned char )NbPages++; // Numro de l'entre dans le fichier + TaillePage = (TailleFic - PosFile + 127) >> 7 ; // Taille de la page (on arrondit par le haut) + if ( TaillePage > 128 ) // Si y'a plus de 16k il faut plusieurs pages + TaillePage = 128; + + DirLoc->NbPages = ( unsigned char )TaillePage; + l = ( DirLoc->NbPages + 7 ) >> 3; //Nombre de blocs=TaillePage/8 arrondi par le haut + memset( DirLoc->Blocks, 0, 16 ); + for ( j = 0; j < l; j++ ) { //Pour chaque bloc de la page + Bloc = RechercheBlocLibre( MaxBloc ); //Met le fichier sur la disquette + if ( Bloc ) { + DirLoc->Blocks[ j ] = ( unsigned char )Bloc; + WriteBloc( Bloc, &BufFile[ PosFile ] ); + PosFile += 1024; // Passe au bloc suivant + } + else + return( ERR_NO_BLOCK ); + + } + SetInfoDirEntry( PosDir, DirLoc ); + } + else + return( ERR_NO_DIRENTRY ); + } + return( ERR_NO_ERR ); +} + + +// +// Retourne une entre du rpertoire +// +StDirEntry * DSK::GetInfoDirEntry( int NumDir ) { + static StDirEntry Dir; + int MinSect = GetMinSect(); + int s = ( NumDir >> 4 ) + MinSect; + int t = ( MinSect == 0x41 ? 2 : 0 ); + if ( MinSect == 1 ) + t = 1; + + memcpy( &Dir + , &ImgDsk[ ( ( NumDir & 15 ) << 5 ) + GetPosData( t, s, true ) ] + , sizeof( StDirEntry ) + ); + return( &Dir ); +} + + +// +// Vrifier si DSK est "standard" (DATA ou VENDOR) +// +bool DSK::CheckDsk( void ) { + CPCEMUEnt * Infos = ( CPCEMUEnt * )ImgDsk; + if ( Infos->NbHeads == 1 ) { + int MinSectFirst = GetMinSect(); + if ( MinSectFirst != 0x41 && MinSectFirst != 0xC1 && MinSectFirst != 0x01 ) + { + cout << "DSK has wrong sector number!" << endl; + return( false ); + } + + + if ( Infos->NbTracks > 42 ) + Infos->NbTracks = 42; + + for ( int track = 0; track < Infos->NbTracks; track++ ) { + // Recherche position secteur + int Pos = sizeof( CPCEMUEnt ) + ( 0x1200 + sizeof( CPCEMUTrack ) ) * track; + CPCEMUTrack * tr = ( CPCEMUTrack * )&ImgDsk[ Pos ]; + + int MinSect = 0xFF, MaxSect = 0; + if ( tr->NbSect != 9 ) + { + cout << "Warning : track " << track <<" has "<NbSect<<" sectors ! (wanted 9)" << endl; + // return( false ); + } + for ( int s = 0; s < (int)tr->NbSect; s++ ) { + if ( MinSect > tr->Sect[ s ].R ) + MinSect = tr->Sect[ s ].R; + + if ( MaxSect < tr->Sect[ s ].R ) + MaxSect = tr->Sect[ s ].R; + } + if ( MaxSect - MinSect != 8 ) + { + cout << "Warning : trange sector numbering in track "<NbHeads << endl; + return( false ); +} + + +// +// Lire un fichier DSK +// +bool DSK::ReadDsk( std::string NomFic ) { + bool Ret = false; + CPCEMUEnt * Infos; + if(sizeof(CPCEMUEnt) != 0x100) cout << "INVALID DSK BUILD" << endl; + FILE* fp ; + + if ( (fp=fopen(NomFic.c_str(),"rb"))!=NULL ) { + fread(ImgDsk,sizeof(ImgDsk),1,fp); + Infos = ( CPCEMUEnt * )ImgDsk; + if ( isBigEndian( ) ) FixEndianDsk( false ); // fix endian for Big endianness machines (PPC) + if ( ! strncmp( Infos->debut, "MV -", 4 ) + || ! strncmp( Infos->debut, "EXTENDED CPC DSK", 16 ) + ) + Ret = true; + fclose(fp); + } + return( Ret ); +} + + +// +// Formatter une disquette +// +void DSK::FormatDsk( int NbSect, int NbTrack ) { + CPCEMUEnt * Infos = ( CPCEMUEnt * )ImgDsk; + + strcpy( Infos->debut, "MV - CPCEMU Disk-File\r\nDisk-Info\r\n" ); + Infos->DataSize = ( short )( sizeof( CPCEMUTrack ) + (0x200 * NbSect) ); + Infos->NbTracks = ( unsigned char ) NbTrack; + Infos->NbHeads = 1; + for ( int t = 0; t < NbTrack; t++ ) + FormatTrack( Infos, t, 0xC1, NbSect ); + + + FillBitmap(); +} + + + +// +// Modifie le endianness de la disquette +// +void DSK::FixEndianDsk( bool littleToBig) { + CPCEMUEnt * Infos = ( CPCEMUEnt * )ImgDsk; + //std::cerr<< "FixEndianDsk() Infos->DataSize : " << Infos->DataSize <DataSize = FIX_SHORT( Infos->DataSize ); + for ( int t = 0; t < Infos->NbTracks; t++ ) + FixEndianTrack( Infos, t, 9 ); + if ( littleToBig ) + Infos->DataSize = FIX_SHORT( Infos->DataSize ); + FillBitmap(); +} + +// +// Modifie le endianness de la piste +// +void DSK::FixEndianTrack( CPCEMUEnt * Infos, int t, int NbSect ) { + CPCEMUTrack *tr; + if ( Infos->DataSize != 0 ) + tr = ( CPCEMUTrack * )&ImgDsk[ sizeof( CPCEMUEnt ) + t * Infos->DataSize ]; + else { + int ExtendedDataSize = ImgDsk[ 0x34 + t ] *256; //case of a extended dsk image + tr = ( CPCEMUTrack * )&ImgDsk[ sizeof( CPCEMUEnt ) + t * ExtendedDataSize ]; + } + int ss = 0; + + // + // Gestion "entrelacement" des secteurs + // + for ( int s = 0; s < NbSect; ) { + tr->Sect[ s ].SizeByte = FIX_SHORT( tr->Sect[ s ].SizeByte ); + tr->Sect[ s ].Un1 = FIX_SHORT( tr->Sect[ s ].Un1 ); + ss++; + if ( ++s < NbSect ) { + tr->Sect[ s ].SizeByte = FIX_SHORT( tr->Sect[ s ].SizeByte ); + tr->Sect[ s ].Un1 = FIX_SHORT( tr->Sect[ s ].Un1 ); + s++; + } + } + tr->Unused = FIX_SHORT( tr->Unused ); +} + + +// +// Ecriture du fichier DSK +// +bool DSK::WriteDsk( string NomDsk ) { + CPCEMUEnt * Infos = ( CPCEMUEnt * )ImgDsk; + FILE* fp; + int Taille,Copie; + + + if ( (fp=fopen(NomDsk.c_str(),"wb+")) != NULL) { + if ( ! Infos->DataSize ) Infos->DataSize = 0x100 + SECTSIZE * 9; + Taille = Infos->NbTracks * Infos->DataSize + sizeof( * Infos ); + if ( isBigEndian() ) FixEndianDsk( true ) ; // Fix endianness for Big endian machines (PPC) + + if ( (Copie=(fwrite(ImgDsk,1,Taille,fp))) !=Taille ) ; + fclose(fp); + // in case of the same DSK image stay in memory + if ( isBigEndian() ) FixEndianDsk( false ) ; // unFix endianness for Big endian machines (PPC) + + return( true ); + } + return( false ); +} + + +void DSK::DskEndian() { + CPCEMUEnt * Infos = ( CPCEMUEnt * )ImgDsk; + for ( int i=1 ; i<(int)Infos->NbTracks ; i++) { + CPCEMUTrack * TrackData = GetInfoTrack( i ); + TrackData = CPCEMUTrackEndian ( TrackData ) ; + } + Infos = CPCEMUEntEndian ( Infos ) ; +} + + +StAmsdos* DSK::StAmsdosEndian ( StAmsdos * pEntete ){ + pEntete->Length = FIX_SHORT( pEntete->Length ); + pEntete->Adress = FIX_SHORT( pEntete->Adress ); + pEntete->LogicalLength = FIX_SHORT( pEntete->LogicalLength); + pEntete->EntryAdress = FIX_SHORT( pEntete->EntryAdress ); + pEntete->RealLength = FIX_SHORT( pEntete->RealLength ); + pEntete->CheckSum = FIX_SHORT( pEntete->CheckSum ) ; + return ( pEntete ); +} + + +CPCEMUEnt* DSK::CPCEMUEntEndian ( CPCEMUEnt* Infos ) { + Infos->DataSize = FIX_SHORT( Infos->DataSize ); + return (Infos); +} + + +CPCEMUTrack* DSK::CPCEMUTrackEndian ( CPCEMUTrack* tr ) { + for ( int i=0;i < (int)tr->NbSect ; i++) { + tr->Sect[i] = CPCEMUSectEndian( tr->Sect[i] ); + } + + return ( tr); + +} + + +CPCEMUSect DSK::CPCEMUSectEndian ( CPCEMUSect Sect) { + Sect.Un1 = FIX_SHORT( Sect.Un1 ); + Sect.SizeByte = FIX_SHORT( Sect.SizeByte ); + return (Sect); +} + +// Retourne le type de fichier sous forme de chaine +// +const char * DSK::GetType( int Langue, StAmsdos * Ams ) { + if ( CheckAmsdos( ( unsigned char * )Ams ) ) { + switch( Ams->FileType ) { + case 0 : // BASIC + return( "BASIC"); //GetTexteLoc( 22, Langue ) ); + + case 1 : // BASIC (P) + return( "BASIC(P)"); // GetTexteLoc( 23, Langue ) ); + + case 2 : // BINAIRE + return("BINAIRE"); // GetTexteLoc( 24, Langue ) ); + + case 3 : // BINAIRE (P) + return( "BINAIRE(P)"); //GetTexteLoc( 25, Langue ) ); + + default : + return( "INCONNU"); // GetTexteLoc( 26, Langue ) ); + } + } + return("ASCII"); // GetTexteLoc( 27, Langue ) ); +} + +char * DSK::GetEntryNameInCatalogue ( int num , char* Nom ) { + int PosItem[ 64 ]; + StDirEntry TabDir[ 64 ]; + + memset( PosItem, 0, sizeof( PosItem ) ); + + for ( int i = 0; i < 64; i++ ) + memcpy( &TabDir[ i ], GetInfoDirEntry( i ), sizeof( StDirEntry )); + + for ( int i = 0; i < 64; i++ ) { + SetInfoDirEntry( i, &TabDir[ i ] ); + + if ( TabDir[ i ].User != USER_DELETED && ! TabDir[ i ].NumPage && num == i) { + memcpy( Nom, TabDir[ i ].Nom, 8 ); + memcpy( &Nom[ 9 ], TabDir[ i ].Ext, 3 ); + Nom[ 8 ] = '.'; + Nom[ 12 ] = 0; + for ( int j = 0; j < 12; j++ ) + Nom[ j ] &= 0x7F; + for ( int j = 0; j < 12; j++ ) + if ( ! isprint( Nom[ j ] ) ) + Nom[ j ] = '?' ; + return Nom; + } + } + return Nom; +} + +char * DSK::GetEntrySizeInCatalogue ( int num , char* Size ) { + int PosItem[ 64 ]; + StDirEntry TabDir[ 64 ]; + + + memset( PosItem, 0, sizeof( PosItem ) ); + + for ( int i = 0; i < 64; i++ ) + memcpy( &TabDir[ i ], GetInfoDirEntry( i ), sizeof( StDirEntry )); + + for ( int i = 0; i < 64; i++ ) { + SetInfoDirEntry( i, &TabDir[ i ] ); + + if ( TabDir[ i ].User != USER_DELETED && ! TabDir[ i ].NumPage && num == i) { + int p = 0, t = 0; + do { + if ( TabDir[ p + i ].User == TabDir[ i ].User ) { + t += TabDir[ p + i ].NbPages; + } + p++; + } + while( TabDir[ p + i ].NumPage && ( p + i ) < 64 ); + sprintf( Size, "%d Ko", ( t + 7 ) >>3 ); + return Size; + } + } + return Size; +} + + +bool DSK::GetFileInDsk( char* path, int Indice ){ + int i = Indice; + char current[ 16 ]; + char NomIndice[ 16 ]; + int lMax = 0x1000000; + int cumul=0; + FILE* f; + StDirEntry TabDir[ 64 ]; + + if ( (f=fopen(path,"wb"))==NULL ) + return false; + + for ( int i = 0; i < 64; i++ ) + memcpy( &TabDir[ i ], GetInfoDirEntry( i ), sizeof( StDirEntry )); + + + memset( NomIndice, 0 , sizeof( NomIndice ) ); + strncpy( NomIndice, GetNomAmsdos( TabDir[ i ].Nom ), 16); + strncat( NomIndice, GetNomAmsdos( TabDir[ i ].Ext), 3); + + do + { + // Longueur du fichier + int l = ( TabDir[ i ].NbPages + 7 ) >> 3; + for ( int j = 0; j < l; j++ ) { + int TailleBloc = 1024; + unsigned char * p = ReadBloc( TabDir[ i ].Blocks[ j ] ); + int NbOctets = min( lMax, TailleBloc ); + if ( NbOctets > 0 ) { + fwrite(p,1,NbOctets,f); + cumul+=NbOctets; + } + lMax -= 1024; + } + memset( current , 0, sizeof( current ) ); + i++; + strncpy(current, GetNomAmsdos( TabDir[ i ].Nom ), 16 ); + strncat(current, GetNomAmsdos( TabDir[ i ].Ext ), 3); + + if ( i > 64 ) return false; + }while (! strncmp( NomIndice, current , max( strlen( NomIndice ), strlen( current ) ))); + + fclose (f); + return true; +} + + +bool DSK::PutFileInDsk( string Masque ,int TypeModeImport ,int loadAdress, int exeAdress, int UserNumber, bool System_file, bool Read_only ) { + static unsigned char Buff[ 0x20000 ]; + static char *cFileName; + unsigned long Lg; + bool ret; + FILE* Hfile; + if ( NULL==(cFileName = (char*)malloc(16*sizeof(char))) ) + return false; + + cFileName = GetNomAmsdos((char *)Masque.c_str()); + if (( Hfile = fopen(Masque.c_str(),"rb")) == NULL ) return false; + Lg=fread(Buff,1, 0x20000 ,Hfile); + fclose( Hfile ); + bool AjouteEntete = false; + StAmsdos * e = ( StAmsdos * )Buff; + // Attention : longueur > 64Ko ! + if ( Lg > 0x10080 ) { + free(cFileName); + return false; + } + + // + // Regarde si le fichier contient une en-tete ou non + // + bool IsAmsdos = CheckAmsdos( Buff ); + + if ( ! IsAmsdos ) { + // Creer une en-tete amsdos par defaut + cout << "Cration automatique d'une en-tte pour le fichier ...\n"; + e = CreeEnteteAmsdos( cFileName, ( unsigned short )Lg ); + if ( loadAdress != 0) + { + e->Adress = (unsigned short)loadAdress; + TypeModeImport = MODE_BINAIRE; + } + if ( exeAdress != 0 ) + { + e->EntryAdress = (unsigned short)exeAdress; + TypeModeImport = MODE_BINAIRE; + } + // Il faut recalculer le checksum en comptant es adresses ! + SetChecksum(e); + // fix the endianness of the input file + if ( isBigEndian() ) e = StAmsdosEndian(e); + } + else + cout << "Le fichier a dj une en-tte\n"; + // + // En fonction du mode d'importation... + // + switch( TypeModeImport ) { + case MODE_ASCII : + // + // Importation en mode ASCII + // + if ( IsAmsdos ) { + // Supprmier en-tete si elle existe + memcpy( Buff, &Buff[ sizeof( StAmsdos ) ], Lg - sizeof( StAmsdos )); + Lg -= sizeof( StAmsdos ); + } + break; + + case MODE_BINAIRE : + // + // Importation en mode BINAIRE + // + + if ( ! IsAmsdos ) + // + // Indique qu'il faudra ajouter une en-tete + // + AjouteEntete = true; + break; + + } + + // + // Si fichier ok pour etre import + // + if ( AjouteEntete ) { + // Ajoute l'en-tete amsdos si necessaire + + memmove( &Buff[ sizeof( StAmsdos ) ], Buff, Lg ); + memcpy( Buff, e, sizeof( StAmsdos ) ); + Lg += sizeof( StAmsdos ); + } + + //if (MODE_BINAIRE) ClearAmsdos(Buff); //Remplace les octets inutiliss par des 0 dans l'en-tte + + if ( CopieFichier( Buff,cFileName,Lg,256, UserNumber, System_file, Read_only) != ERR_NO_ERR ) + ret = false; + else + ret = true; + + return ret; +} + + +bool DSK::OnViewFic(int nItem) { + int LongFic = 0; + memset( BufFile, 0, sizeof( BufFile ) ); + memset( Listing, 0, sizeof( Listing ) ); + char NomFic[ 16 ]; + char current[ 16 ]; + int i = nItem; + bool FirstBlock = true; + StDirEntry TabDir[ 64 ]; + + for ( int j = 0; j < 64; j++ ) + memcpy( &TabDir[ j ], GetInfoDirEntry( j ), sizeof( StDirEntry )); + + memset( NomFic, 0 , sizeof( NomFic ) ); + strncpy( NomFic, GetNomAmsdos( TabDir[ i ].Nom ), 16); + strncat( NomFic, GetNomAmsdos( TabDir[ i ].Ext), 3); + + int lMax = sizeof( BufFile ); + + TailleFic = 0; + + + do + { + // Longueur du fichier + int l = ( TabDir[ i ].NbPages + 7 ) >> 3; + for ( int j = 0; j < l; j++ ) { + int TailleBloc = 1024; + unsigned char * p = ReadBloc( TabDir[ i ].Blocks[ j ] ); + if ( FirstBlock ) { + if ( CheckAmsdos( p ) ) { + TailleFic = p[ 0x18 +1 ] *256 + p[ 0x18 ]; + TailleBloc -= sizeof( StAmsdos ); + memcpy( p , &p[ 0x80 ] , TailleBloc ); + } + FirstBlock = false; + + } + int NbOctets = min( lMax, TailleBloc ); + if ( NbOctets > 0 ) { + memcpy( &BufFile[ LongFic ], p, NbOctets ); + LongFic += NbOctets; + } + lMax -= 1024; + } + memset( current , 0, sizeof( current ) ); + i++; + strncpy(current, GetNomAmsdos( TabDir[ i ].Nom ), 16 ); + strncat(current, GetNomAmsdos( TabDir[ i ].Ext ), 3); + if ( i > 64 ) return false; + }while( ! strncmp( NomFic, current, max( strlen( current ), strlen( NomFic ) ) ) ); + + if ( TailleFic == 0 ) + TailleFic = LongFic; + return true; +} + + +bool DSK::Hexdecimal() { + + int TailleCourante=0; + char OffSet[ 7 ]; + const char * CodeHexa = "0123456789ABCDEF"; + + while (TailleCourante <= TailleFic ) { + // display the offset + memset( OffSet, 0 , 7 ); + snprintf( OffSet,6,"#%.4X:", TailleCourante ); + strcat( Listing, OffSet ); + strcat( Listing, " "); + char Ascii[ 18 ]; + char Hex[ 16 *3 +1 ]; + memset( Ascii, 0 , 18 ); + memset( Hex , 0 , ( 16*3 +1) ); + for ( int i=0; i<16 ; ++i ) { + unsigned char cur = BufFile[ TailleCourante + i ]; + // manage the ascii display + if ( cur > 32 && cur < 125 ) + Ascii[ i ] = cur; + else + Ascii[ i ] = '.'; + char Val[ 4 ]; + // manage the hexadeciaml display + Val[ 0 ] = CodeHexa[ cur >> 4 ]; + Val[ 1 ] = CodeHexa[ cur & 0x0F ]; + Val[ 2 ] = ' '; + Val[ 3 ] ='\0'; + strcat( Hex, Val ); + } + Ascii[ 16 ] = '\n'; + strcat( Listing, Hex ); + strcat( Listing, "| "); + strcat( Listing, Ascii ); + TailleCourante += 16; + } + + return true; +} + + +void DSK::RemoveFile ( int item ) { + char NomFic[ 16 ]; + int i = item; + StDirEntry TabDir[ 64 ]; + + for ( int j = 0; j < 64; j++ ) + memcpy( &TabDir[ j ], GetInfoDirEntry( j ), sizeof( StDirEntry )); + + strcpy( NomFic, GetNomAmsdos( TabDir[ i ].Nom ) ); + char *p ; + + do { + TabDir[ i ].User = USER_DELETED; + SetInfoDirEntry( i, &TabDir[ i ]); + p = GetNomAmsdos( TabDir[ ++i ].Nom) ; + } while ( ! strncmp( NomFic, p , max(strlen( p ), strlen( NomFic ) )) ); + + + return ; +} + + + +void DSK::RenameFile( int item , char *NewName) { + char NomFic[ 16 ]; + StDirEntry TabDir[ 64 ]; + StDirEntry DirLoc; + int c = item; + for ( int j = 0; j < 64; j++ ) + memcpy( &TabDir[ j ], GetInfoDirEntry( j ), sizeof( StDirEntry )); + + memset( DirLoc.Nom, ' ', 8); + memset( DirLoc.Ext, ' ', 3); + for ( int i=0; i<(int) strlen( NewName ) ; ++i) + NewName[ i ] = toupper( NewName[ i ] ); + + char *p = strchr( NewName, '.'); + + if ( p ) { + p++; + memcpy( DirLoc.Nom, NewName, p - NewName -1); + memcpy( DirLoc.Ext, p, std::min((int)strlen(p),3) ); + } + else { + memcpy( DirLoc.Nom, NewName, min( (int)strlen( NewName) , 8 ) ); + } + strcpy( NomFic, GetNomAmsdos( TabDir[ c ].Nom )); + + do { + memcpy( TabDir[ c ].Nom , DirLoc.Nom , 8 ); + memcpy( TabDir[ c ].Ext , DirLoc.Ext, 3 ); + SetInfoDirEntry( c, &TabDir[ c ]); + p = GetNomAmsdos( TabDir[ ++c ].Nom ); + }while (!strncmp( NomFic, p , max(strlen(p),strlen(NomFic)))); +} + + +std::string DSK::ReadDskDir( void ) { + StDirEntry TabDir[ 64 ]; + string catalogue; + for ( int i = 0; i < 64; i++ ) { + memcpy( &TabDir[ i ] + , GetInfoDirEntry( i ) + , sizeof( StDirEntry ) + ); + } + // Trier les fichiers + for ( int i = 0; i < 64; i++ ) { + // + // Afficher les fichiers non effacs + // + if ( TabDir[ i ].User != USER_DELETED && ! TabDir[ i ].NumPage ) { + char Nom[ 13 ]; + memcpy( Nom, TabDir[ i ].Nom, 8 ); + memcpy( &Nom[ 9 ], TabDir[ i ].Ext, 3 ); + Nom[ 8 ] = '.'; + Nom[ 12 ] = 0; + // + // Masquer les bits d'attributs + // + for ( int j = 0; j < 12; j++ ) + { + Nom[ j ] &= 0x7F; + + if ( ! isprint( Nom[ j ] ) ) + Nom[ j ] = '?' ; + } + + catalogue += Nom; + catalogue += " "; + ostringstream c; + c << (int)TabDir[i].User; + catalogue += c.str(); + // + // Calcule la taille du fichier en fonction du nombre de blocs + // + int p = 0, t = 0; + do { + if ( TabDir[ p + i ].User == TabDir[ i ].User ) + t += TabDir[ p + i ].NbPages; + p++; + } while( TabDir[ p + i ].NumPage && ( p + i ) < 64 ); + //string size = GetTaille( ( t + 7 ) >> 3 ); + //catalogue+= " : " + size + "\n"; + catalogue += "\n"; + + } + } + return catalogue; +} diff --git a/tools/iDSK/src/GestDsk.h b/tools/iDSK/src/GestDsk.h new file mode 100644 index 0000000..b825ab4 --- /dev/null +++ b/tools/iDSK/src/GestDsk.h @@ -0,0 +1,168 @@ +#ifndef GESTDSK_H +#define GESTDSK_H + +#include + +#define USER_DELETED 0xE5 + + +extern char Listing[ 0x280000 ]; +extern unsigned char BufFile[ 0x10000 ]; + + +extern int TailleFic, CurLigne; + +#pragma pack(1) //evite le padding des structures qui sont utilisées dans des memcpy par la suite + +// +// Structure d'une entree AMSDOS +// +typedef struct +{ + unsigned char UserNumber; // 00 User + unsigned char FileName[15]; // 01-0F Nom + extension + unsigned char BlockNum; // 10 Numéro du bloc (disquette) + unsigned char LastBlock; // 11 Flag "dernier bloc" bloc (disquette) + unsigned char FileType; // 12 Type de fichier + unsigned short Length; // 13-14 Longueur + unsigned short Adress; // 15-16 Adresse + unsigned char FirstBlock; // 17 Flag premier bloc de fichier (disquette) + unsigned short LogicalLength; // 18-19 Longueur logique + unsigned short EntryAdress; // 1A-1B Point d'entree + unsigned char Unused[0x24]; + unsigned short RealLength; // 40-42 Longueur reelle + unsigned char BigLength; // Longueur reelle (3 octets) + unsigned short CheckSum; // 43-44 CheckSum Amsdos + unsigned char Unused2[0x3B]; +} StAmsdos; + + +#define SECTSIZE 512 + + +typedef struct +{ + char debut[0x30]; // "MV - CPCEMU Disk-File\r\nDisk-Info\r\n" + unsigned char NbTracks; + unsigned char NbHeads; + unsigned short DataSize; // 0x1300 = 256 + ( 512 * nbsecteurs ) + unsigned char Unused[0xCC]; +} CPCEMUEnt; + + +typedef struct +{ + unsigned char C; // track + unsigned char H; // head + unsigned char R; // sect + unsigned char N; // size + short Un1; + short SizeByte; // Taille secteur en octets +} CPCEMUSect; + + +typedef struct +{ + char ID[0x10]; // "Track-Info\r\n" + unsigned char Track; + unsigned char Head; + short Unused; + unsigned char SectSize; // 2 + unsigned char NbSect; // 9 + unsigned char Gap3; // 0x4E + unsigned char OctRemp; // 0xE5 + CPCEMUSect Sect[29]; +} CPCEMUTrack; + +#ifdef __GNUC__ +#define PACK( __Declaration__ ) __Declaration__ __attribute__((__packed__)) +#else +#define PACK( __Declaration__ ) __pragma( pack(push, 1) ) __Declaration__ __pragma( pack(pop) ) +#endif + +PACK(typedef struct +{ + unsigned char User; + char Nom[8]; + char Ext[3]; + unsigned char NumPage; + unsigned char Unused[2]; + unsigned char NbPages; + unsigned char Blocks[16]; +}) StDirEntry; + +#pragma pack() + +enum { ERR_NO_ERR = 0, ERR_NO_DIRENTRY, ERR_NO_BLOCK, ERR_FILE_EXIST }; + +bool CheckAmsdos( unsigned char * Buf ); +StAmsdos * CreeEnteteAmsdos( char * NomFic, unsigned short Length ); +void ClearAmsdos( unsigned char * Buf ); +void SetChecksum( StAmsdos * pEntete ); +bool CheckAmsdos( unsigned char * Buf ); + + +class DSK +{ + unsigned char ImgDsk[ 0x80000 ]; + unsigned char Bitmap[ 256 ]; + + unsigned char * GetRawData( int Pos ); + void WriteRawData( int Pos, unsigned char * Data, int Longueur ); + int GetNbTracks( void ); + void WriteBloc( int bloc, unsigned char * BufBloc ); + void WriteSect( int Track, int Sect, unsigned char * Buff, int AmsdosMode ); + unsigned char * ReadSect( int Track, int Sect, int AmsdosMode ); + CPCEMUTrack * GetInfoTrack( int Track ); + int FillBitmap( void ); + void DskEndian(); + CPCEMUEnt* CPCEMUEntEndian ( CPCEMUEnt* Infos ); + CPCEMUTrack* CPCEMUTrackEndian ( CPCEMUTrack* tr ); + CPCEMUSect CPCEMUSectEndian ( CPCEMUSect Sect); + const char * GetType( int Langue, StAmsdos * Ams ); + int GetMinSect( void ); + int GetPosData( int track, int sect, bool SectPhysique ); + int RechercheBlocLibre( int MaxBloc ); + void FormatTrack( CPCEMUEnt * Infos, int t, int MinSect, int NbSect ); + +public: + DSK(){} + DSK(const DSK& d) + { + for (int i=0; i< 0x80000; i++) + ImgDsk[i]=d.ImgDsk[i]; + for (int j=0; j< 256 ; j++ ) + Bitmap[j]=d.Bitmap[j]; + } + + ~DSK(){} + + int GetTailleDsk(); + StDirEntry * GetNomDir(std::string Nom ); + int CopieFichier( unsigned char * BufFile, char * NomFic, int TailleFic, int MaxBloc, int, bool,bool ); + bool WriteDsk( std::string NomDsk ); + unsigned char * ReadBloc( int bloc ); + bool ReadDsk( std::string NomFic ); + bool CheckDsk( void ); + int FileExist( char * Nom ); + StDirEntry * GetInfoDirEntry( int NumDir ); + int FileIsIn( std::string FileName ); + int RechercheDirLibre( void ); + void FormatDsk( int NbSect, int NbTrack ); + StAmsdos* StAmsdosEndian ( StAmsdos * pEntete ); + void SetInfoDirEntry( int NumDir, StDirEntry * Dir ); + char * GetEntryNameInCatalogue ( int num , char* Nom ); + char * GetEntrySizeInCatalogue ( int num , char* Size ); + bool GetFileInDsk( char* path, int Indice ); + bool PutFileInDsk( std::string Masque ,int TypeModeImport ,int loadAdress, int exeAdress, int,bool,bool ); + bool OnViewFic(int nItem); + bool Hexdecimal(); + void RemoveFile ( int item ); + void FixEndianDsk( bool LittleToBig ); + void FixEndianTrack( CPCEMUEnt * Infos, int t, int NbSect ); + void RenameFile( int item , char *NewName); + std::string ReadDskDir(void); + +}; + +#endif diff --git a/tools/iDSK/src/Main.cpp b/tools/iDSK/src/Main.cpp new file mode 100644 index 0000000..f8bcdce --- /dev/null +++ b/tools/iDSK/src/Main.cpp @@ -0,0 +1,284 @@ +#include +#include +#include +#include // pour contourner un bug de std::vector ... + +#include "getopt_pp.h" /* Command line handling */ + +using namespace std; + +#include "MyType.h" +#include "GestDsk.h" +#include "Outils.h" +#include "Main.h" +#include "endianPPC.h" +#include "ViewFile.h" + +int main(int argc, char** argv) { + bool IsDskLoc, IsDskSet, + ModeListDsk, ModeImportFile, + ModeRemoveFile, + ModeDisaFile, ModeListBasic, + ModeListDams,ModeListHex, + ModeGetFile, ModeNewDsk, Force_Overwrite, + Read_only, System_file; + + ModeListDsk = ModeImportFile = + ModeRemoveFile = ModeDisaFile = + ModeListBasic = ModeListDams = ModeListHex = ModeNewDsk = + ModeGetFile = IsDskLoc = IsDskSet = Force_Overwrite = Read_only = System_file = false ; + + string DskFile, AmsdosFile; + vector AmsdosFileList; + + int exeAdress=0,loadAdress=0,AmsdosType=1, UserNumber=0; + + DSK MyDsk; + + IsDsk = IsDskValid = false; + IsDskSaved = true; + + // Rcupration des arguments avec getopt_pp +{using namespace GetOpt; + GetOpt_pp opts(argc,argv); + + opts >> GlobalOption(DskFile); + if (DskFile != "") + IsDskSet = true; + + opts >> OptionPresent('l',"list",ModeListDsk) + + >> OptionPresent('i',"import",ModeImportFile) + >> Option('i',"import",AmsdosFileList) + + >> OptionPresent('r',"remove",ModeRemoveFile) + >> Option('r',"remove",AmsdosFileList) + + >> OptionPresent('n',"new",ModeNewDsk) + + >> OptionPresent('z',"disassemble",ModeDisaFile) + >> Option('z',"disassemble",AmsdosFileList) + + >> OptionPresent('b',"basic",ModeListBasic) + >> Option('b',"basic",AmsdosFileList) + + >> OptionPresent('d',"dams",ModeListDams) + >> Option('d',"dams",AmsdosFileList) + + >> OptionPresent('h',"hex",ModeListHex) + >> Option('h',"hex",AmsdosFileList) + + >> std::hex >> Option('e',"exec",exeAdress) + >> Option('c',"load",loadAdress) + >> std::dec >> Option('t',"type",AmsdosType) + + >> OptionPresent('g',"get",ModeGetFile) + >> Option('g',"get",AmsdosFileList) + + >> OptionPresent('f',"force",Force_Overwrite) + >> OptionPresent('o',"write-protect",Read_only) + >> OptionPresent('s',"system",System_file) + >> Option('u',"user",UserNumber) + ; + + if(opts.options_remain()) + { + cout << "Unhandled option ! Check the syntax." << endl; + exit(EXIT_FAILURE); + } + +}//namespace getopt + + if ( ! IsDskSet ) { + cerr << "You did not select a DSK file to work with !" << endl; + help(); + } + else cerr << "DSK : " << DskFile << endl; + + if ( ModeListBasic || ModeListHex || ModeListDams || ModeDisaFile ) + { + if ( ! MyDsk.ReadDsk(DskFile)) + { + cerr<< "Error reading file ("<< DskFile << ")."<::iterator iter=AmsdosFileList.begin(); iter!=AmsdosFileList.end(); iter++) + { + char* amsdosF = GetNomAmsdos(iter->c_str()); + cerr << "Amsdos file : " << amsdosF << endl; + if ( (Indice= MyDsk.FileIsIn( amsdosF ))<0) { + cerr << "Error: File "<< amsdosF << " not found."<< endl; + exit(EXIT_FAILURE); + } + MyDsk.OnViewFic(Indice); + + if ( ModeListBasic ) + cout << ViewBasic( ) << endl; + else if ( ModeListDams ) + cout << "Not yet coded ! Please try a newer version of iDSK ! Sorry !"<::iterator iter=AmsdosFileList.begin(); iter!=AmsdosFileList.end(); iter++) + { + string amsdosfile = GetNomAmsdos(iter->c_str()); + int Indice; + if ( ( Indice = MyDsk.FileIsIn( amsdosfile ) ) != -1 && !Force_Overwrite) { + cerr << "(" << amsdosfile <<") File exists, replace ? (Y/N) (try -f switch for autoreplace...):"; + string answer ; + cin >> answer; + if ( toupper(answer[0]) == 'Y') + MyDsk.RemoveFile(Indice); + else { + cerr<<"Import cancelled, dsk unchanged."<::iterator iter=AmsdosFileList.begin(); iter!=AmsdosFileList.end(); iter++) + { + char* amsdosF = GetNomAmsdos(iter->c_str()); + cerr << "Amsdos file : " << amsdosF << endl; + if ( (Indice= MyDsk.FileIsIn( amsdosF ))<0) { + cerr << "Error : file "<< amsdosF << " not found."<< endl; + exit(EXIT_FAILURE); + } + MyDsk.RemoveFile(Indice); + if ( MyDsk.WriteDsk ((char*)DskFile.c_str()) ) + cout << MyDsk.ReadDskDir(); + else cerr<< "Error writing file " << (*iter) << endl; + } + } + + if ( ModeGetFile ) { + if ( ! MyDsk.ReadDsk( (char*)DskFile.c_str() ) ) { + cerr<< "Error reading dskfile ("<< DskFile << ")."<::iterator iter=AmsdosFileList.begin(); iter!=AmsdosFileList.end(); iter++) + { + char* amsdosF = GetNomAmsdos(iter->c_str()); + cerr << "Fichier Amsdos : " << amsdosF << endl; + if ( (Indice= MyDsk.FileIsIn( amsdosF ))<0) { + cerr << "Error : file "<< amsdosF << " not found."<< endl; + exit(EXIT_FAILURE); + } + if ( ! MyDsk.GetFileInDsk((char*)(*iter).c_str(),Indice) ) { + cerr <<"System error : unable to copy ("< [OPTIONS] [files to process]" << endl; + cout << "OPTIONS : EXAMPLE" << endl; + cout << "-l : List disk catalog iDSK floppy.dsk -l" << endl; + cout << "-g : export ('Get') file iDSK floppy.dsk -g myprog.bas"< +#include +#include +using namespace std; +#include "Outils.h" + +// +// Initialise une chaine au format hexad�cimal en fonction de la valeur d'entr�e +// +void Hex( char Chaine[], int Valeur, int Digit ) +{ + static char TabDigit[ 17 ] = "0123456789ABCDEF"; + + while( Digit ) + * Chaine++ = TabDigit[ ( Valeur >> ( 4 * ( --Digit ) ) ) & 0x0F ]; +} + + +// +// Conversion hexa->d�cimal +// +int HexToDec( char * Valeur ) +{ + char * p = strchr( Valeur, 'X' ); + if ( p ) + Valeur = ++p; + + p = strchr( Valeur, 'x' ); + if ( p ) + Valeur = ++p; + + p = strchr( Valeur, '#' ); + if ( p ) + Valeur = ++p; + + p = strchr( Valeur, '$' ); + if ( p ) + Valeur = ++p; + + p = strchr( Valeur, '&' ); + if ( p ) + Valeur = ++p; + + int Ret = 0, i = 0; + while( Valeur[ i ] ) + { + Ret <<= 4; + char c = Valeur[ i++ ]; + if ( c >= '0' && c <= '9' ) + Ret += c - '0'; + else + Ret += ( c & 0x5F ) - 0x37; + } + return( Ret ); +} + + +// +// Conversion d'un secteur (512 octets) en affichage Hexa et ASCII +// +void SetBuffViewHexa( unsigned char * src, char * Hex, char * Ascii, unsigned short Offset, int AddOffset) +{ + const char * CodeHexa = "0123456789ABCDEF"; + int q = 0,i; + + // + // Parcourir les 512 octets de la source et remplir les buffers + // + for ( i = 0; i < 512; i++ ) + { + unsigned char b = * src++; + if ( b > 32 && b < 127 ) + { + Ascii[ i ] = b; + // cout << "b32:" << (int)b <<" Ascii["<> 12 ]; + Hex[ q++ ] = CodeHexa[ ( Offset >> 8 ) & 0x0F ]; + Hex[ q++ ] = CodeHexa[ ( Offset >> 4 ) & 0x0F ]; + Hex[ q++ ] = CodeHexa[ Offset & 0x0F ]; + Hex[ q++ ] = ':'; + } + Offset++; + Hex[ q++ ] = CodeHexa[ b >> 4 ]; + Hex[ q++ ] = CodeHexa[ b & 0x0F ]; + Hex[ q++ ] = ' '; + } + Hex[ q ] = 0; + Ascii[ i ] = 0; +} + + +// +// Retourne le num�ro d'user sous forme de chaine +// +char * GetUser( int u ) +{ + static char User[ 8 ]; + sprintf(User, "%d", u); + return( User); +} + + + +// +// Retourne la taille du fichier sous forme de chaine +// +char * GetTaille( int t ) +{ + static char Taille[ 16 ]; + + sprintf( Taille, "%d Ko", t ); + return( Taille ); +} + + +// +// Retourne le nom du fichier formatt� amsdos (8+3) +// +char * GetNomAmsdos(const char * AmsName ) +{ + // Extract the name (without directory components) + const char* lastSlash = strrchr(AmsName, '/'); + const char* lastBackslash = strrchr(AmsName, '\\'); + if (lastSlash > lastBackslash) + AmsName = lastSlash + 1; + else if (lastSlash < lastBackslash) + AmsName = lastBackslash + 1; + + static char NomAmsdos[ 16 ]; + int i; + + char * p = NomAmsdos; + for ( i = 0; i < 8; i++ ) { + if ( * AmsName != ' ' && *AmsName != '.' ) + * p++ = * AmsName++; + /*if ( * AmsName == '-' ) + * p++ = * AmsName++;*/ + } + + while( * AmsName != '.' && * AmsName ) + AmsName++; + + AmsName++; + + * p = 0; + strcat( NomAmsdos, "." ); + + for ( i = 0; * AmsName && i < 3; i++ ) + *++p = * AmsName++; + + * ++p = 0; + i = 0; + while( NomAmsdos[ i ] ) + NomAmsdos[ i++ ] &= 0x7F; + + return( NomAmsdos ); +} diff --git a/tools/iDSK/src/Outils.h b/tools/iDSK/src/Outils.h new file mode 100644 index 0000000..3e64dc4 --- /dev/null +++ b/tools/iDSK/src/Outils.h @@ -0,0 +1,19 @@ +#ifndef __OUTILS_H__ +#define __OUTILS_H__ + + +void Hex( char Chaine[], int Valeur, int Digit ); + +int HexToDec( char * Valeur ); + +void SetBuffViewHexa( unsigned char * src, char * Hex, char * Ascii,unsigned short Offset, int AddOffset); + +char * GetNomAmsdos( const char * AmsName ); + +char * GetUser( int u ); + +char * GetTaille( int t ); + + + +#endif diff --git a/tools/iDSK/src/ViewFile.cpp b/tools/iDSK/src/ViewFile.cpp new file mode 100644 index 0000000..9ad2de7 --- /dev/null +++ b/tools/iDSK/src/ViewFile.cpp @@ -0,0 +1,36 @@ +#include +using namespace std; +#include "GestDsk.h" +#include "Outils.h" +#include "Basic.h" +#include "Desass.h" +#include "Dams.h" +#include "endianPPC.h" +#include "ViewFile.h" + +string ViewDams( ) +{ + cerr << "Taille du fichier : " << TailleFic << endl; + Dams( BufFile, TailleFic , Listing ); + return Listing; + //cout << Listing << endl; +} + + +string ViewDesass( ) +{ + cerr << "Taille du fichier : " << TailleFic << endl; + Desass( BufFile, Listing, TailleFic ); + return Listing; + //cout << Listing << endl; +} +string ViewBasic( ) +{ + bool IsBasic=true; + //cout << "Entre Ici\n"; + cerr << "Taille du fichier : " << TailleFic << endl; + Basic( BufFile, Listing, IsBasic, true ); + //cout << Listing << endl; + return Listing; + +} diff --git a/tools/iDSK/src/ViewFile.h b/tools/iDSK/src/ViewFile.h new file mode 100644 index 0000000..fd9b645 --- /dev/null +++ b/tools/iDSK/src/ViewFile.h @@ -0,0 +1,13 @@ +#ifndef __VIEWFILE_H__ +#define __VIEWFILE_H__ + + + + +string ViewDams(); +string ViewLine(); +string ViewDesass(); +string ViewBasic(); + + +#endif diff --git a/tools/iDSK/src/endianPPC.cpp b/tools/iDSK/src/endianPPC.cpp new file mode 100644 index 0000000..7b51225 --- /dev/null +++ b/tools/iDSK/src/endianPPC.cpp @@ -0,0 +1,20 @@ +#include +#include +using namespace std; +#include "endianPPC.h" + +#ifndef _MSC_VER +#include +#include +#endif + +bool isBigEndian(void) +{ +#ifdef BYTE_ORDER + return BYTE_ORDER == BIG_ENDIAN; +#elif defined _MSC_VER + return true; // It doesn't run on anything except x86, right? +#else + return __BYTE_ORDER == __BIG_ENDIAN; +#endif +} diff --git a/tools/iDSK/src/endianPPC.h b/tools/iDSK/src/endianPPC.h new file mode 100644 index 0000000..9def637 --- /dev/null +++ b/tools/iDSK/src/endianPPC.h @@ -0,0 +1,22 @@ +#ifndef __ENDIANPPC_H__ +#define __ENDIANPPC_H__ + +/* macros convertion little endian convertion to big endian convertion */ + + +#define SWAP_2(x) ( (((x) & 0xff) << 8) | ((unsigned short)(x) >> 8) ) +#define SWAP_4(x) ( ((x) << 24) | \ + (((x) << 8) & 0x00ff0000) | \ + (((x) >> 8) & 0x0000ff00) | \ + ((x) >> 24) ) +#define FIX_SHORT(x) (*(unsigned short *)&(x) = SWAP_2(*(unsigned short *)&(x))) +#define FIX_INT(x) (*(unsigned int *)&(x) = SWAP_4(*(unsigned int *)&(x))) +#define FIX_FLOAT(x) FIX_INT(x) + + + +/* endianness test function */ + +bool isBigEndian(void); + +#endif diff --git a/tools/iDSK/src/getopt_pp.cpp b/tools/iDSK/src/getopt_pp.cpp new file mode 100644 index 0000000..b22c81f --- /dev/null +++ b/tools/iDSK/src/getopt_pp.cpp @@ -0,0 +1,307 @@ +/* +GetOpt_pp: Yet another C++ version of getopt. + This file is part of GetOpt_pp. + + Copyright (C) Daniel Gutson, FuDePAN 2007-2010 + Distributed under the Boost Software License, Version 1.0. + (See accompanying file LICENSE_1_0.txt in the root directory or + copy at http://www.boost.org/LICENSE_1_0.txt) + + GetOpt_pp IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT + SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE + FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, + ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. +*/ + +#include + +#if __APPLE__ +#include +#define environ (*_NSGetEnviron()) +#elif _WIN32 +#include +#define environ _environ +#else +#include +#endif + +#include "getopt_pp.h" + +namespace GetOpt +{ + +GETOPT_INLINE Token* GetOpt_pp::_add_token(const std::string& value, Token::Type type) +{ + Token* const ret = new Token(value, type); + if (_first_token == NULL) + _first_token = ret; + else + _last_token->link_to(ret); + _last_token = ret; + return ret; +} + +GETOPT_INLINE void GetOpt_pp::_init_flags() +{ + std::stringstream ss; + _flags = ss.flags(); +} + +GETOPT_INLINE void GetOpt_pp::_parse_sub_file(const std::string& file) +{ + std::ifstream ifile(file.c_str()); + if (!ifile) + throw OptionsFileNotFoundEx(file); + + std::vector args; + std::string arg; + + while (ifile >> arg) + args.push_back(arg); + + _parse(args); +} + +GETOPT_INLINE void GetOpt_pp::_parse(const std::vector& args) +{ + bool any_option_processed = false; + const size_t argc = args.size(); + + size_t start = 0; + if ( _app_name.empty() ) + { + _app_name = args[0]; + start = 1; + } + + // parse arguments by their '-' or '--': + // (this will be a state machine soon) + for (size_t i = start; i < argc; i++) + { + const std::string& currentArg = args[i]; + + if (currentArg[0] == '-' && currentArg.size() > 1) + { + // see what's next, differentiate whether it's short or long: + if (currentArg[1] == '-') + { + if ( currentArg.size() > 2 ) + { + // long option + _longOps[currentArg.substr(2)].token = _add_token(currentArg.substr(2), Token::LongOption); + } + else + { + // it's the -- option alone + _longOps[currentArg].token = _add_token(currentArg, Token::GlobalArgument); + } + + any_option_processed = true; + } + else + { + // check if it is a negative number: rules + // * floating point negative numbers are straight classified as 'arguments' + // * integer negative numbers of more than 1 digit length are also 'arguments' + // * integer negatives of 1 digit length can be either arguments or short options. + // * anything else: short options. + int anInt; + float aFloat; + std::stringstream dummy; + if ( convert(currentArg, anInt, dummy.flags()) == _Option::OK ) + { + if ( currentArg.size() > 2 ) // if it's larger than -d (d=digit), then assume it's a negative number: + _add_token(currentArg, any_option_processed ? Token::UnknownYet : Token::GlobalArgument); + else // size == 2: it's a 1 digit negative number + _shortOps[currentArg[1]].token = _add_token(currentArg, Token::PossibleNegativeArgument); + } + else if ( convert(currentArg, aFloat, dummy.flags()) == _Option::OK ) + _add_token(currentArg, any_option_processed ? Token::UnknownYet : Token::GlobalArgument); + else + { + // short option + // iterate over all of them, keeping the last one in currentData + // (so the intermediates will generate 'existent' arguments, as of '-abc') + for( size_t j = 1; j < currentArg.size(); j++ ) + _shortOps[currentArg[j]].token = _add_token(std::string(currentArg, j, 1), Token::ShortOption); + } + + any_option_processed = true; + } + } + else if ( currentArg[0] == '@' && currentArg.size() > 1 ) + { + // suboptions file + _parse_sub_file(currentArg.substr(1)); + } + else + { + _add_token(currentArg, any_option_processed ? Token::UnknownYet : Token::GlobalArgument); + } + } + + _last = _Option::OK; // TODO: IMPROVE!! +} + +GETOPT_INLINE void GetOpt_pp::_parse_env() +{ + // this will be optimized in version 3 + std::string var_name; + std::string var_value; + size_t var = 0; + std::string::size_type pos; + OptionData* data; + + while (environ[var] != NULL) + { + var_name = environ[var]; + pos = var_name.find('='); + + if (pos != std::string::npos) + { + var_value = var_name.substr(pos + 1); + var_name = var_name.substr(0, pos); + + if (_longOps.find(var_name) == _longOps.end()) + { + data = &_longOps[var_name]; + data->token = _add_token(var_name, Token::LongOption); + data->flags = OptionData::Envir; + _add_token(var_value, Token::OptionArgument); + } + } + else + (data = &_longOps[var_name])->flags = OptionData::Envir; + + var++; + } +} + + +GETOPT_INLINE void GetOpt_pp::_argc_argv_to_vector(int argc, const char* const* const argv, std::vector& args) +{ + for (int i = 0; i < argc; i++) + args.push_back(argv[i]); +} + +GETOPT_INLINE GetOpt_pp::TokensDeleter::~TokensDeleter() +{ + Token* next; + Token* current(_first); + while (current != NULL) + { + next = current->next; + delete current; + current = next; + } +} + +GETOPT_INLINE GetOpt_pp::GetOpt_pp(int argc, const char* const* const argv) + : _exc(std::ios_base::goodbit), _first_token(NULL), _last_token(NULL), _tokens_deleter(_first_token) +{ + _init_flags(); + std::vector args; + _argc_argv_to_vector(argc, argv, args); + _parse(args); +} + +GETOPT_INLINE GetOpt_pp::GetOpt_pp(int argc, const char* const* const argv, _EnvTag) + : _first_token(NULL), _last_token(NULL), _tokens_deleter(_first_token) +{ + _init_flags(); + std::vector args; + _argc_argv_to_vector(argc, argv, args); + _parse(args); + _parse_env(); +} + +GETOPT_INLINE GetOpt_pp& GetOpt_pp::operator >> (const _Option& opt) throw(GetOptEx) +{ + if (_last != _Option::ParsingError) + { + _last = opt(_shortOps, _longOps, _first_token, _flags); + + switch (_last) + { + case _Option::OK: + break; + + case _Option::OptionNotFound: + if (_exc & std::ios_base::eofbit) + throw OptionNotFoundEx(); + break; + + case _Option::BadType: + if (_exc & std::ios_base::failbit) + throw InvalidFormatEx(); + break; + + case _Option::NoArgs: + if (_exc & std::ios_base::eofbit) + throw ArgumentNotFoundEx(); + break; + + case _Option::TooManyArgs: + if (_exc & std::ios_base::failbit) + throw TooManyArgumentsEx(); + break; + + case _Option::OptionNotFound_NoEx: + break; // Ok, it will be read by casting to bool + + case _Option::ParsingError: + break; // just to disable warning + } + } + else if (_exc & std::ios_base::failbit) + throw ParsingErrorEx(); + + return *this; +} + +GETOPT_INLINE GetOpt_pp& GetOpt_pp::operator >> (std::ios_base & (*iomanip)(std::ios_base&)) +{ + std::stringstream ss; + ss.flags(_flags); + _flags = (ss << iomanip).flags(); + return *this; +} + +GETOPT_INLINE bool GetOpt_pp::options_remain() const +{ + bool remain = false; + ShortOptions::const_iterator it = _shortOps.begin(); + while (it != _shortOps.end() && !remain) + { + remain = (it->second.flags == OptionData::CmdLine_NotExtracted); + ++it; + } + + if (!remain) + { + LongOptions::const_iterator it = _longOps.begin(); + while (it != _longOps.end() && !remain) + { + remain = (it->second.flags == OptionData::CmdLine_NotExtracted); + ++it; + } + } + + if (!remain) + { + // check for the global arguments: + Token* token = _first_token; + while (!remain && token != NULL) + { + remain = (token->type == Token::GlobalArgument || token->type == Token::UnknownYet); + token = token->next; + } + } + + return remain; +} + +} diff --git a/tools/iDSK/src/getopt_pp.h b/tools/iDSK/src/getopt_pp.h new file mode 100644 index 0000000..e0f991a --- /dev/null +++ b/tools/iDSK/src/getopt_pp.h @@ -0,0 +1,745 @@ +/* +GetOpt_pp: Yet another C++ version of getopt. + This file is part of GetOpt_pp. + + Copyright (C) Daniel Gutson, FuDePAN 2007-2010 + Distributed under the Boost Software License, Version 1.0. + (See accompanying file LICENSE_1_0.txt in the root directory or + copy at http://www.boost.org/LICENSE_1_0.txt) + + GetOpt_pp IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT + SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE + FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, + ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. +*/ + +#ifndef GETOPT_PP_H +#define GETOPT_PP_H + +#include +#include // candidate to be removed +#include +#include +#include + +/* + DESIGN GOALS: + - EASY to use + - EASY to learn + - mimc STL's streams + - EASY to extend +*/ + +#ifndef GETOPT_INLINE +# define GETOPT_INLINE +#endif + +namespace GetOpt +{ + +struct Token +{ + enum Type + { + ShortOption, + LongOption, + GlobalArgument, + GlobalArgumentUsed, // already read, skip in the next read + OptionArgument, + PossibleNegativeArgument, + UnknownYet // can be a global option, or an option of the previous one + }; + + Type type; + std::string value; + Token* next; + + Token(const std::string& value, Type type = UnknownYet) + : type(type), value(value), next(NULL) + {} + + bool is_last() const + { + return next == NULL; + } + + void link_to(Token* new_next) + { + next = new_next; + } + + Token* get_next_option_argument() const + { + if (is_last()) + return NULL; + else + { + if (next->type == UnknownYet || next->type == OptionArgument || next->type == PossibleNegativeArgument) + return next; + else + return NULL; + } + } +}; + +struct OptionData +{ + enum _Flags + { + CmdLine_NotExtracted, + CmdLine_Extracted, + Envir + }; + + _Flags flags; + Token* token; + OptionData() : flags(CmdLine_NotExtracted) {} +}; + +typedef std::map LongOptions; +typedef std::map ShortOptions; + + +struct _Option +{ + enum Result + { + OK, + ParsingError, + OptionNotFound, + BadType, + NoArgs, + TooManyArgs, + OptionNotFound_NoEx + }; + + virtual Result operator()(ShortOptions& short_ops, LongOptions& long_ops, Token* first, std::ios::fmtflags flags) const = 0; + virtual ~_Option() {} + + static const char NO_SHORT_OPT = 0; +protected: + static void setTokenAsUsed(Token* token, ShortOptions& short_ops, Token::Type usedAs) + { + if (token->type == Token::PossibleNegativeArgument) + short_ops.erase(token->value[1]); + + token->type = usedAs; + } +}; + +template inline _Option::Result convert(const std::string& s, T& result, std::ios::fmtflags flags) +{ + std::stringstream ss; + ss.clear(); + ss.flags(flags); + ss << s; + ss >> result; + if (ss.fail() || !ss.eof()) + return _Option::BadType; + else + return _Option::OK; +} + +template <> inline _Option::Result convert(const std::string& s, std::string& result, std::ios::fmtflags /*flags*/) +{ + result = s; + return _Option::OK; +} + + +template class _OptionTBase : public _Option +{ + const char short_opt; + const std::string long_opt; +protected: + T& target; + virtual Result _assign(Token* token, std::ios::fmtflags flags, ShortOptions& short_ops) const = 0; + +public: + _OptionTBase(const _OptionTBase& other) + : _Option(), short_opt(other.short_opt), long_opt(other.long_opt), target(other.target) + {} + + _OptionTBase(char short_opt, const std::string& long_opt, T& target) + : short_opt(short_opt), long_opt(long_opt), target(target) + {} + + virtual Result operator()(ShortOptions& short_ops, LongOptions& long_ops, Token* /*first*/, std::ios::fmtflags flags) const + { + Result ret = OptionNotFound; + ShortOptions::iterator it; + if (short_opt == _Option::NO_SHORT_OPT) + it = short_ops.end(); + else + it = short_ops.find(short_opt); + + if (it != short_ops.end()) + { + it->second.flags = OptionData::CmdLine_Extracted; + ret = _assign(it->second.token, flags, short_ops); + } + else if (!long_opt.empty()) + { + LongOptions::iterator it = long_ops.find(long_opt); + if (it != long_ops.end()) + { + it->second.flags = OptionData::CmdLine_Extracted; + ret = _assign(it->second.token, flags, short_ops); + } + } + + return ret; + } +}; + + +template class _OptionT : public _OptionTBase +{ +protected: + virtual _Option::Result _assign(Token* token, std::ios::fmtflags flags, ShortOptions& short_ops) const + { + Token* const option_token = token->get_next_option_argument(); + if (option_token == NULL) + return _Option::NoArgs; + else + { + this->setTokenAsUsed(option_token, short_ops, Token::OptionArgument); + return convert(option_token->value, this->target, flags); + } + } +public: + _OptionT(const _OptionT& other) + : _OptionTBase(other) + {} + + _OptionT(char short_opt, const std::string& long_opt, T& target) + : _OptionTBase(short_opt, long_opt, target) + {} + +}; + +template class _OptionT > : public _OptionTBase > +{ +protected: + virtual _Option::Result _assign(Token* token, std::ios::fmtflags flags, ShortOptions& short_ops) const + { + Token* option_token = token->get_next_option_argument(); + if (option_token != NULL) + { + _Option::Result result; + //OptionArgs::const_iterator it = args.begin(); + T temp; + + do + { + this->setTokenAsUsed(option_token, short_ops, Token::OptionArgument); + result = convert(option_token->value, temp, flags); + if (result == _Option::OK) + this->target.push_back(temp); + + option_token = option_token->get_next_option_argument(); + } + while (option_token != NULL && result == _Option::OK); + + return result; + } + else + return _Option::NoArgs; + } + +public: + _OptionT(const _OptionT >& other) + : _OptionTBase >(other) + {} + + _OptionT(char short_opt, const std::string& long_opt, std::vector& target) + : _OptionTBase >(short_opt, long_opt, target) + {} +}; + + +template +class _DefValOption : public BaseOption +{ + const T default_value; +public: + + _DefValOption(const _DefValOption& other) + : BaseOption(other), default_value(other.default_value) + {} + + _DefValOption(char short_opt, const std::string& long_opt, T& target, const T& default_value) + : BaseOption(short_opt, long_opt, target), default_value(default_value) + {} + + virtual _Option::Result operator()(ShortOptions& short_ops, LongOptions& long_ops, Token* first, std::ios::fmtflags flags) const + { + _Option::Result ret = BaseOption::operator()(short_ops, long_ops, first, flags); + + if (ret == _Option::OptionNotFound) + { + this->target = default_value; + ret = _Option::OK; + } + + return ret; + } +}; + +template +class _GlobalOption : public _Option +{ + T& target; + virtual Result operator()(ShortOptions& short_ops, LongOptions& long_ops, Token* first, std::ios::fmtflags flags) const + { + // find first token GlobalArgument or UnknownYet (candidate) or PossibleNegativeArgument (candidate too) + Token* token(first); + bool found(false); + while (token != NULL && !found) + { + found = (token->type == Token::GlobalArgument || token->type == Token::UnknownYet || token->type == Token::PossibleNegativeArgument); + if (!found) + token = token->next; + } + if (found) + { + this->setTokenAsUsed(token, short_ops, Token::GlobalArgumentUsed); + return convert(token->value, target, flags); + } + else + return OptionNotFound; + } +public: + _GlobalOption(const _GlobalOption& other) + : target(other.target) + {} + + _GlobalOption(T& target) + : target(target) + {} +}; + +template +class _GlobalOption > : public _Option +{ + std::vector& target; + virtual Result operator()(ShortOptions& short_ops, LongOptions& /*long_ops*/, Token* first, std::ios::fmtflags flags) const + { + // find first token GlobalArgument or UnknownYet (candidate) or PossibleNegativeArgument (candidate too) + Token* token(first); + bool found_any(false); + T tmp; + Result res(OK); + + while (token != NULL && res == OK) + { + if (token->type == Token::GlobalArgument || token->type == Token::UnknownYet || token->type == Token::PossibleNegativeArgument) + { + res = convert(token->value, tmp, flags); + if (res == OK) + { + this->setTokenAsUsed(token, short_ops, Token::GlobalArgumentUsed); + found_any = true; + target.push_back(tmp); + } + } + token = token->next; + } + if (res == OK) + { + if (found_any) + return res; + else + return OptionNotFound; + } + else + return res; + } +public: + _GlobalOption(const _GlobalOption >& other) + : target(other.target) + {} + + _GlobalOption(std::vector& target) + : target(target) + {} +}; + +template +inline _OptionT Option(char short_opt, const std::string& long_opt, T& target) +{ + return _OptionT(short_opt, long_opt, target); +} + +template +inline _OptionT Option(char short_opt, T& target) +{ + return _OptionT(short_opt, std::string(), target); +} + +// LongOpt only +template +inline _OptionT Option(const std::string& long_opt, T& target) +{ + return _OptionT(_Option::NO_SHORT_OPT, long_opt, target); +} + +// Defaulted version +template +inline _DefValOption > +Option(char short_opt, const std::string& long_opt, T& target, const T& def) +{ + return _DefValOption >(short_opt, long_opt, target, def); +} + +template +inline _DefValOption > Option(char short_opt, T& target, const T& def) +{ + return _DefValOption >(short_opt, std::string(), target, def); +} + +// no short opt. +template +inline _DefValOption > +Option(const std::string& long_opt, T& target, const T& def) +{ + return _DefValOption >(_Option::NO_SHORT_OPT, long_opt, target, def); +} + +// Defaults for strings: +inline _DefValOption > +Option(char short_opt, const std::string& long_opt, std::string& target, const char* def) +{ + return _DefValOption >(short_opt, long_opt, target, def); +} + +inline _OptionT Option(char short_opt, std::string& target, const char* def) +{ + return _DefValOption >(short_opt, std::string(), target, def); +} + +// no short opt. +inline _DefValOption > +Option(const std::string& long_opt, std::string& target, const char* def) +{ + return _DefValOption >(_Option::NO_SHORT_OPT, long_opt, target, def); +} + +// Global Option: +template +inline _GlobalOption GlobalOption(T& target) +{ + return _GlobalOption(target); +} + +class OptionPresent : public _Option +{ + const char short_opt; + const std::string long_opt; + bool* const present; +public: + // two combinations: with/without target, and with/without long opt. + + // WITH long_opt: + OptionPresent(char short_opt, const std::string& long_opt, bool& present) + : short_opt(short_opt), long_opt(long_opt), present(&present) + {} + + OptionPresent(char short_opt, const std::string& long_opt) + : short_opt(short_opt), long_opt(long_opt), present(NULL) + {} + + // WITHOUT long_opt: + OptionPresent(char short_opt, bool& present) + : short_opt(short_opt), present(&present) + {} + + OptionPresent(char short_opt) + : short_opt(short_opt), present(NULL) + {} + + // WITHOUT short_opt + OptionPresent(const std::string& long_opt, bool& present) + : short_opt(_Option::NO_SHORT_OPT), long_opt(long_opt), present(&present) + {} + + OptionPresent(const std::string& long_opt) + : short_opt(_Option::NO_SHORT_OPT), long_opt(long_opt), present(NULL) + {} +protected: + virtual Result operator()(ShortOptions& short_ops, LongOptions& long_ops, Token* /*first*/, std::ios::fmtflags /*flags*/) const + { + bool found; + ShortOptions::iterator it = short_ops.find(short_opt); + + found = (it != short_ops.end()); + if (found) + { + it->second.flags = OptionData::CmdLine_Extracted; + } + else if (!long_opt.empty()) + { + LongOptions::iterator it = long_ops.find(long_opt); + found = (it != long_ops.end()); + if (found) + { + it->second.flags = OptionData::CmdLine_Extracted; + } + } + + if (present != NULL) + { + *present = found; + return OK; + } + else + { + return found ? OK : OptionNotFound_NoEx; + } + } +}; + +class GetOptEx : public std::exception {}; +struct ParsingErrorEx : GetOptEx {}; +struct InvalidFormatEx : GetOptEx {}; +struct ArgumentNotFoundEx : GetOptEx {}; +struct TooManyArgumentsEx : GetOptEx {}; +struct OptionNotFoundEx : GetOptEx {}; +struct TooManyOptionsEx : GetOptEx {}; +struct OptionsFileNotFoundEx : GetOptEx +{ + const std::string targetFile; + OptionsFileNotFoundEx(const std::string& file) : targetFile(file) {} + ~OptionsFileNotFoundEx() throw() {} +}; + +enum _EnvTag +{ + Include_Environment +}; + +class GetOpt_pp +{ + ShortOptions _shortOps; + LongOptions _longOps; + std::ios_base::iostate _exc; + _Option::Result _last; + std::ios::fmtflags _flags; + std::string _app_name; + Token* _first_token; + Token* _last_token; + + class TokensDeleter + { + Token*& _first; + public: + TokensDeleter(Token*& first) : _first(first) {} + + GETOPT_INLINE ~TokensDeleter(); + }; + + TokensDeleter _tokens_deleter; + + GETOPT_INLINE Token* _add_token(const std::string& value, Token::Type type); + GETOPT_INLINE void _init_flags(); + GETOPT_INLINE void _parse(const std::vector& args); + GETOPT_INLINE void _parse_env(); + static GETOPT_INLINE void _argc_argv_to_vector(int argc, const char* const* const argv, std::vector& args); + GETOPT_INLINE void _parse_sub_file(const std::string& file); +public: + GETOPT_INLINE GetOpt_pp(int argc, const char* const* const argv); + GETOPT_INLINE GetOpt_pp(int argc, const char* const* const argv, _EnvTag); + + std::ios_base::iostate exceptions() const + { + return _exc; + } + void exceptions(std::ios_base::iostate except) + { + _exc = except; + } + void exceptions_all() + { + _exc = std::ios_base::failbit | std::ios_base::eofbit; + } + + operator bool() const + { + return _last == _Option::OK; + } + + GETOPT_INLINE bool options_remain() const; + + void end_of_options() const throw(GetOptEx) + { + if (options_remain() && (_exc & std::ios_base::eofbit)) + throw TooManyOptionsEx(); + } + + std::ios::fmtflags flags() const + { + return _flags; + } + void flags(std::ios::fmtflags flags) + { + _flags = flags; + } + + const std::string& app_name() const + { + return _app_name; + } + + GETOPT_INLINE GetOpt_pp& operator >> (const _Option& opt) throw(GetOptEx); + + GETOPT_INLINE GetOpt_pp& operator >> (std::ios_base& (*iomanip)(std::ios_base&)); + + // Alternative to manipulators, for those who don't like them: the 'getopt' method :) + // Combination 1: with long option: + template inline T getopt(char short_opt, const std::string& long_opt) throw(GetOptEx) + { + T result; + operator >> (Option(short_opt, long_opt, result)); + return result; + } + + template inline T getopt(char short_opt, const std::string& long_opt, const T& def_value) + { + T result; + operator >> (Option(short_opt, long_opt, result, def_value)); + return result; + } + + // Combination 2: without long option: + template inline T getopt(char short_opt) throw(GetOptEx) + { + T result; + operator >> (Option(short_opt, result)); + return result; + } + + template inline T getopt(char short_opt, const T& def_value) + { + T result; + operator >> (Option(short_opt, result, def_value)); + return result; + } + + struct ItCtorData + { + ShortOptions::const_iterator short_iter; + LongOptions::const_iterator long_iter; + GetOpt_pp* getopt_pp; + }; + + template + class _iterator + { + typename Container::const_iterator _it; + GetOpt_pp* _getopt_pp; + public: + _iterator(const ItCtorData& ctor_data) + { + _it = Adapter::adapt(ctor_data); + _getopt_pp = ctor_data.getopt_pp; + } + + _iterator() : _getopt_pp(NULL) + {} + + _iterator& operator = (const _iterator& other) + { + _it = other._it; + _getopt_pp = other._getopt_pp; + return *this; + } + + bool operator != (const _iterator& other) const + { + return _it != other._it; + } + + OptionType option() const + { + return _it->first; + } + OptionType operator*() const + { + return option(); + } + + _iterator& operator ++() + { + ++_it; + return *this; + } + + template + GetOpt_pp& operator >> (T& t) + { + Adapter::extract(t, *_getopt_pp, option()); + return *_getopt_pp; + } + }; + + ItCtorData begin() + { + ItCtorData ret; + ret.short_iter = _shortOps.begin(); + ret.long_iter = _longOps.begin(); + ret.getopt_pp = this; + return ret; + } + + ItCtorData end() + { + ItCtorData ret; + ret.short_iter = _shortOps.end(); + ret.long_iter = _longOps.end(); + ret.getopt_pp = this; + return ret; + } + + struct ShortAdapter + { + static ShortOptions::const_iterator adapt(const ItCtorData& data) + { + return data.short_iter; + } + + template + static void extract(T& t, GetOpt_pp& getopt_pp, char option) + { + getopt_pp >> Option(option, t); + } + }; + + struct LongAdapter + { + static LongOptions::const_iterator adapt(const ItCtorData& data) + { + return data.long_iter; + } + + template + static void extract(T& t, GetOpt_pp& getopt_pp, const std::string& option) + { + getopt_pp >> Option('\0', option, t); + } + }; + + typedef _iterator short_iterator; + typedef _iterator long_iterator; +}; + +class Environment +{ + // Coming soon! +}; + +} + +#endif -- cgit v1.2.3