From 801224749fa4d2aa0e2ee0e095983b121cfb9a23 Mon Sep 17 00:00:00 2001 From: elsid Date: Fri, 19 Sep 2025 19:26:22 +0200 Subject: [PATCH] Handle errors when computing stream size for BSA --- components/CMakeLists.txt | 2 +- components/bsa/ba2dx10file.cpp | 9 ++----- components/bsa/ba2gnrlfile.cpp | 9 ++----- components/bsa/bsafile.cpp | 8 ++---- components/bsa/compressedbsafile.cpp | 9 ++----- components/files/utils.hpp | 38 ++++++++++++++++++++++++++++ 6 files changed, 47 insertions(+), 28 deletions(-) create mode 100644 components/files/utils.hpp diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index f23d54eb56..8b48080a79 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -321,7 +321,7 @@ ENDIF() add_component_dir (files linuxpath androidpath windowspath macospath fixedpath multidircollection collections configurationmanager constrainedfilestream memorystream hash configfileparser openfile constrainedfilestreambuf conversion - istreamptr streamwithbuffer + istreamptr streamwithbuffer utils ) if(NOT CMAKE_CXX_COMPILER_ID STREQUAL "MSVC" AND NOT CMAKE_CXX_COMPILER_FRONTEND_VARIANT STREQUAL "MSVC") diff --git a/components/bsa/ba2dx10file.cpp b/components/bsa/ba2dx10file.cpp index c0922d905c..c426b258dd 100644 --- a/components/bsa/ba2dx10file.cpp +++ b/components/bsa/ba2dx10file.cpp @@ -12,6 +12,7 @@ #include #include #include +#include #include #include "ba2file.hpp" @@ -80,13 +81,7 @@ namespace Bsa std::ifstream input(mFilepath, std::ios_base::binary); - // Total archive size - std::streamoff fsize = 0; - if (input.seekg(0, std::ios_base::end)) - { - fsize = input.tellg(); - input.seekg(0); - } + const std::streamsize fsize = Files::getStreamSizeLeft(input); if (fsize < 24) // header is 24 bytes fail("File too small to be a valid BSA archive"); diff --git a/components/bsa/ba2gnrlfile.cpp b/components/bsa/ba2gnrlfile.cpp index fec7b9a255..5e8b835651 100644 --- a/components/bsa/ba2gnrlfile.cpp +++ b/components/bsa/ba2gnrlfile.cpp @@ -11,6 +11,7 @@ #include #include #include +#include #include #include "ba2file.hpp" @@ -75,13 +76,7 @@ namespace Bsa std::ifstream input(mFilepath, std::ios_base::binary); - // Total archive size - std::streamoff fsize = 0; - if (input.seekg(0, std::ios_base::end)) - { - fsize = input.tellg(); - input.seekg(0); - } + const std::streamsize fsize = Files::getStreamSizeLeft(input); if (fsize < 24) // header is 24 bytes fail("File too small to be a valid BSA archive"); diff --git a/components/bsa/bsafile.cpp b/components/bsa/bsafile.cpp index 636fda6b68..92116bced5 100644 --- a/components/bsa/bsafile.cpp +++ b/components/bsa/bsafile.cpp @@ -31,6 +31,7 @@ #include #include +#include using namespace Bsa; @@ -106,12 +107,7 @@ void BSAFile::readHeader() std::ifstream input(mFilepath, std::ios_base::binary); // Total archive size - std::streamoff fsize = 0; - if (input.seekg(0, std::ios_base::end)) - { - fsize = input.tellg(); - input.seekg(0); - } + const std::streamsize fsize = Files::getStreamSizeLeft(input); if (fsize < 12) fail("File too small to be a valid BSA archive"); diff --git a/components/bsa/compressedbsafile.cpp b/components/bsa/compressedbsafile.cpp index 64fc187def..06eee80539 100644 --- a/components/bsa/compressedbsafile.cpp +++ b/components/bsa/compressedbsafile.cpp @@ -37,6 +37,7 @@ #include #include +#include #include #include "memorystream.hpp" @@ -50,13 +51,7 @@ namespace Bsa std::ifstream input(mFilepath, std::ios_base::binary); - // Total archive size - std::streamoff fsize = 0; - if (input.seekg(0, std::ios_base::end)) - { - fsize = input.tellg(); - input.seekg(0); - } + const std::streamsize fsize = Files::getStreamSizeLeft(input); if (fsize < 36) // Header is 36 bytes fail("File too small to be a valid BSA archive"); diff --git a/components/files/utils.hpp b/components/files/utils.hpp new file mode 100644 index 0000000000..732a7d39cd --- /dev/null +++ b/components/files/utils.hpp @@ -0,0 +1,38 @@ +#ifndef COMPONENTS_FILES_UTILS_H +#define COMPONENTS_FILES_UTILS_H + +#include +#include +#include +#include +#include + +namespace Files +{ + inline std::streamsize getStreamSizeLeft(std::istream& stream) + { + const auto begin = stream.tellg(); + if (stream.fail()) + throw std::runtime_error( + std::format("Failed to get current file position: {}", std::generic_category().message(errno))); + + stream.seekg(0, std::ios_base::end); + if (stream.fail()) + throw std::runtime_error( + std::format("Failed to seek end file position: {}", std::generic_category().message(errno))); + + const auto end = stream.tellg(); + if (stream.fail()) + throw std::runtime_error( + std::format("Failed to get current file position: {}", std::generic_category().message(errno))); + + stream.seekg(begin); + if (stream.fail()) + throw std::runtime_error( + std::format("Failed to seek original file position: {}", std::generic_category().message(errno))); + + return end - begin; + } +} + +#endif