//	CFileDos

#include "ADFS_Strings.h"
#include "CDiskMapwindow.h"
#include "CCopyTree.h"
#include "MemUtils.h"
#include "ProStructs.h"
#include "DosCatalog.h"
#include "CFolderDos.h"
#include "CDiskDos.h"
#include "CFileDos.h"


OSErr		CFileDos::IFileDos(
	CDiskDos			*cDisk, 
	CFolderDos			*cParentFolderDos, 
	Dos_SectorSpec		sector, 
	Dos_EntryIndex		diskLocDirEntryIndex,	//	relative to cur dir sector
	Dos_EntryIndex		directoryIndex			//	relative to entire directory
) {
	DiskLocSpecUnion	locSpec;
	
	i_curSectorSpec		= Dos_gInvalidSector;
	i_curSectorP		= NULL;
	locSpec.dos			= sector;
	i_cachedLoadAddress	= 0;
	
	return _inherited::IFile(
		cDisk, cParentFolderDos, locSpec, diskLocDirEntryIndex, directoryIndex);
}

void		CFileDos::SetBinFileType(void)
{
	_inherited::SetBinFileType();
	
	switch (GetDosFileType()) {
		
		case Dos_FileType_BIN: {
			i_eof += sizeof(Dos_FileHeader_BIN);
			break;
		}
		
		case Dos_FileType_INT:
		case Dos_FileType_BAS: {
			i_eof += sizeof(Dos_FileHeader_BASIC);
			break;
		}
	}
}

void	CFileDos::FlushEntry(void)
{
	if (i_myEntryCachedB) {
		Dos_DirEntry	*entryP = ((CFolderDos *)GetParentFolder())->GetEntry(
			i_diskLoc.dos, i_diskLocDirEntryIndex);

		if (entryP) {
			*entryP = i_myEntry;
			(void)i_cDisk.dos->SetAndDisposeSector(i_diskLoc.dos);
		}
	}
}

Dos_DirEntry	*CFileDos::GetMyEntry(void)
{
	Dos_DirEntry	*entryP = NULL;
	
	if (!i_myEntryCachedB) {
		entryP = ((CFolderDos *)GetParentFolder())->GetEntry(
			i_diskLoc.dos, i_diskLocDirEntryIndex);
		
		if (entryP) {
			i_myEntry		= *entryP;
			i_myEntryCachedB	= TRUE;
			
			(void)i_cDisk.dos->DisposeSector(i_diskLoc.dos);
		}
	}
	
	return &i_myEntry;
}

char		*CFileDos::GetName(char *buf)
{
	_inherited::GetName(buf);
	
	if (buf[0] == 0) {
		Dos_DirEntry	*entryP = GetMyEntry();
		
		buf[0] = 0;
		if (entryP) {
			Dos_GetFileName(entryP, buf);
		}
	}
	
	return buf;
}

void		CFileDos::SetName(char *buf)
{
	Dos_DirEntry	*entryP = GetMyEntry();
	
	if (entryP) {
		Dos_SetFileName(entryP, buf);
		Dos_GetFileName(entryP, buf);
		_inherited::SetName(buf);
		FlushEntry();
	}
}


OSErr 		CFileDos::ReadFile(Byte *buffer, long length)
{
	OSErr	err = noErr;
	
	return err;
}

OSErr 		CFileDos::WriteFile(Byte *buffer, long length)
{
	OSErr	err = noErr;
	
	return err;
}

char		*CFileDos::GetDescription(char *buf)
{
	if (IsGraphic()) {
		_inherited::GetDescription(buf);
	} else {
		Dos_FileDescType	descType = Dos_FileTypeToDescType(GetDosFileType());
		
		strcpy(buf, Dos_FileDescArray[descType]);
	}

	return buf;
}


Dos_Sector			*CFileDos::GetFirstFileSector(Dos_SectorSpec *firstSectorSpec)
{
	Dos_Sector			*firstSectorP	= NULL;
	Dos_DirEntry		*entryP			= GetMyEntry();
	Dos_SectorSpec		firstSector		= GetFirstTSSector(entryP);
	
	if (entryP && !Dos_IsNullSector(firstSector)) {
		OSErr				err = noErr;
		Dos_TSListSector	*tsListP;
		
		err = i_cDisk.dos->GetSector(firstSector, (Dos_Sector **)&tsListP);
		
		if (!err) {
			if (!Dos_IsNullSector(tsListP->fileSectors[0])) {
				err = i_cDisk.dos->GetSector(tsListP->fileSectors[0], (Dos_Sector **)&firstSectorP);
				if (!err) {
					*firstSectorSpec = tsListP->fileSectors[0];
				}
			}

			(void)i_cDisk.dos->DisposeSector(firstSector);
		}
	}
	
	return firstSectorP;
}

Dos_FileHeader_BIN		*CFileDos::GetBinFileHeader(Dos_SectorSpec *firstSectorSpec)
{
	return (Dos_FileHeader_BIN *)GetFirstFileSector(firstSectorSpec);
}

