// 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;
}