size_t VirtualDiscFileSystem::ReadFile(u32 handle, u8 *pointer, s64 size) { EntryMap::iterator iter = entries.find(handle); if (iter != entries.end()) { // it's the whole iso... it could reference any of the files on the disc. // For now let's just open and close the files on demand. Can certainly be done // better though if (iter->second.type == VFILETYPE_ISO) { int fileIndex = getFileListIndex(iter->second.curOffset,size*2048,true); if (fileIndex == -1) { ERROR_LOG(FILESYS,"VirtualDiscFileSystem: Reading from unknown address in %08x at %08llx", handle, iter->second.curOffset); return 0; } OpenFileEntry temp; if (fileList[fileIndex].handler != NULL) { temp.handler = fileList[fileIndex].handler; } bool success = temp.Open(basePath, fileList[fileIndex].fileName, FILEACCESS_READ); if (!success) { ERROR_LOG(FILESYS,"VirtualDiscFileSystem: Error opening file %s", fileList[fileIndex].fileName.c_str()); return 0; } u32 startOffset = (iter->second.curOffset-fileList[fileIndex].firstBlock)*2048; size_t bytesRead; temp.Seek(startOffset, FILEMOVE_BEGIN); u32 remainingSize = fileList[fileIndex].totalSize-startOffset; if (remainingSize < size * 2048) { // the file doesn't fill the whole last sector // read what's there and zero fill the rest like on a real disc bytesRead = temp.Read(pointer, remainingSize); memset(&pointer[bytesRead], 0, size * 2048 - bytesRead); } else { bytesRead = temp.Read(pointer, size * 2048); } temp.Close(); iter->second.curOffset += size; return size; } size_t bytesRead = iter->second.Read(pointer, size); iter->second.curOffset += bytesRead; return bytesRead; } else { //This shouldn't happen... ERROR_LOG(FILESYS,"VirtualDiscFileSystem: Cannot read file that hasn't been opened: %08x", handle); return 0; } }
void VirtualDiscFileSystem::DoState(PointerWrap &p) { auto s = p.Section("VirtualDiscFileSystem", 1); if (!s) return; int fileListSize = (int)fileList.size(); int entryCount = (int)entries.size(); p.Do(fileListSize); p.Do(entryCount); p.Do(currentBlockIndex); FileListEntry dummy = {""}; fileList.resize(fileListSize, dummy); for (int i = 0; i < fileListSize; i++) { p.Do(fileList[i].fileName); p.Do(fileList[i].firstBlock); p.Do(fileList[i].totalSize); } if (p.mode == p.MODE_READ) { entries.clear(); for (int i = 0; i < entryCount; i++) { u32 fd = 0; OpenFileEntry of; p.Do(fd); p.Do(of.fileIndex); p.Do(of.type); p.Do(of.curOffset); p.Do(of.startOffset); p.Do(of.size); // open file if (of.type != VFILETYPE_ISO) { if (fileList[of.fileIndex].handler != NULL) { of.handler = fileList[of.fileIndex].handler; } bool success = of.Open(basePath, fileList[of.fileIndex].fileName, FILEACCESS_READ); if (!success) { ERROR_LOG(FILESYS, "Failed to create file handle for %s.", fileList[of.fileIndex].fileName.c_str()); } else { if (of.type == VFILETYPE_LBN) { of.Seek(of.curOffset + of.startOffset, FILEMOVE_BEGIN); } else { of.Seek(of.curOffset, FILEMOVE_BEGIN); } } } entries[fd] = of; } } else { for (EntryMap::iterator it = entries.begin(), end = entries.end(); it != end; ++it) { OpenFileEntry &of = it->second; p.Do(it->first); p.Do(of.fileIndex); p.Do(of.type); p.Do(of.curOffset); p.Do(of.startOffset); p.Do(of.size); } } // We don't savestate handlers (loaded on fs load), but if they change, it may not load properly. }
u32 VirtualDiscFileSystem::OpenFile(std::string filename, FileAccess access, const char *devicename) { OpenFileEntry entry; entry.curOffset = 0; entry.size = 0; entry.startOffset = 0; if (filename == "") { entry.type = VFILETYPE_ISO; entry.fileIndex = -1; u32 newHandle = hAlloc->GetNewHandle(); entries[newHandle] = entry; return newHandle; } if (filename.compare(0,8,"/sce_lbn") == 0) { u32 sectorStart = 0xFFFFFFFF, readSize = 0xFFFFFFFF; parseLBN(filename, §orStart, &readSize); entry.type = VFILETYPE_LBN; entry.size = readSize; int fileIndex = getFileListIndex(sectorStart,readSize); if (fileIndex == -1) { ERROR_LOG(FILESYS, "VirtualDiscFileSystem: sce_lbn used without calling fileinfo."); return 0; } entry.fileIndex = (u32)fileIndex; entry.startOffset = (sectorStart-fileList[entry.fileIndex].firstBlock)*2048; // now we just need an actual file handle if (fileList[entry.fileIndex].handler != NULL) { entry.handler = fileList[entry.fileIndex].handler; } bool success = entry.Open(basePath, fileList[entry.fileIndex].fileName, FILEACCESS_READ); if (!success) { #ifdef _WIN32 ERROR_LOG(FILESYS, "VirtualDiscFileSystem::OpenFile: FAILED, %i", GetLastError()); #else ERROR_LOG(FILESYS, "VirtualDiscFileSystem::OpenFile: FAILED"); #endif return 0; } // seek to start entry.Seek(entry.startOffset, FILEMOVE_BEGIN); u32 newHandle = hAlloc->GetNewHandle(); entries[newHandle] = entry; return newHandle; } entry.type = VFILETYPE_NORMAL; entry.fileIndex = getFileListIndex(filename); if (entry.fileIndex != (u32)-1 && fileList[entry.fileIndex].handler != NULL) { entry.handler = fileList[entry.fileIndex].handler; } bool success = entry.Open(basePath, filename, access); if (!success) { #ifdef _WIN32 ERROR_LOG(FILESYS, "VirtualDiscFileSystem::OpenFile: FAILED, %i - access = %i", GetLastError(), (int)access); #else ERROR_LOG(FILESYS, "VirtualDiscFileSystem::OpenFile: FAILED, access = %i", (int)access); #endif //wwwwaaaaahh!! return 0; } else { u32 newHandle = hAlloc->GetNewHandle(); entries[newHandle] = entry; return newHandle; } }
size_t VirtualDiscFileSystem::ReadFile(u32 handle, u8 *pointer, s64 size, int &usec) { EntryMap::iterator iter = entries.find(handle); if (iter != entries.end()) { if (size < 0) { ERROR_LOG_REPORT(FILESYS, "Invalid read for %lld bytes from virtual umd", size); return 0; } // it's the whole iso... it could reference any of the files on the disc. // For now let's just open and close the files on demand. Can certainly be done // better though if (iter->second.type == VFILETYPE_ISO) { int fileIndex = getFileListIndex(iter->second.curOffset,size*2048,true); if (fileIndex == -1) { ERROR_LOG(FILESYS,"VirtualDiscFileSystem: Reading from unknown address in %08x at %08llx", handle, iter->second.curOffset); return 0; } OpenFileEntry temp; if (fileList[fileIndex].handler != NULL) { temp.handler = fileList[fileIndex].handler; } bool success = temp.Open(basePath, fileList[fileIndex].fileName, FILEACCESS_READ); if (!success) { ERROR_LOG(FILESYS,"VirtualDiscFileSystem: Error opening file %s", fileList[fileIndex].fileName.c_str()); return 0; } u32 startOffset = (iter->second.curOffset-fileList[fileIndex].firstBlock)*2048; size_t bytesRead; temp.Seek(startOffset, FILEMOVE_BEGIN); u32 remainingSize = fileList[fileIndex].totalSize-startOffset; if (remainingSize < size * 2048) { // the file doesn't fill the whole last sector // read what's there and zero fill the rest like on a real disc bytesRead = temp.Read(pointer, remainingSize); memset(&pointer[bytesRead], 0, size * 2048 - bytesRead); } else { bytesRead = temp.Read(pointer, size * 2048); } temp.Close(); iter->second.curOffset += size; // TODO: This probably isn't enough... if (abs((int)lastReadBlock_ - (int)iter->second.curOffset) > 100) { // This is an estimate, sometimes it takes 1+ seconds, but it definitely takes time. usec = 100000; } lastReadBlock_ = iter->second.curOffset; return size; } if (iter->second.type == VFILETYPE_LBN && iter->second.curOffset + size > iter->second.size) { // Clamp to the remaining size, but read what we can. const s64 newSize = iter->second.size - iter->second.curOffset; WARN_LOG(FILESYS, "VirtualDiscFileSystem: Reading beyond end of file, clamping size %lld to %lld", size, newSize); size = newSize; } size_t bytesRead = iter->second.Read(pointer, size); iter->second.curOffset += bytesRead; return bytesRead; } else { //This shouldn't happen... ERROR_LOG(FILESYS,"VirtualDiscFileSystem: Cannot read file that hasn't been opened: %08x", handle); return 0; } }