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
17 changes: 13 additions & 4 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ set(CMAKE_CXX_STANDARD_REQUIRED ON)
# Options (General)
option(SOURCEPP_USE_DMXPP "Build dmxpp library" ON)
option(SOURCEPP_USE_FGDPP "Build fgdpp library" ON)
option(SOURCEPP_USE_KVPP "Build kvpp library" ON)
option(SOURCEPP_USE_MDLPP "Build mdlpp library" ON)
option(SOURCEPP_USE_VICEPP "Build vicepp library" ON)
option(SOURCEPP_USE_VMFPP "Build vmfpp library" ON)
Expand Down Expand Up @@ -47,9 +48,9 @@ if(SOURCEPP_USE_VTFPP AND NOT TARGET miniz)
endif()


# stb_image
# stb
if(SOURCEPP_USE_VTFPP)
add_subdirectory("${CMAKE_CURRENT_SOURCE_DIR}/src/thirdparty/stb_image")
add_subdirectory("${CMAKE_CURRENT_SOURCE_DIR}/src/thirdparty/stb")
endif()


Expand Down Expand Up @@ -118,6 +119,14 @@ if(SOURCEPP_USE_FGDPP)
endif()


# kvpp
if(SOURCEPP_USE_KVPP)
add_pretty_parser(kvpp SOURCES
"${CMAKE_CURRENT_SOURCE_DIR}/include/kvpp/kvpp.h"
"${CMAKE_CURRENT_SOURCE_DIR}/src/kvpp/kvpp.cpp")
endif()


# mdlpp
if(SOURCEPP_USE_MDLPP)
add_pretty_parser(mdlpp SOURCES
Expand All @@ -138,7 +147,7 @@ if(SOURCEPP_USE_VICEPP)
add_pretty_parser(vicepp SOURCES
"${CMAKE_CURRENT_SOURCE_DIR}/include/vicepp/vicepp.h"
"${CMAKE_CURRENT_SOURCE_DIR}/src/vicepp/vicepp.cpp")
target_link_libraries(vicepp PRIVATE ice)
target_link_libraries(vicepp PRIVATE sourcepp_ice)
endif()


Expand All @@ -160,7 +169,7 @@ if(SOURCEPP_USE_VTFPP)
"${CMAKE_CURRENT_SOURCE_DIR}/include/vtfpp/vtfpp.h"
"${CMAKE_CURRENT_SOURCE_DIR}/src/vtfpp/ImageConversion.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/src/vtfpp/vtfpp.cpp")
target_link_libraries(vtfpp PRIVATE miniz stb_image)
target_link_libraries(vtfpp PRIVATE miniz sourcepp_stb)

# Compressonator
if(MSVC)
Expand Down
21 changes: 12 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,16 @@ Looking for more parsers in this vein? Try my other project which relies on this

### Supported Formats

