-
Notifications
You must be signed in to change notification settings - Fork 6
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
2 changed files
with
315 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,273 @@ | ||
|
||
#include "filesystem.h" | ||
#include "zipreader.h" | ||
#include "file.h" | ||
#include <map> | ||
#include <stdexcept> | ||
|
||
FFileSystem fileSystem; | ||
|
||
///////////////////////////////////////////////////////////////////////////// | ||
|
||
class ZipFileSystemSource : public IFileSystemSource | ||
{ | ||
public: | ||
ZipFileSystemSource(const FString& filename) | ||
{ | ||
zip = ZipReader::open(filename.GetChars()); | ||
} | ||
|
||
int GetLumpCount() override | ||
{ | ||
return zip->get_num_files(); | ||
} | ||
|
||
int CheckNumForFullName(const FString& fullname) override | ||
{ | ||
return zip->locate_file(fullname.GetChars()); | ||
} | ||
|
||
int FileLength(int lump) override | ||
{ | ||
uint64_t size = zip->get_uncompressed_size(lump); | ||
// For safety. The filesystem API clearly wasn't designed to handle large files. | ||
if (size >= 0x7fffffff) throw std::runtime_error("File is too big"); | ||
return (int)size; | ||
} | ||
|
||
FileData ReadFile(int lump) override | ||
{ | ||
FileData data; | ||
data.Buffer = zip->read_all_bytes(lump); | ||
return data; | ||
} | ||
|
||
const char* GetFileFullName(int lump, bool returnshort) override | ||
{ | ||
static std::string tempstring; | ||
tempstring = zip->get_filename(lump); | ||
return tempstring.c_str(); | ||
} | ||
|
||
std::unique_ptr<ZipReader> zip; | ||
}; | ||
|
||
///////////////////////////////////////////////////////////////////////////// | ||
|
||
class FolderFileSystemSource : public IFileSystemSource | ||
{ | ||
public: | ||
FolderFileSystemSource(const FString& foldername) | ||
{ | ||
ScanFolder(foldername.GetChars()); | ||
} | ||
|
||
int GetLumpCount() override | ||
{ | ||
return (int)Filenames.size(); | ||
} | ||
|
||
int CheckNumForFullName(const FString& fullname) override | ||
{ | ||
auto it = FilenameKeyToIndex.find(fullname.GetChars()); | ||
if (it == FilenameKeyToIndex.end()) | ||
return -1; | ||
return (int)it->second; | ||
} | ||
|
||
int FileLength(int lump) override | ||
{ | ||
int64_t size = File::open_existing(Filenames[lump])->size(); | ||
// For safety. The filesystem API clearly wasn't designed to handle large files. | ||
if (size >= 0x7fffffff) throw std::runtime_error("File is too big"); | ||
return (int)size; | ||
} | ||
|
||
FileData ReadFile(int lump) override | ||
{ | ||
FileData data; | ||
data.Buffer = File::read_all_bytes(Filenames[lump]); | ||
return data; | ||
} | ||
|
||
const char* GetFileFullName(int lump, bool returnshort) override | ||
{ | ||
return Filenames[lump].c_str(); | ||
} | ||
|
||
void ScanFolder(const std::string& foldername, int depth = 0) | ||
{ | ||
for (const std::string& filename : Directory::files(foldername)) | ||
{ | ||
std::string fullname = FilePath::combine(foldername, filename); | ||
FilenameKeyToIndex[fullname] = Filenames.size(); | ||
Filenames.push_back(fullname); | ||
} | ||
|
||
if (depth < 16) | ||
{ | ||
for (const std::string& subfolder : Directory::folders(foldername)) | ||
{ | ||
ScanFolder(FilePath::combine(foldername, subfolder), depth + 1); | ||
} | ||
} | ||
} | ||
|
||
std::vector<std::string> Filenames; | ||
std::map<std::string, size_t> FilenameKeyToIndex; | ||
}; | ||
|
||
///////////////////////////////////////////////////////////////////////////// | ||
|
||
class WadFileEntry | ||
{ | ||
public: | ||
uint32_t offset = 0; | ||
uint32_t size = 0; | ||
std::string name; | ||
void *data = nullptr; | ||
}; | ||
|
||
class WadFileSystemSource : public IFileSystemSource | ||
{ | ||
public: | ||
WadFileSystemSource(const FString& filename) | ||
{ | ||
file = File::open_existing(filename.GetChars()); | ||
|
||
char magic[4]; | ||
file->read(magic, 4); | ||
pwad = memcmp(magic, "PWAD", 4) == 0; | ||
iwad = memcmp(magic, "IWAD", 4) == 0; | ||
if (!pwad && !iwad) | ||
throw std::runtime_error("Not a valid WAD file"); | ||
|
||
uint32_t num_entries = file->read_uint32(); | ||
uint32_t directory_offset = file->read_uint32(); | ||
file->seek(directory_offset); | ||
for (uint32_t i = 0; i < num_entries; i++) | ||
{ | ||
WadFileEntry entry; | ||
entry.offset = file->read_uint32(); | ||
entry.size = file->read_uint32(); | ||
|
||
char name[9]; | ||
name[8] = 0; | ||
file->read(name, 8); | ||
entry.name = name; | ||
|
||
FilenameKeyToIndex[entry.name] = entries.size(); | ||
entries.push_back(entry); | ||
} | ||
} | ||
|
||
int GetLumpCount() override | ||
{ | ||
return (int)entries.size(); | ||
} | ||
|
||
int CheckNumForFullName(const FString& fullname) override | ||
{ | ||
auto it = FilenameKeyToIndex.find(fullname.GetChars()); | ||
if (it == FilenameKeyToIndex.end()) | ||
return -1; | ||
return (int)it->second; | ||
} | ||
|
||
int FileLength(int lump) override | ||
{ | ||
return entries[lump].size; | ||
} | ||
|
||
FileData ReadFile(int lump) override | ||
{ | ||
FileData data; | ||
data.Buffer.resize(entries[lump].size); | ||
file->seek(entries[lump].offset); | ||
file->read(data.Buffer.data(), data.Buffer.size()); | ||
return data; | ||
} | ||
|
||
const char* GetFileFullName(int lump, bool returnshort) override | ||
{ | ||
return entries[lump].name.c_str(); | ||
} | ||
|
||
std::shared_ptr<File> file; | ||
bool pwad = false; | ||
bool iwad = false; | ||
std::vector<WadFileEntry> entries; | ||
std::map<std::string, size_t> FilenameKeyToIndex; | ||
}; | ||
|
||
///////////////////////////////////////////////////////////////////////////// | ||
|
||
void FFileSystem::AddZipSource(const FString& filename) | ||
{ | ||
Sources.push_back(std::make_unique<ZipFileSystemSource>(filename)); | ||
} | ||
|
||
void FFileSystem::AddFolderSource(const FString& foldername) | ||
{ | ||
Sources.push_back(std::make_unique<FolderFileSystemSource>(foldername)); | ||
} | ||
|
||
void FFileSystem::AddWadSource(const FString& filename) | ||
{ | ||
Sources.push_back(std::make_unique<WadFileSystemSource>(filename)); | ||
} | ||
|
||
int FFileSystem::CheckNumForFullName(const FString& fullname) | ||
{ | ||
int pos = 0; | ||
for (auto& source : Sources) | ||
{ | ||
int index = source->CheckNumForFullName(fullname); | ||
if (index != -1) | ||
return pos + index; | ||
pos += source->GetLumpCount(); | ||
} | ||
return -1; | ||
} | ||
|
||
int FFileSystem::FileLength(int lump) | ||
{ | ||
int pos = 0; | ||
for (auto& source : Sources) | ||
{ | ||
if (lump - pos < source->GetLumpCount()) | ||
{ | ||
return source->FileLength(lump - pos); | ||
} | ||
pos += source->GetLumpCount(); | ||
} | ||
return 0; | ||
} | ||
|
||
FileData FFileSystem::ReadFile(int lump) | ||
{ | ||
int pos = 0; | ||
for (auto& source : Sources) | ||
{ | ||
if (lump - pos < source->GetLumpCount()) | ||
{ | ||
return source->ReadFile(lump - pos); | ||
} | ||
pos += source->GetLumpCount(); | ||
} | ||
return {}; | ||
} | ||
|
||
const char* FFileSystem::GetFileFullName(int lump, bool returnshort) const | ||
{ | ||
int pos = 0; | ||
for (auto& source : Sources) | ||
{ | ||
if (lump - pos < source->GetLumpCount()) | ||
{ | ||
return source->GetFileFullName(lump - pos, returnshort); | ||
} | ||
pos += source->GetLumpCount(); | ||
} | ||
return {}; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
#pragma once | ||
|
||
#include "framework/tarray.h" | ||
#include "framework/templates.h" | ||
#include "framework/zstring.h" | ||
#include <memory> | ||
#include <vector> | ||
|
||
struct FileData | ||
{ | ||
char* GetMem() { return (char*)Buffer.data(); } | ||
std::vector<uint8_t> Buffer; | ||
}; | ||
|
||
class IFileSystemSource | ||
{ | ||
public: | ||
virtual ~IFileSystemSource() = default; | ||
virtual int GetLumpCount() = 0; | ||
virtual int CheckNumForFullName(const FString& fullname) = 0; | ||
virtual int FileLength(int lump) = 0; | ||
virtual FileData ReadFile(int lump) = 0; | ||
virtual const char* GetFileFullName(int lump, bool returnshort) = 0; | ||
}; | ||
|
||
class FFileSystem | ||
{ | ||
public: | ||
void AddZipSource(const FString& filename); | ||
void AddFolderSource(const FString& foldername); | ||
void AddWadSource(const FString& filename); | ||
|
||
int CheckNumForFullName(const FString& fullname); | ||
int FileLength(int lump); | ||
FileData ReadFile(int lump); | ||
const char* GetFileFullName(int lump, bool returnshort = true) const; | ||
|
||
private: | ||
std::vector<std::unique_ptr<IFileSystemSource>> Sources; | ||
}; | ||
|
||
extern FFileSystem fileSystem; |