aboutsummaryrefslogtreecommitdiff
path: root/jindroush/lib
diff options
context:
space:
mode:
authorB. Watson <urchlay@slackware.uk>2024-05-16 01:43:09 -0400
committerB. Watson <urchlay@slackware.uk>2024-05-16 01:43:09 -0400
commita4cc3ad3504d634e379369862c9f9fd8eed379f3 (patch)
tree7b6f55c352a4ca62dddaa1b4a6854799111d2d2f /jindroush/lib
parentb33c25d1363110e6e4a714530f460b0ff951f56b (diff)
downloadbw-atari8-tools-a4cc3ad3504d634e379369862c9f9fd8eed379f3.tar.gz
Add Jindrich Kubec's tools.
Diffstat (limited to 'jindroush/lib')
-rw-r--r--jindroush/lib/Makefile23
-rw-r--r--jindroush/lib/adsk.cpp319
-rw-r--r--jindroush/lib/adsk_atr.cpp483
-rw-r--r--jindroush/lib/adsk_dcm.cpp764
-rw-r--r--jindroush/lib/adsk_di.cpp271
-rw-r--r--jindroush/lib/adsk_scp.cpp281
-rw-r--r--jindroush/lib/adsk_xfd.cpp327
-rw-r--r--jindroush/lib/at_dis.cpp1201
-rw-r--r--jindroush/lib/autil.cpp139
-rw-r--r--jindroush/lib/cdisk.cpp276
-rw-r--r--jindroush/lib/cdsk.cpp115
-rw-r--r--jindroush/lib/cdsk_atr.cpp439
-rw-r--r--jindroush/lib/cdsk_dcm.cpp762
-rw-r--r--jindroush/lib/cdsk_scp.cpp279
-rw-r--r--jindroush/lib/cdsk_xfd.cpp334
-rw-r--r--jindroush/lib/cfile.cpp139
-rw-r--r--jindroush/lib/cfs.cpp69
-rw-r--r--jindroush/lib/cfs_b2b.cpp156
-rw-r--r--jindroush/lib/cfs_boot.cpp128
-rw-r--r--jindroush/lib/cfs_dos2.cpp224
-rw-r--r--jindroush/lib/cfs_dos3.cpp209
-rw-r--r--jindroush/lib/cfs_dosm.cpp240
-rw-r--r--jindroush/lib/cfs_doss.cpp383
-rw-r--r--jindroush/lib/cfs_howf.cpp209
-rw-r--r--jindroush/lib/cfs_jonw.cpp204
-rw-r--r--jindroush/lib/cfs_kboo.cpp148
-rw-r--r--jindroush/lib/cfs_robc.cpp231
-rw-r--r--jindroush/lib/cgenfile.cpp95
-rw-r--r--jindroush/lib/cobj.cpp23
-rw-r--r--jindroush/lib/cprefile.cpp153
30 files changed, 8624 insertions, 0 deletions
diff --git a/jindroush/lib/Makefile b/jindroush/lib/Makefile
new file mode 100644
index 0000000..bafe06c
--- /dev/null
+++ b/jindroush/lib/Makefile
@@ -0,0 +1,23 @@
+OBJS=adsk.o adsk_atr.o adsk_dcm.o adsk_di.o \
+ adsk_scp.o adsk_xfd.o at_dis.o autil.o \
+ cdsk.o cdsk_atr.o cdsk_dcm.o cdsk_scp.o \
+ cdsk_xfd.o cfile.o cgenfile.o cobj.o cprefile.o \
+ cdisk.o cfs.o cfs_b2b.o cfs_boot.o cfs_dos2.o \
+ cfs_dos3.o cfs_dosm.o cfs_doss.o cfs_howf.o \
+ cfs_jonw.o cfs_kboo.o cfs_robc.o
+
+COPT=-O2
+CXX=g++
+CXXFLAGS=$(COPT) -D__CDISK_SAVE__ -D__CDISK_WRITE__
+
+all: libjindroush.a
+
+libjindroush.a: $(OBJS)
+ ar r libjindroush.a $(OBJS)
+ ranlib libjindroush.a
+
+clean:
+ rm -f *.o *.a
+
+%.o : %.cpp
+ $(CXX) -I../include $(CXXFLAGS) -c $<
diff --git a/jindroush/lib/adsk.cpp b/jindroush/lib/adsk.cpp
new file mode 100644
index 0000000..e5d0b5a
--- /dev/null
+++ b/jindroush/lib/adsk.cpp
@@ -0,0 +1,319 @@
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+//
+
+#include "adsk.h"
+
+ADisk::ADisk() : CDisk()
+{
+ #ifdef _MEMORY_DUMP_
+ printf( "ADisk constructed: %p\n", this );
+ #endif
+}
+
+ADisk::~ADisk()
+{
+ #ifdef _MEMORY_DUMP_
+ printf( "ADisk destructed: %p\n", this );
+ #endif
+}
+
+void GuessClassicSizes( int iSectors, int iSectorSize, DISK_GEOMETRY* pGeometry )
+{
+ pGeometry->iSides = 1;
+ pGeometry->iBytesPerSector = iSectorSize;
+
+ pGeometry->iTracks = 1;
+ pGeometry->iSectorsPerTrack = iSectors;
+
+ switch( iSectors )
+ {
+ case 720:
+ switch( iSectorSize )
+ {
+ case 0x80:
+ pGeometry->iTracks = 40;
+ pGeometry->iSectorsPerTrack = 18;
+ break;
+
+ case 0x100:
+ pGeometry->iTracks = 40;
+ pGeometry->iSectorsPerTrack = 18;
+ break;
+ }
+ break;
+
+ case 1040:
+ pGeometry->iTracks = 40;
+ pGeometry->iSectorsPerTrack = 26;
+ break;
+
+ }
+
+}
+
+void ForceClassicSize( DISK_GEOMETRY* pGeometry )
+{
+ ForceClassicSize( pGeometry->iSectors, pGeometry->iBytesPerSector, pGeometry );
+}
+
+void ForceClassicSize( int iSectors, int iSectorSize, DISK_GEOMETRY* pGeometry )
+{
+ pGeometry->iSides = 1;
+ pGeometry->iBytesPerSector = iSectorSize;
+
+ pGeometry->iTracks = 1;
+ pGeometry->iSectorsPerTrack = iSectors;
+
+ switch( iSectorSize )
+ {
+ case 0x80:
+ if ( iSectors <= 720 )
+ {
+ pGeometry->iTracks = 40;
+ pGeometry->iSectorsPerTrack = 18;
+ }
+ else if ( ( iSectors > 720 ) && ( iSectors <= 1040 ) )
+ {
+ pGeometry->iTracks = 40;
+ pGeometry->iSectorsPerTrack = 26;
+ }
+ else
+ {
+ GuessClassicSizes( iSectors, iSectorSize, pGeometry );
+ }
+ break;
+
+ case 0x100:
+ default:
+ if ( iSectors <= 720 )
+ {
+ pGeometry->iTracks = 40;
+ pGeometry->iSectorsPerTrack = 18;
+ }
+ else
+ {
+ GuessClassicSizes( iSectors, iSectorSize, pGeometry );
+ }
+ break;
+ }
+
+ switch( iSectors )
+ {
+ case 720:
+ switch( iSectorSize )
+ {
+ case 0x80:
+ pGeometry->iTracks = 40;
+ pGeometry->iSectorsPerTrack = 18;
+ break;
+
+ case 0x100:
+ pGeometry->iTracks = 40;
+ pGeometry->iSectorsPerTrack = 18;
+ break;
+ }
+ break;
+
+ case 1040:
+ pGeometry->iTracks = 40;
+ pGeometry->iSectorsPerTrack = 26;
+ break;
+
+ }
+
+}
+
+
+//returns ptr to disk type name
+char* GetDiskTypeName( DISK_TYPE disktype )
+{
+ switch( disktype )
+ {
+ case DISK_XFD:
+ return "XFD";
+
+ case DISK_ATR:
+ return "ATR";
+
+ case DISK_XFDb:
+ return "XFDb";
+
+ case DISK_ATRb:
+ return "ATRb";
+
+ case DISK_DCM:
+ return "DCM";
+
+ case DISK_SCP:
+ return "SCP";
+
+ case DISK_DI:
+ return "DI";
+
+ default:
+ return "None";
+ }
+}
+
+//returns ptr to disk type extension
+char* GetDiskTypeExt( DISK_TYPE disktype )
+{
+ switch( disktype )
+ {
+ case DISK_XFD:
+ case DISK_XFDb:
+ return "xfd";
+
+ case DISK_ATR:
+ case DISK_ATRb:
+ return "atr";
+
+ case DISK_DCM:
+ return "dcm";
+
+ case DISK_SCP:
+ return "scp";
+
+ case DISK_DI:
+ return "di";
+
+ default:
+ return "xxx";
+ }
+}
+
+#ifndef __CDISK_NOLOAD__
+DISKINIT_RETCODE InitializeDisk( ADisk** ppDisk, DISK_TYPE disktype, char* szFname, BOOL bVerbose, BOOL bRepair, BOOL bRepairAuto )
+{
+ switch( disktype )
+ {
+ case DISK_ATR:
+ *ppDisk = new CAtr();
+ break;
+
+ case DISK_SCP:
+ *ppDisk = new CScp();
+ break;
+
+ case DISK_DCM:
+ *ppDisk = new CDcm();
+ break;
+
+ case DISK_XFD:
+ *ppDisk = new CXfd();
+ break;
+
+ case DISK_DI:
+ *ppDisk = new CDi();
+ break;
+
+ default:
+ if ( bVerbose )
+ fprintf( stderr, "Invalid disk type specified!\n" );
+ return DI_RET_CANT_CONTINUE;
+ }
+
+ if ( !*ppDisk )
+ {
+ if ( bVerbose )
+ fprintf( stderr, "Can't initialize disk driver!\n" );
+ return DI_RET_CONTINUE;
+ }
+
+ if ( !(*ppDisk)->Load( szFname, bRepair, bRepairAuto ) )
+ {
+ int iError = (*ppDisk)->GetErrorCode();
+
+ DISKINIT_RETCODE ret = DI_RET_CONTINUE;
+
+ switch( iError )
+ {
+ case CATR_FORMAT_VIOLATED:
+ case CXFD_FORMAT_VIOLATED:
+ case CDISK_ERROR_CANT_OPEN:
+ case CDCM_FORMAT_VIOLATED:
+ case CSCP_FORMAT_VIOLATED:
+ case CDI_FORMAT_VIOLATED:
+ ret = DI_RET_CANT_CONTINUE;
+ break;
+ }
+
+ if ( bVerbose || ( ret == DI_RET_CANT_CONTINUE ) )
+ {
+ printf( "Input file '%s' ", szFname );
+ printf( "(%s)\n", GetDiskTypeName( disktype ) );
+ printf( "Load failed because:\n%s\n", (*ppDisk)->GetLastError() );
+ }
+ if ( ret != DI_RET_OK )
+ {
+ delete *ppDisk;
+ return ret;
+ }
+ }
+
+ return DI_RET_OK;
+}
+#endif
+
+BOOL ADisk::ReadSectors( void* pBuf, int iStartSec, int iSecs )
+{
+ while( iSecs )
+ {
+ if ( !ReadSector( pBuf, iStartSec ) )
+ return FALSE;
+
+ pBuf = (BYTE*)pBuf + ( ( iStartSec <= 3 ) ? 0x80 :m_geometry.iBytesPerSector );
+ iStartSec++;
+ iSecs--;
+ }
+
+ return TRUE;
+}
+
+BOOL ADisk::WriteSectors( int iStartSec, void* pBuf, int iSecs )
+{
+ while( iSecs )
+ {
+ if ( !WriteSector( iStartSec, pBuf ) )
+ return FALSE;
+
+ pBuf = (BYTE*)pBuf + ( ( iStartSec <= 3 ) ? 0x80 :m_geometry.iBytesPerSector );
+ iStartSec++;
+ iSecs--;
+ }
+
+ return TRUE;
+}
+
+int ADisk::GetBootSectorCount()
+{
+ return m_pbtMemory[ 1 ];
+}
+
+int ADisk::GetBootSectorSize()
+{
+ int iSecCount = GetBootSectorCount();
+
+ if ( iSecCount > 3 )
+ return ( ( iSecCount - 3 ) * GetSectorSize() + 0x180 );
+ else
+ return iSecCount * 0x80;
+}
+
+BOOL ADisk::GetBootSector( BYTE* pbtData )
+{
+ return ReadSectors( pbtData, 1, GetBootSectorCount() );
+}
+
diff --git a/jindroush/lib/adsk_atr.cpp b/jindroush/lib/adsk_atr.cpp
new file mode 100644
index 0000000..ad7dce6
--- /dev/null
+++ b/jindroush/lib/adsk_atr.cpp
@@ -0,0 +1,483 @@
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+//
+
+#include "adsk_atr.h"
+#include "autil.h"
+#include "cfile.h"
+
+#define ATR_MAGIC 0x0296
+
+typedef struct
+{
+ WORD wMagic;
+ WORD wPars;
+ WORD wSecSize;
+ BYTE btParHigh;
+ DWORD dwCRC;
+ DWORD dwUnused;
+ BYTE btFlags;
+
+} ATRhead;
+
+#define ATR_HEAD_LEN 0x10
+
+CAtr::CAtr() : ADisk()
+{
+ #ifdef _MEMORY_DUMP_
+ printf( "CAtr constructed: %p\n", this );
+ #endif
+}
+
+CAtr::~CAtr()
+{
+ #ifdef _MEMORY_DUMP_
+ printf( "CAtr destructed: %p\n", this );
+ #endif
+}
+
+typedef enum
+{
+ LOAD_OK,
+ LOAD_BAD_DD_1,
+ LOAD_BAD_DD_2,
+ LOAD_BAD_DD_3,
+ LOAD_PAD
+} LOAD_VARIANT;
+
+#ifndef __CDISK_NOLOAD__
+BOOL CAtr::Load( char* szFname, BOOL bRepair, BOOL bRepairAuto )
+{
+ LOAD_VARIANT load_method = LOAD_OK;
+
+ m_iErrorCode = 0;
+
+ int iFirstSectorsSize = 0x80;
+
+ CFile cf;
+
+ if ( !cf.Open( szFname ) )
+ {
+ sprintf( m_szLastError, "ATR: Can't open '%s'", szFname );
+ m_iErrorCode = CDISK_ERROR_CANT_OPEN;
+ return FALSE;
+ }
+
+ strcpy( m_szFname, szFname );
+
+ ATRhead head;
+
+ head.wMagic = cf.readLEw();
+ head.wPars = cf.readLEw();
+ head.wSecSize = cf.readLEw();
+ head.btParHigh = cf.readb();
+ head.dwCRC = cf.readLEdw();
+ head.dwUnused = cf.readLEdw();
+ head.btFlags = cf.readb();
+
+ if ( head.wMagic != ATR_MAGIC )
+ {
+ sprintf( m_szLastError, "ATR: File '%s' is not an ATR file!", szFname );
+ return FALSE;
+ }
+
+ LONG lFileLen = cf.GetLength();
+ cf.Seek( ATR_HEAD_LEN, SEEK_SET );
+
+ switch( head.wSecSize )
+ {
+ case 0x80:
+ case 0x100:
+ break;
+
+ default:
+ {
+ sprintf( m_szLastError, "ATR: Invalid sector size: %04X", head.wSecSize );
+ return FALSE;
+ }
+ }
+
+ DWORD dwPars = head.wPars | ( head.btParHigh << 16 );
+
+ int iSectors = ( dwPars * 0x10 ) / head.wSecSize;
+
+ //BOOL bReadOnly = (head.btFlags & 1) ? TRUE : FALSE;
+
+ if ( head.wSecSize == 0x100 )
+ {
+ //if ( dwPars % head.wSecSize )
+ if ( ( dwPars * 0x10 ) % head.wSecSize )
+ {
+ iSectors = ( ( dwPars * 0x10 - 0x180 ) / head.wSecSize ) + 3;
+ }
+ else
+ {
+ sprintf( m_szLastError, "ATR: Format violated. First three sectors are not $80 long!" );
+ m_iErrorCode = CATR_FORMAT_VIOLATED;
+
+ #ifdef __CDISK_NOREPAIR__
+ return FALSE;
+ #else
+ if ( !bRepair )
+ {
+ return FALSE;
+ }
+ else
+ {
+ BYTE abtBuff[ 0x100 ];
+
+ memset( abtBuff, 0, 0x100 );
+
+ int iM1zeroes = 3;
+ int iM2zeroes = 3;
+ int iM3zeroes = 3;
+
+ cf.Seek( ATR_HEAD_LEN + ( 0x02 - 1 ) * 0x80, SEEK_SET );
+ cf.Read( abtBuff, 0x80 );
+
+ if ( IsBlockEmpty( abtBuff, 0x80 ) )
+ iM1zeroes--;
+
+ cf.Seek( ATR_HEAD_LEN + ( 0x04 - 1 ) * 0x80, SEEK_SET );
+ cf.Read( abtBuff, 0x80 );
+
+ if ( IsBlockEmpty( abtBuff, 0x80 ) )
+ {
+ iM1zeroes--;
+ iM2zeroes--;
+ }
+
+ cf.Seek( ATR_HEAD_LEN + ( 0x05 - 1 ) * 0x80, SEEK_SET );
+ cf.Read( abtBuff, 0x80 );
+
+ if ( IsBlockEmpty( abtBuff, 0x80 ) )
+ iM2zeroes--;
+
+ cf.Seek( ATR_HEAD_LEN + ( 0x06 - 1 ) * 0x80, SEEK_SET );
+ cf.Read( abtBuff, 0x80 );
+
+ if ( IsBlockEmpty( abtBuff, 0x80 ) )
+ {
+ iM1zeroes--;
+ iM2zeroes--;
+ }
+
+ cf.Seek( -0x180, SEEK_END );
+ cf.Read( abtBuff, 0x80 );
+ if ( IsBlockEmpty( abtBuff, 0x80 ) )
+ iM3zeroes--;
+
+ cf.Read( abtBuff, 0x80 );
+ if ( IsBlockEmpty( abtBuff, 0x80 ) )
+ iM3zeroes--;
+
+ cf.Read( abtBuff, 0x80 );
+ if ( IsBlockEmpty( abtBuff, 0x80 ) )
+ iM3zeroes--;
+
+ if ( !iM1zeroes )
+ {
+ load_method = LOAD_BAD_DD_1;
+ }
+ else if ( !iM2zeroes )
+ {
+ load_method = LOAD_BAD_DD_2;
+ }
+ else if ( !iM3zeroes )
+ {
+ load_method = LOAD_BAD_DD_3;
+ }
+
+ if ( !bRepairAuto )
+ {
+ printf( "Invalid DD ATR file encountered.\n" );
+ printf( "Choose repair method:\n" );
+ printf( "1) Sector, gap, sector, gap, sector, gap, data\n" );
+ printf( "2) Three sectors, three empty sectors, data\n" );
+ printf( "3) Data, three empty sectors\n" );
+ printf( "4) Don't repair\n" );
+
+ switch( load_method )
+ {
+ case LOAD_BAD_DD_1:
+ printf( "(Method 1 looks best)\n" );
+ break;
+
+ case LOAD_BAD_DD_2:
+ printf( "(Method 2 looks best)\n" );
+ break;
+
+ case LOAD_BAD_DD_3:
+ printf( "(Method 3 looks best)\n" );
+ break;
+
+ default:
+ break;
+ }
+
+ int iMethod;
+
+ printf( "\n" );
+ do
+ {
+ iMethod = getch() - '0';
+ } while( ( iMethod < 1 ) || ( iMethod > 4 ) );
+
+ switch( iMethod )
+ {
+ case 1:
+ load_method = LOAD_BAD_DD_1;
+ break;
+ case 2:
+ load_method = LOAD_BAD_DD_2;
+ break;
+ case 3:
+ load_method = LOAD_BAD_DD_3;
+ break;
+ default:
+ case 4:
+ return FALSE;
+ break;
+ }
+ }
+ else
+ {
+ if ( load_method == LOAD_OK )
+ load_method = LOAD_BAD_DD_1;
+ }
+
+
+ cf.Seek( ATR_HEAD_LEN, SEEK_SET );
+
+ switch( load_method )
+ {
+ case LOAD_BAD_DD_1:
+ case LOAD_BAD_DD_2:
+ case LOAD_BAD_DD_3:
+ iFirstSectorsSize = 0x100;
+ break;
+
+ default:
+ break;
+
+ }
+
+ } //end of repair
+
+ #endif
+ }
+ }
+
+ LONG lTotalComputedLen = (LONG) ( ( iSectors - 3 ) * head.wSecSize + ATR_HEAD_LEN + 3 * iFirstSectorsSize );
+
+ if ( lTotalComputedLen != lFileLen )
+ {
+ sprintf( m_szLastError, "ATR: Invalid length! %08lX <> %08lX (%08X)", lTotalComputedLen, lFileLen, iSectors );
+ m_iErrorCode = CATR_FORMAT_VIOLATED;
+
+ #ifdef __CDISK_NOREPAIR__
+ return FALSE;
+ #else
+ if ( !bRepair || ( load_method != LOAD_OK ) )
+ return FALSE;
+ else
+ {
+ if ( !bRepairAuto )
+ {
+ printf( "ATR with invalid length encountered.\n" );
+ printf( "Should be: $%08lX. Is: $%08lX.\n", lTotalComputedLen, lFileLen );
+ printf( "Choose:\n" );
+ printf( "1) Change file length (shorten/pad)\n" );
+ printf( "2) Change header info\n" );
+ printf( "3) Don't repair\n" );
+
+ int iMethod;
+
+ do
+ {
+ iMethod = getch() - '0';
+ } while( ( iMethod < 1 ) || ( iMethod > 3 ) );
+
+ switch( iMethod )
+ {
+ case 1:
+ load_method = LOAD_PAD;
+ break;
+
+ case 2:
+ load_method = LOAD_OK;
+ if ( lFileLen > 0x180 )
+ {
+ iSectors = ( ( lFileLen - 0x180 ) / head.wSecSize ) + 3;
+ }
+ else
+ {
+ iSectors = lFileLen / 0x80;
+ }
+
+ break;
+
+ default:
+ case 3:
+ return FALSE;
+ break;
+ }
+ }
+ else
+ {
+ if ( load_method == LOAD_OK )
+ load_method = LOAD_PAD;
+ }
+
+ }
+ #endif
+
+ }
+
+ DISK_GEOMETRY dg;
+
+ GuessClassicSizes( iSectors, head.wSecSize, &dg );
+
+ if ( !Format( &dg ) )
+ return FALSE;
+
+ BYTE abtBuff[ 0x100 ];
+ memset( abtBuff, 0, 0x100 );
+
+ for( int i = 0; i < iSectors; i++ )
+ {
+ switch( load_method )
+ {
+ default:
+ case LOAD_OK:
+ cf.Read( abtBuff, ( i < 3 ) ? 0x80 : head.wSecSize );
+ break;
+
+ case LOAD_PAD:
+ memset( abtBuff, 0, 0x100 );
+ cf.Read( abtBuff, ( i < 3 ) ? 0x80 : head.wSecSize );
+ break;
+
+ case LOAD_BAD_DD_1:
+ if ( i < 3 )
+ {
+ cf.Read( abtBuff, 0x80 );
+ cf.Seek( 0x80, SEEK_CUR );
+ }
+ else
+ cf.Read( abtBuff, 0x100 );
+ break;
+
+ case LOAD_BAD_DD_2:
+ if ( i < 3 )
+ {
+ cf.Read( abtBuff, 0x80 );
+
+ if ( i == 2 )
+ cf.Seek( 0x180, SEEK_CUR );
+ }
+ else
+ cf.Read( abtBuff, 0x100 );
+
+ break;
+
+ case LOAD_BAD_DD_3:
+ if ( i < 3 )
+ cf.Read( abtBuff, 0x80 );
+ else
+ cf.Read( abtBuff, 0x100 );
+
+ break;
+ }
+
+ WriteSector( i + 1, abtBuff );
+ }
+
+ cf.Close();
+ return TRUE;
+
+}
+
+#endif
+
+#ifdef __CDISK_SAVE__
+
+BOOL CAtr::Save( char* szOutFile, BOOL bOverWrite )
+{
+ CFile cf;
+
+ if ( !bOverWrite && !access( szOutFile, F_OK ) )
+ {
+ sprintf( m_szLastError, "ATR: File already exists! '%s'", szOutFile );
+ return FALSE;
+ }
+
+ if ( !cf.Create( szOutFile ) )
+ {
+ sprintf( m_szLastError, "ATR: Can't create '%s'", szOutFile );
+ return FALSE;
+ }
+
+ ATRhead head;
+ memset( &head, 0, sizeof( ATRhead ) );
+
+ head.wMagic = ATR_MAGIC;
+ head.wSecSize = m_geometry.iBytesPerSector;
+
+ BOOL bReadOnly = TRUE;
+ head.btFlags |= ( bReadOnly ) ? 0x01 : 0x00;
+
+ DWORD dwLength = 0;
+
+ dwLength = 0x180 + ( m_geometry.iSectors - 3 ) * m_geometry.iBytesPerSector;
+
+ dwLength >>= 4;
+
+ head.wPars = dwLength & 0xFFFF;
+ head.btParHigh = dwLength >> 0x10;
+
+ cf.writeLEw( head.wMagic );
+ cf.writeLEw( head.wPars );
+ cf.writeLEw( head.wSecSize );
+ cf.writeb( head.btParHigh );
+ cf.writeLEdw( head.dwCRC );
+ cf.writeLEdw( head.dwUnused );
+ cf.writeb( head.btFlags );
+
+ BYTE abtBuff[ 0x100 ];
+
+ for( WORD i = 1; i <= m_geometry.iSectors; i++ )
+ {
+ ReadSector( abtBuff, i );
+
+ int iToWrite = ( i <= 3 ) ? 0x80: m_geometry.iBytesPerSector;
+
+ int iWritten;
+
+ if ( !cf.Write( abtBuff, iToWrite, &iWritten ) || ( iToWrite != iWritten ) )
+ {
+ sprintf( m_szLastError, "ATR: Can't write!" );
+ cf.Close();
+ unlink( szOutFile );
+ return FALSE;
+
+ }
+ }
+
+ cf.Close();
+
+ return TRUE;
+}
+
+#endif //__CDISK_WRITE__
diff --git a/jindroush/lib/adsk_dcm.cpp b/jindroush/lib/adsk_dcm.cpp
new file mode 100644
index 0000000..d664761
--- /dev/null
+++ b/jindroush/lib/adsk_dcm.cpp
@@ -0,0 +1,764 @@
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+//
+
+#include "adsk_dcm.h"
+#include "cfile.h"
+#include "cprefile.h"
+#include "autil.h"
+
+//#define _DCM_DUMP_
+
+#define DCM_CHANGE_BEGIN 0x41 //Change only start of sector
+#define DCM_DOS_SECTOR 0x42 //128 byte compressed sector
+#define DCM_COMPRESSED 0x43 //Uncompressed/compressed pairs
+#define DCM_CHANGE_END 0x44 //Change only end of sector
+#define DCM_PASS_END 0x45 //End of pass
+#define DCM_SAME_AS_BEFORE 0x46 //Same as previous non-zero
+#define DCM_UNCOMPRESSED 0x47 //Uncompressed sector
+
+#define DCM_HEADER_SINGLE 0xFA
+#define DCM_HEADER_MULTI 0xF9
+
+#define DCM_DENSITY_SD 0 //Single density, 90K
+#define DCM_DENSITY_DD 1 //Double density, 180K
+#define DCM_DENSITY_ED 2 //Enhanced density, 130K
+
+CDcm::CDcm() : ADisk()
+{
+ #ifdef _MEMORY_DUMP_
+ printf( "CDcm constructed: %p\n", this );
+ #endif
+}
+
+CDcm::~CDcm()
+{
+ #ifdef _MEMORY_DUMP_
+ printf( "CDcm destructed: %p\n", this );
+ #endif
+}
+
+#ifndef __CDISK_NOLOAD__
+BOOL CDcm::Load( char* szFname, BOOL, BOOL )
+{
+ BYTE btArcType = 0; //Block type for first block
+ BYTE btBlkType; //Current block type
+
+ m_bAlreadyFormatted = FALSE;
+ m_bLastPass = FALSE;
+ m_wCurrentSector = 0;
+
+ CFile cfo;
+ CPreFile cf;
+
+ if ( !cfo.Open( szFname ) )
+ {
+ sprintf( m_szLastError, "DCM: Can't open '%s'", szFname );
+ m_iErrorCode = CDISK_ERROR_CANT_OPEN;
+ return FALSE;
+ }
+
+ strcpy( m_szFname, szFname );
+
+ cf.Open( &cfo, 20 );
+
+ m_lFileLength = cf.GetLength();
+
+ for(;;) //outpass
+ {
+ if ( cf.Tell() >= m_lFileLength )
+ {
+ if ( ( !m_bLastPass ) && ( btArcType == DCM_HEADER_MULTI ) )
+ {
+ sprintf( m_szLastError,"DCM: Multi-part archive error.\n" \
+ "To process these files, you must first combine the files into a single file." );
+ m_iErrorCode = CDCM_FORMAT_VIOLATED;
+ return FALSE;
+ }
+ }
+
+ btArcType = cf.readb();
+
+ switch( btArcType )
+ {
+ case DCM_HEADER_MULTI:
+ case DCM_HEADER_SINGLE:
+ if ( !DecodeRecFA( cf ) )
+ return FALSE;
+ break;
+
+ default:
+ sprintf( m_szLastError, "DCM: %02X is an unknown header block.\n", btArcType );
+ return FALSE;
+ }
+
+ for(;;) //inpass
+ {
+ btBlkType = cf.readb();
+
+ if ( btBlkType == DCM_PASS_END )
+ break;
+
+ if ( cf.Tell() >= m_lFileLength )
+ {
+ sprintf( m_szLastError, "DCM: EOF before end block." );
+ m_iErrorCode = CDCM_FORMAT_VIOLATED;
+ return FALSE;
+ }
+
+ BOOL bRes = TRUE;
+
+ *m_szLastError = '\0';
+ switch( btBlkType & 0x7F )
+ {
+ case DCM_CHANGE_BEGIN:
+ bRes = DecodeRec41( cf );
+ break;
+
+ case DCM_DOS_SECTOR:
+ bRes = DecodeRec42( cf );
+ break;
+
+ case DCM_COMPRESSED:
+ bRes = DecodeRec43( cf );
+ break;
+
+ case DCM_CHANGE_END:
+ bRes = DecodeRec44( cf );
+ break;
+
+ case DCM_SAME_AS_BEFORE:
+ //not needed
+ //bRes = DecodeRec46( cf );
+ break;
+
+ case DCM_UNCOMPRESSED:
+ bRes = DecodeRec47( cf );
+ break;
+
+ default:
+ {
+ switch( btBlkType )
+ {
+ case DCM_HEADER_MULTI:
+ case DCM_HEADER_SINGLE:
+ sprintf( m_szLastError, "DCM: Trying to start section but last section never had "
+ "an end section block.");
+ break;
+
+ default:
+ sprintf( m_szLastError, "DCM: %02X is an unknown block type. File may be "
+ "corrupt.",btBlkType);
+ break;
+ }
+
+ m_iErrorCode = CDCM_FORMAT_VIOLATED;
+ return FALSE;
+ }
+ }
+
+ if ( !bRes )
+ {
+ sprintf( m_szLastError, "DCM: Block %02X decode error!", btBlkType );
+ m_iErrorCode = CDCM_FORMAT_VIOLATED;
+ return FALSE;
+ }
+
+ if ( !WriteSector( m_wCurrentSector, m_abtCurrBuff ) )
+ return FALSE;
+
+ if ( btBlkType & 0x80 )
+ m_wCurrentSector++;
+ else
+ m_wCurrentSector = cf.readLEw();
+
+ } //infinite for (inpass)
+
+ //End block
+ if ( m_bLastPass )
+ break;
+
+ } //infinite for (outpass)
+
+ cf.Close();
+ cfo.Close();
+ return TRUE;
+
+}
+
+BOOL CDcm::DecodeRec41( CGenFile& cf )
+{
+ #ifdef _DCM_DUMP_
+ printf( "dec41: %08lX\n", cf.Tell() - 1 );
+ #endif
+
+ int iOffset = cf.readb();
+ BYTE* pbt = m_abtCurrBuff + iOffset;
+
+ do
+ {
+ *( pbt-- ) = cf.readb();
+ } while( iOffset-- );
+
+ return TRUE;
+}
+
+BOOL CDcm::DecodeRec42( CGenFile& cf )
+{
+ #ifdef _DCM_DUMP_
+ printf( "dec42: %08lX\n", cf.Tell() - 1 );
+ #endif
+
+ sprintf( m_szLastError, "DCM: Record type 0x42 untested. Uncomment?" );
+ return FALSE;
+
+ //TODO: uncomment later!
+ //cf.Read( m_abtCurrBuff + 123, 5 );
+ //memset( m_abtCurrBuff, m_abtCurrBuff[ 123 ], 123 );
+ //return TRUE;
+}
+
+BOOL CDcm::DecodeRec43( CGenFile& cf )
+{
+ #ifdef _DCM_DUMP_
+ printf( "dec43: %08lX\n", cf.Tell() - 1 );
+ #endif
+
+ BYTE* pbtP = m_abtCurrBuff;
+ BYTE* pbtE;
+
+ BYTE* pbtEnd = m_abtCurrBuff + m_iSectorSize;
+
+ do
+ {
+ //uncompressed string
+ if ( pbtP != m_abtCurrBuff )
+ pbtE = m_abtCurrBuff + ReadOffset( cf );
+ else
+ pbtE = m_abtCurrBuff + cf.readb();
+
+ if ( pbtE < pbtP )
+ return FALSE;
+
+ #ifdef _DCM_DUMP_
+ printf( "dec43: uncst: %p %p %ld\n", pbtP, pbtE, pbtE - pbtP );
+ #endif
+
+ if ( pbtE != pbtP )
+ {
+ cf.Read( pbtP, pbtE - pbtP );
+ pbtP = pbtE;
+ }
+
+ if ( pbtP >= pbtEnd )
+ break;
+
+ //rle compressed string
+ pbtE = m_abtCurrBuff + ReadOffset( cf );
+ BYTE c = cf.readb();
+
+ #ifdef _DCM_DUMP_
+ printf( "dec43: cst: %p %p %ld\n", pbtP, pbtE, pbtE - pbtP );
+ #endif
+
+ if ( pbtE < pbtP )
+ return FALSE;
+
+ memset( pbtP, c, pbtE - pbtP );
+ pbtP = pbtE;
+
+ } while( pbtP < pbtEnd );
+
+ return TRUE;
+}
+
+BOOL CDcm::DecodeRec44( CGenFile& cf )
+{
+ #ifdef _DCM_DUMP_
+ printf( "dec44: %08lX\n", cf.Tell() - 1 );
+ #endif
+
+ int iOffset = ReadOffset( cf );
+
+ cf.Read( m_abtCurrBuff + iOffset, m_iSectorSize - iOffset );
+
+ return TRUE;
+}
+
+BOOL CDcm::DecodeRec46( CGenFile& cf )
+{
+ #ifdef _DCM_DUMP_
+ printf( "dec46: %08lX\n", cf.Tell() - 1 );
+ #endif
+
+ return TRUE;
+}
+
+BOOL CDcm::DecodeRec47( CGenFile& cf )
+{
+ #ifdef _DCM_DUMP_
+ printf( "dec47: %08lX\n", cf.Tell() - 1 );
+ #endif
+
+ //TODO: Is this TRUE or NOT???
+ //cf.Read( m_abtCurrBuff, ( m_wCurrentSector < 4 ? 128 : m_iSectorSize ) );
+
+ cf.Read( m_abtCurrBuff, m_iSectorSize );
+ return TRUE;
+}
+
+BOOL CDcm::DecodeRecFA( CGenFile& cf )
+{
+ #ifdef _DCM_DUMP_
+ printf( "decFA: %08lX\n", cf.Tell() - 1 );
+ #endif
+
+ BYTE btPom = cf.readb();
+
+ BYTE btDensity = ( btPom >> 5 ) & 0x03;
+ //BYTE btPass = btPom & 0x1F;
+ m_bLastPass = ( btPom & 0x80 ) ? TRUE : FALSE;
+
+ int iSpT;
+ int iTracks;
+
+ switch( btDensity )
+ {
+ case DCM_DENSITY_SD:
+ iTracks = 40;
+ iSpT = 18;
+ m_iSectorSize = 128;
+ break;
+
+ case DCM_DENSITY_DD:
+ iTracks = 40;
+ iSpT = 18;
+ m_iSectorSize = 256;
+ break;
+
+ case DCM_DENSITY_ED:
+ iTracks = 40;
+ iSpT = 26;
+ m_iSectorSize = 128;
+ break;
+
+ default:
+ sprintf( m_szLastError,"DCM: Density type unknown (%02X)\n", btDensity );
+ return FALSE;
+ }
+
+ if ( !m_bAlreadyFormatted )
+ {
+ DISK_GEOMETRY dg;
+ dg.iSides = 1;
+ dg.iTracks = iTracks;
+ dg.iSectorsPerTrack = iSpT;
+ dg.iBytesPerSector = m_iSectorSize;
+
+ if ( !Format( &dg ) )
+ return FALSE;
+
+ m_bAlreadyFormatted = TRUE;
+ }
+
+ m_wCurrentSector = cf.readLEw();
+
+ return TRUE;
+}
+
+WORD CDcm::ReadOffset( CGenFile& cf )
+{
+ BYTE bt = cf.readb();
+
+ return( bt ? bt : 256 );
+}
+#endif
+
+#ifdef __CDISK_SAVE__
+
+BOOL CDcm::Save( char* szOutFile, BOOL bOverWrite )
+{
+ if ( !bOverWrite && !access( szOutFile, F_OK ) )
+ {
+ sprintf( m_szLastError, "DCM: File already exists! '%s'", szOutFile );
+ return FALSE;
+ }
+
+ int iDensity = -1;
+ m_iSectorSize = m_geometry.iBytesPerSector;
+
+ if ( m_iSectorSize == 0x80 )
+ {
+ if ( m_geometry.iTracks == 40 )
+ {
+ if ( m_geometry.iSectorsPerTrack == 18 )
+ iDensity = DCM_DENSITY_SD;
+
+ if ( m_geometry.iSectorsPerTrack == 26 )
+ iDensity = DCM_DENSITY_ED;
+ }
+ }
+
+ if ( m_iSectorSize == 0x100 )
+ {
+ if ( ( m_geometry.iSectorsPerTrack == 18 ) &&
+ ( m_geometry.iTracks == 40 ) )
+ iDensity = DCM_DENSITY_DD;
+ }
+
+ if ( iDensity == - 1 )
+ {
+ sprintf( m_szLastError, "DCM: Can't work with such density!" );
+ return FALSE;
+ }
+
+ int iPass = 1;
+
+ m_pbtPass = new BYTE [ 0x6500 ];
+
+ CFile cf;
+
+ if ( !cf.Create( szOutFile ) )
+ {
+ sprintf( m_szLastError, "DCM: Can't create '%s'", szOutFile );
+ delete [] m_pbtPass;
+ return FALSE;
+ }
+
+ int iFirstSector = 0;
+ int iPrevSector = 0;
+ int iCurrentSector = 1;
+
+ memset( m_abtPrevBuff, 0, m_iSectorSize );
+
+ EncodeRecFA( FALSE, iPass, iDensity, iFirstSector );
+
+ //here should be other compression
+
+ while( iCurrentSector <= m_geometry.iSectors )
+ {
+ iFirstSector = 0;
+
+ while( ( m_pbtCurr - m_pbtPass ) < 0x5EFD )
+ {
+ if ( iCurrentSector > m_geometry.iSectors )
+ break;
+
+ ReadSector( m_abtCurrBuff, iCurrentSector );
+
+ BOOL bSkip = IsBlockEmpty( m_abtCurrBuff, m_iSectorSize );
+
+ //first non empty sector is marked as first, what a surprise! :)
+ if ( !bSkip && !iFirstSector )
+ {
+ iFirstSector = iCurrentSector;
+ iPrevSector = iCurrentSector;
+ }
+
+ //if just skipped, increment sector
+ if ( bSkip )
+ {
+ iCurrentSector++;
+ }
+ else
+ {
+ //if there is a gap, write sector number
+ if ( ( iCurrentSector - iPrevSector ) > 1 )
+ {
+ *( m_pbtCurr++ ) = iCurrentSector;
+ *( m_pbtCurr++ ) = iCurrentSector >> 8;
+ }
+ else
+ {
+ //else mark previous record
+ *m_pbtLastRec |= 0x80;
+ }
+
+ //first sector could be encoded with only some data
+ if ( iCurrentSector == iFirstSector )
+ EncodeRec( TRUE );
+ else
+ {
+ //if are same, encode as record 46
+ if ( !memcmp( m_abtPrevBuff, m_abtCurrBuff, m_iSectorSize ) )
+ EncodeRec46();
+ else
+ EncodeRec( FALSE );
+ }
+
+ //store this sector as previous
+ memcpy( m_abtPrevBuff, m_abtCurrBuff, m_iSectorSize );
+
+ //and move pointers
+ iPrevSector = iCurrentSector;
+ iCurrentSector++;
+ }
+
+ }
+
+ //mark previous sector
+ *m_pbtLastRec |= 0x80;
+
+ //encode end
+ EncodeRec45();
+
+ BYTE* pEnd = m_pbtCurr;
+
+ //change beginning block
+ if ( iCurrentSector > m_geometry.iSectors )
+ EncodeRecFA( TRUE, iPass, iDensity, iFirstSector );
+ else
+ EncodeRecFA( FALSE, iPass, iDensity, iFirstSector );
+
+ //and write whole pass
+
+ if ( ( pEnd - m_pbtPass ) > 0x6000 )
+ {
+ sprintf( m_szLastError, "DCM: Internal error! Pass too long!" );
+ delete [] m_pbtPass;
+ cf.Close();
+ unlink( szOutFile );
+ return FALSE;
+ }
+
+ if ( !cf.Write( m_pbtPass, pEnd - m_pbtPass ) )
+ {
+ sprintf( m_szLastError, "DCM: Can't write!" );
+ delete [] m_pbtPass;
+ cf.Close();
+ unlink( szOutFile );
+ return FALSE;
+ }
+
+ iPass++;
+ }
+
+ cf.Close();
+
+ delete [] m_pbtPass;
+
+ return TRUE;
+}
+
+void CDcm::EncodeRecFA( BOOL bLast, int iPass, int iDensity, int iFirstSec )
+{
+ m_pbtCurr = m_pbtPass;
+
+ #ifdef _DCM_DUMP_
+ printf( "ERFA: %08lX\n", m_pbtCurr - m_pbtPass );
+ #endif
+
+ m_pbtLastRec = m_pbtCurr;
+
+ BYTE btType = bLast ? 0x80 : 0;
+
+ btType |= ( iDensity & 3 ) << 5;
+
+ btType |= ( iPass & 0x1F );
+
+ *( m_pbtCurr++ ) = DCM_HEADER_SINGLE;
+ *( m_pbtCurr++ ) = btType;
+ *( m_pbtCurr++ ) = iFirstSec;
+ *( m_pbtCurr++ ) = iFirstSec >> 8;
+
+}
+
+void CDcm::EncodeRec45()
+{
+ #ifdef _DCM_DUMP_
+ printf( "ER45: %08lX\n", m_pbtCurr - m_pbtPass );
+ #endif
+
+ m_pbtLastRec = m_pbtCurr;
+ *( m_pbtCurr++ ) = DCM_PASS_END;
+}
+
+void CDcm::EncodeRec46()
+{
+ #ifdef _DCM_DUMP_
+ printf( "ER46: %08lX\n", m_pbtCurr - m_pbtPass );
+ #endif
+
+ m_pbtLastRec = m_pbtCurr;
+ *( m_pbtCurr++ ) = DCM_SAME_AS_BEFORE;
+}
+
+void CDcm::EncodeRec( BOOL bIsFirstSector )
+{
+ #ifdef _DCM_DUMP_
+ printf( "ER: %08lX\n", m_pbtCurr - m_pbtPass );
+ #endif
+
+ m_pbtLastRec = m_pbtCurr;
+
+ BYTE abtBuff41[ 0x300 ];
+ BYTE abtBuff43[ 0x300 ];
+ BYTE abtBuff44[ 0x300 ];
+ BYTE* abtBuff47 = m_abtCurrBuff;
+
+ int iEnd41 = 0x300;
+ int iEnd43 = 0x300;
+ int iEnd44 = 0x300;
+
+ int iBestMethod = DCM_UNCOMPRESSED;
+ int iBestEnd = m_iSectorSize;
+ BYTE* pbtBest = abtBuff47;
+
+ EncodeRec43( abtBuff43, &iEnd43, m_abtCurrBuff, m_iSectorSize );
+
+ if ( !bIsFirstSector )
+ {
+ EncodeRec41( abtBuff41, &iEnd41, m_abtCurrBuff, m_abtPrevBuff, m_iSectorSize );
+ EncodeRec44( abtBuff44, &iEnd44, m_abtCurrBuff, m_abtPrevBuff, m_iSectorSize );
+ }
+
+ if ( iEnd41 < iBestEnd )
+ {
+ iBestMethod = DCM_CHANGE_BEGIN;
+ iBestEnd = iEnd41;
+ pbtBest = abtBuff41;
+ }
+
+ if ( iEnd43 < iBestEnd )
+ {
+ iBestMethod = DCM_COMPRESSED;
+ iBestEnd = iEnd43;
+ pbtBest = abtBuff43;
+ }
+
+ if ( iEnd44 < iBestEnd )
+ {
+ iBestMethod = DCM_CHANGE_END;
+ iBestEnd = iEnd44;
+ pbtBest = abtBuff44;
+ }
+
+ *( m_pbtCurr++ ) = iBestMethod;
+ memcpy( m_pbtCurr, pbtBest, iBestEnd );
+ m_pbtCurr += iBestEnd;
+}
+
+void CDcm::EncodeRec41( BYTE* pbtDest, int* piDestLen, BYTE* pbtSrc, BYTE* pbtSrcOld, int iSrcLen )
+{
+ BYTE* pbtS = pbtSrc + iSrcLen - 1;
+ pbtSrcOld += iSrcLen - 1;
+
+ BYTE* pbtD = pbtDest;
+
+ for( int i = 0; i < iSrcLen; i++ )
+ {
+ if ( *( pbtS-- ) != * ( pbtSrcOld-- ) )
+ break;
+ }
+
+ pbtS++;
+
+ *( pbtD++ ) = pbtS - pbtSrc;
+
+ int iBytes = pbtS - pbtSrc + 1;
+
+ while( iBytes-- )
+ {
+ *( pbtD++ ) = *( pbtS-- );
+ }
+
+ *piDestLen = pbtD - pbtDest;
+}
+
+void CDcm::EncodeRec43( BYTE* pbtDest, int* piDestLen, BYTE* pbtSrc, int iSrcLen )
+{
+ BYTE* pbtEnd = pbtSrc + iSrcLen;
+ BYTE* pbtCur = pbtSrc;
+
+ BYTE* pbtD = pbtDest;
+
+ while( pbtCur < pbtEnd )
+ {
+ BOOL bFound = FALSE;
+
+ for( BYTE* pbtNow = pbtCur; pbtNow < ( pbtEnd - 2 ); pbtNow++ )
+ {
+
+ if ( ( *pbtNow == *(pbtNow+1) ) && ( *pbtNow == *(pbtNow+2) ) )
+ {
+ int iUnc = pbtNow - pbtCur;
+
+ *( pbtD ++ ) = pbtNow - pbtSrc;
+ if ( iUnc )
+ {
+ memcpy( pbtD, pbtCur, iUnc );
+ pbtD += iUnc;
+ }
+
+ BYTE bt = *pbtNow;
+ BYTE*p;
+ for( p = pbtNow + 1; p < pbtEnd; p++ )
+ {
+ if ( *p != bt )
+ break;
+ }
+
+ if ( p > pbtEnd )
+ p = pbtEnd;
+
+ *( pbtD++ ) = p - pbtSrc;
+ *( pbtD++ ) = bt;
+
+ pbtCur = p;
+ bFound = TRUE;
+ break;
+ }
+ }
+
+ if ( ( pbtCur >= pbtEnd - 2 ) || !bFound )
+ {
+ if ( pbtCur < pbtEnd )
+ {
+ *( pbtD++ ) = iSrcLen;
+ memcpy( pbtD, pbtCur, pbtEnd - pbtCur );
+ pbtD += pbtEnd - pbtCur;
+ }
+
+ break;
+ }
+
+ }
+
+ *piDestLen = pbtD - pbtDest;
+}
+
+void CDcm::EncodeRec44( BYTE* pbtDest, int* piDestLen, BYTE* pbtSrc, BYTE* pbtSrcOld, int iSrcLen )
+{
+ BYTE* pbtS = pbtSrc;
+ BYTE* pbtEnd = pbtSrc + iSrcLen;
+
+ BYTE* pbtD = pbtDest;
+
+ for( int i = 0; i < iSrcLen; i++ )
+ {
+ if ( *( pbtS++ ) != * ( pbtSrcOld++ ) )
+ break;
+ }
+
+ pbtS--;
+
+ *( pbtD++ ) = pbtS - pbtSrc;
+ memcpy( pbtD, pbtS, pbtEnd - pbtS );
+ pbtD += pbtEnd - pbtS;
+
+ *piDestLen = pbtD - pbtDest;
+}
+
+#endif // __CDISK_SAVE__
+
diff --git a/jindroush/lib/adsk_di.cpp b/jindroush/lib/adsk_di.cpp
new file mode 100644
index 0000000..b49bb9d
--- /dev/null
+++ b/jindroush/lib/adsk_di.cpp
@@ -0,0 +1,271 @@
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+//
+
+#include "adsk_di.h"
+#include "autil.h"
+#include "cfile.h"
+
+BYTE di_crc( BYTE* pbt, int iLen )
+{
+ WORD crc = 0;
+
+ while( iLen-- )
+ {
+ crc += *( pbt++ );
+ if( crc >= 0x100 )
+ crc -= 0xFF;
+ }
+
+ return crc;
+}
+
+CDi::CDi() : ADisk()
+{
+ #ifdef _MEMORY_DUMP_
+ printf( "CDi constructed: %p\n", this );
+ #endif
+}
+
+CDi::~CDi()
+{
+ #ifdef _MEMORY_DUMP_
+ printf( "CDi destructed: %p\n", this );
+ #endif
+}
+
+#ifndef __CDISK_NOLOAD__
+BOOL CDi::Load( char* szFname, BOOL bRepair, BOOL bRepairAuto )
+{
+ m_iErrorCode = 0;
+
+ CFile cf;
+ if ( !cf.Open( szFname ) )
+ {
+ sprintf( m_szLastError, "DI: Can't open '%s'", szFname );
+ m_iErrorCode = CDISK_ERROR_CANT_OPEN;
+ return FALSE;
+ }
+
+ strcpy( m_szFname, szFname );
+
+ WORD wMagic = cf.readLEw();
+
+ if ( wMagic != 18756 ) //'DI'
+ {
+ sprintf( m_szLastError, "DI: File '%s' is not an DI file!", szFname );
+ return FALSE;
+ }
+
+ BYTE btVerLo = cf.readb();
+ BYTE btVerHi = cf.readb();
+
+ if( ( btVerLo != 0x20 ) || ( btVerHi != 0x02 ) )
+ {
+ sprintf( m_szLastError, "DI: The file '%s' has strange version!\n"
+ "This program can't work with it now.\n"
+ "Send the file for the analysis.", szFname );
+ m_iErrorCode = CDI_FORMAT_VIOLATED;
+ return FALSE;
+ }
+
+ int iMax = 200;
+ while( iMax-- )
+ {
+ if( ! cf.readb() )
+ break;
+ }
+
+ if( !iMax )
+ {
+ sprintf( m_szLastError, "DI: Runaway in header ('%s')", szFname );
+ m_iErrorCode = CDI_FORMAT_VIOLATED;
+ return FALSE;
+ }
+
+ //todo: this need the documentation! Is it number of sides?
+ //BYTE btUnk1 =
+ cf.readb();
+
+ BYTE btTracks = cf.readb();
+ WORD wSectorsPerTrack = cf.readBEw();
+
+ //todo: are these the flags?
+ //WORD wUnk2 =
+ //cf.readBEw();
+ BYTE btSides = cf.readb() + 1;
+ cf.readb();
+
+ WORD wSectorSize = cf.readBEw();
+
+ //todo: and what about this?
+ //BYTE btUnk3 =
+ cf.readb();
+
+ switch( wSectorSize )
+ {
+ case 0x80:
+ case 0x100:
+ break;
+
+ default:
+ {
+ sprintf( m_szLastError, "DI: Invalid sector size: %04X", wSectorSize );
+ m_iErrorCode = CDI_FORMAT_VIOLATED;
+ return FALSE;
+ }
+ }
+
+ DISK_GEOMETRY dg;
+
+ dg.iSides = btSides;
+ dg.iTracks = btTracks;
+ dg.iSectorsPerTrack = wSectorsPerTrack;
+ dg.iBytesPerSector = wSectorSize;
+
+ if ( !Format( &dg ) )
+ return FALSE;
+
+ BYTE abtBuff[ 0x100 ];
+ memset( abtBuff, 0, 0x100 );
+
+ int iSectors = m_geometry.iSectors;
+
+ BYTE* pBuf = new BYTE[ iSectors ];
+ cf.Read( pBuf, iSectors );
+
+ BYTE* p = pBuf;
+
+ for( int i = 0; i < iSectors; i++ )
+ {
+ if( *p )
+ {
+ int iSecSize = ( i < 3 ) ? 0x80 : wSectorSize;
+
+ int iRead;
+
+ cf.Read( abtBuff, iSecSize, &iRead );
+
+ if ( iRead != iSecSize )
+ {
+ sprintf( m_szLastError, "DI: Read error. File truncated?" );
+ delete [] pBuf;
+ cf.Close();
+ m_iErrorCode = CDI_FORMAT_VIOLATED;
+ return FALSE;
+ }
+
+ BYTE crc = di_crc( abtBuff, iSecSize );
+
+ if( *p != crc )
+ {
+ sprintf( m_szLastError, "DI: Sector checksum failed: Sector %d Given: %02X Computed: %02X", i + 1, *p, crc );
+ delete [] pBuf;
+ cf.Close();
+ m_iErrorCode = CDI_FORMAT_VIOLATED;
+ return FALSE;
+ }
+
+ WriteSector( i + 1, abtBuff );
+ }
+ p++;
+ }
+
+ delete [] pBuf;
+
+ cf.Close();
+ return TRUE;
+
+}
+
+#endif
+
+#ifdef __CDISK_SAVE__
+
+char szDIhd[] = "Jindroush's DI class v1.00";
+//char szDIhd[] = "XL/ST-link 2.2.0› ";
+
+BOOL CDi::Save( char* szOutFile, BOOL bOverWrite )
+{
+ if( ( m_geometry.iTracks > 0xFF ) ||
+ ( m_geometry.iSectorsPerTrack > 0xFFFF ) ||
+ ( m_geometry.iSides > 2 ) )
+ {
+ sprintf( m_szLastError, "DI: Can't create such file! Is it possible? :-)" );
+ return FALSE;
+ }
+
+ CFile cf;
+
+ if ( !bOverWrite && !access( szOutFile, F_OK ) )
+ {
+ sprintf( m_szLastError, "DI: File already exists! '%s'", szOutFile );
+ return FALSE;
+ }
+
+ if ( !cf.Create( szOutFile ) )
+ {
+ sprintf( m_szLastError, "DI: Can't create '%s'", szOutFile );
+ return FALSE;
+ }
+
+ cf.writeb( 'D' );
+ cf.writeb( 'I' );
+ cf.writeb( 0x20 );
+ cf.writeb( 0x02 );
+
+ cf.Write( szDIhd, strlen( szDIhd ) + 1 );
+
+ cf.writeb( 1 );
+ cf.writeb( m_geometry.iTracks );
+ cf.writeBEw( m_geometry.iSectorsPerTrack );
+ cf.writeb( m_geometry.iSides - 1 );
+ cf.writeb( 0 );
+ cf.writeBEw( m_geometry.iBytesPerSector );
+ cf.writeb( 0 );
+
+ BYTE abtBuff[ 0x100 ];
+ memset( abtBuff, 0, 0x100 );
+
+ BYTE* pBuf = new BYTE[ m_geometry.iSectors ];
+
+ for( int i = 0; i < m_geometry.iSectors; i++ )
+ {
+ int iSecSize = ( i < 3 ) ? 0x80 : m_geometry.iBytesPerSector;
+
+ ReadSector( abtBuff, i + 1 );
+ pBuf[ i ] = di_crc( abtBuff, iSecSize );
+ }
+
+ cf.Write( pBuf, m_geometry.iSectors );
+
+ for( int i = 0; i < m_geometry.iSectors; i++ )
+ {
+ int iSecSize = ( i < 3 ) ? 0x80 : m_geometry.iBytesPerSector;
+
+ ReadSector( abtBuff, i + 1 );
+ if( pBuf[ i ] || !IsBlockEmpty( abtBuff, iSecSize ) )
+ {
+ cf.Write( abtBuff, iSecSize );
+ }
+ }
+
+ delete [] pBuf;
+
+ cf.Close();
+
+ return TRUE;
+}
+
+#endif //__CDISK_WRITE__
diff --git a/jindroush/lib/adsk_scp.cpp b/jindroush/lib/adsk_scp.cpp
new file mode 100644
index 0000000..51d3dae
--- /dev/null
+++ b/jindroush/lib/adsk_scp.cpp
@@ -0,0 +1,281 @@
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+//
+
+#include "adsk_scp.h"
+#include "autil.h"
+#include "cfile.h"
+
+#define SCP_MAGIC 0xFDFD
+
+CScp::CScp() : ADisk()
+{
+ #ifdef _MEMORY_DUMP_
+ printf( "CScp constructed: %p\n", this );
+ #endif
+}
+
+CScp::~CScp()
+{
+ #ifdef _MEMORY_DUMP_
+ printf( "CScp destructed: %p\n", this );
+ #endif
+}
+
+#ifndef __CDISK_NOLOAD__
+BOOL CScp::Load( char* szFname, BOOL, BOOL )
+{
+ WORD wMagic;
+ BYTE btSectorSize;
+ BYTE btTracks;
+ BYTE btSectorsPerTrack;
+
+ CFile cf;
+
+ if( !cf.Open( szFname ) )
+ {
+ sprintf( m_szLastError, "SCP: Can't open '%s'", szFname );
+ return FALSE;
+ }
+
+ strcpy( m_szFname, szFname );
+
+ wMagic = cf.readLEw();
+
+ if ( wMagic != SCP_MAGIC )
+ {
+ sprintf( m_szLastError, "SCP: File '%s' is not an SCP file!", szFname );
+ return FALSE;
+ }
+
+ btSectorSize = cf.readb();
+ btTracks = cf.readb();
+ btSectorsPerTrack = cf.readb();
+
+ int iSectorSize;
+
+ switch( btSectorSize )
+ {
+ case 0x80:
+ iSectorSize = 0x80;
+ break;
+
+ case 0x00:
+ iSectorSize = 0x100;
+ break;
+
+ default:
+ {
+ sprintf( m_szLastError, "SCP: Invalid sector size: %02X", btSectorSize );
+ return FALSE;
+ }
+ }
+
+ DISK_GEOMETRY dg;
+ dg.iSides = 1;
+ dg.iTracks = btTracks;
+ dg.iSectorsPerTrack = btSectorsPerTrack;
+ dg.iBytesPerSector = iSectorSize;
+
+ if ( !Format( &dg ) )
+ return FALSE;
+
+ BYTE *pbtTable = new BYTE [ btSectorsPerTrack * btTracks ];
+
+ if ( ! pbtTable )
+ {
+ sprintf( m_szLastError, "SCP: Not enough memory for sector table!" );
+ return FALSE;
+ }
+
+ if ( !cf.Read( pbtTable, btSectorsPerTrack * btTracks ) )
+ {
+ sprintf( m_szLastError, "SCP: Can't read sector table!" );
+ return FALSE;
+ }
+
+ BYTE abtBuff[ 0x100 ];
+ memset( abtBuff, 0, 0x100 );
+
+ BYTE* pbtPtr = pbtTable;
+
+ for( int iTrack = 0; iTrack < btTracks; iTrack++ )
+ {
+ for( int iSector = 0; iSector < btSectorsPerTrack; iSector++ )
+ {
+ if ( *pbtPtr )
+ {
+ int iNowRead;
+
+ if ( !iTrack && ( iSector < 3 ) )
+ iNowRead = 0x80;
+ else
+ iNowRead = iSectorSize;
+
+ int iReallyRead;
+
+ if ( !cf.Read( abtBuff, iNowRead, &iReallyRead ) || ( iNowRead != iReallyRead ) )
+ {
+ delete [] pbtTable;
+ sprintf( m_szLastError, "SCP: Image broken!" );
+ return FALSE;
+ }
+
+ if ( !WriteSector( *pbtPtr + iTrack* btSectorsPerTrack, abtBuff ) )
+ {
+ delete [] pbtTable;
+ return FALSE;
+ }
+
+ }
+ pbtPtr++;
+ }
+
+ }
+
+ delete [] pbtTable;
+
+ cf.Close();
+ return TRUE;
+
+}
+#endif
+
+#ifdef __CDISK_SAVE__
+
+BOOL CScp::Save( char* szOutFile, BOOL bOverWrite )
+{
+ if ( !bOverWrite && !access( szOutFile, F_OK ) )
+ {
+ sprintf( m_szLastError, "SCP: File already exists! '%s'", szOutFile );
+ return FALSE;
+ }
+
+ BYTE btSize;
+ BYTE btTracks;
+ BYTE btSpT;
+
+ switch ( m_geometry.iBytesPerSector )
+ {
+ case 0x80:
+ btSize = 0x80;
+ break;
+
+ case 0x100:
+ default:
+ btSize = 0x00;
+ break;
+ }
+
+ BOOL bGood = FALSE;
+
+ btTracks = m_geometry.iTracks;
+ btSpT = m_geometry.iSectorsPerTrack;
+
+ if ( ( m_geometry.iTracks == 40 ) && ( m_geometry.iSectorsPerTrack == 18 ) )
+ bGood = TRUE;
+
+ if ( ( m_geometry.iTracks == 40 ) && ( m_geometry.iSectorsPerTrack == 26 ) )
+ bGood = TRUE;
+
+ if ( !bGood )
+ {
+ sprintf( m_szLastError, "SCP: Can't export, because of invalid disk size!" );
+ return FALSE;
+ }
+
+ int iMapSize = m_geometry.iTracks * m_geometry.iSectorsPerTrack;
+
+ BYTE* pMap = new BYTE [ iMapSize ];
+
+ if ( !pMap )
+ {
+ sprintf( m_szLastError, "SCP: Can't allocate memory for map!" );
+ return FALSE;
+ }
+
+ memset( pMap, 0, iMapSize );
+
+
+ CFile cf;
+
+ if ( !cf.Create( szOutFile ) )
+ {
+ sprintf( m_szLastError, "SCP: Can't create '%s'", szOutFile );
+ delete [] pMap;
+ return FALSE;
+ }
+
+ WORD wMagic = SCP_MAGIC;
+
+ cf.writeLEw( wMagic );
+ cf.writeb( btSize );
+ cf.writeb( btTracks );
+ cf.writeb( btSpT );
+
+ cf.Seek( iMapSize, SEEK_CUR );
+
+ BYTE abtBuff[ 0x100 ];
+
+ int iSectors = m_geometry.iSectors;
+
+ for( int i = 0; i < iSectors; i++ )
+ {
+ if ( !ReadSector( abtBuff, i + 1 ) )
+ {
+ delete [] pMap;
+ cf.Close();
+ unlink( szOutFile );
+ return FALSE;
+ }
+
+ int iBytesNow = ( i < 3 ) ? 0x80 : m_geometry.iBytesPerSector;
+
+ if ( !IsBlockEmpty( abtBuff, iBytesNow ) )
+ {
+ int iWritten;
+ if ( !cf.Write( abtBuff, iBytesNow, &iWritten ) || ( iBytesNow != iWritten ) )
+ {
+ sprintf( m_szLastError, "SCP: Error writing to '%s'", szOutFile );
+ delete [] pMap;
+ cf.Close( );
+ unlink( szOutFile );
+ return FALSE;
+
+ }
+
+ pMap[ i ] = ( i % btSpT ) + 1;
+ }
+ }
+
+ cf.Seek( 5, SEEK_SET );
+
+ if ( !cf.Write( pMap, iMapSize ) )
+ {
+ sprintf( m_szLastError, "SCP: Can't write!" );
+ delete [] pMap;
+ cf.Close( );
+ unlink( szOutFile );
+ return FALSE;
+
+ }
+
+ delete [] pMap;
+
+ cf.Close();
+
+ return TRUE;
+}
+
+#endif //__CDISK_SAVE__
diff --git a/jindroush/lib/adsk_xfd.cpp b/jindroush/lib/adsk_xfd.cpp
new file mode 100644
index 0000000..870a59b
--- /dev/null
+++ b/jindroush/lib/adsk_xfd.cpp
@@ -0,0 +1,327 @@
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+//
+
+#include "adsk_xfd.h"
+#include "autil.h"
+#include "cfile.h"
+
+CXfd::CXfd() : ADisk()
+{
+ #ifdef _MEMORY_DUMP_
+ printf( "CXfd constructed: %p\n", this );
+ #endif
+}
+
+CXfd::~CXfd()
+{
+ #ifdef _MEMORY_DUMP_
+ printf( "CXfd destructed: %p\n", this );
+ #endif
+}
+
+typedef enum
+{
+ LOAD_OK,
+ LOAD_BAD_DD_1,
+ LOAD_BAD_DD_2,
+ LOAD_BAD_DD_3
+} LOAD_VARIANT;
+
+#ifndef __CDISK_NOLOAD__
+BOOL CXfd::Load( char* szFname, BOOL bRepair, BOOL bRepairAuto )
+{
+ LOAD_VARIANT load_method = LOAD_OK;
+
+ CFile cf;
+
+ if ( !cf.Open( szFname ) )
+ {
+ sprintf( m_szLastError, "XFD: Can't open '%s'", szFname );
+ return FALSE;
+ }
+
+ strcpy( m_szFname, szFname );
+
+ LONG lFileLen = cf.GetLength();
+
+ int iSecs;
+ int iSecSize;
+
+ if ( lFileLen % 0x80 )
+ {
+ sprintf( m_szLastError, "XFD: Strange length!" );
+ cf.Close();
+ return FALSE;
+ }
+
+ if ( ( lFileLen / 0x80 ) > 1040 )
+ {
+ iSecSize = 0x100;
+
+ iSecs = ( ( lFileLen - 0x180 ) / 0x100 ) + 3;
+ }
+ else
+ {
+ iSecSize = 0x80;
+ iSecs = lFileLen / 0x80;
+ }
+
+ if ( ( ( ( iSecs - 3 ) * iSecSize ) + 0x180 ) != lFileLen )
+ {
+ sprintf( m_szLastError, "XFD: Format violated: (%08lX != %08X)", lFileLen, iSecs * iSecSize );
+ m_iErrorCode = CXFD_FORMAT_VIOLATED;
+
+ #ifdef __CDISK_NOREPAIR__
+ cf.Close();
+ return FALSE;
+
+ #else
+ if ( !bRepair )
+ {
+ cf.Close();
+ return FALSE;
+ }
+ else
+ {
+ iSecs = lFileLen / iSecSize;
+ BYTE abtBuff[ 0x100 ];
+
+ memset( abtBuff, 0, 0x100 );
+
+ int iM1zeroes = 3;
+ int iM2zeroes = 3;
+ int iM3zeroes = 3;
+
+ cf.Seek( ( 0x02 - 1 ) * 0x80, SEEK_SET );
+ cf.Read( abtBuff, 0x80 );
+
+ if ( IsBlockEmpty( abtBuff, 0x80 ) )
+ iM1zeroes--;
+
+ cf.Seek( ( 0x04 - 1 ) * 0x80, SEEK_SET );
+ cf.Read( abtBuff, 0x80 );
+
+ if ( IsBlockEmpty( abtBuff, 0x80 ) )
+ {
+ iM1zeroes--;
+ iM2zeroes--;
+ }
+
+ cf.Seek( ( 0x05 - 1 ) * 0x80, SEEK_SET );
+ cf.Read( abtBuff, 0x80 );
+
+ if ( IsBlockEmpty( abtBuff, 0x80 ) )
+ iM2zeroes--;
+
+ cf.Seek( ( 0x06 - 1 ) * 0x80, SEEK_SET );
+ cf.Read( abtBuff, 0x80 );
+
+ if ( IsBlockEmpty( abtBuff, 0x80 ) )
+ {
+ iM1zeroes--;
+ iM2zeroes--;
+ }
+
+ cf.Seek( -0x180, SEEK_END );
+ cf.Read( abtBuff, 0x80 );
+ if ( IsBlockEmpty( abtBuff, 0x80 ) )
+ iM3zeroes--;
+
+ cf.Read( abtBuff, 0x80 );
+ if ( IsBlockEmpty( abtBuff, 0x80 ) )
+ iM3zeroes--;
+
+ cf.Read( abtBuff, 0x80 );
+ if ( IsBlockEmpty( abtBuff, 0x80 ) )
+ iM3zeroes--;
+
+ if ( !iM1zeroes )
+ {
+ load_method = LOAD_BAD_DD_1;
+ }
+ else if ( !iM2zeroes )
+ {
+ load_method = LOAD_BAD_DD_2;
+ }
+ else if ( !iM3zeroes )
+ {
+ load_method = LOAD_BAD_DD_3;
+ }
+
+ if ( !bRepairAuto )
+ {
+ printf( "Invalid DD ATR file encountered.\n" );
+ printf( "Choose repair method:\n" );
+ printf( "1) Sector, gap, sector, gap, sector, gap, data\n" );
+ printf( "2) Three sectors, three empty sectors, data\n" );
+ printf( "3) Data, three empty sectors\n" );
+ printf( "4) Don't repair\n" );
+
+ switch( load_method )
+ {
+ case LOAD_BAD_DD_1:
+ printf( "(Method 1 looks best)\n" );
+ break;
+
+ case LOAD_BAD_DD_2:
+ printf( "(Method 2 looks best)\n" );
+ break;
+
+ case LOAD_BAD_DD_3:
+ printf( "(Method 3 looks best)\n" );
+ break;
+
+ default:
+ break;
+ }
+
+ int iMethod;
+
+ printf( "\n" );
+ do
+ {
+ iMethod = getch() - '0';
+ } while( ( iMethod < 1 ) || ( iMethod > 4 ) );
+
+ if ( iMethod == 4 )
+ {
+ cf.Close();
+ return FALSE;
+ }
+ }
+ else
+ {
+ if ( load_method == LOAD_OK )
+ load_method = LOAD_BAD_DD_1;
+ }
+
+ cf.Seek( 0, SEEK_SET );
+ }
+ #endif
+ }
+
+ DISK_GEOMETRY dg;
+
+ GuessClassicSizes( iSecs, iSecSize, &dg );
+
+ if ( !Format( &dg ) )
+ {
+ cf.Close();
+ return FALSE;
+ }
+
+ BYTE abtBuff[ 0x100 ];
+ memset( abtBuff, 0, 0x100 );
+
+ for( int i = 0; i < iSecs; i++ )
+ {
+ switch( load_method )
+ {
+ default:
+ case LOAD_OK:
+ cf.Read( abtBuff, ( i < 3 ) ? 0x80 : iSecSize );
+ break;
+
+ case LOAD_BAD_DD_1:
+ if ( i < 3 )
+ {
+ cf.Read( abtBuff, 0x80 );
+ cf.Seek( 0x80, SEEK_CUR );
+ }
+ else
+ cf.Read( abtBuff, 0x100 );
+ break;
+
+ case LOAD_BAD_DD_2:
+ if ( i < 3 )
+ {
+ cf.Read( abtBuff, 0x80 );
+
+ if ( i == 2 )
+ cf.Seek( 0x180, SEEK_CUR );
+ }
+ else
+ cf.Read( abtBuff, 0x100 );
+
+ break;
+
+ case LOAD_BAD_DD_3:
+ if ( i < 3 )
+ cf.Read( abtBuff, 0x80 );
+ else
+ cf.Read( abtBuff, 0x100 );
+
+ break;
+ }
+
+ if ( !WriteSector( i + 1, abtBuff ) )
+ {
+ cf.Close();
+ return FALSE;
+ }
+ }
+
+ cf.Close();
+ return TRUE;
+
+}
+#endif
+
+
+#ifdef __CDISK_SAVE__
+
+BOOL CXfd::Save( char* szOutFile, BOOL bOverWrite )
+{
+ CFile cf;
+
+ if ( !bOverWrite && !access( szOutFile, F_OK ) )
+ {
+ sprintf( m_szLastError, "XFD: File already exists! '%s'", szOutFile );
+ return FALSE;
+ }
+
+ if ( !cf.Create( szOutFile ) )
+ {
+ sprintf( m_szLastError, "XFD: Can't create '%s'", szOutFile );
+ return FALSE;
+ }
+
+ BYTE abtBuff[ 0x100 ];
+
+ for( WORD i = 1; i <= m_geometry.iSectors; i++ )
+ {
+ if ( !ReadSector( abtBuff, i ) )
+ return FALSE;
+
+ int iToWrite = ( i <= 3 ) ? 0x80: m_geometry.iBytesPerSector;
+
+ int iWritten;
+
+ if ( !cf.Write( abtBuff, iToWrite, &iWritten ) || ( iWritten != iToWrite ) )
+ {
+ sprintf( m_szLastError, "XFD: Can't write!" );
+ cf.Close();
+ unlink( szOutFile );
+ return FALSE;
+ }
+
+ }
+
+ cf.Close();
+
+ return TRUE;
+}
+
+#endif //__CDISK_SAVE__
diff --git a/jindroush/lib/at_dis.cpp b/jindroush/lib/at_dis.cpp
new file mode 100644
index 0000000..e799258
--- /dev/null
+++ b/jindroush/lib/at_dis.cpp
@@ -0,0 +1,1201 @@
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+//
+
+#include "jintypes.h"
+#include "at_dis.h"
+
+struct
+{
+ char *instruct;
+ int length;
+ int branch;
+ int immed;
+ int write;
+} instable[] =
+{
+ { "BRK", 0, 0, 1, 0 }, //00
+ { "ORA\t(*,X)", 1, 0, 0, 0 }, //01
+ { "???", 0, 0, 1, 0 }, //02
+ { "???", 0, 0, 1, 0 }, //03
+ { "???", 0, 0, 1, 0 }, //04
+ { "ORA\t*", 1, 0, 0, 0 }, //05
+ { "ASL\t*", 1, 0, 0, 0 }, //06
+ { "???", 0, 0, 1, 0 }, //07
+ { "PHP", 0, 0, 1, 0 }, //08
+ { "ORA\t#*", 1, 0, 1, 0 }, //09
+ { "ASL", 0, 0, 1, 0 }, //0A
+ { "???", 0, 0, 1, 0 }, //0B
+ { "???", 0, 0, 1, 0 }, //0C
+ { "ORA\t*", 2, 0, 0, 0 }, //0D
+ { "ASL\t*", 2, 0, 0, 0 }, //0E
+ { "???", 0, 0, 1, 0 }, //0F
+ { "BPL\t$*", 1, 1, 1, 0 }, //10
+ { "ORA\t(*),Y", 1, 0, 0, 0 }, //11
+ { "???", 0, 0, 1, 0 }, //12
+ { "???", 0, 0, 1, 0 }, //13
+ { "???", 0, 0, 1, 0 }, //14
+ { "ORA\t*,X", 1, 0, 0, 0 }, //15
+ { "ASL\t*,X", 1, 0, 0, 0 }, //16
+ { "???", 0, 0, 1, 0 }, //17
+ { "CLC", 0, 0, 1, 0 }, //18
+ { "ORA\t*,Y", 2, 0, 0, 0 }, //19
+ { "???", 0, 0, 1, 0 }, //1A
+ { "???", 0, 0, 1, 0 }, //1B
+ { "???", 0, 0, 1, 0 }, //1C
+ { "ORA\t*,X", 2, 0, 0, 0 }, //1D
+ { "ASL\t*,X", 2, 0, 0, 0 }, //1E
+ { "???", 0, 0, 1, 0 }, //1F
+ { "JSR\t*", 2, 0, 0, 0 }, //20
+ { "AND\t(*,X)", 1, 0, 0, 0 }, //21
+ { "???", 0, 0, 1, 0 }, //22
+ { "???", 0, 0, 1, 0 }, //23
+ { "BIT\t*", 1, 0, 0, 0 }, //24
+ { "AND\t*", 1, 0, 0, 0 }, //25
+ { "ROL\t*", 1, 0, 0, 0 }, //26
+ { "???", 0, 0, 1, 0 }, //27
+ { "PLP", 0, 0, 1, 0 }, //28
+ { "AND\t#*", 1, 0, 1, 0 }, //29
+ { "ROL", 0, 0, 1, 0 }, //2A
+ { "???", 0, 0, 1, 0 }, //2B
+ { "BIT\t*", 2, 0, 0, 0 }, //2C
+ { "AND\t*", 2, 0, 0, 0 }, //2D
+ { "ROL\t*", 2, 0, 0, 0 }, //2E
+ { "???", 0, 0, 1, 0 }, //2F
+ { "BMI\t$*", 1, 1, 1, 0 }, //30
+ { "AND\t(*),Y", 1, 0, 0, 0 }, //31
+ { "???", 0, 0, 1, 0 }, //32
+ { "???", 0, 0, 1, 0 }, //33
+ { "???", 0, 0, 1, 0 }, //34
+ { "AND\t*,X", 1, 0, 0, 0 }, //35
+ { "ROL\t*,X", 1, 0, 0, 0 }, //36
+ { "???", 0, 0, 1, 0 }, //37
+ { "SEC", 0, 0, 1, 0 }, //38
+ { "AND\t*,Y", 2, 0, 0, 0 }, //39
+ { "???", 0, 0, 1, 0 }, //3A
+ { "???", 0, 0, 1, 0 }, //3B
+ { "???", 0, 0, 1, 0 }, //3C
+ { "AND\t*,X", 2, 0, 0, 0 }, //3D
+ { "ROL\t*,X", 2, 0, 0, 0 }, //3E
+ { "???", 0, 0, 1, 0 }, //3F
+ { "RTI", 0, 0, 1, 0 }, //40
+ { "EOR\t(*,X)", 1, 0, 0, 0 }, //41
+ { "???", 0, 0, 1, 0 }, //42
+ { "???", 0, 0, 1, 0 }, //43
+ { "???", 0, 0, 1, 0 }, //44
+ { "EOR\t*", 1, 0, 0, 0 }, //45
+ { "LSR\t*", 1, 0, 0, 0 }, //46
+ { "???", 0, 0, 1, 0 }, //47
+ { "PHA", 0, 0, 1, 0 }, //48
+ { "EOR\t#*", 1, 0, 1, 0 }, //49
+ { "LSR", 0, 0, 1, 0 }, //4A
+ { "???", 0, 0, 1, 0 }, //4B
+ { "JMP\t*", 2, 0, 0, 0 }, //4C
+ { "EOR\t*", 2, 0, 0, 0 }, //4D
+ { "LSR\t*", 2, 0, 0, 0 }, //4E
+ { "???", 0, 0, 1, 0 }, //4F
+ { "BVC\t$*", 1, 1, 1, 0 }, //50
+ { "EOR\t(*),Y", 1, 0, 0, 0 }, //51
+ { "???", 0, 0, 1, 0 }, //52
+ { "???", 0, 0, 1, 0 }, //53
+ { "???", 0, 0, 1, 0 }, //54
+ { "EOR\t*,X", 1, 0, 0, 0 }, //55
+ { "LSR\t*,X", 1, 0, 0, 0 }, //56
+ { "???", 0, 0, 1, 0 }, //57
+ { "CLI", 0, 0, 1, 0 }, //58
+ { "EOR\t*,Y", 2, 0, 0, 0 }, //59
+ { "???", 0, 0, 1, 0 }, //5A
+ { "???", 0, 0, 1, 0 }, //5B
+ { "???", 0, 0, 1, 0 }, //5C
+ { "EOR\t*,X", 2, 0, 0, 0 }, //5D
+ { "LSR\t*,X", 2, 0, 0, 0 }, //5E
+ { "???", 0, 0, 1, 0 }, //5F
+ { "RTS", 0, 0, 1, 0 }, //60
+ { "ADC\t(*,X)", 1, 0, 0, 0 }, //61
+ { "???", 0, 0, 1, 0 }, //62
+ { "???", 0, 0, 1, 0 }, //63
+ { "???", 0, 0, 1, 0 }, //64
+ { "ADC\t*", 1, 0, 0, 0 }, //65
+ { "ROR\t*", 1, 0, 0, 0 }, //66
+ { "???", 0, 0, 1, 0 }, //67
+ { "PLA", 0, 0, 1, 0 }, //68
+ { "ADC\t#*", 1, 0, 1, 0 }, //69
+ { "ROR", 0, 0, 1, 0 }, //6A
+ { "???", 0, 0, 1, 0 }, //6B
+ { "JMP\t(*)", 2, 0, 0, 0 }, //6C
+ { "ADC\t*", 2, 0, 0, 0 }, //6D
+ { "ROR\t*", 2, 0, 0, 0 }, //6E
+ { "???", 0, 0, 1, 0 }, //6F
+ { "BVS\t$*", 1, 1, 1, 0 }, //70
+ { "ADC\t(*),Y", 1, 0, 0, 0 }, //71
+ { "???", 0, 0, 1, 0 }, //72
+ { "???", 0, 0, 1, 0 }, //73
+ { "???", 0, 0, 1, 0 }, //74
+ { "ADC\t*,X", 1, 0, 0, 0 }, //75
+ { "ROR\t*,X", 1, 0, 0, 0 }, //76
+ { "???", 0, 0, 1, 0 }, //77
+ { "SEI", 0, 0, 1, 0 }, //78
+ { "ADC\t*,Y", 2, 0, 0, 0 }, //79
+ { "???", 0, 0, 1, 0 }, //7A
+ { "???", 0, 0, 1, 0 }, //7B
+ { "SKW", 1, 0, 1, 0 }, //7C
+ { "ADC\t*,X", 2, 0, 1, 0 }, //7D
+ { "ROR\t*,X", 2, 0, 1, 0 }, //7E
+ { "???", 0, 0, 1, 0 }, //7F
+ { "???", 0, 0, 1, 0 }, //80
+ { "STA\t(*,X)", 1, 0, 0, 1 }, //81
+ { "???", 0, 0, 1, 0 }, //82
+ { "???", 0, 0, 1, 0 }, //83
+ { "STY\t*", 1, 0, 0, 1 }, //84
+ { "STA\t*", 1, 0, 0, 1 }, //85
+ { "STX\t*", 1, 0, 0, 1 }, //86
+ { "???", 0, 0, 1, 0 }, //87
+ { "DEY", 0, 0, 1, 0 }, //88
+ { "???", 0, 0, 1, 0 }, //89
+ { "TXA", 0, 0, 1, 0 }, //8A
+ { "???", 0, 0, 1, 0 }, //8B
+ { "STY\t*", 2, 0, 0, 1 }, //8C
+ { "STA\t*", 2, 0, 0, 1 }, //8D
+ { "STX\t*", 2, 0, 0, 1 }, //8E
+ { "???", 0, 0, 1, 0 }, //8F
+ { "BCC\t$*", 1, 1, 1, 0 }, //90
+ { "STA\t(*),Y", 1, 0, 0, 1 }, //91
+ { "???", 0, 0, 1, 0 }, //92
+ { "???", 0, 0, 1, 0 }, //93
+ { "STY\t*,X", 1, 0, 0, 1 }, //94
+ { "STA\t*,X", 1, 0, 0, 1 }, //95
+ { "STX\t*,Y", 1, 0, 0, 1 }, //96
+ { "???", 0, 0, 1, 0 }, //97
+ { "TYA", 0, 0, 1, 0 }, //98
+ { "STA\t*,Y", 2, 0, 0, 1 }, //99
+ { "TXS", 0, 0, 1, 0 }, //9A
+ { "???", 0, 0, 1, 0 }, //9B
+ { "???", 0, 0, 1, 0 }, //9C
+ { "STA\t*,X", 2, 0, 0, 1 }, //9D
+ { "???", 0, 0, 1, 0 }, //9E
+ { "???", 0, 0, 1, 0 }, //9F
+ { "LDY\t#*", 1, 0, 1, 0 }, //A0
+ { "LDA\t(*,X)", 1, 0, 0, 0 }, //A1
+ { "LDX\t#*", 1, 0, 1, 0 }, //A2
+ { "???", 0, 0, 1, 0 }, //A3
+ { "LDY\t*", 1, 0, 0, 0 }, //A4
+ { "LDA\t*", 1, 0, 0, 0 }, //A5
+ { "LDX\t*", 1, 0, 0, 0 }, //A6
+ { "???", 0, 0, 1, 0 }, //A7
+ { "TAY", 0, 0, 1, 0 }, //A8
+ { "LDA\t#*", 1, 0, 1, 0 }, //A9
+ { "TAX", 0, 0, 1, 0 }, //AA
+ { "???", 0, 0, 1, 0 }, //AB
+ { "LDY\t*", 2, 0, 0, 0 }, //AC
+ { "LDA\t*", 2, 0, 0, 0 }, //AD
+ { "LDX\t*", 2, 0, 0, 0 }, //AE
+ { "???", 0, 0, 1, 0 }, //AF
+ { "BCS\t$*", 1, 1, 1, 0 }, //B0
+ { "LDA\t(*),Y", 1, 0, 0, 0 }, //B1
+ { "???", 0, 0, 1, 0 }, //B2
+ { "???", 0, 0, 1, 0 }, //B3
+ { "LDY\t*,X", 1, 0, 0, 0 }, //B4
+ { "LDA\t*,X", 1, 0, 0, 0 }, //B5
+ { "LDX\t*,Y", 1, 0, 0, 0 }, //B6
+ { "???", 0, 0, 1, 0 }, //B7
+ { "CLV", 0, 0, 1, 0 }, //B8
+ { "LDA\t*,Y", 2, 0, 0, 0 }, //B9
+ { "TSX", 0, 0, 1, 0 }, //BA
+ { "???", 0, 0, 1, 0 }, //BB
+ { "LDY\t*,X", 2, 0, 0, 0 }, //BC
+ { "LDA\t*,X", 2, 0, 0, 0 }, //BD
+ { "LDX\t*,Y", 2, 0, 0, 0 }, //BE
+ { "???", 0, 0, 1, 0 }, //BF
+ { "CPY\t#*", 1, 0, 1, 0 }, //C0
+ { "CMP\t(*,X)", 1, 0, 0, 0 }, //C1
+ { "???", 0, 0, 1, 0 }, //C2
+ { "???", 0, 0, 1, 0 }, //C3
+ { "CPY\t*", 1, 0, 0, 0 }, //C4
+ { "CMP\t*", 1, 0, 0, 0 }, //C5
+ { "DEC\t*", 1, 0, 0, 0 }, //C6
+ { "???", 0, 0, 1, 0 }, //C7
+ { "INY", 0, 0, 1, 0 }, //C8
+ { "CMP\t#*", 1, 0, 1, 0 }, //C9
+ { "DEX", 0, 0, 1, 0 }, //CA
+ { "???", 0, 0, 1, 0 }, //CB
+ { "CPY\t*", 2, 0, 0, 0 }, //CC
+ { "CMP\t*", 2, 0, 0, 0 }, //CD
+ { "DEC\t*", 2, 0, 0, 0 }, //CE
+ { "???", 0, 0, 1, 0 }, //CF
+ { "BNE\t$*", 1, 1, 1, 0 }, //D0
+ { "CMP\t(*),Y", 1, 0, 0, 0 }, //D1
+ { "???", 0, 0, 1, 0 }, //D2
+ { "???", 0, 0, 1, 0 }, //D3
+ { "???", 0, 0, 1, 0 }, //D4
+ { "CMP\t*,X", 1, 0, 0, 0 }, //D5
+ { "DEC\t*,X", 1, 0, 0, 0 }, //D6
+ { "???", 0, 0, 1, 0 }, //D7
+ { "CLD", 0, 0, 1, 0 }, //D8
+ { "CMP\t*,Y", 2, 0, 0, 0 }, //D9
+ { "???", 0, 0, 1, 0 }, //DA
+ { "???", 0, 0, 1, 0 }, //DB
+ { "???", 0, 0, 1, 0 }, //DC
+ { "CMP\t*,X", 2, 0, 0, 0 }, //DD
+ { "DEC\t*,X", 2, 0, 0, 0 }, //DE
+ { "???", 0, 0, 1, 0 }, //DF
+ { "CPX\t#*", 1, 0, 1, 0 }, //E0
+ { "SBC\t(*,X)", 1, 0, 0, 0 }, //E1
+ { "???", 0, 0, 1, 0 }, //E2
+ { "???", 0, 0, 1, 0 }, //E3
+ { "CPX\t*", 1, 0, 0, 0 }, //E4
+ { "SBC\t*", 1, 0, 0, 0 }, //E5
+ { "INC\t*", 1, 0, 0, 0 }, //E6
+ { "???", 0, 0, 1, 0 }, //E7
+ { "INX", 0, 0, 1, 0 }, //E8
+ { "SBC\t#*", 1, 0, 1, 0 }, //E9
+ { "NOP", 0, 0, 1, 0 }, //EA
+ { "???", 0, 0, 1, 0 }, //EB
+ { "CPX\t*", 2, 0, 0, 0 }, //EC
+ { "SBC\t*", 2, 0, 0, 0 }, //ED
+ { "INC\t*", 2, 0, 0, 0 }, //EE
+ { "???", 0, 0, 1, 0 }, //EF
+ { "BEQ\t$*", 1, 1, 1, 0 }, //F0
+ { "SBC\t(*),Y", 1, 0, 0, 0 }, //F1
+ { "???", 0, 0, 1, 0 }, //F2
+ { "???", 0, 0, 1, 0 }, //F3
+ { "???", 0, 0, 1, 0 }, //F4
+ { "SBC\t*,X", 1, 0, 0, 0 }, //F5
+ { "INC\t*,X", 1, 0, 0, 0 }, //F6
+ { "???", 0, 0, 1, 0 }, //F7
+ { "SED", 0, 0, 1, 0 }, //F8
+ { "SBC\t*,Y", 2, 0, 0, 0 }, //F9
+ { "???", 0, 0, 1, 0 }, //FA
+ { "???", 0, 0, 1, 0 }, //FB
+ { "???", 0, 0, 1, 0 }, //FC
+ { "SBC\t*,X", 2, 0, 0, 0 }, //FD
+ { "INC\t*,X", 2, 0, 0, 0 }, //FE
+ { "???", 0, 0, 1, 0 }, //FF
+ { "\0", 0, 0, 1, 0 }
+};
+
+typedef struct
+{
+ char* name;
+ WORD addr;
+} symtable_rec;
+
+symtable_rec symtable[] = {
+ { "NGFLAG", 0x0001 },
+ { "CASINI", 0x0002 },
+ { "CASINI+1", 0x0003 },
+ { "RAMLO", 0x0004 },
+ { "RAMLO+1", 0x0005 },
+ { "TRAMSZ", 0x0006 },
+ { "CMCMD", 0x0007 },
+ { "WARMST", 0x0008 },
+ { "BOOT", 0x0009 },
+ { "DOSVEC", 0x000A },
+ { "DOSVEC+1", 0x000B },
+ { "DOSINI", 0x000C },
+ { "DOSINI+1", 0x000D },
+ { "APPMHI", 0x000E },
+ { "APPMHI+1", 0x000F },
+ { "POKMSK", 0x0010 },
+ { "BRKKEY", 0x0011 },
+ { "RTCLOK", 0x0012 },
+ { "RTCLOK+1", 0x0013 },
+ { "RTCLOK+2", 0x0014 },
+ { "BUFADR", 0x0015 },
+ { "BUFADR+1", 0x0016 },
+ { "ICCOMT", 0x0017 },
+ { "DSKFMS", 0x0018 },
+ { "DSKFMS+1", 0x0019 },
+ { "DSKUTL", 0x001A },
+ { "DSKUTL+1", 0x001B },
+ { "ABUFPT", 0x001C },
+ { "ABUFPT+1", 0x001D },
+ { "ABUFPT+2", 0x001E },
+ { "ABUFPT+3", 0x001F },
+ { "ICHIDZ", 0x0020 },
+ { "ICDNOZ", 0x0021 },
+ { "ICCOMZ", 0x0022 },
+ { "ICSTAZ", 0x0023 },
+ { "ICBALZ", 0x0024 },
+ { "ICBAHZ", 0x0025 },
+ { "ICPTLZ", 0x0026 },
+ { "ICPTHZ", 0x0027 },
+ { "ICBLLZ", 0x0028 },
+ { "ICBLHZ", 0x0029 },
+ { "ICAX1Z", 0x002A },
+ { "ICAX2Z", 0x002B },
+ { "ICAX3Z", 0x002C },
+ { "ICAX4Z", 0x002D },
+ { "ICAX5Z", 0x002E },
+ { "ICAX6Z", 0x002F },
+ { "STATUS", 0x0030 },
+ { "CHKSUM", 0x0031 },
+ { "BUFRLO", 0x0032 },
+ { "BUFRHI", 0x0033 },
+ { "BFENLO", 0x0034 },
+ { "BFENHI", 0x0035 },
+ { "LTEMP", 0x0036 },
+ { "LTEMP+1", 0x0037 },
+ { "BUFRFL", 0x0038 },
+ { "RECVDN", 0x0039 },
+ { "XMTDON", 0x003A },
+ { "CHKSNT", 0x003B },
+ { "NOCKSM", 0x003C },
+ { "BPTR", 0x003D },
+ { "FTYPE", 0x003E },
+ { "FEOF", 0x003F },
+ { "FREQ", 0x0040 },
+ { "SOUNDR", 0x0041 },
+ { "CRITIC", 0x0042 },
+ { "FMSZPG", 0x0043 },
+ { "FMSZPG+1", 0x0044 },
+ { "FMSZPG+2", 0x0045 },
+ { "FMSZPG+3", 0x0046 },
+ { "FMSZPG+4", 0x0047 },
+ { "FMSZPG+5", 0x0048 },
+ { "FMSZPG+6", 0x0049 },
+ { "ZCHAIN", 0x004A },
+ { "ZCHAIN+1", 0x004B },
+ { "DSTAT", 0x004C },
+ { "ATRACT", 0x004D },
+ { "DRKMSK", 0x004E },
+ { "COLRSH", 0x004F },
+ { "TEMP", 0x0050 },
+ { "HOLD1", 0x0051 },
+ { "LMARGN", 0x0052 },
+ { "RMARGN", 0x0053 },
+ { "ROWCRS", 0x0054 },
+ { "COLCRS", 0x0055 },
+ { "COLCRS+1", 0x0056 },
+ { "DINDEX", 0x0057 },
+ { "SAVMSC", 0x0058 },
+ { "SAVMSC+1", 0x0059 },
+ { "OLDROW", 0x005A },
+ { "OLDCOL", 0x005B },
+ { "OLDCOL+1", 0x005C },
+ { "OLDCHR", 0x005D },
+ { "OLDADR", 0x005E },
+ { "OLDADR+1", 0x005F },
+ { "FKDEF", 0x0060 },
+ { "FKDEF+1", 0x0061 },
+ { "PALNTS", 0x0062 },
+ { "LOGCOL", 0x0063 },
+ { "ADRESS", 0x0064 },
+ { "ADRESS+1", 0x0065 },
+ { "MLTTMP", 0x0066 },
+ { "MLTTMP+1", 0x0067 },
+ { "SAVADR", 0x0068 },
+ { "SAVADR+1", 0x0069 },
+ { "RAMTOP", 0x006A },
+ { "BUFCNT", 0x006B },
+ { "BUFSTR", 0x006C },
+ { "BUFSTR+1", 0x006D },
+ { "BITMSK", 0x006E },
+ { "SHFAMT", 0x006F },
+ { "ROWAC", 0x0070 },
+ { "ROWAC+1", 0x0071 },
+ { "COLAC", 0x0072 },
+ { "COLAC+1", 0x0073 },
+ { "ENDPT", 0x0074 },
+ { "ENDPT+1", 0x0075 },
+ { "DELTAR", 0x0076 },
+ { "DELTAC", 0x0077 },
+ { "DELTAC+1", 0x0078 },
+ { "KEYDEF", 0x0079 },
+ { "KEYDEF+1", 0x007A },
+ { "SWPFLG", 0x007B },
+ { "HOLDCH", 0x007C },
+ { "INSDAT", 0x007D },
+ { "COUNTR", 0x007E },
+ { "COUNTR+1", 0x007F },
+ { "LOMEM", 0x0080 },
+ { "LOMEM+1", 0x0081 },
+ { "VNTP", 0x0082 },
+ { "VNTP+1", 0x0083 },
+ { "VNTD", 0x0084 },
+ { "VNTD+1", 0x0085 },
+ { "VVTP", 0x0086 },
+ { "VVTP+1", 0x0087 },
+ { "STMTAB", 0x0088 },
+ { "STMTAB+1", 0x0089 },
+ { "STMCUR", 0x008A },
+ { "STMCUR+1", 0x008B },
+ { "STARP", 0x008C },
+ { "STARP+1", 0x008D },
+ { "RUNSTK", 0x008E },
+ { "RUNSTK+1", 0x008F },
+ { "TOPSTK", 0x0090 },
+ { "TOPSTK+1", 0x0091 },
+ { "MEOLFLG", 0x0092 },
+ { "POKADR", 0x0095 },
+ { "POKADR+1", 0x0096 },
+ { "DATAD", 0x00B6 },
+ { "DATALN", 0x00B7 },
+ { "DATALN+1", 0x00B8 },
+ { "STOPLN", 0x00BA },
+ { "STOPLN+1", 0x00BB },
+ { "SAVCUR", 0x00BE },
+ { "IOCMD", 0x00C0 },
+ { "IODVC", 0x00C1 },
+ { "PROMPT", 0x00C2 },
+ { "ERRSAVE", 0x00C3 },
+ { "COLOUR", 0x00C8 },
+ { "PTABW", 0x00C9 },
+ { "LOADFLG", 0x00CA },
+ { "FR0", 0x00D4 },
+ { "FR0+1", 0x00D5 },
+ { "FR0+2", 0x00D6 },
+ { "FR0+3", 0x00D7 },
+ { "FR0+4", 0x00D8 },
+ { "FR0+5", 0x00D9 },
+ { "FRE", 0x00DA },
+ { "FRE+1", 0x00DB },
+ { "FRE+2", 0x00DC },
+ { "FRE+3", 0x00DD },
+ { "FRE+4", 0x00DE },
+ { "FRE+5", 0x00DF },
+ { "FR1", 0x00E0 },
+ { "FR1+1", 0x00E1 },
+ { "FR1+2", 0x00E2 },
+ { "FR1+3", 0x00E3 },
+ { "FR1+4", 0x00E4 },
+ { "FR1+5", 0x00E5 },
+ { "FR2", 0x00E6 },
+ { "FR2+1", 0x00E7 },
+ { "FR2+2", 0x00E8 },
+ { "FR2+3", 0x00E9 },
+ { "FR2+4", 0x00EA },
+ { "FR2+5", 0x00EB },
+ { "FRX", 0x00EC },
+ { "EEXP", 0x00ED },
+ { "NSIGN", 0x00EE },
+ { "ESIGN", 0x00EF },
+ { "FCHRFLG", 0x00F0 },
+ { "DIGRT", 0x00F1 },
+ { "CIX", 0x00F2 },
+ { "INBUFF", 0x00F3 },
+ { "INBUFF+1", 0x00F4 },
+ { "ZTEMP1", 0x00F5 },
+ { "ZTEMP1+1", 0x00F6 },
+ { "ZTEMP4", 0x00F7 },
+ { "ZTEMP4+1", 0x00F8 },
+ { "ZTEMP3", 0x00F9 },
+ { "ZTEMP3+1", 0x00FA },
+ { "RADFLG", 0x00FB },
+ { "FLPTR", 0x00FC },
+ { "FLPTR+1", 0x00FD },
+ { "FPTR2", 0x00FE },
+ { "FPTR2+1", 0x00FF },
+
+ { "VDSLST", 0x0200 },
+ { "VDSLST+1", 0x0201 },
+ { "VPRCED", 0x0202 },
+ { "VPRCED+1", 0x0203 },
+ { "VINTER", 0x0204 },
+ { "VINTER+1", 0x0205 },
+ { "VBREAK", 0x0206 },
+ { "VBREAK+1", 0x0207 },
+ { "VKEYBD", 0x0208 },
+ { "VKEYBD+1", 0x0209 },
+ { "VSERIN", 0x020A },
+ { "VSERIN+1", 0x020B },
+ { "VSEROR", 0x020C },
+ { "VSEROR+1", 0x020D },
+ { "VSEROC", 0x020E },
+ { "VSEROC+1", 0x020F },
+ { "VTIMR1", 0x0210 },
+ { "VTIMR1+1", 0x0211 },
+ { "VTIMR2", 0x0212 },
+ { "VTIMR2+1", 0x0213 },
+ { "VTIMR4", 0x0214 },
+ { "VTIMR4+1", 0x0215 },
+ { "VIMIRQ", 0x0216 },
+ { "VIMIRQ+1", 0x0217 },
+ { "CDTMV1", 0x0218 },
+ { "CDTMV1+1", 0x0219 },
+ { "CDTMV2", 0x021A },
+ { "CDTMV2+1", 0x021B },
+ { "CDTMV3", 0x021C },
+ { "CDTMV3+1", 0x021D },
+ { "CDTMV4", 0x021E },
+ { "CDTMV4+1", 0x021F },
+ { "CDTMV5", 0x0220 },
+ { "CDTMV5+1", 0x0221 },
+ { "VVBLKI", 0x0222 },
+ { "VVBLKI+1", 0x0223 },
+ { "VVBLKD", 0x0224 },
+ { "VVBLKD+1", 0x0225 },
+ { "CDTMA1", 0x0226 },
+ { "CDTMA1+1", 0x0227 },
+ { "CDTMA2", 0x0228 },
+ { "CDTMA2+1", 0x0229 },
+ { "CDTMF3", 0x022A },
+ { "SRTIMR", 0x022B },
+ { "CDTMF4", 0x022C },
+ { "INTEMP", 0x022D },
+ { "CDTMF5", 0x022E },
+ { "SDMCTL", 0x022F },
+ { "SDLSTL", 0x0230 },
+ { "SDLSTH", 0x0231 },
+ { "SSKCTL", 0x0232 },
+ { "SPARE", 0x0233 },
+ { "LPENH", 0x0234 },
+ { "LPENV", 0x0235 },
+ { "BRKKY", 0x0236 },
+ { "BRKKY+1", 0x0237 },
+ { "VPIRQ", 0x0238 },
+ { "VPIRQ+1", 0x0239 },
+ { "CDEVIC", 0x023A },
+ { "CCOMND", 0x023B },
+ { "CAUX1", 0x023C },
+ { "CAUX2", 0x023D },
+ { "TMPSIO", 0x023E },
+ { "ERRFLG", 0x023F },
+ { "DFLAGS", 0x0240 },
+ { "DBSECT", 0x0241 },
+ { "BOOTAD", 0x0242 },
+ { "BOOTAD+1", 0x0243 },
+ { "COLDST", 0x0244 },
+ { "RECLEN", 0x0245 },
+ { "DSKTIM", 0x0246 },
+ { "PDVMSK", 0x0247 },
+ { "SHPDVS", 0x0248 },
+ { "PDMSK", 0x0249 },
+ { "RELADR", 0x024A },
+ { "RELADR+1", 0x024B },
+ { "PPTMPA", 0x024C },
+ { "PPTMPX", 0x024D },
+ { "CHSALT", 0x026B },
+ { "VSFLAG", 0x026C },
+ { "KEYDIS", 0x026D },
+ { "FINE", 0x026E },
+ { "GPRIOR", 0x026F },
+ { "PADDL0", 0x0270 },
+ { "PADDL1", 0x0271 },
+ { "PADDL2", 0x0272 },
+ { "PADDL3", 0x0273 },
+ { "PADDL4", 0x0274 },
+ { "PADDL5", 0x0275 },
+ { "PADDL6", 0x0276 },
+ { "PADDL7", 0x0277 },
+ { "STICK0", 0x0278 },
+ { "STICK1", 0x0279 },
+ { "STICK2", 0x027A },
+ { "STICK3", 0x027B },
+ { "PTRIG0", 0x027C },
+ { "PTRIG1", 0x027D },
+ { "PTRIG2", 0x027E },
+ { "PTRIG3", 0x027F },
+ { "PTRIG4", 0x0280 },
+ { "PTRIG5", 0x0281 },
+ { "PTRIG6", 0x0282 },
+ { "PTRIG7", 0x0283 },
+ { "STRIG0", 0x0284 },
+ { "STRIG1", 0x0285 },
+ { "STRIG2", 0x0286 },
+ { "STRIG3", 0x0287 },
+ { "HIBYTE", 0x0288 },
+ { "WMODE", 0x0289 },
+ { "BLIM", 0x028A },
+ { "IMASK", 0x028B },
+ { "JVECK", 0x028C },
+ { "NEWADR", 0x028E },
+ { "TXTROW", 0x0290 },
+ { "TXTCOL", 0x0291 },
+ { "TXTCOL+1", 0x0292 },
+ { "TINDEX", 0x0293 },
+ { "TXTMSC", 0x0294 },
+ { "TXTMSC+1", 0x0295 },
+ { "TXTOLD", 0x0296 },
+ { "TXTOLD+1", 0x0297 },
+ { "TXTOLD+2", 0x0298 },
+ { "TXTOLD+3", 0x0299 },
+ { "TXTOLD+4", 0x029A },
+ { "TXTOLD+5", 0x029B },
+ { "CRETRY", 0x029C },
+ { "HOLD3", 0x029D },
+ { "SUBTMP", 0x029E },
+ { "HOLD2", 0x029F },
+ { "DMASK", 0x02A0 },
+ { "TMPLBT", 0x02A1 },
+ { "ESCFLG", 0x02A2 },
+ { "TABMAP", 0x02A3 },
+ { "TABMAP+1", 0x02A4 },
+ { "TABMAP+2", 0x02A5 },
+ { "TABMAP+3", 0x02A6 },
+ { "TABMAP+4", 0x02A7 },
+ { "TABMAP+5", 0x02A8 },
+ { "TABMAP+6", 0x02A9 },
+ { "TABMAP+7", 0x02AA },
+ { "TABMAP+8", 0x02AB },
+ { "TABMAP+9", 0x02AC },
+ { "TABMAP+A", 0x02AD },
+ { "TABMAP+B", 0x02AE },
+ { "TABMAP+C", 0x02AF },
+ { "TABMAP+D", 0x02B0 },
+ { "TABMAP+E", 0x02B1 },
+ { "LOGMAP", 0x02B2 },
+ { "LOGMAP+1", 0x02B3 },
+ { "LOGMAP+2", 0x02B4 },
+ { "LOGMAP+3", 0x02B5 },
+ { "INVFLG", 0x02B6 },
+ { "FILFLG", 0x02B7 },
+ { "TMPROW", 0x02B8 },
+ { "TMPCOL", 0x02B9 },
+ { "TMPCOL+1", 0x02BA },
+ { "SCRFLG", 0x02BB },
+ { "HOLD4", 0x02BC },
+ { "DRETRY", 0x02BD },
+ { "SHFLOC", 0x02BE },
+ { "BOTSCR", 0x02BF },
+ { "PCOLR0", 0x02C0 },
+ { "PCOLR1", 0x02C1 },
+ { "PCOLR2", 0x02C2 },
+ { "PCOLR3", 0x02C3 },
+ { "COLOR0", 0x02C4 },
+ { "COLOR1", 0x02C5 },
+ { "COLOR2", 0x02C6 },
+ { "COLOR3", 0x02C7 },
+ { "COLOR4", 0x02C8 },
+ { "RUNADR", 0x02C9 },
+ { "RUNADR+1", 0x02CA },
+ { "HIUSED", 0x02CB },
+ { "HIUSED+1", 0x02CC },
+ { "ZHIUSE", 0x02CD },
+ { "ZHIUSE+1", 0x02CE },
+ { "GBYTEA", 0x02CF },
+ { "GBYTEA+1", 0x02D0 },
+ { "LOADAD", 0x02D1 },
+ { "LOADAD+1", 0x02D2 },
+ { "ZLOADA", 0x02D3 },
+ { "ZLOADA+1", 0x02D4 },
+ { "DSCTLN", 0x02D5 },
+ { "DSCTLN+1", 0x02D6 },
+ { "ACMISR", 0x02D7 },
+ { "ACMISR+1", 0x02D8 },
+ { "KRPDER", 0x02D9 },
+ { "KEYREP", 0x02DA },
+ { "NOCLIK", 0x02DB },
+ { "HELPFG", 0x02DC },
+ { "DMASAV", 0x02DD },
+ { "PBPNT", 0x02DE },
+ { "PBUFSZ", 0x02DF },
+ { "RUNAD", 0x02E0 },
+ { "RUNAD+1", 0x02E1 },
+ { "INITAD", 0x02E2 },
+ { "INITAD+1", 0x02E3 },
+ { "RAMSIZ", 0x02E4 },
+ { "MEMTOP", 0x02E5 },
+ { "MEMTOP+1", 0x02E6 },
+ { "MEMLO", 0x02E7 },
+ { "MEMLO+1", 0x02E8 },
+ { "HNDLOD", 0x02E9 },
+ { "DVSTAT", 0x02EA },
+ { "DVSTAT+1", 0x02EB },
+ { "DVSTAT+2", 0x02EC },
+ { "DVSTAT+3", 0x02ED },
+ { "CBAUDL", 0x02EE },
+ { "CBAUDH", 0x02EF },
+ { "CRSINH", 0x02F0 },
+ { "KEYDEL", 0x02F1 },
+ { "CH1", 0x02F2 },
+ { "CHACT", 0x02F3 },
+ { "CHBAS", 0x02F4 },
+ { "NEWROW", 0x02F5 },
+ { "NEWCOL", 0x02F6 },
+ { "NEWCOL+1", 0x02F7 },
+ { "ROWINC", 0x02F8 },
+ { "COLINC", 0x02F9 },
+ { "CHAR", 0x02FA },
+ { "ATACHR", 0x02FB },
+ { "CH", 0x02FC },
+ { "FILDAT", 0x02FD },
+ { "DSPFLG", 0x02FE },
+ { "SSFLAG", 0x02FF },
+
+
+ { "DDEVIC", 0x0300 },
+ { "DUNIT", 0x0301 },
+ { "DCOMND", 0x0302 },
+ { "DSTATS", 0x0303 },
+ { "DBUFLO", 0x0304 },
+ { "DBUFHI", 0x0305 },
+ { "DTIMLO", 0x0306 },
+ { "DUNUSE", 0x0307 },
+ { "DBYTLO", 0x0308 },
+ { "DBYTHI", 0x0309 },
+ { "DAUX1", 0x030A },
+ { "DAUX2", 0x030B },
+ { "TIMER1", 0x030C },
+ { "TIMER1+1", 0x030D },
+ { "ADDCOR", 0x030E },
+ { "CASFLG", 0x030F },
+ { "TIMER2", 0x0310 },
+ { "TIMER2+1", 0x0311 },
+ { "TEMP1", 0x0312 },
+ { "TEMP1+1", 0x0313 },
+ { "TEMP2", 0x0314 },
+ { "TEMP3", 0x0315 },
+ { "SAVIO", 0x0316 },
+ { "TIMFLG", 0x0317 },
+ { "STACKP", 0x0318 },
+ { "TSTAT", 0x0319 },
+ { "HATABS", 0x031A }, /*HATABS 1-34*/
+ { "PUTBT1", 0x033D },
+ { "PUTBT2", 0x033E },
+ { "PUTBT3", 0x033F },
+ { "B0-ICHID", 0x0340 },
+ { "B0-ICDNO", 0x0341 },
+ { "B0-ICCOM", 0x0342 },
+ { "B0-ICSTA", 0x0343 },
+ { "B0-ICBAL", 0x0344 },
+ { "B0-ICBAH", 0x0345 },
+ { "B0-ICPTL", 0x0346 },
+ { "B0-ICPTH", 0x0347 },
+ { "B0-ICBLL", 0x0348 },
+ { "B0-ICBLH", 0x0349 },
+ { "B0-ICAX1", 0x034A },
+ { "B0-ICAX2", 0x034B },
+ { "B0-ICAX3", 0x034C },
+ { "B0-ICAX4", 0x034D },
+ { "B0-ICAX5", 0x034E },
+ { "B0-ICAX6", 0x034F },
+ { "B1-ICHID", 0x0350 },
+ { "B1-ICDNO", 0x0351 },
+ { "B1-ICCOM", 0x0352 },
+ { "B1-ICSTA", 0x0353 },
+ { "B1-ICBAL", 0x0354 },
+ { "B1-ICBAH", 0x0355 },
+ { "B1-ICPTL", 0x0356 },
+ { "B1-ICPTH", 0x0357 },
+ { "B1-ICBLL", 0x0358 },
+ { "B1-ICBLH", 0x0359 },
+ { "B1-ICAX1", 0x035A },
+ { "B1-ICAX2", 0x035B },
+ { "B1-ICAX3", 0x035C },
+ { "B1-ICAX4", 0x035D },
+ { "B1-ICAX5", 0x035E },
+ { "B1-ICAX6", 0x035F },
+ { "B2-ICHID", 0x0360 },
+ { "B2-ICDNO", 0x0361 },
+ { "B2-ICCOM", 0x0362 },
+ { "B2-ICSTA", 0x0363 },
+ { "B2-ICBAL", 0x0364 },
+ { "B2-ICBAH", 0x0365 },
+ { "B2-ICPTL", 0x0366 },
+ { "B2-ICPTH", 0x0367 },
+ { "B2-ICBLL", 0x0368 },
+ { "B2-ICBLH", 0x0369 },
+ { "B2-ICAX1", 0x036A },
+ { "B2-ICAX2", 0x036B },
+ { "B2-ICAX3", 0x036C },
+ { "B2-ICAX4", 0x036D },
+ { "B2-ICAX5", 0x036E },
+ { "B2-ICAX6", 0x036F },
+ { "B3-ICHID", 0x0370 },
+ { "B3-ICDNO", 0x0371 },
+ { "B3-ICCOM", 0x0372 },
+ { "B3-ICSTA", 0x0373 },
+ { "B3-ICBAL", 0x0374 },
+ { "B3-ICBAH", 0x0375 },
+ { "B3-ICPTL", 0x0376 },
+ { "B3-ICPTH", 0x0377 },
+ { "B3-ICBLL", 0x0378 },
+ { "B3-ICBLH", 0x0379 },
+ { "B3-ICAX1", 0x037A },
+ { "B3-ICAX2", 0x037B },
+ { "B3-ICAX3", 0x037C },
+ { "B3-ICAX4", 0x037D },
+ { "B3-ICAX5", 0x037E },
+ { "B3-ICAX6", 0x037F },
+ { "B4-ICHID", 0x0380 },
+ { "B4-ICDNO", 0x0381 },
+ { "B4-ICCOM", 0x0382 },
+ { "B4-ICSTA", 0x0383 },
+ { "B4-ICBAL", 0x0384 },
+ { "B4-ICBAH", 0x0385 },
+ { "B4-ICPTL", 0x0386 },
+ { "B4-ICPTH", 0x0387 },
+ { "B4-ICBLL", 0x0388 },
+ { "B4-ICBLH", 0x0389 },
+ { "B4-ICAX1", 0x038A },
+ { "B4-ICAX2", 0x038B },
+ { "B4-ICAX3", 0x038C },
+ { "B4-ICAX4", 0x038D },
+ { "B4-ICAX5", 0x038E },
+ { "B4-ICAX6", 0x038F },
+ { "B5-ICHID", 0x0390 },
+ { "B5-ICDNO", 0x0391 },
+ { "B5-ICCOM", 0x0392 },
+ { "B5-ICSTA", 0x0393 },
+ { "B5-ICBAL", 0x0394 },
+ { "B5-ICBAH", 0x0395 },
+ { "B5-ICPTL", 0x0396 },
+ { "B5-ICPTH", 0x0397 },
+ { "B5-ICBLL", 0x0398 },
+ { "B5-ICBLH", 0x0399 },
+ { "B5-ICAX1", 0x039A },
+ { "B5-ICAX2", 0x039B },
+ { "B5-ICAX3", 0x039C },
+ { "B5-ICAX4", 0x039D },
+ { "B5-ICAX5", 0x039E },
+ { "B5-ICAX6", 0x039F },
+ { "B6-ICHID", 0x03A0 },
+ { "B6-ICDNO", 0x03A1 },
+ { "B6-ICCOM", 0x03A2 },
+ { "B6-ICSTA", 0x03A3 },
+ { "B6-ICBAL", 0x03A4 },
+ { "B6-ICBAH", 0x03A5 },
+ { "B6-ICPTL", 0x03A6 },
+ { "B6-ICPTH", 0x03A7 },
+ { "B6-ICBLL", 0x03A8 },
+ { "B6-ICBLH", 0x03A9 },
+ { "B6-ICAX1", 0x03AA },
+ { "B6-ICAX2", 0x03AB },
+ { "B6-ICAX3", 0x03AC },
+ { "B6-ICAX4", 0x03AD },
+ { "B6-ICAX5", 0x03AE },
+ { "B6-ICAX6", 0x03AF },
+ { "B7-ICHID", 0x03B0 },
+ { "B7-ICDNO", 0x03B1 },
+ { "B7-ICCOM", 0x03B2 },
+ { "B7-ICSTA", 0x03B3 },
+ { "B7-ICBAL", 0x03B4 },
+ { "B7-ICBAH", 0x03B5 },
+ { "B7-ICPTL", 0x03B6 },
+ { "B7-ICPTH", 0x03B7 },
+ { "B7-ICBLL", 0x03B8 },
+ { "B7-ICBLH", 0x03B9 },
+ { "B7-ICAX1", 0x03BA },
+ { "B7-ICAX2", 0x03BB },
+ { "B7-ICAX3", 0x03BC },
+ { "B7-ICAX4", 0x03BD },
+ { "B7-ICAX5", 0x03BE },
+ { "B7-ICAX6", 0x03BF },
+ { "PRNBUF", 0x03C0 }, /*PRNBUF 1-39 */
+ { "SUPERF", 0x03E8 },
+ { "CKEY", 0x03E9 },
+ { "CASSBT", 0x03EA },
+ { "CARTCK", 0x03EB },
+ { "DERRF", 0x03EC },
+ { "ACMVAR", 0x03ED }, /*ACMVAR 1-10*/
+ { "BASICF", 0x03F8 },
+ { "MINTLK", 0x03F9 },
+ { "GINTLK", 0x03FA },
+ { "CHLINK", 0x03FB },
+ { "CHLINK+1", 0x03FC },
+ { "CASBUF", 0x03FD },
+
+ { "M0PF", 0xD000 },
+ { "HPOSP0", 0xD000 },
+ { "M1PF", 0xD001 },
+ { "HPOSP1", 0xD001 },
+ { "M2PF", 0xD002 },
+ { "HPOSP2", 0xD002 },
+ { "M3PF", 0xD003 },
+ { "HPOSP3", 0xD003 },
+ { "P0PF", 0xD004 },
+ { "HPOSM0", 0xD004 },
+ { "P1PF", 0xD005 },
+ { "HPOSM1", 0xD005 },
+ { "P2PF", 0xD006 },
+ { "HPOSM2", 0xD006 },
+ { "P3PF", 0xD007 },
+ { "HPOSM3", 0xD007 },
+ { "M0PL", 0xD008 },
+ { "SIZEP0", 0xD008 },
+ { "M1PL", 0xD009 },
+ { "SIZEP1", 0xD009 },
+ { "M2PL", 0xD00A },
+ { "HPOSP2", 0xD00A },
+ { "M3PL", 0xD00B },
+ { "HPOSP3", 0xD00B },
+ { "P0PL", 0xD00C },
+ { "SIZEM", 0xD00C },
+ { "P1PL", 0xD00D },
+ { "GRAFP0", 0xD00D },
+ { "P2PL", 0xD00E },
+ { "GRAFP1", 0xD00E },
+ { "P3PL", 0xD00F },
+ { "GRAFP2", 0xD00F },
+ { "TRIG0", 0xD010 },
+ { "GRAFP3", 0xD010 },
+ { "TRIG1", 0xD011 },
+ { "GRAFM", 0xD011 },
+ { "TRIG2", 0xD012 },
+ { "COLPM0", 0xD012 },
+ { "TRIG3", 0xD013 },
+ { "COLPM1", 0xD013 },
+ { "PAL", 0xD014 },
+ { "COLPM2", 0xD014 },
+ { "COLPM3", 0xD015 },
+ { "COLPF0", 0xD016 },
+ { "COLPF1", 0xD017 },
+ { "COLPF2", 0xD018 },
+ { "COLPF3", 0xD019 },
+ { "COLBK", 0xD01A },
+ { "PRIOR", 0xD01B },
+ { "VDELAY", 0xD01C },
+ { "GRACTL", 0xD01D },
+ { "HITCLR", 0xD01E },
+ { "CONSOL", 0xD01F },
+
+ { "POT0", 0xD200 },
+ { "AUDF1", 0xD200 },
+ { "POT1", 0xD201 },
+ { "AUDC1", 0xD201 },
+ { "POT2", 0xD202 },
+ { "AUDF2", 0xD202 },
+ { "POT3", 0xD203 },
+ { "AUDC2", 0xD203 },
+ { "POT4", 0xD204 },
+ { "AUDF3", 0xD204 },
+ { "POT5", 0xD205 },
+ { "AUDC3", 0xD205 },
+ { "POT6", 0xD206 },
+ { "AUDF4", 0xD206 },
+ { "POT7", 0xD207 },
+ { "AUDC4", 0xD207 },
+ { "ALLPOT", 0xD208 },
+ { "AUDCTL", 0xD208 },
+ { "KBCODE", 0xD209 },
+ { "STIMER", 0xD209 },
+ { "RANDOM", 0xD20A },
+ { "SKREST", 0xD20A },
+ { "POTGO", 0xD20B },
+ { "SERIN", 0xD20D },
+ { "SEROUT", 0xD20D },
+ { "IRQST", 0xD20E },
+ { "IRQEN", 0xD20E },
+ { "SKSTAT", 0xD20F },
+ { "SKCTL", 0xD20F },
+
+ { "PORTA", 0xD300 },
+ { "PORTB", 0xD301 },
+ { "PACTL", 0xD302 },
+ { "PBCTL", 0xD303 },
+
+ { "DMACTL", 0xD400 },
+ { "CHACTL", 0xD401 },
+ { "DLISTL", 0xD402 },
+ { "DLISTH", 0xD403 },
+ { "HSCROL", 0xD404 },
+ { "VSCROL", 0xD405 },
+ { "PMBASE", 0xD407 },
+ { "CHBASE", 0xD409 },
+ { "WSYNC", 0xD40A },
+ { "VCOUNT", 0xD40B },
+ { "PENH", 0xD40C },
+ { "PENL", 0xD40D },
+ { "NMIEN", 0xD40E },
+ { "NMIST", 0xD40F },
+ { "NMIRES", 0xD40F },
+
+ { "AFP", 0xD800 },
+ { "FASC", 0xD8E6 },
+ { "IFP", 0xD9AA },
+ { "FPI", 0xD9D2 },
+ { "ZPRO", 0xDA44 },
+ { "ZF1", 0xDA46 },
+ { "FSUB", 0xDA60 },
+ { "FADD", 0xDA66 },
+ { "FMUL", 0xDADB },
+ { "FDIV", 0xDB28 },
+ { "PLYEVL", 0xDD40 },
+ { "FLD0R", 0xDD89 },
+ { "FLD0R", 0xDD8D },
+ { "FLD1R", 0xDD98 },
+ { "FLD1P", 0xDD9C },
+ { "FST0R", 0xDDA7 },
+ { "FST0P", 0xDDAB },
+ { "FMOVE", 0xDDB6 },
+ { "EXP", 0xDDC0 },
+ { "EXP10", 0xDDCC },
+ { "LOG", 0xDECD },
+ { "LOG10", 0xDED1 },
+
+ { "DSKINV", 0xE453 },
+ { "CIOV", 0xE456 },
+ { "SIOV", 0xE459 },
+ { "SETVBV", 0xE45C },
+ { "SYSVBV", 0xE45F },
+ { "XITVBV", 0xE462 },
+ { "SIOINV", 0xE465 },
+ { "SENDEV", 0xE468 },
+ { "INTINV", 0xE46B },
+ { "CIOINV", 0xE46E },
+ { "SELFSV", 0xE471 },
+ { "WARMSV", 0xE474 },
+ { "COLDSV", 0xE477 },
+ { "RBLOKV", 0xE47A },
+ { "CSOPIV", 0xE47D },
+ { "PUPDIV", 0xE480 },
+ { "SELFTSV", 0xE483 },
+ { "PENTV", 0xE486 },
+ { "PHUNLV", 0xE489 },
+ { "PHINIV", 0xE48C },
+ { "GPDVV", 0xE48F }
+};
+
+int symtable_size=sizeof(symtable)/sizeof(symtable_rec);
+
+
+void OutputBlockDiss( BYTE* pbtBlock, WORD wOffset, WORD wEnd )
+{
+ WORD wPC_curr = 0;
+ WORD wPC_end = wEnd - wOffset;
+ WORD wInsLen = 0;
+ WORD wInsCode = 0;
+ BOOL bInsIncomplete = FALSE;
+
+ while ( wPC_curr <= wPC_end )
+ {
+ wInsCode = pbtBlock[ wPC_curr ];
+ wInsLen = instable[ wInsCode ].length;
+
+ printf("%04X ", wPC_curr + wOffset );
+
+ if ( wPC_curr + wInsLen > wPC_end )
+ {
+ wInsLen = wPC_end - wPC_curr;
+ bInsIncomplete = TRUE;
+ }
+
+ for ( int i = 0; i <= wInsLen; i++ )
+ {
+ printf("%02X ", pbtBlock[ wPC_curr + i ] );
+ }
+
+ for ( int i = 0; i < ( 3 - wInsLen ); i++ )
+ {
+ printf(" ");
+ }
+
+ char obuf[256];
+ char *p;
+
+ char* szSymbol = NULL;
+
+ strcpy( obuf, instable[ wInsCode ].instruct );
+
+ for (p = obuf; *p; p++)
+ {
+ if (*p == '*')
+ {
+ *p = '\0';
+ p++;
+ break;
+ }
+ }
+
+ if ( !instable[ pbtBlock[ wPC_curr ] ].length )
+ {
+ printf( "%s\n", instable[pbtBlock[wPC_curr]].instruct );
+ }
+ else
+ {
+ if ( bInsIncomplete )
+ {
+ printf( "!!!\n" );
+ break;
+ }
+
+ printf( "%s",obuf );
+
+ if ( instable[wInsCode].branch )
+ {
+ int uPdata = (int) (signed char)pbtBlock[ wPC_curr + 1 ];
+ printf( "%04X", wPC_curr + 2 + uPdata + wOffset );
+ }
+ else
+ {
+ if ( instable[wInsCode].length == 1 )
+ {
+ WORD wAddr = (BYTE)pbtBlock[ wPC_curr + 1 ];
+
+ if ( !instable[ wInsCode ].immed )
+ szSymbol = SymbolFind( wAddr, instable[ wInsCode ].write ? TRUE : FALSE );
+
+ printf( "$%02X", wAddr );
+
+ }
+ else if ( instable[wInsCode].length == 2 )
+ {
+ WORD wAddr = (WORD) pbtBlock[ wPC_curr + 1 ] |
+ (WORD)( pbtBlock[ wPC_curr + 2 ] << 8 );
+
+ if ( !instable[ wInsCode ].immed )
+ szSymbol = SymbolFind( wAddr, instable[ wInsCode ].write ? TRUE : FALSE );
+
+ printf( "$%04X", wAddr );
+
+ }
+ }
+
+ if ( szSymbol )
+ printf("%s\t;%s\n", p, szSymbol );
+ else
+ printf("%s\n",p);
+ }
+
+ wPC_curr += ( wInsLen + 1 );
+ }
+
+}
+
+char* SymbolFind( WORD addr, BOOL bWrite )
+{
+ int lo = 0;
+ int mi = 0;
+ int hi = symtable_size - 1;
+
+ while ( lo < hi )
+ {
+ mi = ( lo + hi ) / 2;
+
+ if ( symtable[ mi ].addr == addr )
+ {
+ break;
+ }
+ else
+ {
+ if ( symtable[ mi ].addr > addr )
+ hi=mi;
+ else
+ lo=mi+1;
+ }
+ }
+
+ if ( symtable[mi].addr == addr )
+ {
+ if ( mi>0 && symtable[mi-1].addr == addr )
+ {
+ mi--;
+ }
+
+ if ( bWrite )
+ {
+ if ( mi < symtable_size - 1 )
+ if ( symtable[ mi + 1 ].addr == addr )
+ mi++;
+ }
+
+ return symtable[ mi ].name;
+ }
+
+ else
+ return NULL;
+}
+
+
+
diff --git a/jindroush/lib/autil.cpp b/jindroush/lib/autil.cpp
new file mode 100644
index 0000000..3afc782
--- /dev/null
+++ b/jindroush/lib/autil.cpp
@@ -0,0 +1,139 @@
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+//
+
+#include "autil.h"
+
+void Peecize( char* szPC, char* szAtari );
+
+//converts 8+3 Atari fname to it's PC equivalent
+void ADos2MsDos( char* szMsDos, char* szADos )
+{
+ char szName[ 9 ];
+ strncpy( szName, szADos, 8 );
+ szName[ 8 ] = '\0';
+
+ char szExt[ 4 ];
+ strncpy( szExt, szADos + 8, 3 );
+ szExt[ 3 ] = '\0';
+
+ Peecize( szName, szName );
+ Peecize( szExt, szExt );
+
+ if ( !*szName )
+ strcpy( szName, "out" );
+
+ strcpy( szMsDos, szName );
+
+ if ( *szExt )
+ {
+ strcat( szMsDos, "." );
+ strcat( szMsDos, szExt );
+ }
+}
+
+//kind of 'good-for-dos' filter
+void Peecize( char* szPC, char* szAtari )
+{
+ int iLen = strlen( szAtari );
+
+ while( iLen-- )
+ {
+ //filter off the inverse chars
+ char c = *( szAtari++ ) & 0x7F;
+
+ //filter spaces
+ if ( c == ' ' )
+ continue;
+
+ //filter unprintables
+ if ( !isprint( c ) )
+ c = '_';
+
+ //filter other 'ugly' characters :)
+ switch( c )
+ {
+ case '*':
+ case ':':
+ case '\"':
+ case ',':
+ case '.':
+ case '|':
+ case '?':
+ case '/':
+ case '\\':
+ c = '_';
+ break;
+ }
+
+ *( szPC++ ) = c;
+ }
+
+ *szPC = '\0';
+}
+
+
+//converts any Atari name to it's PC equivalent
+void GuessBestFnameFromAtari( char* szDest, char* szSrc, char* szExt )
+{
+ char szTemp[ 255 ];
+ Peecize( szTemp, szSrc );
+ GuessBestFnameFromPC( szDest, szTemp, szExt );
+}
+
+//changes file extension
+void GuessBestFnameFromPC( char* szDest, char* szSrc, char* szExt, char* szAdd )
+{
+ char szTemp[ 255 ];
+
+ char szGoodSrc[ 255 ];
+
+ _fixpath( szSrc, szGoodSrc );
+
+ char* szSl = strrchr( szGoodSrc, '/' );
+
+ if ( szSl )
+ strcpy( szTemp, szSl + 1 );
+ else
+ strcpy( szTemp, szGoodSrc );
+
+ char* szDot = strrchr( szTemp, '.' );
+
+ if ( szDot )
+ *szDot = '\0';
+
+ if ( !strlen( szTemp ) )
+ strcpy( szTemp, "out" );
+
+ strcpy( szDest, szTemp );
+
+ if ( szAdd )
+ strcat( szDest, szAdd );
+
+ strcat( szDest, "." );
+ strcat( szDest, szExt );
+}
+
+//is memory block empty?
+BOOL IsBlockEmpty( BYTE* p, int iLen )
+{
+ while( iLen-- )
+ {
+ if ( *( p++ ) )
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
diff --git a/jindroush/lib/cdisk.cpp b/jindroush/lib/cdisk.cpp
new file mode 100644
index 0000000..74ee067
--- /dev/null
+++ b/jindroush/lib/cdisk.cpp
@@ -0,0 +1,276 @@
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+//
+
+#include "cdisk.h"
+#include "cdsk_atr.h"
+#include "cdsk_xfd.h"
+#include "cdsk_dcm.h"
+#include "cdsk_scp.h"
+
+
+CDisk::CDisk()
+{
+ m_bOpened = FALSE;
+ m_pbtMemory = NULL;
+
+ #ifdef _MEMORY_DUMP_
+ printf( "CDisk constructed: %08X\n", this );
+ #endif
+}
+
+CDisk::~CDisk()
+{
+ if ( m_pbtMemory )
+ {
+ delete [] m_pbtMemory;
+ m_pbtMemory = NULL;
+ }
+
+ #ifdef _MEMORY_DUMP_
+ printf( "CDisk destructed: %08X\n", this );
+ #endif
+}
+
+BOOL CDisk::Duplicate( CDisk* pDisk )
+{
+ if ( !Format( & ( pDisk->m_geometry ) ) )
+ return FALSE;
+
+ memcpy( m_pbtMemory, pDisk->m_pbtMemory, pDisk->m_iAllocated );
+ return TRUE;
+}
+
+BOOL CDisk::Format( DISK_GEOMETRY* pgeo )
+{
+ int iSectors = pgeo->iSides * pgeo->iTracks * pgeo->iSectorsPerTrack;
+
+ if ( m_pbtMemory )
+ delete [] m_pbtMemory;
+
+ m_iAllocated = iSectors * pgeo->iBytesPerSector;
+ m_pbtMemory = new BYTE [ m_iAllocated ];
+
+ if ( !m_pbtMemory )
+ {
+ sprintf( m_szLastError, "DISK: Can't format - Not enough memory!" );
+ return FALSE;
+ }
+
+ memset( m_pbtMemory, 0, m_iAllocated );
+
+ m_geometry.iSides = pgeo->iSides;
+ m_geometry.iTracks = pgeo->iTracks;
+ m_geometry.iSectorsPerTrack = pgeo->iSectorsPerTrack;
+ m_geometry.iBytesPerSector = pgeo->iBytesPerSector;
+ m_geometry.iSectors = iSectors;
+
+ return TRUE;
+}
+
+BOOL CDisk::ReadSector( void* pBuf, int iStartSec )
+{
+ if ( iStartSec && ( iStartSec <= m_geometry.iSectors ) )
+ memcpy( pBuf, m_pbtMemory + ( iStartSec - 1 ) * m_geometry.iBytesPerSector, m_geometry.iBytesPerSector );
+ else
+ {
+ sprintf( m_szLastError, "DISK: Reading non-existent sector: %04X", iStartSec );
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+BOOL CDisk::ReadSectors( void* pBuf, int iStartSec, int iSecs )
+{
+ while( iSecs )
+ {
+ if ( !ReadSector( pBuf, iStartSec ) )
+ return FALSE;
+
+ iStartSec++;
+ iSecs--;
+ pBuf = (BYTE*)pBuf + m_geometry.iBytesPerSector;
+ }
+
+ return TRUE;
+}
+
+BOOL CDisk::WriteSector( int iStartSec, void* pBuf )
+{
+ //printf( " ws: %d ", iStartSec );
+ if ( iStartSec && ( iStartSec <= m_geometry.iSectors ) )
+ memcpy( m_pbtMemory + ( iStartSec - 1 ) * m_geometry.iBytesPerSector, pBuf, m_geometry.iBytesPerSector );
+ else
+ {
+ sprintf( m_szLastError, "DISK: Writing non-existent sector: %04X", iStartSec );
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+void GuessClassicSizes( int iSectors, int iSectorSize, DISK_GEOMETRY* pGeometry )
+{
+ pGeometry->iSides = 1;
+ pGeometry->iBytesPerSector = iSectorSize;
+
+ pGeometry->iTracks = 1;
+ pGeometry->iSectorsPerTrack = iSectors;
+
+ switch( iSectors )
+ {
+ case 720:
+ switch( iSectorSize )
+ {
+ case 0x80:
+ pGeometry->iTracks = 40;
+ pGeometry->iSectorsPerTrack = 18;
+ break;
+
+ case 0x100:
+ pGeometry->iTracks = 40;
+ pGeometry->iSectorsPerTrack = 18;
+ break;
+ }
+ break;
+
+ case 1040:
+ pGeometry->iTracks = 40;
+ pGeometry->iSectorsPerTrack = 26;
+ break;
+
+ }
+
+}
+
+//returns ptr to disk type name
+char* GetDiskTypeName( DISK_TYPE disktype )
+{
+ switch( disktype )
+ {
+ case DISK_XFD:
+ return "XFD";
+
+ case DISK_ATR:
+ return "ATR";
+
+ case DISK_XFDb:
+ return "XFDb";
+
+ case DISK_ATRb:
+ return "ATRb";
+
+ case DISK_DCM:
+ return "DCM";
+
+ case DISK_SCP:
+ return "SCP";
+
+ default:
+ return "None";
+ }
+}
+
+//returns ptr to disk type extension
+char* GetDiskTypeExt( DISK_TYPE disktype )
+{
+ switch( disktype )
+ {
+ case DISK_XFD:
+ case DISK_XFDb:
+ return "xfd";
+
+ case DISK_ATR:
+ case DISK_ATRb:
+ return "atr";
+
+ case DISK_DCM:
+ return "dcm";
+
+ case DISK_SCP:
+ return "scp";
+
+ default:
+ return "xxx";
+ }
+}
+
+DISKINIT_RETCODE InitializeDisk( CDisk** ppDisk, DISK_TYPE disktype, char* szFname, BOOL bVerbose, BOOL bRepair, BOOL bRepairAuto )
+{
+ switch( disktype )
+ {
+ case DISK_ATR:
+ *ppDisk = new CAtr();
+ break;
+
+ case DISK_SCP:
+ *ppDisk = new CScp();
+ break;
+
+ case DISK_DCM:
+ *ppDisk = new CDcm();
+ break;
+
+ case DISK_XFD:
+ *ppDisk = new CXfd();
+ break;
+
+ default:
+ if ( bVerbose )
+ fprintf( stderr, "Invalid disk type specified!\n" );
+ return DI_RET_CANT_CONTINUE;
+ }
+
+ if ( !*ppDisk )
+ {
+ if ( bVerbose )
+ fprintf( stderr, "Can't initialize disk driver!\n" );
+ return DI_RET_CONTINUE;
+ }
+
+ if ( !(*ppDisk)->Load( szFname, bRepair, bRepairAuto ) )
+ {
+ int iError = (*ppDisk)->GetErrorCode();
+
+ DISKINIT_RETCODE ret = DI_RET_CONTINUE;
+
+ switch( iError )
+ {
+ case CATR_FORMAT_VIOLATED:
+ case CXFD_FORMAT_VIOLATED:
+ case CDISK_ERROR_CANT_OPEN:
+ case CDCM_FORMAT_VIOLATED:
+ case CSCP_FORMAT_VIOLATED:
+ ret = DI_RET_CANT_CONTINUE;
+ break;
+ }
+
+ if ( bVerbose || ( ret == DI_RET_CANT_CONTINUE ) )
+ {
+ printf( "Input file '%s' ", szFname );
+ printf( "(%s)\n", GetDiskTypeName( disktype ) );
+ printf( "Load failed because:\n%s\n", (*ppDisk)->GetLastError() );
+ }
+ if ( ret != DI_RET_OK )
+ {
+ delete *ppDisk;
+ return ret;
+ }
+ }
+
+ return DI_RET_OK;
+}
+
+
diff --git a/jindroush/lib/cdsk.cpp b/jindroush/lib/cdsk.cpp
new file mode 100644
index 0000000..cc905f6
--- /dev/null
+++ b/jindroush/lib/cdsk.cpp
@@ -0,0 +1,115 @@
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+//
+
+#include "cdsk.h"
+
+CDisk::CDisk()
+{
+ m_bHasData = FALSE;
+ m_pbtMemory = NULL;
+
+ m_iMaxSectorWritten = 0;
+
+ #ifdef _MEMORY_DUMP_
+ printf( "CDisk constructed: %p\n", this );
+ #endif
+}
+
+CDisk::~CDisk()
+{
+ if ( m_pbtMemory )
+ {
+ delete [] m_pbtMemory;
+ m_pbtMemory = NULL;
+ }
+
+ #ifdef _MEMORY_DUMP_
+ printf( "CDisk destructed: %p\n", this );
+ #endif
+}
+
+BOOL CDisk::Duplicate( CDisk* pDisk, DISK_GEOMETRY* pGeoForced )
+{
+ DISK_GEOMETRY* pGeo = pGeoForced;
+ if ( !pGeo )
+ pGeo = &( pDisk->m_geometry );
+
+ if ( !Format( pGeo ) )
+ return FALSE;
+
+ memcpy( m_pbtMemory, pDisk->m_pbtMemory, pDisk->m_iAllocated );
+ m_iMaxSectorWritten = pDisk->m_iMaxSectorWritten;
+ return TRUE;
+}
+
+BOOL CDisk::Format( DISK_GEOMETRY* pgeo )
+{
+ m_iMaxSectorWritten = 0;
+
+ int iSectors = pgeo->iSides * pgeo->iTracks * pgeo->iSectorsPerTrack;
+
+ if ( m_pbtMemory )
+ delete [] m_pbtMemory;
+
+ m_iAllocated = iSectors * pgeo->iBytesPerSector;
+ m_pbtMemory = new BYTE [ m_iAllocated ];
+
+ if ( !m_pbtMemory )
+ {
+ sprintf( m_szLastError, "DISK: Can't format - Not enough memory!" );
+ return FALSE;
+ }
+
+ memset( m_pbtMemory, 0, m_iAllocated );
+
+ m_geometry.iSides = pgeo->iSides;
+ m_geometry.iTracks = pgeo->iTracks;
+ m_geometry.iSectorsPerTrack = pgeo->iSectorsPerTrack;
+ m_geometry.iBytesPerSector = pgeo->iBytesPerSector;
+ m_geometry.iSectors = iSectors;
+
+ return TRUE;
+}
+
+BOOL CDisk::ReadSector( void* pBuf, int iStartSec )
+{
+ if ( iStartSec && ( iStartSec <= m_geometry.iSectors ) )
+ memcpy( pBuf, m_pbtMemory + ( iStartSec - 1 ) * m_geometry.iBytesPerSector, m_geometry.iBytesPerSector );
+ else
+ {
+ sprintf( m_szLastError, "DISK: Reading non-existent sector: %04X", iStartSec );
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+BOOL CDisk::WriteSector( int iStartSec, void* pBuf )
+{
+ //printf( " ws: %d ", iStartSec );
+ if ( iStartSec && ( iStartSec <= m_geometry.iSectors ) )
+ memcpy( m_pbtMemory + ( iStartSec - 1 ) * m_geometry.iBytesPerSector, pBuf, m_geometry.iBytesPerSector );
+ else
+ {
+ sprintf( m_szLastError, "DISK: Writing non-existent sector: %04X", iStartSec );
+ return FALSE;
+ }
+
+ if ( iStartSec > m_iMaxSectorWritten )
+ m_iMaxSectorWritten = iStartSec;
+
+ return TRUE;
+}
+
diff --git a/jindroush/lib/cdsk_atr.cpp b/jindroush/lib/cdsk_atr.cpp
new file mode 100644
index 0000000..a472561
--- /dev/null
+++ b/jindroush/lib/cdsk_atr.cpp
@@ -0,0 +1,439 @@
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+//
+
+#include "cdsk_atr.h"
+#include "autil.h"
+#include "cfile.h"
+
+#define ATR_MAGIC 0x0296
+
+typedef struct
+{
+ WORD wMagic;
+ WORD wPars;
+ WORD wSecSize;
+ BYTE btParHigh;
+ DWORD dwCRC;
+ DWORD dwUnused;
+ BYTE btFlags;
+
+} ATRhead;
+
+#define ATR_HEAD_LEN 0x10
+
+CAtr::CAtr() : CDisk()
+{
+ #ifdef _MEMORY_DUMP_
+ printf( "CAtr constructed: %08X\n", this );
+ #endif
+}
+
+CAtr::~CAtr()
+{
+ #ifdef _MEMORY_DUMP_
+ printf( "CAtr destructed: %08X\n", this );
+ #endif
+}
+
+typedef enum
+{
+ LOAD_OK,
+ LOAD_BAD_DD_1,
+ LOAD_BAD_DD_2,
+ LOAD_BAD_DD_3,
+ LOAD_PAD
+} LOAD_VARIANT;
+
+BOOL CAtr::Load( char* szFname, BOOL bRepair, BOOL bRepairAuto )
+{
+ LOAD_VARIANT load_method = LOAD_OK;
+
+ m_iErrorCode = 0;
+
+ int iFirstSectorsSize = 0x80;
+
+ CFile cf;
+
+ if ( !cf.Open( szFname ) )
+ {
+ sprintf( m_szLastError, "ATR: Can't open '%s'", szFname );
+ m_iErrorCode = CDISK_ERROR_CANT_OPEN;
+ return FALSE;
+ }
+
+ strcpy( m_szFname, szFname );
+
+ ATRhead head;
+
+ head.wMagic = cf.readLEw();
+ head.wPars = cf.readLEw();
+ head.wSecSize = cf.readLEw();
+ head.btParHigh = cf.readb();
+ head.dwCRC = cf.readLEdw();
+ head.dwUnused = cf.readLEdw();
+ head.btFlags = cf.readb();
+
+ if ( head.wMagic != ATR_MAGIC )
+ {
+ sprintf( m_szLastError, "ATR: File '%s' is not an ATR file!", szFname );
+ return FALSE;
+ }
+
+ LONG lFileLen = cf.GetLength();
+ cf.Seek( ATR_HEAD_LEN, SEEK_SET );
+
+ switch( head.wSecSize )
+ {
+ case 0x80:
+ case 0x100:
+ break;
+
+ default:
+ {
+ sprintf( m_szLastError, "ATR: Invalid sector size: %04X", head.wSecSize );
+ return FALSE;
+ }
+ }
+
+ DWORD dwPars = head.wPars | ( head.btParHigh << 16 );
+
+ int iSectors = ( dwPars * 0x10 ) / head.wSecSize;
+
+ //BOOL bReadOnly = (head.btFlags & 1) ? TRUE : FALSE;
+
+ if ( head.wSecSize == 0x100 )
+ {
+ //if ( dwPars % head.wSecSize )
+ if ( ( dwPars * 0x10 ) % head.wSecSize )
+ {
+ iSectors = ( ( dwPars * 0x10 - 0x180 ) / head.wSecSize ) + 3;
+ }
+ else
+ {
+ sprintf( m_szLastError, "ATR: Format violated. First three sectors are not $80 long!" );
+ m_iErrorCode = CATR_FORMAT_VIOLATED;
+
+ if ( !bRepair )
+ {
+ return FALSE;
+ }
+ else
+ {
+ BYTE abtBuff[ 0x100 ];
+
+ memset( abtBuff, 0, 0x100 );
+
+ int iM1zeroes = 3;
+ int iM2zeroes = 3;
+ int iM3zeroes = 3;
+
+ cf.Seek( ATR_HEAD_LEN + ( 0x02 - 1 ) * 0x80, SEEK_SET );
+ cf.Read( abtBuff, 0x80 );
+
+ if ( IsBlockEmpty( abtBuff, 0x80 ) )
+ iM1zeroes--;
+
+ cf.Seek( ATR_HEAD_LEN + ( 0x04 - 1 ) * 0x80, SEEK_SET );
+ cf.Read( abtBuff, 0x80 );
+
+ if ( IsBlockEmpty( abtBuff, 0x80 ) )
+ {
+ iM1zeroes--;
+ iM2zeroes--;
+ }
+
+ cf.Seek( ATR_HEAD_LEN + ( 0x05 - 1 ) * 0x80, SEEK_SET );
+ cf.Read( abtBuff, 0x80 );
+
+ if ( IsBlockEmpty( abtBuff, 0x80 ) )
+ iM2zeroes--;
+
+ cf.Seek( ATR_HEAD_LEN + ( 0x06 - 1 ) * 0x80, SEEK_SET );
+ cf.Read( abtBuff, 0x80 );
+
+ if ( IsBlockEmpty( abtBuff, 0x80 ) )
+ {
+ iM1zeroes--;
+ iM2zeroes--;
+ }
+
+ cf.Seek( -0x180, SEEK_END );
+ cf.Read( abtBuff, 0x80 );
+ if ( IsBlockEmpty( abtBuff, 0x80 ) )
+ iM3zeroes--;
+
+ cf.Read( abtBuff, 0x80 );
+ if ( IsBlockEmpty( abtBuff, 0x80 ) )
+ iM3zeroes--;
+
+ cf.Read( abtBuff, 0x80 );
+ if ( IsBlockEmpty( abtBuff, 0x80 ) )
+ iM3zeroes--;
+
+ if ( !iM1zeroes )
+ {
+ load_method = LOAD_BAD_DD_1;
+ }
+ else if ( !iM2zeroes )
+ {
+ load_method = LOAD_BAD_DD_2;
+ }
+ else if ( !iM3zeroes )
+ {
+ load_method = LOAD_BAD_DD_3;
+ }
+
+ if ( !bRepairAuto )
+ {
+ printf( "Invalid DD ATR file encountered.\n" );
+ printf( "Choose repair method:\n" );
+ printf( "1) Sector, gap, sector, gap, sector, gap, data\n" );
+ printf( "2) Three sectors, three empty sectors, data\n" );
+ printf( "3) Data, three empty sectors\n" );
+ printf( "4) Don't repair\n" );
+
+ switch( load_method )
+ {
+ case LOAD_BAD_DD_1:
+ printf( "(Method 1 looks best)\n" );
+ break;
+
+ case LOAD_BAD_DD_2:
+ printf( "(Method 2 looks best)\n" );
+ break;
+
+ case LOAD_BAD_DD_3:
+ printf( "(Method 3 looks best)\n" );
+ break;
+
+ default:
+ break;
+ }
+
+ int iMethod;
+
+ printf( "\n" );
+ do
+ {
+ iMethod = getch() - '0';
+ } while( ( iMethod < 1 ) || ( iMethod > 4 ) );
+
+ if ( iMethod == 4 )
+ {
+ return FALSE;
+ }
+ }
+ else
+ {
+ if ( load_method == LOAD_OK )
+ load_method = LOAD_BAD_DD_1;
+ }
+
+
+ cf.Seek( ATR_HEAD_LEN, SEEK_SET );
+
+ switch( load_method )
+ {
+ case LOAD_BAD_DD_1:
+ case LOAD_BAD_DD_2:
+ case LOAD_BAD_DD_3:
+ iFirstSectorsSize = 0x100;
+ break;
+
+ default:
+ break;
+
+ }
+
+ } //end of repair
+
+ }
+ }
+
+ LONG lTotalComputedLen = (LONG) ( ( iSectors - 3 ) * head.wSecSize + ATR_HEAD_LEN + 3 * iFirstSectorsSize );
+
+ if ( lTotalComputedLen != lFileLen )
+ {
+ sprintf( m_szLastError, "ATR: Invalid length! %08lX <> %08lX (%08X)", lTotalComputedLen, lFileLen, iSectors );
+ m_iErrorCode = CATR_FORMAT_VIOLATED;
+
+ if ( !bRepair || ( load_method != LOAD_OK ) )
+ return FALSE;
+ else
+ {
+ if ( !bRepairAuto )
+ {
+ printf( "ATR with invalid length encountered.\n" );
+ printf( "Should be: $%08lX. Is: $%08lX.\n", lTotalComputedLen, lFileLen );
+ printf( "Choose:\n" );
+ printf( "1) Repair (shorten/pad)\n" );
+ printf( "2) Don't repair\n" );
+
+ int iMethod;
+
+ do
+ {
+ iMethod = getch() - '0';
+ } while( ( iMethod < 1 ) || ( iMethod > 2 ) );
+
+ if ( iMethod == 2 )
+ return FALSE;
+
+ load_method = LOAD_PAD;
+ }
+ else
+ {
+ if ( load_method == LOAD_OK )
+ load_method = LOAD_PAD;
+ }
+
+ }
+
+ }
+
+ DISK_GEOMETRY dg;
+
+ GuessClassicSizes( iSectors, head.wSecSize, &dg );
+
+ if ( !Format( &dg ) )
+ return FALSE;
+
+ BYTE abtBuff[ 0x100 ];
+ memset( abtBuff, 0, 0x100 );
+
+ for( int i = 0; i < iSectors; i++ )
+ {
+ switch( load_method )
+ {
+ default:
+ case LOAD_OK:
+ cf.Read( abtBuff, ( i < 3 ) ? 0x80 : head.wSecSize );
+ break;
+
+ case LOAD_PAD:
+ memset( abtBuff, 0, 0x100 );
+ cf.Read( abtBuff, ( i < 3 ) ? 0x80 : head.wSecSize );
+ break;
+
+ case LOAD_BAD_DD_1:
+ if ( i < 3 )
+ {
+ cf.Read( abtBuff, 0x80 );
+ cf.Seek( 0x80, SEEK_CUR );
+ }
+ else
+ cf.Read( abtBuff, 0x100 );
+ break;
+
+ case LOAD_BAD_DD_2:
+ if ( i < 3 )
+ {
+ cf.Read( abtBuff, 0x80 );
+
+ if ( i == 2 )
+ cf.Seek( 0x180, SEEK_CUR );
+ }
+ else
+ cf.Read( abtBuff, 0x100 );
+
+ break;
+
+ case LOAD_BAD_DD_3:
+ if ( i < 3 )
+ cf.Read( abtBuff, 0x80 );
+ else
+ cf.Read( abtBuff, 0x100 );
+
+ break;
+ }
+
+ WriteSector( i + 1, abtBuff );
+ }
+
+ cf.Close();
+ return TRUE;
+
+}
+
+#ifdef __CDISK_WRITE__
+
+BOOL CAtr::Save( char* szOutFile, BOOL bOverWrite )
+{
+ CFile cf;
+
+ if ( !bOverWrite && !access( szOutFile, F_OK ) )
+ {
+ sprintf( m_szLastError, "ATR: File already exists! '%s'", szOutFile );
+ return FALSE;
+ }
+
+ if ( !cf.Create( szOutFile ) )
+ {
+ sprintf( m_szLastError, "ATR: Can't create '%s'", szOutFile );
+ return FALSE;
+ }
+
+ ATRhead head;
+ memset( &head, 0, sizeof( ATRhead ) );
+
+ head.wMagic = ATR_MAGIC;
+ head.wSecSize = m_geometry.iBytesPerSector;
+
+ BOOL bReadOnly = TRUE;
+ head.btFlags |= ( bReadOnly ) ? 0x01 : 0x00;
+
+ DWORD dwLength = 0;
+
+ dwLength = 0x180 + ( m_geometry.iSectors - 3 ) * m_geometry.iBytesPerSector;
+
+ dwLength >>= 4;
+
+ head.wPars = dwLength & 0xFFFF;
+ head.btParHigh = dwLength >> 0x10;
+
+ cf.writeLEw( head.wMagic );
+ cf.writeLEw( head.wPars );
+ cf.writeLEw( head.wSecSize );
+ cf.writeb( head.btParHigh );
+ cf.writeLEdw( head.dwCRC );
+ cf.writeLEdw( head.dwUnused );
+ cf.writeb( head.btFlags );
+
+ BYTE abtBuff[ 0x100 ];
+
+ for( WORD i = 1; i <= m_geometry.iSectors; i++ )
+ {
+ ReadSector( abtBuff, i );
+
+ int iToWrite = ( i <= 3 ) ? 0x80: m_geometry.iBytesPerSector;
+
+ int iWritten;
+
+ if ( !cf.Write( abtBuff, iToWrite, &iWritten ) || ( iToWrite != iWritten ) )
+ {
+ sprintf( m_szLastError, "ATR: Can't write!" );
+ cf.Close();
+ unlink( szOutFile );
+ return FALSE;
+
+ }
+ }
+
+ cf.Close();
+
+ return TRUE;
+}
+
+#endif //__CDISK_WRITE__
diff --git a/jindroush/lib/cdsk_dcm.cpp b/jindroush/lib/cdsk_dcm.cpp
new file mode 100644
index 0000000..06ec1a3
--- /dev/null
+++ b/jindroush/lib/cdsk_dcm.cpp
@@ -0,0 +1,762 @@
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+//
+
+#include "cdsk_dcm.h"
+#include "cfile.h"
+#include "cprefile.h"
+#include "autil.h"
+
+//#define _DCM_DUMP_
+
+#define DCM_CHANGE_BEGIN 0x41 //Change only start of sector
+#define DCM_DOS_SECTOR 0x42 //128 byte compressed sector
+#define DCM_COMPRESSED 0x43 //Uncompressed/compressed pairs
+#define DCM_CHANGE_END 0x44 //Change only end of sector
+#define DCM_PASS_END 0x45 //End of pass
+#define DCM_SAME_AS_BEFORE 0x46 //Same as previous non-zero
+#define DCM_UNCOMPRESSED 0x47 //Uncompressed sector
+
+#define DCM_HEADER_SINGLE 0xFA
+#define DCM_HEADER_MULTI 0xF9
+
+#define DCM_DENSITY_SD 0 //Single density, 90K
+#define DCM_DENSITY_DD 1 //Double density, 180K
+#define DCM_DENSITY_ED 2 //Enhanced density, 130K
+
+CDcm::CDcm() : CDisk()
+{
+ #ifdef _MEMORY_DUMP_
+ printf( "CDcm constructed: %08X\n", this );
+ #endif
+}
+
+CDcm::~CDcm()
+{
+ #ifdef _MEMORY_DUMP_
+ printf( "CDcm destructed: %08X\n", this );
+ #endif
+}
+
+BOOL CDcm::Load( char* szFname, BOOL, BOOL )
+{
+ BYTE btArcType = 0; //Block type for first block
+ BYTE btBlkType; //Current block type
+
+ m_bAlreadyFormatted = FALSE;
+ m_bLastPass = FALSE;
+ m_wCurrentSector = 0;
+
+ CFile cfo;
+ CPreFile cf;
+
+ if ( !cfo.Open( szFname ) )
+ {
+ sprintf( m_szLastError, "DCM: Can't open '%s'", szFname );
+ m_iErrorCode = CDISK_ERROR_CANT_OPEN;
+ return FALSE;
+ }
+
+ strcpy( m_szFname, szFname );
+
+ cf.Open( &cfo, 20 );
+
+ m_lFileLength = cf.GetLength();
+
+ for(;;) //outpass
+ {
+ if ( cf.Tell() >= m_lFileLength )
+ {
+ if ( ( !m_bLastPass ) && ( btArcType == DCM_HEADER_MULTI ) )
+ {
+ sprintf( m_szLastError,"DCM: Multi-part archive error.\n" \
+ "To process these files, you must first combine the files into a single file." );
+ m_iErrorCode = CDCM_FORMAT_VIOLATED;
+ return FALSE;
+ }
+ }
+
+ btArcType = cf.readb();
+
+ switch( btArcType )
+ {
+ case DCM_HEADER_MULTI:
+ case DCM_HEADER_SINGLE:
+ if ( !DecodeRecFA( cf ) )
+ return FALSE;
+ break;
+
+ default:
+ sprintf( m_szLastError, "DCM: %02X is an unknown header block.\n", btArcType );
+ return FALSE;
+ }
+
+ for(;;) //inpass
+ {
+ btBlkType = cf.readb();
+
+ if ( btBlkType == DCM_PASS_END )
+ break;
+
+ if ( cf.Tell() >= m_lFileLength )
+ {
+ sprintf( m_szLastError, "DCM: EOF before end block." );
+ m_iErrorCode = CDCM_FORMAT_VIOLATED;
+ return FALSE;
+ }
+
+ BOOL bRes = TRUE;
+
+ *m_szLastError = '\0';
+ switch( btBlkType & 0x7F )
+ {
+ case DCM_CHANGE_BEGIN:
+ bRes = DecodeRec41( cf );
+ break;
+
+ case DCM_DOS_SECTOR:
+ bRes = DecodeRec42( cf );
+ break;
+
+ case DCM_COMPRESSED:
+ bRes = DecodeRec43( cf );
+ break;
+
+ case DCM_CHANGE_END:
+ bRes = DecodeRec44( cf );
+ break;
+
+ case DCM_SAME_AS_BEFORE:
+ //not needed
+ //bRes = DecodeRec46( cf );
+ break;
+
+ case DCM_UNCOMPRESSED:
+ bRes = DecodeRec47( cf );
+ break;
+
+ default:
+ {
+ switch( btBlkType )
+ {
+ case DCM_HEADER_MULTI:
+ case DCM_HEADER_SINGLE:
+ sprintf( m_szLastError, "DCM: Trying to start section but last section never had "
+ "an end section block.");
+ break;
+
+ default:
+ sprintf( m_szLastError, "DCM: %02X is an unknown block type. File may be "
+ "corrupt.",btBlkType);
+ break;
+ }
+
+ m_iErrorCode = CDCM_FORMAT_VIOLATED;
+ return FALSE;
+ }
+ }
+
+ if ( !bRes )
+ {
+ sprintf( m_szLastError, "DCM: Block %02X decode error!", btBlkType );
+ m_iErrorCode = CDCM_FORMAT_VIOLATED;
+ return FALSE;
+ }
+
+ if ( !WriteSector( m_wCurrentSector, m_abtCurrBuff ) )
+ return FALSE;
+
+ if ( btBlkType & 0x80 )
+ m_wCurrentSector++;
+ else
+ m_wCurrentSector = cf.readLEw();
+
+ } //infinite for (inpass)
+
+ //End block
+ if ( m_bLastPass )
+ break;
+
+ } //infinite for (outpass)
+
+ cf.Close();
+ cfo.Close();
+ return TRUE;
+
+}
+
+BOOL CDcm::DecodeRec41( CGenFile& cf )
+{
+ #ifdef _DCM_DUMP_
+ printf( "dec41: %08lX\n", cf.Tell() - 1 );
+ #endif
+
+ int iOffset = cf.readb();
+ BYTE* pbt = m_abtCurrBuff + iOffset;
+
+ do
+ {
+ *( pbt-- ) = cf.readb();
+ } while( iOffset-- );
+
+ return TRUE;
+}
+
+BOOL CDcm::DecodeRec42( CGenFile& cf )
+{
+ #ifdef _DCM_DUMP_
+ printf( "dec42: %08lX\n", cf.Tell() - 1 );
+ #endif
+
+ sprintf( m_szLastError, "DCM: Record type 0x42 untested. Uncomment?" );
+ return FALSE;
+
+ //TODO: uncomment later!
+ //cf.Read( m_abtCurrBuff + 123, 5 );
+ //memset( m_abtCurrBuff, m_abtCurrBuff[ 123 ], 123 );
+ //return TRUE;
+}
+
+BOOL CDcm::DecodeRec43( CGenFile& cf )
+{
+ #ifdef _DCM_DUMP_
+ printf( "dec43: %08lX\n", cf.Tell() - 1 );
+ #endif
+
+ BYTE* pbtP = m_abtCurrBuff;
+ BYTE* pbtE;
+
+ BYTE* pbtEnd = m_abtCurrBuff + m_iSectorSize;
+
+ do
+ {
+ //uncompressed string
+ if ( pbtP != m_abtCurrBuff )
+ pbtE = m_abtCurrBuff + ReadOffset( cf );
+ else
+ pbtE = m_abtCurrBuff + cf.readb();
+
+ if ( pbtE < pbtP )
+ return FALSE;
+
+ #ifdef _DCM_DUMP_
+ printf( "dec43: uncst: %p %p %ld\n", pbtP, pbtE, pbtE - pbtP );
+ #endif
+
+ if ( pbtE != pbtP )
+ {
+ cf.Read( pbtP, pbtE - pbtP );
+ pbtP = pbtE;
+ }
+
+ if ( pbtP >= pbtEnd )
+ break;
+
+ //rle compressed string
+ pbtE = m_abtCurrBuff + ReadOffset( cf );
+ BYTE c = cf.readb();
+
+ #ifdef _DCM_DUMP_
+ printf( "dec43: cst: %p %p %ld\n", pbtP, pbtE, pbtE - pbtP );
+ #endif
+
+ if ( pbtE < pbtP )
+ return FALSE;
+
+ memset( pbtP, c, pbtE - pbtP );
+ pbtP = pbtE;
+
+ } while( pbtP < pbtEnd );
+
+ return TRUE;
+}
+
+BOOL CDcm::DecodeRec44( CGenFile& cf )
+{
+ #ifdef _DCM_DUMP_
+ printf( "dec44: %08lX\n", cf.Tell() - 1 );
+ #endif
+
+ int iOffset = ReadOffset( cf );
+
+ cf.Read( m_abtCurrBuff + iOffset, m_iSectorSize - iOffset );
+
+ return TRUE;
+}
+
+BOOL CDcm::DecodeRec46( CGenFile& cf )
+{
+ #ifdef _DCM_DUMP_
+ printf( "dec46: %08lX\n", cf.Tell() - 1 );
+ #endif
+
+ return TRUE;
+}
+
+BOOL CDcm::DecodeRec47( CGenFile& cf )
+{
+ #ifdef _DCM_DUMP_
+ printf( "dec47: %08lX\n", cf.Tell() - 1 );
+ #endif
+
+ //TODO: Is this TRUE or NOT???
+ //cf.Read( m_abtCurrBuff, ( m_wCurrentSector < 4 ? 128 : m_iSectorSize ) );
+
+ cf.Read( m_abtCurrBuff, m_iSectorSize );
+ return TRUE;
+}
+
+BOOL CDcm::DecodeRecFA( CGenFile& cf )
+{
+ #ifdef _DCM_DUMP_
+ printf( "decFA: %08lX\n", cf.Tell() - 1 );
+ #endif
+
+ BYTE btPom = cf.readb();
+
+ BYTE btDensity = ( btPom >> 5 ) & 0x03;
+ //BYTE btPass = btPom & 0x1F;
+ m_bLastPass = ( btPom & 0x80 ) ? TRUE : FALSE;
+
+ int iSpT;
+ int iTracks;
+
+ switch( btDensity )
+ {
+ case DCM_DENSITY_SD:
+ iTracks = 40;
+ iSpT = 18;
+ m_iSectorSize = 128;
+ break;
+
+ case DCM_DENSITY_DD:
+ iTracks = 40;
+ iSpT = 18;
+ m_iSectorSize = 256;
+ break;
+
+ case DCM_DENSITY_ED:
+ iTracks = 40;
+ iSpT = 26;
+ m_iSectorSize = 128;
+ break;
+
+ default:
+ sprintf( m_szLastError,"DCM: Density type unknown (%02X)\n", btDensity );
+ return FALSE;
+ }
+
+ if ( !m_bAlreadyFormatted )
+ {
+ DISK_GEOMETRY dg;
+ dg.iSides = 1;
+ dg.iTracks = iTracks;
+ dg.iSectorsPerTrack = iSpT;
+ dg.iBytesPerSector = m_iSectorSize;
+
+ if ( !Format( &dg ) )
+ return FALSE;
+
+ m_bAlreadyFormatted = TRUE;
+ }
+
+ m_wCurrentSector = cf.readLEw();
+
+ return TRUE;
+}
+
+WORD CDcm::ReadOffset( CGenFile& cf )
+{
+ BYTE bt = cf.readb();
+
+ return( bt ? bt : 256 );
+}
+
+#ifdef __CDISK_WRITE__
+
+BOOL CDcm::Save( char* szOutFile, BOOL bOverWrite )
+{
+ if ( !bOverWrite && !access( szOutFile, F_OK ) )
+ {
+ sprintf( m_szLastError, "DCM: File already exists! '%s'", szOutFile );
+ return FALSE;
+ }
+
+ int iDensity = -1;
+ m_iSectorSize = m_geometry.iBytesPerSector;
+
+ if ( m_iSectorSize == 0x80 )
+ {
+ if ( m_geometry.iTracks == 40 )
+ {
+ if ( m_geometry.iSectorsPerTrack == 18 )
+ iDensity = DCM_DENSITY_SD;
+
+ if ( m_geometry.iSectorsPerTrack == 26 )
+ iDensity = DCM_DENSITY_ED;
+ }
+ }
+
+ if ( m_iSectorSize == 0x100 )
+ {
+ if ( ( m_geometry.iSectorsPerTrack == 18 ) &&
+ ( m_geometry.iTracks == 40 ) )
+ iDensity = DCM_DENSITY_DD;
+ }
+
+ if ( iDensity == - 1 )
+ {
+ sprintf( m_szLastError, "DCM: Can't work with such density!" );
+ return FALSE;
+ }
+
+ int iPass = 1;
+
+ m_pbtPass = new BYTE [ 0x6500 ];
+
+ CFile cf;
+
+ if ( !cf.Create( szOutFile ) )
+ {
+ sprintf( m_szLastError, "DCM: Can't create '%s'", szOutFile );
+ delete [] m_pbtPass;
+ return FALSE;
+ }
+
+ int iFirstSector = 0;
+ int iPrevSector = 0;
+ int iCurrentSector = 1;
+
+ memset( m_abtPrevBuff, 0, m_iSectorSize );
+
+ EncodeRecFA( FALSE, iPass, iDensity, iFirstSector );
+
+ //here should be other compression
+
+ while( iCurrentSector <= m_geometry.iSectors )
+ {
+ iFirstSector = 0;
+
+ while( ( m_pbtCurr - m_pbtPass ) < 0x5EFD )
+ {
+ if ( iCurrentSector > m_geometry.iSectors )
+ break;
+
+ ReadSector( m_abtCurrBuff, iCurrentSector );
+
+ BOOL bSkip = IsBlockEmpty( m_abtCurrBuff, m_iSectorSize );
+
+ //first non empty sector is marked as first, what a surprise! :)
+ if ( !bSkip && !iFirstSector )
+ {
+ iFirstSector = iCurrentSector;
+ iPrevSector = iCurrentSector;
+ }
+
+ //if just skipped, increment sector
+ if ( bSkip )
+ {
+ iCurrentSector++;
+ }
+ else
+ {
+ //if there is a gap, write sector number
+ if ( ( iCurrentSector - iPrevSector ) > 1 )
+ {
+ *( m_pbtCurr++ ) = iCurrentSector;
+ *( m_pbtCurr++ ) = iCurrentSector >> 8;
+ }
+ else
+ {
+ //else mark previous record
+ *m_pbtLastRec |= 0x80;
+ }
+
+ //first sector could be encoded with only some data
+ if ( iCurrentSector == iFirstSector )
+ EncodeRec( TRUE );
+ else
+ {
+ //if are same, encode as record 46
+ if ( !memcmp( m_abtPrevBuff, m_abtCurrBuff, m_iSectorSize ) )
+ EncodeRec46();
+ else
+ EncodeRec( FALSE );
+ }
+
+ //store this sector as previous
+ memcpy( m_abtPrevBuff, m_abtCurrBuff, m_iSectorSize );
+
+ //and move pointers
+ iPrevSector = iCurrentSector;
+ iCurrentSector++;
+ }
+
+ }
+
+ //mark previous sector
+ *m_pbtLastRec |= 0x80;
+
+ //encode end
+ EncodeRec45();
+
+ BYTE* pEnd = m_pbtCurr;
+
+ //change beginning block
+ if ( iCurrentSector > m_geometry.iSectors )
+ EncodeRecFA( TRUE, iPass, iDensity, iFirstSector );
+ else
+ EncodeRecFA( FALSE, iPass, iDensity, iFirstSector );
+
+ //and write whole pass
+
+ if ( ( pEnd - m_pbtPass ) > 0x6000 )
+ {
+ sprintf( m_szLastError, "DCM: Internal error! Pass too long!" );
+ delete [] m_pbtPass;
+ cf.Close();
+ unlink( szOutFile );
+ return FALSE;
+ }
+
+ if ( !cf.Write( m_pbtPass, pEnd - m_pbtPass ) )
+ {
+ sprintf( m_szLastError, "DCM: Can't write!" );
+ delete [] m_pbtPass;
+ cf.Close();
+ unlink( szOutFile );
+ return FALSE;
+ }
+
+ iPass++;
+ }
+
+ cf.Close();
+
+ delete [] m_pbtPass;
+
+ return TRUE;
+}
+
+void CDcm::EncodeRecFA( BOOL bLast, int iPass, int iDensity, int iFirstSec )
+{
+ m_pbtCurr = m_pbtPass;
+
+ #ifdef _DCM_DUMP_
+ printf( "ERFA: %08lX\n", m_pbtCurr - m_pbtPass );
+ #endif
+
+ m_pbtLastRec = m_pbtCurr;
+
+ BYTE btType = bLast ? 0x80 : 0;
+
+ btType |= ( iDensity & 3 ) << 5;
+
+ btType |= ( iPass & 0x1F );
+
+ *( m_pbtCurr++ ) = DCM_HEADER_SINGLE;
+ *( m_pbtCurr++ ) = btType;
+ *( m_pbtCurr++ ) = iFirstSec;
+ *( m_pbtCurr++ ) = iFirstSec >> 8;
+
+}
+
+void CDcm::EncodeRec45()
+{
+ #ifdef _DCM_DUMP_
+ printf( "ER45: %08lX\n", m_pbtCurr - m_pbtPass );
+ #endif
+
+ m_pbtLastRec = m_pbtCurr;
+ *( m_pbtCurr++ ) = DCM_PASS_END;
+}
+
+void CDcm::EncodeRec46()
+{
+ #ifdef _DCM_DUMP_
+ printf( "ER46: %08lX\n", m_pbtCurr - m_pbtPass );
+ #endif
+
+ m_pbtLastRec = m_pbtCurr;
+ *( m_pbtCurr++ ) = DCM_SAME_AS_BEFORE;
+}
+
+void CDcm::EncodeRec( BOOL bIsFirstSector )
+{
+ #ifdef _DCM_DUMP_
+ printf( "ER: %08lX\n", m_pbtCurr - m_pbtPass );
+ #endif
+
+ m_pbtLastRec = m_pbtCurr;
+
+ BYTE abtBuff41[ 0x300 ];
+ BYTE abtBuff43[ 0x300 ];
+ BYTE abtBuff44[ 0x300 ];
+ BYTE* abtBuff47 = m_abtCurrBuff;
+
+ int iEnd41 = 0x300;
+ int iEnd43 = 0x300;
+ int iEnd44 = 0x300;
+
+ int iBestMethod = DCM_UNCOMPRESSED;
+ int iBestEnd = m_iSectorSize;
+ BYTE* pbtBest = abtBuff47;
+
+ EncodeRec43( abtBuff43, &iEnd43, m_abtCurrBuff, m_iSectorSize );
+
+ if ( !bIsFirstSector )
+ {
+ EncodeRec41( abtBuff41, &iEnd41, m_abtCurrBuff, m_abtPrevBuff, m_iSectorSize );
+ EncodeRec44( abtBuff44, &iEnd44, m_abtCurrBuff, m_abtPrevBuff, m_iSectorSize );
+ }
+
+ if ( iEnd41 < iBestEnd )
+ {
+ iBestMethod = DCM_CHANGE_BEGIN;
+ iBestEnd = iEnd41;
+ pbtBest = abtBuff41;
+ }
+
+ if ( iEnd43 < iBestEnd )
+ {
+ iBestMethod = DCM_COMPRESSED;
+ iBestEnd = iEnd43;
+ pbtBest = abtBuff43;
+ }
+
+ if ( iEnd44 < iBestEnd )
+ {
+ iBestMethod = DCM_CHANGE_END;
+ iBestEnd = iEnd44;
+ pbtBest = abtBuff44;
+ }
+
+ *( m_pbtCurr++ ) = iBestMethod;
+ memcpy( m_pbtCurr, pbtBest, iBestEnd );
+ m_pbtCurr += iBestEnd;
+}
+
+void CDcm::EncodeRec41( BYTE* pbtDest, int* piDestLen, BYTE* pbtSrc, BYTE* pbtSrcOld, int iSrcLen )
+{
+ BYTE* pbtS = pbtSrc + iSrcLen - 1;
+ pbtSrcOld += iSrcLen - 1;
+
+ BYTE* pbtD = pbtDest;
+
+ for( int i = 0; i < iSrcLen; i++ )
+ {
+ if ( *( pbtS-- ) != * ( pbtSrcOld-- ) )
+ break;
+ }
+
+ pbtS++;
+
+ *( pbtD++ ) = pbtS - pbtSrc;
+
+ int iBytes = pbtS - pbtSrc + 1;
+
+ while( iBytes-- )
+ {
+ *( pbtD++ ) = *( pbtS-- );
+ }
+
+ *piDestLen = pbtD - pbtDest;
+}
+
+void CDcm::EncodeRec43( BYTE* pbtDest, int* piDestLen, BYTE* pbtSrc, int iSrcLen )
+{
+ BYTE* pbtEnd = pbtSrc + iSrcLen;
+ BYTE* pbtCur = pbtSrc;
+
+ BYTE* pbtD = pbtDest;
+
+ while( pbtCur < pbtEnd )
+ {
+ BOOL bFound = FALSE;
+
+ for( BYTE* pbtNow = pbtCur; pbtNow < ( pbtEnd - 2 ); pbtNow++ )
+ {
+
+ if ( ( *pbtNow == *(pbtNow+1) ) && ( *pbtNow == *(pbtNow+2) ) )
+ {
+ int iUnc = pbtNow - pbtCur;
+
+ *( pbtD ++ ) = pbtNow - pbtSrc;
+ if ( iUnc )
+ {
+ memcpy( pbtD, pbtCur, iUnc );
+ pbtD += iUnc;
+ }
+
+ BYTE bt = *pbtNow;
+ BYTE*p;
+ for( p = pbtNow + 1; p < pbtEnd; p++ )
+ {
+ if ( *p != bt )
+ break;
+ }
+
+ if ( p > pbtEnd )
+ p = pbtEnd;
+
+ *( pbtD++ ) = p - pbtSrc;
+ *( pbtD++ ) = bt;
+
+ pbtCur = p;
+ bFound = TRUE;
+ break;
+ }
+ }
+
+ if ( ( pbtCur >= pbtEnd - 2 ) || !bFound )
+ {
+ if ( pbtCur < pbtEnd )
+ {
+ *( pbtD++ ) = iSrcLen;
+ memcpy( pbtD, pbtCur, pbtEnd - pbtCur );
+ pbtD += pbtEnd - pbtCur;
+ }
+
+ break;
+ }
+
+ }
+
+ *piDestLen = pbtD - pbtDest;
+}
+
+void CDcm::EncodeRec44( BYTE* pbtDest, int* piDestLen, BYTE* pbtSrc, BYTE* pbtSrcOld, int iSrcLen )
+{
+ BYTE* pbtS = pbtSrc;
+ BYTE* pbtEnd = pbtSrc + iSrcLen;
+
+ BYTE* pbtD = pbtDest;
+
+ for( int i = 0; i < iSrcLen; i++ )
+ {
+ if ( *( pbtS++ ) != * ( pbtSrcOld++ ) )
+ break;
+ }
+
+ pbtS--;
+
+ *( pbtD++ ) = pbtS - pbtSrc;
+ memcpy( pbtD, pbtS, pbtEnd - pbtS );
+ pbtD += pbtEnd - pbtS;
+
+ *piDestLen = pbtD - pbtDest;
+}
+
+#endif // __CDISK_WRITE__
+
diff --git a/jindroush/lib/cdsk_scp.cpp b/jindroush/lib/cdsk_scp.cpp
new file mode 100644
index 0000000..eb2e0f2
--- /dev/null
+++ b/jindroush/lib/cdsk_scp.cpp
@@ -0,0 +1,279 @@
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+//
+
+#include "cdsk_scp.h"
+#include "autil.h"
+#include "cfile.h"
+
+#define SCP_MAGIC 0xFDFD
+
+CScp::CScp() : CDisk()
+{
+ #ifdef _MEMORY_DUMP_
+ printf( "CScp constructed: %08X\n", this );
+ #endif
+}
+
+CScp::~CScp()
+{
+ #ifdef _MEMORY_DUMP_
+ printf( "CScp destructed: %08X\n", this );
+ #endif
+}
+
+BOOL CScp::Load( char* szFname, BOOL, BOOL )
+{
+ WORD wMagic;
+ BYTE btSectorSize;
+ BYTE btTracks;
+ BYTE btSectorsPerTrack;
+
+ CFile cf;
+
+ if( !cf.Open( szFname ) )
+ {
+ sprintf( m_szLastError, "SCP: Can't open '%s'", szFname );
+ return FALSE;
+ }
+
+ strcpy( m_szFname, szFname );
+
+ wMagic = cf.readLEw();
+
+ if ( wMagic != SCP_MAGIC )
+ {
+ sprintf( m_szLastError, "SCP: File '%s' is not an SCP file!", szFname );
+ return FALSE;
+ }
+
+ btSectorSize = cf.readb();
+ btTracks = cf.readb();
+ btSectorsPerTrack = cf.readb();
+
+ int iSectorSize;
+
+ switch( btSectorSize )
+ {
+ case 0x80:
+ iSectorSize = 0x80;
+ break;
+
+ case 0x00:
+ iSectorSize = 0x100;
+ break;
+
+ default:
+ {
+ sprintf( m_szLastError, "SCP: Invalid sector size: %02X", btSectorSize );
+ return FALSE;
+ }
+ }
+
+ DISK_GEOMETRY dg;
+ dg.iSides = 1;
+ dg.iTracks = btTracks;
+ dg.iSectorsPerTrack = btSectorsPerTrack;
+ dg.iBytesPerSector = iSectorSize;
+
+ if ( !Format( &dg ) )
+ return FALSE;
+
+ BYTE *pbtTable = new BYTE [ btSectorsPerTrack * btTracks ];
+
+ if ( ! pbtTable )
+ {
+ sprintf( m_szLastError, "SCP: Not enough memory for sector table!" );
+ return FALSE;
+ }
+
+ if ( !cf.Read( pbtTable, btSectorsPerTrack * btTracks ) )
+ {
+ sprintf( m_szLastError, "SCP: Can't read sector table!" );
+ return FALSE;
+ }
+
+ BYTE abtBuff[ 0x100 ];
+ memset( abtBuff, 0, 0x100 );
+
+ BYTE* pbtPtr = pbtTable;
+
+ for( int iTrack = 0; iTrack < btTracks; iTrack++ )
+ {
+ for( int iSector = 0; iSector < btSectorsPerTrack; iSector++ )
+ {
+ if ( *pbtPtr )
+ {
+ int iNowRead;
+
+ if ( !iTrack && ( iSector < 3 ) )
+ iNowRead = 0x80;
+ else
+ iNowRead = iSectorSize;
+
+ int iReallyRead;
+
+ if ( !cf.Read( abtBuff, iNowRead, &iReallyRead ) || ( iNowRead != iReallyRead ) )
+ {
+ delete [] pbtTable;
+ sprintf( m_szLastError, "SCP: Image broken!" );
+ return FALSE;
+ }
+
+ if ( !WriteSector( *pbtPtr + iTrack* btSectorsPerTrack, abtBuff ) )
+ {
+ delete [] pbtTable;
+ return FALSE;
+ }
+
+ }
+ pbtPtr++;
+ }
+
+ }
+
+ delete [] pbtTable;
+
+ cf.Close();
+ return TRUE;
+
+}
+
+#ifdef __CDISK_WRITE__
+
+BOOL CScp::Save( char* szOutFile, BOOL bOverWrite )
+{
+ if ( !bOverWrite && !access( szOutFile, F_OK ) )
+ {
+ sprintf( m_szLastError, "SCP: File already exists! '%s'", szOutFile );
+ return FALSE;
+ }
+
+ BYTE btSize;
+ BYTE btTracks;
+ BYTE btSpT;
+
+ switch ( m_geometry.iBytesPerSector )
+ {
+ case 0x80:
+ btSize = 0x80;
+ break;
+
+ case 0x100:
+ default:
+ btSize = 0x00;
+ break;
+ }
+
+ BOOL bGood = FALSE;
+
+ btTracks = m_geometry.iTracks;
+ btSpT = m_geometry.iSectorsPerTrack;
+
+ if ( ( m_geometry.iTracks == 40 ) && ( m_geometry.iSectorsPerTrack == 18 ) )
+ bGood = TRUE;
+
+ if ( ( m_geometry.iTracks == 40 ) && ( m_geometry.iSectorsPerTrack == 26 ) )
+ bGood = TRUE;
+
+ if ( !bGood )
+ {
+ sprintf( m_szLastError, "SCP: Can't export, because of invalid disk size!" );
+ return FALSE;
+ }
+
+ int iMapSize = m_geometry.iTracks * m_geometry.iSectorsPerTrack;
+
+ BYTE* pMap = new BYTE [ iMapSize ];
+
+ if ( !pMap )
+ {
+ sprintf( m_szLastError, "SCP: Can't allocate memory for map!" );
+ return FALSE;
+ }
+
+ memset( pMap, 0, iMapSize );
+
+
+ CFile cf;
+
+ if ( !cf.Create( szOutFile ) )
+ {
+ sprintf( m_szLastError, "SCP: Can't create '%s'", szOutFile );
+ delete [] pMap;
+ return FALSE;
+ }
+
+ WORD wMagic = SCP_MAGIC;
+
+ cf.writeLEw( wMagic );
+ cf.writeb( btSize );
+ cf.writeb( btTracks );
+ cf.writeb( btSpT );
+
+ cf.Seek( iMapSize, SEEK_CUR );
+
+ BYTE abtBuff[ 0x100 ];
+
+ int iSectors = m_geometry.iSectors;
+
+ for( int i = 0; i < iSectors; i++ )
+ {
+ if ( !ReadSector( abtBuff, i + 1 ) )
+ {
+ delete [] pMap;
+ cf.Close();
+ unlink( szOutFile );
+ return FALSE;
+ }
+
+ int iBytesNow = ( i < 3 ) ? 0x80 : m_geometry.iBytesPerSector;
+
+ if ( !IsBlockEmpty( abtBuff, iBytesNow ) )
+ {
+ int iWritten;
+ if ( !cf.Write( abtBuff, iBytesNow, &iWritten ) || ( iBytesNow != iWritten ) )
+ {
+ sprintf( m_szLastError, "SCP: Error writing to '%s'", szOutFile );
+ delete [] pMap;
+ cf.Close( );
+ unlink( szOutFile );
+ return FALSE;
+
+ }
+
+ pMap[ i ] = ( i % btSpT ) + 1;
+ }
+ }
+
+ cf.Seek( 5, SEEK_SET );
+
+ if ( !cf.Write( pMap, iMapSize ) )
+ {
+ sprintf( m_szLastError, "SCP: Can't write!" );
+ delete [] pMap;
+ cf.Close( );
+ unlink( szOutFile );
+ return FALSE;
+
+ }
+
+ delete [] pMap;
+
+ cf.Close();
+
+ return TRUE;
+}
+
+#endif //__CDISK_WRITE__
diff --git a/jindroush/lib/cdsk_xfd.cpp b/jindroush/lib/cdsk_xfd.cpp
new file mode 100644
index 0000000..aecaeb2
--- /dev/null
+++ b/jindroush/lib/cdsk_xfd.cpp
@@ -0,0 +1,334 @@
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+//
+
+#include "cdsk_xfd.h"
+#include "autil.h"
+#include "cfile.h"
+
+CXfd::CXfd() : CDisk()
+{
+ #ifdef _MEMORY_DUMP_
+ printf( "CXfd constructed: %08X\n", this );
+ #endif
+}
+
+CXfd::~CXfd()
+{
+ #ifdef _MEMORY_DUMP_
+ printf( "CXfd destructed: %08X\n", this );
+ #endif
+}
+
+typedef enum
+{
+ LOAD_OK,
+ LOAD_BAD_DD_1,
+ LOAD_BAD_DD_2,
+ LOAD_BAD_DD_3
+} LOAD_VARIANT;
+
+BOOL CXfd::Load( char* szFname, BOOL bRepair, BOOL bRepairAuto )
+{
+ LOAD_VARIANT load_method = LOAD_OK;
+
+ int iFirstSectorsSize = 0x80;
+
+ CFile cf;
+
+ if ( !cf.Open( szFname ) )
+ {
+ sprintf( m_szLastError, "XFD: Can't open '%s'", szFname );
+ return FALSE;
+ }
+
+ strcpy( m_szFname, szFname );
+
+ LONG lFileLen = cf.GetLength();
+
+ int iSecs;
+ int iSecSize;
+
+ if ( lFileLen % 0x80 )
+ {
+ sprintf( m_szLastError, "XFD: Strange length!" );
+ cf.Close();
+ return FALSE;
+ }
+
+ if ( ( lFileLen / 0x80 ) > 1040 )
+ {
+ iSecSize = 0x100;
+
+ iSecs = ( ( lFileLen - 0x180 ) / 0x100 ) + 3;
+ }
+ else
+ {
+ iSecSize = 0x80;
+ iSecs = lFileLen / 0x80;
+ }
+
+ if ( ( ( ( iSecs - 3 ) * iSecSize ) + 0x180 ) != lFileLen )
+ {
+ sprintf( m_szLastError, "XFD: Format violated: (%08lX != %08X)", lFileLen, iSecs * iSecSize );
+ m_iErrorCode = CXFD_FORMAT_VIOLATED;
+
+ if ( !bRepair )
+ {
+ cf.Close();
+ return FALSE;
+ }
+ else
+ {
+ iSecs = lFileLen / iSecSize;
+ BYTE abtBuff[ 0x100 ];
+
+ memset( abtBuff, 0, 0x100 );
+
+ int iM1zeroes = 3;
+ int iM2zeroes = 3;
+ int iM3zeroes = 3;
+
+ cf.Seek( ( 0x02 - 1 ) * 0x80, SEEK_SET );
+ cf.Read( abtBuff, 0x80 );
+
+ if ( IsBlockEmpty( abtBuff, 0x80 ) )
+ iM1zeroes--;
+
+ cf.Seek( ( 0x04 - 1 ) * 0x80, SEEK_SET );
+ cf.Read( abtBuff, 0x80 );
+
+ if ( IsBlockEmpty( abtBuff, 0x80 ) )
+ {
+ iM1zeroes--;
+ iM2zeroes--;
+ }
+
+ cf.Seek( ( 0x05 - 1 ) * 0x80, SEEK_SET );
+ cf.Read( abtBuff, 0x80 );
+
+ if ( IsBlockEmpty( abtBuff, 0x80 ) )
+ iM2zeroes--;
+
+ cf.Seek( ( 0x06 - 1 ) * 0x80, SEEK_SET );
+ cf.Read( abtBuff, 0x80 );
+
+ if ( IsBlockEmpty( abtBuff, 0x80 ) )
+ {
+ iM1zeroes--;
+ iM2zeroes--;
+ }
+
+ cf.Seek( -0x180, SEEK_END );
+ cf.Read( abtBuff, 0x80 );
+ if ( IsBlockEmpty( abtBuff, 0x80 ) )
+ iM3zeroes--;
+
+ cf.Read( abtBuff, 0x80 );
+ if ( IsBlockEmpty( abtBuff, 0x80 ) )
+ iM3zeroes--;
+
+ cf.Read( abtBuff, 0x80 );
+ if ( IsBlockEmpty( abtBuff, 0x80 ) )
+ iM3zeroes--;
+
+ if ( !iM1zeroes )
+ {
+ load_method = LOAD_BAD_DD_1;
+ }
+ else if ( !iM2zeroes )
+ {
+ load_method = LOAD_BAD_DD_2;
+ }
+ else if ( !iM3zeroes )
+ {
+ load_method = LOAD_BAD_DD_3;
+ }
+
+ if ( !bRepairAuto )
+ {
+ printf( "Invalid DD ATR file encountered.\n" );
+ printf( "Choose repair method:\n" );
+ printf( "1) Sector, gap, sector, gap, sector, gap, data\n" );
+ printf( "2) Three sectors, three empty sectors, data\n" );
+ printf( "3) Data, three empty sectors\n" );
+ printf( "4) Don't repair\n" );
+
+ switch( load_method )
+ {
+ case LOAD_BAD_DD_1:
+ printf( "(Method 1 looks best)\n" );
+ break;
+
+ case LOAD_BAD_DD_2:
+ printf( "(Method 2 looks best)\n" );
+ break;
+
+ case LOAD_BAD_DD_3:
+ printf( "(Method 3 looks best)\n" );
+ break;
+
+ default:
+ break;
+ }
+
+ int iMethod;
+
+ printf( "\n" );
+ do
+ {
+ iMethod = getch() - '0';
+ } while( ( iMethod < 1 ) || ( iMethod > 4 ) );
+
+ if ( iMethod == 4 )
+ {
+ cf.Close();
+ return FALSE;
+ }
+ }
+ else
+ {
+ if ( load_method == LOAD_OK )
+ load_method = LOAD_BAD_DD_1;
+ }
+
+ cf.Seek( 0, SEEK_SET );
+
+ switch( load_method )
+ {
+ case LOAD_BAD_DD_1:
+ case LOAD_BAD_DD_2:
+ iFirstSectorsSize = 0x100;
+ break;
+
+ default:
+ break;
+
+ }
+
+
+ }
+ }
+
+ DISK_GEOMETRY dg;
+
+ GuessClassicSizes( iSecs, iSecSize, &dg );
+
+ if ( !Format( &dg ) )
+ {
+ cf.Close();
+ return FALSE;
+ }
+
+ BYTE abtBuff[ 0x100 ];
+ memset( abtBuff, 0, 0x100 );
+
+ for( int i = 0; i < iSecs; i++ )
+ {
+ switch( load_method )
+ {
+ default:
+ case LOAD_OK:
+ cf.Read( abtBuff, ( i < 3 ) ? 0x80 : iSecSize );
+ break;
+
+ case LOAD_BAD_DD_1:
+ if ( i < 3 )
+ {
+ cf.Read( abtBuff, 0x80 );
+ cf.Seek( 0x80, SEEK_CUR );
+ }
+ else
+ cf.Read( abtBuff, 0x100 );
+ break;
+
+ case LOAD_BAD_DD_2:
+ if ( i < 3 )
+ {
+ cf.Read( abtBuff, 0x80 );
+
+ if ( i == 2 )
+ cf.Seek( 0x180, SEEK_CUR );
+ }
+ else
+ cf.Read( abtBuff, 0x100 );
+
+ break;
+
+ case LOAD_BAD_DD_3:
+ if ( i < 3 )
+ cf.Read( abtBuff, 0x80 );
+ else
+ cf.Read( abtBuff, 0x100 );
+
+ break;
+ }
+
+ if ( !WriteSector( i + 1, abtBuff ) )
+ {
+ cf.Close();
+ return FALSE;
+ }
+ }
+
+ cf.Close();
+ return TRUE;
+
+}
+
+#ifdef __CDISK_WRITE__
+
+BOOL CXfd::Save( char* szOutFile, BOOL bOverWrite )
+{
+ CFile cf;
+
+ if ( !bOverWrite && !access( szOutFile, F_OK ) )
+ {
+ sprintf( m_szLastError, "XFD: File already exists! '%s'", szOutFile );
+ return FALSE;
+ }
+
+ if ( !cf.Create( szOutFile ) )
+ {
+ sprintf( m_szLastError, "XFD: Can't create '%s'", szOutFile );
+ return FALSE;
+ }
+
+ BYTE abtBuff[ 0x100 ];
+
+ for( WORD i = 1; i <= m_geometry.iSectors; i++ )
+ {
+ if ( !ReadSector( abtBuff, i ) )
+ return FALSE;
+
+ int iToWrite = ( i <= 3 ) ? 0x80: m_geometry.iBytesPerSector;
+
+ int iWritten;
+
+ if ( !cf.Write( abtBuff, iToWrite, &iWritten ) || ( iWritten != iToWrite ) )
+ {
+ sprintf( m_szLastError, "XFD: Can't write!" );
+ cf.Close();
+ unlink( szOutFile );
+ return FALSE;
+ }
+
+ }
+
+ cf.Close();
+
+ return TRUE;
+}
+
+#endif //__CDISK_WRITE__
diff --git a/jindroush/lib/cfile.cpp b/jindroush/lib/cfile.cpp
new file mode 100644
index 0000000..97a78d2
--- /dev/null
+++ b/jindroush/lib/cfile.cpp
@@ -0,0 +1,139 @@
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+//
+
+#include "cfile.h"
+
+CFile::CFile()
+{
+ m_bOpened = FALSE;
+ m_hFile = 0;
+ m_bIsDirty = FALSE;
+}
+
+CFile::~CFile()
+{
+ Close();
+}
+
+//opens file for reading, binary
+BOOL CFile::Open( char* szName )
+{
+ if ( m_bOpened )
+ return FALSE;
+
+ m_hFile = open( szName, O_BINARY | O_RDONLY );
+
+ if ( m_hFile == -1 )
+ {
+ m_hFile = 0;
+
+ //printf( "CFile::Open %s Err:%d\n", szName, errno );
+
+ return FALSE;
+ }
+
+ m_bOpened = TRUE;
+
+ m_lLength = lseek( m_hFile, 0, SEEK_END );
+ lseek( m_hFile, 0, SEEK_SET );
+
+ return TRUE;
+
+}
+
+//creates new file, opened for rdwr, binary, deletes existing
+BOOL CFile::Create( char* szName )
+{
+ if ( m_bOpened )
+ return FALSE;
+
+ m_bIsDirty = FALSE;
+ m_hFile = open( szName, O_BINARY | O_RDWR | O_CREAT | O_TRUNC, 0666 );
+
+ if ( m_hFile == -1 )
+ {
+ m_hFile = 0;
+ return FALSE;
+ }
+
+ m_bOpened = TRUE;
+
+ m_lLength = lseek( m_hFile, 0, SEEK_END );
+ lseek( m_hFile, 0, SEEK_SET );
+
+ return TRUE;
+
+}
+
+//reads iBytesToRead bytes to buffer
+BOOL CFile::Read( void* pBuff, int iBytesToRead, int* piBytesRead )
+{
+ if ( !m_bOpened )
+ return FALSE;
+
+ m_bIsDirty = FALSE;
+ int iBytesRead = read( m_hFile, pBuff, iBytesToRead );
+
+ if ( piBytesRead )
+ *piBytesRead = iBytesRead;
+
+ if ( -1 == iBytesRead )
+ return FALSE;
+
+ m_lCurrPtr = tell( m_hFile );
+
+ return TRUE;
+}
+
+//writes iBytesToWrite from buffer
+//TODO:check for file being opened for writing
+BOOL CFile::Write( void* pBuff, int iBytesToWrite, int* piBytesWritten )
+{
+ if ( !m_bOpened )
+ return FALSE;
+
+ int iBytesWritten = write( m_hFile, pBuff, iBytesToWrite );
+
+ if ( piBytesWritten )
+ *piBytesWritten = iBytesWritten;
+
+ if ( -1 == iBytesWritten )
+ return FALSE;
+
+ m_lCurrPtr = tell( m_hFile );
+ m_bIsDirty = TRUE;
+
+ return TRUE;
+}
+
+//seek
+BOOL CFile::Seek( long lPos, int iType )
+{
+ m_lCurrPtr = lseek( m_hFile, lPos, iType );
+
+ return TRUE;
+}
+
+//closes the file
+void CFile::Close()
+{
+ if ( m_hFile )
+ close( m_hFile );
+
+ m_bIsDirty = FALSE;
+ m_hFile = 0;
+ m_bOpened = FALSE;
+}
+
diff --git a/jindroush/lib/cfs.cpp b/jindroush/lib/cfs.cpp
new file mode 100644
index 0000000..17de630
--- /dev/null
+++ b/jindroush/lib/cfs.cpp
@@ -0,0 +1,69 @@
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+//
+
+#include "cfs.h"
+
+CDirEntry::CDirEntry()
+{
+ *m_szFname = '\0';
+ *m_szAscData = '\0';
+ m_dwFlags = 0;
+ m_pSubdir = NULL;
+ m_pNext = NULL;
+ m_pPrev = NULL;
+
+ #ifdef _MEMORY_DUMP_
+ printf( "CDirEntry constructed: %08X\n", this );
+ #endif
+}
+
+CDirEntry::~CDirEntry()
+{
+ #ifdef _MEMORY_DUMP_
+ printf( "CDirEntry destructed: %08X\n", this );
+ #endif
+}
+
+CFs::CFs()
+{
+ #ifdef _MEMORY_DUMP_
+ printf( "CFs constructed: %08X\n", this );
+ #endif
+}
+
+CFs::~CFs()
+{
+ #ifdef _MEMORY_DUMP_
+ printf( "CFs destructed: %08X\n", this );
+ #endif
+}
+
+void CFs::DeleteList( CDirEntry* pList )
+{
+ CDirEntry* pCurr = pList;
+ CDirEntry* pNext;
+
+ while( pCurr )
+ {
+ if ( pCurr->m_pSubdir )
+ DeleteList( pCurr->m_pSubdir );
+
+ pNext = pCurr->m_pNext;
+ delete pCurr;
+
+ pCurr = pNext;
+ }
+}
+
diff --git a/jindroush/lib/cfs_b2b.cpp b/jindroush/lib/cfs_b2b.cpp
new file mode 100644
index 0000000..8b62ded
--- /dev/null
+++ b/jindroush/lib/cfs_b2b.cpp
@@ -0,0 +1,156 @@
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+//
+
+#include "cfs_b2b.h"
+#include "autil.h"
+
+CBas2Boot::CBas2Boot() : CFs()
+{
+ #ifdef _MEMORY_DUMP_
+ printf( "CBas2Boot constructed: %08X\n", this );
+ #endif
+}
+
+CBas2Boot::~CBas2Boot()
+{
+ Dismount();
+ #ifdef _MEMORY_DUMP_
+ printf( "CBas2Boot destructed: %08X\n", this );
+ #endif
+}
+
+BOOL CBas2Boot::Mount( ADisk* pDisk )
+{
+ m_iFilesValid = 0;
+ m_iFilesInvalid = 0;
+ m_pDisk = pDisk;
+ m_pRoot = NULL;
+
+ if ( m_pDisk->GetSectorSize() != 0x80 )
+ {
+ sprintf( m_szLastError, "BAS2BOOT: Can't process DD disk!" );
+ return FALSE;
+ }
+
+ m_pRoot = CreateEntry();
+
+ return m_pRoot ? TRUE : FALSE;
+}
+
+void CBas2Boot::Dismount()
+{
+ DeleteList( m_pRoot );
+}
+
+CBas2BootDirEntry* CBas2Boot::CreateEntry()
+{
+ CBas2BootDirEntry* pE = new CBas2BootDirEntry();
+
+ if ( !pE )
+ return NULL;
+
+ BYTE abtSec[ 0x100 ];
+
+ if ( !m_pDisk->ReadSector( abtSec, 1 ) )
+ {
+ sprintf( m_szLastError, "BAS2BOOT: Can't read boot sector because\n%s", m_pDisk->GetLastError() );
+ delete pE;
+ return NULL;
+ }
+
+ pE->m_dwFileLen = abtSec[ 8 ] + ( abtSec[ 9 ] << 8 );
+
+ if ( !m_pDisk->ReadSector( abtSec, 2 ) )
+ {
+ sprintf( m_szLastError, "BAS2BOOT: Can't read boot sector because\n%s", m_pDisk->GetLastError() );
+ delete pE;
+ return NULL;
+ }
+
+ int iSectors = ( ( pE->m_dwFileLen - 0x0E + 0x7F ) / 0x80 );
+ int iStoredSectors = abtSec[ 0x70 ] + ( abtSec[ 0x71 ] << 8 );
+
+ if ( ( iSectors - 1 ) != iStoredSectors )
+ {
+ sprintf( m_szLastError, "BAS2BOOT: Not a Bas2Boot image or invalid! (%d<>%d)", iSectors - 1, iStoredSectors );
+ delete pE;
+ return NULL;
+ }
+
+
+ if ( ( iSectors + 2 ) > m_pDisk->GetSectorCount() )
+ {
+ sprintf( m_szLastError, "BAS2BOOT: Not a Bas2Boot image or invalid! (%d<>%d)", iSectors + 2, m_pDisk->GetSectorCount() );
+ delete pE;
+ return NULL;
+ }
+
+ sprintf( pE->m_szAscData, "%06lX", pE->m_dwFileLen );
+
+ GuessBestFnameFromPC( pE->m_szFname, m_pDisk->GetImageName(), "bas" );
+
+ return pE;
+}
+
+BOOL CBas2Boot::ExportFile( char* szOutFile, CDirEntry* pDirE )
+{
+ int hOutfile = -1;
+
+ if ( szOutFile )
+ {
+ hOutfile = open( szOutFile, O_BINARY | O_CREAT | O_TRUNC | O_WRONLY, 0666 );
+
+ if ( -1 == hOutfile )
+ {
+ sprintf( m_szLastError, "BAS2BOOT: Unable to create file '%s'!", szOutFile );
+ return FALSE;
+ }
+ }
+
+ DWORD dwFileLen = ((CBas2BootDirEntry*)pDirE) ->m_dwFileLen;
+
+ BYTE abtBuff[ 0x80 ];
+
+ int iSector = 3;
+
+ m_pDisk->ReadSector( abtBuff, 2 );
+ if ( -1 != hOutfile )
+ write( hOutfile, abtBuff + 0x72, 0x0E );
+
+ dwFileLen -= 0xE;
+
+ while( dwFileLen )
+ {
+ WORD wToCopy = ( dwFileLen < 0x80 ) ? dwFileLen : 0x80;
+
+ if ( !m_pDisk->ReadSector( abtBuff, iSector ) )
+ {
+ sprintf( m_szLastError, "BAS2BOOT: Can't read sector because\n%s", m_pDisk->GetLastError() );
+ return FALSE;
+ }
+
+ if ( -1 != hOutfile )
+ write( hOutfile, abtBuff, wToCopy );
+
+ dwFileLen -= wToCopy;
+ iSector++;
+
+ }
+ if ( -1 != hOutfile )
+ close( hOutfile );
+
+ return TRUE;
+}
+
diff --git a/jindroush/lib/cfs_boot.cpp b/jindroush/lib/cfs_boot.cpp
new file mode 100644
index 0000000..b1279ac
--- /dev/null
+++ b/jindroush/lib/cfs_boot.cpp
@@ -0,0 +1,128 @@
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+//
+
+#include "cfs_boot.h"
+#include "autil.h"
+#include "adsk_xfd.h"
+
+CBoot::CBoot() : CFs()
+{
+ #ifdef _MEMORY_DUMP_
+ printf( "CBoot constructed: %08X\n", this );
+ #endif
+}
+
+CBoot::~CBoot()
+{
+ Dismount();
+ #ifdef _MEMORY_DUMP_
+ printf( "CBoot destructed: %08X\n", this );
+ #endif
+}
+
+BOOL CBoot::Mount( ADisk* pDisk )
+{
+ m_iFilesValid = 0;
+ m_iFilesInvalid = 0;
+ m_pDisk = pDisk;
+ m_pRoot = NULL;
+
+ m_pRoot = CreateEntry();
+
+ return m_pRoot ? TRUE : FALSE;
+}
+
+void CBoot::Dismount()
+{
+ DeleteList( m_pRoot );
+}
+
+CBootDirEntry* CBoot::CreateEntry()
+{
+ CBootDirEntry* pE = new CBootDirEntry();
+
+ if ( !pE )
+ return NULL;
+
+ pE->m_iSectorCount = m_pDisk->GetBootSectorCount();
+
+ if ( pE->m_iSectorCount > m_pDisk->GetSectorCount() )
+ {
+ sprintf( m_szLastError, "BOOT: Overlaps end of file!" );
+ delete pE;
+ return NULL;
+ }
+
+ sprintf( pE->m_szAscData, "%08X", pE->m_iSectorCount );
+
+ GuessBestFnameFromPC( pE->m_szFname, m_pDisk->GetImageName(), "xfd", "_boot" );
+
+ return pE;
+}
+
+BOOL CBoot::ExportFile( char* szOutFile, CDirEntry* pDirE )
+{
+ if ( !szOutFile )
+ return TRUE;
+
+ CXfd newdisk;
+
+ DISK_GEOMETRY dg;
+
+ int iSecCount = ((CBootDirEntry*)pDirE)->m_iSectorCount;
+
+ dg.iSides = 1;
+ dg.iTracks = 1;
+ dg.iSectorsPerTrack = iSecCount;
+ dg.iBytesPerSector = 0x80;
+
+ if ( !newdisk.Format( &dg ) )
+ {
+ sprintf( m_szLastError, "BOOT: File '%s' can't create because\n%s", szOutFile, newdisk.GetLastError() );
+ return FALSE;
+ }
+
+ int iStartSec = 1;
+ int iCurrSec = 1;
+
+ BYTE abtBuff[ MAX_ATARI_SECTOR_LEN ];
+
+ while( iSecCount )
+ {
+ if( !m_pDisk->ReadSector( abtBuff, iStartSec++ ) )
+ {
+ sprintf( m_szLastError, "BOOT: File '%s' can't create because\n%s", szOutFile, m_pDisk->GetLastError() );
+ return FALSE;
+ }
+
+ if ( !newdisk.WriteSector( iCurrSec++, abtBuff ) )
+ {
+ sprintf( m_szLastError, "BOOT: File '%s' can't create because\n%s", szOutFile, newdisk.GetLastError() );
+ return FALSE;
+ }
+
+ iSecCount--;
+ }
+
+ if ( !newdisk.Save( szOutFile, FALSE ) )
+ {
+ sprintf( m_szLastError, "BOOT: File '%s' can't create because\n%s", szOutFile, newdisk.GetLastError() );
+ return FALSE;
+ }
+
+
+ return TRUE;
+}
+
diff --git a/jindroush/lib/cfs_dos2.cpp b/jindroush/lib/cfs_dos2.cpp
new file mode 100644
index 0000000..81a8037
--- /dev/null
+++ b/jindroush/lib/cfs_dos2.cpp
@@ -0,0 +1,224 @@
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+//
+
+#include "cfs_dos2.h"
+#include "autil.h"
+
+#define ROOT_DIR 361
+
+CDos2::CDos2() : CFs()
+{
+ #ifdef _MEMORY_DUMP_
+ printf( "CDos2 constructed: %08X\n", this );
+ #endif
+}
+
+CDos2::~CDos2()
+{
+ Dismount();
+ #ifdef _MEMORY_DUMP_
+ printf( "CDos2 destructed: %08X\n", this );
+ #endif
+}
+
+BOOL CDos2::Mount( ADisk* pDisk )
+{
+ m_iFilesValid = 0;
+ m_iFilesInvalid = 0;
+
+ m_pDisk = pDisk;
+ m_pRoot = NULL;
+
+ DOS2_DIRENT dire;
+
+ WORD wEntry = 0;
+
+ CDos2DirEntry* pPrev = NULL;
+
+ do
+ {
+ BYTE abtSec[ 0x100 ];
+
+ if ( !m_pDisk->ReadSector( abtSec, ROOT_DIR + ( wEntry / 8 ) ) )
+ {
+ sprintf( m_szLastError, "DOS2: Can't read directory entry %04X because\n%s", wEntry, m_pDisk->GetLastError() );
+ return FALSE;
+ }
+
+ //this is not endian-safe
+ //memcpy( &dire, abtSec + ( wEntry % 8) * sizeof( DOS2_DIRENT ), sizeof( DOS2_DIRENT ) );
+ BYTE* pTmp = abtSec + ( wEntry % 8) * sizeof( DOS2_DIRENT );
+ dire.btFlags = MGET_B( pTmp );
+ dire.wSecCount = MGET_LEW( pTmp );
+ dire.wSecStart = MGET_LEW( pTmp );
+ memcpy( dire.acAtariName, pTmp, 11 );
+
+ if ( !dire.btFlags )
+ break;
+
+ CDos2DirEntry* pE = CreateEntry( &dire, wEntry );
+
+ if ( pE && ! ( pE->m_dwFlags & DIRE_DELETED ) )
+ {
+ if ( m_pRoot )
+ {
+ pPrev->m_pNext = pE;
+ pE->m_pPrev = pPrev;
+ pPrev = pE;
+ }
+ else
+ {
+ m_pRoot = pE;
+ pPrev = pE;
+ }
+
+ }
+
+ wEntry++;
+
+ } while( dire.btFlags && ( wEntry < 64 ) );
+
+ return TRUE;
+}
+
+void CDos2::Dismount()
+{
+ DeleteList( m_pRoot );
+}
+
+CDos2DirEntry* CDos2::CreateEntry( DOS2_DIRENT* pDire, WORD wEntry )
+{
+ CDos2DirEntry* pE = new CDos2DirEntry();
+
+ if ( !pE )
+ {
+ sprintf( m_szLastError, "DOS2: Can't allocate memory for directory!" );
+ return NULL;
+ }
+
+ if ( pDire->btFlags == 0x80 )
+ {
+ pE->m_dwFlags |= DIRE_DELETED;
+ }
+
+ ADos2MsDos( pE->m_szFname, pDire->acAtariName );
+
+ sprintf( pE->m_szAscData, "%02X %04X %04X", pDire->btFlags, pDire->wSecStart, pDire->wSecCount );
+
+ pE->m_wFileNumber = wEntry;
+ pE->m_btFlags = pDire->btFlags;
+ pE->m_wSecStart = pDire->wSecStart;
+ pE->m_wSecCount = pDire->wSecCount;
+
+ if ( pE->m_dwFlags & DIRE_DELETED )
+ {
+ }
+ else if ( ExportFile( NULL, pE ) )
+ m_iFilesValid++;
+ else
+ m_iFilesInvalid++;
+
+ return pE;
+}
+
+BOOL CDos2::ExportFile( char* szOutFile, CDirEntry* pDirE )
+{
+ int hOutfile = -1;
+
+ if ( szOutFile )
+ {
+ hOutfile = open( szOutFile, O_BINARY | O_CREAT | O_TRUNC | O_WRONLY, 0666 );
+
+ if ( -1 == hOutfile )
+ {
+ sprintf( m_szLastError, "DOS2: Unable to create file '%s'!", szOutFile );
+ return FALSE;
+ }
+ }
+
+ BYTE abtBuff[ 0x0100 ];
+
+ WORD wSector = ((CDos2DirEntry*)pDirE ) -> m_wSecStart;
+ WORD wCount = ((CDos2DirEntry*)pDirE ) -> m_wSecCount;
+ WORD wSectorSize = m_pDisk->GetSectorSize();
+ WORD wFileNumber = ((CDos2DirEntry*)pDirE ) -> m_wFileNumber;
+
+ abtBuff[ wSectorSize - 1 ] = 0;
+
+ while( wCount )
+ {
+ if ( wSector < 1 )
+ {
+ sprintf( m_szLastError, "DOS2: Corrupted file '%s' (invalid sector %04X)", szOutFile, wSector );
+ return FALSE;
+ }
+
+ if ( ( abtBuff[ wSectorSize - 1 ] & 0x80 ) && ( wSectorSize == 0x80 ) )
+ {
+ sprintf( m_szLastError, "DOS2: Corrupted file '%s' (unexpected EOF)", szOutFile );
+ return FALSE;
+ }
+
+ if ( !m_pDisk->ReadSector( abtBuff, wSector ) )
+ {
+ sprintf( m_szLastError, "DOS2: Corrupted file '%s'\n%s\n", szOutFile, m_pDisk->GetLastError() );
+ return FALSE;
+ }
+
+ /*
+ if ( -1 != hOutfile )
+ {
+ printf( "%04X/%04X %02X | %02X %02X %02X\n",
+ wSector,
+ wCount,
+ wFileNumber,
+ abtBuff[ wSectorSize - 3 ],
+ abtBuff[ wSectorSize - 2 ],
+ abtBuff[ wSectorSize - 1 ] );
+ }
+ */
+
+ wSector = abtBuff[ wSectorSize - 2 ] + ( 0x03 & abtBuff[ wSectorSize - 3 ] ) * 0x100;
+
+ if ( ( abtBuff[ wSectorSize-3 ] >> 2 ) != wFileNumber )
+ {
+ WORD wFN = abtBuff[ wSectorSize - 3 ] >> 2;
+
+ sprintf( m_szLastError, "DOS2: Corrupted file '%s' (167: file number mismatch [%04X != %04X])", szOutFile, wFileNumber, wFN );
+ return FALSE;
+ }
+
+
+ if ( -1 != hOutfile )
+ write( hOutfile, abtBuff, abtBuff[ wSectorSize - 1 ] );
+
+ wCount--;
+ }
+
+ if ( ((CDos2DirEntry*)pDirE ) -> m_wSecCount )
+ {
+ if ( ! ( abtBuff[ wSectorSize - 1 ] & 128 ) && ( wSectorSize == 128 ) && wSector)
+ {
+ sprintf( m_szLastError, "DOS2: Corrupted file '%s' (expected EOF, code %02X, next sector %04X)", szOutFile, abtBuff[ wSectorSize - 1 ], wSector );
+ return FALSE;
+ }
+ }
+
+ if ( -1 != hOutfile )
+ close( hOutfile );
+
+ return TRUE;
+}
+
diff --git a/jindroush/lib/cfs_dos3.cpp b/jindroush/lib/cfs_dos3.cpp
new file mode 100644
index 0000000..2eca4b2
--- /dev/null
+++ b/jindroush/lib/cfs_dos3.cpp
@@ -0,0 +1,209 @@
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+//
+
+#include "cfs_dos3.h"
+#include "autil.h"
+
+#define ROOT_DIR 0x10
+#define FAT 0x18
+
+CDos3::CDos3() : CFs()
+{
+ #ifdef _MEMORY_DUMP_
+ printf( "CDos3 constructed: %08X\n", this );
+ #endif
+}
+
+CDos3::~CDos3()
+{
+ Dismount();
+ #ifdef _MEMORY_DUMP_
+ printf( "CDos3 destructed: %08X\n", this );
+ #endif
+}
+
+BOOL CDos3::Mount( ADisk* pDisk )
+{
+ m_iFilesValid = 0;
+ m_iFilesInvalid = 0;
+ m_pDisk = pDisk;
+ m_pRoot = NULL;
+
+ if ( m_pDisk->GetSectorSize() != 0x80 )
+ {
+ sprintf( m_szLastError, "DOS3: Can't process DD disk!" );
+ return FALSE;
+ }
+
+ CDos3DirEntry* pPrev = NULL;
+
+ DOS3_DIRENT dire;
+
+ WORD wEntry = 1;
+
+ if ( !pDisk->ReadSector( m_abtFat, FAT ) )
+ {
+ sprintf( m_szLastError, "DOS3: Can't read FAT sector because\n%s", m_pDisk->GetLastError() );
+ return FALSE;
+ }
+
+ do
+ {
+ BYTE abtSec[ 0x100 ];
+
+ if ( !pDisk->ReadSector( abtSec, ROOT_DIR + ( wEntry / 8 ) ) )
+ {
+ sprintf( m_szLastError, "DOS3: Can't read directory entry %04X because\n%s", wEntry, m_pDisk->GetLastError() );
+ return FALSE;
+ }
+
+ memcpy( &dire, abtSec + ( wEntry % 8) * sizeof( DOS3_DIRENT ), sizeof( DOS3_DIRENT ) );
+
+ if ( !dire.btFlags )
+ break;
+
+ CDos3DirEntry* pE = CreateEntry( &dire );
+
+ if ( pE && ! ( pE->m_dwFlags & DIRE_DELETED ) )
+ {
+ if ( m_pRoot )
+ {
+ pPrev->m_pNext = pE;
+ pE->m_pPrev = pPrev;
+ pPrev = pE;
+ }
+ else
+ {
+ m_pRoot = pE;
+ pPrev = pE;
+ }
+
+ }
+
+ wEntry++;
+
+ } while( dire.btFlags );
+
+ return TRUE;
+}
+
+void CDos3::Dismount()
+{
+ DeleteList( m_pRoot );
+}
+
+CDos3DirEntry* CDos3::CreateEntry( DOS3_DIRENT* pDire )
+{
+ CDos3DirEntry* pE = new CDos3DirEntry();
+
+ if ( !pE )
+ return NULL;
+
+ if ( pDire->btFlags == 0x80 )
+ {
+ pE->m_dwFlags |= DIRE_DELETED;
+ }
+
+ ADos2MsDos( pE->m_szFname, pDire->acAtariName );
+
+ //sprintf( pE->m_szAscData, "%02X %02X %02X %04X", pDire->btSecStart, pDire->btSecCount, pDire->btFlags, pDire->wFileLen );
+ sprintf( pE->m_szAscData, "%02X %04X", pDire->btFlags, pDire->wFileLen );
+
+ pE->m_btSecStart = pDire->btSecStart;
+ pE->m_btSecCount = pDire->btSecCount;
+ pE->m_btFlags = pDire->btFlags;
+ pE->m_wFileLen = pDire->wFileLen;
+
+ if ( pE->m_dwFlags & DIRE_DELETED )
+ {
+ }
+ else if ( ExportFile( NULL, pE ) )
+ m_iFilesValid++;
+ else
+ m_iFilesInvalid++;
+
+ return pE;
+}
+
+BOOL CDos3::ExportFile( char* szOutFile, CDirEntry* pDirE )
+{
+ int hOutfile = -1;
+
+ if ( szOutFile )
+ {
+ hOutfile = open( szOutFile, O_BINARY | O_CREAT | O_TRUNC | O_WRONLY, 0666 );
+
+ if ( -1 == hOutfile )
+ {
+ sprintf( m_szLastError, "DOS3: Unable to create file '%s'!", szOutFile );
+ return FALSE;
+ }
+ }
+
+ BYTE abtBuff[ 0x80 * 8 ];
+
+ BYTE btSecCount = ((CDos3DirEntry*)pDirE) ->m_btSecCount;
+ BYTE btSector = ((CDos3DirEntry*)pDirE) ->m_btSecStart;
+ WORD wFileLen = ((CDos3DirEntry*)pDirE) ->m_wFileLen;
+
+ while( btSecCount )
+ {
+ WORD wToCopy = ( wFileLen < 0x400 ) ? wFileLen : 0x400;
+
+ if ( !m_pDisk->ReadSectors( abtBuff, ( btSector * 8 ) + FAT + 1, 8 ) )
+ {
+ {
+ sprintf( m_szLastError, "DOS3: Corrupted file '%s'\n%s\n", szOutFile, m_pDisk->GetLastError() );
+ return FALSE;
+ }
+ }
+
+ if ( -1 != hOutfile )
+ write( hOutfile, abtBuff, wToCopy );
+
+ btSecCount--;
+ wFileLen -= wToCopy;
+
+ btSector = m_abtFat[ btSector ];
+
+ if ( wToCopy == 0x400 )
+ {
+ if ( btSector >= 0xFD )
+ {
+ sprintf( m_szLastError, "DOS3: Corrupted file '%s' (unexpected EOF)", szOutFile );
+ return FALSE;
+ }
+
+ }
+ else
+ {
+ if ( btSector != 0xFD )
+ {
+ sprintf( m_szLastError, "DOS3: Corrupted file '%s' (missed EOF) %02X", szOutFile, btSector );
+ return FALSE;
+ }
+
+ }
+
+
+ }
+
+
+ if ( -1 != hOutfile )
+ close( hOutfile );
+
+ return TRUE;
+}
+
diff --git a/jindroush/lib/cfs_dosm.cpp b/jindroush/lib/cfs_dosm.cpp
new file mode 100644
index 0000000..96c04fb
--- /dev/null
+++ b/jindroush/lib/cfs_dosm.cpp
@@ -0,0 +1,240 @@
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+//
+
+#include "cfs_dosm.h"
+#include "autil.h"
+
+#define ROOT_DIR 361
+
+CDosM::CDosM() : CFs()
+{
+ #ifdef _MEMORY_DUMP_
+ printf( "CDosM constructed: %08X\n", this );
+ #endif
+}
+
+CDosM::~CDosM()
+{
+ Dismount();
+ #ifdef _MEMORY_DUMP_
+ printf( "CDosM destructed: %08X\n", this );
+ #endif
+}
+
+BOOL CDosM::Mount( ADisk* pDisk )
+{
+ m_iFilesValid = 0;
+ m_iFilesInvalid = 0;
+
+ m_pDisk = pDisk;
+ m_pRoot = NULL;
+
+ return ReadDir( ROOT_DIR, (CDosMDirEntry**)&m_pRoot );
+}
+
+BOOL CDosM::ReadDir( int iSector, CDosMDirEntry** ppRoot )
+{
+ DOSM_DIRENT dire;
+
+ WORD wEntry = 0;
+
+ CDosMDirEntry* pPrev = NULL;
+
+ do
+ {
+ BYTE abtSec[ 0x100 ];
+
+ //printf( "reading sec %d\n", iSector + ( wEntry / 8 ) );
+
+ if ( !m_pDisk->ReadSector( abtSec, iSector + ( wEntry / 8 ) ) )
+ {
+ sprintf( m_szLastError, "DOSM: Can't read directory entry %04X because\n%s", wEntry, m_pDisk->GetLastError() );
+ return FALSE;
+ }
+
+ //this is not endian-safe
+ //memcpy( &dire, abtSec + ( wEntry % 8) * sizeof( DOSM_DIRENT ), sizeof( DOSM_DIRENT ) );
+ BYTE* pTmp = abtSec + ( wEntry % 8) * sizeof( DOSM_DIRENT );
+ dire.btFlags = MGET_B( pTmp );
+ dire.wSecCount = MGET_LEW( pTmp );
+ dire.wSecStart = MGET_LEW( pTmp );
+ memcpy( dire.acAtariName, pTmp, 11 );
+
+ //printf( "%p %p %04X %02X\n", pTmp, abtSec, wEntry, dire.btFlags );
+
+ if ( !dire.btFlags )
+ break;
+
+ CDosMDirEntry* pE = CreateEntry( &dire );
+
+ if ( pE && ! ( pE->m_dwFlags & DIRE_DELETED ) )
+ {
+ if ( *ppRoot )
+ {
+ pPrev->m_pNext = pE;
+ pE->m_pPrev = pPrev;
+ pPrev = pE;
+ }
+ else
+ {
+ *ppRoot = pE;
+ pPrev = pE;
+ }
+
+ }
+
+ wEntry++;
+
+ } while( dire.btFlags && ( wEntry < 64 ) );
+
+ return TRUE;
+}
+
+void CDosM::Dismount()
+{
+ DeleteList( m_pRoot );
+}
+
+CDosMDirEntry* CDosM::CreateEntry( DOSM_DIRENT* pDire )
+{
+ CDosMDirEntry* pE = new CDosMDirEntry();
+
+ if ( !pE )
+ {
+ sprintf( m_szLastError, "DOSM: Can't allocate memory for directory!" );
+ return NULL;
+ }
+
+ if ( pDire->btFlags == 0x80 )
+ {
+ pE->m_dwFlags |= DIRE_DELETED;
+ }
+
+ ADos2MsDos( pE->m_szFname, pDire->acAtariName );
+
+ sprintf( pE->m_szAscData, "%02X %04X %04X", pDire->btFlags, pDire->wSecStart, pDire->wSecCount );
+ //printf( "%02X %04X %04X %s\n", pDire->btFlags, pDire->wSecStart, pDire->wSecCount, pE->m_szFname );
+
+ pE->m_btFlags = pDire->btFlags;
+ pE->m_wSecStart = pDire->wSecStart;
+ pE->m_wSecCount = pDire->wSecCount;
+
+ if ( pDire->btFlags == 0x10 )
+ {
+ pE->m_dwFlags |= DIRE_SUBDIR;
+
+ BOOL bRes = ReadDir( pE->m_wSecStart, (CDosMDirEntry**)&pE->m_pSubdir );
+
+ if ( !bRes )
+ return NULL;
+ }
+ else
+ {
+ if ( pE->m_dwFlags & DIRE_DELETED )
+ {
+ }
+ else if ( ExportFile( NULL, pE ) )
+ {
+ m_iFilesValid++;
+ }
+ else
+ {
+ m_iFilesInvalid++;
+ }
+ }
+
+ return pE;
+}
+
+BOOL CDosM::ExportFile( char* szOutFile, CDirEntry* pDirE )
+{
+ int hOutfile = -1;
+
+ if ( szOutFile )
+ {
+ hOutfile = open( szOutFile, O_BINARY | O_CREAT | O_TRUNC | O_WRONLY, 0666 );
+
+ if ( -1 == hOutfile )
+ {
+ sprintf( m_szLastError, "DOSM: Unable to create file '%s'!", szOutFile );
+ return FALSE;
+ }
+ }
+
+ BYTE abtBuff[ 0x0100 ];
+
+ WORD wSector = ((CDosMDirEntry*)pDirE ) -> m_wSecStart;
+ WORD wCount = ((CDosMDirEntry*)pDirE ) -> m_wSecCount;
+ WORD wSectorSize = m_pDisk->GetSectorSize();
+
+ abtBuff[ wSectorSize - 1 ] = 0;
+
+ while( wCount )
+ {
+ if ( wSector < 1 )
+ {
+ sprintf( m_szLastError, "DOSM: Corrupted file '%s' (invalid sector %04X)", szOutFile, wSector );
+ return FALSE;
+ }
+
+ if ( ( abtBuff[ wSectorSize - 1 ] & 0x80 ) && ( wSectorSize == 0x80 ) )
+ {
+ sprintf( m_szLastError, "DOSM: Corrupted file '%s' (unexpected EOF)", szOutFile );
+ return FALSE;
+ }
+
+ if ( !m_pDisk->ReadSector( abtBuff, wSector ) )
+ {
+ sprintf( m_szLastError, "DOSM: Corrupted file '%s'\n%s\n", szOutFile, m_pDisk->GetLastError() );
+ return FALSE;
+ }
+
+// if ( -1 != hOutfile )
+// {
+// printf( "%04X/%04X | %02X %02X %02X\n",
+// wSector,
+// wCount,
+// abtBuff[ wSectorSize - 3 ],
+// abtBuff[ wSectorSize - 2 ],
+// abtBuff[ wSectorSize - 1 ] );
+// }
+
+ //originally, there was 0x07 as a mask, but megaimages were not working with it
+ if ( m_pDisk->GetSectorCount() > 943 )
+ wSector = abtBuff[ wSectorSize - 2 ] + ( (WORD)abtBuff[ wSectorSize - 3 ] & 0xff ) * 0x100;
+ else
+ wSector = abtBuff[ wSectorSize - 2 ] + ( 0x03 & (WORD)abtBuff[ wSectorSize - 3 ] ) * 0x100;
+
+ if ( -1 != hOutfile )
+ write( hOutfile, abtBuff, abtBuff[ wSectorSize - 1 ] );
+
+ wCount--;
+ }
+
+ if ( ((CDosMDirEntry*)pDirE ) -> m_wSecCount )
+ {
+ if ( ! ( abtBuff[ wSectorSize - 1 ] & 128 ) && ( wSectorSize == 128 ) && wSector)
+ {
+ sprintf( m_szLastError, "DOSM: Corrupted file '%s' (expected EOF, code %02X, next sector %04X)", szOutFile, abtBuff[ wSectorSize - 1 ], wSector );
+ return FALSE;
+ }
+ }
+
+ if ( -1 != hOutfile )
+ close( hOutfile );
+
+ return TRUE;
+}
+
diff --git a/jindroush/lib/cfs_doss.cpp b/jindroush/lib/cfs_doss.cpp
new file mode 100644
index 0000000..42092ec
--- /dev/null
+++ b/jindroush/lib/cfs_doss.cpp
@@ -0,0 +1,383 @@
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+//
+
+#include "cfs_doss.h"
+#include "autil.h"
+
+#define SP3TOLONG(dire) ( ( dire.btSizeHi << 16 ) + dire.wSizeLo )
+
+CDosS::CDosS() : CFs()
+{
+ #ifdef _MEMORY_DUMP_
+ printf( "CDosS constructed: %08X\n", this );
+ #endif
+}
+
+CDosS::~CDosS()
+{
+ Dismount();
+ #ifdef _MEMORY_DUMP_
+ printf( "CDosS destructed: %08X\n", this );
+ #endif
+}
+
+BOOL CDosS::Mount( ADisk* pDisk )
+{
+ m_iFilesValid = 0;
+ m_iFilesInvalid = 0;
+
+ m_pDisk = pDisk;
+ m_pRoot = NULL;
+
+ if ( m_pDisk->GetBootSectorCount() != 3 )
+ {
+ sprintf( m_szLastError, "DOSS: Strange boot sector!" );
+ return FALSE;
+ }
+
+ int iSize = m_pDisk->GetBootSectorSize();
+
+ BYTE* pBoot = new BYTE [ iSize ];
+
+ if ( !pBoot )
+ {
+ sprintf( m_szLastError, "DOSS: Not enough memory to allocate boot sector!" );
+ return FALSE;
+ }
+
+ if ( !m_pDisk->GetBootSector( pBoot ) )
+ {
+ sprintf( m_szLastError, "DOSS: Can't read boot sector because\n%s", m_pDisk->GetLastError() );
+ delete [] pBoot;
+ return FALSE;
+ }
+
+ BYTE btSpDosIdent = pBoot[ 7 ];
+
+ if ( btSpDosIdent != 0x80 )
+ {
+ sprintf( m_szLastError, "DOSS: Mismatched boot." );
+ delete [] pBoot;
+ return FALSE;
+ }
+
+ m_wMainDirStart = pBoot[ 9 ] + ( pBoot[ 10 ] << 8 );
+ //WORD wSectors = pBoot[ 11 ] + ( pBoot[ 12 ] << 8 );
+ //WORD wFreeSectors = pBoot[ 13 ] + ( pBoot[ 14 ] << 8 );
+ //BYTE btBitmapSectors = pBoot[ 15 ];
+ //WORD wFirstBitmapSector = pBoot[ 16 ] + ( pBoot[ 17 ] << 8 );
+ //WORD wFreeDataSector = pBoot[ 18 ] + ( pBoot[ 19 ] << 8 );
+ //WORD wFreeDirSector = pBoot[ 20 ] + ( pBoot[ 21 ] << 8 );
+ //22-29 volume name
+
+ switch( pBoot[ 31 ] )
+ {
+ case 0:
+ m_wSectorSize = 0x100;
+ break;
+
+ case 0x80:
+ m_wSectorSize = 0x80;
+ break;
+
+ default:
+ {
+ sprintf( m_szLastError, "DOSS: Unknown sector size %02X!", pBoot[ 31 ] );
+ delete [] pBoot;
+ return FALSE;
+ }
+
+ }
+
+ //BYTE btVersion = pBoot[ 32 ];
+ //BYTE btSeqNumber = pBoot[ 38 ];
+ //BYTE btRndNumber = pBoot[ 39 ];
+ //WORD wDosBootStart = pBoot[ 40 ] + ( pBoot[ 41 ] << 8 );
+
+ delete [] pBoot;
+
+ return ReadDir( m_wMainDirStart, (CDosSDirEntry**)&m_pRoot );
+}
+
+int CDosS::GetSectorLinkEntry( int iLink, int iSec )
+{
+ WORD awSector[ 0x80 ];
+
+ int iCurrLink = iLink;
+
+ int iDivisor = 0;
+ switch( m_wSectorSize )
+ {
+ case 0x80:
+ iDivisor = 0x3E;
+ break;
+
+ case 0x100:
+ iDivisor = 0x7E;
+ break;
+
+ default:
+ return 0;
+
+ }
+
+ int iSecNeeded = ( iSec / iDivisor ) + 1;
+
+ do
+ {
+ if ( !m_pDisk->ReadSector( awSector, iCurrLink ) )
+ {
+ sprintf( m_szLastError, "DOSS: Can't read link sector because\n%s", m_pDisk->GetLastError() );
+ return 0;
+ }
+
+ iSecNeeded--;
+ //not endian-safe
+ //iCurrLink = awSector[ 0 ];
+ iCurrLink = MREAD_LEW( (BYTE*)awSector );
+ if ( iSec >= iDivisor )
+ iSec -= iDivisor;
+
+ } while( iSecNeeded );
+
+ //not endian-safe
+ //return awSector[ iSec + 2 ];
+ return MREAD_LEW( (BYTE*)(awSector + iSec + 2 ));
+}
+
+BOOL CDosS::ReadDir( int iSectorLink, CDosSDirEntry** ppRoot )
+{
+ DOSS_DIRENT dire;
+
+ BYTE abtSector[ 0x100 ];
+
+ int iSector = GetSectorLinkEntry( iSectorLink, 0 );
+
+ if ( !m_pDisk->ReadSector( abtSector, iSector ) )
+ {
+ sprintf( m_szLastError, "DOSS: Can't read dir because\n%s", m_pDisk->GetLastError() );
+ return FALSE;
+ }
+
+ //not endian safe
+ //memcpy( &dire, abtSector, sizeof( DOSS_DIRENT ) );
+ BYTE* pTmp = abtSector;
+ dire.btFlags = MGET_B( pTmp );
+ dire.wSector = MGET_LEW( pTmp );
+ dire.wSizeLo = MGET_LEW( pTmp );
+ dire.btSizeHi = MGET_B( pTmp );
+ memcpy( dire.acAtariName, pTmp, 11 ); pTmp+= 11;
+ memcpy( &dire.btDay, pTmp, 6 ); //dirty hack, copying last 6 byte values
+
+ int iDirLen = SP3TOLONG( dire );
+ BYTE* pDir = MapFile( iSectorLink, iDirLen );
+ if ( !pDir )
+ return FALSE;
+
+ int iEntries = iDirLen / sizeof( DOSS_DIRENT );
+
+ //if ( iDirLen != iEntries * (int)sizeof( DOSS_DIRENT ) )
+ //{
+ // UnMapFile( pDir );
+ // sprintf( m_szLastError, "DOSS: Dir size mismatch! (%04X<>%04X)\n",
+ // iDirLen,
+ // iEntries * (int)sizeof( DOSS_DIRENT )
+ // );
+ // return FALSE;
+ //}
+
+ CDosSDirEntry* pPrev = NULL;
+
+ for( int i = 1; i < iEntries; i++ )
+ {
+
+ DOSS_DIRENT dire2;
+ BYTE* pTmp = pDir + i * sizeof( DOSS_DIRENT );
+ dire2.btFlags = MGET_B( pTmp );
+ dire2.wSector = MGET_LEW( pTmp );
+ dire2.wSizeLo = MGET_LEW( pTmp );
+ dire2.btSizeHi = MGET_B( pTmp );
+ memcpy( dire2.acAtariName, pTmp, 11 ); pTmp+= 11;
+ memcpy( &dire2.btDay, pTmp, 6 ); //dirty hack, copying last 6 byte values
+
+ CDosSDirEntry* pE = CreateEntry( &dire2 );
+
+ if ( pE && ! ( pE->m_dwFlags & DIRE_DELETED ) )
+ {
+ if ( *ppRoot )
+ {
+ pPrev->m_pNext = pE;
+ pE->m_pPrev = pPrev;
+ pPrev = pE;
+ }
+ else
+ {
+ *ppRoot = pE;
+ pPrev = pE;
+ }
+
+ }
+
+ }
+
+ UnMapFile( pDir );
+
+ return TRUE;
+}
+
+void CDosS::Dismount()
+{
+ DeleteList( m_pRoot );
+}
+
+CDosSDirEntry* CDosS::CreateEntry( DOSS_DIRENT* pDire )
+{
+ CDosSDirEntry* pE = new CDosSDirEntry();
+
+ if ( !pE )
+ {
+ sprintf( m_szLastError, "DOSS: Can't allocate memory for directory!" );
+ return NULL;
+ }
+
+ ADos2MsDos( pE->m_szFname, pDire->acAtariName );
+
+ sprintf( pE->m_szAscData, "%02X %04X %02X%04X %02d-%02d-19%02d %2d:%02d.%02d",
+ pDire->btFlags,
+ pDire->wSector,
+ pDire->btSizeHi,
+ pDire->wSizeLo,
+ pDire->btMonth,
+ pDire->btDay,
+ pDire->btYear,
+ pDire->btHour,
+ pDire->btMinute,
+ pDire->btSecond
+ );
+
+ pE->m_iLength = ( pDire->btSizeHi << 16 ) + pDire->wSizeLo;
+ pE->m_iLinkSector = pDire->wSector;
+
+ if ( pDire->btFlags == 0x10 )
+ {
+ pE->m_dwFlags |= DIRE_DELETED;
+ }
+
+ if ( ! ( pDire->btFlags && 0x08 ) )
+ {
+ pE->m_dwFlags |= DIRE_DELETED;
+ }
+
+ if ( pDire->btFlags & 0x20 )
+ {
+ pE->m_dwFlags |= DIRE_SUBDIR;
+
+ BOOL bRes = ReadDir( pE->m_iLinkSector, (CDosSDirEntry**)&pE->m_pSubdir );
+
+ if ( !bRes )
+ {
+ delete pE;
+ return NULL;
+ }
+ }
+ else
+ {
+ if ( pE->m_dwFlags & DIRE_DELETED )
+ {
+ }
+ else if ( ExportFile( NULL, pE ) )
+ m_iFilesValid++;
+ else
+ m_iFilesInvalid++;
+ }
+
+ return pE;
+}
+
+BOOL CDosS::ExportFile( char* szOutFile, CDirEntry* pDirE )
+{
+ int hOutfile = -1;
+
+ if ( szOutFile )
+ {
+ hOutfile = open( szOutFile, O_BINARY | O_CREAT | O_TRUNC | O_WRONLY, 0666 );
+
+ if ( -1 == hOutfile )
+ {
+ sprintf( m_szLastError, "DOSS: Unable to create file '%s'!", szOutFile );
+ return FALSE;
+ }
+ }
+
+ int iLinkSector = ((CDosSDirEntry*)pDirE ) -> m_iLinkSector;
+ int iLength = ((CDosSDirEntry*)pDirE ) -> m_iLength;
+
+ BYTE* pDir = MapFile( iLinkSector, iLength );
+
+ if ( !pDir )
+ {
+ return FALSE;
+ }
+
+ if ( -1 != hOutfile )
+ write( hOutfile, pDir, iLength );
+
+ UnMapFile( pDir );
+
+ if ( -1 != hOutfile )
+ close( hOutfile );
+
+ return TRUE;
+}
+
+BYTE* CDosS::MapFile( int iLinkSector, int iLength )
+{
+ BYTE* pBuff = new BYTE [ iLength ];
+
+ if ( !pBuff )
+ return NULL;
+
+ int iLogSector = 0;
+
+ BYTE abtBuff[ 0x100 ];
+ BYTE * p = pBuff;
+
+ while( iLength )
+ {
+ int iToCopy = ( iLength > m_wSectorSize ) ? m_wSectorSize : iLength;
+
+ int iSector = GetSectorLinkEntry( iLinkSector, iLogSector );
+
+ if ( !m_pDisk->ReadSector( abtBuff, iSector ) )
+ {
+ sprintf( m_szLastError, "DOSS: Can't read file sector because\n%s", m_pDisk->GetLastError() );
+ delete [] pBuff;
+ return 0;
+ }
+
+ memcpy( p, abtBuff, iToCopy );
+ iLength -= iToCopy;
+ p += iToCopy;
+ iLogSector++;
+ }
+
+ return pBuff;
+}
+
+void CDosS::UnMapFile( BYTE * pBuff )
+{
+ if ( pBuff )
+ delete [] pBuff;
+}
diff --git a/jindroush/lib/cfs_howf.cpp b/jindroush/lib/cfs_howf.cpp
new file mode 100644
index 0000000..2fa71ae
--- /dev/null
+++ b/jindroush/lib/cfs_howf.cpp
@@ -0,0 +1,209 @@
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+//
+
+#include "cfs_howf.h"
+#include "autil.h"
+#include "adsk_atr.h"
+
+#define HOWF_MAX_NAME 32
+#define HOWF_REASONABLE_NAME ( HOWF_MAX_NAME - 7 )
+
+CHowf::CHowf() : CFs()
+{
+ #ifdef _MEMORY_DUMP_
+ printf( "CHowf constructed: %08X\n", this );
+ #endif
+}
+
+CHowf::~CHowf()
+{
+ Dismount();
+ #ifdef _MEMORY_DUMP_
+ printf( "CHowf destructed: %08X\n", this );
+ #endif
+}
+
+BOOL CHowf::Mount( ADisk* pDisk )
+{
+ m_iFilesValid = 0;
+ m_iFilesInvalid = 0;
+ m_pDisk = pDisk;
+ m_pRoot = NULL;
+
+ if ( m_pDisk->GetSectorSize() != 0x80 )
+ {
+ sprintf( m_szLastError, "HOWF: Can't process DD disk!" );
+ return FALSE;
+ }
+
+ switch( m_pDisk->GetBootSectorCount() )
+ {
+ case 0x0A:
+ break;
+
+ default:
+ {
+ sprintf( m_szLastError, "HOWF: Can't identify disk as a HowFen menu!" );
+ return FALSE;
+ }
+ }
+
+ CHowfDirEntry* pPrev = NULL;
+
+ BYTE abtSec[ 0xA * 0x80 ];
+
+ if ( !m_pDisk->ReadSectors( abtSec, 0x1, 0xA ) )
+ {
+ sprintf( m_szLastError, "HOWF: Can't read directory because\n%s", m_pDisk->GetLastError() );
+ return FALSE;
+ }
+
+ BYTE* pbtName = abtSec + 0x89;
+ BYTE* abtStartSecLo = abtSec + 0x32A;
+ BYTE* abtStartSecHi = abtSec + 0x33E;
+
+ BYTE btRecords = abtSec[ 0x329 ];
+
+ for( int i = 0; i < btRecords; i++ )
+ {
+ WORD wStartSec = *abtStartSecLo + ( *abtStartSecHi << 8 );
+
+ if ( !wStartSec )
+ break;
+
+ CHowfDirEntry* pE = CreateEntry( wStartSec, pbtName );
+
+ if ( m_pRoot )
+ {
+ pPrev->m_pNext = pE;
+ pE->m_pPrev = pPrev;
+ pPrev = pE;
+ }
+ else
+ {
+ m_pRoot = pE;
+ pPrev = pE;
+ }
+
+ abtStartSecLo++;
+ abtStartSecHi++;
+ pbtName += HOWF_MAX_NAME;
+ }
+
+ return TRUE;
+}
+
+void CHowf::Dismount()
+{
+ DeleteList( m_pRoot );
+}
+
+CHowfDirEntry* CHowf::CreateEntry( WORD wStartSec, BYTE* btName )
+{
+ CHowfDirEntry* pE = new CHowfDirEntry();
+
+ if ( !pE )
+ return NULL;
+
+ pE->m_iStartSec = wStartSec;
+
+ sprintf( pE->m_szAscData, "%04X", wStartSec );
+
+ char szTemp[ HOWF_REASONABLE_NAME + 1 ];
+ memcpy( szTemp, (char*)btName + 3, HOWF_REASONABLE_NAME );
+ szTemp[ HOWF_REASONABLE_NAME ] = '\0';
+
+ for( int i = 0; i < HOWF_REASONABLE_NAME; i++ )
+ {
+ char c = szTemp[ i ];
+ if ( ( c >= 0x00 ) && ( c <= 0x40 ) )
+ c += 0x20;
+
+ szTemp[ i ] = c;
+ }
+
+ GuessBestFnameFromAtari( pE->m_szFname, szTemp, "atr" );
+
+ if ( ExportFile( NULL, pE ) )
+ m_iFilesValid++;
+ else
+ m_iFilesInvalid++;
+
+ return pE;
+}
+
+BOOL CHowf::ExportFile( char* szOutFile, CDirEntry* pDirE )
+{
+ int iSecCount;
+ int iStartSec = ((CHowfDirEntry*)pDirE) ->m_iStartSec;
+
+ BYTE abtBuff[ 0x80 ];
+
+ m_pDisk->ReadSector( abtBuff, iStartSec );
+
+ iSecCount = abtBuff[1];
+
+ if ( ( iStartSec + iSecCount - 1 ) > m_pDisk->GetSectorCount() )
+ {
+ sprintf( m_szLastError, "HOWF: File '%s' goes past last sector!", szOutFile );
+ return FALSE;
+ }
+
+ if ( !szOutFile )
+ return TRUE;
+
+ CAtr newdisk;
+
+ DISK_GEOMETRY dg;
+
+ dg.iSides = 1;
+ dg.iTracks = 1;
+ dg.iSectorsPerTrack = iSecCount;
+ dg.iBytesPerSector = 0x80;
+
+ if ( !newdisk.Format( &dg ) )
+ {
+ sprintf( m_szLastError, "HOWF: File '%s' can't create because\n%s", szOutFile, newdisk.GetLastError() );
+ return FALSE;
+ }
+
+ int iCurrSec = 1;
+
+ while( iSecCount )
+ {
+ if( !m_pDisk->ReadSector( abtBuff, iStartSec++ ) )
+ {
+ sprintf( m_szLastError, "HOWF: File '%s' can't create because\n%s", szOutFile, m_pDisk->GetLastError() );
+ return FALSE;
+ }
+
+ if ( !newdisk.WriteSector( iCurrSec++, abtBuff ) )
+ {
+ sprintf( m_szLastError, "HOWF: File '%s' can't create because\n%s", szOutFile, newdisk.GetLastError() );
+ return FALSE;
+ }
+
+ iSecCount--;
+ }
+
+ if ( !newdisk.Save( szOutFile, FALSE ) )
+ {
+ sprintf( m_szLastError, "HOWF: File '%s' can't create because\n%s", szOutFile, newdisk.GetLastError() );
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
diff --git a/jindroush/lib/cfs_jonw.cpp b/jindroush/lib/cfs_jonw.cpp
new file mode 100644
index 0000000..6517bee
--- /dev/null
+++ b/jindroush/lib/cfs_jonw.cpp
@@ -0,0 +1,204 @@
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+//
+
+#include "cfs_jonw.h"
+#include "autil.h"
+#include "adsk_atr.h"
+
+#define JONW_MAX_NAME 20
+
+CJonw::CJonw() : CFs()
+{
+ #ifdef _MEMORY_DUMP_
+ printf( "CJonw constructed: %08X\n", this );
+ #endif
+}
+
+CJonw::~CJonw()
+{
+ Dismount();
+ #ifdef _MEMORY_DUMP_
+ printf( "CJonw destructed: %08X\n", this );
+ #endif
+}
+
+BOOL CJonw::Mount( ADisk* pDisk )
+{
+ m_iFilesValid = 0;
+ m_iFilesInvalid = 0;
+ m_pDisk = pDisk;
+ m_pRoot = NULL;
+
+ if ( m_pDisk->GetSectorSize() != 0x80 )
+ {
+ sprintf( m_szLastError, "JONW: Can't process DD disk!" );
+ return FALSE;
+ }
+
+ switch( m_pDisk->GetBootSectorCount() )
+ {
+ case 0x28:
+ case 0x29:
+ case 0x2F:
+ break;
+
+ default:
+ {
+ sprintf( m_szLastError, "JONW: Can't identify disk as a JonW menu!" );
+ return FALSE;
+ }
+ }
+
+ CJonwDirEntry* pPrev = NULL;
+
+ BYTE abtSec[ 0x100 ];
+
+ if ( !m_pDisk->ReadSectors( abtSec, 0x30, 2 ) )
+ {
+ sprintf( m_szLastError, "JONW: Can't read directory because\n%s", m_pDisk->GetLastError() );
+ return FALSE;
+ }
+
+ BYTE* abtSecCounts = abtSec;
+ BYTE* abtStartSecLo = abtSec + 10;
+ BYTE* abtStartSecHi = abtSec + 20;
+ BYTE* pbtName = abtSec + 30;
+
+ for( int i = 0; i < 10; i++ )
+ {
+ if ( ! *abtSecCounts )
+ break;
+
+ CJonwDirEntry* pE = CreateEntry( *abtSecCounts, *abtStartSecLo + ( *abtStartSecHi << 8 ), pbtName );
+
+ if ( m_pRoot )
+ {
+ pPrev->m_pNext = pE;
+ pE->m_pPrev = pPrev;
+ pPrev = pE;
+ }
+ else
+ {
+ m_pRoot = pE;
+ pPrev = pE;
+ }
+
+ abtSecCounts++;
+ abtStartSecLo++;
+ abtStartSecHi++;
+ pbtName += JONW_MAX_NAME;
+ }
+
+ return TRUE;
+}
+
+void CJonw::Dismount()
+{
+ DeleteList( m_pRoot );
+}
+
+CJonwDirEntry* CJonw::CreateEntry( BYTE btSecCount, WORD wStartSec, BYTE* btName )
+{
+ CJonwDirEntry* pE = new CJonwDirEntry();
+
+ if ( !pE )
+ return NULL;
+
+ pE->m_iStartSec = wStartSec;
+ pE->m_iSecCount = btSecCount;
+
+ sprintf( pE->m_szAscData, "%04X %02X", wStartSec, btSecCount );
+
+ char szTemp[ 21 ];
+ strncpy( szTemp, (char*)btName, 20 );
+ szTemp[ 20 ] = '\0';
+
+ GuessBestFnameFromAtari( pE->m_szFname, szTemp, "atr" );
+
+ if ( ExportFile( NULL, pE ) )
+ m_iFilesValid++;
+ else
+ m_iFilesInvalid++;
+
+ return pE;
+}
+
+BOOL CJonw::ExportFile( char* szOutFile, CDirEntry* pDirE )
+{
+ int iSecCount = ((CJonwDirEntry*)pDirE) ->m_iSecCount;
+ int iStartSec = ((CJonwDirEntry*)pDirE) ->m_iStartSec;
+
+ BYTE abtBuff[ 0x80 ];
+
+ if ( ( iStartSec + iSecCount - 1 ) > m_pDisk->GetSectorCount() )
+ {
+ sprintf( m_szLastError, "JONW: File '%s' goes past last sector!", szOutFile );
+ return FALSE;
+ }
+
+ m_pDisk->ReadSector( abtBuff, iStartSec );
+
+ if ( abtBuff[ 1 ] != iSecCount )
+ {
+ sprintf( m_szLastError, "JONW: File '%s' Mismatched length (%d<>%d)!", szOutFile, abtBuff[ 1 ], iSecCount );
+ return FALSE;
+ }
+
+ if ( !szOutFile )
+ return TRUE;
+
+ CAtr newdisk;
+
+ DISK_GEOMETRY dg;
+
+ dg.iSides = 1;
+ dg.iTracks = 1;
+ dg.iSectorsPerTrack = iSecCount;
+ dg.iBytesPerSector = 0x80;
+
+ if ( !newdisk.Format( &dg ) )
+ {
+ sprintf( m_szLastError, "JONW: File '%s' can't create because\n%s", szOutFile, newdisk.GetLastError() );
+ return FALSE;
+ }
+
+ int iCurrSec = 1;
+
+ while( iSecCount )
+ {
+ if( !m_pDisk->ReadSector( abtBuff, iStartSec++ ) )
+ {
+ sprintf( m_szLastError, "JONW: File '%s' can't create because\n%s", szOutFile, m_pDisk->GetLastError() );
+ return FALSE;
+ }
+
+ if ( !newdisk.WriteSector( iCurrSec++, abtBuff ) )
+ {
+ sprintf( m_szLastError, "JONW: File '%s' can't create because\n%s", szOutFile, newdisk.GetLastError() );
+ return FALSE;
+ }
+
+ iSecCount--;
+ }
+
+ if ( !newdisk.Save( szOutFile, FALSE ) )
+ {
+ sprintf( m_szLastError, "JONW: File '%s' can't create because\n%s", szOutFile, newdisk.GetLastError() );
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
diff --git a/jindroush/lib/cfs_kboo.cpp b/jindroush/lib/cfs_kboo.cpp
new file mode 100644
index 0000000..526e9a6
--- /dev/null
+++ b/jindroush/lib/cfs_kboo.cpp
@@ -0,0 +1,148 @@
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+//
+
+#include "cfs_kboo.h"
+#include "autil.h"
+
+CKBoot::CKBoot() : CFs()
+{
+ #ifdef _MEMORY_DUMP_
+ printf( "CKBoot constructed: %08X\n", this );
+ #endif
+}
+
+CKBoot::~CKBoot()
+{
+ Dismount();
+ #ifdef _MEMORY_DUMP_
+ printf( "CKBoot destructed: %08X\n", this );
+ #endif
+}
+
+BOOL CKBoot::Mount( ADisk* pDisk )
+{
+ m_iFilesValid = 0;
+ m_iFilesInvalid = 0;
+ m_pDisk = pDisk;
+ m_pRoot = NULL;
+
+ if ( m_pDisk->GetSectorSize() != 0x80 )
+ {
+ sprintf( m_szLastError, "KBOOT: Can't process DD disk!" );
+ return FALSE;
+ }
+
+ m_pRoot = CreateEntry();
+
+ return m_pRoot ? TRUE : FALSE;
+}
+
+void CKBoot::Dismount()
+{
+ DeleteList( m_pRoot );
+}
+
+CKBootDirEntry* CKBoot::CreateEntry()
+{
+ CKBootDirEntry* pE = new CKBootDirEntry();
+
+ if ( !pE )
+ return NULL;
+
+ BYTE abtSec[ 0x100 ];
+
+ if ( !m_pDisk->ReadSector( abtSec, 1 ) )
+ {
+ sprintf( m_szLastError, "KBOOT: Can't read boot sector because\n%s", m_pDisk->GetLastError() );
+ delete pE;
+ return NULL;
+ }
+
+ pE->m_dwFileLen = abtSec[ 9 ] + ( abtSec[ 10 ] << 8 ) + ( abtSec[ 11 ] << 16 );
+
+ if ( !m_pDisk->ReadSector( abtSec, 4 ) )
+ {
+ sprintf( m_szLastError, "KBOOT: Can't read first post boot sector because\n%s", m_pDisk->GetLastError() );
+ delete pE;
+ return NULL;
+ }
+
+ if ( ( abtSec[ 0 ] != 0xFF ) || ( abtSec[ 1 ] != 0xFF ) )
+ {
+ sprintf( m_szLastError, "KBOOT: Not a KBoot image!" );
+ delete pE;
+ return NULL;
+ }
+
+ int iSectors = 3 + ( ( pE->m_dwFileLen + 0x7F ) / 0x80 );
+
+ if ( iSectors > m_pDisk->GetSectorCount() )
+ {
+ sprintf( m_szLastError, "KBOOT: Not a KBoot image or invalid! (%d<>%d)", iSectors, m_pDisk->GetSectorCount() );
+ delete pE;
+ return NULL;
+ }
+
+ sprintf( pE->m_szAscData, "%06lX", pE->m_dwFileLen );
+
+ GuessBestFnameFromPC( pE->m_szFname, m_pDisk->GetImageName(), "axe" );
+
+ return pE;
+}
+
+BOOL CKBoot::ExportFile( char* szOutFile, CDirEntry* pDirE )
+{
+ int hOutfile = -1;
+
+ if ( szOutFile )
+ {
+ hOutfile = open( szOutFile, O_BINARY | O_CREAT | O_TRUNC | O_WRONLY, 0666 );
+
+ if ( -1 == hOutfile )
+ {
+ sprintf( m_szLastError, "KBOOT: Unable to create file '%s'!", szOutFile );
+ return FALSE;
+ }
+ }
+
+ DWORD dwFileLen = ((CKBootDirEntry*)pDirE) ->m_dwFileLen;
+
+ BYTE abtBuff[ 0x80 ];
+
+ int iSector = 4;
+
+ while( dwFileLen )
+ {
+ WORD wToCopy = ( dwFileLen < 0x80 ) ? dwFileLen : 0x80;
+
+ if ( !m_pDisk->ReadSector( abtBuff, iSector ) )
+ {
+ sprintf( m_szLastError, "KBOOT: Can't read sector because\n%s", m_pDisk->GetLastError() );
+ return FALSE;
+ }
+
+ if ( -1 != hOutfile )
+ write( hOutfile, abtBuff, wToCopy );
+
+ dwFileLen -= wToCopy;
+ iSector++;
+
+ }
+ if ( -1 != hOutfile )
+ close( hOutfile );
+
+ return TRUE;
+}
+
diff --git a/jindroush/lib/cfs_robc.cpp b/jindroush/lib/cfs_robc.cpp
new file mode 100644
index 0000000..089b4bc
--- /dev/null
+++ b/jindroush/lib/cfs_robc.cpp
@@ -0,0 +1,231 @@
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+//
+
+#include "cfs_robc.h"
+#include "autil.h"
+#include "adsk_atr.h"
+
+#define ROBC_MAX_NAME 20
+
+CRobc::CRobc() : CFs()
+{
+ #ifdef _MEMORY_DUMP_
+ printf( "CRobc constructed: %08X\n", this );
+ #endif
+}
+
+CRobc::~CRobc()
+{
+ Dismount();
+ #ifdef _MEMORY_DUMP_
+ printf( "CRobc destructed: %08X\n", this );
+ #endif
+}
+
+BOOL CRobc::Mount( ADisk* pDisk )
+{
+ m_iFilesValid = 0;
+ m_iFilesInvalid = 0;
+ m_pDisk = pDisk;
+ m_pRoot = NULL;
+
+ if ( m_pDisk->GetSectorSize() != 0x80 )
+ {
+ sprintf( m_szLastError, "ROBC: Can't process DD disk!" );
+ return FALSE;
+ }
+
+ switch( m_pDisk->GetBootSectorCount() )
+ {
+ case 0x04:
+ break;
+
+ default:
+ {
+ sprintf( m_szLastError, "ROBC: Can't identify disk as a RobC menu!" );
+ return FALSE;
+ }
+ }
+
+ CRobcDirEntry* pPrev = NULL;
+
+ BYTE abtSec[ 0x180 ];
+
+ if ( !m_pDisk->ReadSectors( abtSec, 0x02, 3 ) )
+ {
+ sprintf( m_szLastError, "ROBC: Can't read directory because\n%s", m_pDisk->GetLastError() );
+ return FALSE;
+ }
+
+ BYTE* abtStartSecLo = abtSec + 0x77;
+ BYTE* abtStartSecHi = abtSec + 0x6E;
+ BYTE* pbtName = abtSec + 0xB9;
+
+ for( int i = 0; i < 10; i++ )
+ {
+ WORD wSec = *abtStartSecLo + ( *abtStartSecHi << 8 );
+
+ //printf( "%d) %04X\n", i, wSec );
+
+ if ( ! wSec )
+ continue;
+
+ BYTE abtLocSec[ 0x80 ];
+ BYTE btSecCount;
+
+ if( !m_pDisk->ReadSector( abtLocSec, wSec ) )
+ {
+ sprintf( m_szLastError, "ROBC: Can't read dir entry %d!", i );
+ return FALSE;
+ }
+
+ btSecCount = abtLocSec[ 1 ];
+
+ if ( ! btSecCount )
+ break;
+
+ CRobcDirEntry* pE = CreateEntry( btSecCount, wSec, pbtName + 2 );
+
+ if ( m_pRoot )
+ {
+ pPrev->m_pNext = pE;
+ pE->m_pPrev = pPrev;
+ pPrev = pE;
+ }
+ else
+ {
+ m_pRoot = pE;
+ pPrev = pE;
+ }
+
+ abtStartSecLo++;
+ abtStartSecHi++;
+ pbtName += ROBC_MAX_NAME;
+ }
+
+ return TRUE;
+}
+
+void CRobc::Dismount()
+{
+ DeleteList( m_pRoot );
+}
+
+CRobcDirEntry* CRobc::CreateEntry( BYTE btSecCount, WORD wStartSec, BYTE* btName )
+{
+ CRobcDirEntry* pE = new CRobcDirEntry();
+
+ if ( !pE )
+ return NULL;
+
+ pE->m_iStartSec = wStartSec;
+ pE->m_iSecCount = btSecCount;
+
+ sprintf( pE->m_szAscData, "%04X %02X", wStartSec, btSecCount );
+
+ char szTemp[ ROBC_MAX_NAME + 1 - 2 ];
+ memcpy( szTemp, btName, ROBC_MAX_NAME - 2 );
+ szTemp[ ROBC_MAX_NAME - 2 ] = '\0';
+
+ //printf( "%s\n", szTemp );
+
+ char* szT = szTemp;
+
+ while( *szT )
+ {
+ *szT &= 0x7F;
+ *szT -= 0x20;
+ szT++;
+ }
+
+ GuessBestFnameFromAtari( pE->m_szFname, szTemp, "atr" );
+
+ //printf( "%s\n", pE->m_szFname );
+
+ if ( ExportFile( NULL, pE ) )
+ m_iFilesValid++;
+ else
+ m_iFilesInvalid++;
+
+ return pE;
+}
+
+BOOL CRobc::ExportFile( char* szOutFile, CDirEntry* pDirE )
+{
+ int iSecCount = ((CRobcDirEntry*)pDirE) ->m_iSecCount;
+ int iStartSec = ((CRobcDirEntry*)pDirE) ->m_iStartSec;
+
+ BYTE abtBuff[ 0x80 ];
+
+ if ( ( iStartSec + iSecCount - 1 ) > m_pDisk->GetSectorCount() )
+ {
+ sprintf( m_szLastError, "ROBC: File '%s' goes past last sector!", szOutFile );
+ return FALSE;
+ }
+
+ m_pDisk->ReadSector( abtBuff, iStartSec );
+
+ if ( abtBuff[ 1 ] != iSecCount )
+ {
+ sprintf( m_szLastError, "ROBC: File '%s' Mismatched length (%d<>%d)!", szOutFile, abtBuff[ 1 ], iSecCount );
+ return FALSE;
+ }
+
+ if ( !szOutFile )
+ return TRUE;
+
+ CAtr newdisk;
+
+ DISK_GEOMETRY dg;
+
+ dg.iSides = 1;
+ dg.iTracks = 1;
+ dg.iSectorsPerTrack = iSecCount;
+ dg.iBytesPerSector = 0x80;
+
+ if ( !newdisk.Format( &dg ) )
+ {
+ sprintf( m_szLastError, "ROBC: File '%s' can't create because\n%s", szOutFile, newdisk.GetLastError() );
+ return FALSE;
+ }
+
+ int iCurrSec = 1;
+
+ while( iSecCount )
+ {
+ if( !m_pDisk->ReadSector( abtBuff, iStartSec++ ) )
+ {
+ sprintf( m_szLastError, "ROBC: File '%s' can't create because\n%s", szOutFile, m_pDisk->GetLastError() );
+ return FALSE;
+ }
+
+ if ( !newdisk.WriteSector( iCurrSec++, abtBuff ) )
+ {
+ sprintf( m_szLastError, "ROBC: File '%s' can't create because\n%s", szOutFile, newdisk.GetLastError() );
+ return FALSE;
+ }
+
+ iSecCount--;
+ }
+
+ if ( !newdisk.Save( szOutFile, FALSE ) )
+ {
+ sprintf( m_szLastError, "ROBC: File '%s' can't create because\n%s", szOutFile, newdisk.GetLastError() );
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
diff --git a/jindroush/lib/cgenfile.cpp b/jindroush/lib/cgenfile.cpp
new file mode 100644
index 0000000..66d678d
--- /dev/null
+++ b/jindroush/lib/cgenfile.cpp
@@ -0,0 +1,95 @@
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+//
+
+#include "cgenfile.h"
+
+//writes little-endian dword
+void CGenFile::writeLEdw( DWORD dwT )
+{
+ writeb( dwT & 0xFF );
+ writeb( ( dwT >> 8 ) & 0xFF );
+ writeb( ( dwT >>16 ) & 0xFF );
+ writeb( ( dwT >>24 ) & 0xFF );
+}
+
+//writes little-endian word
+void CGenFile::writeLEw( WORD wT )
+{
+ writeb( wT & 0xFF );
+ writeb( ( wT >> 8 ) & 0xFF );
+}
+
+void CGenFile::writeBEw( WORD wT )
+{
+ writeb( ( wT >> 8 ) & 0xFF );
+ writeb( wT & 0xFF );
+}
+
+//reads little-endian word
+WORD CGenFile::readLEw()
+{
+ WORD wT;
+ wT = readb();
+ wT |= readb() << 8;
+ return wT;
+}
+
+WORD CGenFile::readBEw()
+{
+ WORD wT;
+ wT = readb() << 8;
+ wT |= readb();
+ return wT;
+}
+
+
+//reads little-endian dword
+DWORD CGenFile::readLEdw()
+{
+ DWORD dwT;
+ dwT = readb();
+ dwT |= readb() << 8;
+ dwT |= readb() << 16;
+ dwT |= readb() << 24;
+
+ return dwT;
+}
+
+//writes byte
+void CGenFile::writeb( BYTE btT )
+{
+ Write( &btT, 1, NULL );
+}
+
+//reads byte
+BYTE CGenFile::readb()
+{
+ BYTE btPom;
+ Read( &btPom, 1, NULL );
+ return btPom;
+}
+
+//skips part of file
+BOOL CGenFile::skip( long lSkip )
+{
+ return Seek( lSkip, SEEK_CUR );
+}
+
+//gets current value of pointer
+long CGenFile::Tell()
+{
+ return m_lCurrPtr;
+}
+
diff --git a/jindroush/lib/cobj.cpp b/jindroush/lib/cobj.cpp
new file mode 100644
index 0000000..9c2a6c6
--- /dev/null
+++ b/jindroush/lib/cobj.cpp
@@ -0,0 +1,23 @@
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+//
+
+#include "cobj.h"
+
+CObj::CObj()
+{
+ *m_szLastError = '\0';
+ m_iErrorCode = 0;
+}
+
diff --git a/jindroush/lib/cprefile.cpp b/jindroush/lib/cprefile.cpp
new file mode 100644
index 0000000..b96cdfe
--- /dev/null
+++ b/jindroush/lib/cprefile.cpp
@@ -0,0 +1,153 @@
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+//
+
+#include "cprefile.h"
+
+CPreFile::CPreFile()
+{
+ m_lCacheStartOffset = -1;
+ m_lCacheEndOffset = -1;
+ m_bOpened = FALSE;
+ m_pbtCache = NULL;
+}
+
+CPreFile::~CPreFile()
+{
+ Close();
+}
+
+BOOL CPreFile::Open( CGenFile* pcf, int iCacheSizeKB )
+{
+ m_lCacheLen = 1024 * iCacheSizeKB;
+
+ if ( m_bOpened )
+ return FALSE;
+
+ m_pcf = pcf;
+
+ m_pcf->Seek( 0, SEEK_END );
+
+ m_lLength = m_pcf->Tell();
+
+ if ( m_lLength < m_lCacheLen )
+ {
+ m_lCacheLen = m_lLength;
+ }
+
+ if ( ! ( m_pbtCache = new BYTE [ m_lCacheLen ] ) )
+ return FALSE;
+
+ m_pcf->Seek( 0, SEEK_SET );
+
+ m_lCurrPtr = 0;
+
+ m_bOpened = TRUE;
+
+ PreRead();
+
+ return TRUE;
+
+}
+
+BOOL CPreFile::PreRead()
+{
+ m_pcf->Seek( m_lCurrPtr, SEEK_SET );
+ m_lCacheStartOffset = m_lCurrPtr;
+ m_lCacheEndOffset = m_lCacheStartOffset + m_lCacheLen - 1;
+
+ m_pcf->Read( m_pbtCache, m_lCacheLen );
+
+ return TRUE;
+}
+
+BOOL CPreFile::Read( void* pBuff, int iLen, int* piLen )
+{
+ if ( !m_bOpened )
+ return FALSE;
+
+ if ( m_lCurrPtr > m_lLength )
+ return FALSE;
+
+ if ( iLen >= m_lCacheLen )
+ {
+ m_pcf->Seek( m_lCurrPtr, SEEK_SET );
+ if ( !m_pcf->Read( pBuff, iLen, piLen ) )
+ return FALSE;
+
+ m_lCurrPtr = m_pcf->Tell();
+ m_lCacheEndOffset = -1;
+ return TRUE;
+ }
+
+ if ( ( m_lCurrPtr < m_lCacheStartOffset ) || ( m_lCurrPtr > m_lCacheEndOffset ) )
+ PreRead();
+
+ long lReadEnd = m_lCurrPtr + iLen - 1;
+
+ if ( lReadEnd >= m_lCacheEndOffset )
+ {
+ m_pcf->Seek( m_lCurrPtr, SEEK_SET );
+ if ( !m_pcf->Read( pBuff, iLen, piLen ) )
+ return FALSE;
+
+ m_lCurrPtr = m_pcf->Tell();
+ m_lCacheEndOffset = -1;
+
+ return TRUE;
+ }
+
+ memcpy( pBuff, m_pbtCache + m_lCurrPtr - m_lCacheStartOffset, iLen );
+ m_lCurrPtr += iLen;
+
+ return TRUE;
+}
+
+BOOL CPreFile::Write( void* pBuff, int iLen, int* piLen )
+{
+ return FALSE;
+}
+
+BOOL CPreFile::Seek( long lPos, int iType )
+{
+
+ switch( iType )
+ {
+ case SEEK_SET:
+ m_lCurrPtr = lPos;
+ break;
+
+ case SEEK_CUR:
+ m_lCurrPtr += lPos;
+ break;
+
+ case SEEK_END:
+ m_lCurrPtr = m_lLength - lPos;
+ break;
+
+ }
+ return TRUE;
+}
+
+void CPreFile::Close()
+{
+ m_bOpened = FALSE;
+
+ if ( m_pbtCache )
+ delete [] m_pbtCache;
+
+ m_pbtCache = NULL;
+ m_lCurrPtr = 0;
+}
+