Dos_FileHeader_BASIC	*CFileDos::GetBasFileHeader(Dos_SectorSpec *firstSectorSpec)
{
	return (Dos_FileHeader_BASIC *)GetFirstFileSector(firstSectorSpec);
}

ushort		CFileDos::GetLoadAddress(void)
{
	ushort	laddr = 0;
	
	switch (GetDosFileType()) {
	
		case Dos_FileType_BIN: {
			Dos_SectorSpec		firstSectorSpec;
			Dos_FileHeader_BIN	*binHeaderP = GetBinFileHeader(&firstSectorSpec);

			if (i_cachedLoadAddress || !binHeaderP) {
				laddr = i_cachedLoadAddress;
			} else {
				laddr = GetRboShort(binHeaderP->loadAddress);
			}
			
			if (binHeaderP) {
				(void)i_cDisk.dos->DisposeSector(firstSectorSpec);
			}
			break;
		}
	}
	
	return laddr;
}

ulong		CFileDos::GetPhysicalSize(void)
{
	if (i_physical_sizeL == 0) {
		Dos_DirEntry		*entryP = GetMyEntry();

		if (entryP) {
	 		i_physical_sizeL = GetRboShort(entryP->size) * Dos_kBytesPerSector;
	 	}
	 }
	
	return i_physical_sizeL;
}

ulong		CFileDos::GetTextFileLength(void)
{
	ulong				lsize = 0;
	Dos_DirEntry		*entryP = NULL;
	
	entryP = GetMyEntry();
	
	if (entryP) {
		ushort				loop;
		Boolean				doneB;
		Dos_SectorSpec		sectorSpec, curSectorSpec, nextSectorSpec;
		Dos_TSListSector	*tsListP = NULL;
		OSErr				err = noErr;
		
		curSectorSpec = GetFirstTSSector(entryP);
		err = i_cDisk.dos->GetSector(curSectorSpec, (Dos_Sector **)&tsListP);

		if (!err) do {
			for (loop = 0; loop < Dos_kMaxSectorSpecs; loop++) {
				if (!Dos_IsNullSector(tsListP->fileSectors[loop])) {
					sectorSpec = tsListP->fileSectors[loop];
					lsize += sizeof(Dos_Sector);
				}
			}
			
			doneB = Dos_IsNullSector(tsListP->nextTsSector);
			
			if (!doneB) {
				nextSectorSpec = tsListP->nextTsSector;
				err = i_cDisk.dos->DisposeSector(curSectorSpec);
				curSectorSpec = nextSectorSpec;

				if (!err) err = i_cDisk.dos->GetSector(curSectorSpec, (Dos_Sector **)&tsListP);
				
				if (err) {
					lsize = 0;
					doneB = TRUE;
				}
			} else {
				Dos_FileSector		*fileSectorP;
				
				err = i_cDisk.dos->DisposeSector(curSectorSpec);
				if (!err) err = i_cDisk.dos->GetSector(sectorSpec, (Dos_Sector **)&fileSectorP);

				if (err) {
					lsize = 0;
					doneB = TRUE;
				} else {
					ushort		curByte = 0;
					
					lsize -= sizeof(Dos_Sector);
		
					while (fileSectorP->file[curByte] != 0 && curByte < Dos_kBytesPerSector) {
						curByte++;
						lsize++;
					}
	
					err = i_cDisk.dos->DisposeSector(sectorSpec);
				}
			}
		} while (!err && !doneB);
	}
	
	return lsize;
}

ulong		CFileDos::GetLogicalSize(void)
{
	if (i_logical_sizeL == 0) {
		Dos_SectorSpec	firstSectorSpec;
		Dos_Sector		*sectorP = GetFirstFileSector(&firstSectorSpec);
		
		if (sectorP != NULL) {

			switch (GetDosFileType()) {
			
				case Dos_FileType_BIN: {
					Dos_FileHeader_BIN	*binHeaderP = (Dos_FileHeader_BIN *)sectorP;

					i_logical_sizeL = GetRboShort(binHeaderP->length);
					break;
				}
				
				case Dos_FileType_INT:
				case Dos_FileType_BAS: {
					Dos_FileHeader_BASIC	*basHeaderP = (Dos_FileHeader_BASIC *)sectorP;
					
					i_logical_sizeL += GetRboShort(basHeaderP->length);
					break;
				}
				
				case Dos_FileType_TXT: {
					i_logical_sizeL = GetTextFileLength();
					break;
				}
			}
			
			(void)i_cDisk.dos->DisposeSector(firstSectorSpec);
		}
	}
		
	return i_logical_sizeL;
}

//	gets native file type
ushort			CFileDos::GetFileType(void)
{
	ushort				type = 0;
	Dos_DirEntry 		*entryP		= GetMyEntry();

	if (entryP) {
		type = entryP->fileType & Dos_FileType_MASK;
	}
	
	return type;
}

