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/cfs_doss.cpp | 383 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 383 insertions(+) create mode 100644 jindroush/lib/cfs_doss.cpp (limited to 'jindroush/lib/cfs_doss.cpp') 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; +} -- cgit v1.2.3