static void __CheatStart() { __CheatStop(); gameTitle = g_paramSFO.GetValueString("DISC_ID"); activeCheatFile = GetSysDirectory(DIRECTORY_CHEATS) + gameTitle + ".ini"; File::CreateFullPath(GetSysDirectory(DIRECTORY_CHEATS)); if (!File::Exists(activeCheatFile)) { FILE *f = File::OpenCFile(activeCheatFile, "wb"); if (f) { fwrite("\xEF\xBB\xBF", 1, 3, f); fclose(f); } if (!File::Exists(activeCheatFile)) { I18NCategory *err = GetI18NCategory("Error"); osm.Show(err->T("Unable to create cheat file, disk may be full")); } } cheatEngine = new CWCheatEngine(); cheatEngine->CreateCodeList(); g_Config.bReloadCheats = false; cheatsEnabled = true; }
std::string GetThemeDir(const std::string& theme_name) { std::string dir = File::GetUserPath(D_THEMES_IDX) + theme_name + "/"; if (Exists(dir)) return dir; // If the theme doesn't exist in the user dir, load from shared directory dir = GetSysDirectory() + THEMES_DIR "/" + theme_name + "/"; if (Exists(dir)) return dir; // If the theme doesn't exist at all, load the default theme return GetSysDirectory() + THEMES_DIR "/" DEFAULT_THEME_DIR "/"; }
void CWCheatEngine::CreateCheatFile() { activeCheatFile = GetSysDirectory(DIRECTORY_CHEATS) + gameTitle + ".ini"; File::CreateFullPath(GetSysDirectory(DIRECTORY_CHEATS)); if (!File::Exists(activeCheatFile)) { FILE *f = File::OpenCFile(activeCheatFile, "wb"); if (f) { fwrite("\xEF\xBB\xBF\n", 1, 4, f); fclose(f); } if (!File::Exists(activeCheatFile)) { I18NCategory *err = GetI18NCategory("Error"); host->NotifyUserMessage(err->T("Unable to create cheat file, disk may be full")); } } }
static void __CheatStart() { __CheatStop(); gameTitle = g_paramSFO.GetValueString("DISC_ID"); activeCheatFile = GetSysDirectory(DIRECTORY_CHEATS) + gameTitle + ".ini"; File::CreateFullPath(GetSysDirectory(DIRECTORY_CHEATS)); if (!File::Exists(activeCheatFile)) { File::CreateEmptyFile(activeCheatFile); } cheatEngine = new CWCheatEngine(); cheatEngine->CreateCodeList(); g_Config.bReloadCheats = false; cheatsEnabled = true; }
u32 DiskCachingFileLoaderCache::CountCachedFiles() { std::string dir = cacheDir_; if (dir.empty()) { dir = GetSysDirectory(DIRECTORY_CACHE); } std::vector<FileInfo> files; return (u32)getFilesInDir(dir.c_str(), &files, "ppdc:"); }
std::string GetThemeDir(const std::string& theme_name) { std::string dir = File::GetUserPath(D_THEMES_IDX) + theme_name + "/"; // If theme does not exist in user's dir load from shared directory if (!File::Exists(dir)) dir = GetSysDirectory() + THEMES_DIR "/" + theme_name + "/"; return dir; }
std::string DiskCachingFileLoaderCache::MakeCacheFilePath(const std::string &path) { std::string dir = cacheDir_; if (dir.empty()) { dir = GetSysDirectory(DIRECTORY_CACHE); } if (!File::Exists(dir)) { File::CreateFullPath(dir); } return dir + "/" + MakeCacheFilename(path); }
u64 DiskCachingFileLoaderCache::FreeDiskSpace() { std::string dir = cacheDir_; if (dir.empty()) { dir = GetSysDirectory(DIRECTORY_CACHE); } uint64_t result = 0; if (free_disk_space(dir, result)) { return result; } // We can't know for sure how much is free, so we have to assume none. return 0; }
std::vector<std::string> GameInfo::GetSaveDataDirectories() { std::string memc = GetSysDirectory(DIRECTORY_SAVEDATA); std::vector<FileInfo> dirs; getFilesInDir(memc.c_str(), &dirs); std::vector<std::string> directories; for (size_t i = 0; i < dirs.size(); i++) { if (startsWith(dirs[i].name, id)) { directories.push_back(dirs[i].fullName); } } return directories; }
void DiskCachingFileLoaderCache::GarbageCollectCacheFiles(u64 goalBytes) { // We attempt to free up at least enough files from the cache to get goalBytes more space. const std::vector<std::string> usedPaths = DiskCachingFileLoader::GetCachedPathsInUse(); std::set<std::string> used; for (std::string path : usedPaths) { used.insert(MakeCacheFilename(path)); } std::string dir = cacheDir_; if (dir.empty()) { dir = GetSysDirectory(DIRECTORY_CACHE); } std::vector<FileInfo> files; getFilesInDir(dir.c_str(), &files, "ppdc:"); u64 remaining = goalBytes; // TODO: Could order by LRU or etc. for (FileInfo file : files) { if (file.isDirectory) { continue; } if (used.find(file.name) != used.end()) { // In use, must leave alone. continue; } #ifdef _WIN32 const std::wstring w32path = ConvertUTF8ToWString(file.fullName); bool success = DeleteFileW(w32path.c_str()) != 0; #else bool success = unlink(file.fullName.c_str()) == 0; #endif if (success) { if (file.size > remaining) { // We're done, huzzah. break; } // A little bit more. remaining -= file.size; } } // At this point, we've done all we can. }
void TextureReplacer::NotifyConfigChanged() { gameID_ = g_paramSFO.GetValueString("DISC_ID"); enabled_ = !gameID_.empty() && (g_Config.bReplaceTextures || g_Config.bSaveNewTextures); if (enabled_) { basePath_ = GetSysDirectory(DIRECTORY_TEXTURES) + gameID_ + "/"; // If we're saving, auto-create the directory. if (g_Config.bSaveNewTextures && !File::Exists(basePath_ + NEW_TEXTURE_DIR)) { File::CreateFullPath(basePath_ + NEW_TEXTURE_DIR); } enabled_ = File::Exists(basePath_) && File::IsDirectory(basePath_); } if (enabled_) { enabled_ = LoadIni(); } }
void Compatibility::Load(const std::string &gameID) { Clear(); { IniFile compat; // This loads from assets. if (compat.LoadFromVFS("compat.ini")) { CheckSettings(compat, gameID); } } { IniFile compat2; // This one is user-editable. Need to load it after the system one. std::string path = GetSysDirectory(DIRECTORY_SYSTEM) + "compat.ini"; if (compat2.Load(path)) { CheckSettings(compat2, gameID); } } }
bool GameManager::Uninstall(std::string name) { if (name.empty()) { ERROR_LOG(HLE, "Cannot remove an empty-named game"); return false; } std::string gameDir = GetSysDirectory(DIRECTORY_GAME) + name; INFO_LOG(HLE, "Deleting %s", gameDir.c_str()); if (!File::Exists(gameDir)) { ERROR_LOG(HLE, "Game %s not installed, cannot uninstall", name.c_str()); return false; } bool success = File::DeleteDirRecursively(gameDir); if (success) { INFO_LOG(HLE, "Successfully deleted game %s", name.c_str()); g_Config.CleanRecent(); return true; } else { ERROR_LOG(HLE, "Failed to delete game %s", name.c_str()); return false; } }
// Run this at startup time. Please use GetSysDirectory if you need to query where folders are. void InitSysDirectories() { if (!g_Config.memCardDirectory.empty() && !g_Config.flash0Directory.empty()) return; const std::string path = ConvertWStringToUTF8(File::GetExeDirectory()); // Mount a filesystem g_Config.flash0Directory = path + "/flash0/"; // Detect the "My Documents"(XP) or "Documents"(on Vista/7/8) folder. wchar_t myDocumentsPath[MAX_PATH]; const HRESULT result = SHGetFolderPath(NULL, CSIDL_PERSONAL, NULL, SHGFP_TYPE_CURRENT, myDocumentsPath); const std::string myDocsPath = ConvertWStringToUTF8(myDocumentsPath) + "/PPSSPP/"; const std::string installedFile = path + "/installed.txt"; const bool installed = File::Exists(installedFile); // If installed.txt exists(and we can determine the Documents directory) if (installed && (result == S_OK)) { std::ifstream inputFile(ConvertUTF8ToWString(installedFile)); if (!inputFile.fail() && inputFile.is_open()) { std::string tempString; std::getline(inputFile, tempString); // Skip UTF-8 encoding bytes if there are any. There are 3 of them. if (tempString.substr(0, 3) == "\xEF\xBB\xBF") tempString = tempString.substr(3); g_Config.memCardDirectory = tempString; } inputFile.close(); // Check if the file is empty first, before appending the slash. if (g_Config.memCardDirectory.empty()) g_Config.memCardDirectory = myDocsPath; size_t lastSlash = g_Config.memCardDirectory.find_last_of("/"); if (lastSlash != (g_Config.memCardDirectory.length() - 1)) g_Config.memCardDirectory.append("/"); } else { g_Config.memCardDirectory = path + "/memstick/"; } // Create the memstickpath before trying to write to it, and fall back on Documents yet again // if we can't make it. if (!File::Exists(g_Config.memCardDirectory)) { if (!File::CreateDir(g_Config.memCardDirectory)) g_Config.memCardDirectory = myDocsPath; } const std::string testFile = "/_writable_test.$$$"; // If any directory is read-only, fall back to the Documents directory. // We're screwed anyway if we can't write to Documents, or can't detect it. if (!File::CreateEmptyFile(g_Config.memCardDirectory + testFile)) g_Config.memCardDirectory = myDocsPath; // Clean up our mess. if (File::Exists(g_Config.memCardDirectory + testFile)) File::Delete(g_Config.memCardDirectory + testFile); if (g_Config.currentDirectory.empty()) { g_Config.currentDirectory = GetSysDirectory(DIRECTORY_GAME); } }
GPU_Vulkan::GPU_Vulkan(GraphicsContext *gfxCtx, Draw::DrawContext *draw) : GPUCommon(gfxCtx, draw), vulkan_((VulkanContext *)gfxCtx->GetAPIContext()), drawEngine_(vulkan_, draw), depalShaderCache_(draw, vulkan_), vulkan2D_(vulkan_) { UpdateVsyncInterval(true); CheckGPUFeatures(); shaderManagerVulkan_ = new ShaderManagerVulkan(vulkan_); pipelineManager_ = new PipelineManagerVulkan(vulkan_); framebufferManagerVulkan_ = new FramebufferManagerVulkan(draw, vulkan_); framebufferManager_ = framebufferManagerVulkan_; textureCacheVulkan_ = new TextureCacheVulkan(draw, vulkan_); textureCache_ = textureCacheVulkan_; drawEngineCommon_ = &drawEngine_; shaderManager_ = shaderManagerVulkan_; drawEngine_.SetTextureCache(textureCacheVulkan_); drawEngine_.SetFramebufferManager(framebufferManagerVulkan_); drawEngine_.SetShaderManager(shaderManagerVulkan_); drawEngine_.SetPipelineManager(pipelineManager_); framebufferManagerVulkan_->SetVulkan2D(&vulkan2D_); framebufferManagerVulkan_->Init(); framebufferManagerVulkan_->SetTextureCache(textureCacheVulkan_); framebufferManagerVulkan_->SetDrawEngine(&drawEngine_); framebufferManagerVulkan_->SetShaderManager(shaderManagerVulkan_); textureCacheVulkan_->SetDepalShaderCache(&depalShaderCache_); textureCacheVulkan_->SetFramebufferManager(framebufferManagerVulkan_); textureCacheVulkan_->SetShaderManager(shaderManagerVulkan_); textureCacheVulkan_->SetDrawEngine(&drawEngine_); textureCacheVulkan_->SetVulkan2D(&vulkan2D_); InitDeviceObjects(); // Sanity check gstate if ((int *)&gstate.transferstart - (int *)&gstate != 0xEA) { ERROR_LOG(G3D, "gstate has drifted out of sync!"); } BuildReportingInfo(); // Update again after init to be sure of any silly driver problems. UpdateVsyncInterval(true); textureCacheVulkan_->NotifyConfigChanged(); if (vulkan_->GetFeaturesEnabled().wideLines) { drawEngine_.SetLineWidth(PSP_CoreParameter().renderWidth / 480.0f); } // Load shader cache. std::string discID = g_paramSFO.GetDiscID(); if (discID.size()) { File::CreateFullPath(GetSysDirectory(DIRECTORY_APP_CACHE)); shaderCachePath_ = GetSysDirectory(DIRECTORY_APP_CACHE) + "/" + discID + ".vkshadercache"; shaderCacheLoaded_ = false; std::thread th([&] { LoadCache(shaderCachePath_); shaderCacheLoaded_ = true; }); th.detach(); } }
int WINAPI WinMain(HINSTANCE _hInstance, HINSTANCE hPrevInstance, LPSTR szCmdLine, int iCmdShow) { setCurrentThreadName("Main"); // Windows Vista and above: alert Windows that PPSSPP is DPI aware, // so that we don't flicker in fullscreen on some PCs. MakePPSSPPDPIAware(); // FMA3 support in the 2013 CRT is broken on Vista and Windows 7 RTM (fixed in SP1). Just disable it. #ifdef _M_X64 _set_FMA3_enable(0); #endif EnableCrashingOnCrashes(); wchar_t modulePath[MAX_PATH]; GetModuleFileName(NULL, modulePath, MAX_PATH); for (size_t i = wcslen(modulePath) - 1; i > 0; i--) { if (modulePath[i] == '\\') { modulePath[i] = 0; break; } } SetCurrentDirectory(modulePath); // GetCurrentDirectory(MAX_PATH, modulePath); // for checking in the debugger #ifndef _DEBUG bool showLog = false; #else bool showLog = false; #endif VFSRegister("", new DirectoryAssetReader("assets/")); VFSRegister("", new DirectoryAssetReader("")); wchar_t lcCountry[256]; // LOCALE_SNAME is only available in WinVista+ // Really should find a way to do this in XP too :/ if (0 != GetLocaleInfo(LOCALE_NAME_USER_DEFAULT, LOCALE_SNAME, lcCountry, 256)) { langRegion = ConvertWStringToUTF8(lcCountry); for (size_t i = 0; i < langRegion.size(); i++) { if (langRegion[i] == '-') langRegion[i] = '_'; } } else { langRegion = "en_US"; } osName = GetWindowsVersion() + " " + GetWindowsSystemArchitecture(); const char *configFilename = NULL; const char *configOption = "--config="; const char *controlsConfigFilename = NULL; const char *controlsOption = "--controlconfig="; for (int i = 1; i < __argc; ++i) { if (__argv[i][0] == '\0') continue; if (__argv[i][0] == '-') { if (!strncmp(__argv[i], configOption, strlen(configOption)) && strlen(__argv[i]) > strlen(configOption)) { configFilename = __argv[i] + strlen(configOption); } if (!strncmp(__argv[i], controlsOption, strlen(controlsOption)) && strlen(__argv[i]) > strlen(controlsOption)) { controlsConfigFilename = __argv[i] + strlen(controlsOption); } } } // On Win32 it makes more sense to initialize the system directories here // because the next place it was called was in the EmuThread, and it's too late by then. InitSysDirectories(); // Load config up here, because those changes below would be overwritten // if it's not loaded here first. g_Config.AddSearchPath(""); g_Config.AddSearchPath(GetSysDirectory(DIRECTORY_SYSTEM)); g_Config.SetDefaultPath(GetSysDirectory(DIRECTORY_SYSTEM)); g_Config.Load(configFilename, controlsConfigFilename); bool debugLogLevel = false; // The rest is handled in NativeInit(). for (int i = 1; i < __argc; ++i) { if (__argv[i][0] == '\0') continue; if (__argv[i][0] == '-') { switch (__argv[i][1]) { case 'l': showLog = true; g_Config.bEnableLogging = true; break; case 's': g_Config.bAutoRun = false; g_Config.bSaveSettings = false; break; case 'd': debugLogLevel = true; break; } if (!strncmp(__argv[i], "--fullscreen", strlen("--fullscreen"))) g_Config.bFullScreen = true; if (!strncmp(__argv[i], "--windowed", strlen("--windowed"))) g_Config.bFullScreen = false; } } #ifdef _DEBUG g_Config.bEnableLogging = true; #endif LogManager::Init(); // Consider at least the following cases before changing this code: // - By default in Release, the console should be hidden by default even if logging is enabled. // - By default in Debug, the console should be shown by default. // - The -l switch is expected to show the log console, REGARDLESS of config settings. // - It should be possible to log to a file without showing the console. LogManager::GetInstance()->GetConsoleListener()->Init(showLog, 150, 120, "PPSSPP Debug Console"); if (debugLogLevel) LogManager::GetInstance()->SetAllLogLevels(LogTypes::LDEBUG); //Windows, API init stuff INITCOMMONCONTROLSEX comm; comm.dwSize = sizeof(comm); comm.dwICC = ICC_BAR_CLASSES | ICC_LISTVIEW_CLASSES | ICC_TAB_CLASSES; InitCommonControlsEx(&comm); timeBeginPeriod(1); MainWindow::Init(_hInstance); g_hPopupMenus = LoadMenu(_hInstance, (LPCWSTR)IDR_POPUPMENUS); MainWindow::Show(_hInstance, iCmdShow); HWND hwndMain = MainWindow::GetHWND(); HWND hwndDisplay = MainWindow::GetDisplayHWND(); //initialize custom controls CtrlDisAsmView::init(); CtrlMemView::init(); CtrlRegisterList::init(); CGEDebugger::Init(); DialogManager::AddDlg(vfpudlg = new CVFPUDlg(_hInstance, hwndMain, currentDebugMIPS)); host = new WindowsHost(hwndMain, hwndDisplay); host->SetWindowTitle(0); MainWindow::CreateDebugWindows(); // Emu thread is always running! EmuThread_Start(); InputDevice::BeginPolling(); HACCEL hAccelTable = LoadAccelerators(_hInstance, (LPCTSTR)IDR_ACCELS); HACCEL hDebugAccelTable = LoadAccelerators(_hInstance, (LPCTSTR)IDR_DEBUGACCELS); //so.. we're at the message pump of the GUI thread for (MSG msg; GetMessage(&msg, NULL, 0, 0); ) // for no quit { if (msg.message == WM_KEYDOWN) { //hack to enable/disable menu command accelerate keys MainWindow::UpdateCommands(); //hack to make it possible to get to main window from floating windows with Esc if (msg.hwnd != hwndMain && msg.wParam == VK_ESCAPE) BringWindowToTop(hwndMain); } //Translate accelerators and dialog messages... HWND wnd; HACCEL accel; switch (g_activeWindow) { case WINDOW_MAINWINDOW: wnd = hwndMain; accel = hAccelTable; break; case WINDOW_CPUDEBUGGER: wnd = disasmWindow[0] ? disasmWindow[0]->GetDlgHandle() : 0; accel = hDebugAccelTable; break; case WINDOW_GEDEBUGGER: default: wnd = 0; accel = 0; break; } if (!TranslateAccelerator(wnd, accel, &msg)) { if (!DialogManager::IsDialogMessage(&msg)) { //and finally translate and dispatch TranslateMessage(&msg); DispatchMessage(&msg); } } } VFSShutdown(); InputDevice::StopPolling(); EmuThread_Stop(); MainWindow::DestroyDebugWindows(); DialogManager::DestroyAll(); timeEndPeriod(1); delete host; g_Config.Save(); LogManager::Shutdown(); return 0; }
int WINAPI WinMain(HINSTANCE _hInstance, HINSTANCE hPrevInstance, LPSTR szCmdLine, int iCmdShow) { setCurrentThreadName("Main"); CoInitializeEx(NULL, COINIT_MULTITHREADED); #ifdef _DEBUG _CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF); #endif PROFILE_INIT(); #if defined(_M_X64) && defined(_MSC_VER) && _MSC_VER < 1900 // FMA3 support in the 2013 CRT is broken on Vista and Windows 7 RTM (fixed in SP1). Just disable it. _set_FMA3_enable(0); #endif EnableCrashingOnCrashes(); #ifndef _DEBUG bool showLog = false; #else bool showLog = true; #endif const std::string &exePath = File::GetExeDirectory(); VFSRegister("", new DirectoryAssetReader((exePath + "/assets/").c_str())); VFSRegister("", new DirectoryAssetReader(exePath.c_str())); langRegion = GetDefaultLangRegion(); osName = GetWindowsVersion() + " " + GetWindowsSystemArchitecture(); char configFilename[MAX_PATH] = { 0 }; const std::wstring configOption = L"--config="; char controlsConfigFilename[MAX_PATH] = { 0 }; const std::wstring controlsOption = L"--controlconfig="; std::vector<std::wstring> wideArgs = GetWideCmdLine(); for (size_t i = 1; i < wideArgs.size(); ++i) { if (wideArgs[i][0] == L'\0') continue; if (wideArgs[i][0] == L'-') { if (wideArgs[i].find(configOption) != std::wstring::npos && wideArgs[i].size() > configOption.size()) { const std::wstring tempWide = wideArgs[i].substr(configOption.size()); const std::string tempStr = ConvertWStringToUTF8(tempWide); std::strncpy(configFilename, tempStr.c_str(), MAX_PATH); } if (wideArgs[i].find(controlsOption) != std::wstring::npos && wideArgs[i].size() > controlsOption.size()) { const std::wstring tempWide = wideArgs[i].substr(controlsOption.size()); const std::string tempStr = ConvertWStringToUTF8(tempWide); std::strncpy(controlsConfigFilename, tempStr.c_str(), MAX_PATH); } } } // On Win32 it makes more sense to initialize the system directories here // because the next place it was called was in the EmuThread, and it's too late by then. InitSysDirectories(); // Load config up here, because those changes below would be overwritten // if it's not loaded here first. g_Config.AddSearchPath(""); g_Config.AddSearchPath(GetSysDirectory(DIRECTORY_SYSTEM)); g_Config.SetDefaultPath(GetSysDirectory(DIRECTORY_SYSTEM)); g_Config.Load(configFilename, controlsConfigFilename); bool debugLogLevel = false; const std::wstring gpuBackend = L"--graphics="; // The rest is handled in NativeInit(). for (size_t i = 1; i < wideArgs.size(); ++i) { if (wideArgs[i][0] == L'\0') continue; if (wideArgs[i][0] == L'-') { switch (wideArgs[i][1]) { case L'l': showLog = true; g_Config.bEnableLogging = true; break; case L's': g_Config.bAutoRun = false; g_Config.bSaveSettings = false; break; case L'd': debugLogLevel = true; break; } if (wideArgs[i] == L"--fullscreen") g_Config.bFullScreen = true; if (wideArgs[i] == L"--windowed") g_Config.bFullScreen = false; if (wideArgs[i].find(gpuBackend) != std::wstring::npos && wideArgs[i].size() > gpuBackend.size()) { const std::wstring restOfOption = wideArgs[i].substr(gpuBackend.size()); // Force software rendering off, as picking directx9 or gles implies HW acceleration. // Once software rendering supports Direct3D9/11, we can add more options for software, // such as "software-gles", "software-d3d9", and "software-d3d11", or something similar. // For now, software rendering force-activates OpenGL. if (restOfOption == L"directx9") { g_Config.iGPUBackend = GPU_BACKEND_DIRECT3D9; g_Config.bSoftwareRendering = false; } else if (restOfOption == L"gles") { g_Config.iGPUBackend = GPU_BACKEND_OPENGL; g_Config.bSoftwareRendering = false; } else if (restOfOption == L"software") { g_Config.iGPUBackend = GPU_BACKEND_OPENGL; g_Config.bSoftwareRendering = true; } } } } #ifdef _DEBUG g_Config.bEnableLogging = true; #endif if (iCmdShow == SW_MAXIMIZE) { // Consider this to mean --fullscreen. g_Config.bFullScreen = true; } LogManager::Init(); // Consider at least the following cases before changing this code: // - By default in Release, the console should be hidden by default even if logging is enabled. // - By default in Debug, the console should be shown by default. // - The -l switch is expected to show the log console, REGARDLESS of config settings. // - It should be possible to log to a file without showing the console. LogManager::GetInstance()->GetConsoleListener()->Init(showLog, 150, 120, "PPSSPP Debug Console"); if (debugLogLevel) LogManager::GetInstance()->SetAllLogLevels(LogTypes::LDEBUG); //Windows, API init stuff INITCOMMONCONTROLSEX comm; comm.dwSize = sizeof(comm); comm.dwICC = ICC_BAR_CLASSES | ICC_LISTVIEW_CLASSES | ICC_TAB_CLASSES; InitCommonControlsEx(&comm); timeBeginPeriod(1); MainWindow::Init(_hInstance); g_hPopupMenus = LoadMenu(_hInstance, (LPCWSTR)IDR_POPUPMENUS); MainWindow::Show(_hInstance); HWND hwndMain = MainWindow::GetHWND(); HWND hwndDisplay = MainWindow::GetDisplayHWND(); //initialize custom controls CtrlDisAsmView::init(); CtrlMemView::init(); CtrlRegisterList::init(); CGEDebugger::Init(); DialogManager::AddDlg(vfpudlg = new CVFPUDlg(_hInstance, hwndMain, currentDebugMIPS)); host = new WindowsHost(_hInstance, hwndMain, hwndDisplay); host->SetWindowTitle(0); MainWindow::CreateDebugWindows(); const bool minimized = iCmdShow == SW_MINIMIZE || iCmdShow == SW_SHOWMINIMIZED || iCmdShow == SW_SHOWMINNOACTIVE; if (minimized) { MainWindow::Minimize(); } // Emu thread is always running! EmuThread_Start(); InputDevice::BeginPolling(); HACCEL hAccelTable = LoadAccelerators(_hInstance, (LPCTSTR)IDR_ACCELS); HACCEL hDebugAccelTable = LoadAccelerators(_hInstance, (LPCTSTR)IDR_DEBUGACCELS); //so.. we're at the message pump of the GUI thread for (MSG msg; GetMessage(&msg, NULL, 0, 0); ) // for no quit { if (msg.message == WM_KEYDOWN) { //hack to enable/disable menu command accelerate keys MainWindow::UpdateCommands(); //hack to make it possible to get to main window from floating windows with Esc if (msg.hwnd != hwndMain && msg.wParam == VK_ESCAPE) BringWindowToTop(hwndMain); } //Translate accelerators and dialog messages... HWND wnd; HACCEL accel; switch (g_activeWindow) { case WINDOW_MAINWINDOW: wnd = hwndMain; accel = hAccelTable; break; case WINDOW_CPUDEBUGGER: wnd = disasmWindow[0] ? disasmWindow[0]->GetDlgHandle() : 0; accel = hDebugAccelTable; break; case WINDOW_GEDEBUGGER: default: wnd = 0; accel = 0; break; } if (!TranslateAccelerator(wnd, accel, &msg)) { if (!DialogManager::IsDialogMessage(&msg)) { //and finally translate and dispatch TranslateMessage(&msg); DispatchMessage(&msg); } } } VFSShutdown(); InputDevice::StopPolling(); EmuThread_Stop(); MainWindow::DestroyDebugWindows(); DialogManager::DestroyAll(); timeEndPeriod(1); delete host; g_Config.Save(); LogManager::Shutdown(); if (g_Config.bRestartRequired) { W32Util::ExitAndRestart(); } CoUninitialize(); return 0; }
bool GameManager::IsGameInstalled(std::string name) { std::string pspGame = GetSysDirectory(DIRECTORY_GAME); return File::Exists(pspGame + name); }
bool GameManager::InstallGame(std::string zipfile, bool deleteAfter) { if (installInProgress_) { ERROR_LOG(HLE, "Cannot have two installs in progress at the same time"); return false; } installInProgress_ = true; std::string pspGame = GetSysDirectory(DIRECTORY_GAME); INFO_LOG(HLE, "Installing %s into %s", zipfile.c_str(), pspGame.c_str()); if (!File::Exists(zipfile)) { ERROR_LOG(HLE, "ZIP file %s doesn't exist", zipfile.c_str()); return false; } int error; #ifdef _WIN32 struct zip *z = zip_open(ConvertUTF8ToWString(zipfile).c_str(), 0, &error); #elif defined(__SYMBIAN32__) // If zipfile is non-ascii, this may not function correctly. Other options? struct zip *z = zip_open(std::wstring(zipfile.begin(), zipfile.end()).c_str(), 0, &error); #else struct zip *z = zip_open(zipfile.c_str(), 0, &error); #endif if (!z) { ERROR_LOG(HLE, "Failed to open ZIP file %s, error code=%i", zipfile.c_str(), error); return false; } int numFiles = zip_get_num_files(z); // First, find all the directories, and precreate them before we fill in with files. // Also, verify that this is a PSP zip file with the correct layout. bool isPSP = false; int stripChars = 0; for (int i = 0; i < numFiles; i++) { const char *fn = zip_get_name(z, i, 0); std::string zippedName = fn; if (zippedName.find("EBOOT.PBP") != std::string::npos) { int slashCount = 0; int lastSlashLocation = -1; int slashLocation = -1; for (size_t i = 0; i < zippedName.size(); i++) { if (zippedName[i] == '/') { slashCount++; slashLocation = lastSlashLocation; lastSlashLocation = i; } } if (slashCount >= 1 && (!isPSP || slashLocation < stripChars + 1)) { stripChars = slashLocation + 1; isPSP = true; } else { INFO_LOG(HLE, "Wrong number of slashes (%i) in %s", slashCount, zippedName.c_str()); } } } if (!isPSP) { ERROR_LOG(HLE, "File not a PSP game, no EBOOT.PBP found."); return false; } size_t allBytes = 0, bytesCopied = 0; // Create all the directories in one pass std::set<std::string> createdDirs; for (int i = 0; i < numFiles; i++) { const char *fn = zip_get_name(z, i, 0); std::string zippedName = fn; std::string outFilename = pspGame + zippedName.substr(stripChars); bool isDir = *outFilename.rbegin() == '/'; if (!isDir && outFilename.find("/") != std::string::npos) { outFilename = outFilename.substr(0, outFilename.rfind('/')); } if (createdDirs.find(outFilename) == createdDirs.end()) { File::CreateFullPath(outFilename.c_str()); createdDirs.insert(outFilename); } if (!isDir) { struct zip_stat zstat; if (zip_stat_index(z, i, 0, &zstat) >= 0) { allBytes += zstat.size; } } } // Now, loop through again in a second pass, writing files. for (int i = 0; i < numFiles; i++) { const char *fn = zip_get_name(z, i, 0); // Note that we do NOT write files that are not in a directory, to avoid random // README files etc. if (strstr(fn, "/") != 0) { struct zip_stat zstat; zip_stat_index(z, i, 0, &zstat); size_t size = zstat.size; fn += stripChars; std::string outFilename = pspGame + fn; bool isDir = *outFilename.rbegin() == '/'; if (isDir) continue; if (i < 10) { INFO_LOG(HLE, "Writing %i bytes to %s", (int)size, outFilename.c_str()); } zip_file *zf = zip_fopen_index(z, i, 0); FILE *f = fopen(outFilename.c_str(), "wb"); if (f) { size_t pos = 0; const size_t blockSize = 1024 * 128; u8 *buffer = new u8[blockSize]; while (pos < size) { size_t bs = std::min(blockSize, pos - size); zip_fread(zf, buffer, bs); size_t written = fwrite(buffer, 1, bs, f); if (written != bs) { ERROR_LOG(HLE, "Wrote %i bytes out of %i - Disk full?", (int)written, (int)bs); // TODO: What do we do? } pos += bs; bytesCopied += bs; installProgress_ = (float)bytesCopied / (float)allBytes; // printf("Progress: %f\n", installProgress_); } zip_fclose(zf); fclose(f); delete [] buffer; } else { ERROR_LOG(HLE, "Failed to open file for writing"); } } } INFO_LOG(HLE, "Extracted %i files (%i bytes).", numFiles, (int)bytesCopied); zip_close(z); installProgress_ = 1.0f; installInProgress_ = false; if (deleteAfter) { deleteFile(zipfile.c_str()); } InstallDone(); return true; }
// Run this at startup time. Please use GetSysDirectory if you need to query where folders are. void InitSysDirectories() { if (!g_Config.memStickDirectory.empty() && !g_Config.flash0Directory.empty()) return; const std::string path = File::GetExeDirectory(); // Mount a filesystem g_Config.flash0Directory = path + "flash0/"; // Detect the "My Documents"(XP) or "Documents"(on Vista/7/8) folder. #if PPSSPP_PLATFORM(UWP) const std::string myDocsPath = ""; // TODO UWP const HRESULT result = E_FAIL; #else wchar_t myDocumentsPath[MAX_PATH]; const HRESULT result = SHGetFolderPath(NULL, CSIDL_PERSONAL, NULL, SHGFP_TYPE_CURRENT, myDocumentsPath); const std::string myDocsPath = ConvertWStringToUTF8(myDocumentsPath) + "/PPSSPP/"; #endif const std::string installedFile = path + "installed.txt"; const bool installed = File::Exists(installedFile); // If installed.txt exists(and we can determine the Documents directory) if (installed && (result == S_OK)) { std::ifstream inputFile(ConvertUTF8ToWString(installedFile)); if (!inputFile.fail() && inputFile.is_open()) { std::string tempString; std::getline(inputFile, tempString); // Skip UTF-8 encoding bytes if there are any. There are 3 of them. if (tempString.substr(0, 3) == "\xEF\xBB\xBF") tempString = tempString.substr(3); g_Config.memStickDirectory = tempString; } inputFile.close(); // Check if the file is empty first, before appending the slash. if (g_Config.memStickDirectory.empty()) g_Config.memStickDirectory = myDocsPath; size_t lastSlash = g_Config.memStickDirectory.find_last_of("/"); if (lastSlash != (g_Config.memStickDirectory.length() - 1)) g_Config.memStickDirectory.append("/"); } else { g_Config.memStickDirectory = path + "memstick/"; } // Create the memstickpath before trying to write to it, and fall back on Documents yet again // if we can't make it. if (!File::Exists(g_Config.memStickDirectory)) { if (!File::CreateDir(g_Config.memStickDirectory)) g_Config.memStickDirectory = myDocsPath; INFO_LOG(COMMON, "Memstick directory not present, creating at '%s'", g_Config.memStickDirectory.c_str()); } const std::string testFile = g_Config.memStickDirectory + "/_writable_test.$$$"; // If any directory is read-only, fall back to the Documents directory. // We're screwed anyway if we can't write to Documents, or can't detect it. if (!File::CreateEmptyFile(testFile)) g_Config.memStickDirectory = myDocsPath; // Clean up our mess. if (File::Exists(testFile)) File::Delete(testFile); // Create the default directories that a real PSP creates. Good for homebrew so they can // expect a standard environment. Skipping THEME though, that's pointless. File::CreateDir(g_Config.memStickDirectory + "PSP"); File::CreateDir(g_Config.memStickDirectory + "PSP/COMMON"); File::CreateDir(g_Config.memStickDirectory + "PSP/GAME"); File::CreateDir(g_Config.memStickDirectory + "PSP/SAVEDATA"); File::CreateDir(g_Config.memStickDirectory + "PSP/PPSSPP_STATE"); #ifdef ANDROID // Avoid media scanners in PPSSPP_STATE directory File::CreateEmptyFile(g_Config.memStickDirectory + "PSP/PPSSPP_STATE/.nomedia"); #endif if (g_Config.currentDirectory.empty()) { g_Config.currentDirectory = GetSysDirectory(DIRECTORY_GAME); } }
// Mix samples from the various audio channels into a single sample queue. // This single sample queue is where __AudioMix should read from. If the sample queue is full, we should // just sleep the main emulator thread a little. void __AudioUpdate() { // Audio throttle doesn't really work on the PSP since the mixing intervals are so closely tied // to the CPU. Much better to throttle the frame rate on frame display and just throw away audio // if the buffer somehow gets full. bool firstChannel = true; for (u32 i = 0; i < PSP_AUDIO_CHANNEL_MAX + 1; i++) { if (!chans[i].reserved) continue; __AudioWakeThreads(chans[i], 0, hwBlockSize); if (!chans[i].sampleQueue.size()) { continue; } if (hwBlockSize * 2 > (int)chans[i].sampleQueue.size()) { ERROR_LOG(SCEAUDIO, "Channel %i buffer underrun at %i of %i", i, (int)chans[i].sampleQueue.size() / 2, hwBlockSize); } const s16 *buf1 = 0, *buf2 = 0; size_t sz1, sz2; chans[i].sampleQueue.popPointers(hwBlockSize * 2, &buf1, &sz1, &buf2, &sz2); if (firstChannel) { for (size_t s = 0; s < sz1; s++) mixBuffer[s] = buf1[s]; if (buf2) { for (size_t s = 0; s < sz2; s++) mixBuffer[s + sz1] = buf2[s]; } firstChannel = false; } else { // Surprisingly hard to SIMD efficiently on SSE2 due to lack of 16-to-32-bit sign extension. NEON should be straight-forward though, and SSE4.1 can do it nicely. // Actually, the cmple/pack trick should work fine... for (size_t s = 0; s < sz1; s++) mixBuffer[s] += buf1[s]; if (buf2) { for (size_t s = 0; s < sz2; s++) mixBuffer[s + sz1] += buf2[s]; } } } if (firstChannel) { // Nothing was written above, let's memset. memset(mixBuffer, 0, hwBlockSize * 2 * sizeof(s32)); } if (g_Config.bEnableSound) { resampler.PushSamples(mixBuffer, hwBlockSize); #ifndef MOBILE_DEVICE if (!m_logAudio) { if (g_Config.bDumpAudio) { std::string audio_file_name = GetSysDirectory(DIRECTORY_AUDIO) + "audiodump.wav"; // Create the path just in case it doesn't exist File::CreateDir(GetSysDirectory(DIRECTORY_AUDIO)); File::CreateEmptyFile(audio_file_name); __StartLogAudio(audio_file_name); } } else { if (g_Config.bDumpAudio) { for (int i = 0; i < hwBlockSize * 2; i++) { clampedMixBuffer[i] = clamp_s16(mixBuffer[i]); } g_wave_writer.AddStereoSamples(clampedMixBuffer, hwBlockSize); } else { __StopLogAudio(); } } #endif } }