SplitFileBlob.cpp 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102
  1. // Copyright 2023 Dolphin Emulator Project
  2. // SPDX-License-Identifier: GPL-2.0-or-later
  3. #include "DiscIO/SplitFileBlob.h"
  4. #include <memory>
  5. #include <string>
  6. #include <string_view>
  7. #include <vector>
  8. #include <fmt/format.h>
  9. #include "Common/Assert.h"
  10. #include "Common/FileUtil.h"
  11. #include "Common/IOFile.h"
  12. #include "Common/MsgHandler.h"
  13. namespace DiscIO
  14. {
  15. SplitPlainFileReader::SplitPlainFileReader(std::vector<SingleFile> files)
  16. : m_files(std::move(files))
  17. {
  18. m_size = 0;
  19. for (const auto& f : m_files)
  20. m_size += f.size;
  21. }
  22. std::unique_ptr<SplitPlainFileReader> SplitPlainFileReader::Create(std::string_view first_file_path)
  23. {
  24. constexpr std::string_view part0_iso = ".part0.iso";
  25. if (!first_file_path.ends_with(part0_iso))
  26. return nullptr;
  27. const std::string_view base_path =
  28. first_file_path.substr(0, first_file_path.size() - part0_iso.size());
  29. std::vector<SingleFile> files;
  30. size_t index = 0;
  31. u64 offset = 0;
  32. while (true)
  33. {
  34. File::IOFile f(fmt::format("{}.part{}.iso", base_path, index), "rb");
  35. if (!f.IsOpen())
  36. break;
  37. const u64 size = f.GetSize();
  38. if (size == 0)
  39. return nullptr;
  40. files.emplace_back(SingleFile{std::move(f), offset, size});
  41. offset += size;
  42. ++index;
  43. }
  44. if (files.size() < 2)
  45. return nullptr;
  46. files.shrink_to_fit();
  47. return std::unique_ptr<SplitPlainFileReader>(new SplitPlainFileReader(std::move(files)));
  48. }
  49. std::unique_ptr<BlobReader> SplitPlainFileReader::CopyReader() const
  50. {
  51. std::vector<SingleFile> new_files{};
  52. for (const SingleFile& file : m_files)
  53. {
  54. new_files.push_back(
  55. {.file = file.file.Duplicate("rb"), .offset = file.offset, .size = file.size});
  56. }
  57. return std::unique_ptr<SplitPlainFileReader>(new SplitPlainFileReader(std::move(new_files)));
  58. }
  59. bool SplitPlainFileReader::Read(u64 offset, u64 nbytes, u8* out_ptr)
  60. {
  61. if (offset >= m_size)
  62. return false;
  63. u64 current_offset = offset;
  64. u64 rest = nbytes;
  65. u8* out = out_ptr;
  66. for (auto& file : m_files)
  67. {
  68. if (current_offset >= file.offset && current_offset < file.offset + file.size)
  69. {
  70. auto& f = file.file;
  71. const u64 seek_offset = current_offset - file.offset;
  72. const u64 current_read = std::min(file.size - seek_offset, rest);
  73. if (!f.Seek(seek_offset, File::SeekOrigin::Begin) || !f.ReadBytes(out, current_read))
  74. {
  75. f.ClearError();
  76. return false;
  77. }
  78. rest -= current_read;
  79. if (rest == 0)
  80. return true;
  81. current_offset += current_read;
  82. out += current_read;
  83. }
  84. }
  85. return rest == 0;
  86. }
  87. } // namespace DiscIO