From a4cc3ad3504d634e379369862c9f9fd8eed379f3 Mon Sep 17 00:00:00 2001 From: "B. Watson" Date: Thu, 16 May 2024 01:43:09 -0400 Subject: Add Jindrich Kubec's tools. --- jindroush/lib/Makefile | 23 + jindroush/lib/adsk.cpp | 319 ++++++++++++ jindroush/lib/adsk_atr.cpp | 483 ++++++++++++++++++ jindroush/lib/adsk_dcm.cpp | 764 ++++++++++++++++++++++++++++ jindroush/lib/adsk_di.cpp | 271 ++++++++++ jindroush/lib/adsk_scp.cpp | 281 +++++++++++ jindroush/lib/adsk_xfd.cpp | 327 ++++++++++++ jindroush/lib/at_dis.cpp | 1201 ++++++++++++++++++++++++++++++++++++++++++++ jindroush/lib/autil.cpp | 139 +++++ jindroush/lib/cdisk.cpp | 276 ++++++++++ jindroush/lib/cdsk.cpp | 115 +++++ jindroush/lib/cdsk_atr.cpp | 439 ++++++++++++++++ jindroush/lib/cdsk_dcm.cpp | 762 ++++++++++++++++++++++++++++ jindroush/lib/cdsk_scp.cpp | 279 ++++++++++ jindroush/lib/cdsk_xfd.cpp | 334 ++++++++++++ jindroush/lib/cfile.cpp | 139 +++++ jindroush/lib/cfs.cpp | 69 +++ jindroush/lib/cfs_b2b.cpp | 156 ++++++ jindroush/lib/cfs_boot.cpp | 128 +++++ jindroush/lib/cfs_dos2.cpp | 224 +++++++++ jindroush/lib/cfs_dos3.cpp | 209 ++++++++ jindroush/lib/cfs_dosm.cpp | 240 +++++++++ jindroush/lib/cfs_doss.cpp | 383 ++++++++++++++ jindroush/lib/cfs_howf.cpp | 209 ++++++++ jindroush/lib/cfs_jonw.cpp | 204 ++++++++ jindroush/lib/cfs_kboo.cpp | 148 ++++++ jindroush/lib/cfs_robc.cpp | 231 +++++++++ jindroush/lib/cgenfile.cpp | 95 ++++ jindroush/lib/cobj.cpp | 23 + jindroush/lib/cprefile.cpp | 153 ++++++ 30 files changed, 8624 insertions(+) create mode 100644 jindroush/lib/Makefile create mode 100644 jindroush/lib/adsk.cpp create mode 100644 jindroush/lib/adsk_atr.cpp create mode 100644 jindroush/lib/adsk_dcm.cpp create mode 100644 jindroush/lib/adsk_di.cpp create mode 100644 jindroush/lib/adsk_scp.cpp create mode 100644 jindroush/lib/adsk_xfd.cpp create mode 100644 jindroush/lib/at_dis.cpp create mode 100644 jindroush/lib/autil.cpp create mode 100644 jindroush/lib/cdisk.cpp create mode 100644 jindroush/lib/cdsk.cpp create mode 100644 jindroush/lib/cdsk_atr.cpp create mode 100644 jindroush/lib/cdsk_dcm.cpp create mode 100644 jindroush/lib/cdsk_scp.cpp create mode 100644 jindroush/lib/cdsk_xfd.cpp create mode 100644 jindroush/lib/cfile.cpp create mode 100644 jindroush/lib/cfs.cpp create mode 100644 jindroush/lib/cfs_b2b.cpp create mode 100644 jindroush/lib/cfs_boot.cpp create mode 100644 jindroush/lib/cfs_dos2.cpp create mode 100644 jindroush/lib/cfs_dos3.cpp create mode 100644 jindroush/lib/cfs_dosm.cpp create mode 100644 jindroush/lib/cfs_doss.cpp create mode 100644 jindroush/lib/cfs_howf.cpp create mode 100644 jindroush/lib/cfs_jonw.cpp create mode 100644 jindroush/lib/cfs_kboo.cpp create mode 100644 jindroush/lib/cfs_robc.cpp create mode 100644 jindroush/lib/cgenfile.cpp create mode 100644 jindroush/lib/cobj.cpp create mode 100644 jindroush/lib/cprefile.cpp (limited to 'jindroush/lib') 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; +} + -- cgit v1.2.3