Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 10 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -157,11 +157,11 @@ Several modern C++20 libraries for sanely parsing Valve formats, rolled into one
</tr>
<tr><!-- empty row to disable github striped bg color --></tr>
<tr>
<td rowspan="25"><code>vpkpp</code></td>
<td rowspan="27"><code>vpkpp</code></td>
<td>007 v1.1, v1.3 (007 - Nightfire)</td>
<td align="center">✅</td>
<td align="center">❌</td>
<td rowspan="25" align="center">C<br>C#</td>
<td rowspan="27" align="center">C<br>C#</td>
</tr>
<tr><!-- empty row to disable github striped bg color --></tr>
<tr>
Expand All @@ -182,6 +182,12 @@ Several modern C++20 libraries for sanely parsing Valve formats, rolled into one
<td align="center">✅</td>
</tr>
<tr><!-- empty row to disable github striped bg color --></tr>
<tr>
<td>HOG (Descent)</td>
<td align="center">✅</td>
<td align="center">❌</td>
</tr>
<tr><!-- empty row to disable github striped bg color --></tr>
<tr>
<td>OL (Worldcraft Object Library)</td>
<td align="center">✅</td>
Expand Down Expand Up @@ -226,7 +232,7 @@ Several modern C++20 libraries for sanely parsing Valve formats, rolled into one
</tr>
<tr><!-- empty row to disable github striped bg color --></tr>
<tr>
<td>VPP (Red Faction)</td>
<td>VPP v1-2 (Red Faction)</td>
<td align="center">✅</td>
<td align="center">❌</td>
</tr>
Expand Down Expand Up @@ -373,6 +379,7 @@ found on PyPI in the [sourcepp](https://pypi.org/project/sourcepp) package.
- `steampp` is based on the [SteamAppPathProvider](https://github.com/Trico-Everfire/SteamAppPathProvider) library by [@Trico Everfire](https://github.com/Trico-Everfire) and [Momentum Mod](https://momentum-mod.org) contributors.
- `vpkpp`'s 007 parser is based on [reverse-engineering work](https://raw.githubusercontent.com/SmileyAG/dumpster/refs/heads/src_jb007nightfirepc_alurazoe/file_format_analysis.txt) by Alhexx.
- `vpkpp`'s GCF parser was contributed by [@bt](https://github.com/caatge) and [@ymgve](https://github.com/ymgve).
- `vpkpp`'s HOG parser was contributed by [@erysdren](https://github.com/erysdren).
- `vpkpp`'s OL parser is based on [reverse-engineering work](https://github.com/erysdren/scratch/blob/main/kaitai/worldcraft_ol.ksy) by [@erysdren](https://github.com/erysdren).
- `vpkpp`'s ORE parser is based on [reverse-engineering work](https://github.com/erysdren/narbacular-drop-tools) by [@erysdren](https://github.com/erysdren).
- `vpkpp`'s VPP parser was contributed by [@erysdren](https://github.com/erysdren).
Expand Down
12 changes: 9 additions & 3 deletions docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -140,11 +140,11 @@ Several modern C++20 libraries for sanely parsing Valve formats, rolled into one
<td align="center">❌</td>
</tr>
<tr>
<td rowspan="13"><code>vpkpp</code></td>
<td rowspan="14"><code>vpkpp</code></td>
<td>007 v1.1, v1.3 (007 - Nightfire)</td>
<td align="center">✅</td>
<td align="center">❌</td>
<td rowspan="13" align="center">C<br>C#</td>
<td rowspan="14" align="center">C<br>C#</td>
</tr>
<tr>
<td>FPX v10 (Tactical Intervention)</td>
Expand All @@ -161,6 +161,11 @@ Several modern C++20 libraries for sanely parsing Valve formats, rolled into one
<td align="center">✅</td>
<td align="center">✅</td>
</tr>
<tr>
<td>HOG (Descent)</td>
<td align="center">✅</td>
<td align="center">❌</td>
</tr>
<tr>
<td>OL (Worldcraft Object Library)</td>
<td align="center">✅</td>
Expand Down Expand Up @@ -199,7 +204,7 @@ Several modern C++20 libraries for sanely parsing Valve formats, rolled into one
<td align="center">✅</td>
</tr>
<tr>
<td>VPP (Red Faction)</td>
<td>VPP v1-2 (Red Faction)</td>
<td align="center">✅</td>
<td align="center">❌</td>
</tr>
Expand Down Expand Up @@ -329,6 +334,7 @@ found on PyPI in the [sourcepp](https://pypi.org/project/sourcepp) package.
- `steampp` is based on the [SteamAppPathProvider](https://github.com/Trico-Everfire/SteamAppPathProvider) library by [@Trico Everfire](https://github.com/Trico-Everfire) and [Momentum Mod](https://momentum-mod.org) contributors.
- `vpkpp`'s 007 parser is based on [reverse-engineering work](https://raw.githubusercontent.com/SmileyAG/dumpster/refs/heads/src_jb007nightfirepc_alurazoe/file_format_analysis.txt) by Alhexx.
- `vpkpp`'s GCF parser was contributed by [@bt](https://github.com/caatge) and [@ymgve](https://github.com/ymgve).
- `vpkpp`'s HOG parser was contributed by [@erysdren](https://github.com/erysdren).
- `vpkpp`'s OL parser is based on [reverse-engineering work](https://github.com/erysdren/scratch/blob/main/kaitai/worldcraft_ol.ksy) by [@erysdren](https://github.com/erysdren).
- `vpkpp`'s ORE parser is based on [reverse-engineering work](https://github.com/erysdren/narbacular-drop-tools) by [@erysdren](https://github.com/erysdren).
- `vpkpp`'s VPP parser was contributed by [@erysdren](https://github.com/erysdren).
Expand Down
36 changes: 36 additions & 0 deletions include/vpkpp/format/HOG.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
#pragma once

#include "../PackFile.h"

namespace vpkpp {

constexpr std::string_view HOG_SIGNATURE = "DHF";
constexpr std::string_view HOG_EXTENSION = ".hog";

class HOG : public PackFileReadOnly {
public:
/// Open a HOG file
[[nodiscard]] static std::unique_ptr<PackFile> open(const std::string& path, const EntryCallback& callback = nullptr);

static constexpr inline std::string_view GUID = "FDE9941424FF4EC1BC4C90A7DA52AF87";

[[nodiscard]] constexpr std::string_view getGUID() const override {
return HOG::GUID;
}

[[nodiscard]] constexpr bool isCaseSensitive() const override {
return true;
}

[[nodiscard]] std::optional<std::vector<std::byte>> readEntry(const std::string& path_) const override;

[[nodiscard]] Attribute getSupportedEntryAttributes() const override;

protected:
using PackFileReadOnly::PackFileReadOnly;

private:
VPKPP_REGISTER_PACKFILE_OPEN(HOG_EXTENSION, &HOG::open);
};

} // namespace vpkpp
1 change: 1 addition & 0 deletions include/vpkpp/vpkpp.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#include "format/FPX.h"
#include "format/GCF.h"
#include "format/GMA.h"
#include "format/HOG.h"
#include "format/OO7.h"
#include "format/OL.h"
#include "format/ORE.h"
Expand Down
2 changes: 2 additions & 0 deletions src/vpkpp/_vpkpp.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ add_pretty_parser(vpkpp
"${CMAKE_CURRENT_SOURCE_DIR}/include/vpkpp/format/FPX.h"
"${CMAKE_CURRENT_SOURCE_DIR}/include/vpkpp/format/GCF.h"
"${CMAKE_CURRENT_SOURCE_DIR}/include/vpkpp/format/GMA.h"
"${CMAKE_CURRENT_SOURCE_DIR}/include/vpkpp/format/HOG.h"
"${CMAKE_CURRENT_SOURCE_DIR}/include/vpkpp/format/OL.h"
"${CMAKE_CURRENT_SOURCE_DIR}/include/vpkpp/format/OO7.h"
"${CMAKE_CURRENT_SOURCE_DIR}/include/vpkpp/format/ORE.h"
Expand All @@ -24,6 +25,7 @@ add_pretty_parser(vpkpp
"${CMAKE_CURRENT_LIST_DIR}/format/FPX.cpp"
"${CMAKE_CURRENT_LIST_DIR}/format/GCF.cpp"
"${CMAKE_CURRENT_LIST_DIR}/format/GMA.cpp"
"${CMAKE_CURRENT_LIST_DIR}/format/HOG.cpp"
"${CMAKE_CURRENT_LIST_DIR}/format/OL.cpp"
"${CMAKE_CURRENT_LIST_DIR}/format/OO7.cpp"
"${CMAKE_CURRENT_LIST_DIR}/format/ORE.cpp"
Expand Down
80 changes: 80 additions & 0 deletions src/vpkpp/format/HOG.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
#include <vpkpp/format/HOG.h>

#include <filesystem>

#include <FileStream.h>

using namespace sourcepp;
using namespace vpkpp;

std::unique_ptr<PackFile> HOG::open(const std::string& path, const EntryCallback& callback) {
if (!std::filesystem::exists(path)) {
// File does not exist
return nullptr;
}

auto* hog = new HOG{path};
auto packFile = std::unique_ptr<PackFile>(hog);

FileStream reader{hog->fullFilePath};
reader.seek_in(0);

// Verify signature
if (const auto signature = reader.read_string(3); signature != HOG_SIGNATURE) {
return nullptr;
}

// Read file entries
while (true) {
// Create new entry
Entry entry = createNewEntry();

// Get file path
const auto entryPath = hog->cleanEntryPath(reader.read_string(13));

// Check if we're at EOF (must perform the check after reading beyond file bounds)
if (!reader) {
break;
}

// Get file size and offset
entry.length = reader.read<uint32_t>();
entry.offset = reader.tell_in();

// Seek past file data
reader.seek_in_u(entry.offset + entry.length);

// Put it in
hog->entries.emplace(entryPath, entry);

if (callback) {
callback(entryPath, entry);
}
}

return packFile;
}

std::optional<std::vector<std::byte>> HOG::readEntry(const std::string& path_) const {
auto path = this->cleanEntryPath(path_);
auto entry = this->findEntry(path);
if (!entry) {
return std::nullopt;
}
if (entry->unbaked) {
return readUnbakedEntry(*entry);
}

// It's baked into the file on disk
FileStream stream{this->fullFilePath};
if (!stream) {
return std::nullopt;
}
stream.seek_in_u(entry->offset);
return stream.read_bytes(entry->length);
}

Attribute HOG::getSupportedEntryAttributes() const {
using enum Attribute;
return LENGTH;
}
6 changes: 6 additions & 0 deletions test/vpkpp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,12 @@
using namespace sourcepp;
using namespace vpkpp;

TEST(vpkpp, hog_read) {
const auto hog = PackFile::open(ASSET_ROOT "vpkpp/hog/chaos.hog");
ASSERT_TRUE(hog);
EXPECT_EQ(hog->getEntryCount(), 5);
}

TEST(vpkpp, vpp_read) {
const auto vpp = PackFile::open(ASSET_ROOT "vpkpp/vpp/v1.vpp");
ASSERT_TRUE(vpp);
Expand Down