| Library Name | Supports | Read | Write | Author(s) |
|--------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|:----:|:-----:|------------------------------------------------------------------------------------------------|
| dmxpp | [DMX](https://developer.valvesoftware.com/wiki/DMX) Binary v1-5 | ✅ | ❌ | [@craftablescience](https://github.com/craftablescience) |
| fgdpp | [FGD](https://developer.valvesoftware.com/wiki/FGD)<br>[TeamSpen's Unified FGD](https://github.com/TeamSpen210/HammerAddons/wiki/Unified-FGD) | ✅ | ❌ | [@Trico-Everfire](https://github.com/Trico-Everfire) |
| mdlpp | [MDL](https://developer.valvesoftware.com/wiki/MDL_(Source)) v44-49*<br>[VTX](https://developer.valvesoftware.com/wiki/VTX) v7<br>[VVD](https://developer.valvesoftware.com/wiki/VVD) v4 | ✅ | ❌ | [@craftablescience](https://github.com/craftablescience) |
| vicepp | [VICE](https://developer.valvesoftware.com/wiki/VICE) Encrypted Files | ✅ | ✅ | [@craftablescience](https://github.com/craftablescience) |
| vmfpp | [VMF](https://developer.valvesoftware.com/wiki/VMF_(Valve_Map_Format)) | ✅ | ❌ | [@Galaco](https://github.com/Galaco), [@craftablescience](https://github.com/craftablescience) |
| vtfpp | [VTF](https://developer.valvesoftware.com/wiki/VTF_(Valve_Texture_Format)) v7.0-7.6 | ✅ | ❌ | [@craftablescience](https://github.com/craftablescience) |
| Library Name | Supports | Read | Write | Author(s) |
|--------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|:----:|:-----:|------------------------------------------------------------------------------------------------|
| dmxpp | [DMX](https://developer.valvesoftware.com/wiki/DMX) Binary v1-5 | ✅ | ❌ | [@craftablescience](https://github.com/craftablescience) |
| fgdpp | [FGD](https://developer.valvesoftware.com/wiki/FGD)<br>[TeamSpen's Unified FGD](https://github.com/TeamSpen210/HammerAddons/wiki/Unified-FGD) | ✅ | ❌ | [@Trico-Everfire](https://github.com/Trico-Everfire) |
| kvpp | [KeyValues](https://developer.valvesoftware.com/wiki/KeyValues) v1[^1] | ✅ | ❌ | [@craftablescience](https://github.com/craftablescience) |
| mdlpp | [MDL](https://developer.valvesoftware.com/wiki/MDL_(Source)) v44-49[^2]<br>[VTX](https://developer.valvesoftware.com/wiki/VTX) v7<br>[VVD](https://developer.valvesoftware.com/wiki/VVD) v4 | ✅ | ❌ | [@craftablescience](https://github.com/craftablescience) |
| vicepp | [VICE](https://developer.valvesoftware.com/wiki/VICE) Encrypted Files | ✅ | ✅ | [@craftablescience](https://github.com/craftablescience) |
| vmfpp | [VMF](https://developer.valvesoftware.com/wiki/VMF_(Valve_Map_Format)) | ✅ | ❌ | [@Galaco](https://github.com/Galaco), [@craftablescience](https://github.com/craftablescience) |
| vtfpp | [VTF](https://developer.valvesoftware.com/wiki/VTF_(Valve_Texture_Format)) v7.0-7.6 | ✅ | ❌ | [@craftablescience](https://github.com/craftablescience) |

\* *Note that the MDL parser is not complete. It is usable in its current state, but it does not currently parse more complex components like animations. This parser is still in development.*
[^1]: Many text-based formats in Source are close to (if not identical to) KeyValues v1, such as [VDF](https://developer.valvesoftware.com/wiki/VDF), [VMT](https://developer.valvesoftware.com/wiki/VMT), and [VMF](https://developer.valvesoftware.com/wiki/VMF_(Valve_Map_Format)).

[^2]: The MDL parser is not complete. It is usable in its current state, but it does not currently parse more complex components like animations. This parser is still in development.
90 changes: 90 additions & 0 deletions include/kvpp/kvpp.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
#pragma once

#include <concepts>
#include <string>
#include <string_view>
#include <vector>

#include <sourcepp/math/Integer.h>

class BufferStream;

namespace kvpp {

class Element {
public:
/// Get the key associated with the element
[[nodiscard]] std::string_view getKey() const;

/// Get the value associated with the element
[[nodiscard]] std::string_view getValue() const;

/// Get the value associated with the element as the given type
template<typename T>
requires std::same_as<T, std::string_view> || std::same_as<T, bool> || std::same_as<T, int> || std::same_as<T, float>
[[nodiscard]] T getValue() const {
if constexpr (std::same_as<T, std::string_view>) {
return this->value;
} else if constexpr (std::same_as<T, bool>) {
return static_cast<bool>(this->getValue<int>());
} else if constexpr (std::same_as<T, int>) {
return std::stoi(this->value);
} else if constexpr (std::same_as<T, float>) {
return std::stof(this->value);
}
return T{};
}

/// Get the conditional associated with the element
[[nodiscard]] std::string_view getConditional() const;

/// Check if the element has one or more children with the given name
[[nodiscard]] bool hasChild(std::string_view childKey) const;

/// Get the number of child elements with the given key
[[nodiscard]] unsigned int getChildCount(std::string_view childKey) const;

/// Get the child elements of the element
[[nodiscard]] const std::vector<Element>& getChildren() const;

/// Get the child element of the element at the given index
[[nodiscard]] const Element& operator[](std::size_t index) const;

/// Get the first child element of the element with the given key
[[nodiscard]] const Element& operator[](std::string_view childKey) const;

/// Get the first child element of the element with the given key
[[nodiscard]] const Element& operator()(std::string_view childKey) const;

/// Get the nth child element of the element with the given key
[[nodiscard]] const Element& operator()(std::string_view childKey, unsigned int n) const;

/// Check if the given element is invalid
[[nodiscard]] bool isInvalid() const;

protected:
std::string key;
std::string value;
std::string conditional;
std::vector<Element> children;

Element() = default;

static const Element& getInvalid();

static void readElementsFrom(BufferStream& stream, std::vector<Element>& element, bool useEscapeSequences);
};

class KV1 : public Element {
public:
explicit KV1(std::string_view kv1Data, bool useEscapeSequences_ = false);

protected:
using Element::getKey;
using Element::getValue;
using Element::getConditional;

bool useEscapeSequences;
};

} // namespace kvpp
3 changes: 0 additions & 3 deletions include/sourcepp/math/Matrix.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,6 @@ class Matrix {

[[nodiscard]] const P* operator[](uint8_t i) const { return this->data[i]; }

// todo(c++23): convert to operator[]
[[nodiscard]] P operator()(uint8_t i, uint8_t j) const { return this->data[i][j]; }

private:
P data[M][N];
};
Expand Down
4 changes: 2 additions & 2 deletions src/dmxpp/structs/Value.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ std::string Attribute::getValue() const {
for (int i = 0; i < 4; i++) {
out += (i == 0 ? '[' : ' ');
for (int j = 0; j < 4; j++) {
out += std::to_string(mat4(i,j));
out += std::to_string(mat4[i][j]);
if (j < 3) {
out += ", ";
} else if (i < 3) {
Expand Down Expand Up @@ -236,7 +236,7 @@ std::string Attribute::getValue() const {
for (int i = 0; i < 4; i++) {
out += (i == 0 ? "" : " ");
for (int j = 0; j < 4; j++) {
out += std::to_string(matrices[m](i,j));
out += std::to_string(matrices[m][i][j]);
if (j < 3) {
out += ", ";
} else if (i < 3) {
Expand Down
186 changes: 186 additions & 0 deletions src/kvpp/kvpp.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,186 @@
#include <kvpp/kvpp.h>

#include <BufferStream.h>

using namespace kvpp;

namespace {

[[nodiscard]] bool isNewLine(char c) {
return c == '\n' || c == '\r';
}

[[nodiscard]] bool isWhitespace(char c) {
return c == ' ' || c == '\a' || c == '\f' || c == '\t' || c == '\v' || ::isNewLine(c);
}

void eatComment(BufferStream& stream) {
while (!::isNewLine(stream.read<char>())) {}
}

// NOLINTNEXTLINE(*-no-recursion)
void eatWhitespace(BufferStream& stream) {
while (::isWhitespace(stream.read<char>())) {}
stream.seek(-1, std::ios::cur);

if (stream.peek<char>(0) == '/' && (stream.peek<char>(1) == '/' || stream.peek<char>(1) == '*')) {
stream.skip(2);
::eatComment(stream);
::eatWhitespace(stream);
return;
}
}

std::string readString(BufferStream& stream, bool useEscapeSequences, char start = '\"', char end = '\"') {
std::string out;

bool stopAtWhitespace = true;
char c = stream.read<char>();
if (c == start) {
stopAtWhitespace = false;
} else {
out += c;
}

for (c = stream.read<char>(); c != end; c = stream.read<char>()) {
if (stopAtWhitespace && ::isWhitespace(c)) {
break;
}
if (useEscapeSequences && c == '\\') {
auto n = stream.read<char>();
if (stopAtWhitespace && ::isWhitespace(n)) {
break;
}
if (n == 'n') {
out += '\n';
} else if (n == 't') {
out += '\t';
} else if (n == '\\' || n == '\"') {
out += n;
} else {
out += c;
out += n;
}
} else {
out += c;
}
}

return out;
}

} // namespace

std::string_view Element::getKey() const {
return this->key;
}

std::string_view Element::getValue() const {
return this->value;
}

std::string_view Element::getConditional() const {
return this->conditional;
}

bool Element::hasChild(std::string_view childKey) const {
return !this->operator[](childKey).isInvalid();
}

unsigned int Element::getChildCount(std::string_view childKey) const {
unsigned int count = 0;
for (const Element& element : this->children) {
if (element.key == childKey) {
++count;
}
}
return count;
}

const std::vector<Element>& Element::getChildren() const {
return this->children;
}

const Element& Element::operator[](std::size_t index) const {
return this->children.at(index);
}

const Element& Element::operator[](std::string_view childKey) const {
return this->operator()(childKey);
}

const Element& Element::operator()(std::string_view childKey) const {
for (const Element& element : this->children) {
if (element.key == childKey) {
return element;
}
}
return *this;
}

const Element& Element::operator()(std::string_view childKey, unsigned int n) const {
unsigned int count = 0;
for (const Element& element : this->children) {
if (element.key == childKey) {
if (count == n) {
return element;
} else {
++count;
}
}
}
return *this;
}

bool Element::isInvalid() const {
return this == &getInvalid();
}

const Element& Element::getInvalid() {
static Element element;
return element;
}

// NOLINTNEXTLINE(*-no-recursion)
void Element::readElementsFrom(BufferStream& stream, std::vector<Element>& elements, bool useEscapeSequences) {
while (true) {
::eatWhitespace(stream);
if (static_cast<char>(stream.peek(0)) == '}') {
stream.skip();
break;
}

auto childKey = ::readString(stream, useEscapeSequences);
elements.push_back({});
auto& element = elements.back();
element.key = childKey;
::eatWhitespace(stream);

if (stream.peek<char>(0) != '{') {
element.value = ::readString(stream, useEscapeSequences);
::eatWhitespace(stream);
}
if (stream.peek<char>(0) == '[') {
element.conditional = ::readString(stream, useEscapeSequences, '[', ']');
::eatWhitespace(stream);
}
if (stream.peek<char>(0) == '{') {
stream.skip();
::eatWhitespace(stream);
if (stream.peek<char>(0) != '}') {
readElementsFrom(stream, element.children, useEscapeSequences);
} else {
stream.skip();
}
}
}
}

KV1::KV1(std::string_view kv1Data, bool useEscapeSequences_)
: Element()
, useEscapeSequences(useEscapeSequences_) {
BufferStreamReadOnly stream{kv1Data.data(), kv1Data.size()};
try {
readElementsFrom(stream, this->children, this->useEscapeSequences);
} catch (const std::overflow_error&) {}
}
2 changes: 1 addition & 1 deletion src/thirdparty/bufferstream
2 changes: 1 addition & 1 deletion src/thirdparty/ice/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
cmake_minimum_required(VERSION 3.16)
project(ice)
project(sourcepp_ice)
set(CMAKE_CXX_STANDARD 20)

# Create library
Expand Down
Loading