FileBlob.cpp 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123
  1. // Copyright 2008 Dolphin Emulator Project
  2. // SPDX-License-Identifier: GPL-2.0-or-later
  3. #include "DiscIO/FileBlob.h"
  4. #include <algorithm>
  5. #include <memory>
  6. #include <string>
  7. #include <utility>
  8. #include <vector>
  9. #include "Common/Assert.h"
  10. #include "Common/FileUtil.h"
  11. #include "Common/MsgHandler.h"
  12. namespace DiscIO
  13. {
  14. PlainFileReader::PlainFileReader(File::IOFile file) : m_file(std::move(file))
  15. {
  16. m_size = m_file.GetSize();
  17. }
  18. std::unique_ptr<PlainFileReader> PlainFileReader::Create(File::IOFile file)
  19. {
  20. if (file)
  21. return std::unique_ptr<PlainFileReader>(new PlainFileReader(std::move(file)));
  22. return nullptr;
  23. }
  24. std::unique_ptr<BlobReader> PlainFileReader::CopyReader() const
  25. {
  26. return Create(m_file.Duplicate("rb"));
  27. }
  28. bool PlainFileReader::Read(u64 offset, u64 nbytes, u8* out_ptr)
  29. {
  30. if (m_file.Seek(offset, File::SeekOrigin::Begin) && m_file.ReadBytes(out_ptr, nbytes))
  31. {
  32. return true;
  33. }
  34. else
  35. {
  36. m_file.ClearError();
  37. return false;
  38. }
  39. }
  40. bool ConvertToPlain(BlobReader* infile, const std::string& infile_path,
  41. const std::string& outfile_path, CompressCB callback)
  42. {
  43. ASSERT(infile->GetDataSizeType() == DataSizeType::Accurate);
  44. File::IOFile outfile(outfile_path, "wb");
  45. if (!outfile)
  46. {
  47. PanicAlertFmtT(
  48. "Failed to open the output file \"{0}\".\n"
  49. "Check that you have permissions to write the target folder and that the media can "
  50. "be written.",
  51. outfile_path);
  52. return false;
  53. }
  54. constexpr size_t DESIRED_BUFFER_SIZE = 0x80000;
  55. u64 buffer_size = infile->GetBlockSize();
  56. if (buffer_size == 0)
  57. {
  58. buffer_size = DESIRED_BUFFER_SIZE;
  59. }
  60. else
  61. {
  62. while (buffer_size < DESIRED_BUFFER_SIZE)
  63. buffer_size *= 2;
  64. }
  65. std::vector<u8> buffer(buffer_size);
  66. const u64 num_buffers = (infile->GetDataSize() + buffer_size - 1) / buffer_size;
  67. int progress_monitor = std::max<int>(1, num_buffers / 100);
  68. bool success = true;
  69. for (u64 i = 0; i < num_buffers; i++)
  70. {
  71. if (i % progress_monitor == 0)
  72. {
  73. const bool was_cancelled =
  74. !callback(Common::GetStringT("Unpacking"), (float)i / (float)num_buffers);
  75. if (was_cancelled)
  76. {
  77. success = false;
  78. break;
  79. }
  80. }
  81. const u64 inpos = i * buffer_size;
  82. const u64 sz = std::min(buffer_size, infile->GetDataSize() - inpos);
  83. if (!infile->Read(inpos, sz, buffer.data()))
  84. {
  85. PanicAlertFmtT("Failed to read from the input file \"{0}\".", infile_path);
  86. success = false;
  87. break;
  88. }
  89. if (!outfile.WriteBytes(buffer.data(), sz))
  90. {
  91. PanicAlertFmtT("Failed to write the output file \"{0}\".\n"
  92. "Check that you have enough space available on the target drive.",
  93. outfile_path);
  94. success = false;
  95. break;
  96. }
  97. }
  98. if (!success)
  99. {
  100. // Remove the incomplete output file.
  101. outfile.Close();
  102. File::Delete(outfile_path);
  103. }
  104. return success;
  105. }
  106. } // namespace DiscIO