www.pudn.com > potemkin_sourceforPSP.rar > ISOFileSystem.cpp


#include "stdafx.h" 
#include "ISOFileSystem.h" 
 
const int sectorSize = 2048; 
 
#pragma pack(push) 
#pragma pack(1) 
	struct DirectoryEntry 
	{ 
		u8 size; 
		u8 sectorsInExtendedRecord; 
		u32 firstDataSectorLE; 
		u32 firstDataSectorBE; 
		u32 dataLengthLE; 
		u32 dataLengthBE; 
		u8 years; 
		u8 month; 
		u8 day; 
		u8 hour; 
		u8 minute; 
		u8 second; 
		u8 offsetFromGMT; 
		u8 flags; // 2 = directory 
		u8 fileUnitSize; 
		u8 interleaveGap; 
		u16 volSeqNumberLE; 
		u16 volSeqNumberBE; 
		u8 identifierLength; //identifier comes right after 
		u8 firstIdChar; 
	}; 
	struct DirectorySector 
	{ 
		DirectoryEntry entry; 
		char space[2048-sizeof(DirectoryEntry)]; 
	}; 
 
	struct VolDescriptor 
	{ 
		char type; 
		char cd001[6]; 
		char version; 
		char sysid[32]; 
		char volid[32]; 
		char zeros[8]; 
		u32 numSectorsLE; 
		u32 numSectoreBE; 
		char morezeros[32]; 
		u16 volSetSizeLE; 
		u16 volSetSizeBE; 
		u16 volSeqNumLE; 
		u16 volSeqNumBE; 
		u16 sectorSizeLE; 
		u16 sectorSizeBE; 
		u32 pathTableLengthLE; 
		u32 pathTableLengthBE; 
		u16 firstLETableSectorLE; 
		u16 firstLETableSectorBE; 
		u16 secondLETableSectorLE; 
		u16 secondLETableSectorBE; 
		u16 firstBETableSectorLE; 
		u16 firstBETableSectorBE; 
		u16 secondBETableSectorLE; 
		u16 secondBETableSectorBE; 
		DirectoryEntry root; 
		char volumeSetIdentifier[128]; 
		char publisherIdentifier[128]; 
		char dataPreparerIdentifier[128]; 
		char applicationIdentifier[128]; 
		char copyrightFileIdentifier[37]; 
		char abstractFileIdentifier[37]; 
		char bibliographicalFileIdentifier[37]; 
		char volCreationDateTime[17]; 
		char mreModDateTime[17]; 
		char volExpireDateTime[17]; 
		char volEffectiveDateTime[17]; 
		char one; 
		char zero; 
		char reserved[512]; 
		char zeroos[653]; 
	}; 
 
 
#pragma pack(pop) 
 
ISOFileSystem::ISOFileSystem(IHandleAllocator *_hAlloc, BlockDevice *_blockDevice)  
{ 
	blockDevice = _blockDevice; 
	hAlloc = _hAlloc; 
 
	VolDescriptor desc; 
	blockDevice->ReadBlock(16, (u8*)&desc); 
 
	entireISO.isDirectory = false; 
	entireISO.startingPosition = 0; 
	entireISO.size = _blockDevice->GetNumBlocks()*_blockDevice->GetBlockSize(); 
 
	int x = sizeof (DirectoryEntry); 
	if (!memcmp(desc.cd001, "CD001", 5)) 
	{ 
		LOG(FILESYS, "Looks like a valid ISO!"); 
	} 
 
	treeroot = new TreeEntry; 
 
	u32 rootSector = desc.root.firstDataSectorLE; 
	u32 rootSize = desc.root.dataLengthLE; 
 
	ReadDirectory(rootSector, rootSize, treeroot); 
} 
 
 
ISOFileSystem::~ISOFileSystem() 
{ 
	delete blockDevice; 
} 
 
 
void ISOFileSystem::ReadDirectory(u32 startsector, u32 dirsize, TreeEntry *root) 
{ 
	u8 buffer[2048]; 
	int offset=0; 
	u32 secnum=startsector; 
	bool cont=true; 
	int num = 0; 
 
	u8 theSector[2048]; 
	blockDevice->ReadBlock(secnum, theSector); 
 
	while (secnum < (dirsize/2048 + startsector)) 
	{ 
		DirectoryEntry &dir = *((DirectoryEntry *)buffer); 
		u8 sz = theSector[offset]; 
		if (sz==0) // NOT the correct way 
			goto nextblock; //done 
 
		memcpy(&dir, theSector + offset, sz); 
		 
		buffer[2047]=0; 
		offset += dir.size; 
		if (offset >= 2048) 
		{ 
nextblock: 
			offset=0; 
			secnum++; 
			blockDevice->ReadBlock(secnum, theSector); 
		} 
		bool isFile = (dir.flags & 2) ? false : true; 
		char *name = (char *)buffer + 33; 
 
		TreeEntry *e = new TreeEntry; 
		e->name = name; 
		e->size = dir.dataLengthLE; 
		e->startingPosition = dir.firstDataSectorLE * 2048; 
		e->isDirectory = !isFile; 
		 
		LOG(FILESYS, "%s: %s %08x %08x %i", e->isDirectory?"D":"F", name, dir.firstDataSectorLE, e->startingPosition, e->startingPosition); 
 
		//LOG(HLE, "%s - %i", e->name, e->size); 
 
		if (isFile) 
		{ 
			//LOG(FILESYS,"File %s.", (char*)buffer + 33); 
		} 
		else 
		{ 
			//LOG(FILESYS,"Directory %s.", (char*)buffer + 33); 
			if (num>1) //skip . and .., maybe better test than this should be done 
			{ 
				if (dir.firstDataSectorLE == startsector) 
				{ 
					LOG(FILESYS, "WARNING: Appear to have a recursive file system, breaking recursion"); 
				} 
				else 
				{ 
					if (strlen(name)>2) // HACK 
						ReadDirectory(dir.firstDataSectorLE, dir.dataLengthLE, e); 
				} 
			} 
		} 
		if (num>1)  
			root->children.push_back(e); 
 
		num++; 
	} 
 
} 
 
