/* This file is part of jpcsp. Jpcsp 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 3 of the License, or (at your option) any later version. Jpcsp 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 Jpcsp. If not, see <http://www.gnu.org/licenses/>. */ package jpcsp.HLE.VFS.iso; import static jpcsp.HLE.kernel.types.SceKernelErrors.ERROR_ERRNO_INVALID_ARGUMENT; import static jpcsp.HLE.kernel.types.SceKernelErrors.ERROR_INVALID_ARGUMENT; import static jpcsp.HLE.kernel.types.SceKernelErrors.ERROR_KERNEL_FILE_READ_ERROR; import static jpcsp.HLE.modules.IoFileMgrForUser.PSP_SEEK_CUR; import static jpcsp.HLE.modules.IoFileMgrForUser.PSP_SEEK_END; import static jpcsp.HLE.modules.IoFileMgrForUser.PSP_SEEK_SET; import java.io.IOException; import java.nio.ByteBuffer; import jpcsp.HLE.TPointer; import jpcsp.HLE.VFS.AbstractVirtualFile; import jpcsp.HLE.VFS.IVirtualFile; import jpcsp.filesystems.umdiso.UmdIsoFile; import jpcsp.filesystems.umdiso.UmdIsoReader; import jpcsp.memory.IMemoryWriter; import jpcsp.memory.MemoryWriter; import jpcsp.util.Utilities; public class UmdIsoVirtualFile extends AbstractVirtualFile { protected final UmdIsoFile file; protected final boolean sectorBlockMode; protected final UmdIsoReader iso; public UmdIsoVirtualFile(UmdIsoFile file) { super(file); this.file = file; this.sectorBlockMode = false; this.iso = file.getUmdIsoReader(); } public UmdIsoVirtualFile(UmdIsoFile file, boolean sectorBlockMode, UmdIsoReader iso) { super(file); this.file = file; this.sectorBlockMode = sectorBlockMode; this.iso = iso; } @Override public boolean isSectorBlockMode() { return sectorBlockMode; } @Override public int ioIoctl(int command, TPointer inputPointer, int inputLength, TPointer outputPointer, int outputLength) { int result; switch (command) { // UMD file seek set. case 0x01010005: { if (inputPointer.isAddressGood() && inputLength >= 4) { int offset = inputPointer.getValue32(); if (log.isDebugEnabled()) { log.debug(String.format("ioIoctl umd file seek set %d", offset)); } setPosition(offset); result = 0; } else { result = ERROR_INVALID_ARGUMENT; } break; } // Get UMD Primary Volume Descriptor case 0x01020001: { if (outputPointer.isAddressGood() && outputLength == UmdIsoFile.sectorLength) { try { byte[] primaryVolumeSector = iso.readSector(UmdIsoReader.startSector); IMemoryWriter memoryWriter = MemoryWriter.getMemoryWriter(outputPointer.getAddress(), outputLength, 1); for (int i = 0; i < outputLength; i++) { memoryWriter.writeNext(primaryVolumeSector[i] & 0xFF); } memoryWriter.flush(); result = 0; } catch (IOException e) { log.error("ioIoctl", e); result = ERROR_KERNEL_FILE_READ_ERROR; } } else { result = ERROR_ERRNO_INVALID_ARGUMENT; } break; } // Get UMD Path Table case 0x01020002: { if (outputPointer.isAddressGood() && outputLength <= UmdIsoFile.sectorLength) { try { byte[] primaryVolumeSector = iso.readSector(UmdIsoReader.startSector); ByteBuffer primaryVolume = ByteBuffer.wrap(primaryVolumeSector); primaryVolume.position(140); int pathTableLocation = Utilities.readWord(primaryVolume); byte[] pathTableSector = iso.readSector(pathTableLocation); IMemoryWriter memoryWriter = MemoryWriter.getMemoryWriter(outputPointer.getAddress(), outputLength, 1); for (int i = 0; i < outputLength; i++) { memoryWriter.writeNext(pathTableSector[i] & 0xFF); } memoryWriter.flush(); result = 0; } catch (IOException e) { log.error("ioIoctl", e); result = ERROR_KERNEL_FILE_READ_ERROR; } } else { result = ERROR_ERRNO_INVALID_ARGUMENT; } break; } // Get Sector size case 0x01020003: { if (outputPointer.isAddressGood() && outputLength == 4) { outputPointer.setValue32(UmdIsoFile.sectorLength); result = 0; } else { result = ERROR_ERRNO_INVALID_ARGUMENT; } break; } // Get UMD file pointer. case 0x01020004: { if (outputPointer.isAddressGood() && outputLength >= 4) { try { int fPointer = (int) file.getFilePointer(); outputPointer.setValue32(fPointer); if (log.isDebugEnabled()) { log.debug(String.format("ioIoctl umd file get file pointer %d", fPointer)); } result = 0; } catch (IOException e) { log.error("ioIoctl", e); result = ERROR_KERNEL_FILE_READ_ERROR; } } else { result = ERROR_INVALID_ARGUMENT; } break; } // Get UMD file start sector. case 0x01020006: { if (outputPointer.isAddressGood() && outputLength >= 4) { int startSector = 0; startSector = file.getStartSector(); if (log.isDebugEnabled()) { log.debug(String.format("ioIoctl umd file get start sector %d", startSector)); } outputPointer.setValue32(startSector); result = 0; } else { result = ERROR_INVALID_ARGUMENT; } break; } // Get UMD file length in bytes. case 0x01020007: { if (outputPointer.isAddressGood() && outputLength >= 8) { long length = length(); outputPointer.setValue64(length); if (log.isDebugEnabled()) { log.debug(String.format("ioIoctl get file size %d", length)); } result = 0; } else { result = ERROR_INVALID_ARGUMENT; } break; } // Read UMD file. case 0x01030008: { if (inputPointer.isAddressGood() && inputLength >= 4) { int length = inputPointer.getValue32(); if (length > 0) { if (outputPointer.isAddressGood() && outputLength >= length) { try { Utilities.readFully(file, outputPointer.getAddress(), length); setPosition(getPosition() + length); result = length; } catch (IOException e) { log.error("ioIoctl", e); result = ERROR_KERNEL_FILE_READ_ERROR; } } else { result = ERROR_INVALID_ARGUMENT; } } else { result = ERROR_INVALID_ARGUMENT; } } else { result = ERROR_INVALID_ARGUMENT; } break; } // UMD disc read sectors operation. case 0x01F30003: { if (inputPointer.isAddressGood() && inputLength >= 4) { int numberOfSectors = inputPointer.getValue32(); if (numberOfSectors > 0) { if (outputPointer.isAddressGood() && outputLength >= numberOfSectors) { try { int length = numberOfSectors * UmdIsoFile.sectorLength; Utilities.readFully(file, outputPointer.getAddress(), length); setPosition(getPosition() + length); result = length / UmdIsoFile.sectorLength; } catch (IOException e) { log.error("ioIoctl", e); result = ERROR_KERNEL_FILE_READ_ERROR; } } else { result = ERROR_ERRNO_INVALID_ARGUMENT; } } else { result = ERROR_ERRNO_INVALID_ARGUMENT; } } else { result = ERROR_ERRNO_INVALID_ARGUMENT; } break; } // UMD file seek whence. case 0x01F100A6: { if (inputPointer.isAddressGood() && inputLength >= 16) { long offset = inputPointer.getValue64(0); int whence = inputPointer.getValue32(12); if (isSectorBlockMode()) { offset *= UmdIsoFile.sectorLength; } if (log.isDebugEnabled()) { log.debug(String.format("ioIoctl UMD file seek offset %d, whence %d", offset, whence)); } switch (whence) { case PSP_SEEK_SET: setPosition(offset); result = 0; break; case PSP_SEEK_CUR: setPosition(getPosition() + offset); result = 0; break; case PSP_SEEK_END: setPosition(length() + offset); result = 0; break; default: log.error(String.format("ioIoctl - unhandled whence %d", whence)); result = ERROR_INVALID_ARGUMENT; break; } } else { result = ERROR_INVALID_ARGUMENT; } break; } default: result = super.ioIoctl(command, inputPointer, inputLength, outputPointer, outputLength); } return result; } @Override public IVirtualFile duplicate() { IVirtualFile duplicate = null; try { UmdIsoFile umdIsoFile = file.duplicate(); if (umdIsoFile != null) { duplicate = new UmdIsoVirtualFile(umdIsoFile, isSectorBlockMode(), iso); } } catch (IOException e) { log.warn("UmdIsoVirtualFile.duplicate", e); } return duplicate; } public void setLength(long lengthInBytes) { file.setLength(lengthInBytes); } @Override public String toString() { return String.format("UmdIsoVirtualFile[%s, sectorBlockMode=%b]", file, sectorBlockMode); } }