+/**
+ * SysOverride allows overriding a system symbol and
+ * set the return value for n-th call of it.
+ *
+ * After invoking the symbol override is disabled.
+ */
+template<class R, class F>
+struct SysOverride
+{
+ SysOverride(const char* funcName)
+ {
+ funcNameStr = funcName;
+ if(!func)
+ {
+ func = decltype(func)(dlsym(RTLD_NEXT, funcName));
+ }
+ }
+
+ void SetReturnValue( R value, uint32_t n )
+ {
+ if(overrideEnabled)
+ {
+ tet_infoline("Warning! Overriding return value is already enabled! Ignoring!\n");
+ return;
+ }
+ result = value;
+ overrideCounter = n;
+ overrideEnabled = true;
+ }
+
+ template<class... Args>
+ R Invoke(Args&&... args)
+ {
+ auto retval = func(args...);
+ if(overrideEnabled)
+ {
+ if(!overrideCounter)
+ {
+ overrideEnabled = false;
+ return result;
+ }
+ overrideCounter--;
+ }
+ return retval;
+ }
+
+ std::string funcNameStr;
+ R result{R{}};
+ F* func{nullptr};
+ uint32_t overrideCounter = 0;
+ bool overrideEnabled = false;
+};
+
+// Override fseek()
+static thread_local SysOverride<int, decltype(fseek)> call_fseek("fseek");
+extern "C" int fseek (FILE *s, long int o, int w)
+{
+ return call_fseek.Invoke( s, o, w );
+}
+
+// Override ftell()
+static thread_local SysOverride<int, decltype(ftell)> call_ftell("ftell");
+extern "C" long int ftell(FILE *s)
+{
+ return call_ftell.Invoke( s );
+}
+
+// Override fread()
+static thread_local SysOverride<int, decltype(fread)> call_fread("fread");
+extern "C" size_t fread (void *__restrict p, size_t s, size_t n, FILE *__restrict st)
+{
+ return call_fread.Invoke(p, s, n, st);
+}
+