void			CFileDos::SetFileType(Dos_FileType fileType)
{
//	ushort			type		= 0;
	Dos_DirEntry 	*entryP		= GetMyEntry();
	
	if (entryP) {
		entryP->fileType = (entryP->fileType & Dos_FileType_LOCK) | fileType;
		FlushEntry();
	}
}

void		CFileDos::SetLoadAddress(ushort address)
{
	switch (GetDosFileType()) {
	
		case Dos_FileType_BIN: {
			Dos_SectorSpec		firstSectorSpec;
			Dos_FileHeader_BIN	*binHeaderP = GetBinFileHeader(&firstSectorSpec);
			
			if (!binHeaderP) {
				i_cachedLoadAddress = address;
			} else {
				binHeaderP->loadAddress = SetRboShort(address);
				i_cachedLoadAddress		= 0;
				(void)i_cDisk.dos->SetAndDisposeSector(firstSectorSpec);
			}
			break;
		}
	}
}

ushort			CFileDos::GetAuxType(void)
{
	return GetLoadAddress();
}

void		CFileDos::SetAuxType(ushort auxType)
{
	SetLoadAddress(auxType);
}

void			CFileDos::SetFileAndAuxType(Byte fileType, ushort auxType)
{
	SetFileType(fileType);
	SetAuxType(auxType);

	_inherited::SetFileAndAuxType(fileType, auxType);
}

void			CFileDos::SetFileType_ProEquiv(Byte proType)
{
	Dos_FileType		dosType;
	
	switch (proType) {
	
		case Pro_FileType_TXT: {
			dosType = Dos_FileType_TXT;
			break;
		}

		case Pro_FileType_INT: {
			dosType = Dos_FileType_INT;
			break;
		}

		case Pro_FileType_BAS: {
			dosType = Dos_FileType_BAS;
			break;
		}

		case Pro_FileType_REL: {
			dosType = Dos_FileType_R;
			break;
		}

		default:
		case Pro_FileType_BIN: {
			dosType = Dos_FileType_BIN;
			break;
		}
	}
	
	SetFileType(dosType);
}

ushort			CFileDos::GetFileType_ProEquiv(void)
{
	ushort			proType;
	Dos_FileType	fileType = GetDosFileType();
	
	switch (fileType) {

		case Dos_FileType_TXT: {
			proType = Pro_FileType_TXT;
			break;
		}

		case Dos_FileType_INT: {
			proType = Pro_FileType_INT;
			break;
		}

		case Dos_FileType_BAS: {
			proType = Pro_FileType_BAS;
			break;
		}

		case Dos_FileType_BIN: {
			proType = Pro_FileType_BIN;
			break;
		}

		//	nobody knows what type these are
		default:
		case Dos_FileType_S:
		case Dos_FileType_a:
		case Dos_FileType_b: {
			proType = Pro_FileType_BINA;
			break;
		}

		case Dos_FileType_R: {
			proType = Pro_FileType_REL;
			break;
		}
	}
	
	return proType;
}

ulong			CFileDos::ADFS_GetBufSize(void)
{
	Dos_FileType	fileType	= GetDosFileType();
	ulong			size		= sizeof(Dos_Sector);
	
	if (
		fileType == Dos_FileType_BAS
		|| fileType == Dos_FileType_INT
	) {
		//	largest theoretically possible basic program
		size = (0x9600 - 0x0800);
	}

	return size;
}

OSErr	CFileDos::Dos_GetIndSectorSpec(ushort sectorIndex, Dos_SectorSpec *sectorSpec)
{
	OSErr				err			= noErr;
	Dos_DirEntry 		*entryP		= GetMyEntry();
	Dos_TSListSector	*tsListP	= NULL;
	Dos_SectorSpec		curSectorSpec, nextSectorSpec;
	
	if (!entryP) {
		err = IC_Err_READ_ILLEGAL_TRACK_SECTOR;
	} else {
		curSectorSpec = GetFirstTSSector(entryP);
		err = i_cDisk.dos->GetSector(curSectorSpec, (Dos_Sector **)&tsListP);
	}
		
	while (!err && sectorIndex >= Dos_kMaxSectorSpecs) {
		if (Dos_IsNullSector(tsListP->nextTsSector)) {
			ReportError(err = IC_Err_READ_ILLEGAL_TRACK_SECTOR);
		} else {
			nextSectorSpec = tsListP->nextTsSector;
			err = i_cDisk.dos->DisposeSector(curSectorSpec);
			curSectorSpec = nextSectorSpec;

			if (!err) err = i_cDisk.dos->GetSector(curSectorSpec, (Dos_Sector **)&tsListP);

			sectorIndex -= Dos_kMaxSectorSpecs;
		}
	}
	
	if (!err) {
		*sectorSpec = tsListP->fileSectors[sectorIndex];

		err = i_cDisk.dos->DisposeSector(curSectorSpec);
	}
	
	return err;
}

