/*
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.modules;
import static java.lang.Math.max;
import static java.lang.Math.min;
import static jpcsp.Allegrex.Common._s0;
import static jpcsp.Allegrex.Common._s1;
import static jpcsp.HLE.kernel.types.SceUtilityScreenshotParams.PSP_UTILITY_SCREENSHOT_FORMAT_JPEG;
import static jpcsp.HLE.kernel.types.SceUtilityScreenshotParams.PSP_UTILITY_SCREENSHOT_FORMAT_PNG;
import static jpcsp.HLE.kernel.types.SceUtilityScreenshotParams.PSP_UTILITY_SCREENSHOT_NAMERULE_AUTONUM;
import static jpcsp.HLE.modules.sceFont.PSP_FONT_PIXELFORMAT_4;
import static jpcsp.graphics.GeCommands.ALPHA_ONE_MINUS_SOURCE_ALPHA;
import static jpcsp.graphics.GeCommands.ALPHA_SOURCE_ALPHA;
import static jpcsp.graphics.GeCommands.ALPHA_SOURCE_BLEND_OPERATION_ADD;
import static jpcsp.graphics.GeCommands.CLEAR_COLOR_BUFFER;
import static jpcsp.graphics.GeCommands.CMODE_FORMAT_32BIT_ABGR8888;
import static jpcsp.graphics.GeCommands.PRIM_SPRITES;
import static jpcsp.graphics.GeCommands.TFLT_LINEAR;
import static jpcsp.graphics.GeCommands.TFUNC_FRAGMENT_DOUBLE_TEXTURE_EFECT_REPLACE;
import static jpcsp.graphics.GeCommands.TPSM_PIXEL_STORAGE_MODE_32BIT_ABGR8888;
import static jpcsp.graphics.GeCommands.TPSM_PIXEL_STORAGE_MODE_4BIT_INDEXED;
import static jpcsp.graphics.GeCommands.TWRAP_WRAP_MODE_CLAMP;
import static jpcsp.graphics.GeCommands.VTYPE_POSITION_FORMAT_16_BIT;
import static jpcsp.graphics.GeCommands.VTYPE_TEXTURE_FORMAT_16_BIT;
import static jpcsp.graphics.GeCommands.VTYPE_TRANSFORM_PIPELINE_RAW_COORD;
import static jpcsp.graphics.RE.IRenderingEngine.GU_TEXTURE_2D;
import static jpcsp.graphics.VideoEngine.alignBufferWidth;
import static jpcsp.memory.ImageReader.colorARGBtoABGR;
import jpcsp.GUI.SettingsGUI;
import jpcsp.HLE.BufferInfo;
import jpcsp.HLE.BufferInfo.LengthInfo;
import jpcsp.HLE.BufferInfo.Usage;
import jpcsp.HLE.CanBeNull;
import jpcsp.HLE.HLEFunction;
import jpcsp.HLE.HLELogging;
import jpcsp.HLE.HLEModule;
import jpcsp.HLE.HLEModuleManager;
import jpcsp.HLE.HLEUnimplemented;
import jpcsp.HLE.PspString;
import jpcsp.HLE.StringInfo;
import jpcsp.HLE.TPointer;
import jpcsp.HLE.TPointer32;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.Frame;
import java.awt.Point;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.nio.Buffer;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Locale;
import java.util.MissingResourceException;
import java.util.ResourceBundle;
import javax.imageio.ImageIO;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JRootPane;
import javax.swing.JTextField;
import javax.swing.UIManager;
import javax.swing.border.EmptyBorder;
import jpcsp.Controller;
import jpcsp.Emulator;
import jpcsp.GeneralJpcspException;
import jpcsp.Loader;
import jpcsp.Memory;
import jpcsp.NIDMapper;
import jpcsp.Processor;
import jpcsp.State;
import jpcsp.HLE.Modules;
import jpcsp.HLE.VFS.IVirtualFile;
import jpcsp.HLE.VFS.IVirtualFileSystem;
import jpcsp.HLE.kernel.Managers;
import jpcsp.HLE.kernel.managers.SystemTimeManager;
import jpcsp.HLE.kernel.types.SceFontInfo;
import jpcsp.HLE.kernel.types.SceIoStat;
import jpcsp.HLE.kernel.types.SceKernelErrors;
import jpcsp.HLE.kernel.types.SceKernelLMOption;
import jpcsp.HLE.kernel.types.SceKernelThreadInfo;
import jpcsp.HLE.kernel.types.SceModule;
import jpcsp.HLE.kernel.types.SceUtilityGamedataInstallParams;
import jpcsp.HLE.kernel.types.SceUtilityGameSharingParams;
import jpcsp.HLE.kernel.types.SceUtilityHtmlViewerParams;
import jpcsp.HLE.kernel.types.SceUtilityInstallParams;
import jpcsp.HLE.kernel.types.SceUtilityMsgDialogParams;
import jpcsp.HLE.kernel.types.SceUtilityNetconfParams;
import jpcsp.HLE.kernel.types.SceUtilityNpSigninParams;
import jpcsp.HLE.kernel.types.SceUtilityOskParams;
import jpcsp.HLE.kernel.types.SceUtilitySavedataParam;
import jpcsp.HLE.kernel.types.SceUtilityScreenshotParams;
import jpcsp.HLE.kernel.types.pspUtilityBaseDialog;
import jpcsp.HLE.kernel.types.pspUtilityDialogCommon;
import jpcsp.HLE.kernel.types.SceUtilityOskParams.SceUtilityOskData;
import jpcsp.HLE.kernel.types.pspCharInfo;
import jpcsp.HLE.modules.ModuleMgrForUser.LoadModuleContext;
import jpcsp.HLE.modules.SysMemUserForUser.SysMemInfo;
import jpcsp.crypto.CryptoEngine;
import jpcsp.filesystems.SeekableDataInput;
import jpcsp.format.PNG;
import jpcsp.format.PSF;
import jpcsp.graphics.RE.IRenderingEngine;
import jpcsp.graphics.capture.CaptureImage;
import jpcsp.hardware.MemoryStick;
import jpcsp.hardware.Screen;
import jpcsp.memory.IMemoryReader;
import jpcsp.memory.IMemoryWriter;
import jpcsp.memory.MemoryReader;
import jpcsp.memory.MemoryWriter;
import jpcsp.settings.Settings;
import jpcsp.util.MemoryInputStream;
import jpcsp.util.Utilities;
import jpcsp.util.sceGu;
import org.apache.log4j.Logger;
public class sceUtility extends HLEModule {
public static Logger log = Modules.getLogger("sceUtility");
@Override
public void start() {
gameSharingState = new GameSharingUtilityDialogState("sceUtilityGameSharing");
netplayDialogState = new NotImplementedUtilityDialogState("sceNetplayDialog");
netconfState = new NetconfUtilityDialogState("sceUtilityNetconf");
savedataState = new SavedataUtilityDialogState("sceUtilitySavedata");
msgDialogState = new MsgDialogUtilityDialogState("sceUtilityMsgDialog");
oskState = new OskUtilityDialogState("sceUtilityOsk");
npSigninState = new NpSigninUtilityDialogState("sceUtilityNpSignin");
PS3ScanState = new NotImplementedUtilityDialogState("sceUtilityPS3Scan");
rssReaderState = new NotImplementedUtilityDialogState("sceUtilityRssReader");
rssSubscriberState = new NotImplementedUtilityDialogState("sceUtilityRssSubscriber");
screenshotState = new ScreenshotUtilityDialogState("sceUtilityScreenshot");
htmlViewerState = new HtmlViewerUtilityDialogState("sceUtilityHtmlViewer");
savedataErrState = new NotImplementedUtilityDialogState("sceUtilitySavedataErr");
gamedataInstallState = new GamedataInstallUtilityDialogState("sceUtilityGamedataInstall");
storeCheckoutState = new NotImplementedUtilityDialogState("sceUtilityStoreCheckout");
psnState = new NotImplementedUtilityDialogState("sceUtilityPsn");
installState = new InstallUtilityDialogState("sceUtilityInstall");
startedDialogState = null;
utilityPrivateModules = new HashMap<String, String>();
utilityPrivateModules.put("htmlviewer_ui", "flash0:/vsh/module/htmlviewer_ui.prx");
utilityPrivateModules.put("hvauth_r", "flash0:/vsh/module/hvauth_r.prx");
utilityPrivateModules.put("hvauth_t", "flash0:/vsh/module/hvauth_t.prx");
utilityPrivateModules.put("netfront", "flash0:/vsh/module/netfront.prx");
utilityPrivateModules.put("mgvideo", "flash0:/kd/mgvideo.prx");
utilityPrivateModules.put("mm_flash", "flash0:/vsh/module/mm_flash.prx");
utilityPrivateModules.put("libslim", "flash0:/vsh/module/libslim.prx");
utilityPrivateModules.put("libwww", "flash0:/vsh/module/libwww.prx");
utilityPrivateModules.put("libfont_hv", "flash0:/vsh/module/libfont_hv.prx");
super.start();
}
@Override
public void stop() {
loadedNetModules.clear();
waitingNetModules.clear();
loadedAvModules.clear();
waitingAvModules.clear();
loadedUsbModules.clear();
waitingUsbModules.clear();
loadedModules.clear();
waitingModules.clear();
super.stop();
}
public static final String SYSTEMPARAM_SETTINGS_OPTION_NICKNAME = "emu.sysparam.nickname";
public static final String SYSTEMPARAM_SETTINGS_OPTION_ADHOC_CHANNEL = "emu.sysparam.adhocchannel";
public static final String SYSTEMPARAM_SETTINGS_OPTION_WLAN_POWER_SAVE = "emu.sysparam.wlanpowersave";
public static final String SYSTEMPARAM_SETTINGS_OPTION_DATE_FORMAT = "emu.sysparam.dateformat";
public static final String SYSTEMPARAM_SETTINGS_OPTION_TIME_FORMAT = "emu.sysparam.timeformat";
public static final String SYSTEMPARAM_SETTINGS_OPTION_TIME_ZONE = "emu.sysparam.timezone";
public static final String SYSTEMPARAM_SETTINGS_OPTION_DAYLIGHT_SAVING_TIME = "emu.sysparam.daylightsavings";
public static final String SYSTEMPARAM_SETTINGS_OPTION_LANGUAGE = "emu.impose.language";
public static final String SYSTEMPARAM_SETTINGS_OPTION_BUTTON_PREFERENCE = "emu.impose.button";
public static final String SYSTEMPARAM_SETTINGS_OPTION_LOCK_PARENTAL_LEVEL = "emu.sysparam.locl.parentallevel";
public static final int PSP_SYSTEMPARAM_ID_STRING_NICKNAME = 1; // PSP Registry "/CONFIG/SYSTEM/owner_name"
public static final int PSP_SYSTEMPARAM_ID_INT_ADHOC_CHANNEL = 2; // PSP Registry "/CONFIG/NETWORK/ADHOC/channel"
public static final int PSP_SYSTEMPARAM_ID_INT_WLAN_POWERSAVE = 3; // PSP Registry "/CONFIG/SYSTEM/POWER_SAVING/wlan_mode"
public static final int PSP_SYSTEMPARAM_ID_INT_DATE_FORMAT = 4; // PSP Registry "/CONFIG/DATE/date_format"
public static final int PSP_SYSTEMPARAM_ID_INT_TIME_FORMAT = 5; // PSP Registry "/CONFIG/DATE/time_format"
public static final int PSP_SYSTEMPARAM_ID_INT_TIMEZONE = 6; // PSP Registry "/CONFIG/DATE/time_zone_offset"
public static final int PSP_SYSTEMPARAM_ID_INT_DAYLIGHTSAVINGS = 7; // PSP Registry "/CONFIG/DATE/summer_time"
public static final int PSP_SYSTEMPARAM_ID_INT_LANGUAGE = 8; // PSP Registry "/CONFIG/SYSTEM/XMB/language"
public static final int PSP_SYSTEMPARAM_ID_INT_BUTTON_PREFERENCE = 9; // PSP Registry "/CONFIG/SYSTEM/XMB/button_assign"
public static final int PSP_SYSTEMPARAM_ID_INT_LOCK_PARENTAL_LEVEL = 10; // PSP Registry "/CONFIG/SYSTEM/LOCK/parental_level"
public static final int PSP_SYSTEMPARAM_LANGUAGE_JAPANESE = 0;
public static final int PSP_SYSTEMPARAM_LANGUAGE_ENGLISH = 1;
public static final int PSP_SYSTEMPARAM_LANGUAGE_FRENCH = 2;
public static final int PSP_SYSTEMPARAM_LANGUAGE_SPANISH = 3;
public static final int PSP_SYSTEMPARAM_LANGUAGE_GERMAN = 4;
public static final int PSP_SYSTEMPARAM_LANGUAGE_ITALIAN = 5;
public static final int PSP_SYSTEMPARAM_LANGUAGE_DUTCH = 6;
public static final int PSP_SYSTEMPARAM_LANGUAGE_PORTUGUESE = 7;
public static final int PSP_SYSTEMPARAM_LANGUAGE_RUSSIAN = 8;
public static final int PSP_SYSTEMPARAM_LANGUAGE_KOREAN = 9;
public static final int PSP_SYSTEMPARAM_LANGUAGE_CHINESE_TRADITIONAL = 10;
public static final int PSP_SYSTEMPARAM_LANGUAGE_CHINESE_SIMPLIFIED = 11;
public static final int PSP_SYSTEMPARAM_DATE_FORMAT_YYYYMMDD = 0;
public static final int PSP_SYSTEMPARAM_DATE_FORMAT_MMDDYYYY = 1;
public static final int PSP_SYSTEMPARAM_DATE_FORMAT_DDMMYYYY = 2;
public static final int PSP_SYSTEMPARAM_TIME_FORMAT_24HR = 0;
public static final int PSP_SYSTEMPARAM_TIME_FORMAT_12HR = 1;
public final static int PSP_SYSTEMPARAM_BUTTON_CIRCLE = 0;
public final static int PSP_SYSTEMPARAM_BUTTON_CROSS = 1;
public static final int PSP_UTILITY_DIALOG_STATUS_NONE = 0;
public static final int PSP_UTILITY_DIALOG_STATUS_INIT = 1;
public static final int PSP_UTILITY_DIALOG_STATUS_VISIBLE = 2;
public static final int PSP_UTILITY_DIALOG_STATUS_QUIT = 3;
public static final int PSP_UTILITY_DIALOG_STATUS_FINISHED = 4;
public static final int PSP_UTILITY_DIALOG_STATUS_SCREENSHOT_UNKNOWN = 5;
public static final int PSP_UTILITY_DIALOG_RESULT_OK = 0;
public static final int PSP_UTILITY_DIALOG_RESULT_CANCELED = 1;
public static final int PSP_UTILITY_DIALOG_RESULT_ABORTED = 2;
public static final int PSP_NETPARAM_NAME = 0; // string
public static final int PSP_NETPARAM_SSID = 1; // string
public static final int PSP_NETPARAM_SECURE = 2; // int
public static final int PSP_NETPARAM_WEPKEY = 3; // string
public static final int PSP_NETPARAM_IS_STATIC_IP = 4; // int
public static final int PSP_NETPARAM_IP = 5; // string
public static final int PSP_NETPARAM_NETMASK = 6; // string
public static final int PSP_NETPARAM_ROUTE = 7; // string
public static final int PSP_NETPARAM_MANUAL_DNS = 8; // int
public static final int PSP_NETPARAM_PRIMARYDNS = 9; // string
public static final int PSP_NETPARAM_SECONDARYDNS = 10; // string
public static final int PSP_NETPARAM_PROXY_USER = 11; // string
public static final int PSP_NETPARAM_PROXY_PASS = 12; // string
public static final int PSP_NETPARAM_USE_PROXY = 13; // int
public static final int PSP_NETPARAM_PROXY_SERVER = 14; // string
public static final int PSP_NETPARAM_PROXY_PORT = 15; // int
public static final int PSP_NETPARAM_VERSION = 16; // int
public static final int PSP_NETPARAM_UNKNOWN = 17; // int
public static final int PSP_NETPARAM_8021X_AUTH_TYPE = 18; // int
public static final int PSP_NETPARAM_8021X_USER = 19; // string
public static final int PSP_NETPARAM_8021X_PASS = 20; // string
public static final int PSP_NETPARAM_WPA_TYPE = 21; // int
public static final int PSP_NETPARAM_WPA_KEY = 22; // string
public static final int PSP_NETPARAM_BROWSER = 23; // int
public static final int PSP_NETPARAM_WIFI_CONFIG = 24; // int
public static final int PSP_NETPARAM_MAX_NUMBER_DUMMY_ENTRIES = 10;
protected static final int maxLineLengthForDialog = 40;
protected static final int icon0Width = 144;
protected static final int icon0Height = 80;
protected static final int icon0PixelFormat = TPSM_PIXEL_STORAGE_MODE_32BIT_ABGR8888;
protected static final int smallIcon0Width = 80;
protected static final int smallIcon0Height = 44;
// Round-up width to next valid buffer width
protected static final int icon0BufferWidth = alignBufferWidth(icon0Width + IRenderingEngine.alignementOfTextureBufferWidth[icon0PixelFormat] - 1, icon0PixelFormat);
protected GameSharingUtilityDialogState gameSharingState;
protected UtilityDialogState netplayDialogState;
protected NetconfUtilityDialogState netconfState;
protected SavedataUtilityDialogState savedataState;
protected MsgDialogUtilityDialogState msgDialogState;
protected OskUtilityDialogState oskState;
protected UtilityDialogState npSigninState;
protected UtilityDialogState PS3ScanState;
protected UtilityDialogState rssReaderState;
protected UtilityDialogState rssSubscriberState;
protected ScreenshotUtilityDialogState screenshotState;
protected HtmlViewerUtilityDialogState htmlViewerState;
protected UtilityDialogState savedataErrState;
protected GamedataInstallUtilityDialogState gamedataInstallState;
protected UtilityDialogState storeCheckoutState;
protected UtilityDialogState psnState;
protected UtilityDialogState startedDialogState;
private static final String dummyNetParamName = "NetConf #%d";
private final static int utilityThreadActionRegister = _s0; // $s0 is preserved across calls
private final static int utilityThreadDelayRegister = _s1; // $s1 is preserved across calls
private final static int UTILITY_THREAD_ACTION_SHUTDOWN_START = 0;
private final static int UTILITY_THREAD_ACTION_SHUTDOWN_COMPLETE = 1;
protected HashMap<Integer, SceModule> loadedAvModules = new HashMap<Integer, SceModule>();
protected HashMap<Integer, String> waitingAvModules = new HashMap<Integer, String>();
protected HashMap<Integer, SceModule> loadedUsbModules = new HashMap<Integer, SceModule>();
protected HashMap<Integer, String> waitingUsbModules = new HashMap<Integer, String>();
protected HashMap<Integer, List<SceModule>> loadedModules = new HashMap<Integer, List<SceModule>>();
protected HashMap<Integer, String> waitingModules = new HashMap<Integer, String>();
public static final String[] utilityAvModuleNames = new String[] {
"PSP_AV_MODULE_AVCODEC",
"PSP_AV_MODULE_SASCORE",
"PSP_AV_MODULE_ATRAC3PLUS",
"PSP_AV_MODULE_MPEGBASE",
"PSP_AV_MODULE_MP3",
"PSP_AV_MODULE_VAUDIO",
"PSP_AV_MODULE_AAC",
"PSP_AV_MODULE_G729",
};
public static final String[] utilityUsbModuleNames = new String[] {
"PSP_USB_MODULE_UNKNOWN_0",
"PSP_USB_MODULE_PSPCM",
"PSP_USB_MODULE_ACC",
"PSP_USB_MODULE_MIC",
"PSP_USB_MODULE_CAM",
"PSP_USB_MODULE_GPS"
};
private static HashMap<String, String> utilityPrivateModules;
public static final int PSP_AV_MODULE_AVCODEC = 0;
public static final int PSP_AV_MODULE_SASCORE = 1;
public static final int PSP_AV_MODULE_ATRAC3PLUS = 2;
public static final int PSP_AV_MODULE_MPEGBASE = 3;
public static final int PSP_AV_MODULE_MP3 = 4;
public static final int PSP_AV_MODULE_VAUDIO = 5;
public static final int PSP_AV_MODULE_AAC = 6;
public static final int PSP_AV_MODULE_G729 = 7;
public static final int PSP_USB_MODULE_PSPCM = 1;
public static final int PSP_USB_MODULE_ACC = 2;
public static final int PSP_USB_MODULE_MIC = 3;
public static final int PSP_USB_MODULE_CAM = 4;
public static final int PSP_USB_MODULE_GPS = 5;
protected static class InstallUtilityDialogState extends UtilityDialogState {
protected SceUtilityInstallParams installParams;
public InstallUtilityDialogState(String name) {
super(name);
}
@Override
protected boolean executeUpdateVisible() {
boolean keepVisible = false;
log.warn(String.format("Partial sceUtilityInstallUpdate %s", installParams.toString()));
// We only get the game name from the install params. Is the rest fixed?
String fileName = String.format("ms0:/PSP/GAME/%s/EBOOT.PBP", installParams.gameName);
try {
SeekableDataInput moduleInput = Modules.IoFileMgrForUserModule.getFile(fileName, IoFileMgrForUser.PSP_O_RDONLY);
if (moduleInput != null) {
byte[] moduleBytes = new byte[(int) moduleInput.length()];
moduleInput.readFully(moduleBytes);
ByteBuffer moduleBuffer = ByteBuffer.wrap(moduleBytes);
// TODO How is this module being loaded?
// Does it unload the current module? i.e. re-init the PSP
SceModule module = Emulator.getInstance().load(name, moduleBuffer, true);
Emulator.getClock().resume();
if ((module.fileFormat & Loader.FORMAT_ELF) == Loader.FORMAT_ELF) {
installParams.base.result = 0;
keepVisible = false;
} else {
log.warn("sceUtilityInstall - failed, target is not an ELF");
installParams.base.result = -1;
}
moduleInput.close();
}
} catch (GeneralJpcspException e) {
log.error("General Error : " + e.getMessage());
Emulator.PauseEmu();
} catch (IOException e) {
log.error(String.format("sceUtilityInstall - Error while loading module %s: %s", fileName, e.getMessage()));
installParams.base.result = -1;
}
return keepVisible;
}
@Override
protected pspUtilityBaseDialog createParams() {
installParams = new SceUtilityInstallParams();
return installParams;
}
@Override
protected boolean hasDialog() {
return false;
}
}
public static final String[] utilityNetModuleNames = new String[] {
"PSP_NET_MODULE_UNKNOWN(1)",
"PSP_NET_MODULE_COMMON",
"PSP_NET_MODULE_ADHOC",
"PSP_NET_MODULE_INET",
"PSP_NET_MODULE_PARSEURI",
"PSP_NET_MODULE_PARSEHTTP",
"PSP_NET_MODULE_HTTP",
"PSP_NET_MODULE_SSL",
};
public static final int PSP_NET_MODULE_COMMON = 1;
public static final int PSP_NET_MODULE_ADHOC = 2;
public static final int PSP_NET_MODULE_INET = 3;
public static final int PSP_NET_MODULE_PARSEURI = 4;
public static final int PSP_NET_MODULE_PARSEHTTP = 5;
public static final int PSP_NET_MODULE_HTTP = 6;
public static final int PSP_NET_MODULE_SSL = 7;
protected HashMap<Integer, SceModule> loadedNetModules = new HashMap<Integer, SceModule>();
protected HashMap<Integer, String> waitingNetModules = new HashMap<Integer, String>();
protected InstallUtilityDialogState installState;
private String getNetModuleName(int module) {
if (module < 0 || module >= utilityNetModuleNames.length) {
return "PSP_NET_MODULE_UNKNOWN_" + module;
}
return utilityNetModuleNames[module];
}
protected int hleUtilityLoadNetModule(int module, String moduleName) {
HLEModuleManager moduleManager = HLEModuleManager.getInstance();
if (loadedNetModules.containsKey(module) || waitingNetModules.containsKey(module)) { // Module already loaded.
return SceKernelErrors.ERROR_NET_MODULE_ALREADY_LOADED;
} else if (!moduleManager.hasFlash0Module(moduleName)) { // Can't load flash0 module.
waitingNetModules.put(module, moduleName); // Always save a load attempt.
return SceKernelErrors.ERROR_NET_MODULE_BAD_ID;
} else {
// Load and save it in loadedNetModules.
int sceModuleId = moduleManager.LoadFlash0Module(moduleName);
SceModule sceModule = Managers.modules.getModuleByUID(sceModuleId);
loadedNetModules.put(module, sceModule);
return 0;
}
}
protected int hleUtilityUnloadNetModule(int module) {
if (loadedNetModules.containsKey(module)) {
// Unload the module.
HLEModuleManager moduleManager = HLEModuleManager.getInstance();
SceModule sceModule = loadedNetModules.remove(module);
moduleManager.UnloadFlash0Module(sceModule);
return 0;
} else if (waitingNetModules.containsKey(module)) {
// Simulate a successful unload.
waitingNetModules.remove(module);
return 0;
} else {
return SceKernelErrors.ERROR_NET_MODULE_NOT_LOADED;
}
}
private static Locale getUtilityLocale(int language) {
Locale utilityLocale = Locale.getDefault();
switch (language) {
case PSP_SYSTEMPARAM_LANGUAGE_JAPANESE: utilityLocale = Locale.JAPANESE; break;
case PSP_SYSTEMPARAM_LANGUAGE_ENGLISH: utilityLocale = Locale.ENGLISH; break;
case PSP_SYSTEMPARAM_LANGUAGE_FRENCH: utilityLocale = Locale.FRENCH; break;
case PSP_SYSTEMPARAM_LANGUAGE_SPANISH: utilityLocale = new Locale("es"); break;
case PSP_SYSTEMPARAM_LANGUAGE_GERMAN: utilityLocale = Locale.GERMAN; break;
case PSP_SYSTEMPARAM_LANGUAGE_ITALIAN: utilityLocale = Locale.ITALIAN; break;
case PSP_SYSTEMPARAM_LANGUAGE_DUTCH: utilityLocale = new Locale("nl"); break;
case PSP_SYSTEMPARAM_LANGUAGE_PORTUGUESE: utilityLocale = new Locale("pt"); break;
case PSP_SYSTEMPARAM_LANGUAGE_RUSSIAN: utilityLocale = new Locale("ru"); break;
case PSP_SYSTEMPARAM_LANGUAGE_KOREAN: utilityLocale = Locale.KOREAN; break;
case PSP_SYSTEMPARAM_LANGUAGE_CHINESE_TRADITIONAL: utilityLocale = Locale.TRADITIONAL_CHINESE; break;
case PSP_SYSTEMPARAM_LANGUAGE_CHINESE_SIMPLIFIED: utilityLocale = Locale.CHINESE; break;
}
return utilityLocale;
}
private static String getDateTimeFormatString() {
StringBuilder dateTimeFormat = new StringBuilder();
switch (getSystemParamDateFormat()) {
case PSP_SYSTEMPARAM_DATE_FORMAT_DDMMYYYY:
dateTimeFormat.append("%te/%<tm/%<tY");
break;
case PSP_SYSTEMPARAM_DATE_FORMAT_MMDDYYYY:
dateTimeFormat.append("%tm/%<te/%<tY");
break;
case PSP_SYSTEMPARAM_DATE_FORMAT_YYYYMMDD:
dateTimeFormat.append("%tY/%<tm/%<te");
break;
default:
dateTimeFormat.append("%tF");
break;
}
dateTimeFormat.append(" ");
switch (getSystemParamTimeFormat()) {
case PSP_SYSTEMPARAM_TIME_FORMAT_12HR:
dateTimeFormat.append("%<tl:%<tM %<Tp");
break;
case PSP_SYSTEMPARAM_TIME_FORMAT_24HR:
dateTimeFormat.append("%<tk:%<tM");
break;
default:
dateTimeFormat.append("%<tR");
break;
}
return dateTimeFormat.toString();
}
private static String formatDateTime(Calendar dateTime) {
return String.format(getDateTimeFormatString(), dateTime);
}
public void hleUtilityThread(Processor processor) {
int action = processor.cpu.getRegister(utilityThreadActionRegister);
int delay = processor.cpu.getRegister(utilityThreadDelayRegister);
if (log.isDebugEnabled()) {
log.debug(String.format("hleUtilityThread action=%d, delay=%d", action, delay));
}
switch (action) {
case UTILITY_THREAD_ACTION_SHUTDOWN_START:
// Starting the shutdown action.
// Wait a short time before completing the shutdown.
processor.cpu.setRegister(utilityThreadActionRegister, UTILITY_THREAD_ACTION_SHUTDOWN_COMPLETE);
Modules.ThreadManForUserModule.hleKernelDelayThread(delay, false);
break;
case UTILITY_THREAD_ACTION_SHUTDOWN_COMPLETE:
// Completing the shutdown action.
startedDialogState.status = PSP_UTILITY_DIALOG_STATUS_NONE;
processor.cpu._v0 = 0;
Modules.ThreadManForUserModule.hleKernelExitDeleteThread();
break;
}
}
protected abstract static class UtilityDialogState {
protected String name;
protected pspUtilityBaseDialog params;
protected TPointer paramsAddr;
protected int status;
protected UtilityDialog dialog;
protected int drawSpeed;
protected int minimumVisibleDurationMillis;
protected long startVisibleTimeMillis;
protected int buttonPressed;
protected GuUtilityDialog guDialog;
protected boolean isOnlyGeGraphics;
protected boolean isYesSelected;
protected static enum DialogState {
init,
display,
confirmation,
inProgress,
completed,
quit
};
protected DialogState dialogState;
public UtilityDialogState(String name) {
this.name = name;
status = PSP_UTILITY_DIALOG_STATUS_NONE;
dialogState = DialogState.init;
setButtonPressed(SceUtilityMsgDialogParams.PSP_UTILITY_BUTTON_PRESSED_INVALID);
}
protected void openDialog(UtilityDialog dialog) {
if (dialogState == DialogState.init) {
dialogState = DialogState.display;
}
status = PSP_UTILITY_DIALOG_STATUS_VISIBLE;
this.dialog = dialog;
dialog.setVisible(true);
}
protected void openDialog(GuUtilityDialog guDialog) {
if (dialogState == DialogState.init) {
dialogState = DialogState.display;
}
status = PSP_UTILITY_DIALOG_STATUS_VISIBLE;
this.guDialog = guDialog;
// The option "Only GE Graphics" cannot be used during the
// rendering of the GU dialog. The GE list has to be rendered
// additionally to the application display.
isOnlyGeGraphics = Modules.sceDisplayModule.isOnlyGEGraphics();
if (isOnlyGeGraphics) {
Modules.sceDisplayModule.setOnlyGEGraphics(false);
}
}
protected boolean isDialogOpen() {
return dialog != null || guDialog != null;
}
protected void updateDialog() {
int delayMicros = 1000000 / 60;
// if (drawSpeed > 0) {
// delayMicros *= drawSpeed;
// }
Modules.ThreadManForUserModule.hleKernelDelayThread(delayMicros, false);
}
protected boolean isDialogActive() {
if (isDialogOpen()) {
if (dialog != null) {
return dialog.isVisible();
}
if (guDialog != null) {
return guDialog.isVisible();
}
}
return false;
}
protected void closeDialog() {
if (dialog != null) {
dialog = null;
}
if (guDialog != null) {
// Reset the previous state of the option "Only GE Graphics"
if (isOnlyGeGraphics) {
Modules.sceDisplayModule.setOnlyGEGraphics(isOnlyGeGraphics);
}
guDialog = null;
}
}
private void setResult(int result) {
if (params != null && params.base != null) {
params.base.result = result;
params.base.writeResult(paramsAddr);
}
}
protected void quitDialog() {
closeDialog();
status = PSP_UTILITY_DIALOG_STATUS_QUIT;
dialogState = DialogState.quit;
}
protected void quitDialog(int result) {
quitDialog();
setResult(result);
}
public int getButtonPressed() {
return buttonPressed;
}
final public void setButtonPressed(int buttonPressed) {
this.buttonPressed = buttonPressed;
}
public int executeInitStart(TPointer paramsAddr) {
if (status != PSP_UTILITY_DIALOG_STATUS_NONE) {
if (log.isDebugEnabled()) {
log.debug(String.format("%sInitStart already started status=%d", name, status));
}
return SceKernelErrors.ERROR_UTILITY_INVALID_STATUS;
}
this.paramsAddr = paramsAddr;
this.params = createParams();
params.read(paramsAddr);
if (log.isInfoEnabled()) {
log.info(String.format("%sInitStart %s-0x%08X: %s", name, paramsAddr, paramsAddr.getAddress() + params.sizeof(), params.toString()));
}
int validityResult = checkValidity();
if (validityResult == 0) {
// Start with INIT
status = PSP_UTILITY_DIALOG_STATUS_INIT;
dialogState = DialogState.init;
Modules.sceUtilityModule.startedDialogState = this;
// Move directly to status VISIBLE when there is no dialog needed.
if (!hasDialog()) {
status = PSP_UTILITY_DIALOG_STATUS_VISIBLE;
dialogState = DialogState.quit;
startVisibleTimeMillis = Emulator.getClock().currentTimeMillis();
}
}
return validityResult;
}
protected boolean isReadyForVisible() {
// Wait for all the buttons to be released
if (State.controller.getButtons() != 0) {
if (log.isDebugEnabled()) {
log.debug(String.format("Not ready for visible, button pressed 0x%X", State.controller.getButtons()));
}
return false;
}
return true;
}
protected boolean hasDialog() {
return true;
}
public int executeGetStatus() {
// Return ERROR_UTILITY_WRONG_TYPE if no sceUtilityXXXInitStart has ever been started or
// if a different type of dialog was started.
if (Modules.sceUtilityModule.startedDialogState == null || Modules.sceUtilityModule.startedDialogState != this) {
if (log.isDebugEnabled()) {
log.debug(String.format("%sGetStatus returning ERROR_UTILITY_WRONG_TYPE", name));
}
return SceKernelErrors.ERROR_UTILITY_WRONG_TYPE;
}
if (log.isDebugEnabled()) {
log.debug(String.format("%sGetStatus status %d", name, status));
}
int previousStatus = status;
// Remark: moving from FINISHED status to NONE is performed in the shutdown thread.
if (status == PSP_UTILITY_DIALOG_STATUS_INIT && isReadyForVisible()) {
// Move from INIT to VISIBLE
status = PSP_UTILITY_DIALOG_STATUS_VISIBLE;
startVisibleTimeMillis = Emulator.getClock().currentTimeMillis();
}
// After moving to status NONE, subsequent calls of sceUtilityXXXGetStatus
// keep returning status NONE (if of the same type) and not ERROR_UTILITY_WRONG_TYPE.
// Keep the current value in Modules.sceUtilityModule.startedDialogState for this purpose.
return previousStatus;
}
public int executeShutdownStart() {
if (Modules.sceUtilityModule.startedDialogState == null || Modules.sceUtilityModule.startedDialogState != this) {
if (log.isDebugEnabled()) {
log.debug(String.format("%ShutdownStart returning ERROR_UTILITY_WRONG_TYPE", name));
}
return SceKernelErrors.ERROR_UTILITY_WRONG_TYPE;
}
if (status != PSP_UTILITY_DIALOG_STATUS_QUIT) {
if (log.isDebugEnabled()) {
log.debug(String.format("%ShutdownStart returning ERROR_UTILITY_INVALID_STATUS", name));
}
return SceKernelErrors.ERROR_UTILITY_INVALID_STATUS;
}
status = PSP_UTILITY_DIALOG_STATUS_FINISHED;
// Execute the shutdown thread, it will set the status to 0.
SceKernelThreadInfo shutdownThread = Modules.ThreadManForUserModule.hleKernelCreateThread("SceUtilityShutdown", ThreadManForUser.UTILITY_LOOP_ADDRESS, params.base.accessThread, 0x800, 0, 0, SysMemUserForUser.USER_PARTITION_ID);
Modules.ThreadManForUserModule.hleKernelStartThread(shutdownThread, 0, 0, shutdownThread.gpReg_addr);
shutdownThread.cpuContext.setRegister(utilityThreadActionRegister, UTILITY_THREAD_ACTION_SHUTDOWN_START);
shutdownThread.cpuContext.setRegister(utilityThreadDelayRegister, getShutdownDelay());
return 0;
}
/**
* @param drawSpeed FPS used for internal animation sync (1 = 60 FPS; 2 = 30 FPS; 3 = 15 FPS)
* @return
*/
public final int executeUpdate(int drawSpeed) {
this.drawSpeed = drawSpeed;
if (Modules.sceUtilityModule.startedDialogState == null || Modules.sceUtilityModule.startedDialogState != this) {
if (log.isDebugEnabled()) {
log.debug(String.format("%sUpdate returning ERROR_UTILITY_WRONG_TYPE", name));
}
return SceKernelErrors.ERROR_UTILITY_WRONG_TYPE;
}
// PSP is returning ERROR_UTILITY_INVALID_STATUS when not in STATUS_VISIBLE
int result = SceKernelErrors.ERROR_UTILITY_INVALID_STATUS;
if (status == PSP_UTILITY_DIALOG_STATUS_INIT && isReadyForVisible()) {
// Move from INIT to VISIBLE
status = PSP_UTILITY_DIALOG_STATUS_VISIBLE;
startVisibleTimeMillis = Emulator.getClock().currentTimeMillis();
} else if (status == PSP_UTILITY_DIALOG_STATUS_VISIBLE || status == PSP_UTILITY_DIALOG_STATUS_SCREENSHOT_UNKNOWN) {
// PSP is returning 0 only in STATUS_VISIBLE
result = 0;
// Some games reach sceUtilitySavedataInitStart with empty params which only
// get filled with a subsequent call to sceUtilitySavedataUpdate (eg.: To Love-Ru).
// This is why we have to re-read the params here.
params.read(paramsAddr);
if (guDialog != null) {
guDialog.update(drawSpeed);
}
boolean keepVisible = executeUpdateVisible();
if (status == PSP_UTILITY_DIALOG_STATUS_VISIBLE && isDialogOpen()) {
if (dialog != null) {
dialog.checkController();
}
if (guDialog != null) {
guDialog.checkController();
}
}
if (status == PSP_UTILITY_DIALOG_STATUS_VISIBLE && !isDialogOpen() && !keepVisible && dialogState == DialogState.quit) {
// Check if we stayed long enough in the VISIBLE state
long now = Emulator.getClock().currentTimeMillis();
if (now - startVisibleTimeMillis >= getMinimumVisibleDurationMillis()) {
// There was no dialog or it has completed
status = PSP_UTILITY_DIALOG_STATUS_QUIT;
}
}
}
if (log.isDebugEnabled()) {
log.debug(String.format("%sUpdate returning 0x%08X", name, result));
}
return result;
}
public int executeAbort() {
if (Modules.sceUtilityModule.startedDialogState == null || Modules.sceUtilityModule.startedDialogState != this) {
if (log.isDebugEnabled()) {
log.debug(String.format("%sAbort returning ERROR_UTILITY_WRONG_TYPE", name));
}
return SceKernelErrors.ERROR_UTILITY_WRONG_TYPE;
}
if (status != PSP_UTILITY_DIALOG_STATUS_VISIBLE) {
if (log.isDebugEnabled()) {
log.debug(String.format("%sAbort returning ERROR_UTILITY_INVALID_STATUS", name));
}
return SceKernelErrors.ERROR_UTILITY_INVALID_STATUS;
}
if (log.isDebugEnabled()) {
log.debug(String.format("%sAbort", name));
}
quitDialog(PSP_UTILITY_DIALOG_RESULT_ABORTED);
return 0;
}
public void cancel() {
quitDialog(PSP_UTILITY_DIALOG_RESULT_CANCELED);
}
protected abstract boolean executeUpdateVisible();
protected abstract pspUtilityBaseDialog createParams();
protected int checkValidity() {
return 0;
}
public int getMinimumVisibleDurationMillis() {
return minimumVisibleDurationMillis;
}
public void setMinimumVisibleDurationMillis(int minimumVisibleDurationMillis) {
this.minimumVisibleDurationMillis = minimumVisibleDurationMillis;
}
protected String getDialogTitle(String key, String defaultTitle, Locale utilityLocale) {
String title;
try {
ResourceBundle bundle = ResourceBundle.getBundle("jpcsp/languages/jpcsp", utilityLocale);
if (key == null) {
title = bundle.getString(name);
} else {
title = bundle.getString(name + "." + key);
}
} catch (MissingResourceException mre) {
title = defaultTitle;
}
return title;
}
public boolean isYesSelected() {
return isYesSelected;
}
public boolean isNoSelected() {
return !isYesSelected;
}
public void setYesSelected(boolean isYesSelected) {
this.isYesSelected = isYesSelected;
}
protected int getShutdownDelay() {
if (hasDialog()) {
// The shutdown is taking some time to complete
// when a dialog has been shown to the user.
return 50000;
}
return 0;
}
}
protected static class NotImplementedUtilityDialogState extends UtilityDialogState {
public NotImplementedUtilityDialogState(String name) {
super(name);
}
@Override
public int executeInitStart(TPointer paramsAddr) {
log.warn(String.format("Unimplemented: %sInitStart params: %s", name, Utilities.getMemoryDump(paramsAddr.getAddress(), paramsAddr.getValue32())));
return SceKernelErrors.ERROR_UTILITY_IS_UNKNOWN;
}
@Override
public int executeShutdownStart() {
log.warn(String.format("Unimplemented: %sShutdownStart", name));
return SceKernelErrors.ERROR_UTILITY_IS_UNKNOWN;
}
@Override
public int executeGetStatus() {
log.warn(String.format("Unimplemented: %sGetStatus", name));
return SceKernelErrors.ERROR_UTILITY_IS_UNKNOWN;
}
@Override
protected boolean executeUpdateVisible() {
log.warn(String.format("Unimplemented: %sUpdate", name));
return false;
}
@Override
protected pspUtilityBaseDialog createParams() {
return null;
}
@Override
protected boolean hasDialog() {
return false;
}
}
protected static class SavedataUtilityDialogState extends UtilityDialogState {
protected SceUtilitySavedataParam savedataParams;
protected volatile String saveListSelection;
protected boolean saveListEmpty;
public SavedataUtilityDialogState(String name) {
super(name);
// Stay at least 500ms in the VISIBLE state.
// E.g. do not complete too quickly the AUTOLOAD/AUTOSAVE modes.
setMinimumVisibleDurationMillis(500);
}
@Override
protected pspUtilityBaseDialog createParams() {
savedataParams = new SceUtilitySavedataParam();
return savedataParams;
}
@Override
protected int checkValidity() {
int paramSize = savedataParams.base.totalSizeof();
// Only these parameter sizes are allowed:
if (paramSize != 1480 && paramSize != 1500 && paramSize != 1536) {
log.warn(String.format("sceUtilitySavedataInitStart invalid parameter size %d", paramSize));
return SceKernelErrors.ERROR_UTILITY_INVALID_PARAM_SIZE;
}
return super.checkValidity();
}
// All SAVEDATA modes after MODE_SINGLEDELETE can be called multiple times and keep track of that.
private int savedataMultiStatus;
protected int checkMultipleCallStatus() {
// Check the current multiple call status.
if (savedataParams.multiStatus == SceUtilitySavedataParam.MULTI_STATUS_SINGLE
|| savedataParams.multiStatus == SceUtilitySavedataParam.MULTI_STATUS_INIT) {
// If the multiple call status is SINGLE or INIT, just save it.
savedataMultiStatus = savedataParams.multiStatus;
return 0;
}
if (savedataParams.multiStatus == SceUtilitySavedataParam.MULTI_STATUS_RELAY
|| savedataParams.multiStatus == SceUtilitySavedataParam.MULTI_STATUS_FINISH) {
// If the multiple call status is RELAY or FINISH, check if INIT or another RELAY has been called.
if (savedataMultiStatus <= savedataParams.multiStatus) {
savedataMultiStatus = savedataParams.multiStatus;
return 0;
}
}
return SceKernelErrors.ERROR_SAVEDATA_RW_BAD_STATUS;
}
@Override
protected boolean executeUpdateVisible() {
Memory mem = Processor.memory;
switch (savedataParams.mode) {
case SceUtilitySavedataParam.MODE_AUTOLOAD: {
if (savedataParams.saveName == null
|| savedataParams.saveName.equals(SceUtilitySavedataParam.anyFileName)
|| savedataParams.saveName.length() == 0) {
if (savedataParams.saveNameList != null && savedataParams.saveNameList.length > 0) {
savedataParams.saveName = savedataParams.saveNameList[0];
}
}
try {
savedataParams.load(mem);
savedataParams.base.result = 0;
savedataParams.write(mem);
} catch (IOException e) {
if (!savedataParams.isGameDirectoryPresent()) {
savedataParams.base.result = SceKernelErrors.ERROR_SAVEDATA_LOAD_NO_DATA;
} else if (savedataParams.base.totalSizeof() < 1536) {
savedataParams.base.result = SceKernelErrors.ERROR_SAVEDATA_LOAD_NO_DATA;
} else {
// The PSP is returning a different return code based on the size of the savedataParams input structure.
savedataParams.base.result = SceKernelErrors.ERROR_SAVEDATA_LOAD_NO_UMD;
}
} catch (Exception e) {
savedataParams.base.result = SceKernelErrors.ERROR_SAVEDATA_LOAD_ACCESS_ERROR;
log.error(e);
}
break;
}
case SceUtilitySavedataParam.MODE_LOAD: {
switch (dialogState) {
case init: {
if (savedataParams.saveName == null || savedataParams.saveName.length() == 0) {
if (savedataParams.saveNameList != null && savedataParams.saveNameList.length > 0) {
savedataParams.saveName = savedataParams.saveNameList[0];
}
}
setYesSelected(true);
GuSavedataDialogLoad gu = new GuSavedataDialogLoad(savedataParams, this);
openDialog(gu);
dialogState = DialogState.confirmation;
break;
}
case confirmation: {
if (!isDialogActive()) {
if (getButtonPressed() != SceUtilityMsgDialogParams.PSP_UTILITY_BUTTON_PRESSED_OK || isNoSelected()) {
// The dialog has been cancelled or the user did not want to load.
cancel();
} else {
closeDialog();
dialogState = DialogState.inProgress;
}
} else {
updateDialog();
}
break;
}
case inProgress: {
try {
savedataParams.load(mem);
savedataParams.base.result = 0;
savedataParams.write(mem);
} catch (IOException e) {
if (!savedataParams.isGameDirectoryPresent()) {
savedataParams.base.result = SceKernelErrors.ERROR_SAVEDATA_LOAD_NO_DATA;
} else if (savedataParams.base.totalSizeof() < 1536) {
savedataParams.base.result = SceKernelErrors.ERROR_SAVEDATA_LOAD_NO_DATA;
} else {
// The PSP is returning a different return code based on the size of the savedataParams input structure.
savedataParams.base.result = SceKernelErrors.ERROR_SAVEDATA_LOAD_NO_UMD;
}
} catch (Exception e) {
savedataParams.base.result = SceKernelErrors.ERROR_SAVEDATA_LOAD_ACCESS_ERROR;
log.error(e);
}
if (isReadyForVisible()) {
GuSavedataDialogCompleted gu = new GuSavedataDialogCompleted(savedataParams, this);
openDialog(gu);
dialogState = DialogState.completed;
}
break;
}
case completed: {
if (!isDialogActive()) {
quitDialog();
} else {
updateDialog();
}
break;
}
case display:
case quit:
// Nothing to do
break;
}
break;
}
case SceUtilitySavedataParam.MODE_LISTLOAD: {
switch (dialogState) {
case init: {
// Search for valid saves.
ArrayList<String> validNames = new ArrayList<String>();
for (int i = 0; i < savedataParams.saveNameList.length; i++) {
savedataParams.saveName = savedataParams.saveNameList[i];
if (savedataParams.isPresent()) {
validNames.add(savedataParams.saveName);
}
}
GuSavedataDialog gu = new GuSavedataDialog(savedataParams, this, validNames.toArray(new String[validNames.size()]));
openDialog(gu);
break;
}
case display: {
if (!isDialogActive()) {
if (getButtonPressed() != SceUtilityMsgDialogParams.PSP_UTILITY_BUTTON_PRESSED_OK) {
if (saveListEmpty) {
// No data available
savedataParams.base.result = SceKernelErrors.ERROR_SAVEDATA_LOAD_NO_DATA;
} else {
// Dialog cancelled
savedataParams.base.result = SceKernelErrors.ERROR_SAVEDATA_LOAD_BAD_PARAMS;
}
quitDialog(savedataParams.base.result);
} else if (saveListSelection == null) {
log.warn("Savedata MODE_LISTLOAD no save selected");
quitDialog(SceKernelErrors.ERROR_SAVEDATA_LOAD_BAD_PARAMS);
} else {
closeDialog();
dialogState = DialogState.inProgress;
}
} else {
updateDialog();
}
break;
}
case inProgress: {
try {
savedataParams.saveName = saveListSelection;
if (log.isDebugEnabled()) {
log.debug(String.format("Loading savedata %s", savedataParams.saveName));
}
savedataParams.load(mem);
savedataParams.base.result = 0;
savedataParams.write(mem);
} catch (IOException e) {
if (!savedataParams.isGameDirectoryPresent()) {
savedataParams.base.result = SceKernelErrors.ERROR_SAVEDATA_LOAD_NO_DATA;
} else if (savedataParams.base.totalSizeof() < 1536) {
savedataParams.base.result = SceKernelErrors.ERROR_SAVEDATA_LOAD_NO_DATA;
} else {
// The PSP is returning a different return code based on the size of the savedataParams input structure.
savedataParams.base.result = SceKernelErrors.ERROR_SAVEDATA_LOAD_NO_UMD;
}
} catch (Exception e) {
savedataParams.base.result = SceKernelErrors.ERROR_SAVEDATA_LOAD_ACCESS_ERROR;
log.error(e);
}
if (isReadyForVisible()) {
GuSavedataDialogCompleted gu = new GuSavedataDialogCompleted(savedataParams, this);
openDialog(gu);
dialogState = DialogState.completed;
}
break;
}
case completed: {
if (!isDialogActive()) {
quitDialog();
} else {
updateDialog();
}
break;
}
case confirmation:
case quit:
// Nothing to do
break;
}
break;
}
case SceUtilitySavedataParam.MODE_AUTOSAVE: {
if (savedataParams.saveName == null
|| savedataParams.saveName.equals(SceUtilitySavedataParam.anyFileName)
|| savedataParams.saveName.length() == 0) {
if (savedataParams.saveNameList != null && savedataParams.saveNameList.length > 0) {
savedataParams.saveName = savedataParams.saveNameList[0];
}
}
try {
savedataParams.save(mem);
savedataParams.base.result = 0;
} catch (IOException e) {
savedataParams.base.result = SceKernelErrors.ERROR_SAVEDATA_SAVE_ACCESS_ERROR;
} catch (Exception e) {
savedataParams.base.result = SceKernelErrors.ERROR_SAVEDATA_SAVE_ACCESS_ERROR;
log.error(e);
}
break;
}
case SceUtilitySavedataParam.MODE_SAVE: {
switch (dialogState) {
case init: {
if (savedataParams.saveName == null || savedataParams.saveName.length() == 0) {
if (savedataParams.saveNameList != null && savedataParams.saveNameList.length > 0) {
savedataParams.saveName = savedataParams.saveNameList[0];
}
}
// Yes is selected by default if the save does not exist.
// No is selected by default if the save does exist (overwrite).
setYesSelected(!savedataParams.isPresent());
GuSavedataDialogSave gu = new GuSavedataDialogSave(savedataParams, this);
openDialog(gu);
dialogState = DialogState.confirmation;
break;
}
case confirmation: {
if (!isDialogActive()) {
if (getButtonPressed() != SceUtilityMsgDialogParams.PSP_UTILITY_BUTTON_PRESSED_OK || isNoSelected()) {
// The dialog has been cancelled or the user did not want to save.
cancel();
} else {
closeDialog();
dialogState = DialogState.inProgress;
}
} else {
updateDialog();
}
break;
}
case inProgress: {
try {
savedataParams.save(mem);
savedataParams.base.result = 0;
} catch (IOException e) {
savedataParams.base.result = SceKernelErrors.ERROR_SAVEDATA_SAVE_ACCESS_ERROR;
} catch (Exception e) {
savedataParams.base.result = SceKernelErrors.ERROR_SAVEDATA_SAVE_ACCESS_ERROR;
log.error(e);
}
if (isReadyForVisible()) {
GuSavedataDialogCompleted gu = new GuSavedataDialogCompleted(savedataParams, this);
openDialog(gu);
dialogState = DialogState.completed;
}
break;
}
case completed: {
if (!isDialogActive()) {
quitDialog();
} else {
updateDialog();
}
break;
}
case display:
case quit:
// Nothing to do
break;
}
break;
}
case SceUtilitySavedataParam.MODE_LISTSAVE: {
switch (dialogState) {
case init: {
GuSavedataDialog gu = new GuSavedataDialog(savedataParams, this, savedataParams.saveNameList);
openDialog(gu);
break;
}
case display: {
if (!isDialogActive()) {
closeDialog();
if (getButtonPressed() != SceUtilityMsgDialogParams.PSP_UTILITY_BUTTON_PRESSED_OK) {
// Dialog cancelled
quitDialog(SceKernelErrors.ERROR_SAVEDATA_SAVE_BAD_PARAMS);
} else if (saveListSelection == null) {
log.warn("Savedata MODE_LISTSAVE no save selected");
quitDialog(SceKernelErrors.ERROR_SAVEDATA_SAVE_BAD_PARAMS);
} else {
savedataParams.saveName = saveListSelection;
savedataParams.write(mem);
if (savedataParams.isPresent(savedataParams.gameName, saveListSelection)) {
if (isReadyForVisible()) {
GuSavedataDialogSave gu = new GuSavedataDialogSave(savedataParams, this);
openDialog(gu);
dialogState = DialogState.confirmation;
}
} else {
dialogState = DialogState.inProgress;
}
}
} else {
updateDialog();
}
break;
}
case confirmation: {
if (!isDialogActive()) {
if (getButtonPressed() != SceUtilityMsgDialogParams.PSP_UTILITY_BUTTON_PRESSED_OK || isNoSelected()) {
// The dialog has been cancelled or the user did not want to save.
cancel();
} else {
closeDialog();
dialogState = DialogState.inProgress;
}
} else {
updateDialog();
}
break;
}
case inProgress: {
try {
if (log.isDebugEnabled()) {
log.debug(String.format("Saving savedata %s", savedataParams.saveName));
}
savedataParams.save(mem);
savedataParams.base.result = 0;
} catch (IOException e) {
savedataParams.base.result = SceKernelErrors.ERROR_SAVEDATA_SAVE_ACCESS_ERROR;
} catch (Exception e) {
savedataParams.base.result = SceKernelErrors.ERROR_SAVEDATA_SAVE_ACCESS_ERROR;
log.error(e);
}
if (isReadyForVisible()) {
GuSavedataDialogCompleted gu = new GuSavedataDialogCompleted(savedataParams, this);
openDialog(gu);
dialogState = DialogState.completed;
}
break;
}
case completed: {
if (!isDialogActive()) {
quitDialog();
} else {
updateDialog();
}
break;
}
case quit:
// Nothing to do
break;
}
break;
}
case SceUtilitySavedataParam.MODE_DELETE: {
if (!isDialogOpen()) {
// Search for valid saves.
String pattern = savedataParams.gameName + ".*";
String[] entries = Modules.IoFileMgrForUserModule.listFiles(SceUtilitySavedataParam.savedataPath, pattern);
ArrayList<String> validNames = new ArrayList<String>();
for (int i = 0; entries != null && i < entries.length; i++) {
String saveName = entries[i].substring(savedataParams.gameName.length());
if (savedataParams.isPresent(savedataParams.gameName, saveName)) {
validNames.add(saveName);
}
}
GuSavedataDialog gu = new GuSavedataDialog(savedataParams, this, validNames.toArray(new String[validNames.size()]));
openDialog(gu);
} else if (!isDialogActive()) {
if (getButtonPressed() != SceUtilityMsgDialogParams.PSP_UTILITY_BUTTON_PRESSED_OK) {
// Dialog cancelled
savedataParams.base.result = SceKernelErrors.ERROR_SAVEDATA_DELETE_BAD_PARAMS;
} else if (saveListSelection == null) {
log.warn("Savedata MODE_DELETE no save selected");
savedataParams.base.result = SceKernelErrors.ERROR_SAVEDATA_DELETE_BAD_PARAMS;
} else {
String dirName = savedataParams.getBasePath(saveListSelection);
if (savedataParams.deleteDir(dirName)) {
log.debug("Savedata MODE_DELETE deleting " + dirName);
savedataParams.base.result = 0;
} else {
savedataParams.base.result = SceKernelErrors.ERROR_SAVEDATA_DELETE_ACCESS_ERROR;
}
}
quitDialog(savedataParams.base.result);
} else {
updateDialog();
}
break;
}
case SceUtilitySavedataParam.MODE_SIZES: {
// "METAL SLUG XX" outputs the following on stdout after calling mode 8:
//
// ------ SIZES ------
// ---------- savedata result ----------
// result = 0x801103c7
//
// bind : un used(0x0).
//
// -- dir name --
// title id : ULUS10495
// user id : METALSLUGXX
//
// ms free size
// cluster size(byte) : 32768 byte
// free cluster num : 32768
// free size(KB) : 1048576 KB
// free size(string) : "1 GB"
//
// ms data size(titleId=ULUS10495, userId=METALSLUGXX)
// cluster num : 0
// size (KB) : 0 KB
// size (string) : "0 KB"
// size (32KB) : 0 KB
// size (32KB string) : "0 KB"
//
// utility data size
// cluster num : 13
// size (KB) : 416 KB
// size (string) : "416 KB"
// size (32KB) : 416 KB
// size (32KB string) : "416 KB"
// error: SCE_UTILITY_SAVEDATA_TYPE_SIZES return 801103c7
//
int retval = 0;
if (log.isDebugEnabled()) {
log.debug(String.format("MODE_SIZES: msFreeAddr=0x%08X-0x%08X, msDataAddr=0x%08X-0x%08X, utilityDataAddr=0x%08X-0x%08X", savedataParams.msFreeAddr, savedataParams.msFreeAddr + 20, savedataParams.msDataAddr, savedataParams.msDataAddr + 64, savedataParams.utilityDataAddr, savedataParams.utilityDataAddr + 28));
}
// Gets the amount of free space on the Memory Stick.
int msFreeAddr = savedataParams.msFreeAddr;
if (msFreeAddr != 0) {
String memoryStickFreeSpaceString = MemoryStick.getSizeKbString(MemoryStick.getFreeSizeKb());
mem.write32(msFreeAddr + 0, MemoryStick.getSectorSize());
mem.write32(msFreeAddr + 4, MemoryStick.getFreeSizeKb() / MemoryStick.getSectorSizeKb());
mem.write32(msFreeAddr + 8, MemoryStick.getFreeSizeKb());
Utilities.writeStringNZ(mem, msFreeAddr + 12, 8, memoryStickFreeSpaceString);
log.debug("Memory Stick Free Space = " + memoryStickFreeSpaceString);
}
// Gets the size of the data already saved on the Memory Stick.
int msDataAddr = savedataParams.msDataAddr;
if (msDataAddr != 0) {
String gameName = Utilities.readStringNZ(mem, msDataAddr, 13);
String saveName = Utilities.readStringNZ(mem, msDataAddr + 16, 20);
saveName = savedataParams.getAnySaveName(gameName, saveName);
if (savedataParams.isDirectoryPresent(gameName, saveName)) {
int savedataSizeKb = savedataParams.getSizeKb(gameName, saveName);
int savedataSize32Kb = MemoryStick.getSize32Kb(savedataSizeKb);
mem.write32(msDataAddr + 36, savedataSizeKb / MemoryStick.getSectorSizeKb()); // Number of sectors.
mem.write32(msDataAddr + 40, savedataSizeKb); // Size in Kb.
Utilities.writeStringNZ(mem, msDataAddr + 44, 8, MemoryStick.getSizeKbString(savedataSizeKb));
mem.write32(msDataAddr + 52, savedataSize32Kb);
Utilities.writeStringNZ(mem, msDataAddr + 56, 8, MemoryStick.getSizeKbString(savedataSize32Kb));
log.debug("Memory Stick Used Space = " + MemoryStick.getSizeKbString(savedataSizeKb));
} else {
log.debug(String.format("Savedata MODE_SIZES directory not found, gameName='%s', saveName='%s'", gameName, saveName));
retval = SceKernelErrors.ERROR_SAVEDATA_SIZES_NO_DATA;
}
}
// Gets the size of the data to be saved on the Memory Stick.
int utilityDataAddr = savedataParams.utilityDataAddr;
if (utilityDataAddr != 0) {
int memoryStickRequiredSpaceKb = savedataParams.getRequiredSizeKb();
String memoryStickRequiredSpaceString = MemoryStick.getSizeKbString(memoryStickRequiredSpaceKb);
int memoryStickRequiredSpace32Kb = MemoryStick.getSize32Kb(memoryStickRequiredSpaceKb);
String memoryStickRequiredSpace32KbString = MemoryStick.getSizeKbString(memoryStickRequiredSpace32Kb);
mem.write32(utilityDataAddr + 0, memoryStickRequiredSpaceKb / MemoryStick.getSectorSizeKb());
mem.write32(utilityDataAddr + 4, memoryStickRequiredSpaceKb);
Utilities.writeStringNZ(mem, utilityDataAddr + 8, 8, memoryStickRequiredSpaceString);
mem.write32(utilityDataAddr + 16, memoryStickRequiredSpace32Kb);
Utilities.writeStringNZ(mem, utilityDataAddr + 20, 8, memoryStickRequiredSpace32KbString);
log.debug("Memory Stick Required Space = " + memoryStickRequiredSpaceString);
}
savedataParams.base.result = retval;
break;
}
case SceUtilitySavedataParam.MODE_AUTODELETE: {
if (savedataParams.deleteDir(savedataParams.getBasePath())) {
savedataParams.base.result = 0;
} else {
log.warn("Savedata MODE_AUTODELETE directory not found!");
savedataParams.base.result = SceKernelErrors.ERROR_SAVEDATA_DELETE_NO_DATA;
}
// Tests show certain applications expect the PSP to change the
// dialog status automatically after delete.
status = PSP_UTILITY_DIALOG_STATUS_QUIT;
break;
}
case SceUtilitySavedataParam.MODE_SINGLEDELETE: {
if (savedataParams.deleteFile(savedataParams.fileName)) {
savedataParams.base.result = 0;
} else {
log.warn("Savedata MODE_SINGLEDELETE file not found!");
savedataParams.base.result = SceKernelErrors.ERROR_SAVEDATA_DELETE_NO_MEMSTICK;
}
// Tests show certain applications expect the PSP to change the
// dialog status automatically after delete.
status = PSP_UTILITY_DIALOG_STATUS_QUIT;
break;
}
case SceUtilitySavedataParam.MODE_LIST: {
int buffer4Addr = savedataParams.idListAddr;
if (Memory.isAddressGood(buffer4Addr)) {
int maxEntries = mem.read32(buffer4Addr + 0);
int entriesAddr = mem.read32(buffer4Addr + 8);
String saveName = savedataParams.saveName;
// PSP file name pattern:
// '?' matches one character
// '*' matches any character sequence
// To convert to regular expressions:
// replace '?' with '.'
// replace '*' with '.*'
String pattern = saveName.replace('?', '.');
pattern = pattern.replace("*", ".*");
pattern = savedataParams.gameName + pattern;
String[] entries = Modules.IoFileMgrForUserModule.listFiles(SceUtilitySavedataParam.savedataPath, pattern);
int numEntries = entries == null ? 0 : entries.length;
numEntries = Math.min(numEntries, maxEntries);
for (int i = 0; i < numEntries; i++) {
String filePath = SceUtilitySavedataParam.savedataPath + "/" + entries[i];
SceIoStat stat = Modules.IoFileMgrForUserModule.statFile(filePath);
int entryAddr = entriesAddr + i * 72;
if (stat != null) {
mem.write32(entryAddr + 0, stat.mode);
stat.ctime.write(mem, entryAddr + 4);
stat.atime.write(mem, entryAddr + 20);
stat.mtime.write(mem, entryAddr + 36);
}
String entryName = entries[i].substring(savedataParams.gameName.length());
// File names are always returned in upper case
entryName = entryName.toUpperCase();
Utilities.writeStringNZ(mem, entryAddr + 52, 20, entryName);
if (log.isDebugEnabled()) {
log.debug(String.format("MODE_LIST returning filePath=%s, stat=%s, entryName=%s at 0x%08X", filePath, stat, entryName, entryAddr));
}
}
mem.write32(buffer4Addr + 4, numEntries);
if (log.isDebugEnabled()) {
log.debug(String.format("MODE_LIST returning %d entries", numEntries));
}
}
savedataParams.base.result = checkMultipleCallStatus();
break;
}
case SceUtilitySavedataParam.MODE_FILES: {
int fileListAddr = savedataParams.fileListAddr;
if (Memory.isAddressGood(fileListAddr)) {
int saveFileSecureMaxNumEntries = mem.read32(fileListAddr);
int saveFileMaxNumEntries = mem.read32(fileListAddr + 4);
int systemMaxNumEntries = mem.read32(fileListAddr + 8);
if (log.isDebugEnabled()) {
log.debug(String.format("MaxFiles in FileList: secure=%d, normal=%d, system=%d", saveFileSecureMaxNumEntries, saveFileMaxNumEntries, systemMaxNumEntries));
}
int saveFileSecureEntriesAddr = mem.read32(fileListAddr + 24);
int saveFileEntriesAddr = mem.read32(fileListAddr + 28);
int systemEntriesAddr = mem.read32(fileListAddr + 32);
String path = savedataParams.getBasePath();
String[] entries = Modules.IoFileMgrForUserModule.listFiles(path, null);
int maxNumEntries = (entries == null) ? 0 : entries.length;
int saveFileSecureNumEntries = 0;
int saveFileNumEntries = 0;
int systemFileNumEntries = 0;
// List all files in the savedata (normal and/or encrypted).
for (int i = 0; i < maxNumEntries; i++) {
// File names are always returned in upper case
String entry = entries[i].toUpperCase();
String filePath = path + "/" + entry;
SceIoStat stat = Modules.IoFileMgrForUserModule.statFile(filePath);
// System files.
if (SceUtilitySavedataParam.isSystemFile(entry)) {
if (systemEntriesAddr != 0 && systemFileNumEntries < systemMaxNumEntries) {
int entryAddr = systemEntriesAddr + systemFileNumEntries * 80;
if (stat != null) {
mem.write32(entryAddr + 0, stat.mode);
mem.write64(entryAddr + 8, stat.size);
stat.ctime.write(mem, entryAddr + 16);
stat.atime.write(mem, entryAddr + 32);
stat.mtime.write(mem, entryAddr + 48);
}
Utilities.writeStringNZ(mem, entryAddr + 64, 16, entry);
systemFileNumEntries++;
}
} else if (savedataParams.isSecureFile(entry)) {
// Write to secure.
if (saveFileSecureEntriesAddr != 0 && saveFileSecureNumEntries < saveFileSecureMaxNumEntries) {
int entryAddr = saveFileSecureEntriesAddr + saveFileSecureNumEntries * 80;
if (stat != null) {
mem.write32(entryAddr + 0, stat.mode);
// Write the file size
long fileSize = stat.size;
if (CryptoEngine.getSavedataCryptoStatus()) {
// Write the size of the decrypted file (fileSize -= IV).
fileSize -= 0x10;
}
mem.write64(entryAddr + 8, fileSize);
stat.ctime.write(mem, entryAddr + 16);
stat.atime.write(mem, entryAddr + 32);
stat.mtime.write(mem, entryAddr + 48);
}
Utilities.writeStringNZ(mem, entryAddr + 64, 16, entry);
saveFileSecureNumEntries++;
}
} else {
// Write to normal.
if (saveFileEntriesAddr != 0 && saveFileNumEntries < saveFileMaxNumEntries) {
int entryAddr = saveFileEntriesAddr + saveFileNumEntries * 80;
if (stat != null) {
mem.write32(entryAddr + 0, stat.mode);
mem.write64(entryAddr + 8, stat.size);
stat.ctime.write(mem, entryAddr + 16);
stat.atime.write(mem, entryAddr + 32);
stat.mtime.write(mem, entryAddr + 48);
}
Utilities.writeStringNZ(mem, entryAddr + 64, 16, entry);
saveFileNumEntries++;
}
}
}
if (entries == null) {
savedataParams.base.result = SceKernelErrors.ERROR_SAVEDATA_RW_NO_DATA;
} else {
savedataParams.base.result = checkMultipleCallStatus();
}
if (savedataParams.base.result == 0) {
// These values are only written when no error is returned
mem.write32(fileListAddr + 12, saveFileSecureNumEntries);
mem.write32(fileListAddr + 16, saveFileNumEntries);
mem.write32(fileListAddr + 20, systemFileNumEntries);
}
if (log.isDebugEnabled()) {
log.debug(String.format("FileList: %s", Utilities.getMemoryDump(fileListAddr, 36)));
if (saveFileSecureEntriesAddr != 0 && saveFileSecureNumEntries > 0) {
log.debug(String.format("SecureEntries: %s", Utilities.getMemoryDump(saveFileSecureEntriesAddr, saveFileSecureNumEntries * 80)));
}
if (saveFileEntriesAddr != 0 && saveFileNumEntries > 0) {
log.debug(String.format("NormalEntries: %s", Utilities.getMemoryDump(saveFileEntriesAddr, saveFileNumEntries * 80)));
}
if (systemEntriesAddr != 0 && systemFileNumEntries > 0) {
log.debug(String.format("SystemEntries: %s", Utilities.getMemoryDump(systemEntriesAddr, systemFileNumEntries * 80)));
}
}
}
break;
}
case SceUtilitySavedataParam.MODE_MAKEDATA:
case SceUtilitySavedataParam.MODE_MAKEDATASECURE: {
// Split saving version.
// Write system data files (encrypted or not).
try {
savedataParams.save(mem, savedataParams.mode == SceUtilitySavedataParam.MODE_MAKEDATASECURE);
savedataParams.base.result = checkMultipleCallStatus();
} catch (IOException e) {
savedataParams.base.result = SceKernelErrors.ERROR_SAVEDATA_RW_ACCESS_ERROR;
} catch (Exception e) {
savedataParams.base.result = SceKernelErrors.ERROR_SAVEDATA_RW_ACCESS_ERROR;
log.error(e);
}
break;
}
case SceUtilitySavedataParam.MODE_READ:
case SceUtilitySavedataParam.MODE_READSECURE: {
// Sub-types of mode LOAD.
// Loads data and can be called multiple times for updating.
if (savedataParams.saveName == null || savedataParams.saveName.length() == 0) {
if (savedataParams.saveNameList != null && savedataParams.saveNameList.length > 0) {
savedataParams.saveName = savedataParams.saveNameList[0];
}
}
try {
savedataParams.load(mem);
if (log.isTraceEnabled()) {
log.trace(String.format("MODE_READ/MODE_READSECURE reading %s", Utilities.getMemoryDump(savedataParams.dataBuf, savedataParams.dataSize, 4, 16)));
}
savedataParams.base.result = checkMultipleCallStatus();
savedataParams.write(mem);
} catch (FileNotFoundException e) {
if (savedataParams.isGameDirectoryPresent()) {
// Directory exists but file does not exist
savedataParams.base.result = SceKernelErrors.ERROR_SAVEDATA_RW_FILE_NOT_FOUND;
} else {
// Directory does not exist
savedataParams.base.result = SceKernelErrors.ERROR_SAVEDATA_RW_NO_DATA;
}
} catch (IOException e) {
savedataParams.base.result = SceKernelErrors.ERROR_SAVEDATA_RW_NO_DATA;
} catch (Exception e) {
savedataParams.base.result = SceKernelErrors.ERROR_SAVEDATA_RW_ACCESS_ERROR;
log.error(e);
}
break;
}
case SceUtilitySavedataParam.MODE_WRITE:
case SceUtilitySavedataParam.MODE_WRITESECURE: {
// Sub-types of mode SAVE.
// Writes data and can be called multiple times for updating.
try {
savedataParams.save(mem, savedataParams.mode == SceUtilitySavedataParam.MODE_WRITESECURE);
savedataParams.base.result = checkMultipleCallStatus();
} catch (IOException e) {
if (!savedataParams.isGameDirectoryPresent()) {
savedataParams.base.result = SceKernelErrors.ERROR_SAVEDATA_RW_NO_DATA;
} else {
savedataParams.base.result = SceKernelErrors.ERROR_SAVEDATA_RW_ACCESS_ERROR;
}
} catch (Exception e) {
savedataParams.base.result = SceKernelErrors.ERROR_SAVEDATA_RW_ACCESS_ERROR;
log.error(e);
}
break;
}
case SceUtilitySavedataParam.MODE_DELETEDATA:
// Sub-type of mode DELETE.
// Deletes the contents of only one specified file.
if (savedataParams.deleteFile(savedataParams.fileName)) {
savedataParams.base.result = checkMultipleCallStatus();
} else {
log.warn("Savedata MODE_DELETEDATA no data found!");
savedataParams.base.result = SceKernelErrors.ERROR_SAVEDATA_RW_NO_DATA;
}
break;
case SceUtilitySavedataParam.MODE_GETSIZE:
int buffer6Addr = savedataParams.sizeAddr;
boolean isPresent = savedataParams.isPresent();
if (Memory.isAddressGood(buffer6Addr)) {
int saveFileSecureNumEntries = mem.read32(buffer6Addr + 0);
int saveFileNumEntries = mem.read32(buffer6Addr + 4);
int saveFileSecureEntriesAddr = mem.read32(buffer6Addr + 8);
int saveFileEntriesAddr = mem.read32(buffer6Addr + 12);
int totalSizeKb = 0;
for (int i = 0; i < saveFileSecureNumEntries; i++) {
int entryAddr = saveFileSecureEntriesAddr + i * 24;
long size = mem.read64(entryAddr);
String fileName = Utilities.readStringNZ(entryAddr + 8, 16);
int sizeKb = Utilities.getSizeKb(size);
if (log.isDebugEnabled()) {
log.debug(String.format(" Secure File '%s', size %d (%d KB)", fileName, size, sizeKb));
}
totalSizeKb += sizeKb;
}
for (int i = 0; i < saveFileNumEntries; i++) {
int entryAddr = saveFileEntriesAddr + i * 24;
long size = mem.read64(entryAddr);
String fileName = Utilities.readStringNZ(entryAddr + 8, 16);
int sizeKb = Utilities.getSizeKb(size);
if (log.isDebugEnabled()) {
log.debug(String.format(" File '%s', size %d (%d KB)", fileName, size, sizeKb));
}
totalSizeKb += sizeKb;
}
// Free MS size.
int freeSizeKb = MemoryStick.getFreeSizeKb();
String memoryStickFreeSpaceString = MemoryStick.getSizeKbString(freeSizeKb);
mem.write32(buffer6Addr + 16, MemoryStick.getSectorSize());
mem.write32(buffer6Addr + 20, freeSizeKb / MemoryStick.getSectorSizeKb());
mem.write32(buffer6Addr + 24, freeSizeKb);
Utilities.writeStringNZ(mem, buffer6Addr + 28, 8, memoryStickFreeSpaceString);
// If there's not enough size, we have to write how much size we need.
// With enough size, our needed size is always 0.
if (totalSizeKb > freeSizeKb) {
int neededSizeKb = totalSizeKb - freeSizeKb;
// Additional size needed to write savedata.
mem.write32(buffer6Addr + 36, neededSizeKb);
Utilities.writeStringNZ(mem, buffer6Addr + 40, 8, MemoryStick.getSizeKbString(neededSizeKb));
if (isPresent) {
// Additional size needed to overwrite savedata.
mem.write32(buffer6Addr + 48, neededSizeKb);
Utilities.writeStringNZ(mem, buffer6Addr + 52, 8, MemoryStick.getSizeKbString(neededSizeKb));
}
} else {
mem.write32(buffer6Addr + 36, 0);
if (isPresent) {
mem.write32(buffer6Addr + 48, 0);
}
}
}
// MODE_GETSIZE also checks if a MemoryStick is inserted and if there're no previous data.
if (MemoryStick.getStateMs() != MemoryStick.PSP_MEMORYSTICK_STATE_DRIVER_READY) {
savedataParams.base.result = SceKernelErrors.ERROR_SAVEDATA_RW_NO_MEMSTICK;
} else if (!isPresent) {
savedataParams.base.result = SceKernelErrors.ERROR_SAVEDATA_RW_NO_DATA;
} else {
savedataParams.base.result = checkMultipleCallStatus();
}
break;
case SceUtilitySavedataParam.MODE_ERASESECURE:
if (savedataParams.fileName != null) {
String save = savedataParams.getFileName(savedataParams.saveName, savedataParams.fileName);
if (Modules.IoFileMgrForUserModule.deleteFile(save)) {
savedataParams.base.result = checkMultipleCallStatus();
} else if (savedataParams.isGameDirectoryPresent()) {
savedataParams.base.result = SceKernelErrors.ERROR_SAVEDATA_RW_NO_DATA;
} else {
savedataParams.base.result = SceKernelErrors.ERROR_SAVEDATA_RW_FILE_NOT_FOUND;
}
} else {
log.warn("Savedata MODE_ERASESECURE no fileName specified!");
savedataParams.base.result = SceKernelErrors.ERROR_SAVEDATA_RW_NO_DATA;
}
break;
default:
log.warn(String.format("Savedata - Unsupported mode %d", savedataParams.mode));
quitDialog(-1);
break;
}
savedataParams.base.writeResult(mem);
if (log.isDebugEnabled()) {
log.debug(String.format("hleUtilitySavedataDisplay result: 0x%08X", savedataParams.base.result));
}
return false;
}
@Override
protected boolean hasDialog() {
switch (savedataParams.mode) {
// Only these modes have a dialog with the user
case SceUtilitySavedataParam.MODE_LOAD:
case SceUtilitySavedataParam.MODE_SAVE:
case SceUtilitySavedataParam.MODE_LISTLOAD:
case SceUtilitySavedataParam.MODE_LISTSAVE:
case SceUtilitySavedataParam.MODE_LISTDELETE:
case SceUtilitySavedataParam.MODE_DELETE:
case SceUtilitySavedataParam.MODE_SINGLEDELETE:
return true;
}
// The other modes are silent
return false;
}
}
protected static class MsgDialogUtilityDialogState extends UtilityDialogState {
protected SceUtilityMsgDialogParams msgDialogParams;
public MsgDialogUtilityDialogState(String name) {
super(name);
}
@Override
protected boolean executeUpdateVisible() {
Memory mem = Processor.memory;
if (!isDialogOpen()) {
GuMsgDialog gu = new GuMsgDialog(msgDialogParams, this);
openDialog(gu);
} else if (!isDialogActive()) {
// buttonPressed is only set for mode TEXT, not for mode ERROR
if (msgDialogParams.mode == SceUtilityMsgDialogParams.PSP_UTILITY_MSGDIALOG_MODE_TEXT) {
msgDialogParams.buttonPressed = getButtonPressed();
} else if (msgDialogParams.mode == SceUtilityMsgDialogParams.PSP_UTILITY_MSGDIALOG_MODE_ERROR) {
msgDialogParams.buttonPressed = SceUtilityMsgDialogParams.PSP_UTILITY_BUTTON_PRESSED_ESC;
} else {
msgDialogParams.buttonPressed = SceUtilityMsgDialogParams.PSP_UTILITY_BUTTON_PRESSED_INVALID;
}
if (log.isDebugEnabled()) {
log.debug(String.format("sceUtilityMsgDialog returning buttonPressed=%d", msgDialogParams.buttonPressed));
}
quitDialog(0);
msgDialogParams.write(mem);
} else {
updateDialog();
}
return false;
}
@Override
protected pspUtilityBaseDialog createParams() {
msgDialogParams = new SceUtilityMsgDialogParams();
return msgDialogParams;
}
}
protected static class OskUtilityDialogState extends UtilityDialogState {
protected SceUtilityOskParams oskParams;
protected OskDialog oskDialog;
public OskUtilityDialogState(String name) {
super(name);
}
@Override
protected boolean executeUpdateVisible() {
Memory mem = Processor.memory;
if (!isDialogOpen()) {
oskDialog = new OskDialog(oskParams, this);
openDialog(oskDialog);
} else if (!isDialogActive()) {
if (oskDialog.buttonPressed == SceUtilityMsgDialogParams.PSP_UTILITY_BUTTON_PRESSED_OK) {
oskParams.oskData.result = SceUtilityOskData.PSP_UTILITY_OSK_DATA_CHANGED;
oskParams.oskData.outText = oskDialog.textField.getText();
log.info("hleUtilityOskDisplay returning '" + oskParams.oskData.outText + "'");
} else {
oskParams.oskData.result = SceUtilityOskData.PSP_UTILITY_OSK_DATA_CANCELED;
oskParams.oskData.outText = oskDialog.textField.getText();
log.info("hleUtilityOskDisplay cancelled");
}
quitDialog(0);
oskParams.write(mem);
} else {
oskDialog.checkController();
updateDialog();
}
return false;
}
@Override
protected pspUtilityBaseDialog createParams() {
oskParams = new SceUtilityOskParams();
return oskParams;
}
}
protected static class GameSharingUtilityDialogState extends UtilityDialogState {
protected SceUtilityGameSharingParams gameSharingParams;
public GameSharingUtilityDialogState(String name) {
super(name);
}
@Override
protected boolean executeUpdateVisible() {
// TODO to be implemented
return false;
}
@Override
protected pspUtilityBaseDialog createParams() {
gameSharingParams = new SceUtilityGameSharingParams();
return gameSharingParams;
}
@Override
protected boolean hasDialog() {
return false;
}
}
protected static class NetconfUtilityDialogState extends UtilityDialogState {
protected SceUtilityNetconfParams netconfParams;
public NetconfUtilityDialogState(String name) {
super(name);
}
@Override
protected boolean executeUpdateVisible() {
boolean keepVisible = false;
if (netconfParams.netAction == SceUtilityNetconfParams.PSP_UTILITY_NETCONF_CONNECT_APNET
|| netconfParams.netAction == SceUtilityNetconfParams.PSP_UTILITY_NETCONF_CONNECT_APNET_LASTUSED) {
int state = Modules.sceNetApctlModule.hleNetApctlGetState();
// The Netconf dialog stays visible until the network reaches
// the state PSP_NET_APCTL_STATE_GOT_IP.
if (state == sceNetApctl.PSP_NET_APCTL_STATE_GOT_IP) {
quitDialog();
keepVisible = false;
} else {
keepVisible = true;
if (state == sceNetApctl.PSP_NET_APCTL_STATE_DISCONNECTED) {
// When connecting with infrastructure, simulate a connection
// using the first network configuration entry.
Modules.sceNetApctlModule.hleNetApctlConnect(1);
}
}
} else if (netconfParams.netAction == SceUtilityNetconfParams.PSP_UTILITY_NETCONF_CONNECT_ADHOC
|| netconfParams.netAction == SceUtilityNetconfParams.PSP_UTILITY_NETCONF_CREATE_ADHOC
|| netconfParams.netAction == SceUtilityNetconfParams.PSP_UTILITY_NETCONF_JOIN_ADHOC) {
int state = Modules.sceNetAdhocctlModule.hleNetAdhocctlGetState();
// The Netconf dialog stays visible until the network reaches
// the state PSP_ADHOCCTL_STATE_CONNECTED.
if (state == sceNetAdhocctl.PSP_ADHOCCTL_STATE_CONNECTED) {
quitDialog();
keepVisible = false;
} else {
updateDialog();
keepVisible = true;
if (state == sceNetAdhocctl.PSP_ADHOCCTL_STATE_DISCONNECTED && netconfParams.netconfData != null) {
// Connect to the given group name
Modules.sceNetAdhocctlModule.hleNetAdhocctlConnect(netconfParams.netconfData.groupName);
}
}
}
return keepVisible;
}
@Override
protected pspUtilityBaseDialog createParams() {
netconfParams = new SceUtilityNetconfParams();
return netconfParams;
}
}
protected static class ScreenshotUtilityDialogState extends UtilityDialogState {
protected SceUtilityScreenshotParams screenshotParams;
public ScreenshotUtilityDialogState(String name) {
super(name);
}
@Override
protected boolean executeUpdateVisible() {
if (log.isDebugEnabled()) {
log.debug(String.format("SceUtilityScreenshotParams %s", Utilities.getMemoryDump(paramsAddr.getAddress(), params.sizeof())));
}
if (status == PSP_UTILITY_DIALOG_STATUS_VISIBLE && (screenshotParams.isContModeAuto() || screenshotParams.isContModeFinish())) {
status = PSP_UTILITY_DIALOG_STATUS_SCREENSHOT_UNKNOWN;
}
if (status == PSP_UTILITY_DIALOG_STATUS_VISIBLE && !screenshotParams.isContModeAuto() && !screenshotParams.isContModeFinish() && Memory.isAddressGood(screenshotParams.imgFrameBufAddr)) {
Buffer buffer = Memory.getInstance().getBuffer(screenshotParams.imgFrameBufAddr, screenshotParams.imgFrameBufWidth * screenshotParams.displayHeigth * IRenderingEngine.sizeOfTextureType[screenshotParams.imgPixelFormat]);
String directoyName = String.format("ms0/PSP/SCREENSHOT/%s/", screenshotParams.screenshotID);
new File(directoyName).mkdirs();
String fileName = null;
String fileSuffix = screenshotParams.imgFormat == PSP_UTILITY_SCREENSHOT_FORMAT_JPEG ? "jpeg" : "png";
if (screenshotParams.nameRule == PSP_UTILITY_SCREENSHOT_NAMERULE_AUTONUM) {
for (int fileIndex = 1; fileIndex <= 9999; fileIndex++) {
fileName = String.format("%s%s_%04d.%s", directoyName, screenshotParams.fileName, fileIndex, fileSuffix);
if (!new File(fileName).exists()) {
break;
}
}
} else {
fileName = String.format("%s%s.%s", directoyName, screenshotParams.fileName, fileSuffix);
}
CaptureImage captureImage = new CaptureImage(screenshotParams.imgFrameBufAddr, 0, buffer, screenshotParams.displayWidth, screenshotParams.displayHeigth, screenshotParams.imgFrameBufWidth, screenshotParams.imgPixelFormat, false, 0, false, true, null);
if (screenshotParams.imgFormat == PSP_UTILITY_SCREENSHOT_FORMAT_PNG) {
captureImage.setFileFormat("png");
} else if (screenshotParams.imgFormat == PSP_UTILITY_SCREENSHOT_FORMAT_JPEG) {
captureImage.setFileFormat("jpg");
}
captureImage.setFileName(fileName);
try {
captureImage.write();
} catch (IOException e) {
log.error("sceUtilityScreenshot", e);
}
}
// TODO to be implemented
return false;
}
protected int executeContStart(TPointer paramsAddr) {
// Continuous mode which takes several screenshots
// on regular intervals set by an internal counter.
// To execute the cont mode, the screenshot utility must
// be initialized with sceUtilityScreenshotInitStart and the startupType
// parameter has to be PSP_UTILITY_SCREENSHOT_TYPE_CONT_AUTO, otherwise, an
// error is returned.
if (status != PSP_UTILITY_DIALOG_STATUS_SCREENSHOT_UNKNOWN) {
return SceKernelErrors.ERROR_UTILITY_INVALID_STATUS;
}
this.paramsAddr = paramsAddr;
this.params = createParams();
params.read(paramsAddr);
if (log.isInfoEnabled()) {
log.info(String.format("%sContStart %s", name, params.toString()));
}
if (!screenshotParams.isContModeAuto()) {
return SceKernelErrors.ERROR_SCREENSHOT_CONT_MODE_NOT_INIT;
}
// PSP is moving to status QUIT
status = PSP_UTILITY_DIALOG_STATUS_QUIT;
return 0;
}
@Override
protected pspUtilityBaseDialog createParams() {
screenshotParams = new SceUtilityScreenshotParams();
return screenshotParams;
}
@Override
protected boolean hasDialog() {
return false;
}
}
protected static class GamedataInstallUtilityDialogState extends UtilityDialogState {
protected SceUtilityGamedataInstallParams gamedataInstallParams;
public GamedataInstallUtilityDialogState(String name) {
super(name);
}
@Override
protected pspUtilityBaseDialog createParams() {
gamedataInstallParams = new SceUtilityGamedataInstallParams();
return gamedataInstallParams;
}
@Override
protected boolean executeUpdateVisible() {
IoFileMgrForUser fileMgr = Modules.IoFileMgrForUserModule;
StringBuilder sourceLocalFileName = new StringBuilder();
IVirtualFileSystem ivfs = fileMgr.getVirtualFileSystem("disc0:/PSP_GAME/INSDIR", sourceLocalFileName);
if (ivfs != null) {
String[] fileNames = ivfs.ioDopen(sourceLocalFileName.toString());
if (fileNames != null) {
ivfs.ioDclose(sourceLocalFileName.toString());
StringBuilder destinationLocalFileName = new StringBuilder();
IVirtualFileSystem ovfs = fileMgr.getVirtualFileSystem(String.format("%s%s%s", SceUtilitySavedataParam.savedataPath, gamedataInstallParams.gameName, gamedataInstallParams.dataName), destinationLocalFileName);
if (ovfs != null) {
int numberFiles = 0;
for (int i = 0; i < fileNames.length; i++) {
String fileName = fileNames[i];
// Skip iso special files
if (!fileName.equals(".") && !fileName.equals("\01")) {
String sourceFileName = String.format("%s/%s", sourceLocalFileName.toString(), fileName);
IVirtualFile ivf = ivfs.ioOpen(sourceFileName, IoFileMgrForUser.PSP_O_RDONLY, 0);
if (ivf != null) {
String destinationFileName = String.format("%s/%s", destinationLocalFileName.toString(), fileName);
IVirtualFile ovf = ovfs.ioOpen(destinationFileName, IoFileMgrForUser.PSP_O_WRONLY | IoFileMgrForUser.PSP_O_CREAT, 0777);
if (ovf != null) {
if (log.isDebugEnabled()) {
log.debug(String.format("GamedataInstall: copying file disc0:/%s to ms0:/%s", sourceFileName, destinationFileName));
}
byte[] buffer = new byte[512 * 1024];
long restLength = ivf.length();
while (restLength > 0) {
int length = buffer.length;
if (length > restLength) {
length = (int) restLength;
}
length = ivf.ioRead(buffer, 0, length);
ovf.ioWrite(buffer, 0, length);
restLength -= length;
}
ovf.ioClose();
numberFiles++;
}
ivf.ioClose();
}
}
}
// TODO Not sure about the values to return here
gamedataInstallParams.unkResult1 = numberFiles;
gamedataInstallParams.unkResult2 = numberFiles;
gamedataInstallParams.write(paramsAddr);
}
}
}
return false;
}
@Override
protected boolean hasDialog() {
return false;
}
@Override
protected int getShutdownDelay() {
return 50000;
}
}
protected static class NpSigninUtilityDialogState extends UtilityDialogState {
protected SceUtilityNpSigninParams npSigninParams;
public NpSigninUtilityDialogState(String name) {
super(name);
}
@Override
protected pspUtilityBaseDialog createParams() {
npSigninParams = new SceUtilityNpSigninParams();
return npSigninParams;
}
@Override
protected boolean executeUpdateVisible() {
Memory mem = Processor.memory;
npSigninParams.signinStatus = SceUtilityNpSigninParams.NP_SIGNING_STATUS_OK;
npSigninParams.write(mem);
int sceNp_E24DA399 = NIDMapper.getInstance().getAddressByName("sceNp_E24DA399");
if (sceNp_E24DA399 != 0) {
int address = mem.read16(sceNp_E24DA399 + 0) << 16;
address += (short) mem.read16(sceNp_E24DA399 + 8);
if (Memory.isAddressGood(address)) {
if (log.isDebugEnabled()) {
log.debug(String.format("sceNp_E24DA399 Address 0x%08X", address));
}
mem.write32(address, 1);
}
}
int sceNp_C48F2847 = NIDMapper.getInstance().getAddressByName("sceNp_C48F2847");
if (sceNp_C48F2847 != 0) {
int address = mem.read16(sceNp_C48F2847 + 0x74) << 16;
address += (short) mem.read16(sceNp_C48F2847 + 0x78);
if (Memory.isAddressGood(address)) {
if (log.isDebugEnabled()) {
log.debug(String.format("sceNp_C48F2847 Address 0x%08X", address));
}
Utilities.writeStringZ(mem, address, Modules.sceNpModule.getOnlineId());
}
}
int sceNpService_7EF4312E = NIDMapper.getInstance().getAddressByName("sceNpService_7EF4312E");
if (sceNpService_7EF4312E != 0) {
int subAddress = (mem.read32(sceNpService_7EF4312E + 0x78) & 0x3FFFFFF) << 2;
int address = mem.read16(subAddress + 0x14) << 16;
address += (short) mem.read16(subAddress + 0x38);
if (Memory.isAddressGood(address)) {
if (log.isDebugEnabled()) {
log.debug(String.format("sceNpService_7EF4312E Address 0x%08X", address));
}
SysMemInfo memInfo = Modules.SysMemUserForUserModule.malloc(SysMemUserForUser.KERNEL_PARTITION_ID, "sceNpService_7EF4312E", SysMemUserForUser.PSP_SMEM_Low, 100, 0);
mem.write32(address, memInfo.addr);
mem.memset(memInfo.addr, (byte) 0, 100);
Utilities.writeStringZ(mem, memInfo.addr + 12, Modules.sceNpModule.getOnlineId());
Modules.SysMemForKernelModule.SysMemUserForUser_945E45DA(new TPointer(mem, memInfo.addr + 64));
}
}
int sceNp_02CA8CAA = NIDMapper.getInstance().getAddressByName("sceNp_02CA8CAA");
if (sceNp_02CA8CAA != 0) {
int address = mem.read16(sceNp_02CA8CAA + 0x8C) << 16;
address += (short) mem.read16(sceNp_02CA8CAA + 0x90);
if (Memory.isAddressGood(address)) {
if (log.isDebugEnabled()) {
log.debug(String.format("sceNp_02CA8CAA Address 0x%08X", address));
}
mem.write64(address, Modules.sceRtcModule.hleGetCurrentTick());
}
}
return false;
}
@Override
protected boolean hasDialog() {
return false;
}
}
protected static class HtmlViewerUtilityDialogState extends UtilityDialogState {
protected SceUtilityHtmlViewerParams htmlViewerParams;
public HtmlViewerUtilityDialogState(String name) {
super(name);
}
@Override
protected boolean executeUpdateVisible() {
// TODO to be implemented
return false;
}
@Override
protected pspUtilityBaseDialog createParams() {
htmlViewerParams = new SceUtilityHtmlViewerParams();
return htmlViewerParams;
}
@Override
protected boolean hasDialog() {
return false;
}
}
protected static abstract class UtilityDialog extends JComponent {
private static final long serialVersionUID = -993546461292372048L;
protected JDialog dialog;
protected int buttonPressed;
protected JPanel messagePane;
protected JPanel buttonPane;
protected ActionListener closeActionListener;
protected static final String actionCommandOK = "OK";
protected static final String actionCommandYES = "YES";
protected static final String actionCommandNO = "NO";
protected static final String actionCommandESC = "ESC";
protected UtilityDialogState utilityDialogState;
protected String confirmButtonActionCommand = actionCommandOK;
protected String cancelButtonActionCommand = actionCommandESC;
protected long pressedTimestamp;
protected static final int repeatDelay = 200000;
protected boolean downPressedButton;
protected boolean downPressedAnalog;
protected boolean upPressedButton;
protected boolean upPressedAnalog;
protected void createDialog(final UtilityDialogState utilityDialogState, String message) {
this.utilityDialogState = utilityDialogState;
String title = String.format("Message from %s", State.title);
dialog = new JDialog((Frame) null, title, false);
dialog.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
messagePane = new JPanel();
messagePane.setBorder(new EmptyBorder(5, 10, 5, 10));
messagePane.setLayout(new BoxLayout(messagePane, BoxLayout.Y_AXIS));
if (message != null) {
message = formatMessageForDialog(message);
// Split the message according to the new lines
while (message.length() > 0) {
int newLinePosition = message.indexOf("\n");
JLabel label = new JLabel();
label.setHorizontalAlignment(JLabel.CENTER);
label.setAlignmentX(CENTER_ALIGNMENT);
if (newLinePosition < 0) {
label.setText(message);
message = "";
} else {
String messagePart = message.substring(0, newLinePosition);
label.setText(messagePart);
message = message.substring(newLinePosition + 1);
}
messagePane.add(label);
}
}
if (JDialog.isDefaultLookAndFeelDecorated()) {
if (UIManager.getLookAndFeel().getSupportsWindowDecorations()) {
dialog.setUndecorated(true);
getRootPane().setWindowDecorationStyle(JRootPane.INFORMATION_DIALOG);
}
}
buttonPane = new JPanel();
buttonPane.setBorder(new EmptyBorder(5, 10, 5, 10));
buttonPane.setLayout(new BoxLayout(buttonPane, BoxLayout.X_AXIS));
closeActionListener = new ActionListener() {
@Override
public void actionPerformed(ActionEvent event) {
processActionCommand(event.getActionCommand());
dispose();
}
};
}
protected void dispose() {
dialog.dispose();
Emulator.getMainGUI().endWindowDialog();
}
protected void processActionCommand(String actionCommand) {
if (actionCommandYES.equals(actionCommand)) {
buttonPressed = SceUtilityMsgDialogParams.PSP_UTILITY_BUTTON_PRESSED_YES;
} else if (actionCommandNO.equals(actionCommand)) {
buttonPressed = SceUtilityMsgDialogParams.PSP_UTILITY_BUTTON_PRESSED_NO;
} else if (actionCommandOK.equals(actionCommand)) {
buttonPressed = SceUtilityMsgDialogParams.PSP_UTILITY_BUTTON_PRESSED_OK;
} else if (actionCommandESC.equals(actionCommand)) {
buttonPressed = SceUtilityMsgDialogParams.PSP_UTILITY_BUTTON_PRESSED_ESC;
} else {
buttonPressed = SceUtilityMsgDialogParams.PSP_UTILITY_BUTTON_PRESSED_INVALID;
}
}
protected void endDialog() {
Container contentPane = dialog.getContentPane();
contentPane.setLayout(new BoxLayout(contentPane, BoxLayout.Y_AXIS));
contentPane.add(messagePane);
contentPane.add(buttonPane);
dialog.pack();
Emulator.getMainGUI().startWindowDialog(dialog);
}
protected void setDefaultButton(JButton button) {
dialog.getRootPane().setDefaultButton(button);
}
@Override
public void setVisible(boolean flag) {
dialog.setVisible(flag);
}
@Override
public boolean isVisible() {
return dialog.isVisible();
}
@Override
public Point getLocation() {
return dialog.getLocation();
}
@Override
public Dimension getSize() {
return dialog.getSize();
}
protected boolean isButtonPressed(int button) {
Controller controller = State.controller;
if ((controller.getButtons() & button) == button) {
return true;
}
return false;
}
protected boolean isConfirmButtonPressed() {
return isButtonPressed(getSystemParamButtonPreference() == PSP_SYSTEMPARAM_BUTTON_CIRCLE ? sceCtrl.PSP_CTRL_CIRCLE : sceCtrl.PSP_CTRL_CROSS);
}
protected boolean isCancelButtonPressed() {
return isButtonPressed(getSystemParamButtonPreference() == PSP_SYSTEMPARAM_BUTTON_CIRCLE ? sceCtrl.PSP_CTRL_CROSS : sceCtrl.PSP_CTRL_CIRCLE);
}
private int getControllerLy() {
return State.controller.getLy() & 0xFF;
}
private int getControllerAnalogCenter() {
return Controller.analogCenter & 0xFF;
}
private void checkRepeat() {
if (pressedTimestamp != 0 && SystemTimeManager.getSystemTime() - pressedTimestamp > repeatDelay) {
upPressedAnalog = false;
upPressedButton = false;
downPressedAnalog = false;
downPressedButton = false;
pressedTimestamp = 0;
}
}
protected boolean isUpPressed() {
checkRepeat();
if (upPressedButton || upPressedAnalog) {
if (!isButtonPressed(sceCtrl.PSP_CTRL_UP)) {
upPressedButton = false;
}
if (getControllerLy() >= getControllerAnalogCenter()) {
upPressedAnalog = false;
}
return false;
}
if (isButtonPressed(sceCtrl.PSP_CTRL_UP)) {
upPressedButton = true;
pressedTimestamp = SystemTimeManager.getSystemTime();
return true;
}
if (getControllerLy() < getControllerAnalogCenter()) {
upPressedAnalog = true;
pressedTimestamp = SystemTimeManager.getSystemTime();
return true;
}
return false;
}
protected boolean isDownPressed() {
checkRepeat();
if (downPressedButton || downPressedAnalog) {
if (!isButtonPressed(sceCtrl.PSP_CTRL_DOWN)) {
downPressedButton = false;
}
if (getControllerLy() <= getControllerAnalogCenter()) {
downPressedAnalog = false;
}
return false;
}
if (isButtonPressed(sceCtrl.PSP_CTRL_DOWN)) {
downPressedButton = true;
pressedTimestamp = SystemTimeManager.getSystemTime();
return true;
}
if (getControllerLy() > getControllerAnalogCenter()) {
downPressedAnalog = true;
pressedTimestamp = SystemTimeManager.getSystemTime();
return true;
}
return false;
}
public void checkController() {
if (isConfirmButtonPressed()) {
processActionCommand(confirmButtonActionCommand);
dispose();
} else if (isCancelButtonPressed()) {
processActionCommand(cancelButtonActionCommand);
dispose();
}
}
}
protected static abstract class GuUtilityDialog {
protected long pressedTimestamp;
protected static final int repeatDelay = 100000;
protected boolean downPressedButton;
protected boolean downPressedAnalog;
protected boolean upPressedButton;
protected boolean upPressedAnalog;
protected boolean leftPressedButton;
protected boolean leftPressedAnalog;
protected boolean rightPressedButton;
protected boolean rightPressedAnalog;
protected sceGu gu;
protected UtilityDialogState utilityDialogState;
private int x;
private int y;
private int textX;
private int textY;
private int textWidth;
private int textHeight;
private int textLineHeight;
private int textAddr;
private SceFontInfo defaultFontInfo;
protected static final float defaultFontScale = 0.75f;
protected static final int baseAscender = 15;
protected static final int defaultTextWidth = 512;
protected static final int defaultTextHeight = 32;
protected static final int textColor = 0xFFFFFF;
protected static final int shadowColor = 0x000000;
protected boolean softShadows;
protected long startDialogMillis;
protected int drawSpeed;
private boolean buttonsSwapped;
private boolean hasNoButtons;
final protected Locale utilityLocale;
final private String strEnter;
final private String strBack;
final private String strYes;
final private String strNo;
protected GuUtilityDialog(pspUtilityDialogCommon utilityDialogCommon) {
utilityLocale = getUtilityLocale(utilityDialogCommon.language);
buttonsSwapped = (utilityDialogCommon.buttonSwap == pspUtilityDialogCommon.BUTTON_ACCEPT_CIRCLE);
hasNoButtons = false;
strEnter = ResourceBundle.getBundle("jpcsp/languages/jpcsp", utilityLocale).getString("sceUtilitySavedata.strEnter.text");
strBack = ResourceBundle.getBundle("jpcsp/languages/jpcsp", utilityLocale).getString("sceUtilitySavedata.strBack.text");
strYes = ResourceBundle.getBundle("jpcsp/languages/jpcsp", utilityLocale).getString("sceUtilitySavedata.strYes.text");
strNo = ResourceBundle.getBundle("jpcsp/languages/jpcsp", utilityLocale).getString("sceUtilitySavedata.strNo.text");
}
protected void createDialog(final UtilityDialogState utilityDialogState) {
this.utilityDialogState = utilityDialogState;
if (log.isDebugEnabled()) {
int partitionId = SysMemUserForUser.USER_PARTITION_ID;
log.debug(String.format("Free memory total=0x%X, max=0x%X", Modules.SysMemUserForUserModule.totalFreeMemSize(partitionId), Modules.SysMemUserForUserModule.maxFreeMemSize(partitionId)));
}
startDialogMillis = Emulator.getClock().milliTime();
// Allocate 1 MB
gu = new sceGu(1 * 1024 * 1024);
}
protected void dispose() {
if (gu != null) {
gu.free();
gu = null;
}
}
public boolean isVisible() {
return gu != null;
}
protected void update(int drawSpeed) {
this.drawSpeed = drawSpeed;
// Do not overwrite a sceGu list still in drawing state
if (gu != null && !gu.isListDrawing()) {
gu.sceGuStart();
// Disable all common flags
gu.sceGuDisable(IRenderingEngine.GU_DEPTH_TEST);
gu.sceGuDisable(IRenderingEngine.GU_ALPHA_TEST);
gu.sceGuDisable(IRenderingEngine.GU_FOG);
gu.sceGuDisable(IRenderingEngine.GU_LIGHTING);
gu.sceGuDisable(IRenderingEngine.GU_COLOR_LOGIC_OP);
gu.sceGuDisable(IRenderingEngine.GU_STENCIL_TEST);
gu.sceGuDisable(IRenderingEngine.GU_CULL_FACE);
gu.sceGuDisable(IRenderingEngine.GU_SCISSOR_TEST);
// Enable standard alpha blending
gu.sceGuBlendFunc(ALPHA_SOURCE_BLEND_OPERATION_ADD, ALPHA_SOURCE_ALPHA, ALPHA_ONE_MINUS_SOURCE_ALPHA, 0, 0);
gu.sceGuEnable(IRenderingEngine.GU_BLEND);
updateDialog();
gu.sceGuFinish();
}
checkController();
}
protected String truncateText(String text, int width, float scale) {
String truncatedText = text;
String truncation = "";
while (true) {
int textLength = getTextLength(getDefaultFontInfo(), truncatedText + truncation, scale);
if (textLength <= width) {
break;
}
truncatedText = truncatedText.substring(0, truncatedText.length() - 1);
truncation = "...";
}
return truncatedText + truncation;
}
private String wrapText(String text, int width, float scale) {
SceFontInfo fontInfo = getDefaultFontInfo();
int glyphType = SceFontInfo.FONT_PGF_GLYPH_TYPE_CHAR;
StringBuilder wrappedText = new StringBuilder();
int x = 0;
int lastSpaceStart = -1;
int lastSpaceEnd = -1;
boolean isSpace = false;
int scaledWidth = (int) (width / scale);
for (int i = 0; i < text.length(); i++) {
char c = text.charAt(i);
pspCharInfo charInfo = fontInfo.getCharInfo(c, glyphType);
if (c == ' ') {
if (!isSpace) {
lastSpaceStart = i;
isSpace = true;
}
lastSpaceEnd = i + 1;
} else if (isSpace) {
lastSpaceEnd = i;
isSpace = false;
}
int nextX = x + charInfo.sfp26AdvanceH >> 6;
if (nextX > scaledWidth) {
x = 0;
if (lastSpaceStart >= 0) {
wrappedText.replace(lastSpaceStart, lastSpaceEnd, "\n");
} else {
wrappedText.append('\n');
}
if (!isSpace) {
wrappedText.append(c);
}
} else {
x = nextX;
wrappedText.append(c);
}
}
return wrappedText.toString();
}
private void drawText(SceFontInfo fontInfo, int baseAscender, char c, int glyphType) {
pspCharInfo charInfo = fontInfo.getCharInfo(c, glyphType);
if (log.isTraceEnabled()) {
log.trace(String.format("drawText '%c'(%d), glyphType=0x%X, baseAscender=%d, position (%d,%d), %s", c, (int) c, glyphType, baseAscender, x, y, charInfo));
}
if (charInfo == null) {
return;
}
if (c == '\n') {
x = textX;
y += textLineHeight;
return;
}
fontInfo.printFont(textAddr, textWidth / 2, textWidth, textHeight, x - textX + charInfo.bitmapLeft, y - textY + baseAscender - charInfo.bitmapTop, 0, 0, 0, 0, textWidth, textHeight, PSP_FONT_PIXELFORMAT_4, c, ' ', glyphType, true);
if (glyphType != SceFontInfo.FONT_PGF_GLYPH_TYPE_CHAR) {
// Take the advanceH from the character, not from the shadow
charInfo = fontInfo.getCharInfo(c, SceFontInfo.FONT_PGF_GLYPH_TYPE_CHAR);
}
x += charInfo.sfp26AdvanceH >> 6;
}
protected int getTextLines(String s) {
int lines = 1;
int index = 0;
while (index < s.length()) {
int newLine = s.indexOf("\n", index);
if (newLine < 0) {
break;
}
lines++;
index = newLine + 1;
}
return lines;
}
protected int centerText(SceFontInfo fontInfo, String s, int x0, int x1, float scale) {
int textLength = getTextLength(fontInfo, s, scale);
int width = x1 - x0 + 1;
if (textLength >= width) {
return x0;
}
return x0 + (width - textLength) / 2;
}
protected int getTextLength(SceFontInfo fontInfo, String s, float scale) {
int textLength = getTextLength(fontInfo, s);
textLength = (int) (scale * textLength);
return textLength;
}
protected int getTextLength(SceFontInfo fontInfo, String s) {
int length = 0;
for (int i = 0; i < s.length(); i++) {
length += getTextLength(fontInfo, s.charAt(i));
}
return length;
}
protected int getTextLength(SceFontInfo fontInfo, char c) {
pspCharInfo charInfo = fontInfo.getCharInfo(c, SceFontInfo.FONT_PGF_GLYPH_TYPE_CHAR);
if (charInfo == null) {
return 0;
}
return charInfo.sfp26AdvanceH >> 6;
}
protected void drawTextWithShadow(int textX, int textY, float scale, String s) {
drawTextWithShadow(textX, textY, textColor, scale, s);
}
protected void drawTextWithShadow(int textX, int textY, int textColor, float scale, String s) {
s = wrapText(s, Screen.width - textX, scale);
int txtHeight = defaultTextHeight;
if (s.contains("\n")) {
txtHeight = Screen.height - textY;
}
drawTextWithShadow(textX, textY, defaultTextWidth, txtHeight, 20, getDefaultFontInfo(), baseAscender, textColor, shadowColor, scale, s);
}
protected void drawTextWithShadow(int textX, int textY, int textWidth, int textHeight, int textLineHeight, SceFontInfo fontInfo, int baseAscender, int textColor, int shadowColor, float scale, String s) {
drawText(textX, textY, textWidth, textHeight, textLineHeight, fontInfo, baseAscender, scale, shadowColor, s, SceFontInfo.FONT_PGF_GLYPH_TYPE_SHADOW);
drawText(textX, textY, textWidth, textHeight, textLineHeight, fontInfo, baseAscender, scale, textColor, s, SceFontInfo.FONT_PGF_GLYPH_TYPE_CHAR);
}
protected void setSoftShadows(boolean softShadows) {
this.softShadows = softShadows;
}
protected void drawText(int textX, int textY, int textWidth, int textHeight, int textLineHeight, SceFontInfo fontInfo, int baseAscender, float scale, int color, String s, int glyphType) {
this.textX = textX;
this.textY = textY;
this.textWidth = textWidth;
this.textHeight = textHeight;
this.textLineHeight = textLineHeight;
x = textX;
y = textY;
int textSize = textWidth * textHeight / 2;
textAddr = gu.sceGuGetMemory(textSize);
if (textAddr == 0) {
return;
}
// Clear the texture for the text
Memory.getInstance().memset(textAddr, (byte) 0, textSize);
for (int i = 0; i < s.length(); i++) {
drawText(fontInfo, baseAscender, s.charAt(i), glyphType);
}
final int numberOfVertex = 2;
int textVertexAddr = gu.sceGuGetMemory(10 * numberOfVertex);
IMemoryWriter vertexWriter = MemoryWriter.getMemoryWriter(textVertexAddr, 2);
// Texture (0,0)
vertexWriter.writeNext(0);
vertexWriter.writeNext(0);
// Position
vertexWriter.writeNext(textX);
vertexWriter.writeNext(textY);
vertexWriter.writeNext(0);
// Texture (textWidth,textHeigt)
vertexWriter.writeNext(textWidth);
vertexWriter.writeNext(textHeight);
// Position
vertexWriter.writeNext(textX + (int) (textWidth * scale));
vertexWriter.writeNext(textY + (int) (textHeight * scale));
vertexWriter.writeNext(0);
vertexWriter.flush();
int clutAddr = gu.sceGuGetMemory(16 * 4);
IMemoryWriter clutWriter = MemoryWriter.getMemoryWriter(clutAddr, 4);
color &= 0x00FFFFFF;
for (int i = 0; i < 16; i++) {
int alpha = (i << 4) | i;
// Reduce alpha by factor 2 if soft shadows are required (MsgDialog)
if (softShadows && glyphType == SceFontInfo.FONT_PGF_GLYPH_TYPE_SHADOW) {
alpha >>= 1;
}
clutWriter.writeNext((alpha << 24) | color);
}
gu.sceGuClutMode(CMODE_FORMAT_32BIT_ABGR8888, 0, 0xFF, 0);
gu.sceGuClutLoad(2, clutAddr);
gu.sceGuTexMode(TPSM_PIXEL_STORAGE_MODE_4BIT_INDEXED, 0, false);
gu.sceGuTexFunc(TFUNC_FRAGMENT_DOUBLE_TEXTURE_EFECT_REPLACE, true, false);
gu.sceGuTexEnvColor(0x000000);
gu.sceGuTexWrap(TWRAP_WRAP_MODE_CLAMP, TWRAP_WRAP_MODE_CLAMP);
gu.sceGuTexFilter(TFLT_LINEAR, TFLT_LINEAR);
gu.sceGuEnable(GU_TEXTURE_2D);
gu.sceGuTexImage(0, 512, 256, textWidth, textAddr);
gu.sceGuDrawArray(PRIM_SPRITES, (VTYPE_TRANSFORM_PIPELINE_RAW_COORD << 23) | (VTYPE_TEXTURE_FORMAT_16_BIT) | (VTYPE_POSITION_FORMAT_16_BIT << 7), numberOfVertex, 0, textVertexAddr);
}
protected void drawButton(int x, int y, String text, boolean selected) {
if (selected) {
int alpha = getAnimationIndex(0xFF);
gu.sceGuDrawRectangle(x, y, x + text.length() * 17, y + 16, (alpha << 24) | 0xC5C8CF);
}
drawTextWithShadow(x + 5, y + 2, 0.8f, text);
}
protected abstract void updateDialog();
public void checkController() {
// In case the dialog has no buttons, assume the user is confirming.
if (canConfirm() && (isConfirmButtonPressed() || hasNoButtons())) {
utilityDialogState.setButtonPressed(getButtonPressedOK());
dispose();
} else if (canCancel() && isCancelButtonPressed()) {
utilityDialogState.setButtonPressed(SceUtilityMsgDialogParams.PSP_UTILITY_BUTTON_PRESSED_ESC);
dispose();
}
if (hasYesNo()) {
if (isLeftPressed()) {
utilityDialogState.setYesSelected(true);
} else if (isRightPressed()) {
utilityDialogState.setYesSelected(false);
}
}
}
protected boolean isButtonPressed(int button) {
Controller controller = State.controller;
if ((controller.getButtons() & button) == button) {
return true;
}
return false;
}
protected boolean isConfirmButtonPressed() {
return isButtonPressed(areButtonsSwapped() ? sceCtrl.PSP_CTRL_CIRCLE : sceCtrl.PSP_CTRL_CROSS);
}
protected boolean isCancelButtonPressed() {
return isButtonPressed(areButtonsSwapped() ? sceCtrl.PSP_CTRL_CROSS : sceCtrl.PSP_CTRL_CIRCLE);
}
protected void useNoButtons() {
hasNoButtons = true;
}
protected boolean hasNoButtons() {
return hasNoButtons;
}
private int getControllerLy() {
return State.controller.getLy() & 0xFF;
}
private int getControllerLx() {
return State.controller.getLx() & 0xFF;
}
private int getControllerAnalogCenter() {
return Controller.analogCenter & 0xFF;
}
protected boolean canConfirm() {
return true;
}
protected boolean canCancel() {
return true;
}
protected boolean hasYesNo() {
return false;
}
protected int getButtonPressedOK() {
return SceUtilityMsgDialogParams.PSP_UTILITY_BUTTON_PRESSED_OK;
}
private void checkRepeat() {
if (pressedTimestamp != 0 && SystemTimeManager.getSystemTime() - pressedTimestamp > repeatDelay) {
upPressedAnalog = false;
upPressedButton = false;
downPressedAnalog = false;
downPressedButton = false;
leftPressedAnalog = false;
leftPressedButton = false;
rightPressedAnalog = false;
rightPressedButton = false;
pressedTimestamp = 0;
}
}
protected boolean isUpPressed() {
checkRepeat();
if (upPressedButton || upPressedAnalog) {
if (!isButtonPressed(sceCtrl.PSP_CTRL_UP)) {
upPressedButton = false;
}
if (getControllerLy() >= getControllerAnalogCenter()) {
upPressedAnalog = false;
}
return false;
}
if (isButtonPressed(sceCtrl.PSP_CTRL_UP)) {
upPressedButton = true;
pressedTimestamp = SystemTimeManager.getSystemTime();
return true;
}
if (getControllerLy() < getControllerAnalogCenter()) {
upPressedAnalog = true;
pressedTimestamp = SystemTimeManager.getSystemTime();
return true;
}
return false;
}
protected boolean isDownPressed() {
checkRepeat();
if (downPressedButton || downPressedAnalog) {
if (!isButtonPressed(sceCtrl.PSP_CTRL_DOWN)) {
downPressedButton = false;
}
if (getControllerLy() <= getControllerAnalogCenter()) {
downPressedAnalog = false;
}
return false;
}
if (isButtonPressed(sceCtrl.PSP_CTRL_DOWN)) {
downPressedButton = true;
pressedTimestamp = SystemTimeManager.getSystemTime();
return true;
}
if (getControllerLy() > getControllerAnalogCenter()) {
downPressedAnalog = true;
pressedTimestamp = SystemTimeManager.getSystemTime();
return true;
}
return false;
}
protected boolean isLeftPressed() {
checkRepeat();
if (leftPressedButton || leftPressedAnalog) {
if (!isButtonPressed(sceCtrl.PSP_CTRL_LEFT)) {
leftPressedButton = false;
}
if (getControllerLx() >= getControllerAnalogCenter()) {
leftPressedAnalog = false;
}
return false;
}
if (isButtonPressed(sceCtrl.PSP_CTRL_LEFT)) {
leftPressedButton = true;
pressedTimestamp = SystemTimeManager.getSystemTime();
return true;
}
if (getControllerLx() < getControllerAnalogCenter()) {
leftPressedAnalog = true;
pressedTimestamp = SystemTimeManager.getSystemTime();
return true;
}
return false;
}
protected boolean isRightPressed() {
checkRepeat();
if (rightPressedButton || rightPressedAnalog) {
if (!isButtonPressed(sceCtrl.PSP_CTRL_RIGHT)) {
rightPressedButton = false;
}
if (getControllerLx() <= getControllerAnalogCenter()) {
rightPressedAnalog = false;
}
return false;
}
if (isButtonPressed(sceCtrl.PSP_CTRL_RIGHT)) {
rightPressedButton = true;
pressedTimestamp = SystemTimeManager.getSystemTime();
return true;
}
if (getControllerLx() > getControllerAnalogCenter()) {
rightPressedAnalog = true;
pressedTimestamp = SystemTimeManager.getSystemTime();
return true;
}
return false;
}
protected SceFontInfo getDefaultFontInfo() {
if (defaultFontInfo == null) {
// Use "jpn0" font
defaultFontInfo = Modules.sceFontModule.getFont(0).fontInfo;
}
return defaultFontInfo;
}
private String getCross() {
return "X";
}
private String getCircle() {
return "O";
}
protected boolean areButtonsSwapped() {
return buttonsSwapped;
}
// Cross is always displayed to the left (even when the buttons are swapped)
private int getCrossX() {
return 183;
}
// Circle is always displayed to the right (even when the buttons are swapped)
private int getCircleX() {
return 260;
}
private int getEnterX() {
return areButtonsSwapped() ? getCircleX() : getCrossX();
}
private int getBackX() {
return areButtonsSwapped() ? getCrossX() : getCircleX();
}
private String getConfirmString() {
return areButtonsSwapped() ? getCircle() : getCross();
}
private String getCancelString() {
return areButtonsSwapped() ? getCross() : getCircle();
}
protected void drawEnter() {
drawTextWithShadow(getEnterX(), 254, defaultFontScale, String.format("%s %s", getConfirmString(), strEnter));
}
protected void drawBack() {
drawTextWithShadow(getBackX(), 254, defaultFontScale, String.format("%s %s", getCancelString(), strBack));
}
protected void drawEnterWithString(String str) {
drawTextWithShadow(getEnterX(), 254, defaultFontScale, String.format("%s %s", getConfirmString(), str));
}
protected void drawBackWithString(String str) {
drawTextWithShadow(getBackX(), 254, defaultFontScale, String.format("%s %s", getCancelString(), str));
}
protected void drawHeader(String title) {
// Draw rectangle on the top of the screen
gu.sceGuDrawRectangle(0, 0, Screen.width, 22, 0x80605C54);
// Draw dialog title in top rectangle
drawText(30, 4, 128, 32, 20, getDefaultFontInfo(), 15, 0.82f, 0xFFFFFF, title, SceFontInfo.FONT_PGF_GLYPH_TYPE_CHAR);
// Draw filled circle just before dialog title
drawText(9, 5, 32, 32, 20, getDefaultFontInfo(), 15, 0.65f, 0xFFFFFF, new String(Character.toChars(0x25CF)), SceFontInfo.FONT_PGF_GLYPH_TYPE_CHAR);
}
protected void drawYesNo(int xYes, int xNo, int y) {
drawButton(xYes, y, strYes, utilityDialogState.isYesSelected());
drawButton(xNo, y, strNo, utilityDialogState.isNoSelected());
}
protected void drawIcon(int textureAddr, int iconX, int iconY, int iconWidth, int iconHeight) {
if (textureAddr == 0) {
return;
}
int numberOfVertex = 2;
int iconVertexAddr = gu.sceGuGetMemory(10 * numberOfVertex);
if (iconVertexAddr == 0) {
return;
}
IMemoryWriter vertexWriter = MemoryWriter.getMemoryWriter(iconVertexAddr, 2);
// Texture
vertexWriter.writeNext(0);
vertexWriter.writeNext(0);
// Position
vertexWriter.writeNext(iconX);
vertexWriter.writeNext(iconY);
vertexWriter.writeNext(0);
// Texture
vertexWriter.writeNext(icon0Width);
vertexWriter.writeNext(icon0Height);
// Position
vertexWriter.writeNext(iconX + iconWidth);
vertexWriter.writeNext(iconY + iconHeight);
vertexWriter.writeNext(0);
vertexWriter.flush();
gu.sceGuTexEnvColor(0x000000);
gu.sceGuTexMode(icon0PixelFormat, 0, false);
gu.sceGuTexImage(0, 256, 128, icon0BufferWidth, textureAddr);
gu.sceGuTexFunc(TFUNC_FRAGMENT_DOUBLE_TEXTURE_EFECT_REPLACE, true, false);
gu.sceGuTexFilter(TFLT_LINEAR, TFLT_LINEAR);
gu.sceGuTexWrap(TWRAP_WRAP_MODE_CLAMP, TWRAP_WRAP_MODE_CLAMP);
gu.sceGuEnable(GU_TEXTURE_2D);
gu.sceGuDrawArray(PRIM_SPRITES, (VTYPE_TRANSFORM_PIPELINE_RAW_COORD << 23) | (VTYPE_TEXTURE_FORMAT_16_BIT) | (VTYPE_POSITION_FORMAT_16_BIT << 7), numberOfVertex, 0, iconVertexAddr);
}
protected int readIcon(InputStream is) {
BufferedImage image = null;
// Get icon image
if (is != null) {
try {
image = ImageIO.read(is);
} catch (IOException e) {
log.debug("getIcon0", e);
} catch (Exception e) {
// Corrupted data, just ignore.
}
}
// Default icon
if (image == null) {
try {
image = ImageIO.read(getClass().getResource("/jpcsp/images/icon0.png"));
} catch (IOException e) {
log.error("Cannot read default icon0.png", e);
}
}
if (image == null) {
return 0;
}
int bytesPerPixel = IRenderingEngine.sizeOfTextureType[icon0PixelFormat];
int textureAddr = gu.sceGuGetMemory(icon0BufferWidth * icon0Height * bytesPerPixel);
if (textureAddr == 0) {
return 0;
}
IMemoryWriter textureWriter = MemoryWriter.getMemoryWriter(textureAddr, bytesPerPixel);
int width = Math.min(image.getWidth(), icon0Width);
int height = Math.min(image.getHeight(), icon0Height);
for (int hy = 0; hy < height; hy++) {
for (int wx = 0; wx < width; wx++) {
int colorARGB = image.getRGB(wx, hy);
int colorABGR = colorARGBtoABGR(colorARGB);
textureWriter.writeNext(colorABGR);
}
for (int wx = width; wx < icon0BufferWidth; wx++) {
textureWriter.writeNext(0);
}
}
textureWriter.flush();
return textureAddr;
}
protected int readIcon(int address) {
InputStream iconStream = null;
if (address != 0) {
iconStream = new MemoryInputStream(address);
}
return readIcon(iconStream);
}
protected int getAnimationIndex(int maxIndex) {
if (drawSpeed <= 0) {
return maxIndex;
}
long now = Emulator.getClock().currentTimeMillis();
int durationMillis = (int) (now - startDialogMillis);
int animationIndex = durationMillis % 500 * (maxIndex + 1) / 500;
if (((durationMillis / 500) % 2) != 0) {
// Revert the animation index every 0.5 second
animationIndex = maxIndex - animationIndex;
}
return animationIndex;
}
}
protected static class GuSavedataDialogSave extends GuUtilityDialog {
protected final SavedataUtilityDialogState savedataDialogState;
protected final SceUtilitySavedataParam savedataParams;
protected boolean isYesSelected;
final private String strAskSaveData;
final private String strAskOverwriteData;
protected GuSavedataDialogSave(final SceUtilitySavedataParam savedataParams, final SavedataUtilityDialogState savedataDialogState) {
super(savedataParams.base);
this.savedataDialogState = savedataDialogState;
this.savedataParams = savedataParams;
strAskSaveData = ResourceBundle.getBundle("jpcsp/languages/jpcsp", utilityLocale).getString("sceUtilitySavedata.strAskSaveData.text");
strAskOverwriteData = ResourceBundle.getBundle("jpcsp/languages/jpcsp", utilityLocale).getString("sceUtilitySavedata.strAskOverwriteData.text");
createDialog(savedataDialogState);
}
@Override
protected void updateDialog() {
String dialogTitle = savedataDialogState.getDialogTitle(savedataParams.getModeName(), "Save", utilityLocale);
Calendar savedTime = savedataParams.getSavedTime();
drawIcon(readIcon(savedataParams.icon0FileData.buf), 26, 96, icon0Width, icon0Height);
String text = getText(dialogTitle);
boolean multiLines = getTextLines(text) > 1;
if (hasYesNo()) {
int textX = multiLines ? 236 : centerText(getDefaultFontInfo(), text, 201, 464, defaultFontScale);
gu.sceGuDrawHorizontalLine(201, 464, multiLines ? 87 : 97, 0xFF000000 | textColor);
drawTextWithShadow(textX, multiLines ? 105 : 113, defaultFontScale, text);
drawYesNo(278, 349, multiLines ? 154 : 145);
gu.sceGuDrawHorizontalLine(201, 464, multiLines ? 184 : 174, 0xFF000000 | textColor);
} else {
int textX = multiLines ? 270 : centerText(getDefaultFontInfo(), text, 201, 464, defaultFontScale);
gu.sceGuDrawHorizontalLine(201, 464, 114, 0xFF000000 | textColor);
drawTextWithShadow(textX, 131, defaultFontScale, text);
gu.sceGuDrawHorizontalLine(201, 464, 157, 0xFF000000 | textColor);
}
drawTextWithShadow(6, 202, defaultFontScale, savedataParams.sfoParam.savedataTitle);
if (savedTime != null) {
drawTextWithShadow(6, 219, 0.7f, formatDateTime(savedTime));
}
drawTextWithShadow(6, 237, defaultFontScale, MemoryStick.getSizeKbString(savedataParams.getRequiredSizeKb()));
if (hasEnter()) {
drawEnter();
}
drawBack();
drawHeader(dialogTitle);
}
protected String getText(String dialogTitle) {
return (savedataParams.isPresent()) ? strAskOverwriteData : strAskSaveData;
}
protected boolean hasEnter() {
return true;
}
@Override
protected boolean hasYesNo() {
return true;
}
}
protected static class GuSavedataDialogLoad extends GuUtilityDialog {
protected final SavedataUtilityDialogState savedataDialogState;
protected final SceUtilitySavedataParam savedataParams;
protected boolean isYesSelected;
protected boolean hasYesNo;
final private String strNoData;
final private String strAskLoadData;
protected GuSavedataDialogLoad(final SceUtilitySavedataParam savedataParams, final SavedataUtilityDialogState savedataDialogState) {
super(savedataParams.base);
this.savedataDialogState = savedataDialogState;
this.savedataParams = savedataParams;
hasYesNo = savedataParams.isPresent();
strNoData = ResourceBundle.getBundle("jpcsp/languages/jpcsp", utilityLocale).getString("sceUtilitySavedata.strNoData.text");
strAskLoadData = ResourceBundle.getBundle("jpcsp/languages/jpcsp", utilityLocale).getString("sceUtilitySavedata.strAskLoadData.text");
createDialog(savedataDialogState);
}
@Override
protected void updateDialog() {
String dialogTitle = savedataDialogState.getDialogTitle(savedataParams.getModeName(), "Load", utilityLocale);
Calendar savedTime = savedataParams.getSavedTime();
drawIcon(readIcon(savedataParams.icon0FileData.buf), 26, 96, icon0Width, icon0Height);
if (!hasYesNo()) {
gu.sceGuDrawHorizontalLine(201, 464, 114, 0xFF000000 | textColor);
drawTextWithShadow(270, 131, defaultFontScale, strNoData);
gu.sceGuDrawHorizontalLine(201, 464, 157, 0xFF000000 | textColor);
} else {
gu.sceGuDrawHorizontalLine(201, 464, 87, 0xFF000000 | textColor);
drawTextWithShadow(236, 105, defaultFontScale, strAskLoadData);
drawYesNo(278, 349, 154);
gu.sceGuDrawHorizontalLine(201, 464, 184, 0xFF000000 | textColor);
drawTextWithShadow(6, 202, defaultFontScale, savedataParams.sfoParam.savedataTitle);
if (savedTime != null) {
drawTextWithShadow(6, 219, 0.7f, formatDateTime(savedTime));
}
drawTextWithShadow(6, 237, defaultFontScale, MemoryStick.getSizeKbString(savedataParams.getRequiredSizeKb()));
drawEnter();
}
drawBack();
drawHeader(dialogTitle);
}
@Override
protected boolean hasYesNo() {
return hasYesNo;
}
@Override
protected boolean canConfirm() {
return hasYesNo();
}
}
protected static class GuSavedataDialogCompleted extends GuUtilityDialog {
protected final SavedataUtilityDialogState savedataDialogState;
protected final SceUtilitySavedataParam savedataParams;
protected boolean isYesSelected;
private String strCompleted;
protected GuSavedataDialogCompleted(final SceUtilitySavedataParam savedataParams, final SavedataUtilityDialogState savedataDialogState) {
super(savedataParams.base);
this.savedataDialogState = savedataDialogState;
this.savedataParams = savedataParams;
try {
strCompleted = ResourceBundle.getBundle("jpcsp/languages/jpcsp", utilityLocale).getString(String.format("sceUtilitySavedata.%s.strCompleted.text", savedataParams.getModeName()));
} catch (MissingResourceException e) {
// Ignore exception and provide a default
strCompleted = "Completed";
}
createDialog(savedataDialogState);
}
@Override
protected void updateDialog() {
String dialogTitle = savedataDialogState.getDialogTitle(savedataParams.getModeName(), "Save", utilityLocale);
Calendar savedTime = savedataParams.getSavedTime();
drawIcon(readIcon(savedataParams.icon0FileData.buf), 26, 96, icon0Width, icon0Height);
gu.sceGuDrawHorizontalLine(201, 464, 114, 0xFF000000 | textColor);
drawTextWithShadow(270, 131, defaultFontScale, strCompleted);
gu.sceGuDrawHorizontalLine(201, 464, 157, 0xFF000000 | textColor);
drawTextWithShadow(6, 202, defaultFontScale, savedataParams.sfoParam.savedataTitle);
if (savedTime != null) {
drawTextWithShadow(6, 219, 0.7f, formatDateTime(savedTime));
}
drawTextWithShadow(6, 237, defaultFontScale, MemoryStick.getSizeKbString(savedataParams.getRequiredSizeKb()));
drawBack();
drawHeader(dialogTitle);
}
@Override
protected boolean canConfirm() {
return false;
}
}
protected static class GuSavedataDialog extends GuUtilityDialog {
private final SavedataUtilityDialogState savedataDialogState;
private final SceUtilitySavedataParam savedataParams;
private final String[] saveNames;
private final int numberRows;
private int selectedRow;
private String strNewData;
final private String strNoData;
public GuSavedataDialog(final SceUtilitySavedataParam savedataParams, final SavedataUtilityDialogState savedataDialogState, final String[] saveNames) {
super(savedataParams.base);
this.savedataDialogState = savedataDialogState;
this.savedataParams = savedataParams;
this.saveNames = saveNames;
strNoData = ResourceBundle.getBundle("jpcsp/languages/jpcsp", utilityLocale).getString("sceUtilitySavedata.strNoData.text");
if (savedataParams.newData != null && savedataParams.newData.title != null) {
// the PspUtilitySavedataListSaveNewData structure contains the title
// to be used for new data.
strNewData = savedataParams.newData.title;
} else {
strNewData = ResourceBundle.getBundle("jpcsp/languages/jpcsp", utilityLocale).getString("sceUtilitySavedata.strNewData.text");
}
createDialog(savedataDialogState);
numberRows = saveNames == null ? 0 : saveNames.length;
savedataDialogState.saveListEmpty = (numberRows <= 0);
// Define the selected row according to the focus field
selectedRow = 0;
switch (savedataParams.focus) {
case SceUtilitySavedataParam.FOCUS_FIRSTLIST: {
selectedRow = 0;
break;
}
case SceUtilitySavedataParam.FOCUS_LASTLIST: {
selectedRow = numberRows - 1;
break;
}
case SceUtilitySavedataParam.FOCUS_LATEST: {
long latestTimestamp = Long.MIN_VALUE;
for (int i = 0; i < numberRows; i++) {
long timestamp = getTimestamp(saveNames[i]);
if (timestamp > latestTimestamp) {
latestTimestamp = timestamp;
selectedRow = i;
}
}
break;
}
case SceUtilitySavedataParam.FOCUS_OLDEST: {
long oldestTimestamp = Long.MAX_VALUE;
for (int i = 0; i < numberRows; i++) {
long timestamp = getTimestamp(saveNames[i]);
if (timestamp < oldestTimestamp) {
oldestTimestamp = timestamp;
selectedRow = i;
}
}
break;
}
case SceUtilitySavedataParam.FOCUS_FIRSTEMPTY: {
for (int i = 0; i < numberRows; i++) {
if (isEmpty(saveNames[i])) {
selectedRow = i;
break;
}
}
break;
}
case SceUtilitySavedataParam.FOCUS_LASTEMPTY: {
for (int i = numberRows - 1; i >= 0; i--) {
if (isEmpty(saveNames[i])) {
selectedRow = i;
break;
}
}
break;
}
}
}
private boolean isEmpty(String saveName) {
return !savedataParams.isPresent(savedataParams.gameName, saveName);
}
private long getTimestamp(String saveName) {
return savedataParams.getTimestamp(savedataParams.gameName, saveName);
}
private int getIcon0(int index) {
if (index < 0 || index >= saveNames.length) {
return 0;
}
InputStream iconStream = null;
// Get icon0 file
String iconFileName = savedataParams.getFileName(saveNames[index], SceUtilitySavedataParam.icon0FileName);
SeekableDataInput iconDataInput = Modules.IoFileMgrForUserModule.getFile(iconFileName, IoFileMgrForUser.PSP_O_RDONLY);
if (iconDataInput != null) {
try {
int length = (int) iconDataInput.length();
byte[] iconBuffer = new byte[length];
iconDataInput.readFully(iconBuffer);
iconDataInput.close();
iconStream = new ByteArrayInputStream(iconBuffer);
} catch (IOException e) {
log.debug("getIcon0", e);
}
} else if (savedataParams.newData != null && savedataParams.newData.icon0 != null) {
// the PspUtilitySavedataListSaveNewData structure contains the default
// icon to be used for new data.
int addr = savedataParams.newData.icon0.buf;
int size = savedataParams.newData.icon0.size;
if (addr != 0 && size > 0) {
// An incorrect size for the icon0 is accepted, look for the end of the PNG
size = PNG.getEndOfPNG(Memory.getInstance(), addr, size);
byte[] iconBuffer = new byte[size];
IMemoryReader memoryReader = MemoryReader.getMemoryReader(addr, size, 1);
for (int i = 0; i < size; i++) {
iconBuffer[i] = (byte) memoryReader.readNext();
}
iconStream = new ByteArrayInputStream(iconBuffer);
}
}
return readIcon(iconStream);
}
private PSF getPsf(int index) {
PSF psf = null;
if (index < 0 || index >= saveNames.length) {
return psf;
}
String sfoFileName = savedataParams.getFileName(saveNames[index], SceUtilitySavedataParam.paramSfoFileName);
SeekableDataInput sfoDataInput = Modules.IoFileMgrForUserModule.getFile(sfoFileName, IoFileMgrForUser.PSP_O_RDONLY);
if (sfoDataInput != null) {
try {
int length = (int) sfoDataInput.length();
byte[] sfoBuffer = new byte[length];
sfoDataInput.readFully(sfoBuffer);
sfoDataInput.close();
psf = new PSF();
psf.read(ByteBuffer.wrap(sfoBuffer));
} catch (IOException e) {
}
}
return psf;
}
private void drawIconByRow(int row, int iconX, int iconY, int iconWidth, int iconHeight) {
drawIcon(getIcon0(row), iconX, iconY, iconWidth, iconHeight);
}
@Override
protected void updateDialog() {
if (numberRows > 0) {
drawIconByRow(selectedRow, 26, 96, icon0Width, icon0Height);
// Get values (title, detail...) from SFO file
PSF psf = getPsf(selectedRow);
if (psf != null) {
String title = psf.getString("TITLE");
String detail = psf.getString("SAVEDATA_DETAIL");
String savedataTitle = psf.getString("SAVEDATA_TITLE");
Calendar savedTime = savedataParams.getSavedTime(saveNames[selectedRow]);
int textX = 180;
int textY = 119;
drawTextWithShadow(textX, textY, 0xD1C6BA, 0.85f, truncateText(title, Screen.width - textX, 0.85f));
textY += 22;
if (savedTime != null) {
String text = formatDateTime(savedTime);
int sizeKb = savedataParams.getSizeKb(savedataParams.gameName, saveNames[selectedRow]);
text += " " + MemoryStick.getSizeKbString(sizeKb);
drawTextWithShadow(textX, textY, 0.7f, text);
}
// Draw horizontal line below title
gu.sceGuDrawHorizontalLine(textX, Screen.width, textY - 6, 0xFF000000 | textColor);
textX -= 5;
textY += 23;
drawTextWithShadow(textX, textY, 0.7f, savedataTitle);
textY += 24;
drawTextWithShadow(textX, textY, 0.7f, detail);
} else {
drawTextWithShadow(180, 130, defaultFontScale, strNewData);
}
drawEnter();
drawBack();
if (selectedRow > 0) {
drawIconByRow(selectedRow - 1, 58, 38, smallIcon0Width, smallIcon0Height);
if (selectedRow > 1) {
drawIconByRow(selectedRow - 2, 58, -5, smallIcon0Width, smallIcon0Height);
}
}
if (selectedRow < numberRows - 1) {
drawIconByRow(selectedRow + 1, 58, 190, smallIcon0Width, smallIcon0Height);
if (selectedRow < numberRows - 2) {
drawIconByRow(selectedRow + 2, 58, 233, smallIcon0Width, smallIcon0Height);
}
}
} else {
gu.sceGuDrawHorizontalLine(201, 464, 114, 0xFF000000 | textColor);
drawTextWithShadow(centerText(getDefaultFontInfo(), strNoData, 201, 464, defaultFontScale), 131, defaultFontScale, strNoData);
gu.sceGuDrawHorizontalLine(201, 464, 157, 0xFF000000 | textColor);
drawBack();
}
String dialogTitle = savedataDialogState.getDialogTitle(savedataParams.getModeName(), "Savedata List", utilityLocale);
drawHeader(dialogTitle);
}
@Override
public void checkController() {
if (isDownPressed()) {
// One row down
selectedRow++;
} else if (isUpPressed()) {
// One row up
selectedRow--;
} else if (isButtonPressed(sceCtrl.PSP_CTRL_LTRIGGER)) {
// First row
selectedRow = 0;
} else if (isButtonPressed(sceCtrl.PSP_CTRL_RTRIGGER)) {
// Last row
selectedRow = numberRows - 1;
}
selectedRow = max(selectedRow, 0);
selectedRow = min(selectedRow, numberRows - 1);
if (selectedRow >= 0) {
savedataDialogState.saveListSelection = saveNames[selectedRow];
} else {
savedataDialogState.saveListSelection = null;
}
super.checkController();
}
@Override
protected boolean canConfirm() {
// Can only confirm if at least one row is displayed
return numberRows > 0;
}
}
protected static class GuMsgDialog extends GuUtilityDialog {
protected SceUtilityMsgDialogParams msgDialogParams;
public GuMsgDialog(final SceUtilityMsgDialogParams msgDialogParams, MsgDialogUtilityDialogState msgDialogState) {
super(msgDialogParams.base);
this.msgDialogParams = msgDialogParams;
msgDialogState.setYesSelected(msgDialogParams.isOptionYesNoDefaultYes());
createDialog(msgDialogState);
}
@Override
protected void updateDialog() {
// Shadows are softer in MsgDialog
setSoftShadows(true);
// Clear screen in light gray color. Do not clear depth and stencil values.
gu.sceGuClear(CLEAR_COLOR_BUFFER, 0x968681);
int buttonY = 192;
String message = getMessage();
if (message != null) {
int currentLineLength = 0;
List<String> lines = new LinkedList<String>();
StringBuilder currentLine = new StringBuilder();
int splitLineIndex = -1;
int maxLineLength = 430;
int longestLine = 0;
SceFontInfo fontInfo = getDefaultFontInfo();
for (int i = 0; i < message.length(); i++) {
char c = message.charAt(i);
if (c == '\n') {
longestLine = Math.max(longestLine, currentLineLength);
lines.add(currentLine.toString());
currentLine.setLength(0);
currentLineLength = 0;
splitLineIndex = -1;
} else {
int charLength = getTextLength(fontInfo, c);
if (currentLineLength + charLength > maxLineLength) {
if (splitLineIndex < 0) {
splitLineIndex = currentLine.length();
}
String line = currentLine.substring(0, splitLineIndex);
longestLine = Math.max(longestLine, getTextLength(fontInfo, line));
lines.add(line);
currentLine.delete(0, splitLineIndex);
currentLineLength = getTextLength(fontInfo, currentLine.toString());
splitLineIndex = -1;
}
currentLine.append(c);
currentLineLength += charLength;
if (c == ' ') {
splitLineIndex = currentLine.length();
}
}
}
if (currentLine.length() > 0) {
longestLine = Math.max(longestLine, currentLineLength);
lines.add(currentLine.toString());
}
final int lineHeight = 19;
int lineCount = lines.size();
int textHeight = lineHeight * lineCount;
int totalHeight = textHeight + 24;
if (msgDialogParams.isOptionYesNo() || msgDialogParams.isOptionOk()) {
// Add height for button(s)
totalHeight += 33;
}
int topLineY = (Screen.height - totalHeight) / 2;
buttonY = topLineY + totalHeight - 29;
int lineColor = 0xFFDFDAD9;
// Draw top line
gu.sceGuDrawHorizontalLine(60, 420, topLineY, lineColor);
// Draw bottom line
gu.sceGuDrawHorizontalLine(60, 420, topLineY + totalHeight, lineColor);
final float scale = 0.79f;
int y = topLineY + 17;
// Center the text
final int x = 63 + (360 - Math.round(longestLine * scale)) / 2;
for (String line : lines) {
drawTextWithShadow(x, y, scale, line);
y += lineHeight;
}
}
if (msgDialogParams.isOptionYesNo()) {
drawYesNo(185, 255, buttonY);
} else if (msgDialogParams.isOptionOk()) {
drawButton(223, buttonY, "OK", true);
}
if ((msgDialogParams.options & SceUtilityMsgDialogParams.PSP_UTILITY_MSGDIALOG_OPTION_NORMAL) != 0 && !msgDialogParams.isOptionOk() && !msgDialogParams.isOptionYesNo()) {
// In this case, no buttons are displayed to the user.
// In the PSP the user waits a few seconds and the dialog closes itself.
useNoButtons();
} else {
if ((msgDialogParams.options & SceUtilityMsgDialogParams.PSP_UTILITY_MSGDIALOG_OPTION_DISABLE_CANCEL) == SceUtilityMsgDialogParams.PSP_UTILITY_MSGDIALOG_OPTION_ENABLE_CANCEL) {
// Enter is not displayed when all options are 0
if (msgDialogParams.options != 0) {
if (msgDialogParams.enterButtonString != null) {
if (!msgDialogParams.enterButtonString.equals("")) {
drawEnterWithString(msgDialogParams.enterButtonString);
} else {
drawEnter();
}
} else {
drawEnter();
}
}
if (msgDialogParams.backButtonString != null) {
if (!msgDialogParams.backButtonString.equals("")) {
drawBackWithString(msgDialogParams.backButtonString);
} else {
drawBack();
}
} else {
drawBack();
}
} else if ((msgDialogParams.options & SceUtilityMsgDialogParams.PSP_UTILITY_MSGDIALOG_OPTION_BUTTON_TYPE_MASK) != SceUtilityMsgDialogParams.PSP_UTILITY_MSGDIALOG_OPTION_BUTTON_TYPE_NONE) {
if (msgDialogParams.enterButtonString != null) {
if (!msgDialogParams.enterButtonString.equals("")) {
drawEnterWithString(msgDialogParams.enterButtonString);
} else {
drawEnter();
}
} else {
drawEnter();
}
}
}
}
protected String getMessage() {
if (msgDialogParams.mode == SceUtilityMsgDialogParams.PSP_UTILITY_MSGDIALOG_MODE_ERROR) {
return String.format("Error 0x%08X", msgDialogParams.errorValue);
}
return msgDialogParams.message;
}
@Override
protected boolean canCancel() {
return (msgDialogParams.options & SceUtilityMsgDialogParams.PSP_UTILITY_MSGDIALOG_OPTION_DISABLE_CANCEL) == SceUtilityMsgDialogParams.PSP_UTILITY_MSGDIALOG_OPTION_ENABLE_CANCEL;
}
@Override
protected boolean canConfirm() {
return (msgDialogParams.options & SceUtilityMsgDialogParams.PSP_UTILITY_MSGDIALOG_OPTION_BUTTON_TYPE_MASK) != SceUtilityMsgDialogParams.PSP_UTILITY_MSGDIALOG_OPTION_BUTTON_TYPE_NONE;
}
@Override
protected int getButtonPressedOK() {
if (msgDialogParams.isOptionYesNo()) {
return utilityDialogState.isYesSelected() ? SceUtilityMsgDialogParams.PSP_UTILITY_BUTTON_PRESSED_YES : SceUtilityMsgDialogParams.PSP_UTILITY_BUTTON_PRESSED_NO;
}
return super.getButtonPressedOK();
}
@Override
protected boolean hasYesNo() {
return msgDialogParams.isOptionYesNo();
}
}
protected static class OskDialog extends UtilityDialog {
private static final long serialVersionUID = 1155047781007677923L;
protected JTextField textField;
public OskDialog(final SceUtilityOskParams oskParams, OskUtilityDialogState oskState) {
createDialog(oskState, oskParams.oskData.desc);
textField = new JTextField(oskParams.oskData.inText);
messagePane.add(textField);
JButton okButton = new JButton("Ok");
okButton.addActionListener(closeActionListener);
okButton.setActionCommand(actionCommandOK);
buttonPane.add(okButton);
setDefaultButton(okButton);
endDialog();
}
}
public static String getSystemParamNickname() {
return Settings.getInstance().readString(SYSTEMPARAM_SETTINGS_OPTION_NICKNAME);
}
public static int getSystemParamAdhocChannel() {
int indexedValue = Settings.getInstance().readInt(SYSTEMPARAM_SETTINGS_OPTION_ADHOC_CHANNEL, 0);
String[] guiValues = SettingsGUI.getSysparamAdhocChannels();
int channel = 0;
// Invalid value?
if (guiValues == null || indexedValue < 0 || indexedValue >= guiValues.length) {
return channel;
}
// Auto value?
if (indexedValue == 0) {
return channel;
}
try {
channel = Integer.parseInt(guiValues[indexedValue]);
} catch (NumberFormatException e) {
log.error(String.format("Invalid channel settings value %d from %s", indexedValue, guiValues));
}
return channel;
}
public static int getSystemParamWlanPowersave() {
return Settings.getInstance().readInt(SYSTEMPARAM_SETTINGS_OPTION_WLAN_POWER_SAVE, 0);
}
public static int getSystemParamDateFormat() {
return Settings.getInstance().readInt(SYSTEMPARAM_SETTINGS_OPTION_DATE_FORMAT, PSP_SYSTEMPARAM_DATE_FORMAT_YYYYMMDD);
}
public static int getSystemParamTimeFormat() {
return Settings.getInstance().readInt(SYSTEMPARAM_SETTINGS_OPTION_TIME_FORMAT, PSP_SYSTEMPARAM_TIME_FORMAT_24HR);
}
public static int getSystemParamTimeZone() {
return Settings.getInstance().readInt(SYSTEMPARAM_SETTINGS_OPTION_TIME_ZONE, 0);
}
public static int getSystemParamDaylightSavingTime() {
return Settings.getInstance().readInt(SYSTEMPARAM_SETTINGS_OPTION_DAYLIGHT_SAVING_TIME, 0);
}
public static int getSystemParamLanguage() {
return Settings.getInstance().readInt(SYSTEMPARAM_SETTINGS_OPTION_LANGUAGE, PSP_SYSTEMPARAM_LANGUAGE_ENGLISH);
}
public static int getSystemParamButtonPreference() {
return Settings.getInstance().readInt(SYSTEMPARAM_SETTINGS_OPTION_BUTTON_PREFERENCE, PSP_SYSTEMPARAM_BUTTON_CROSS);
}
public static int getSystemParamLockParentalLevel() {
return Settings.getInstance().readInt(SYSTEMPARAM_SETTINGS_OPTION_LOCK_PARENTAL_LEVEL, 0);
}
protected static String getNetParamName(int id) {
if (id == 0) {
return "";
}
return String.format(dummyNetParamName, id);
}
protected static String formatMessageForDialog(String message) {
StringBuilder formattedMessage = new StringBuilder();
for (int i = 0; i < message.length();) {
String rest = message.substring(i);
int newLineIndex = rest.indexOf("\n");
if (newLineIndex >= 0 && newLineIndex < maxLineLengthForDialog) {
formattedMessage.append(rest.substring(0, newLineIndex + 1));
i += newLineIndex + 1;
} else if (rest.length() > maxLineLengthForDialog) {
int lastSpace = rest.lastIndexOf(' ', maxLineLengthForDialog);
rest = rest.substring(0, (lastSpace >= 0 ? lastSpace : maxLineLengthForDialog));
formattedMessage.append(rest);
i += rest.length() + 1;
formattedMessage.append("\n");
} else {
formattedMessage.append(rest);
i += rest.length();
}
}
return formattedMessage.toString();
}
public static enum UtilityModule {
PSP_MODULE_NET_COMMON(0x0100),
PSP_MODULE_NET_ADHOC(0x0101),
PSP_MODULE_NET_INET(0x0102),
PSP_MODULE_NET_PARSEURI(0x0103),
PSP_MODULE_NET_PARSEHTTP(0x0104),
PSP_MODULE_NET_HTTP(0x0105),
PSP_MODULE_NET_SSL(0x0106, new String[] { "flash0:/kd/libssl.prx", "flash0:/kd/cert_loader.prx" }),
PSP_MODULE_NET_UPNP(0x0107),
PSP_MODULE_NET_HTTPSTORAGE(0x0108),
PSP_MODULE_USB_PSPCM(0x0200),
PSP_MODULE_USB_MIC(0x0201),
PSP_MODULE_USB_CAM(0x0202),
PSP_MODULE_USB_GPS(0x0203),
PSP_MODULE_AV_AVCODEC(0x0300, "flash0:/kd/avcodec.prx"),
PSP_MODULE_AV_SASCORE(0x0301, "flash0:/kd/sc_sascore.prx"),
PSP_MODULE_AV_ATRAC3PLUS(0x0302, "flash0:/kd/libatrac3plus.prx"),
PSP_MODULE_AV_MPEGBASE(0x0303, "flash0:/kd/mpeg.prx"),
PSP_MODULE_AV_MP3(0x0304),
PSP_MODULE_AV_VAUDIO(0x0305),
PSP_MODULE_AV_AAC(0x0306),
PSP_MODULE_AV_G729(0x0307),
PSP_MODULE_AV_MP4(0x0308, new String[] { "flash0:/kd/libmp4.prx", "flash0:/kd/mp4msv.prx" } ),
PSP_MODULE_NP_COMMON(0x0400, new String[] { "flash0:/kd/np.prx", "flash0:/kd/np_core.prx", "flash0:/kd/np_auth.prx" }),
PSP_MODULE_NP_SERVICE(0x0401, "flash0:/kd/np_service.prx"),
PSP_MODULE_NP_MATCHING2(0x0402, "flash0:/kd/np_matching2.prx"),
PSP_MODULE_NP_COMMERCE2(0x0403, "flash0:/kd/np_commerce2.prx"),
PSP_MODULE_NP_DRM(0x0500),
PSP_MODULE_IRDA(0x0600);
private int id;
private String[] prxNames;
private UtilityModule(int id) {
this.id = id;
}
private UtilityModule(int id, String prxName) {
this.id = id;
prxNames = new String[] { prxName };
}
private UtilityModule(int id, String[] prxNames) {
this.id = id;
this.prxNames = prxNames;
}
public int getID() {
return id;
}
public String[] getPrxNames() {
if (prxNames == null) {
return new String[] { toString() };
}
return prxNames;
}
}
protected String[] getModuleNames(int module) {
for (UtilityModule m : UtilityModule.values()) {
if (m.getID() == module) {
return m.getPrxNames();
}
}
return new String[] { String.format("PSP_MODULE_UNKNOWN_%X", module) };
}
protected int hleUtilityLoadModule(int module, String moduleName) {
// Extract the PRX name from the module name
String prxName = moduleName;
if (moduleName.endsWith(".prx")) {
prxName = moduleName.substring(moduleName.lastIndexOf("/") + 1, moduleName.length() - 4);
}
HLEModuleManager moduleManager = HLEModuleManager.getInstance();
if (!moduleManager.hasFlash0Module(prxName)) { // Can't load flash0 module.
waitingModules.put(module, moduleName); // Always save a load attempt.
log.error("Can't load flash0 module");
return SceKernelErrors.ERROR_MODULE_BAD_ID;
}
// Load and save it in loadedModules.
int sceModuleId;
if (moduleName.equals(prxName)) {
sceModuleId = moduleManager.LoadFlash0Module(moduleName);
} else {
sceModuleId = Modules.ModuleMgrForUserModule.hleKernelLoadAndStartModule(moduleName, 0x10);
}
SceModule sceModule = Managers.modules.getModuleByUID(sceModuleId);
if (!loadedModules.containsKey(module)) {
loadedModules.put(module, new LinkedList<SceModule>());
}
loadedModules.get(module).add(sceModule);
return 0;
}
protected int hleUtilityUnloadModule(int module) {
if (loadedModules.containsKey(module)) {
// Unload the module.
HLEModuleManager moduleManager = HLEModuleManager.getInstance();
for (SceModule sceModule : loadedModules.remove(module)) {
moduleManager.UnloadFlash0Module(sceModule);
}
return 0;
} else if (waitingModules.containsKey(module)) {
// Simulate a successful unload.
waitingModules.remove(module);
return 0;
} else {
log.error("Not yet loaded");
return SceKernelErrors.ERROR_MODULE_NOT_LOADED;
}
}
private String getAvModuleName(int module) {
if (module < 0 || module >= utilityAvModuleNames.length) {
return "PSP_AV_MODULE_UNKNOWN_" + module;
}
return utilityAvModuleNames[module];
}
private String getUsbModuleName(int module) {
if (module < 0 || module >= utilityUsbModuleNames.length) {
return "PSP_USB_MODULE_UNKNOWN_" + module;
}
return utilityUsbModuleNames[module];
}
protected int hleUtilityLoadAvModule(int module, String moduleName) {
HLEModuleManager moduleManager = HLEModuleManager.getInstance();
if (loadedAvModules.containsKey(module) || waitingAvModules.containsKey(module)) { // Module already loaded.
return SceKernelErrors.ERROR_AV_MODULE_ALREADY_LOADED;
} else if (!moduleManager.hasFlash0Module(moduleName)) { // Can't load flash0 module.
waitingAvModules.put(module, moduleName); // Always save a load attempt.
return SceKernelErrors.ERROR_AV_MODULE_BAD_ID;
} else {
// Load and save it in loadedAvModules.
int sceModuleId = moduleManager.LoadFlash0Module(moduleName);
SceModule sceModule = Managers.modules.getModuleByUID(sceModuleId);
loadedAvModules.put(module, sceModule);
return 0;
}
}
protected int hleUtilityLoadUsbModule(int module, String moduleName) {
HLEModuleManager moduleManager = HLEModuleManager.getInstance();
if (loadedUsbModules.containsKey(module) || waitingUsbModules.containsKey(module)) { // Module already loaded.
return SceKernelErrors.ERROR_AV_MODULE_ALREADY_LOADED;
} else if (!moduleManager.hasFlash0Module(moduleName)) { // Can't load flash0 module.
waitingUsbModules.put(module, moduleName); // Always save a load attempt.
return SceKernelErrors.ERROR_AV_MODULE_BAD_ID;
} else {
// Load and save it in loadedAvModules.
int sceModuleId = moduleManager.LoadFlash0Module(moduleName);
SceModule sceModule = Managers.modules.getModuleByUID(sceModuleId);
loadedUsbModules.put(module, sceModule);
return 0;
}
}
protected int hleUtilityUnloadAvModule(int module) {
if (loadedAvModules.containsKey(module)) {
// Unload the module.
HLEModuleManager moduleManager = HLEModuleManager.getInstance();
SceModule sceModule = loadedAvModules.remove(module);
moduleManager.UnloadFlash0Module(sceModule);
return 0;
} else if (waitingAvModules.containsKey(module)) {
// Simulate a successful unload.
waitingAvModules.remove(module);
return 0;
} else {
return SceKernelErrors.ERROR_AV_MODULE_NOT_LOADED;
}
}
@HLEFunction(nid = 0xC492F751, version = 150)
public int sceUtilityGameSharingInitStart(TPointer paramsAddr) {
return gameSharingState.executeInitStart(paramsAddr);
}
@HLEFunction(nid = 0xEFC6F80F, version = 150)
public int sceUtilityGameSharingShutdownStart() {
return gameSharingState.executeShutdownStart();
}
@HLEFunction(nid = 0x7853182D, version = 150)
public int sceUtilityGameSharingUpdate(int drawSpeed) {
return gameSharingState.executeUpdate(drawSpeed);
}
@HLEFunction(nid = 0x946963F3, version = 150)
public int sceUtilityGameSharingGetStatus() {
return gameSharingState.executeGetStatus();
}
@HLEFunction(nid = 0x3AD50AE7, version = 150)
public int sceNetplayDialogInitStart(TPointer paramsAddr) {
return netplayDialogState.executeInitStart(paramsAddr);
}
@HLEFunction(nid = 0xBC6B6296, version = 150)
public int sceNetplayDialogShutdownStart() {
return netplayDialogState.executeShutdownStart();
}
@HLEFunction(nid = 0x417BED54, version = 150)
public int sceNetplayDialogUpdate(int drawSpeed) {
return netplayDialogState.executeUpdate(drawSpeed);
}
@HLEFunction(nid = 0xB6CEE597, version = 150)
public int sceNetplayDialogGetStatus() {
return netplayDialogState.executeGetStatus();
}
@HLEFunction(nid = 0x4DB1E739, version = 150)
public int sceUtilityNetconfInitStart(TPointer paramsAddr) {
return netconfState.executeInitStart(paramsAddr);
}
@HLEFunction(nid = 0xF88155F6, version = 150)
public int sceUtilityNetconfShutdownStart() {
return netconfState.executeShutdownStart();
}
@HLEFunction(nid = 0x91E70E35, version = 150)
public int sceUtilityNetconfUpdate(int drawSpeed) {
return netconfState.executeUpdate(drawSpeed);
}
@HLEFunction(nid = 0x6332AA39, version = 150)
public int sceUtilityNetconfGetStatus() {
return netconfState.executeGetStatus();
}
@HLEFunction(nid = 0x50C4CD57, version = 150)
public int sceUtilitySavedataInitStart(@BufferInfo(lengthInfo=LengthInfo.variableLength, usage=Usage.inout) TPointer paramsAddr) {
return savedataState.executeInitStart(paramsAddr);
}
@HLEFunction(nid = 0x9790B33C, version = 150)
public int sceUtilitySavedataShutdownStart() {
return savedataState.executeShutdownStart();
}
@HLEFunction(nid = 0xD4B95FFB, version = 150)
public int sceUtilitySavedataUpdate(int drawSpeed) {
return savedataState.executeUpdate(drawSpeed);
}
@HLEFunction(nid = 0x8874DBE0, version = 150)
public int sceUtilitySavedataGetStatus() {
return savedataState.executeGetStatus();
}
@HLEFunction(nid = 0x2995D020, version = 150)
public int sceUtilitySavedataErrInitStart(TPointer paramsAddr) {
return savedataErrState.executeInitStart(paramsAddr);
}
@HLEFunction(nid = 0xB62A4061, version = 150)
public int sceUtilitySavedataErrShutdownStart() {
return savedataErrState.executeShutdownStart();
}
@HLEFunction(nid = 0xED0FAD38, version = 150)
public int sceUtilitySavedataErrUpdate(int drawSpeed) {
return savedataErrState.executeUpdate(drawSpeed);
}
@HLEFunction(nid = 0x88BC7406, version = 150)
public int sceUtilitySavedataErrGetStatus() {
return savedataErrState.executeGetStatus();
}
@HLEFunction(nid = 0x2AD8E239, version = 150)
public int sceUtilityMsgDialogInitStart(@BufferInfo(lengthInfo=LengthInfo.variableLength, usage=Usage.inout) TPointer paramsAddr) {
return msgDialogState.executeInitStart(paramsAddr);
}
@HLEFunction(nid = 0x67AF3428, version = 150)
public int sceUtilityMsgDialogShutdownStart() {
return msgDialogState.executeShutdownStart();
}
@HLEFunction(nid = 0x95FC253B, version = 150)
public int sceUtilityMsgDialogUpdate(int drawSpeed) {
return msgDialogState.executeUpdate(drawSpeed);
}
@HLEFunction(nid = 0x9A1C91D7, version = 150)
public int sceUtilityMsgDialogGetStatus() {
return msgDialogState.executeGetStatus();
}
@HLEFunction(nid = 0xF6269B82, version = 150)
public int sceUtilityOskInitStart(@BufferInfo(lengthInfo=LengthInfo.variableLength, usage=Usage.inout) TPointer paramsAddr) {
return oskState.executeInitStart(paramsAddr);
}
@HLEFunction(nid = 0x3DFAEBA9, version = 150)
public int sceUtilityOskShutdownStart() {
return oskState.executeShutdownStart();
}
@HLEFunction(nid = 0x4B85C861, version = 150)
public int sceUtilityOskUpdate(int drawSpeed) {
return oskState.executeUpdate(drawSpeed);
}
@HLEFunction(nid = 0xF3F76017, version = 150)
public int sceUtilityOskGetStatus() {
return oskState.executeGetStatus();
}
@HLEFunction(nid = 0x16D02AF0, version = 150)
public int sceUtilityNpSigninInitStart(TPointer paramsAddr) {
return npSigninState.executeInitStart(paramsAddr);
}
@HLEFunction(nid = 0xE19C97D6, version = 150)
public int sceUtilityNpSigninShutdownStart() {
return npSigninState.executeShutdownStart();
}
@HLEFunction(nid = 0xF3FBC572, version = 150)
public int sceUtilityNpSigninUpdate(int drawSpeed) {
return npSigninState.executeUpdate(drawSpeed);
}
@HLEFunction(nid = 0x86ABDB1B, version = 150)
public int sceUtilityNpSigninGetStatus() {
return npSigninState.executeGetStatus();
}
@HLEFunction(nid = 0x42071A83, version = 150)
public int sceUtilityPS3ScanInitStart(TPointer paramsAddr) {
return PS3ScanState.executeInitStart(paramsAddr);
}
@HLEFunction(nid = 0xD17A0573, version = 150)
public int sceUtilityPS3ScanShutdownStart() {
return PS3ScanState.executeShutdownStart();
}
@HLEFunction(nid = 0xD852CDCE, version = 150)
public int sceUtilityPS3ScanUpdate(int drawSpeed) {
return PS3ScanState.executeUpdate(drawSpeed);
}
@HLEFunction(nid = 0x89317C8F, version = 150)
public int sceUtilityPS3ScanGetStatus() {
return PS3ScanState.executeGetStatus();
}
@HLEFunction(nid = 0x81c44706, version = 150)
public int sceUtilityRssReaderInitStart(TPointer paramsAddr) {
return rssReaderState.executeInitStart(paramsAddr);
}
@HLEUnimplemented
@HLEFunction(nid = 0xB0FB7FF5, version = 150)
public int sceUtilityRssReaderContStart() {
return SceKernelErrors.ERROR_UTILITY_IS_UNKNOWN;
}
@HLEFunction(nid = 0xE7B778D8, version = 150)
public int sceUtilityRssReaderShutdownStart() {
return rssReaderState.executeShutdownStart();
}
@HLEFunction(nid = 0x6F56F9CF, version = 150)
public int sceUtilityRssReaderUpdate(int drawSpeed) {
return rssReaderState.executeUpdate(drawSpeed);
}
@HLEFunction(nid = 0x8326AB05, version = 150)
public int sceUtilityRssReaderGetStatus() {
return rssReaderState.executeGetStatus();
}
@HLEFunction(nid = 0x4B0A8FE5, version = 150)
public int sceUtilityRssSubscriberInitStart(TPointer paramsAddr) {
return rssSubscriberState.executeInitStart(paramsAddr);
}
@HLEFunction(nid = 0x06A48659, version = 150)
public int sceUtilityRssSubscriberShutdownStart() {
return rssSubscriberState.executeShutdownStart();
}
@HLEFunction(nid = 0xA084E056, version = 150)
public int sceUtilityRssSubscriberUpdate(int drawSpeed) {
return rssSubscriberState.executeUpdate(drawSpeed);
}
@HLEFunction(nid = 0x2B96173B, version = 150)
public int sceUtilityRssSubscriberGetStatus() {
return rssSubscriberState.executeGetStatus();
}
@HLEFunction(nid = 0x0251B134, version = 150)
public int sceUtilityScreenshotInitStart(TPointer paramsAddr) {
return screenshotState.executeInitStart(paramsAddr);
}
@HLEFunction(nid = 0x86A03A27, version = 150)
public int sceUtilityScreenshotContStart(TPointer paramsAddr) {
return screenshotState.executeContStart(paramsAddr);
}
@HLEFunction(nid = 0xF9E0008C, version = 150)
public int sceUtilityScreenshotShutdownStart() {
return screenshotState.executeShutdownStart();
}
@HLEFunction(nid = 0xAB083EA9, version = 150)
public int sceUtilityScreenshotUpdate(int drawSpeed) {
return screenshotState.executeUpdate(drawSpeed);
}
@HLEFunction(nid = 0xD81957B7, version = 150)
public int sceUtilityScreenshotGetStatus() {
return screenshotState.executeGetStatus();
}
@HLEFunction(nid = 0xCDC3AA41, version = 150)
public int sceUtilityHtmlViewerInitStart(TPointer paramsAddr) {
return htmlViewerState.executeInitStart(paramsAddr);
}
@HLEFunction(nid = 0xF5CE1134, version = 150)
public int sceUtilityHtmlViewerShutdownStart() {
return htmlViewerState.executeShutdownStart();
}
@HLEFunction(nid = 0x05AFB9E4, version = 150)
public int sceUtilityHtmlViewerUpdate(int drawSpeed) {
return htmlViewerState.executeUpdate(drawSpeed);
}
@HLEFunction(nid = 0xBDA7D894, version = 150)
public int sceUtilityHtmlViewerGetStatus() {
return htmlViewerState.executeGetStatus();
}
@HLEFunction(nid = 0x24AC31EB, version = 150)
public int sceUtilityGamedataInstallInitStart(TPointer paramsAddr) {
return gamedataInstallState.executeInitStart(paramsAddr);
}
@HLEFunction(nid = 0x32E32DCB, version = 150)
public int sceUtilityGamedataInstallShutdownStart() {
return gamedataInstallState.executeShutdownStart();
}
@HLEFunction(nid = 0x4AECD179, version = 150)
public int sceUtilityGamedataInstallUpdate(int drawSpeed) {
return gamedataInstallState.executeUpdate(drawSpeed);
}
@HLEFunction(nid = 0xB57E95D9, version = 150)
public int sceUtilityGamedataInstallGetStatus() {
return gamedataInstallState.executeGetStatus();
}
@HLEFunction(nid = 0x45C18506, version = 150)
public int sceUtilitySetSystemParamInt(int id, int value) {
switch (id) {
case PSP_SYSTEMPARAM_ID_INT_ADHOC_CHANNEL:
if (value != 0 && value != 1 && value != 6 && value != 11) {
return SceKernelErrors.ERROR_UTILITY_INVALID_ADHOC_CHANNEL;
}
Settings.getInstance().writeInt(SYSTEMPARAM_SETTINGS_OPTION_ADHOC_CHANNEL, value);
break;
case PSP_SYSTEMPARAM_ID_INT_WLAN_POWERSAVE:
Settings.getInstance().writeInt(SYSTEMPARAM_SETTINGS_OPTION_WLAN_POWER_SAVE, value);
break;
default:
// PSP can only set above int parameters
return SceKernelErrors.ERROR_UTILITY_INVALID_SYSTEM_PARAM_ID;
}
return 0;
}
@HLELogging(level = "info")
@HLEFunction(nid = 0x41E30674, version = 150)
public int sceUtilitySetSystemParamString(int id, int string) {
// Always return ERROR_UTILITY_INVALID_SYSTEM_PARAM_ID
return SceKernelErrors.ERROR_UTILITY_INVALID_SYSTEM_PARAM_ID;
}
@HLEFunction(nid = 0xA5DA2406, version = 150)
public int sceUtilityGetSystemParamInt(int id, @BufferInfo(usage=Usage.out) TPointer32 valueAddr) {
switch (id) {
case PSP_SYSTEMPARAM_ID_INT_ADHOC_CHANNEL:
valueAddr.setValue(getSystemParamAdhocChannel());
break;
case PSP_SYSTEMPARAM_ID_INT_WLAN_POWERSAVE:
valueAddr.setValue(getSystemParamWlanPowersave());
break;
case PSP_SYSTEMPARAM_ID_INT_DATE_FORMAT:
valueAddr.setValue(getSystemParamDateFormat());
break;
case PSP_SYSTEMPARAM_ID_INT_TIME_FORMAT:
valueAddr.setValue(getSystemParamTimeFormat());
break;
case PSP_SYSTEMPARAM_ID_INT_TIMEZONE:
valueAddr.setValue(getSystemParamTimeZone());
break;
case PSP_SYSTEMPARAM_ID_INT_DAYLIGHTSAVINGS:
valueAddr.setValue(getSystemParamDaylightSavingTime());
break;
case PSP_SYSTEMPARAM_ID_INT_LANGUAGE:
valueAddr.setValue(getSystemParamLanguage());
break;
case PSP_SYSTEMPARAM_ID_INT_BUTTON_PREFERENCE:
valueAddr.setValue(getSystemParamButtonPreference());
break;
case PSP_SYSTEMPARAM_ID_INT_LOCK_PARENTAL_LEVEL:
// This system param ID was introduced somewhere between v5.00 (not available) and v6.20 (available)
if (Emulator.getInstance().getFirmwareVersion() <= 500) {
log.warn(String.format("sceUtilityGetSystemParamInt id=%d, value_addr=%s PSP_SYSTEMPARAM_ID_INT_LOCK_PARENTAL_LEVEL not available in PSP v%d", id, valueAddr, Emulator.getInstance().getFirmwareVersion()));
return SceKernelErrors.ERROR_UTILITY_INVALID_SYSTEM_PARAM_ID;
}
valueAddr.setValue(getSystemParamLockParentalLevel());
break;
default:
log.warn(String.format("sceUtilityGetSystemParamInt id=%d, valueAddr=%s invalid id", id, valueAddr));
return SceKernelErrors.ERROR_UTILITY_INVALID_SYSTEM_PARAM_ID;
}
return 0;
}
@HLEFunction(nid = 0x34B78343, version = 150)
public int sceUtilityGetSystemParamString(int id, TPointer strAddr, int len) {
switch (id) {
case PSP_SYSTEMPARAM_ID_STRING_NICKNAME:
strAddr.setStringNZ(len, getSystemParamNickname());
break;
default:
log.warn(String.format("sceUtilityGetSystemParamString id=%d, strAddr=%s, len=%d invalid id", id, strAddr, len));
return SceKernelErrors.ERROR_UTILITY_INVALID_SYSTEM_PARAM_ID;
}
return 0;
}
/**
* Check existence of a Net Configuration
*
* @param id - id of net Configuration (1 to n)
* @return 0 on success,
*/
@HLEFunction(nid = 0x5EEE6548, version = 150)
public int sceUtilityCheckNetParam(int id) {
boolean available = (id >= 0 && id <= 24);
// We do not return too many entries as some homebrew only support a limited number of entries.
if (id > PSP_NETPARAM_MAX_NUMBER_DUMMY_ENTRIES) {
available = false;
}
return available ? 0 : SceKernelErrors.ERROR_NETPARAM_BAD_NETCONF;
}
/**
* Get Net Configuration Parameter
*
* @param conf - Net Configuration number (1 to n) (0 returns valid but
* seems to be a copy of the last config requested)
* @param param - which parameter to get
* @param data - parameter data
* @return 0 on success,
*/
@HLEFunction(nid = 0x434D4B3A, version = 150)
public int sceUtilityGetNetParam(int id, int param, TPointer data) {
if (id < 0 || id > 24) {
log.warn(String.format("sceUtilityGetNetParam invalid id=%d", id));
return SceKernelErrors.ERROR_NETPARAM_BAD_NETCONF;
}
switch (param) {
case PSP_NETPARAM_NAME:
data.setStringZ(getNetParamName(id));
break;
case PSP_NETPARAM_SSID:
data.setStringZ(sceNetApctl.getSSID());
break;
case PSP_NETPARAM_SECURE:
// 0 is no security.
// 1 is WEP (64bit).
// 2 is WEP (128bit).
// 3 is WPA.
data.setValue32(1);
break;
case PSP_NETPARAM_WEPKEY:
data.setStringZ("XXXXXXXXXXXXXXXXX");
break;
case PSP_NETPARAM_IS_STATIC_IP:
// 0 is DHCP.
// 1 is static.
// 2 is PPPOE.
data.setValue32(1);
break;
case PSP_NETPARAM_IP:
data.setStringZ(sceNetApctl.getLocalHostIP());
break;
case PSP_NETPARAM_NETMASK:
data.setStringZ(sceNetApctl.getSubnetMask());
break;
case PSP_NETPARAM_ROUTE:
data.setStringZ(sceNetApctl.getGateway());
break;
case PSP_NETPARAM_MANUAL_DNS:
// 0 is auto.
// 1 is manual.
data.setValue32(0);
break;
case PSP_NETPARAM_PRIMARYDNS:
data.setStringZ(sceNetApctl.getPrimaryDNS());
break;
case PSP_NETPARAM_SECONDARYDNS:
data.setStringZ(sceNetApctl.getSecondaryDNS());
break;
case PSP_NETPARAM_PROXY_USER:
data.setStringZ("JPCSP"); // Faking.
break;
case PSP_NETPARAM_PROXY_PASS:
data.setStringZ("JPCSP"); // Faking.
break;
case PSP_NETPARAM_USE_PROXY:
// 0 is to not use proxy.
// 1 is to use proxy.
data.setValue32(0);
break;
case PSP_NETPARAM_PROXY_SERVER:
data.setStringZ("dummy_server"); // Faking.
break;
case PSP_NETPARAM_PROXY_PORT:
data.setValue32(0); // Faking.
break;
case PSP_NETPARAM_VERSION:
// 0 is not used.
// 1 is old version.
// 2 is new version.
data.setValue32(2);
break;
case PSP_NETPARAM_UNKNOWN:
data.setValue32(0);
break;
case PSP_NETPARAM_8021X_AUTH_TYPE:
// 0 is none.
// 1 is EAP (MD5).
data.setValue32(0);
break;
case PSP_NETPARAM_8021X_USER:
data.setStringZ("JPCSP"); // Faking.
break;
case PSP_NETPARAM_8021X_PASS:
data.setStringZ("JPCSP"); // Faking.
break;
case PSP_NETPARAM_WPA_TYPE:
// 0 is key in hexadecimal format.
// 1 is key in ASCII format.
data.setValue32(0);
break;
case PSP_NETPARAM_WPA_KEY:
data.setStringZ("XXXXXXXXXXXXXXXXX");
break;
case PSP_NETPARAM_BROWSER:
// 0 is to not start the native browser.
// 1 is to start the native browser.
data.setValue32(0);
break;
case PSP_NETPARAM_WIFI_CONFIG:
// 0 is no config.
// 1 is unknown.
// 2 is Playstation Spot.
// 3 is unknown.
data.setValue32(0);
break;
default:
log.warn(String.format("sceUtilityGetNetParam invalid param %d", param));
return SceKernelErrors.ERROR_NETPARAM_BAD_PARAM;
}
return 0;
}
/**
* Get Current Net Configuration ID
*
* @param idAddr - Address to store the current net ID
* @return 0 on success,
*/
@HLEFunction(nid = 0x4FED24D8, version = 150)
public int sceUtilityGetNetParamLatestID(TPointer32 idAddr) {
// This function is saving the last net param ID and not
// the number of net configurations.
idAddr.setValue(Modules.sceRegModule.getNetworkLatestId());
return 0;
}
@HLEFunction(nid = 0x1579A159, version = 200, checkInsideInterrupt = true)
public int sceUtilityLoadNetModule(int module) {
String moduleName = getNetModuleName(module);
int result = hleUtilityLoadNetModule(module, moduleName);
if (result == SceKernelErrors.ERROR_NET_MODULE_BAD_ID) {
log.info(String.format("IGNORING: sceUtilityLoadNetModule(module=0x%04X) %s", module, moduleName));
Modules.ThreadManForUserModule.hleKernelDelayThread(ModuleMgrForUser.loadHLEModuleDelay, false);
return 0;
}
log.info(String.format("sceUtilityLoadNetModule(module=0x%04X) %s loaded", module, moduleName));
if (result >= 0) {
Modules.ThreadManForUserModule.hleKernelDelayThread(ModuleMgrForUser.loadHLEModuleDelay, false);
}
return result;
}
@HLEFunction(nid = 0x64D50C56, version = 200, checkInsideInterrupt = true)
public int sceUtilityUnloadNetModule(int module) {
String moduleName = getNetModuleName(module);
log.info(String.format("sceUtilityUnloadNetModule(module=0x%04X) %s unloaded", module, moduleName));
return hleUtilityUnloadNetModule(module);
}
@HLEFunction(nid = 0x1281DA8E, version = 200)
public int sceUtilityInstallInitStart(TPointer paramsAddr) {
return installState.executeInitStart(paramsAddr);
}
@HLEFunction(nid = 0x5EF1C24A, version = 200)
public int sceUtilityInstallShutdownStart() {
return installState.executeShutdownStart();
}
@HLEFunction(nid = 0xA03D29BA, version = 200)
public int sceUtilityInstallUpdate(int drawSpeed) {
return installState.executeUpdate(drawSpeed);
}
@HLEFunction(nid = 0xC4700FA3, version = 200)
public int sceUtilityInstallGetStatus() {
return installState.executeGetStatus();
}
@HLEFunction(nid = 0x4928BD96, version = 260)
public int sceUtilityMsgDialogAbort() {
return msgDialogState.executeAbort();
}
@HLELogging(level="info")
@HLEFunction(nid = 0xC629AF26, version = 270, checkInsideInterrupt = true)
public int sceUtilityLoadAvModule(int module) {
String moduleName = getAvModuleName(module);
int result = hleUtilityLoadAvModule(module, moduleName);
if (result == SceKernelErrors.ERROR_AV_MODULE_BAD_ID) {
log.info(String.format("IGNORING: sceUtilityLoadAvModule(module=0x%04X) %s", module, moduleName));
Modules.ThreadManForUserModule.hleKernelDelayThread(ModuleMgrForUser.loadHLEModuleDelay, false);
return 0;
}
if (result >= 0) {
Modules.ThreadManForUserModule.hleKernelDelayThread(ModuleMgrForUser.loadHLEModuleDelay, false);
}
return result;
}
@HLELogging(level="info")
@HLEFunction(nid = 0xF7D8D092, version = 270, checkInsideInterrupt = true)
public int sceUtilityUnloadAvModule(int module) {
return hleUtilityUnloadAvModule(module);
}
@HLELogging(level="info")
@HLEFunction(nid = 0x0D5BC6D2, version = 270, checkInsideInterrupt = true)
public int sceUtilityLoadUsbModule(int module) {
String moduleName = getUsbModuleName(module);
int result = hleUtilityLoadUsbModule(module, moduleName);
if (result == SceKernelErrors.ERROR_AV_MODULE_BAD_ID) {
log.info(String.format("IGNORING: sceUtilityLoadUsbModule(module=0x%04X) %s", module, moduleName));
Modules.ThreadManForUserModule.hleKernelDelayThread(ModuleMgrForUser.loadHLEModuleDelay, false);
return 0;
}
if (result >= 0) {
Modules.ThreadManForUserModule.hleKernelDelayThread(ModuleMgrForUser.loadHLEModuleDelay, false);
}
return result;
}
@HLEFunction(nid = 0x2A2B3DE0, version = 303, checkInsideInterrupt = true)
public int sceUtilityLoadModule(int module) {
if (loadedModules.containsKey(module) || waitingModules.containsKey(module)) { // Module already loaded.
return SceKernelErrors.ERROR_MODULE_ALREADY_LOADED;
} else if ((module == UtilityModule.PSP_MODULE_NET_HTTPSTORAGE.id) && (!loadedModules.containsKey(UtilityModule.PSP_MODULE_NET_HTTP.id))) {
log.error("Library not find");
return SceKernelErrors.ERROR_KERNEL_LIBRARY_NOT_FOUND;
}
int currentThreadID = Modules.ThreadManForUserModule.getCurrentThreadID();
String[] moduleNames = getModuleNames(module);
int result = 0;
for (String moduleName : moduleNames) {
log.info(String.format("Loading: sceUtilityLoadModule(module=0x%04X) %s", module, moduleName));
int loadResult = hleUtilityLoadModule(module, moduleName);
if (loadResult == SceKernelErrors.ERROR_MODULE_BAD_ID) {
log.info(String.format("IGNORING: sceUtilityLoadModule(module=0x%04X) %s", module, moduleName));
} else {
if (loadResult < 0) {
result = loadResult;
}
log.info(String.format("sceUtilityLoadModule(module=0x%04X) %s loaded", module, moduleName));
}
}
if (result >= 0) {
int newCurrentThreadID = Modules.ThreadManForUserModule.getCurrentThreadID();
// Do not delay the current thread if a context switching has already happened,
// the thread is already delayed.
if (currentThreadID == newCurrentThreadID) {
Modules.ThreadManForUserModule.hleKernelDelayThread(currentThreadID, ModuleMgrForUser.loadHLEModuleDelay, false);
}
}
return result;
}
@HLEFunction(nid = 0xE49BFE92, version = 303, checkInsideInterrupt = true)
public int sceUtilityUnloadModule(int module) {
String[] moduleNames = getModuleNames(module);
int result = 0;
for (String moduleName : moduleNames) {
log.info(String.format("sceUtilityUnloadModule(module=0x%04X) %s unloaded", module, moduleName));
int unloadResult = hleUtilityUnloadModule(module);
if (unloadResult < 0) {
result = unloadResult;
}
}
return result;
}
@HLEFunction(nid = 0xDA97F1AA, version = 500)
public int sceUtilityStoreCheckoutInitStart(TPointer paramsAddr) {
return storeCheckoutState.executeInitStart(paramsAddr);
}
@HLEFunction(nid = 0x54A5C62F, version = 500)
public int sceUtilityStoreCheckoutShutdownStart() {
return storeCheckoutState.executeShutdownStart();
}
@HLEFunction(nid = 0xB8592D5F, version = 500)
public int sceUtilityStoreCheckoutUpdate(int drawSpeed) {
return storeCheckoutState.executeUpdate(drawSpeed);
}
@HLEFunction(nid = 0x3AAD51DC, version = 500)
public int sceUtilityStoreCheckoutGetStatus() {
return storeCheckoutState.executeGetStatus();
}
@HLEFunction(nid = 0xA7BB7C67, version = 500)
public int sceUtilityPsnInitStart(TPointer paramsAddr) {
return psnState.executeInitStart(paramsAddr);
}
@HLEFunction(nid = 0xC130D441, version = 500)
public int sceUtilityPsnShutdownStart() {
return psnState.executeShutdownStart();
}
@HLEFunction(nid = 0x0940A1B9, version = 500)
public int sceUtilityPsnUpdate(int drawSpeed) {
return psnState.executeUpdate(drawSpeed);
}
@HLEFunction(nid = 0x094198B8, version = 500)
public int sceUtilityPsnGetStatus() {
return psnState.executeGetStatus();
}
@HLEFunction(nid = 0x180F7B62, version = 600)
public int sceUtilityGamedataInstallAbort() {
return gamedataInstallState.executeAbort();
}
@HLEFunction(nid = 0xECE1D3E5, version = 150)
public int sceUtility_ECE1D3E5_setAuthName(@StringInfo(maxLength = 64) PspString authName) {
Modules.sceRegModule.setAuthName(authName.getString());
return 0;
}
@HLEFunction(nid = 0x28D35634, version = 150)
public int sceUtility_28D35634_getAuthName(TPointer authNameAddr) {
String authName = Modules.sceRegModule.getAuthName();
authNameAddr.setStringNZ(64, authName);
if (log.isDebugEnabled()) {
log.debug(String.format("sceUtility_28D35634_getAuthName returning '%s'", authName));
}
return 0;
}
@HLEUnimplemented
@HLEFunction(nid = 0x70267ADF, version = 150)
public int sceUtility_70267ADF_setAuthKey(@StringInfo(maxLength = 64) PspString authKey) {
Modules.sceRegModule.setAuthKey(authKey.getString());
return 0;
}
@HLEUnimplemented
@HLEFunction(nid = 0xEF3582B2, version = 150)
public int sceUtility_EF3582B2_getAuthKey(TPointer authKeyAddr) {
String authKey = Modules.sceRegModule.getAuthKey();
authKeyAddr.setStringNZ(64, authKey);
if (log.isDebugEnabled()) {
log.debug(String.format("sceUtility_EF3582B2_getAuthKey returning '%s'", authKey));
}
return 0;
}
@HLEFunction(nid = 0x67C2105B, version = 150)
public int sceUtilityGetNetParamInternal(int id, int param, TPointer data) {
return sceUtilityGetNetParam(id, param, data);
}
@HLEFunction(nid = 0x6D77B975, version = 150)
public int sceUtilitySetNetParamLatestID(int id) {
Modules.sceRegModule.setNetworkLatestId(id);
return 0;
}
@HLEUnimplemented
@HLEFunction(nid = 0x5DCBD3C0, version = 150)
public int sceUtility_private_5DCBD3C0() {
// Has no parameters
return 0;
}
@HLEFunction(nid = 0x048BFC46, version = 150)
public int sceUtility_private_048BFC46(PspString libraryName, int unknown1, @CanBeNull TPointer optionAddr) {
String path = utilityPrivateModules.get(libraryName.getString());
if (path == null) {
return -1;
}
SceKernelLMOption lmOption = null;
if (optionAddr.isNotNull()) {
lmOption = new SceKernelLMOption();
lmOption.read(optionAddr);
if (log.isInfoEnabled()) {
log.info(String.format("sceUtility_private_048BFC46 options: %s", lmOption));
}
}
LoadModuleContext loadModuleContext = new LoadModuleContext();
loadModuleContext.fileName = path;
loadModuleContext.lmOption = lmOption;
loadModuleContext.allocMem = true;
return Modules.ModuleMgrForUserModule.hleKernelLoadModule(loadModuleContext);
}
@HLEFunction(nid = 0x78A2FE0C, version = 150)
public int sceUtility_private_78A2FE0C(int uid) {
return Modules.ModuleMgrForUserModule.hleKernelUnloadModule(uid);
}
@HLEUnimplemented
@HLEFunction(nid = 0x031D0944, version = 150)
public int sceUtility_private_031D0944(int unknown) {
return 0;
}
@HLEUnimplemented
@HLEFunction(nid = 0xB9D9C78F, version = 150)
public int sceUtility_private_B9D9C78F(int unknown) {
return 0;
}
@HLEUnimplemented
@HLEFunction(nid = 0x61D0686E, version = 150)
public int sceUtility_netparam_internal_61D0686E(int unknown) {
return 0;
}
@HLEUnimplemented
@HLEFunction(nid = 0x4CB183A4, version = 150)
public int sceUtility_netparam_internal_4CB183A4(int unknown1, int unknown2) {
return 0;
}
@HLEUnimplemented
@HLEFunction(nid = 0x239F260D, version = 150)
public int sceUtility_netparam_internal_239F260D(int type, TPointer value) {
switch (type) {
case 0:
String configurationName = value.getStringZ();
if (log.isDebugEnabled()) {
log.debug(String.format("sceUtility_netparam_internal_239F260D configurationName='%s'", configurationName));
}
break;
case 1:
String ssid = value.getStringZ();
if (log.isDebugEnabled()) {
log.debug(String.format("sceUtility_netparam_internal_239F260D SSID='%s'", ssid));
}
break;
case 2:
int security = value.getValue32(); // One of PSP_NET_APCTL_INFO_SECURITY_TYPE_*
if (log.isDebugEnabled()) {
log.debug(String.format("sceUtility_netparam_internal_239F260D security=%d", security));
}
break;
case 3:
case 4:
case 8:
case 13:
case 17:
case 21:
case 23:
case 24:
case 25:
case 26:
case 27:
case 29:
case 30:
case 31:
// ?
if (log.isDebugEnabled()) {
log.debug(String.format("sceUtility_netparam_internal_239F260D unknown value: %s", Utilities.getMemoryDump(value.getAddress(), 16)));
}
break;
case 22:
String wepKey = value.getStringZ();
if (log.isDebugEnabled()) {
log.debug(String.format("sceUtility_netparam_internal_239F260D wepKey='%s'", wepKey));
}
break;
}
return 0;
}
}