Skip to content

Commit 3245998

Browse files
committed
parse utoc directory index
1 parent 95f5895 commit 3245998

3 files changed

Lines changed: 152 additions & 14 deletions

File tree

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
#pragma once
2+
3+
#include <cstdint>
4+
#include <string>
5+
#include <vector>
6+
7+
#include "../../../../IO/Archive/Archive.h"
8+
#include "satisfactorysave_export.h"
9+
10+
namespace SatisfactorySave {
11+
// https://github.com/EpicGames/UnrealEngine/blob/5.3.2-release/Engine/Source/Runtime/Core/Internal/IO/IoDirectoryIndex.h
12+
13+
struct SATISFACTORYSAVE_API FIoDirectoryIndexEntry {
14+
uint32_t Name = ~static_cast<uint32_t>(0);
15+
uint32_t FirstChildEntry = ~static_cast<uint32_t>(0);
16+
uint32_t NextSiblingEntry = ~static_cast<uint32_t>(0);
17+
uint32_t FirstFileEntry = ~static_cast<uint32_t>(0);
18+
19+
void serialize(Archive& ar) {
20+
ar << Name;
21+
ar << FirstChildEntry;
22+
ar << NextSiblingEntry;
23+
ar << FirstFileEntry;
24+
}
25+
};
26+
27+
struct SATISFACTORYSAVE_API FIoFileIndexEntry {
28+
uint32_t Name = ~static_cast<uint32_t>(0);
29+
uint32_t NextFileEntry = ~static_cast<uint32_t>(0);
30+
uint32_t UserData = 0;
31+
32+
void serialize(Archive& ar) {
33+
ar << Name;
34+
ar << NextFileEntry;
35+
ar << UserData;
36+
}
37+
};
38+
39+
struct SATISFACTORYSAVE_API FIoDirectoryIndexResource {
40+
std::string MountPoint;
41+
std::vector<FIoDirectoryIndexEntry> DirectoryEntries;
42+
std::vector<FIoFileIndexEntry> FileEntries;
43+
std::vector<std::string> StringTable;
44+
45+
void serialize(Archive& ar) {
46+
ar << MountPoint;
47+
ar << DirectoryEntries;
48+
ar << FileEntries;
49+
ar << StringTable;
50+
}
51+
};
52+
} // namespace SatisfactorySave
Lines changed: 29 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,51 @@
11
#pragma once
22

3+
#include <cstdint>
34
#include <filesystem>
5+
#include <string>
6+
#include <unordered_map>
47

8+
#include "../GameTypes/UE/Core/IO/IoDirectoryIndex.h"
9+
#include "../GameTypes/UE/Core/IO/IoStore.h"
510
#include "../IO/Archive/IStreamArchive.h"
611
#include "AbstractPakFile.h"
712
#include "satisfactorysave_export.h"
813

914
namespace SatisfactorySave {
1015

16+
class SATISFACTORYSAVE_API DirectoryIndexReader {
17+
public:
18+
explicit DirectoryIndexReader(const FIoDirectoryIndexResource& res);
19+
20+
[[nodiscard]] const std::unordered_map<std::string, uint32_t>& directoryEntries() const {
21+
return directoryEntries_;
22+
}
23+
24+
private:
25+
void parseDir(uint32_t dir_idx, const std::string& path);
26+
27+
void parseFile(uint32_t file_idx, const std::string& path);
28+
29+
static constexpr uint32_t none = ~static_cast<uint32_t>(0);
30+
31+
const FIoDirectoryIndexResource& res_;
32+
std::unordered_map<std::string, uint32_t> directoryEntries_;
33+
};
34+
1135
class SATISFACTORYSAVE_API IoStoreFile : public AbstractPakFile {
1236
public:
1337
explicit IoStoreFile(const std::filesystem::path& path);
1438

15-
[[nodiscard]] std::vector<std::string> getAllAssetFilenames() const override {
16-
return {};
17-
}
39+
[[nodiscard]] std::vector<std::string> getAllAssetFilenames() const override;
1840

1941
[[nodiscard]] bool containsAssetFilename(const std::string& filename) const override {
20-
return false;
42+
return dirIndex_ != nullptr ? dirIndex_->directoryEntries().contains(filename) : false;
2143
}
2244

23-
std::vector<char> readAssetFileContent(const std::string& filename) override {
24-
return {};
25-
}
45+
std::vector<char> readAssetFileContent(const std::string& filename) override;
2646

2747
private:
28-
std::unique_ptr<IFStreamArchive> ioStoreAr_;
48+
FIoStoreTocResource utoc_;
49+
std::unique_ptr<DirectoryIndexReader> dirIndex_;
2950
};
3051
} // namespace SatisfactorySave

