aboutsummaryrefslogtreecommitdiff
path: root/jindroush/lib/cfs_doss.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'jindroush/lib/cfs_doss.cpp')
-rw-r--r--jindroush/lib/cfs_doss.cpp383
1 files changed, 383 insertions, 0 deletions
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;
+}