loader.cpp 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160
  1. // Copyright 2014 Citra Emulator Project
  2. // Licensed under GPLv2 or any later version
  3. // Refer to the license.txt file included.
  4. #include <string>
  5. #include "common/make_unique.h"
  6. #include "core/file_sys/archive_romfs.h"
  7. #include "core/loader/3dsx.h"
  8. #include "core/loader/elf.h"
  9. #include "core/loader/ncch.h"
  10. #include "core/hle/service/fs/archive.h"
  11. #include "core/mem_map.h"
  12. ////////////////////////////////////////////////////////////////////////////////////////////////////
  13. namespace Loader {
  14. /**
  15. * Identifies the type of a bootable file
  16. * @param file open file
  17. * @return FileType of file
  18. */
  19. static FileType IdentifyFile(FileUtil::IOFile& file) {
  20. FileType type;
  21. #define CHECK_TYPE(loader) \
  22. type = AppLoader_##loader::IdentifyType(file); \
  23. if (FileType::Error != type) \
  24. return type;
  25. CHECK_TYPE(THREEDSX)
  26. CHECK_TYPE(ELF)
  27. CHECK_TYPE(NCCH)
  28. #undef CHECK_TYPE
  29. return FileType::Unknown;
  30. }
  31. /**
  32. * Guess the type of a bootable file from its extension
  33. * @param filename String filename of bootable file
  34. * @return FileType of file
  35. */
  36. static FileType GuessFromFilename(const std::string& filename) {
  37. if (filename.size() == 0) {
  38. LOG_ERROR(Loader, "invalid filename %s", filename.c_str());
  39. return FileType::Error;
  40. }
  41. size_t extension_loc = filename.find_last_of('.');
  42. if (extension_loc == std::string::npos)
  43. return FileType::Unknown;
  44. std::string extension = Common::ToLower(filename.substr(extension_loc));
  45. if (extension == ".elf")
  46. return FileType::ELF;
  47. else if (extension == ".axf")
  48. return FileType::ELF;
  49. else if (extension == ".cxi")
  50. return FileType::CXI;
  51. else if (extension == ".cci")
  52. return FileType::CCI;
  53. else if (extension == ".bin")
  54. return FileType::BIN;
  55. else if (extension == ".3ds")
  56. return FileType::CCI;
  57. else if (extension == ".3dsx")
  58. return FileType::THREEDSX;
  59. return FileType::Unknown;
  60. }
  61. static const char* GetFileTypeString(FileType type) {
  62. switch (type) {
  63. case FileType::CCI:
  64. return "NCSD";
  65. case FileType::CXI:
  66. return "NCCH";
  67. case FileType::ELF:
  68. return "ELF";
  69. case FileType::THREEDSX:
  70. return "3DSX";
  71. case FileType::BIN:
  72. return "raw";
  73. case FileType::Error:
  74. case FileType::Unknown:
  75. return "unknown";
  76. }
  77. }
  78. ResultStatus LoadFile(const std::string& filename) {
  79. std::unique_ptr<FileUtil::IOFile> file(new FileUtil::IOFile(filename, "rb"));
  80. if (!file->IsOpen()) {
  81. LOG_ERROR(Loader, "Failed to load file %s", filename.c_str());
  82. return ResultStatus::Error;
  83. }
  84. FileType type = IdentifyFile(*file);
  85. FileType filename_type = GuessFromFilename(filename);
  86. if (type != filename_type) {
  87. LOG_WARNING(Loader, "File %s has a different type than its extension.", filename.c_str());
  88. if (FileType::Unknown == type)
  89. type = filename_type;
  90. }
  91. LOG_INFO(Loader, "Loading file %s as %s...", filename.c_str(), GetFileTypeString(type));
  92. switch (type) {
  93. //3DSX file format...
  94. case FileType::THREEDSX:
  95. return AppLoader_THREEDSX(std::move(file)).Load();
  96. // Standard ELF file format...
  97. case FileType::ELF:
  98. return AppLoader_ELF(std::move(file)).Load();
  99. // NCCH/NCSD container formats...
  100. case FileType::CXI:
  101. case FileType::CCI:
  102. {
  103. AppLoader_NCCH app_loader(std::move(file));
  104. // Load application and RomFS
  105. if (ResultStatus::Success == app_loader.Load()) {
  106. Kernel::g_program_id = app_loader.GetProgramId();
  107. Service::FS::CreateArchive(Common::make_unique<FileSys::Archive_RomFS>(app_loader), Service::FS::ArchiveIdCode::RomFS);
  108. return ResultStatus::Success;
  109. }
  110. break;
  111. }
  112. // Raw BIN file format...
  113. case FileType::BIN:
  114. {
  115. size_t size = (size_t)file->GetSize();
  116. if (file->ReadBytes(Memory::GetPointer(Memory::EXEFS_CODE_VADDR), size) != size)
  117. return ResultStatus::Error;
  118. Kernel::LoadExec(Memory::EXEFS_CODE_VADDR);
  119. return ResultStatus::Success;
  120. }
  121. // Error occurred durring IdentifyFile...
  122. case FileType::Error:
  123. // IdentifyFile could know identify file type...
  124. case FileType::Unknown:
  125. {
  126. LOG_CRITICAL(Loader, "File %s is of unknown type.");
  127. return ResultStatus::ErrorInvalidFormat;
  128. }
  129. }
  130. return ResultStatus::Error;
  131. }
  132. } // namespace Loader