libsave/src/Pak/IoStoreFile.cpp

Lines changed: 71 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,85 @@
11
#include "Pak/IoStoreFile.h"
22

3+
#include <cstring>
4+
35
#include "GameTypes/UE/Core/IO/IoStore.h"
6+
#include "IO/MemoryStreams.h"
7+
8+
SatisfactorySave::DirectoryIndexReader::DirectoryIndexReader(const FIoDirectoryIndexResource& res) : res_(res) {
9+
if (!res_.MountPoint.starts_with("../../../")) {
10+
throw std::runtime_error("Invalid mount point");
11+
}
12+
parseDir(0, res_.MountPoint.substr(9));
13+
}
14+
15+
void SatisfactorySave::DirectoryIndexReader::parseDir(uint32_t dir_idx, const std::string& path) {
16+
if (dir_idx == none) {
17+
return;
18+
}
19+
const auto& entry = res_.DirectoryEntries[dir_idx];
20+
const std::string name = (entry.Name != none) ? (res_.StringTable[entry.Name] + "/") : "";
21+
// children
22+
parseDir(entry.FirstChildEntry, path + name);
23+
// siblings
24+
parseDir(entry.NextSiblingEntry, path);
25+
// files
26+
parseFile(entry.FirstFileEntry, path + name);
27+
}
28+
29+
void SatisfactorySave::DirectoryIndexReader::parseFile(uint32_t file_idx, const std::string& path) {
30+
if (file_idx == none) {
31+
return;
32+
}
33+
const auto& entry = res_.FileEntries[file_idx];
34+
const std::string filename = path + res_.StringTable[entry.Name];
35+
if (directoryEntries_.contains(filename)) {
36+
throw std::runtime_error("Directory filename entry is not unique!");
37+
}
38+
directoryEntries_[filename] = entry.UserData;
39+
40+
parseFile(entry.NextFileEntry, path);
41+
}
442

543
SatisfactorySave::IoStoreFile::IoStoreFile(const std::filesystem::path& path) {
644
if (!std::filesystem::is_regular_file(path)) {
745
throw std::runtime_error("IoStore file invalid: " + path.string());
846
}
947

10-
ioStoreAr_ = std::make_unique<IFStreamArchive>(path);
11-
auto& ar = *ioStoreAr_;
12-
13-
FIoStoreTocResource utoc;
14-
ar << utoc;
48+
IFStreamArchive utocAr(path);
49+
utocAr << utoc_;
1550

1651
// Debug validation
17-
if (ar.tell() != ar.size()) {
52+
if (utocAr.tell() != utocAr.size()) {
1853
throw std::runtime_error("utoc file not fully read!");
1954
}
55+
56+
if (!utoc_.DirectoryIndexBuffer.empty()) {
57+
auto buf = std::make_unique<std::vector<char>>();
58+
buf->resize(utoc_.DirectoryIndexBuffer.size());
59+
std::memcpy(buf->data(), utoc_.DirectoryIndexBuffer.data(), utoc_.DirectoryIndexBuffer.size());
60+
IStreamArchive dirIndexAr(std::make_unique<MemIStream>(std::move(buf)));
61+
62+
FIoDirectoryIndexResource dirIndexRes;
63+
dirIndexAr << dirIndexRes;
64+
65+
dirIndex_ = std::make_unique<DirectoryIndexReader>(dirIndexRes);
66+
}
67+
}
68+
69+
std::vector<std::string> SatisfactorySave::IoStoreFile::getAllAssetFilenames() const {
70+
if (dirIndex_ == nullptr) {
71+
return {};
72+
}
73+
74+
std::vector<std::string> filenames;
75+
filenames.reserve(dirIndex_->directoryEntries().size());
76+
for (const auto& entry : dirIndex_->directoryEntries()) {
77+
filenames.emplace_back(entry.first);
78+
}
79+
return filenames;
80+
}
81+
82+
std::vector<char> SatisfactorySave::IoStoreFile::readAssetFileContent(const std::string& filename) {
83+
// TODO
84+
return {};
2085
}

0 commit comments

Comments
 (0)