void		CFileDos::Dos_UpdateBytesRead(
	ushort curSectorIndex, 
	ushort lastSectorIndex, 
	ushort *bytesRead)
{
	Dos_FileType	fileType = GetDosFileType();
	
	if (curSectorIndex == lastSectorIndex) {
		*bytesRead += ((i_eof - 1) & 0x000000FF) + 1;
	} else {
		*bytesRead += Dos_kBytesPerSector;
	}

	if (curSectorIndex == 0) {

		switch (fileType) {
			
			case Dos_FileType_BIN: {
				*bytesRead -= sizeof(Dos_FileHeader_BIN);
				break;
			}
			
			case Dos_FileType_INT:
			case Dos_FileType_BAS: {
				*bytesRead -= sizeof(Dos_FileHeader_BASIC);
				break;
			}
			
			default: {
				break;
			}
		}
	}
}

OSErr			CFileDos::ADFS_Read(ushort *bytesRead)
{
	OSErr		err = noErr;
	ushort		curSectorIndex	= (ushort)(i_filePos >> 8);	//	fp is base 0, div by 256
	ushort		lastSectorIndex	= curSectorIndex;
	
	*bytesRead = 0;

	//	error if we're not reading sector boundaries
	if (i_filePos != (ulong)curSectorIndex * (ulong)Dos_kBytesPerSector) {
		err = IC_Err_BLOCK_BOUNDARIES;
		ReportError(err);
	}
	
	if (!err && i_eof > 0) {
		Dos_SectorSpec	sectorSpec;
		Dos_Sector		*sectorP;

		lastSectorIndex	= (ushort)((i_eof - 1) >> 8);		//	eof is base 1, div by 256

		if (!err && curSectorIndex <= lastSectorIndex) {
			err = Dos_GetIndSectorSpec(curSectorIndex, &sectorSpec);
			
			if (!err) err = i_cDisk.dos->GetSector(sectorSpec, &sectorP);
	
			if (!err) {
				Dos_FileType	fileType = GetDosFileType();
				
				if (
					IsCopyTranslated() 
					&& (
						fileType == Dos_FileType_BAS
						|| fileType == Dos_FileType_INT
					)
				) {
					ASSERT(curSectorIndex == 0);
					
					*((Dos_FileHeaderBytes_BASIC *)i_fileBufP) = ((Dos_FileSector_BASIC *)sectorP)->file;
					err = i_cDisk.dos->DisposeSector(sectorSpec);
		
					Dos_UpdateBytesRead(curSectorIndex, lastSectorIndex, bytesRead);
					
					for (++curSectorIndex; !err && curSectorIndex <= lastSectorIndex; curSectorIndex++) {
						err = Dos_GetIndSectorSpec(curSectorIndex,  &sectorSpec);

						if (!err) err = i_cDisk.dos->GetSector(sectorSpec, &sectorP);

						if (!err) {
							*((Dos_Sector *)&(i_fileBufP[*bytesRead])) = *sectorP;
							Dos_UpdateBytesRead(curSectorIndex, lastSectorIndex, bytesRead);
							err = i_cDisk.dos->DisposeSector(sectorSpec);
						}
					}
				} else {
					
					if (curSectorIndex == 0) {
						if (
							fileType == Dos_FileType_BAS
							|| fileType == Dos_FileType_INT
						) {
							*((Dos_FileHeaderBytes_BASIC *)i_fileBufP) = ((Dos_FileSector_BASIC *)sectorP)->file;
						} else if (fileType == Dos_FileType_BIN && curSectorIndex == 0) {
							*((Dos_FileHeaderBytes_BIN *)i_fileBufP) = ((Dos_FileSector_BIN *)sectorP)->file;
						} else {				
							*((Dos_Sector *)i_fileBufP) = *sectorP;
						}
					} else {
						*((Dos_Sector *)i_fileBufP) = *sectorP;
					}
					
					err = i_cDisk.dos->DisposeSector(sectorSpec);

					Dos_UpdateBytesRead(curSectorIndex, lastSectorIndex, bytesRead);
				}
			}

			if (!err) err = _inherited::ADFS_Read(bytesRead);
			
			//	since DOS can read < sector size even when not
			//	at last sector, fudge accordingly
			if (curSectorIndex < lastSectorIndex) {
				i_filePos += sizeof(Dos_Sector) - *bytesRead;
			}
		}
	}
	
	if (!err) {
		if (curSectorIndex >= lastSectorIndex) {
			err = eofErr;
		}
	}
	
	return err;
}

long		CFileDos::GetFirstBufOffset(void)
{
	Dos_FileType		fileType	= GetDosFileType();
	long				offsetL		= 0;

	switch (fileType) {
		
		case Dos_FileType_BIN: {
			offsetL = sizeof(Dos_FileHeader_BIN);
			break;
		}
		
		case Dos_FileType_INT:
		case Dos_FileType_BAS: {
			offsetL = sizeof(Dos_FileHeader_BASIC);
			break;
		}
	}
	
	return offsetL;
}

