added helper functions + restructure folders

This commit is contained in:
otavepto 2024-01-12 21:29:00 +02:00
parent 9a1b49b103
commit 705a1b925a
16 changed files with 315 additions and 83 deletions

View File

@ -165,6 +165,7 @@ release_incs_both=(
"sdk" "sdk"
"overlay_experimental" "overlay_experimental"
"crash_printer" "crash_printer"
"helpers"
) )
release_incs32=( release_incs32=(
"${release_incs_both[@]}" "${release_incs_both[@]}"
@ -216,7 +217,7 @@ release_src=(
"dll/*.cpp" "dll/*.cpp"
"$protoc_out_dir/*.cc" "$protoc_out_dir/*.cc"
"crash_printer/linux.cpp" "crash_printer/linux.cpp"
"crash_printer/common.cpp" "helpers/common_helpers.cpp"
) )
# additional #defines # additional #defines

View File

@ -199,7 +199,7 @@ set mbedtls_lib32="%deps_dir%\mbedtls\install32\lib\mbedcrypto.lib"
set mbedtls_lib64="%deps_dir%\mbedtls\install64\lib\mbedcrypto.lib" set mbedtls_lib64="%deps_dir%\mbedtls\install64\lib\mbedcrypto.lib"
:: directories to use for #include :: directories to use for #include
set release_incs_both=%ssq_inc% /I"%libs_dir%" /I"%protoc_out_dir%" /I"%libs_dir%\utfcpp" /I"controller" /I"dll" /I"sdk" /I"overlay_experimental" /I"crash_printer" set release_incs_both=%ssq_inc% /I"%libs_dir%" /I"%protoc_out_dir%" /I"%libs_dir%\utfcpp" /I"controller" /I"dll" /I"sdk" /I"overlay_experimental" /I"crash_printer" /I"helpers"
set release_incs32=%release_incs_both% %curl_inc32% %protob_inc32% %zlib_inc32% %mbedtls_inc32% set release_incs32=%release_incs_both% %curl_inc32% %protob_inc32% %zlib_inc32% %mbedtls_inc32%
set release_incs64=%release_incs_both% %curl_inc64% %protob_inc64% %zlib_inc64% %mbedtls_inc64% set release_incs64=%release_incs_both% %curl_inc64% %protob_inc64% %zlib_inc64% %mbedtls_inc64%
@ -211,7 +211,7 @@ set release_libs32=%release_libs_both% %ssq_lib32% %curl_lib32% %protob_lib32% %
set release_libs64=%release_libs_both% %ssq_lib64% %curl_lib64% %protob_lib64% %zlib_lib64% %mbedtls_lib64% set release_libs64=%release_libs_both% %ssq_lib64% %curl_lib64% %protob_lib64% %zlib_lib64% %mbedtls_lib64%
:: common source files used everywhere, just for convinience, you still have to provide a complete list later :: common source files used everywhere, just for convinience, you still have to provide a complete list later
set release_src="dll/*.cpp" "%protoc_out_dir%/*.cc" "crash_printer/win.cpp" "crash_printer/common.cpp" set release_src="dll/*.cpp" "%protoc_out_dir%/*.cc" "crash_printer/win.cpp" "helpers/common_helpers.cpp"
:: additional #defines :: additional #defines
set "common_defs=/DUTF_CPP_CPLUSPLUS=201703L /DCURL_STATICLIB /DUNICODE /D_UNICODE" set "common_defs=/DUTF_CPP_CPLUSPLUS=201703L /DCURL_STATICLIB /DUNICODE /D_UNICODE"
@ -585,7 +585,7 @@ endlocal & exit /b %_exit%
:compile_experimentalclient_ldr_32 :compile_experimentalclient_ldr_32
setlocal setlocal
echo // building executable steamclient_loader_32.exe - 32 echo // building executable steamclient_loader_32.exe - 32
set src_files="%win_resources_out_dir%\rsrc-launcher-32.res" "%tools_src_dir%\steamclient_loader\win\*.cpp" "pe_helpers\pe_helpers.cpp" set src_files="%win_resources_out_dir%\rsrc-launcher-32.res" "%tools_src_dir%\steamclient_loader\win\*.cpp" "helpers\pe_helpers.cpp" "helpers\common_helpers.cpp"
set extra_inc_dirs=/I"%tools_src_dir%\steamclient_loader\win\extra_protection" /I"pe_helpers" set extra_inc_dirs=/I"%tools_src_dir%\steamclient_loader\win\extra_protection" /I"pe_helpers"
set "extra_libs=user32.lib" set "extra_libs=user32.lib"
call :build_for 1 2 "%steamclient_dir%\steamclient_loader_32.exe" src_files extra_inc_dirs "" "%extra_libs%" call :build_for 1 2 "%steamclient_dir%\steamclient_loader_32.exe" src_files extra_inc_dirs "" "%extra_libs%"
@ -678,7 +678,7 @@ endlocal & exit /b %_exit%
:compile_experimentalclient_ldr_64 :compile_experimentalclient_ldr_64
setlocal setlocal
echo // building executable steamclient_loader_64.exe - 64 echo // building executable steamclient_loader_64.exe - 64
set src_files="%win_resources_out_dir%\rsrc-launcher-64.res" "%tools_src_dir%\steamclient_loader\win\*.cpp" "pe_helpers\pe_helpers.cpp" set src_files="%win_resources_out_dir%\rsrc-launcher-64.res" "%tools_src_dir%\steamclient_loader\win\*.cpp" "helpers\pe_helpers.cpp" "helpers\common_helpers.cpp"
set extra_inc_dirs=/I"%tools_src_dir%\steamclient_loader\win\extra_protection" /I"pe_helpers" set extra_inc_dirs=/I"%tools_src_dir%\steamclient_loader\win\extra_protection" /I"pe_helpers"
set "extra_libs=user32.lib" set "extra_libs=user32.lib"
call :build_for 0 2 "%steamclient_dir%\steamclient_loader_64.exe" src_files extra_inc_dirs "" "%extra_libs%" call :build_for 0 2 "%steamclient_dir%\steamclient_loader_64.exe" src_files extra_inc_dirs "" "%extra_libs%"

View File

@ -1,38 +0,0 @@
#include "crash_printer/common.hpp"
#include <fstream>
#include <filesystem>
static bool create_dir_impl(std::filesystem::path &dirpath)
{
if (std::filesystem::is_directory(dirpath))
{
return true;
}
else if (std::filesystem::exists(dirpath)) // a file, we can't do anything
{
return false;
}
return std::filesystem::create_directories(dirpath);
}
bool crash_printer::create_dir(const std::string &filepath)
{
std::filesystem::path dirpath = std::filesystem::path(filepath).parent_path();
return create_dir_impl(dirpath);
}
bool crash_printer::create_dir(const std::wstring &filepath)
{
std::filesystem::path dirpath = std::filesystem::path(filepath).parent_path();
return create_dir_impl(dirpath);
}
void crash_printer::write(std::ofstream &file, const std::string &data)
{
if (!file.is_open()) {
return;
}
file << data << std::endl;
}

View File

@ -1,18 +0,0 @@
#ifndef _CRASH_PRINTER_COMMON_H
#define _CRASH_PRINTER_COMMON_H
#include <string>
#include <fstream>
namespace crash_printer {
bool create_dir(const std::string &dir);
bool create_dir(const std::wstring &dir);
void write(std::ofstream &file, const std::string &data);
}
#endif // _CRASH_PRINTER_COMMON_H

View File

@ -1,6 +1,6 @@
// https://stackoverflow.com/a/1925461 // https://stackoverflow.com/a/1925461
#include "crash_printer/common.hpp" #include "common_helpers/common_helpers.hpp"
#include "crash_printer/linux.hpp" #include "crash_printer/linux.hpp"
#include <sstream> #include <sstream>
@ -46,7 +46,7 @@ static void restore_handlers()
static void exception_handler(int signal, siginfo_t *info, void *context, struct sigaction *oldact) static void exception_handler(int signal, siginfo_t *info, void *context, struct sigaction *oldact)
{ {
if (!crash_printer::create_dir(logs_filepath)) { if (!common_helpers::create_dir(logs_filepath)) {
return; return;
} }
@ -57,12 +57,12 @@ static void exception_handler(int signal, siginfo_t *info, void *context, struct
auto gm_time = std::gmtime(&t_now); auto gm_time = std::gmtime(&t_now);
auto time = std::string(std::asctime(gm_time)); auto time = std::string(std::asctime(gm_time));
time.pop_back(); // remove the trailing '\n' added by asctime time.pop_back(); // remove the trailing '\n' added by asctime
crash_printer::write(file, "[" + time + "]"); common_helpers::write(file, "[" + time + "]");
{ {
std::stringstream ss{}; std::stringstream ss{};
ss << "Unhandled exception:" << std::endl ss << "Unhandled exception:" << std::endl
<< " code: " << std::dec << signal << " (" << strsignal(signal) << ")" << std::endl; << " code: " << std::dec << signal << " (" << strsignal(signal) << ")" << std::endl;
crash_printer::write(file, ss.str()); common_helpers::write(file, ss.str());
} }
void* stack_frames[max_stack_frames]; void* stack_frames[max_stack_frames];
int stack_size = backtrace(stack_frames, max_stack_frames); int stack_size = backtrace(stack_frames, max_stack_frames);
@ -70,20 +70,20 @@ static void exception_handler(int signal, siginfo_t *info, void *context, struct
if (stack_symbols != nullptr) { if (stack_symbols != nullptr) {
// fprintf(stderr, "Stack trace:\n"); // fprintf(stderr, "Stack trace:\n");
crash_printer::write(file, "*********** Stack trace ***********"); common_helpers::write(file, "*********** Stack trace ***********");
for (int i = 1; i < stack_size; ++i) { for (int i = 1; i < stack_size; ++i) {
char *symbol = stack_symbols[i]; char *symbol = stack_symbols[i];
std::stringstream ss{}; std::stringstream ss{};
ss << "[frame " << std::dec << (stack_size - i - 1) << "]: " ss << "[frame " << std::dec << (stack_size - i - 1) << "]: "
<< std::hex << stack_frames[i] << " | " << std::hex << stack_frames[i] << " | "
<< symbol; << symbol;
crash_printer::write(file, ss.str()); common_helpers::write(file, ss.str());
} }
free(stack_symbols); free(stack_symbols);
} }
crash_printer::write(file, "**********************************\n"); common_helpers::write(file, "**********************************\n");
file.close(); file.close();
} }

View File

@ -1,4 +1,4 @@
#include "crash_printer/common.hpp" #include "common_helpers/common_helpers.hpp"
#include "crash_printer/win.hpp" #include "crash_printer/win.hpp"
#include <sstream> #include <sstream>
@ -45,7 +45,7 @@ static void print_stacktrace(std::ofstream &file, CONTEXT* context) {
stack_frame.AddrFrame.Mode = ADDRESS_MODE::AddrModeFlat; stack_frame.AddrFrame.Mode = ADDRESS_MODE::AddrModeFlat;
stack_frame.AddrStack.Mode = ADDRESS_MODE::AddrModeFlat; stack_frame.AddrStack.Mode = ADDRESS_MODE::AddrModeFlat;
crash_printer::write(file, "*********** Stack trace ***********"); common_helpers::write(file, "*********** Stack trace ***********");
std::vector<std::string> symbols{}; std::vector<std::string> symbols{};
while (true) { while (true) {
BOOL res = StackWalk( BOOL res = StackWalk(
@ -92,14 +92,14 @@ static void print_stacktrace(std::ofstream &file, CONTEXT* context) {
std::stringstream ss{}; std::stringstream ss{};
ss << "[frame " << std::dec << (idx - 1) << "]: " ss << "[frame " << std::dec << (idx - 1) << "]: "
<< s; << s;
crash_printer::write(file, ss.str()); common_helpers::write(file, ss.str());
idx--; idx--;
} }
} }
static void log_exception(LPEXCEPTION_POINTERS ex_pointers) static void log_exception(LPEXCEPTION_POINTERS ex_pointers)
{ {
if (!crash_printer::create_dir(logs_filepath)) { if (!common_helpers::create_dir(logs_filepath)) {
return; return;
} }
@ -110,17 +110,17 @@ static void log_exception(LPEXCEPTION_POINTERS ex_pointers)
auto gm_time = std::gmtime(&t_now); auto gm_time = std::gmtime(&t_now);
auto time = std::string(std::asctime(gm_time)); auto time = std::string(std::asctime(gm_time));
time.pop_back(); // remove the trailing '\n' added by asctime time.pop_back(); // remove the trailing '\n' added by asctime
crash_printer::write(file, "[" + time + "]"); common_helpers::write(file, "[" + time + "]");
{ {
std::stringstream ss{}; std::stringstream ss{};
ss << "Unhandled exception:" << std::endl ss << "Unhandled exception:" << std::endl
<< " code: 0x" << std::hex << ex_pointers->ExceptionRecord->ExceptionCode << std::endl << " code: 0x" << std::hex << ex_pointers->ExceptionRecord->ExceptionCode << std::endl
<< " @address = 0x" << std::hex << ex_pointers->ExceptionRecord->ExceptionAddress; << " @address = 0x" << std::hex << ex_pointers->ExceptionRecord->ExceptionAddress;
crash_printer::write(file, ss.str()); common_helpers::write(file, ss.str());
} }
print_stacktrace(file, ex_pointers->ContextRecord); print_stacktrace(file, ex_pointers->ContextRecord);
crash_printer::write(file, "**********************************\n"); common_helpers::write(file, "**********************************\n");
file.close(); file.close();
} }
@ -139,13 +139,13 @@ static LONG WINAPI exception_handler(LPEXCEPTION_POINTERS ex_pointers)
bool crash_printer::init(const std::wstring &log_file) bool crash_printer::init(const std::wstring &log_file)
{ {
logs_filepath = log_file; logs_filepath = log_file;
originalExceptionFilter = SetUnhandledExceptionFilter(exception_handler); originalExceptionFilter = SetUnhandledExceptionFilter(exception_handler);
return true; return true;
} }
void crash_printer::deinit() void crash_printer::deinit()
{ {
if (originalExceptionFilter) {
SetUnhandledExceptionFilter(originalExceptionFilter);
}
} }

106
helpers/common_helpers.cpp Normal file
View File

@ -0,0 +1,106 @@
#include "common_helpers/common_helpers.hpp"
#include <fstream>
#include <filesystem>
#include <cwchar>
#include <algorithm>
static bool create_dir_impl(std::filesystem::path &dirpath)
{
if (std::filesystem::is_directory(dirpath))
{
return true;
}
else if (std::filesystem::exists(dirpath)) // a file, we can't do anything
{
return false;
}
return std::filesystem::create_directories(dirpath);
}
bool common_helpers::create_dir(const std::string &filepath)
{
std::filesystem::path parent = std::filesystem::path(filepath).parent_path();
return create_dir_impl(parent);
}
bool common_helpers::create_dir(const std::wstring &filepath)
{
std::filesystem::path parent = std::filesystem::path(filepath).parent_path();
return create_dir_impl(parent);
}
void common_helpers::write(std::ofstream &file, const std::string &data)
{
if (!file.is_open()) {
return;
}
file << data << std::endl;
}
std::wstring common_helpers::str_to_w(const std::string &str)
{
auto cvt_state = std::mbstate_t();
const char* src = &str[0];
size_t conversion_bytes = std::mbsrtowcs(nullptr, &src, 0, &cvt_state);
std::wstring res(conversion_bytes + 1, L'\0');
std::mbsrtowcs(&res[0], &src, res.size(), &cvt_state);
return res.substr(0, conversion_bytes);
}
std::string common_helpers::wstr_to_a(const std::wstring &wstr)
{
auto cvt_state = std::mbstate_t();
const wchar_t* src = &wstr[0];
size_t conversion_bytes = std::wcsrtombs(nullptr, &src, 0, &cvt_state);
std::string res(conversion_bytes + 1, '\0');
std::wcsrtombs(&res[0], &src, res.size(), &cvt_state);
return res.substr(0, conversion_bytes);
}
bool common_helpers::starts_with_i(const std::string &target, const std::string &query)
{
return starts_with_i(str_to_w(target), str_to_w(query));
}
bool common_helpers::starts_with_i(const std::wstring &target, const std::wstring &query)
{
if (target.size() < query.size()) {
return false;
}
auto _target = std::wstring(target);
auto _query = std::wstring(query);
std::transform(_target.begin(), _target.end(), _target.begin(),
[](wchar_t c) { return std::tolower(c); });
std::transform(_query.begin(), _query.end(), _query.begin(),
[](wchar_t c) { return std::tolower(c); });
return _target.compare(0, _query.length(), _query) == 0;
}
bool common_helpers::ends_with_i(const std::string &target, const std::string &query)
{
return ends_with_i(str_to_w(target), str_to_w(query));
}
bool common_helpers::ends_with_i(const std::wstring &target, const std::wstring &query)
{
if (target.size() < query.size()) {
return false;
}
auto _target = std::wstring(target);
auto _query = std::wstring(query);
std::transform(_target.begin(), _target.end(), _target.begin(),
[](wchar_t c) { return std::tolower(c); });
std::transform(_query.begin(), _query.end(), _query.begin(),
[](wchar_t c) { return std::tolower(c); });
return _target.compare(_target.length() - _query.length(), _query.length(), _query) == 0;
}

View File

@ -0,0 +1,26 @@
#pragma once
#include <string>
#include <fstream>
namespace common_helpers {
bool create_dir(const std::string &dir);
bool create_dir(const std::wstring &dir);
void write(std::ofstream &file, const std::string &data);
std::wstring str_to_w(const std::string &str);
std::string wstr_to_a(const std::wstring &wstr);
bool starts_with_i(const std::string &target, const std::string &query);
bool starts_with_i(const std::wstring &target, const std::wstring &query);
bool ends_with_i(const std::string &target, const std::string &query);
bool ends_with_i(const std::wstring &target, const std::wstring &query);
}

75
helpers/dbg_log.cpp Normal file
View File

@ -0,0 +1,75 @@
#include "dbg_log/dbg_log.hpp"
#include <cstdarg>
#include <cstdio>
#include <filesystem>
#include <thread>
#include <sstream>
#include <chrono>
#include <mutex>
static FILE* out_file = nullptr;
auto const static start_time = std::chrono::system_clock::now();
static std::recursive_mutex f_mtx{};
bool dbg_log::init(const wchar_t *path)
{
auto p = std::filesystem::path(path).string();
return init(p.c_str());
}
bool dbg_log::init(const char *path)
{
#ifndef EMU_RELEASE_BUILD
std::lock_guard lk(f_mtx);
if (!out_file) {
out_file = std::fopen(path, "a");
if (!out_file) {
return false;
}
}
#endif
return true;
}
void dbg_log::write(const char *fmt, ...)
{
#ifndef EMU_RELEASE_BUILD
std::lock_guard lk(f_mtx);
if (out_file) {
auto elapsed = std::chrono::system_clock::now() - start_time;
std::stringstream ss{};
ss << "[" << std::chrono::duration_cast<std::chrono::milliseconds>(elapsed).count() << " ms] [tid: " << std::this_thread::get_id() << "] ";
auto ss_str = ss.str();
std::fprintf(out_file, ss_str.c_str());
std::va_list args;
va_start(args, fmt);
std::vfprintf(out_file, fmt, args);
va_end(args);
std::fprintf(out_file, "\n");
std::fflush(out_file);
}
#endif
}
void dbg_log::close()
{
#ifndef EMU_RELEASE_BUILD
std::lock_guard lk(f_mtx);
if (out_file) {
std::fprintf(out_file, "\nLog file closed\n\n");
std::fclose(out_file);
out_file = nullptr;
}
#endif
}

View File

@ -0,0 +1,14 @@
#pragma once
namespace dbg_log
{
bool init(const wchar_t *path);
bool init(const char *path);
void write(const char* fmt, ...);
void close();
}

View File

@ -1,6 +1,9 @@
#include "pe_helpers/pe_helpers.hpp" #include "pe_helpers/pe_helpers.hpp"
#include "common_helpers/common_helpers.hpp"
#include <vector> #include <vector>
#include <utility> #include <utility>
#include <mutex>
#include <cwchar>
static inline bool is_hex(const char c) static inline bool is_hex(const char c)
{ {
@ -361,3 +364,58 @@ size_t pe_helpers::get_pe_size(HMODULE hModule)
return size; return size;
} }
static std::wstring path_w{};
static std::string path_a{};
const std::string pe_helpers::get_current_exe_path()
{
if (path_a.empty()) {
get_current_exe_path_w();
}
return path_a;
}
const std::wstring pe_helpers::get_current_exe_path_w()
{
static std::recursive_mutex path_mtx{};
if (path_w.empty()) {
std::lock_guard lk(path_mtx);
if (path_w.empty()) {
DWORD err = GetLastError();
path_w.resize(8192);
DWORD read_chars = GetModuleFileNameW(GetModuleHandleW(nullptr), &path_w[0], (DWORD)path_w.size());
if (read_chars >= path_w.size()) {
path_w.resize(read_chars);
read_chars = GetModuleFileNameW(GetModuleHandleW(nullptr), &path_w[0], (DWORD)path_w.size());
}
if ((read_chars < path_w.size()) && path_w[0]) {
path_w = path_w.substr(0, path_w.find_last_of(L"\\/") + 1);
auto cvt_state = std::mbstate_t();
const wchar_t* src = &path_w[0];
size_t conversion_bytes = std::wcsrtombs(nullptr, &src, 0, &cvt_state);
path_a.resize(conversion_bytes + 1);
std::wcsrtombs(&path_a[0], &src, path_a.size(), &cvt_state);
path_a = path_a.substr(0, conversion_bytes);
} else {
path_w.clear();
}
SetLastError(err);
}
}
return path_w;
}
bool pe_helpers::ends_with_i(PUNICODE_STRING target, const std::wstring &query)
{
return common_helpers::ends_with_i(
std::wstring(target->Buffer, (PWSTR)((char*)target->Buffer + target->Length)),
query
);
}

View File

@ -2,6 +2,7 @@
#define WIN32_LEAN_AND_MEAN #define WIN32_LEAN_AND_MEAN
#include <windows.h> #include <windows.h>
#include <winternl.h>
#include <string> #include <string>
@ -33,4 +34,10 @@ DWORD loadlib_remote(HANDLE hProcess, const std::wstring &lib_fullpath, const ch
size_t get_pe_size(HMODULE hModule); size_t get_pe_size(HMODULE hModule);
const std::string get_current_exe_path();
const std::wstring get_current_exe_path_w();
bool ends_with_i(PUNICODE_STRING target, const std::wstring &query);
} }

View File

@ -29,7 +29,7 @@ set "common_exe_linker_args_32=%common_linker_args%"
set "common_exe_linker_args_64=%common_linker_args%" set "common_exe_linker_args_64=%common_linker_args%"
:: directories to use for #include :: directories to use for #include
set release_incs_both=%ssq_inc% /I"../../../pe_helpers" set release_incs_both=%ssq_inc% /I"../../../helpers"
set release_incs32=%release_incs_both% set release_incs32=%release_incs_both%
set release_incs64=%release_incs_both% set release_incs64=%release_incs_both%
@ -41,7 +41,7 @@ set release_libs32=%release_libs_both%
set release_libs64=%release_libs_both% set release_libs64=%release_libs_both%
:: common source files used everywhere, just for convinience, you still have to provide a complete list later :: common source files used everywhere, just for convinience, you still have to provide a complete list later
set release_src="file_dos_stub.cpp" "../../../pe_helpers/pe_helpers.cpp" set release_src="file_dos_stub.cpp" "../../../helpers/pe_helpers.cpp" "../../../helpers/common_helpers.cpp"
:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: x32 :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: x32

View File

@ -21,14 +21,15 @@ static size_t get_file_size(std::fstream &file)
} }
static std::vector<uint8_t> load_file(std::fstream &file, size_t size) static std::vector<uint8_t> load_file_partial(std::fstream &file)
{ {
try try
{ {
auto org_pos = file.tellg(); auto org_pos = file.tellg();
file.seekg(0, std::ios::beg); file.seekg(0, std::ios::beg);
std::vector<uint8_t> data(size, 0); // 2MB is enough
std::vector<uint8_t> data(2 * 1024 * 1024, 0);
file.read((char *)&data[0], data.size()); file.read((char *)&data[0], data.size());
file.seekg(org_pos, std::ios::beg); file.seekg(org_pos, std::ios::beg);
@ -67,7 +68,7 @@ int main(int argc, char* *argv)
std::cerr << "Failed get file size for file: '" << arg << "'" << std::endl; std::cerr << "Failed get file size for file: '" << arg << "'" << std::endl;
return 1; return 1;
} }
auto data = load_file(file, file_size); auto data = load_file_partial(file);
if (data.empty()) { if (data.empty()) {
std::cerr << "Failed get file data for file: '" << arg << "'" << std::endl; std::cerr << "Failed get file data for file: '" << arg << "'" << std::endl;
return 1; return 1;