Worldstone
 All Classes Files Functions Variables Enumerations Enumerator Macros Pages
MpqArchive.cpp
1 //
2 // Created by Lectem on 11/11/2016.
3 //
4 
5 #include "MpqArchive.h"
6 #include <StormLib.h>
7 #include <fmt/format.h>
8 #include <type_traits>
9 
10 namespace WorldStone
11 {
12 
13 MpqArchive::MpqArchive(MpqArchive&& toMove) { *this = std::move(toMove); }
14 
15 MpqArchive& MpqArchive::operator=(MpqArchive&& toMove)
16 {
17  std::swap(mpqHandle, toMove.mpqHandle);
18  std::swap(mpqFileName, toMove.mpqFileName);
19  std::swap(_state, toMove._state);
20  return *this;
21 }
22 MpqArchive::MpqArchive(const char* MpqFileName, const char* listFilePath) : mpqFileName(MpqFileName)
23 {
24  static_assert(std::is_same<MpqArchive::HANDLE, ::HANDLE>(),
25  "Make sure we correctly defined HANDLE type");
26  if (load() && listFilePath) {
27  addListFile(listFilePath);
28  }
29 }
30 
31 MpqArchive::~MpqArchive() { unload(); }
32 
33 void MpqArchive::addListFile(const char* listFilePath)
34 {
35  if (!mpqHandle) return;
36  if (SFileAddListFile(mpqHandle, listFilePath) != ERROR_SUCCESS) setstate(failbit);
37 }
38 
39 std::vector<MpqArchive::Path> MpqArchive::findFiles(const Path& searchMask)
40 {
41  if (!mpqHandle) return {};
42  std::vector<Path> list;
43  SFILE_FIND_DATA findFileData;
44  HANDLE findHandle = SFileFindFirstFile(mpqHandle, searchMask.c_str(), &findFileData, nullptr);
45  if (!findHandle) return {};
46  do
47  {
48  list.emplace_back(findFileData.cFileName);
49  } while (SFileFindNextFile(findHandle, &findFileData));
50 
51  SFileFindClose(findHandle);
52  return list;
53 }
54 
55 bool MpqArchive::load()
56 {
57  if (mpqHandle) throw std::runtime_error("tried to reopen mpq archive");
58  if (!SFileOpenArchive(mpqFileName.c_str(), 0, STREAM_FLAG_READ_ONLY, &mpqHandle))
59  setstate(failbit);
60  return good();
61 }
62 
63 bool MpqArchive::is_loaded() { return mpqHandle != nullptr; }
64 
65 bool MpqArchive::unload()
66 {
67  if (!(mpqHandle && SFileCloseArchive(mpqHandle))) setstate(failbit);
68  mpqHandle = nullptr;
69  return good();
70 }
71 
72 bool MpqArchive::exists(const Path& filePath) { return SFileHasFile(mpqHandle, filePath.c_str()); }
73 
74 StreamPtr MpqArchive::open(const Path& filePath)
75 {
76  StreamPtr tmp = std::make_unique<MpqFileStream>(*this, filePath);
77  return tmp->good() ? std::move(tmp) : nullptr;
78 }
79 
80 MpqFileStream::MpqFileStream(MpqArchive& archive, const Path& filename) { open(archive, filename); }
81 
82 MpqFileStream::~MpqFileStream() { close(); }
83 
84 bool MpqFileStream::open(MpqArchive& archive, const Path& filename)
85 {
86  if (!archive || !SFileOpenFileEx(archive.getInternalHandle(), filename.c_str(), 0, &file))
87  setstate(failbit);
88  return good();
89 }
90 
91 bool MpqFileStream::close()
92 {
93  if (!(file && SFileCloseFile(file))) setstate(failbit);
94  file = nullptr;
95  return good();
96 }
97 
98 size_t MpqFileStream::read(void* buffer, size_t size)
99 {
100  DWORD readBytes = 0;
101 
102  bool success = SFileReadFile(file, buffer, static_cast<DWORD>(size), &readBytes, nullptr);
103  if (!success) {
104  const DWORD lastError = GetLastError();
105  if (lastError == ERROR_HANDLE_EOF) {
106  setstate(eofbit);
107  }
108  setstate(failbit);
109  }
110  return readBytes;
111 }
112 
114 {
115  const DWORD size = SFileSetFilePointer(file, 0, nullptr, FILE_CURRENT);
116  if (size == SFILE_INVALID_SIZE) setstate(failbit);
117  return static_cast<long>(size);
118 }
119 
120 // We assume there's no need for conversion, which is probably wrong on some platforms
121 static_assert(MpqFileStream::beg == FILE_BEGIN, "");
122 static_assert(MpqFileStream::cur == FILE_CURRENT, "");
123 static_assert(MpqFileStream::end == FILE_END, "");
124 bool MpqFileStream::seek(long offset, IStream::seekdir origin)
125 {
126  if (SFileSetFilePointer(file, static_cast<LONG>(offset), nullptr, origin) == SFILE_INVALID_SIZE)
127  setstate(failbit);
128  return good();
129 }
130 
132 {
133  DWORD sizeLower32bits = SFileGetFileSize(file, nullptr);
134  if (sizeLower32bits == SFILE_INVALID_SIZE) setstate(failbit);
135  return static_cast<long>(sizeLower32bits);
136 }
137 }
bool seek(long offset, seekdir origin) override
Definition: MpqArchive.cpp:124
long size() override
Compute the size of the file.
Definition: MpqArchive.cpp:131
long tell() override
Return the current position of the stream pointer.
Definition: MpqArchive.cpp:113
size_t read(void *buffer, size_t size) override
Read data from the stream.
Definition: MpqArchive.cpp:98