//	pass Dos_kZeroFileSize to set original file size to zero

#define	Dos_kZeroFileSize	65535
OSErr			CFileDos::Dos_IncFileSize(ushort numBytesS)
{
	OSErr				err			= noErr;
	Dos_DirEntry 		*entryP		= GetMyEntry();

	if (!entryP) {
		err = IC_Err_READ_ILLEGAL_TRACK_SECTOR;
	}
	
	if (!err) {
		Dos_SectorSpec	firstSectorSpec;
		Dos_Sector		*sectorP	= GetFirstFileSector(&firstSectorSpec);
		Dos_FileType	fileType	= GetDosFileType();
		
		if (numBytesS != Dos_kZeroFileSize) {
			//	inc the file count
			entryP->size = SetRboShort(GetRboShort(entryP->size) + 1);
			FlushEntry();
		}
		
		if (sectorP) {
		
			if (!err) switch (fileType) {
				
				case Dos_FileType_BIN: {
					Dos_FileHeader_BIN		*binHeaderP	= (Dos_FileHeader_BIN *)sectorP;
					ulong					final_sizeL;
					
					if (numBytesS != Dos_kZeroFileSize) {
						ushort			file_sizeS	= GetRboShort(binHeaderP->length);
						
						final_sizeL	= (ulong)file_sizeS + (ulong)numBytesS;

						if (final_sizeL > 65535) {
							ReportError(err = IC_Err_FILE_TOO_LARGE);
						}
					}  else {
						final_sizeL = 0;
						binHeaderP->loadAddress = SetRboShort((ushort)0);
					}
					
					if (!err) {
						binHeaderP->length = SetRboShort((ushort)final_sizeL);
					}
					break;
				}
				
				case Dos_FileType_INT:
				case Dos_FileType_BAS: {
					Dos_FileHeader_BASIC	*basHeaderP = (Dos_FileHeader_BASIC *)sectorP;
					
					if (numBytesS != Dos_kZeroFileSize) {
						basHeaderP->length = SetRboShort(
							(ushort)((ulong)GetRboShort(basHeaderP->length) + (ulong)numBytesS));
					} else {
						basHeaderP->length = SetRboShort(0);
					}
					break;
				}
			}
			
			err = i_cDisk.dos->SetAndDisposeSector(firstSectorSpec);
		}
	}
	
	return err;
}

OSErr			CFileDos::Dos_WriteSector(ushort numBytesS, Dos_Sector *sectorBufP)
{
	OSErr				err				= noErr;
	Dos_DirEntry 		*entryP			= GetMyEntry();
	ushort				bufOffset		= GetFirstBufOffset();
	Boolean				firstSectorB	= GetRboShort(entryP->size) == 1;
	Dos_SectorSpec		*sectorSpecP, owningSectorSpec, nextSectorSpec;
	
	if (!entryP) err = IC_Err_READ_ILLEGAL_TRACK_SECTOR;
		
	if (!err) {
		if (numBytesS > sizeof(Dos_Sector)) {
			ReportError(err = IC_Err_CANT_WRITE_MORE_THAN_1);
		}
	}
	
	if (!err && bufOffset) {
	
		if (firstSectorB) {
		
			if (!err) err = i_cDisk.dos->Dos_GetNextFreeTSSectorAlloc(
				entryP, &owningSectorSpec, &sectorSpecP, NULL);
				
			if (!err) err = i_cDisk.dos->ReserveNextFreeSector(sectorSpecP);
			if (!err) err = i_cDisk.dos->SetAndDisposeSector(owningSectorSpec);

			if (!err) {
				i_curSectorSpec = *sectorSpecP;
				err = i_cDisk.dos->GetSector(i_curSectorSpec, &i_curSectorP, TRUE);
			}
			
			if (!err) err = Dos_IncFileSize(Dos_kZeroFileSize);
		}
		
		if (!err) err = ASSERT(i_curSectorP);
		
		if (!err) {
			memcpy(
				&i_curSectorP->byte[bufOffset], 
				sectorBufP, 
				sizeof(Dos_Sector) - bufOffset);

			if (numBytesS > sizeof(Dos_Sector) - bufOffset) {
				if (!err) err = i_cDisk.dos->Dos_GetNextFreeTSSectorAlloc(
					entryP, &owningSectorSpec, &sectorSpecP, NULL);

				if (!err) err = i_cDisk.dos->ReserveNextFreeSector(sectorSpecP);
				
				nextSectorSpec = *sectorSpecP;
				if (!err) err = i_cDisk.dos->SetAndDisposeSector(owningSectorSpec);
				if (!err) err = i_cDisk.dos->SetAndDisposeSector(i_curSectorSpec, i_curSectorP);
				
				if (!err) {
					i_curSectorSpec = nextSectorSpec;
					err = i_cDisk.dos->GetSector(i_curSectorSpec, &i_curSectorP, TRUE);
				}

				if (!err)  {
					memcpy(
						i_curSectorP, 
						&sectorBufP->byte[sizeof(Dos_Sector) - bufOffset], 
						bufOffset);
				}
			}
		}

		if (!err) err = Dos_IncFileSize(numBytesS);
	} else {
		if (!err) err = i_cDisk.dos->Dos_GetNextFreeTSSectorAlloc(
			entryP, &owningSectorSpec, &sectorSpecP, NULL);
			
		if (!err) err = i_cDisk.dos->ReserveNextFreeSector(sectorSpecP);

		nextSectorSpec = *sectorSpecP;
		if (!err) err = i_cDisk.dos->GetSector(nextSectorSpec, &i_curSectorP, TRUE);
		
		if (!err) err = i_cDisk.dos->SetAndDisposeSector(owningSectorSpec);

		if (!err) {
			if (numBytesS < sizeof(Dos_Sector)) {
				memset(&sectorBufP->byte[numBytesS], 0, sizeof(Dos_Sector) - numBytesS);
			}

			if (!err) err = Dos_IncFileSize(numBytesS);

			*i_curSectorP = *sectorBufP;
			if (!err) err = i_cDisk.dos->SetAndDisposeSector(nextSectorSpec, sectorBufP);
		}
	}
	
	return err;
}

