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