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
5 changes: 3 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -252,9 +252,10 @@ The Python wrappers can be found on PyPI in the [sourcepp](https://pypi.org/proj
<tr>
<td>
<a href="https://quakewiki.org/wiki/.pak" target="_blank" rel="noreferrer">PAK</a> (Quake, WON Half-Life)
<br> &bull; Daikatana modifications
<br> &bull; <a href="https://store.steampowered.com/app/824600/HROT" target="_blank" rel="noreferrer">HROT</a> modifications
<br> &bull; <a href="https://en.wikipedia.org/wiki/Sin_(video_game)" target="_blank" rel="noreferrer">SiN</a> modifications
<br> &bull; SiN Reloaded modifications
<br> &bull; <a href="https://store.steampowered.com/app/824600/HROT" target="_blank" rel="noreferrer">HROT</a> modifications
</td>
<td align="center">✅</td>
<td align="center">✅</td>
Expand Down Expand Up @@ -546,8 +547,8 @@ These are only the tools and games using `sourcepp` that I know of. If you would
- HOG parser was contributed by [@erysdren](https://github.com/erysdren).
- 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).
- ORE parser is based on [reverse-engineering work](https://github.com/erysdren/narbacular-drop-tools) by [@erysdren](https://github.com/erysdren).
- PAK's Daikatana, SiN Reloaded support was contributed by [@erysdren](https://github.com/erysdren).
- REZ parser is based on [RezExtract](https://github.com/no-lith/RezExtract) by [@no-lith](https://github.com/no-lith).
- SiN Reloaded parser was contributed by [@erysdren](https://github.com/erysdren).
- VPP parser was contributed by [@erysdren](https://github.com/erysdren).
- WAD3 parser/writer was contributed by [@ozxybox](https://github.com/ozxybox).
- `vtfpp`
Expand Down
5 changes: 3 additions & 2 deletions docs/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -664,9 +664,10 @@ <h2>Supported Formats</h2>
<td>
<a href="https://quakewiki.org/wiki/.pak" target="_blank" rel="noreferrer">PAK</a> (Quake, WON Half-Life)
<ul>
<li>Daikatana modifications</li>
<li><a href="https://store.steampowered.com/app/824600/HROT" target="_blank" rel="noreferrer">HROT</a> modifications</li>
<li><a href="https://en.wikipedia.org/wiki/Sin_(video_game)" target="_blank" rel="noreferrer">SiN</a> modifications</li>
<li>SiN Reloaded modifications</li>
<li><a href="https://store.steampowered.com/app/824600/HROT" target="_blank" rel="noreferrer">HROT</a> modifications</li>
</ul>
</td>
<td>✅</td>
Expand Down Expand Up @@ -901,8 +902,8 @@ <h2>Special Thanks</h2>
<li>HOG parser was contributed by <a href="https://github.com/erysdren" target="_blank" rel="noreferrer">@erysdren</a>.</li>
<li>OL parser is based on <a href="https://github.com/erysdren/scratch/blob/main/kaitai/worldcraft_ol.ksy" target="_blank" rel="noreferrer">reverse-engineering work</a> by <a href="https://github.com/erysdren" target="_blank" rel="noreferrer">@erysdren</a>.</li>
<li>ORE parser is based on <a href="https://github.com/erysdren/narbacular-drop-tools" target="_blank" rel="noreferrer">reverse-engineering work</a> by <a href="https://github.com/erysdren" target="_blank" rel="noreferrer">@erysdren</a>.</li>
<li>PAK's Daikatana, SiN Reloaded support was contributed by <a href="https://github.com/erysdren" target="_blank" rel="noreferrer">@erysdren</a>.</li>
<li>REZ parser is based on <a href="https://github.com/no-lith/RezExtract" target="_blank" rel="noreferrer">RezExtract</a> by <a href="https://github.com/no-lith" target="_blank" rel="noreferrer">@no-lith</a>.</li>
<li>SiN Reloaded parser was contributed by <a href="https://github.com/erysdren" target="_blank" rel="noreferrer">@erysdren</a>.</li>
<li>VPP parser was contributed by <a href="https://github.com/erysdren" target="_blank" rel="noreferrer">@erysdren</a>.</li>
<li>WAD3 parser/writer was contributed by <a href="https://github.com/ozxybox" target="_blank" rel="noreferrer">@ozxybox</a>.</li>
</ul>
Expand Down
2 changes: 1 addition & 1 deletion include/kvpp/KV1.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ class KV1ElementReadable {
return static_cast<bool>(this->getValue<int32_t>());
} else if constexpr (std::same_as<V, int32_t> || std::same_as<V, int64_t>) {
V out = 0;
if (this->value.length() == 10 && this->value.starts_with("0x") && sourcepp::parser::text::isNumber(this->value.substr(2))) {
if (this->value.length() == 10 && this->value.starts_with("0x") && sourcepp::string::isNumber(this->value.substr(2))) {
sourcepp::string::toInt(this->value.substr(2), out, 16);
} else {
sourcepp::string::toInt(this->value, out);
Expand Down
2 changes: 1 addition & 1 deletion include/kvpp/KV1Writer.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ class KV1ElementWritable {
return static_cast<bool>(this->getValue<int32_t>());
} else if constexpr (std::same_as<V, int32_t> || std::same_as<V, int64_t>) {
V out = 0;
if (this->value.length() == 10 && this->value.starts_with("0x") && sourcepp::parser::text::isNumber(this->value.substr(2))) {
if (this->value.length() == 10 && this->value.starts_with("0x") && sourcepp::string::isNumber(this->value.substr(2))) {
sourcepp::string::toInt(this->value.substr(2), out, 16);
} else {
sourcepp::string::toInt(this->value, out);
Expand Down
56 changes: 56 additions & 0 deletions include/sourcepp/String.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,62 @@

namespace sourcepp::string {

/**
* If a char is a newline character.
* @param c The char.
* @return The char is a newline character.
*/
[[nodiscard]] bool isNewLine(char c);

/**
* If a string is entirely composed of newline characters.
* @param str The string.
* @return The string is entirely composed of newline characters.
*/
[[nodiscard]] bool isNewLine(std::string_view str);

/**
* If a char is a whitespace character.
* @param c The char.
* @return The char is a whitespace character.
*/
[[nodiscard]] bool isWhitespace(char c);

/**
* If a string is entirely composed of whitespace characters.
* @param str The string.
* @return The string is entirely composed of whitespace characters.
*/
[[nodiscard]] bool isWhitespace(std::string_view str);

/**
* If a char is a numerical character (0-9).
* @param c The char.
* @return The char is a numerical character.
*/
[[nodiscard]] bool isNumber(char c);

/**
* If a string is entirely composed of numerical characters (0-9).
* @param str The string.
* @return The string is entirely composed of numerical characters.
*/
[[nodiscard]] bool isNumber(std::string_view str);

/**
* If a char is a letter (a-z, A-Z) or a numerical character (0-9).
* @param c The char.
* @return The char is an alphanumeric character.
*/
[[nodiscard]] bool isAlphaNumeric(char c);

/**
* If a string is entirely composed of alphanumeric characters (a-z, A-Z, 0-9).
* @param str The string.
* @return The string is entirely composed of alphanumeric characters.
*/
[[nodiscard]] bool isAlphaNumeric(std::string_view str);

[[nodiscard]] bool contains(std::string_view s, char c);

/// A very basic regex-like pattern checker for ASCII strings. Supports:
Expand Down
42 changes: 0 additions & 42 deletions include/sourcepp/parser/Text.h
Original file line number Diff line number Diff line change
Expand Up @@ -100,48 +100,6 @@ class Tokenizer {
EscapeSequenceMap escapeSequences = getDefaultEscapeSequences();
};

/**
* If a char is a newline character.
* @param c The char.
* @return The char is a newline character.
*/
[[nodiscard]] bool isNewLine(char c);

/**
* If a string is entirely composed of newline characters.
* @param str The string.
* @return The string is entirely composed of newline characters.
*/
[[nodiscard]] bool isNewLine(std::string_view str);

/**
* If a char is a whitespace character.
* @param c The char.
* @return The char is a whitespace character.
*/
[[nodiscard]] bool isWhitespace(char c);

/**
* If a string is entirely composed of whitespace characters.
* @param str The string.
* @return The string is entirely composed of whitespace characters.
*/
[[nodiscard]] bool isWhitespace(std::string_view str);

/**
* If a char is a numerical character (0-9).
* @param c The char.
* @return The char is a numerical character.
*/
[[nodiscard]] bool isNumber(char c);

/**
* If a string is entirely composed of numerical characters (0-9).
* @param str The string.
* @return The string is entirely composed of numerical characters.
*/
[[nodiscard]] bool isNumber(std::string_view str);

/**
* Convert special characters like \\n to escaped special characters like \\\\n
* @param str The string to convert
Expand Down
1 change: 1 addition & 0 deletions include/vpkpp/format/PAK.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ class PAK : public PackFile {
public:
enum class Type {
PAK,
DAIKATANA,
SIN,
SIN_RELOADED,
HROT,
Expand Down
3 changes: 3 additions & 0 deletions lang/c/include/vpkppc/format/PAK.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ VPKPP_EXTERNVAR const char* VPKPP_SIN_EXTENSION;

VPKPP_EXTERN typedef enum {
VPKPP_PAK_TYPE_PAK,
VPKPP_PAK_TYPE_DAIKATANA,
VPKPP_PAK_TYPE_SIN,
VPKPP_PAK_TYPE_SIN_RELOADED,
VPKPP_PAK_TYPE_HROT,
Expand All @@ -39,6 +40,7 @@ namespace sourceppc::convert {
inline vpkpp::PAK::Type cast(vpkpp_pak_type_e value) {
switch (value) {
case VPKPP_PAK_TYPE_PAK: return vpkpp::PAK::Type::PAK;
case VPKPP_PAK_TYPE_DAIKATANA: return vpkpp::PAK::Type::DAIKATANA;
case VPKPP_PAK_TYPE_SIN: return vpkpp::PAK::Type::SIN;
case VPKPP_PAK_TYPE_SIN_RELOADED: return vpkpp::PAK::Type::SIN_RELOADED;
case VPKPP_PAK_TYPE_HROT: return vpkpp::PAK::Type::HROT;
Expand All @@ -49,6 +51,7 @@ inline vpkpp::PAK::Type cast(vpkpp_pak_type_e value) {
inline vpkpp_pak_type_e cast(vpkpp::PAK::Type value) {
switch (value) {
case vpkpp::PAK::Type::PAK: return VPKPP_PAK_TYPE_PAK;
case vpkpp::PAK::Type::DAIKATANA: return VPKPP_PAK_TYPE_DAIKATANA;
case vpkpp::PAK::Type::SIN: return VPKPP_PAK_TYPE_SIN;
case vpkpp::PAK::Type::SIN_RELOADED: return VPKPP_PAK_TYPE_SIN_RELOADED;
case vpkpp::PAK::Type::HROT: return VPKPP_PAK_TYPE_HROT;
Expand Down
1 change: 1 addition & 0 deletions lang/csharp/src/vpkpp/Format/PAK.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ namespace sourcepp.vpkpp.Format;
public enum PAKType
{
PAK,
DAIKATANA,
SIN,
SIN_RELOADED,
HROT,
Expand Down
1 change: 1 addition & 0 deletions lang/python/src/vpkpp.h
Original file line number Diff line number Diff line change
Expand Up @@ -243,6 +243,7 @@ inline void register_python(py::module_& m) {

py::enum_<PAK::Type>(cPAK, "Type")
.value("PAK", PAK::Type::PAK)
.value("DAIKATANA", PAK::Type::DAIKATANA)
.value("SIN", PAK::Type::SIN)
.value("SIN_RELOADED", PAK::Type::SIN_RELOADED)
.value("HROT", PAK::Type::HROT);
Expand Down
33 changes: 33 additions & 0 deletions src/sourcepp/String.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
#include <algorithm>
#include <cctype>
#include <format>
#include <locale>
#include <random>
#include <ranges>
#include <sstream>
Expand All @@ -19,6 +20,38 @@ std::mt19937& getRandomGenerator() {

using namespace sourcepp;

bool string::isNewLine(char c) {
return c == '\r' || c == '\n';
}

bool string::isNewLine(std::string_view str) {
return std::ranges::all_of(str, [](char c) { return isNewLine(c); });
}

bool string::isWhitespace(char c) {
return std::isspace(c, std::locale::classic());
}

bool string::isWhitespace(std::string_view str) {
return std::ranges::all_of(str, [](char c) { return isWhitespace(c); });
}

bool string::isNumber(char c) {
return std::isdigit(c, std::locale::classic());
}

bool string::isNumber(std::string_view str) {
return std::ranges::all_of(str, [](char c) { return isNumber(c); });
}

bool string::isAlphaNumeric(char c) {
return std::isalnum(c, std::locale::classic());
}

bool string::isAlphaNumeric(std::string_view str) {
return std::ranges::all_of(str, [](char c) { return isAlphaNumeric(c); });
}

bool string::contains(std::string_view s, char c) {
return std::ranges::find(s, c) != s.end();
}
Expand Down
49 changes: 13 additions & 36 deletions src/sourcepp/parser/Text.cpp
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
#include <sourcepp/parser/Text.h>

#include <algorithm>
#include <cctype>

#include <BufferStream.h>

Expand Down Expand Up @@ -116,30 +115,6 @@ parser::text::Tokenizer::Result parser::text::Tokenizer::parse(std::string_view
return result;
}

bool parser::text::isNewLine(char c) {
return c == '\n' || c == '\r';
}

bool parser::text::isNewLine(std::string_view str) {
return std::ranges::all_of(str, [](char c) { return isNewLine(c); });
}

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

bool parser::text::isWhitespace(std::string_view str) {
return std::ranges::all_of(str, [](char c) { return isWhitespace(c); });
}

bool parser::text::isNumber(char c) {
return std::isdigit(c);
}

bool parser::text::isNumber(std::string_view str) {
return std::ranges::all_of(str, [](char c) { return isNumber(c); });
}

std::string parser::text::convertSpecialCharsToEscapes(std::string_view str, const EscapeSequenceMap& escapeSequences) {
// Reverse escape sequences map (assume that it's bidirectional)
EscapeSequenceMap specialSequences;
Expand Down Expand Up @@ -177,13 +152,13 @@ std::string parser::text::convertEscapesToSpecialChars(std::string_view str, con
}

void parser::text::eatWhitespace(BufferStream& stream) {
while (stream.tell() < stream.size() && isWhitespace(stream.read<char>())) {}
if (stream.tell() == stream.size() && isWhitespace(stream.seek(-1, std::ios::cur).read<char>())) return;
while (stream.tell() < stream.size() && string::isWhitespace(stream.read<char>())) {}
if (stream.tell() == stream.size() && string::isWhitespace(stream.seek(-1, std::ios::cur).read<char>())) return;
stream.seek(-1, std::ios::cur);
}

void parser::text::eatSingleLineComment(BufferStream& stream) {
while (stream.tell() < stream.size() && !isNewLine(stream.read<char>())) {}
while (stream.tell() < stream.size() && !string::isNewLine(stream.read<char>())) {}
}

void parser::text::eatMultiLineComment(BufferStream& stream, std::string_view multiLineCommentEnd) {
Expand Down Expand Up @@ -248,10 +223,10 @@ std::string parser::text::readString(BufferStream& stream, std::initializer_list
out += c;
}

for (c = stream.read<char>(); (stopAtWhitespace && !isWhitespace(c)) || (!stopAtWhitespace && quoteUsed.second != c); stream >> c) {
for (c = stream.read<char>(); (stopAtWhitespace && !string::isWhitespace(c)) || (!stopAtWhitespace && quoteUsed.second != c); stream >> c) {
if (!escapeSequences.empty() && c == '\\') {
auto n = stream.read<char>();
if (stopAtWhitespace && isWhitespace(n)) {
if (stopAtWhitespace && string::isWhitespace(n)) {
break;
}
if (escapeSequences.contains(n)) {
Expand Down Expand Up @@ -287,10 +262,10 @@ std::string_view parser::text::readStringToBuffer(BufferStream& stream, BufferSt
backing << c;
}

for (c = stream.read<char>(); (stopAtWhitespace && !isWhitespace(c)) || (!stopAtWhitespace && quoteUsed.second != c); stream >> c) {
for (c = stream.read<char>(); (stopAtWhitespace && !string::isWhitespace(c)) || (!stopAtWhitespace && quoteUsed.second != c); stream >> c) {
if (!escapeSequences.empty() && c == '\\') {
auto n = stream.read<char>();
if (stopAtWhitespace && isWhitespace(n)) {
if (stopAtWhitespace && string::isWhitespace(n)) {
break;
}
if (escapeSequences.contains(n)) {
Expand All @@ -306,6 +281,7 @@ std::string_view parser::text::readStringToBuffer(BufferStream& stream, BufferSt
}

backing << '\0';
// ReSharper disable once CppRedundantCastExpression
return {reinterpret_cast<const char*>(backing.data()) + startSpan, static_cast<std::string_view::size_type>(backing.tell() - 1 - startSpan)};
}

Expand All @@ -320,11 +296,11 @@ std::string_view parser::text::readUnquotedStringToBuffer(BufferStream& stream,
std::string parser::text::readUnquotedString(BufferStream& stream, std::string_view end, const EscapeSequenceMap& escapeSequences) {
std::string out;

for (char c = stream.read<char>(); !isWhitespace(c) && end.find(c) == std::string_view::npos; c = stream.read<char>()) {
for (char c = stream.read<char>(); !string::isWhitespace(c) && end.find(c) == std::string_view::npos; c = stream.read<char>()) {
if (!escapeSequences.empty() && c == '\\') {
if (auto n = stream.read<char>(); escapeSequences.contains(n)) {
out += escapeSequences.at(n);
} else if (isWhitespace(n) || end.find(n) != std::string_view::npos) {
} else if (string::isWhitespace(n) || end.find(n) != std::string_view::npos) {
break;
} else {
out += c;
Expand All @@ -341,11 +317,11 @@ std::string parser::text::readUnquotedString(BufferStream& stream, std::string_v
std::string_view parser::text::readUnquotedStringToBuffer(BufferStream& stream, BufferStream& backing, std::string_view end, const EscapeSequenceMap& escapeSequences) {
const auto startSpan = backing.tell();

for (char c = stream.read<char>(); !isWhitespace(c) && end.find(c) == std::string_view::npos; c = stream.read<char>()) {
for (char c = stream.read<char>(); !string::isWhitespace(c) && end.find(c) == std::string_view::npos; c = stream.read<char>()) {
if (!escapeSequences.empty() && c == '\\') {
if (auto n = stream.read<char>(); escapeSequences.contains(n)) {
backing << escapeSequences.at(n);
} else if (isWhitespace(n) || end.find(n) != std::string_view::npos) {
} else if (string::isWhitespace(n) || end.find(n) != std::string_view::npos) {
break;
} else {
backing << c << n;
Expand All @@ -356,5 +332,6 @@ std::string_view parser::text::readUnquotedStringToBuffer(BufferStream& stream,
}

backing << '\0';
// ReSharper disable once CppRedundantCastExpression
return {reinterpret_cast<const char*>(backing.data()) + startSpan, static_cast<std::string_view::size_type>(backing.tell() - 1 - startSpan)};
}
Loading
Loading