OSErr			CFileDos::ADFS_Write(ushort *bytesWritten)
{
	OSErr		err			= noErr;
	ushort		bytesLeftS	= *bytesWritten;
	char		*curBufP	= i_fileBufP;
	ushort		curBytesS	= sizeof(Dos_Sector);
	
	if (!err) err = _inherited::ADFS_Write(bytesWritten);
	
	while (!err && bytesLeftS) {

		if (bytesLeftS > sizeof(Dos_Sector)) {
			bytesLeftS -= sizeof(Dos_Sector);
		} else {
			curBytesS	= bytesLeftS;
			bytesLeftS	= 0;
		}

		if (!err) err = Dos_WriteSector(curBytesS, (Dos_Sector *)curBufP);
		
		curBufP += sizeof(Dos_Sector);
	}
	
	if (!err) i_eof += *bytesWritten;

	return err;
}

OSErr		CFileDos::ADFS_Open(
	ADFS_IOType	ioType, 
	Boolean		resForkB, 
	char		**bufferP, 
	ulong		*bufSize)
{
	OSErr	err	= noErr;
	
	i_curSectorSpec = Dos_gInvalidSector;
	
	if (!err) err = _inherited::ADFS_Open(ioType, resForkB, bufferP, bufSize);
	
	return err;
}

OSErr		CFileDos::ADFS_Close(void)
{
	OSErr		err = noErr;
	OSErr		err2;
	
	if (i_ioType == ADFS_IO_WRITE) {
	
		if (i_cachedLoadAddress) {
			SetLoadAddress(i_cachedLoadAddress);
		}

		if (!Dos_IsInvalidSector(i_curSectorSpec)) {
			ASSERT(i_curSectorP);

			if (!err) err = i_cDisk.dos->SetAndDisposeSector(i_curSectorSpec, i_curSectorP);
			i_curSectorSpec = Dos_gInvalidSector;
		}
	}

	err2 = _inherited::ADFS_Close();
	if (!err) err = err2;
	
	return err;
}

Gen_AccessBits		Gen_kAccess_LOCKED		= { 0, 0, 0, 0, 0, 0 };

void			CFileDos::GetAccessBits(Gen_AccessBits *bits)
{
	if (i_openingB) {
		_inherited::GetAccessBits(bits);
	} else {
		Dos_DirEntry 		*entryP		= GetMyEntry();
		
		if (entryP) {
			*bits = Gen_kAccess_LOCKED;

			if ((entryP->fileType & Dos_FileType_LOCK) == 0) {
				_inherited::GetAccessBits(bits);
			} else {
				bits->readEnable = TRUE;
			}
		}
	}
}

void			CFileDos::SetAccessBits(Gen_AccessBits *bits)
{
	Dos_DirEntry 		*entryP		= GetMyEntry();
	
	if (entryP) {
		if (!bits->destroyEnable && !bits->renameEnable && !bits->writeEnable) {
			entryP->fileType |= Dos_FileType_LOCK;
		} else {
			entryP->fileType &= ~Dos_FileType_LOCK;
		}

		FlushEntry();
	}

	_inherited::SetAccessBits(bits);
}

char		*CFileDos::GetStorageStr(char *buf256)
{
	Dos_DirEntry 	*entryP = GetMyEntry();
	
	buf256[0] = 0;
		
	if (entryP) {
		ushort	sectors = GetRboShort(entryP->size);

		sprintf(buf256, "%hu sector%s", sectors, sectors == 1 ? ADFS_Str(ADFS_Str_NONE) : "s");
	}

	return buf256;
}