ISOFileSystem::TreeEntry *ISOFileSystem::GetFromPath(std::string path) 
{ 
	if (path.length() == 0) 
	{ 
		//Ah, the device! 
		//MessageBox(0,"gotcha",0,0); 
		return &entireISO; 
	} 
 
	if (path[0] == '/') 
		path.erase(0,1); 
 
	TreeEntry *e = treeroot; 
	if (path.length() == 0) 
		return e; 
 
	while (true) 
	{ 
		TreeEntry *ne = 0; 
		std::string name = ""; 
		if (path.length()>0) 
		{ 
			for (size_t i=0; ichildren.size(); i++) 
			{ 
				std::string n = e->children[i]->name; 
				if (path.compare(0,n.length(),n) == 0) //TODO : bad 
				{ 
					//yay we got it 
					ne = e->children[i]; 
					name = n; 
				} 
			} 
		} 
		if (ne) 
		{ 
			e = ne; 
			int l = name.length(); 
			path.erase(0, l); 
			if (path.length() == 0 || path.length()==1 && path[0] == '/') 
				return e; 
			path.erase(0, 1); 
		} 
		else 
		{ 
			LOG(FILESYS,"File %s not found", path.c_str()); 
			return 0; 
		} 
	} 
} 
 
u32 ISOFileSystem::OpenFile(std::string filename, FileAccess access) 
{ 
	OpenFileEntry entry; 
	if (filename.compare(0,8,"/sce_lbn") == 0) 
	{ 
		std::string yo = filename; 
		filename.erase(0,10); 
		u32 hej,ha; 
		sscanf(filename.c_str(), "%08x", &hej); 
		filename.erase(0,8); 
		sscanf(filename.c_str(), "%08x", &ha); 
		LOG(FILESYS, "Got a raw sector read %s, sector %08x, size %08x", yo.c_str(), hej, ha); 
		u32 newHandle = hAlloc->GetNewHandle(); 
		entry.isRawSector=true; 
		entry.sectorStart=hej; 
		entry.openSize=ha; 
		entries[newHandle] = entry; 
		return newHandle; 
	} 
 
	entry.isRawSector=false; 
 
	if (access & FILEACCESS_WRITE) 
	{ 
		LOG(FILESYS, "Can't open file %s with write access on an ISO partition", filename.c_str()); 
		return 0; 
	} 
 
	entry.file = GetFromPath(filename); 
	if (!entry.file) 
		return 0; 
 
	entry.seekPos=0; 
 
	u32 newHandle = hAlloc->GetNewHandle(); 
	entries[newHandle] = entry; 
	return newHandle; 
} 
 
