#include #include "make_unique.h" #include "Utils.h" #include "stricmp.h" #include "DiskUtils.h" #include "IszImageStream.h" #include "CsoImageStream.h" #include "StdStream.h" #ifdef _WIN32 #include "VolumeStream.h" #else #include "Posix_VolumeStream.h" #endif #ifdef __ANDROID__ #include "PosixFileStream.h" #endif #ifdef __APPLE__ #include "TargetConditionals.h" #endif static Framework::CStream* CreateImageStream(const boost::filesystem::path& imagePath) { #ifdef __ANDROID__ return new Framework::CPosixFileStream(imagePath.string().c_str(), O_RDONLY); #else return new Framework::CStdStream(imagePath.string().c_str(), "rb"); #endif } DiskUtils::OpticalMediaPtr DiskUtils::CreateOpticalMediaFromPath(const boost::filesystem::path& imagePath) { assert(!imagePath.empty()); std::shared_ptr stream; auto extension = imagePath.extension().string(); //Gotta think of something better than that... if(!stricmp(extension.c_str(), ".isz")) { stream = std::make_shared(CreateImageStream(imagePath)); } else if(!stricmp(extension.c_str(), ".cso")) { stream = std::make_shared(CreateImageStream(imagePath)); } #ifdef _WIN32 else if(imagePath.string()[0] == '\\') { stream = std::make_shared(imagePath.string()[4]); } #elif !defined(__ANDROID__) && !TARGET_OS_IPHONE && !TARGET_IPHONE_SIMULATOR else if(imagePath.string().find("/dev/") == 0) { try { stream = std::make_shared(imagePath.string().c_str()); } catch(...) { //Ok if it fails here, might be a standard ISO image file //which will be handled below } } #endif //If it's null after all that, just feed it to a StdStream if(!stream) { stream = std::shared_ptr(CreateImageStream(imagePath)); } return std::make_unique(stream); } DiskUtils::SystemConfigMap DiskUtils::ParseSystemConfigFile(Framework::CStream* systemCnfFile) { SystemConfigMap result; auto line = Utils::GetLine(systemCnfFile); while(!systemCnfFile->IsEOF()) { auto trimmedEnd = std::remove_if(line.begin(), line.end(), isspace); auto trimmedLine = std::string(line.begin(), trimmedEnd); std::vector components; boost::split(components, trimmedLine, boost::is_any_of("="), boost::algorithm::token_compress_on); if(components.size() >= 2) { result.insert(std::make_pair(components[0], components[1])); } line = Utils::GetLine(systemCnfFile); } return result; } static std::string GetDiskIdFromPath(const std::string& filePath) { //Expecting something like SCUS_XXX.XX;1 if(filePath.length() < 13) { throw std::runtime_error("File name too short"); } auto subFilePath = filePath.substr(filePath.length() - 13); auto regionCode = subFilePath.substr(0, 4); auto serial1 = subFilePath.substr(5, 3); auto serial2 = subFilePath.substr(9, 2); return regionCode + "_" + serial1 + "." + serial2; } bool DiskUtils::TryGetDiskId(const boost::filesystem::path& imagePath, std::string* diskIdPtr) { try { auto opticalMedia = CreateOpticalMediaFromPath(imagePath); auto fileSystem = opticalMedia->GetFileSystem(); auto systemConfigFile = std::unique_ptr(fileSystem->Open("SYSTEM.CNF;1")); if(!systemConfigFile) return false; auto systemConfig = ParseSystemConfigFile(systemConfigFile.get()); auto bootItemIterator = systemConfig.find("BOOT2"); if(bootItemIterator == std::end(systemConfig)) return false; auto diskId = GetDiskIdFromPath(bootItemIterator->second); if(diskIdPtr) { (*diskIdPtr) = diskId; } return true; } catch(const std::exception&) { return false; } }