/** * Copies target path and all children to destination path. * * Returns 0 on success or a negative value indicating number of failures */ int copyRecursive(const char *fromPath, const char *toPath) { int ret = 0; string fromPathStr(fromPath); string toPathStr(toPath); DIR* dir = opendir(fromPath); if (!dir) { PLOG(ERROR) << "opendir " << fromPath << " failed"; return -1; } if (fromPathStr[fromPathStr.size()-1] != '/') fromPathStr += '/'; if (toPathStr[toPathStr.size()-1] != '/') toPathStr += '/'; struct dirent* entry; while ((entry = readdir(dir))) { const char* name = entry->d_name; // ignore "." and ".." if (name[0] == '.' && (name[1] == 0 || (name[1] == '.' && name[2] == 0))) { continue; } string oldFile = fromPathStr + name; string newFile = toPathStr + name; if (entry->d_type == DT_DIR) { ret += makeFolder(newFile.c_str()); ret += copyRecursive(oldFile.c_str(), newFile.c_str()); } else { ret += copyFile(oldFile.c_str(), newFile.c_str()); } } return ret; }
FSStatus FSMakeDirAsync(FSClient *client, FSCmdBlock *block, const char *path, uint32_t flags, FSAsyncData *asyncData) { auto pathLength = strlen(path); if (pathLength >= FSCmdBlock::MaxPathLength) { return FSStatus::FatalError; } std::memcpy(block->path, path, pathLength); block->path[pathLength] = 0; internal::queueFsWork(client, block, asyncData, [=]() { auto fs = kernel::getFileSystem(); if (!fs->makeFolder(coreinit::internal::translatePath(block->path))) { return FSStatus::FatalError; } return FSStatus::OK; }); return FSStatus::OK; }
//Main program entry point int main(int argc, char** argv) { g_bProgressOverwrite = false; g_iNumThreads = 0; DWORD iTicks = GetTickCount(); //Store the starting number of milliseconds vfs.Prepare(); //read in the resource names to unpack initResMap(); initSoundManifest(); parseCmdLine(argc,argv); if(argc < 2) { cout << "Usage: liDecompress [filename1] [filename2] ... [filenameN]" << endl; return 0; } for(int iArg = 1; iArg < argc; iArg++) { if(argv[iArg][0] == '-') //Skip over commandline switches continue; cout << endl << "Unpacking resource blob file " << argv[iArg] << endl; FILE* f = fopen(argv[iArg], "rb"); if(f == NULL) { cout << "Unable to open file " << argv[iArg] << endl; continue; } blobHeader bH; if(fread((void*)&bH, 1, sizeof(blobHeader), f) != sizeof(blobHeader)) { cout << "Error reading number of resources in file " << argv[iArg] << endl; fclose(f); continue; } list<resourceHeader> lResourceHeaders; for(int i = 0; i < bH.numItems; i++) { resourceHeader rH; size_t sizeRead = fread((void*)&rH, 1, sizeof(resourceHeader), f); if(sizeRead != sizeof(resourceHeader)) { cout << "Read " << sizeRead << " bytes, which differs from resource header size " << sizeof(resourceHeader) << endl; fclose(f); continue; } lResourceHeaders.push_back(rH); } //Create list file with all the files that were in this .pak string sPakListFilename = ""; for(int i = strlen(argv[iArg])-1; i >= 0; i--) { if(argv[iArg][i] == '\\' || argv[iArg][i] == '/') break; sPakListFilename.insert(sPakListFilename.begin(), argv[iArg][i]); } sPakListFilename += ".filelist.txt"; ofstream oPakList(sPakListFilename.c_str()); //Iterate through these items, splitting them out of the file and creating new files out of each cout << "Extracting files..." << endl; for(list<resourceHeader>::iterator i = lResourceHeaders.begin(); i != lResourceHeaders.end(); i++) { ThreadConvertHelper dh; makeFolder(i->id); const wchar_t* cName = getName(i->id); oPakList << ws2s(cName) << endl; fseek(f, i->offset, SEEK_SET); dh.sFilename = cName; if(i->flags == FLAG_ZLIBCOMPRESSED) { compressedHeader cH; if(fread((void*)&cH, 1, sizeof(compressedHeader), f) != sizeof(compressedHeader)) { cout << "Error reading compressed header." << endl; fclose(f); continue; } uint32_t size = cH.compressedSizeBytes; uint8_t* buf = (uint8_t*)malloc(size); size_t sizeRead = fread((void*)buf, 1, size, f); if(sizeRead != size) { cout << "Error reading compressed data. Size: " << size << " read: " << sizeRead << endl; fclose(f); free(buf); continue; } dh.data.data = buf; dh.data.compressedSize = cH.compressedSizeBytes; dh.data.decompressedSize = cH.uncompressedSizeBytes; dh.bCompressed = true; } else if(i->flags == FLAG_NOCOMPRESSION) { uint8_t* buf = (uint8_t*)malloc(i->size); if(fread((void*)buf, 1, i->size, f) != i->size) { cout << "Error reading non-compressed data." << endl; fclose(f); free(buf); continue; } dh.data.data = buf; dh.data.compressedSize = dh.data.decompressedSize = i->size; dh.bCompressed = false; } else cout << "Invalid resource flag " << i->flags << endl; g_lThreadedResources.push_back(dh); } threadedDecompress(); fclose(f); oPakList.close(); } cout << "\rDone. " << endl; iTicks = GetTickCount() - iTicks; float iSeconds = (float)iTicks / 1000.0; //Get seconds elapsed int iMinutes = iSeconds / 60; iSeconds -= iMinutes * 60; cout << "Time elapsed: " << iMinutes << " min, " << iSeconds << " sec" << endl; //system("PAUSE"); return 0; }
bool launchGame() { if (!loadGameInfo(sGameInfo)) { gLog->warn("Could not load game info."); } else { gLog->info("Loaded game info: '{}' - {} v{}", sGameInfo.meta.shortnames[decaf::Language::English], sGameInfo.meta.product_code, sGameInfo.meta.title_version); } auto rpx = sGameInfo.cos.argstr; if (rpx.empty()) { rpx = sExecutableName; } if (rpx.empty()) { gLog->error("Could not find game executable to load."); return false; } // Set up the code heap to load stuff to initialiseCodeHeap(sGameInfo.cos.max_codesize); // Load the application-level kernel binding auto coreinitModule = loader::loadRPL("coreinit"); if (!coreinitModule) { gLog->error("Could not load system coreinit library"); return false; } // Load the application auto appModule = loader::loadRPL(rpx); if (!appModule) { gLog->error("Could not load {}", rpx); return false; } gLog->debug("Succesfully loaded {}", rpx); sUserModule = appModule; // Setup title path auto fileSystem = getFileSystem(); // Temporarily set mlc to write so we can create folders fileSystem->setPermissions("/vol/storage_mlc01", fs::Permissions::ReadWrite, fs::PermissionFlags::Recursive); // Create title folder auto titleID = sGameInfo.app.title_id; auto titleLo = static_cast<uint32_t>(titleID & 0xffffffff); auto titleHi = static_cast<uint32_t>(titleID >> 32); auto titlePath = fmt::format("/vol/storage_mlc01/sys/title/{:08x}/{:08x}", titleHi, titleLo); auto titleFolder = fileSystem->makeFolder(titlePath); // Create Mii database folder fileSystem->makeFolder("/vol/storage_mlc01/usr/save/00050010/1004a100/user/common/db"); // Restore mlc to Read only fileSystem->setPermissions("/vol/storage_mlc01", fs::Permissions::Read, fs::PermissionFlags::Recursive); // Set title folder to ReadWrite fileSystem->setPermissions(titlePath, fs::Permissions::ReadWrite, fs::PermissionFlags::Recursive); // Set mlc/usr to ReadWrite fileSystem->setPermissions("/vol/storage_mlc01/usr", fs::Permissions::ReadWrite, fs::PermissionFlags::Recursive); // We need to set some default stuff up... auto core = cpu::this_core::state(); core->gqr[2].value = 0x40004; core->gqr[3].value = 0x50005; core->gqr[4].value = 0x60006; core->gqr[5].value = 0x70007; // Setup coreinit threads coreinit::internal::startAlarmCallbackThreads(); coreinit::internal::startAppIoThreads(); coreinit::internal::startDefaultCoreThreads(); coreinit::internal::startDeallocatorThreads(); // Notify frontend that game has loaded decaf::event::onGameLoaded(sGameInfo); // Start the entry thread! auto gameThreadEntry = coreinitModule->findFuncExport<uint32_t, uint32_t, void*>("GameThreadEntry"); coreinit::OSRunThread(coreinit::OSGetDefaultThread(1), gameThreadEntry, 0, nullptr); return true; }
bool extractMap(const std::string& file) { int err = 0; zip* zipFile = zip_open(file.c_str(), 0, &err); if(!zipFile) { std::cout << "[ERROR]: Failed to open archive file: " << file << ".\n"; return false; } auto fileNumber = zip_get_num_entries(zipFile, 0); std::string folderName = file.substr(0, file.find_last_of('.')) + "/"; // cut off file extension, add dir char stripWebChars(folderName); if(!makeFolder(folderName)) return false; for(auto i = 0u; i < fileNumber; i++) { zip_file* zipped = zip_fopen_index(zipFile, i, 0); struct zip_stat fileInfo; zip_stat_init(&fileInfo); zip_stat_index(zipFile, i, 0, &fileInfo); if(fileInfo.valid & ZIP_STAT_NAME && fileInfo.valid & ZIP_STAT_SIZE && fileInfo.valid & ZIP_STAT_COMP_SIZE) { std::string fileStr = fileInfo.name; if(fileStr.find('.') == std::string::npos) // if we don't have a dot, this is a folder { continue; // skip this folder } if(fileStr.find('/') != std::string::npos) // if we have any dir chars in the string, strip out dirs { fileStr = fileStr.substr(fileStr.find_last_of('/') + 1); } #ifndef __linux__ #pragma warning(push) #pragma warning(disable: 4244) #endif std::vector<bbyte> bytes(fileInfo.size); // just gotta deal with this conversion #ifndef __linux__ #pragma warning(pop) #endif zip_fread(zipped, bytes.data(), fileInfo.size); std::ofstream fout; fout.open(folderName + fileStr, std::ofstream::binary); if(fout.bad()) { std::cout << "[ERROR]: Unable to extract file: " << fileInfo.name << '\n'; return false; } fout.write(bytes.data(), bytes.size()); fout.close(); } else { std::cout << "[ERROR]: Bad file data for file in archive: " << file << '\n'; return false; } zip_fclose(zipped); } zip_close(zipFile); // delete the zip file, it's no longer needed #ifdef __linux__ // TBD #else DeleteFile(file.c_str()); #endif return true; }
void decompressResource() { for(bool bDone = false;!bDone;) //Loop until we're done { ThreadConvertHelper dh; wstring sFilename; std::lock_guard<std::mutex> lock(g_Mutex); if(!g_lThreadedResources.size()) //Done { bDone = true; } else { //Grab the top item off the list dh = g_lThreadedResources.front(); sFilename = getName(dh.id); //Mutex on this too, since getName() isn't really threadsafe makeFolder(dh.id); //Also create folder (not threadsafe, either) g_lThreadedResources.pop_front(); //Done with this element } //Let user know which resource we're converting now if(!bDone) { g_iCurResource++; if(!(sFilename == RESIDMAP_NAME && g_iCurResource == 1)) { if(g_bProgressOverwrite) { cout << "\rDecompressing file " << g_iCurResource << " out of " << g_iNumResources; cout.flush(); } else cout << "Decompressing file " << g_iCurResource << " out of " << g_iNumResources << ": " << ws2s(sFilename) << endl; } } // Release ownership of the mutex object if(sFilename == RESIDMAP_NAME && g_iCurResource == 1) //Don't release residmap.dat mutex until we've read in all the filenames { g_iNumResources--; } if(bDone) { continue; //Stop here if done } if(dh.bCompressed) //Compressed { uint8_t* tempData = decompress(&dh.data); if(tempData == NULL) { cout << "Error decompressing file " << ws2s(sFilename) << endl; return; } free(dh.data.data); //Free this compressed memory dh.data.data = tempData; //Now we have the decompressed data } //See if this was a PNG image. Convert PNG images from the data in RAM if(sFilename.find(L".png") != wstring::npos || sFilename.find(L".PNG") != wstring::npos || sFilename.find(L"coloritemicon") != wstring::npos || sFilename.find(L"colorbgicon") != wstring::npos || sFilename.find(L"greybgicon") != wstring::npos) //Also would include .png.normal files as well { convertToPNG(sFilename.c_str(), dh.data.data, dh.data.decompressedSize); //Do the conversion to PNG } else //For other file types, go ahead and write to the file before converting { //Write this out to the file FILE* fOut = fopen(ws2s(sFilename).c_str(), "wb"); if(fOut == NULL) { cout << "Unable to open output file " << ws2s(sFilename) << endl; return; } fwrite(dh.data.data, 1, dh.data.decompressedSize, fOut); fclose(fOut); } free(dh.data.data); //Free memory from this file /* //Convert wordPackDict.dat to XML if(sFilename.find(L"wordPackDict.dat") != wstring::npos) { wordPackToXML(sFilename.c_str()); unlink(ws2s(sFilename).c_str()); } //Convert sndmanifest.dat to XML else if(sFilename.find(L"sndmanifest.dat") != wstring::npos) { sndManifestToXML(sFilename.c_str()); unlink(ws2s(sFilename).c_str()); } //Convert itemmanifest.dat to XML else if(sFilename.find(L"itemmanifest.dat") != wstring::npos) { itemManifestToXML(sFilename.c_str()); unlink(ws2s(sFilename).c_str()); } //Convert letterdb.dat to XML else if(sFilename.find(L"letterdb.dat") != wstring::npos) { letterToXML(sFilename.c_str()); unlink(ws2s(sFilename).c_str()); } //Convert catalogdb.dat to XML else if(sFilename.find(L"catalogdb.dat") != wstring::npos) { catalogToXML(sFilename.c_str()); unlink(ws2s(sFilename).c_str()); } //Convert combodb.dat to XML else if(sFilename.find(L"combodb.dat") != wstring::npos) { comboDBToXML(sFilename.c_str()); unlink(ws2s(sFilename).c_str()); } //Convert residmap.dat to XML else if(sFilename.find(L"residmap.dat") != wstring::npos) { residMapToXML(sFilename.c_str()); unlink(ws2s(sFilename).c_str()); } //Convert .flac binary files to OGG else if(sFilename.find(L".flac") != wstring::npos || sFilename.find(L".FLAC") != wstring::npos) { wstring s = sFilename; s += L".ogg"; binaryToOgg(sFilename.c_str(), s.c_str()); unlink(ws2s(sFilename).c_str()); //Delete temporary .flac file } //Convert vdata/fontmanifest.dat to XML else if(sFilename.find(L"fontmanifest.dat") != wstring::npos) { fontManifestToXML(sFilename); unlink(ws2s(sFilename).c_str()); } //Convert font files to XML else if(sFilename.find(L".font.xml") != wstring::npos) { fontToXML(sFilename); } //Convert vdata/loctexmanifest.bin to XML else if(sFilename.find(L"loctexmanifest.bin") != wstring::npos) { LoctexManifestToXML(sFilename); unlink(ws2s(sFilename).c_str()); } //Convert vdata/myPicturesImage.dat to XML else if(sFilename.find(L"myPicturesImage.dat") != wstring::npos) { myPicturesToXML(sFilename); unlink(ws2s(sFilename).c_str()); } //Convert vdata/smokeImage.dat to XML else if(sFilename.find(L"smokeImage.dat") != wstring::npos) { smokeImageToXML(sFilename); unlink(ws2s(sFilename).c_str()); } //Convert vdata/fluidPalettes.dat to XML else if(sFilename.find(L"fluidPalettes.dat") != wstring::npos) { fluidPalettesToXML(sFilename); unlink(ws2s(sFilename).c_str()); } */ if(sFilename == RESIDMAP_NAME && g_iCurResource == 1) { g_iCurResource--; } } return; }