OSErr		CFileDos::GetFileSectors(
	Gen_SectorSpec	*fileSectorsA0, 
	ushort			*numFileSectorsSP, 
	Gen_SectorSpec	*extentSectorsA0, 
	ushort			*numExtentSectorsSP)
{
	OSErr				err			= noErr;
	Dos_DirEntry 		*entryP		= GetMyEntry();
	Dos_TSListSector	*tsListP	= NULL;
	Boolean				doneB		= FALSE;
	ushort				curSectorS;
	Dos_SectorSpec		sectorSpec, curSectorSpec, nextSectorSpec;

	if (!entryP) {
		err = IC_Err_READ_ILLEGAL_TRACK_SECTOR;
	} else {
		curSectorSpec = GetFirstTSSector(entryP);
	
		if (!Dos_IsNullSector(curSectorSpec)) {
			err = i_cDisk.dos->GetSector(curSectorSpec, (Dos_Sector **)&tsListP);

			if (!err) {
				if (extentSectorsA0) {
					extentSectorsA0[*numExtentSectorsSP] = curSectorSpec;
				}
			
				(*numExtentSectorsSP)++;
			}
			
			while (!err && !doneB) {
			
				for (curSectorS = 0; curSectorS < Dos_kMaxSectorSpecs; curSectorS++) {
					sectorSpec = tsListP->fileSectors[curSectorS];

					if (!Dos_IsNullSector(sectorSpec)) {
						if (fileSectorsA0) {
							fileSectorsA0[*numFileSectorsSP] = sectorSpec;
						}
					
						(*numFileSectorsSP)++;					
					}
				}

				if (Dos_IsNullSector(tsListP->nextTsSector)) {
					doneB = TRUE;

					err = i_cDisk.dos->DisposeSector(curSectorSpec);
				}
				
				if (!doneB) {
					if (extentSectorsA0) {
						extentSectorsA0[*numExtentSectorsSP] = tsListP->nextTsSector;
					}
				
					(*numExtentSectorsSP)++;
					
					nextSectorSpec = tsListP->nextTsSector;
					err = i_cDisk.dos->DisposeSector(curSectorSpec);
					curSectorSpec = nextSectorSpec;
					if (!err) err = i_cDisk.dos->GetSector(curSectorSpec, (Dos_Sector **)&tsListP);
				}
			}
		}
	}

	return err;
}

OSErr		CFileDos::GetEntryAlloc(
	Boolean			getAsBlocksB, 
	Gen_EntryAlloc	**sectorListH)
{
	OSErr				err					= noErr;
	Gen_SectorSpec		*sectorNumP			= NULL;
	ushort				numFileSectorsS;
	ushort				numExtentSectorsS;
	
	err = ASSERT(!getAsBlocksB);
	
	if (!err) {
		*sectorListH	= (Gen_EntryAlloc *)TrackNewPtrClear(
			"entry sector header, for DOS file", sizeof(Gen_EntryAlloc));
		
		if (*sectorListH == NULL) err = memFullErr;
	}
	
	if (!err) {		
		(**sectorListH).allocSize = i_cDisk.dos->GetAllocSize();
	}
	
	if (!err && !IsDeleted()) {
		numFileSectorsS		= 0;
		numExtentSectorsS	= 0;

		err = GetFileSectors(
			NULL, &numFileSectorsS, 
			NULL, &numExtentSectorsS);

		if (!err && numFileSectorsS) {
			sectorNumP = (Gen_SectorSpec *)TrackNewPtrClear(
				"entry sectors, DOS file sectors", 
				sizeof(Gen_SectorSpec) * numFileSectorsS);
			
			if (sectorNumP == NULL) err = memFullErr;
			
			if (!err) {
				(**sectorListH).type[Gen_Alloc_FILE].totalS		= numFileSectorsS;
				(**sectorListH).type[Gen_Alloc_FILE].u.sectorsA	= sectorNumP;
				sectorNumP = NULL;
			}
		}

		if (!err && numExtentSectorsS) {
			sectorNumP = (Gen_SectorSpec *)TrackNewPtrClear(
				"entry sectors, DOS file extent sectors", 
				sizeof(Gen_SectorSpec) * numExtentSectorsS);
			
			if (sectorNumP == NULL) err = memFullErr;
			
			if (!err) {
				(**sectorListH).type[Gen_Alloc_EXTENTS].totalS		= numExtentSectorsS;
				(**sectorListH).type[Gen_Alloc_EXTENTS].u.sectorsA	= sectorNumP;
				sectorNumP = NULL;
			}
		}
		
		if (!err) {
			numFileSectorsS		= 0;
			numExtentSectorsS	= 0;

			err = GetFileSectors(
				(**sectorListH).type[Gen_Alloc_FILE].u.sectorsA,	&numFileSectorsS, 
				(**sectorListH).type[Gen_Alloc_EXTENTS].u.sectorsA,	&numExtentSectorsS);
		}
	}
	
	
	if (err) {
		DisposeEntryAlloc(*sectorListH);
		*sectorListH = NULL;
	}
	
	return err;
}