void ISOFileSystem::CloseFile(u32 handle) 
{ 
	EntryMap::iterator iter = entries.find(handle); 
	if (iter != entries.end()) 
	{ 
		//CloseHandle((*iter).second.hFile); 
		hAlloc->FreeHandle(handle); 
		entries.erase(iter); 
	} 
	else 
	{ 
		//This shouldn't happen... 
		LOG(HLE,"Hey, what are you doing? Closing non-open files?"); 
	} 
} 
 
 
bool ISOFileSystem::OwnsHandle(u32 handle) 
{ 
	EntryMap::iterator iter = entries.find(handle); 
	return (iter != entries.end()); 
} 
 
 
size_t ISOFileSystem::ReadFile(u32 handle, u8 *pointer, s64 size) 
{ 
	EntryMap::iterator iter = entries.find(handle); 
	if (iter != entries.end()) 
	{ 
		OpenFileEntry &e = iter->second; 
		u32 position; 
		if (e.isRawSector) 
		{ 
			position = e.sectorStart; 
			if (position + size > e.sectorStart + e.openSize) 
			{ 
				size = e.sectorStart + e.openSize - position; 
			} 
		} 
		else 
		{ 
			//clamp read length 
			if ((s64)e.seekPos > e.file->size - (s64)size) 
			{ 
				size = e.file->size - (s64)e.seekPos; 
			} 
 
			position = e.file->startingPosition + e.seekPos; 
		} 
		//okay, we have size and position, let's rock 
 
		u32 totalRead = 0; 
		int secNum = position / 2048; 
		int posInSector = position & 2047; 
		int remain = size;		 
		u8 theSector[2048]; 
 
		while (remain > 0) 
		{ 
			blockDevice->ReadBlock(secNum, theSector); 
			int bytesToCopy = 2048-posInSector; 
			if (bytesToCopy > remain) 
				bytesToCopy = remain; 
 
			memcpy(pointer, theSector + posInSector, bytesToCopy); 
			totalRead += bytesToCopy; 
			pointer += bytesToCopy; 
			remain -= bytesToCopy; 
			posInSector = 0; 
			secNum++; 
		} 
/* 
		fseek(iso, e.file->startingPosition + e.seekPos, SEEK_SET); 
		if (size) 
			fread(pointer,1,size,iso); 
*/ 
		e.seekPos += size; 
		return totalRead; 
	} 
	else 
	{ 
		//This shouldn't happen... 
		LOG(HLE,"Hey, what are you doing? Reading non-open files?"); 
		return 0; 
	} 
} 
 
size_t ISOFileSystem::WriteFile(u32 handle, const u8 *pointer, s64 size)  
{ 
	LOG(HLE,"Hey, what are you doing? You can't write to an ISO!"); 
	return 0; 
} 
 
size_t ISOFileSystem::SeekFile(u32 handle, s32 position, FileMove type)  
{ 
	EntryMap::iterator iter = entries.find(handle); 
	if (iter != entries.end()) 
	{ 
		OpenFileEntry &e = iter->second; 
		switch (type) 
		{ 
		case FILEMOVE_BEGIN: 
			e.seekPos = position; 
			break; 
		case FILEMOVE_CURRENT: 
			e.seekPos += position; 
			break; 
		case FILEMOVE_END: 
			if (e.isRawSector) 
				e.seekPos = e.openSize; 
			else 
				e.seekPos = e.file->size + position; 
			break; 
		} 
		return (size_t)e.seekPos; 
	} 
	else 
	{ 
		//This shouldn't happen... 
		LOG(HLE,"Hey, what are you doing? Seeking in non-open files?"); 
		return 0; 
	} 
} 
 
 
FileInfo ISOFileSystem::GetFileInfo(std::string filename)  
{ 
	TreeEntry *entry = GetFromPath(filename); 
	FileInfo x;  
	if (!entry) 
	{ 
		x.size=0; 
	} 
	else 
	{ 
		x.name = entry->name; 
		x.access = FILEACCESS_READ; 
		x.size = entry->size;  
		x.type = entry->isDirectory ? FILETYPE_DIRECTORY : FILETYPE_NORMAL; 
		x.isOnSectorSystem = true; 
		x.startSector = entry->startingPosition/2048; 
	} 
	return x; 
} 
 
 
 
std::vector ISOFileSystem::GetDirListing(std::string path) 
{ 
	std::vector myVector; 
	TreeEntry *entry = GetFromPath(path); 
	if (!entry) 
	{ 
		return myVector; 
	} 
	 
	// fake the . and .. 
	FileInfo x; 
	x.type = FILETYPE_DIRECTORY; 
	x.name = "."; 
	myVector.push_back(x); 
	x.name = ".."; 
	myVector.push_back(x); 
 
	for (size_t i=0; ichildren.size(); i++) 
	{ 
		TreeEntry *e = entry->children[i]; 
		FileInfo x; 
		x.name = e->name; 
		x.access = FILEACCESS_READ; 
		x.size = e->size;  
		x.type = e->isDirectory ? FILETYPE_DIRECTORY : FILETYPE_NORMAL; 
		myVector.push_back(x); 
	} 
	return myVector; 
}