diff --git a/CMakeLists.txt b/CMakeLists.txt index be785d145..86028020b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -84,7 +84,7 @@ add_sourcepp_library(dmxpp) add_sourcepp_library(fgdpp) add_sourcepp_library(kvpp) add_sourcepp_library(mdlpp) -add_sourcepp_library(steampp) +add_sourcepp_library(steampp C) add_sourcepp_library(vicepp C CSHARP) add_sourcepp_library(vpkpp C CSHARP) add_sourcepp_library(vtfpp) diff --git a/README.md b/README.md index 480d1500b..cfcd336a1 100644 --- a/README.md +++ b/README.md @@ -89,7 +89,7 @@ Several modern C++20 libraries for sanely parsing Valve formats, rolled into one n/a ✅ n/a - + C Based on the SteamAppPathProvider library by @Trice Everfire and Momentum Mod contributors. diff --git a/lang/c/include/sourceppc/Convert.hpp b/lang/c/include/sourceppc/Convert.hpp index f045b9e6d..5867fbd47 100644 --- a/lang/c/include/sourceppc/Convert.hpp +++ b/lang/c/include/sourceppc/Convert.hpp @@ -10,6 +10,7 @@ #include #include +#include #include #include "Buffer.h" @@ -27,4 +28,16 @@ size_t writeStringToMem(std::string_view str, char* buffer, size_t bufferLen); size_t writeVectorToMem(const std::vector& vec, unsigned char* buffer, size_t bufferLen); +// requires clause copied from BufferStream - not including here because that header is HEAVY +template +requires std::is_trivial_v && std::is_standard_layout_v && (!std::is_pointer_v) +size_t writeVectorToMem(const std::vector& vec, T* buffer, size_t bufferLen) { + if (vec.size() >= bufferLen) { + std::memcpy(buffer, vec.data(), sizeof(T) * bufferLen); + return bufferLen; + } + std::memcpy(buffer, vec.data(), sizeof(T) * vec.size()); + return vec.size(); +} + } // namespace Convert diff --git a/lang/c/include/steamppc/Convert.hpp b/lang/c/include/steamppc/Convert.hpp new file mode 100644 index 000000000..32f308739 --- /dev/null +++ b/lang/c/include/steamppc/Convert.hpp @@ -0,0 +1,23 @@ +#pragma once + +/* + * This is a header designed to be included in C++ source code. + * It should not be included in applications using any C wrapper libraries! + */ +#ifndef __cplusplus +#error "This header can only be used in C++!" +#endif + +#include "steampp.h" + +namespace steampp { + +class Steam; + +} // namespace steampp + +namespace Convert { + +steampp::Steam* steam(steampp_steam_handle_t handle); + +} // namespace Convert diff --git a/lang/c/include/steamppc/steampp.h b/lang/c/include/steamppc/steampp.h new file mode 100644 index 000000000..8066f2ad2 --- /dev/null +++ b/lang/c/include/steamppc/steampp.h @@ -0,0 +1,56 @@ +#pragma once + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef uint32_t AppID; + +typedef void* steampp_steam_handle_t; + +#ifdef __cplusplus +} // extern "C" +#endif + +// REQUIRES MANUAL FREE: steampp_steam_free +SOURCEPP_API steampp_steam_handle_t steampp_steam_new(); + +SOURCEPP_API void steampp_steam_free(steampp_steam_handle_t* handle); + +SOURCEPP_API const char* steampp_get_install_dir(steampp_steam_handle_t handle); + +// REQUIRES MANUAL FREE: sourcepp_string_array_free +SOURCEPP_API sourcepp_string_array_t steampp_get_library_dirs(steampp_steam_handle_t handle); + +// REQUIRES MANUAL FREE: sourcepp_string_free +SOURCEPP_API sourcepp_string_t steampp_get_sourcemod_dir(steampp_steam_handle_t handle); + +SOURCEPP_API size_t steampp_get_installed_apps(steampp_steam_handle_t handle, AppID* array, size_t arrayLen); + +SOURCEPP_API size_t steampp_get_installed_apps_count(steampp_steam_handle_t handle); + +SOURCEPP_API bool steampp_is_app_installed(steampp_steam_handle_t handle, AppID appID); + +SOURCEPP_API const char* steampp_get_app_name(steampp_steam_handle_t handle, AppID appID); + +// REQUIRES MANUAL FREE: sourcepp_string_free +SOURCEPP_API sourcepp_string_t steampp_get_app_install_dir(steampp_steam_handle_t handle, AppID appID); + +// REQUIRES MANUAL FREE: sourcepp_string_free +SOURCEPP_API sourcepp_string_t steampp_get_app_icon_path(steampp_steam_handle_t handle, AppID appID); + +// REQUIRES MANUAL FREE: sourcepp_string_free +SOURCEPP_API sourcepp_string_t steampp_get_app_logo_path(steampp_steam_handle_t handle, AppID appID); + +// REQUIRES MANUAL FREE: sourcepp_string_free +SOURCEPP_API sourcepp_string_t steampp_get_app_box_art_path(steampp_steam_handle_t handle, AppID appID); + +// REQUIRES MANUAL FREE: sourcepp_string_free +SOURCEPP_API sourcepp_string_t steampp_get_app_store_art_path(steampp_steam_handle_t handle, AppID appID); + +SOURCEPP_API bool steampp_is_app_using_source_engine(steampp_steam_handle_t handle, AppID appID); + +SOURCEPP_API bool steampp_is_app_using_source_2_engine(steampp_steam_handle_t handle, AppID appID); diff --git a/lang/c/include/vpkppc/Convert.hpp b/lang/c/include/vpkppc/Convert.hpp index 2cb0a8d01..8aa49c6b3 100644 --- a/lang/c/include/vpkppc/Convert.hpp +++ b/lang/c/include/vpkppc/Convert.hpp @@ -9,8 +9,9 @@ #endif #include -#include -#include + +#include "Entry.h" +#include "PackFile.h" namespace vpkpp { diff --git a/lang/c/include/vpkppc/PackFile.h b/lang/c/include/vpkppc/PackFile.h index 9127b4b51..35538b953 100644 --- a/lang/c/include/vpkppc/PackFile.h +++ b/lang/c/include/vpkppc/PackFile.h @@ -18,8 +18,10 @@ typedef void* vpkpp_pack_file_handle_t; } // extern "C" #endif +// REQUIRES MANUAL FREE: vpkpp_close SOURCEPP_API vpkpp_pack_file_handle_t vpkpp_open(const char* path); +// REQUIRES MANUAL FREE: vpkpp_close SOURCEPP_API vpkpp_pack_file_handle_t vpkpp_open_with_options(const char* path, vpkpp_pack_file_options_t options); SOURCEPP_API vpkpp_pack_file_type_e vpkpp_get_type(vpkpp_pack_file_handle_t handle); diff --git a/lang/c/include/vpkppc/format/BSP.h b/lang/c/include/vpkppc/format/BSP.h index 75cf70915..820003ff2 100644 --- a/lang/c/include/vpkppc/format/BSP.h +++ b/lang/c/include/vpkppc/format/BSP.h @@ -2,6 +2,8 @@ #include "../PackFile.h" +// REQUIRES MANUAL FREE: vpkpp_close SOURCEPP_API vpkpp_pack_file_handle_t vpkpp_bsp_open(const char* path); +// REQUIRES MANUAL FREE: vpkpp_close SOURCEPP_API vpkpp_pack_file_handle_t vpkpp_bsp_open_with_options(const char* path, vpkpp_pack_file_options_t options); diff --git a/lang/c/include/vpkppc/format/FPX.h b/lang/c/include/vpkppc/format/FPX.h index 937db1d3d..93b7f13c1 100644 --- a/lang/c/include/vpkppc/format/FPX.h +++ b/lang/c/include/vpkppc/format/FPX.h @@ -2,6 +2,8 @@ #include "../PackFile.h" +// REQUIRES MANUAL FREE: vpkpp_close SOURCEPP_API vpkpp_pack_file_handle_t vpkpp_fpx_open(const char* path); +// REQUIRES MANUAL FREE: vpkpp_close SOURCEPP_API vpkpp_pack_file_handle_t vpkpp_fpx_open_with_options(const char* path, vpkpp_pack_file_options_t options); diff --git a/lang/c/include/vpkppc/format/GCF.h b/lang/c/include/vpkppc/format/GCF.h index 3b31a4ab8..45725972c 100644 --- a/lang/c/include/vpkppc/format/GCF.h +++ b/lang/c/include/vpkppc/format/GCF.h @@ -2,6 +2,8 @@ #include "../PackFile.h" +// REQUIRES MANUAL FREE: vpkpp_close SOURCEPP_API vpkpp_pack_file_handle_t vpkpp_gcf_open(const char* path); +// REQUIRES MANUAL FREE: vpkpp_close SOURCEPP_API vpkpp_pack_file_handle_t vpkpp_gcf_open_with_options(const char* path, vpkpp_pack_file_options_t options); diff --git a/lang/c/include/vpkppc/format/GMA.h b/lang/c/include/vpkppc/format/GMA.h index bf0b71314..a8b43cc5d 100644 --- a/lang/c/include/vpkppc/format/GMA.h +++ b/lang/c/include/vpkppc/format/GMA.h @@ -2,6 +2,8 @@ #include "../PackFile.h" +// REQUIRES MANUAL FREE: vpkpp_close SOURCEPP_API vpkpp_pack_file_handle_t vpkpp_gma_open(const char* path); +// REQUIRES MANUAL FREE: vpkpp_close SOURCEPP_API vpkpp_pack_file_handle_t vpkpp_gma_open_with_options(const char* path, vpkpp_pack_file_options_t options); diff --git a/lang/c/include/vpkppc/format/GRP.h b/lang/c/include/vpkppc/format/GRP.h index ec3190a0d..44be3fc04 100644 --- a/lang/c/include/vpkppc/format/GRP.h +++ b/lang/c/include/vpkppc/format/GRP.h @@ -2,6 +2,8 @@ #include "../PackFile.h" +// REQUIRES MANUAL FREE: vpkpp_close SOURCEPP_API vpkpp_pack_file_handle_t vpkpp_grp_open(const char* path); +// REQUIRES MANUAL FREE: vpkpp_close SOURCEPP_API vpkpp_pack_file_handle_t vpkpp_grp_open_with_options(const char* path, vpkpp_pack_file_options_t options); diff --git a/lang/c/include/vpkppc/format/PAK.h b/lang/c/include/vpkppc/format/PAK.h index c26332e59..1bdb75333 100644 --- a/lang/c/include/vpkppc/format/PAK.h +++ b/lang/c/include/vpkppc/format/PAK.h @@ -2,6 +2,8 @@ #include "../PackFile.h" +// REQUIRES MANUAL FREE: vpkpp_close SOURCEPP_API vpkpp_pack_file_handle_t vpkpp_pak_open(const char* path); +// REQUIRES MANUAL FREE: vpkpp_close SOURCEPP_API vpkpp_pack_file_handle_t vpkpp_pak_open_with_options(const char* path, vpkpp_pack_file_options_t options); diff --git a/lang/c/include/vpkppc/format/PCK.h b/lang/c/include/vpkppc/format/PCK.h index 4aef9e58a..0a89f60bd 100644 --- a/lang/c/include/vpkppc/format/PCK.h +++ b/lang/c/include/vpkppc/format/PCK.h @@ -2,6 +2,8 @@ #include "../PackFile.h" +// REQUIRES MANUAL FREE: vpkpp_close SOURCEPP_API vpkpp_pack_file_handle_t vpkpp_pck_open(const char* path); +// REQUIRES MANUAL FREE: vpkpp_close SOURCEPP_API vpkpp_pack_file_handle_t vpkpp_pck_open_with_options(const char* path, vpkpp_pack_file_options_t options); diff --git a/lang/c/include/vpkppc/format/VPK.h b/lang/c/include/vpkppc/format/VPK.h index 2501a29f1..91a5934c5 100644 --- a/lang/c/include/vpkppc/format/VPK.h +++ b/lang/c/include/vpkppc/format/VPK.h @@ -2,16 +2,22 @@ #include "../PackFile.h" +// REQUIRES MANUAL FREE: vpkpp_close SOURCEPP_API vpkpp_pack_file_handle_t vpkpp_vpk_create_empty(const char* path); +// REQUIRES MANUAL FREE: vpkpp_close SOURCEPP_API vpkpp_pack_file_handle_t vpkpp_vpk_create_empty_with_options(const char* path, vpkpp_pack_file_options_t options); +// REQUIRES MANUAL FREE: vpkpp_close SOURCEPP_API vpkpp_pack_file_handle_t vpkpp_vpk_create_from_directory(const char* vpkPath, const char* contentPath, bool saveToDir); +// REQUIRES MANUAL FREE: vpkpp_close SOURCEPP_API vpkpp_pack_file_handle_t vpkpp_vpk_create_from_directory_with_options(const char* vpkPath, const char* contentPath, bool saveToDir, vpkpp_pack_file_options_t options); +// REQUIRES MANUAL FREE: vpkpp_close SOURCEPP_API vpkpp_pack_file_handle_t vpkpp_vpk_open(const char* path); +// REQUIRES MANUAL FREE: vpkpp_close SOURCEPP_API vpkpp_pack_file_handle_t vpkpp_vpk_open_with_options(const char* path, vpkpp_pack_file_options_t options); SOURCEPP_API bool vpkpp_vpk_generate_keypair_files(const char* path); diff --git a/lang/c/include/vpkppc/format/ZIP.h b/lang/c/include/vpkppc/format/ZIP.h index 00646fa05..f472c05ea 100644 --- a/lang/c/include/vpkppc/format/ZIP.h +++ b/lang/c/include/vpkppc/format/ZIP.h @@ -2,6 +2,8 @@ #include "../PackFile.h" +// REQUIRES MANUAL FREE: vpkpp_close SOURCEPP_API vpkpp_pack_file_handle_t vpkpp_zip_open(const char* path); +// REQUIRES MANUAL FREE: vpkpp_close SOURCEPP_API vpkpp_pack_file_handle_t vpkpp_zip_open_with_options(const char* path, vpkpp_pack_file_options_t options); diff --git a/lang/c/src/steamppc/Convert.cpp b/lang/c/src/steamppc/Convert.cpp new file mode 100644 index 000000000..6dfd93483 --- /dev/null +++ b/lang/c/src/steamppc/Convert.cpp @@ -0,0 +1,9 @@ +#include + +#include + +using namespace steampp; + +Steam* Convert::steam(steampp_steam_handle_t handle) { + return static_cast(handle); +} diff --git a/lang/c/src/steamppc/_steamppc.cmake b/lang/c/src/steamppc/_steamppc.cmake new file mode 100644 index 000000000..f0890e997 --- /dev/null +++ b/lang/c/src/steamppc/_steamppc.cmake @@ -0,0 +1,5 @@ +add_pretty_parser(steampp C SOURCES + "${CMAKE_CURRENT_SOURCE_DIR}/lang/c/include/steamppc/Convert.hpp" + "${CMAKE_CURRENT_SOURCE_DIR}/lang/c/include/steamppc/steampp.h" + "${CMAKE_CURRENT_LIST_DIR}/Convert.cpp" + "${CMAKE_CURRENT_LIST_DIR}/steampp.cpp") diff --git a/lang/c/src/steamppc/steampp.cpp b/lang/c/src/steamppc/steampp.cpp new file mode 100644 index 000000000..6b65d2670 --- /dev/null +++ b/lang/c/src/steamppc/steampp.cpp @@ -0,0 +1,111 @@ +#include + +#include + +#include +#include +#include + +using namespace steampp; + +SOURCEPP_API steampp_steam_handle_t steampp_steam_new() { + auto* steam = new Steam{}; + if (!*steam) { + delete steam; + steam = nullptr; + } + return steam; +} + +SOURCEPP_API void steampp_steam_free(steampp_steam_handle_t* handle) { + SOURCEPP_EARLY_RETURN(handle); + + delete Convert::steam(*handle); + *handle = nullptr; +} + +SOURCEPP_API const char* steampp_get_install_dir(steampp_steam_handle_t handle) { + SOURCEPP_EARLY_RETURN_VAL(handle, ""); + + return Convert::steam(handle)->getInstallDir().data(); +} + +SOURCEPP_API sourcepp_string_array_t steampp_get_library_dirs(steampp_steam_handle_t handle) { + SOURCEPP_EARLY_RETURN_VAL(handle, SOURCEPP_STRING_ARRAY_INVALID); + + return Convert::toStringArray(Convert::steam(handle)->getLibraryDirs()); +} + +SOURCEPP_API sourcepp_string_t steampp_get_sourcemod_dir(steampp_steam_handle_t handle) { + SOURCEPP_EARLY_RETURN_VAL(handle, SOURCEPP_STRING_INVALID); + + return Convert::toString(Convert::steam(handle)->getSourceModDir()); +} + +SOURCEPP_API size_t steampp_get_installed_apps(steampp_steam_handle_t handle, AppID* array, size_t arrayLen) { + SOURCEPP_EARLY_RETURN_VAL(handle, 0); + SOURCEPP_EARLY_RETURN_VAL(array, 0); + SOURCEPP_EARLY_RETURN_VAL(arrayLen, 0); + + return Convert::writeVectorToMem(Convert::steam(handle)->getInstalledApps(), array, arrayLen); +} + +SOURCEPP_API size_t steampp_get_installed_apps_count(steampp_steam_handle_t handle) { + SOURCEPP_EARLY_RETURN_VAL(handle, 0); + + return Convert::steam(handle)->getInstalledApps().size(); +} + +SOURCEPP_API bool steampp_is_app_installed(steampp_steam_handle_t handle, AppID appID) { + SOURCEPP_EARLY_RETURN_VAL(handle, false); + + return Convert::steam(handle)->isAppInstalled(appID); +} + +SOURCEPP_API const char* steampp_get_app_name(steampp_steam_handle_t handle, AppID appID) { + SOURCEPP_EARLY_RETURN_VAL(handle, ""); + + return Convert::steam(handle)->getAppName(appID).data(); +} + +SOURCEPP_API sourcepp_string_t steampp_get_app_install_dir(steampp_steam_handle_t handle, AppID appID) { + SOURCEPP_EARLY_RETURN_VAL(handle, SOURCEPP_STRING_INVALID); + + return Convert::toString(Convert::steam(handle)->getAppInstallDir(appID)); +} + +SOURCEPP_API sourcepp_string_t steampp_get_app_icon_path(steampp_steam_handle_t handle, AppID appID) { + SOURCEPP_EARLY_RETURN_VAL(handle, SOURCEPP_STRING_INVALID); + + return Convert::toString(Convert::steam(handle)->getAppIconPath(appID)); +} + +SOURCEPP_API sourcepp_string_t steampp_get_app_logo_path(steampp_steam_handle_t handle, AppID appID) { + SOURCEPP_EARLY_RETURN_VAL(handle, SOURCEPP_STRING_INVALID); + + return Convert::toString(Convert::steam(handle)->getAppLogoPath(appID)); +} + +SOURCEPP_API sourcepp_string_t steampp_get_app_box_art_path(steampp_steam_handle_t handle, AppID appID) { + SOURCEPP_EARLY_RETURN_VAL(handle, SOURCEPP_STRING_INVALID); + + return Convert::toString(Convert::steam(handle)->getAppBoxArtPath(appID)); +} + +SOURCEPP_API sourcepp_string_t steampp_get_app_store_art_path(steampp_steam_handle_t handle, AppID appID) { + SOURCEPP_EARLY_RETURN_VAL(handle, SOURCEPP_STRING_INVALID); + + return Convert::toString(Convert::steam(handle)->getAppStoreArtPath(appID)); +} + +SOURCEPP_API bool steampp_is_app_using_source_engine(steampp_steam_handle_t handle, AppID appID) { + SOURCEPP_EARLY_RETURN_VAL(handle, false); + + return Convert::steam(handle)->isAppUsingSourceEngine(appID); +} + +SOURCEPP_API bool steampp_is_app_using_source_2_engine(steampp_steam_handle_t handle, AppID appID) { + SOURCEPP_EARLY_RETURN_VAL(handle, false); + + return Convert::steam(handle)->isAppUsingSource2Engine(appID); +}