Boolean		CFileDos::IsDeleted(void)
{
	Boolean				deletedB	= _inherited::IsDeleted();
	
	if (!deletedB) {
		Dos_DirEntry 		*entryP		= GetMyEntry();
		
		if (entryP) {
			deletedB = Dos_IsDeleted(entryP);
		}
	}

	return deletedB;
}

OSErr		CFileDos::Delete(Boolean warnB, CDialogCopy *copyP0)
{
	OSErr				err;
	CFolderDos			*folderP	= (CFolderDos *)GetParentFolder();
	CDiskDos			*diskP		= i_cDisk.dos;
	Boolean				cachedB		= diskP->i_show_deletedB && i_myEntryCachedB;
	Dos_EntryLocSpec	entryLoc;

	entryLoc.sectorSpec	= i_diskLoc.dos;
	entryLoc.entryIndex	= i_diskLocDirEntryIndex;
	entryLoc.dirIndex	= i_directoryIndex;
	
	err = _inherited::Delete(warnB, copyP0);
	//	THIS may be gone now (if not showing deleted files)
	
	if (!err) {
		err = folderP->Dos_DeleteEntry(entryLoc);
	
		if (cachedB) {
			(void)diskP->DisposeSector(entryLoc.sectorSpec);
		}
	}
	
	return err;
}

OSErr		CFileDos::UnDelete(Boolean recursiveB, CDialogCopy *copyP0)
{
	OSErr	err = noErr;
	
	if (!err) err = ASSERT(IsDeleted());
	
	if (!err) {
		char				errorAC[1024], whereAC[256];
		Dos_DirEntry 		*entryP		= GetMyEntry();
		
		if (entryP) {
			if (GetLogicalSize() == 0) {
				sprintf(
					errorAC, 
					ADFS_Str(ADFS_Str_TOTALLY_OVERWRITTEN), 
					GetWhereString(whereAC));

				entryP = NULL;
				ReportErrorStr(-1, errorAC);
			}
		}
		
		if (entryP) {
			Gen_EntryAlloc		*sectorListP;
			Boolean				successB = FALSE;
			
			i_cDisk.dos->FlushMemDisk(FALSE);

			entryP->firstTSSector.track = entryP->name[Dos_kNameLength - 1];
			entryP->name[Dos_kNameLength - 1] = ' ';
			FlushEntry();
			
			err = GetEntryAlloc(FALSE, &sectorListP);
			
			if (!err) {
				Gen_AllocType		allocType;
				ushort				curSectorS;
				Dos_SectorSpec		curSectorSpec;
				Boolean				isFreeB;

				successB = TRUE;
				
				for (
					allocType = Gen_Alloc_FILE; 
					!err & allocType <= Gen_Alloc_EXTENTS; 
					allocType = (Gen_AllocType)(allocType + (Gen_Alloc_EXTENTS - Gen_Alloc_FILE))
				) {
					for (
						curSectorS = 0;
						!err & curSectorS < sectorListP->type[allocType].totalS;
						curSectorS++
					) {
						curSectorSpec = sectorListP->type[allocType].u.sectorsA[curSectorS];
						
						err = i_cDisk.dos->IsFreeSector(curSectorSpec, &isFreeB);
						if (!isFreeB) {
							goto bad_bail;
						}
					}
				}

				for (
					allocType = Gen_Alloc_FILE; 
					!err & allocType <= Gen_Alloc_EXTENTS; 
					allocType = (Gen_AllocType)(allocType + (Gen_Alloc_EXTENTS - Gen_Alloc_FILE))
				) {
					for (
						curSectorS = 0;
						!err & curSectorS < sectorListP->type[allocType].totalS;
						curSectorS++
					) {
						curSectorSpec = sectorListP->type[allocType].u.sectorsA[curSectorS];
						
						err = i_cDisk.dos->ReserveSector(curSectorSpec);
					}
				}
				
				goto good_done;
				bad_bail:

				entryP->name[Dos_kNameLength - 1] = entryP->firstTSSector.track;
				entryP->firstTSSector.track = 0xFF;
				FlushEntry();

				GetWhereString(whereAC);
				
				if (allocType == Gen_Alloc_EXTENTS) {
					sprintf(
						errorAC, 
						ADFS_Str(ADFS_Str_EXTENTS_OVERWRITTEN), 
						whereAC);
				} else {
					sprintf(
						errorAC, 
						ADFS_Str(ADFS_Str_PARTS_OVERWRITTEN), 
						whereAC);
				}
				
				successB = FALSE;
				ReportErrorStr(-1, errorAC);				
				
				good_done:
				DisposeEntryAlloc(sectorListP);
			}
			
			if (i_myEntryCachedB) {
				(void)i_cDisk.dos->DisposeSector(i_diskLoc.dos);
				i_myEntryCachedB = FALSE;
				
				//	update entry cache
				GetMyEntry();
			}

			i_cDisk.dos->FlushMemDisk(TRUE);
		}
	}
	
	if (!err) err = _inherited::UnDelete(recursiveB, copyP0);

	return err;
}
