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