/*
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.kernel.types;
import jpcsp.Memory;
import jpcsp.HLE.Modules;
import jpcsp.util.Utilities;
/** http://psp.jim.sh/pspsdk-doc/structSceIoDirent.html */
public class SceIoDirent extends pspAbstractMemoryMappedStructure {
public SceIoStat stat;
public String filename;
public int extendedInfoAddr; // This field is a pointer to user data and only used by the MemoryStick driver.
public int dummy; // Always 0.
private boolean useExtendedInfo;
public SceIoDirent(SceIoStat stat, String filename) {
this.stat = stat;
this.filename = filename;
}
@Override
protected void read() {
stat = new SceIoStat();
read(stat);
filename = readStringNZ(256);
extendedInfoAddr = read32();
dummy = read32();
}
// Convert a "long" file name into a 8.3 file name.
// TODO Implement correct 8.3 truncation.
private static String convertFileNameTo83(String fileName) {
if (fileName == null) {
return null;
}
// Special character '+' is turned into '_'
fileName = fileName.replace("+", "_");
// File name is upper-cased
fileName = fileName.toUpperCase();
// Split into the name and extension parts
int lastDot = fileName.lastIndexOf(".");
String name;
String ext;
if (lastDot < 0) {
name = fileName;
ext = "";
} else {
name = fileName.substring(0, lastDot);
ext = fileName.substring(lastDot + 1);
}
// All dots in name part are dropped
name = name.replace(".", "");
// The file extension is truncated to 3 characters
if (ext.length() > 3) {
ext = ext.substring(0, 3);
}
// The name is truncated to 6 characters (if longer than 8 characters)
// followed by "~1"
if (name.length() > 8) {
name = name.substring(0, 6) + "~1";
}
// TODO Check if there is a name collision with "~1"
return name + "." + ext;
}
@Override
protected void write() {
write(stat);
writeStringNZ(256, filename);
// NOTE: Do not overwrite the reserved field.
// Tests confirm that sceIoDread only writes the stat and filename.
if (useExtendedInfo) {
if (extendedInfoAddr == 0) {
extendedInfoAddr = read32();
}
if (Memory.isAddressGood(extendedInfoAddr)) {
if (Modules.SysMemUserForUserModule.hleKernelGetCompiledSdkVersion() <= 0x0307FFFF) {
// "reserved" is pointing to an area of unknown size
// - [0..12] "8.3" file name (null-terminated)
// - [13..???] long file name (null-terminated)
Utilities.writeStringNZ(mem, extendedInfoAddr + 0, 13, convertFileNameTo83(filename));
Utilities.writeStringZ(mem, extendedInfoAddr + 13, filename);
} else {
// "reserved" is pointing to an area of total size 1044
// - [0..3] size of area
// - [4..19] "8.3" file name (null-terminated)
// - [20..???] long file name (null-terminated)
int size = mem.read32(extendedInfoAddr);
if (size == 1044) {
Utilities.writeStringNZ(mem, extendedInfoAddr + 4, 13, convertFileNameTo83(filename));
Utilities.writeStringNZ(mem, extendedInfoAddr + 20, 1024, filename);
}
}
}
}
}
public void setUseExtendedInfo(boolean useExtendedInfo) {
this.useExtendedInfo = useExtendedInfo;
}
@Override
public int sizeof() {
return SceIoStat.SIZEOF + 256 + 8;
}
}