summaryrefslogtreecommitdiffstats
path: root/debian/patches/libdvdread/0001-libdvdread-PR40-enen92.patch
diff options
context:
space:
mode:
Diffstat (limited to 'debian/patches/libdvdread/0001-libdvdread-PR40-enen92.patch')
-rw-r--r--debian/patches/libdvdread/0001-libdvdread-PR40-enen92.patch1694
1 files changed, 1694 insertions, 0 deletions
diff --git a/debian/patches/libdvdread/0001-libdvdread-PR40-enen92.patch b/debian/patches/libdvdread/0001-libdvdread-PR40-enen92.patch
new file mode 100644
index 0000000..f512696
--- /dev/null
+++ b/debian/patches/libdvdread/0001-libdvdread-PR40-enen92.patch
@@ -0,0 +1,1694 @@
+From 4510e2ab7f85f87f781b59cafb0ad278c9edeb61 Mon Sep 17 00:00:00 2001
+From: Miguel Borges de Freitas <enen92@kodi.tv>
+Date: Fri, 17 Jun 2022 09:43:49 +0100
+Subject: [PATCH 1/3] Split filesystem implementation into platform based code
+
+---
+ libdvdread-embedded/Makefile.am | 17 ++-
+ libdvdread-embedded/configure.ac | 4 +
+ libdvdread-embedded/src/dvd_input.c | 58 +++-------
+ libdvdread-embedded/src/dvd_input.h | 23 +---
+ libdvdread-embedded/src/dvd_reader.c | 216 ++++++++++-------------------------
+ libdvdread-embedded/src/dvdread/dvd_filesystem.h | 124 ++++++++++++++++++++
+ libdvdread-embedded/src/dvdread/dvd_reader.h | 13 +--
+ libdvdread-embedded/src/dvdread_internal.h | 1 +
+ libdvdread-embedded/src/file/dir_posix.c | 98 ++++++++++++++++
+ libdvdread-embedded/src/file/dir_win32.c | 108 ++++++++++++++++++
+ libdvdread-embedded/src/file/file_posix.c | 113 ++++++++++++++++++
+ libdvdread-embedded/src/file/file_win32.c | 98 ++++++++++++++++
+ libdvdread-embedded/src/file/filesystem.c | 37 ++++++
+ libdvdread-embedded/src/file/filesystem.h | 46 ++++++++
+ libdvdread-embedded/src/file/stat_posix.c | 36 ++++++
+ libdvdread-embedded/src/file/stat_win32.c | 53 +++++++++
+ 16 files changed, 821 insertions(+), 224 deletions(-)
+ create mode 100644 libdvdread-embedded/src/dvdread/dvd_filesystem.h
+ create mode 100644 libdvdread-embedded/src/file/dir_posix.c
+ create mode 100644 libdvdread-embedded/src/file/dir_win32.c
+ create mode 100644 libdvdread-embedded/src/file/file_posix.c
+ create mode 100644 libdvdread-embedded/src/file/file_win32.c
+ create mode 100644 libdvdread-embedded/src/file/filesystem.c
+ create mode 100644 libdvdread-embedded/src/file/filesystem.h
+ create mode 100644 libdvdread-embedded/src/file/stat_posix.c
+ create mode 100644 libdvdread-embedded/src/file/stat_win32.c
+
+diff --git a/libdvdread-embedded/Makefile.am b/libdvdread-embedded/Makefile.am
+index f2849b8..29dca92 100644
+--- a/libdvdread-embedded/Makefile.am
++++ b/libdvdread-embedded/Makefile.am
+@@ -32,7 +32,21 @@ libdvdread_la_SOURCES = \
+ src/md5.h \
+ src/nav_print.c \
+ src/nav_read.c \
+- msvc/contrib/win32_cs.h
++ msvc/contrib/win32_cs.h \
++ src/file/filesystem.c \
++ src/file/filesystem.h
++
++if HAVE_WIN32
++libdvdread_la_SOURCES+= \
++ src/file/dir_win32.c \
++ src/file/file_win32.c \
++ src/file/stat_win32.c
++else
++libdvdread_la_SOURCES+= \
++ src/file/dir_posix.c \
++ src/file/file_posix.c \
++ src/file/stat_posix.c
++endif
+
+ libdvdread_la_LIBADD = $(CSS_LIBS)
+
+@@ -42,6 +56,7 @@ libdvdread_la_LDFLAGS = -version-info $(DVDREAD_LTVERSION) \
+ pkgincludedir = $(includedir)/dvdread
+ pkginclude_HEADERS = \
+ src/dvdread/bitreader.h \
++ src/dvdread/dvd_filesystem.h \
+ src/dvdread/dvd_reader.h \
+ src/dvdread/dvd_udf.h \
+ src/dvdread/ifo_print.h \
+diff --git a/libdvdread-embedded/configure.ac b/libdvdread-embedded/configure.ac
+index a60ef0c..e3cb5ac 100644
+--- a/libdvdread-embedded/configure.ac
++++ b/libdvdread-embedded/configure.ac
+@@ -77,6 +77,9 @@ AC_ARG_ENABLE([dlfcn],
+ [use_builtin_dlfcn=$enableval],
+ [use_builtin_dlfcn=no])
+
++# for filesystem/dir access
++AC_CHECK_HEADERS([dirent.h])
++
+ AS_IF([test x"$with_libdvdcss" = "xyes"], [
+ CSS_REQUIRES="libdvdcss >= 1.2"
+ PKG_CHECK_MODULES([CSS], [$CSS_REQUIRES])
+@@ -108,6 +111,7 @@ AS_IF([test "x$DOXYGEN" = "x"], [
+ ])
+ ])
+ AM_CONDITIONAL([APIDOC], [test "x$DOXYGEN" != "x" && test "x$enable_apidoc" = "xyes"])
++AM_CONDITIONAL(HAVE_WIN32, expr $host : '.*-mingw' >/dev/null 2>&1)
+
+ AS_IF([test "x$ac_cv_c_compiler_gnu" = "xyes"], [
+ AC_DEFINE([UNUSED], [__attribute__((unused))], [Unused parameter annotation])
+diff --git a/libdvdread-embedded/src/dvd_input.c b/libdvdread-embedded/src/dvd_input.c
+index 17f0d36..1baf8f7 100644
+--- a/libdvdread-embedded/src/dvd_input.c
++++ b/libdvdread-embedded/src/dvd_input.c
+@@ -22,16 +22,9 @@
+ #include "config.h" /* Required for HAVE_DVDCSS_DVDCSS_H */
+ #include <stdio.h> /* fprintf */
+ #include <stdlib.h> /* free */
+-#include <fcntl.h> /* open */
+-#include <unistd.h> /* lseek */
+ #include <string.h> /* strerror */
+ #include <errno.h>
+
+-#ifdef _WIN32
+-#include <windows.h>
+-#include "../msvc/contrib/win32_cs.h"
+-#endif
+-
+ #include "dvdread/dvd_reader.h" /* DVD_VIDEO_LB_LEN */
+ #include "dvdread_internal.h"
+ #include "dvd_input.h"
+@@ -40,7 +33,8 @@
+
+ /* The function pointers that is the exported interface of this file. */
+ dvd_input_t (*dvdinput_open) (void *, dvd_logger_cb *,
+- const char *,dvd_reader_stream_cb *);
++ const char *, dvd_reader_stream_cb *,
++ dvd_reader_filesystem_h *);
+ int (*dvdinput_close) (dvd_input_t);
+ int (*dvdinput_seek) (dvd_input_t, int);
+ int (*dvdinput_title) (dvd_input_t, int);
+@@ -77,22 +71,6 @@ static int (*DVDcss_read) (dvdcss_t, void *, int, int);
+ #define DVDCSS_SEEK_KEY (1 << 1)
+ #endif
+
+-#ifdef _WIN32
+-static int open_win32(const char *path, int flags)
+-{
+- wchar_t *wpath;
+- int fd;
+-
+- wpath = _utf8_to_wchar(path);
+- if (!wpath) {
+- return -1;
+- }
+- fd = _wopen(wpath, flags);
+- free(wpath);
+- return fd;
+-}
+-#endif
+-
+ /* The DVDinput handle, add stuff here for new input methods.
+ * NOTE: All members of this structure must be initialized in dvd_input_New
+ */
+@@ -104,8 +82,8 @@ struct dvd_input_s {
+ dvd_logger_cb *logcb;
+ off_t ipos;
+
+- /* dummy file input */
+- int fd;
++ /* file input */
++ dvd_file_h* file;
+ /* stream input */
+ dvd_reader_stream_cb *stream_cb;
+ };
+@@ -121,7 +99,7 @@ static dvd_input_t dvd_input_New(void *priv, dvd_logger_cb *logcb)
+
+ /* Initialize all inputs to safe defaults */
+ dev->dvdcss = NULL;
+- dev->fd = -1;
++ dev->file = NULL;
+ dev->stream_cb = NULL;
+ }
+ return dev;
+@@ -132,7 +110,8 @@ static dvd_input_t dvd_input_New(void *priv, dvd_logger_cb *logcb)
+ */
+ static dvd_input_t css_open(void *priv, dvd_logger_cb *logcb,
+ const char *target,
+- dvd_reader_stream_cb *stream_cb)
++ dvd_reader_stream_cb *stream_cb,
++ dvd_reader_filesystem_h *fs UNUSED)
+ {
+ dvd_input_t dev;
+
+@@ -210,7 +189,8 @@ static int css_close(dvd_input_t dev)
+ */
+ static dvd_input_t file_open(void *priv, dvd_logger_cb *logcb,
+ const char *target,
+- dvd_reader_stream_cb *stream_cb)
++ dvd_reader_stream_cb *stream_cb,
++ dvd_reader_filesystem_h *fs)
+ {
+ dvd_input_t dev;
+
+@@ -239,14 +219,8 @@ static dvd_input_t file_open(void *priv, dvd_logger_cb *logcb,
+ free(dev);
+ return NULL;
+ }
+-#if defined(_WIN32)
+- dev->fd = open_win32(target, O_RDONLY | O_BINARY);
+-#elif defined(__OS2__)
+- dev->fd = open(target, O_RDONLY | O_BINARY);
+-#else
+- dev->fd = open(target, O_RDONLY);
+-#endif
+- if(dev->fd < 0) {
++ dev->file = fs->file_open(fs, target);
++ if(!dev->file) {
+ char buf[256];
+ #if defined(HAVE_STRERROR_R) && defined(HAVE_DECL_STRERROR_R)
+ #ifdef STRERROR_R_CHAR_P
+@@ -279,7 +253,7 @@ static dvd_input_t file_open(void *priv, dvd_logger_cb *logcb,
+ */
+ static int file_seek(dvd_input_t dev, int blocks)
+ {
+- off_t pos = -1;
++ int64_t pos = -1;
+
+ if(dev->ipos == blocks)
+ {
+@@ -298,7 +272,7 @@ static int file_seek(dvd_input_t dev, int blocks)
+ /* Returns position as the number of bytes from beginning of file
+ * or -1 on error
+ */
+- pos = lseek(dev->fd, (off_t)blocks * (off_t)DVD_VIDEO_LB_LEN, SEEK_SET);
++ pos = dev->file->seek(dev->file, (int64_t)blocks * (int64_t)DVD_VIDEO_LB_LEN, SEEK_SET);
+
+ if (pos >= 0) {
+ dev->ipos = pos / DVD_VIDEO_LB_LEN;
+@@ -342,7 +316,7 @@ static int file_read(dvd_input_t dev, void *buffer, int blocks,
+ ret = dev->stream_cb->pf_read(dev->priv, ((char*)buffer) + bytes, len);
+ } else {
+ /* Returns the number of bytes read or -1 on error */
+- ret = read(dev->fd, ((char*)buffer) + bytes, len);
++ ret = dev->file->read(dev->file, ((char*)buffer) + bytes, len);
+ }
+
+ if(ret < 0) {
+@@ -381,8 +355,8 @@ static int file_close(dvd_input_t dev)
+
+ /* close file if it was open */
+
+- if (dev->fd >= 0) {
+- ret = close(dev->fd);
++ if (dev->file) {
++ ret = dev->file->close(dev->file);
+ }
+
+ free(dev);
+diff --git a/libdvdread-embedded/src/dvd_input.h b/libdvdread-embedded/src/dvd_input.h
+index 470cfa4..56fe170 100644
+--- a/libdvdread-embedded/src/dvd_input.h
++++ b/libdvdread-embedded/src/dvd_input.h
+@@ -31,33 +31,14 @@
+
+ typedef struct dvd_input_s *dvd_input_t;
+
+-#if defined( __MINGW32__ )
+-# undef lseek
+-# define lseek _lseeki64
+-# undef off_t
+-# define off_t off64_t
+-# undef stat
+-# define stat _stati64
+-# undef fstat
+-# define fstat _fstati64
+-# undef wstat
+-# define wstat _wstati64
+-#endif
+-
+-#ifdef __ANDROID__
+-# undef lseek
+-# define lseek lseek64
+-# undef off_t
+-# define off_t off64_t
+-#endif
+-
+ /**
+ * Function pointers that will be filled in by the input implementation.
+ * These functions provide the main API.
+ */
+ extern dvd_input_t (*dvdinput_open) (void *, dvd_logger_cb *,
+ const char *,
+- dvd_reader_stream_cb *);
++ dvd_reader_stream_cb *,
++ dvd_reader_filesystem_h *);
+ extern int (*dvdinput_close) (dvd_input_t);
+ extern int (*dvdinput_seek) (dvd_input_t, int);
+ extern int (*dvdinput_title) (dvd_input_t, int);
+diff --git a/libdvdread-embedded/src/dvd_reader.c b/libdvdread-embedded/src/dvd_reader.c
+index c4d9641..5a21056 100644
+--- a/libdvdread-embedded/src/dvd_reader.c
++++ b/libdvdread-embedded/src/dvd_reader.c
+@@ -21,17 +21,13 @@
+ */
+
+ #include "config.h"
+-#include <sys/types.h> /* off_t */
+-#include <sys/stat.h> /* stat */
+ #include <sys/time.h> /* For the timing of dvdcss_title crack. */
+-#include <fcntl.h> /* open */
+ #include <stdlib.h> /* free */
+ #include <stdio.h> /* fprintf */
+ #include <errno.h> /* errno, EIN* */
+ #include <string.h> /* memcpy, strlen */
+ #include <unistd.h> /* pclose */
+ #include <limits.h> /* PATH_MAX */
+-#include <dirent.h> /* opendir, readdir */
+ #include <ctype.h> /* isalpha */
+
+ #if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) || defined(__bsdi__) || defined(__APPLE__)
+@@ -57,11 +53,8 @@
+ #include "dvdread_internal.h"
+ #include "md5.h"
+ #include "dvdread/ifo_read.h"
++#include "file/filesystem.h"
+
+-#if defined(_WIN32)
+-# include <windows.h>
+-# include "msvc/contrib/win32_cs.h"
+-#endif
+
+ /* misc win32 helpers */
+
+@@ -81,107 +74,6 @@ static inline int _private_gettimeofday( struct timeval *tv, void *tz )
+ # endif
+ #endif /* _WIN32 */
+
+-/* Compat wrapper for stat() */
+-
+-#if defined(_WIN32)
+-/* can't re-define stat (used in both function name and struct name) */
+-typedef struct _stat64 dvdstat_t;
+-static inline int dvdstat(const char *path, dvdstat_t *st)
+-{
+- wchar_t *wpath, *it;
+- int ret;
+-
+- wpath = _utf8_to_wchar(path);
+- if (!wpath) {
+- return -1;
+- }
+-
+- /* need to strip possible trailing \\ */
+- for (it = wpath; *it; it++)
+- if ((*it == '\\' || *it == '/') && *(it+1) == 0)
+- *it = 0;
+-
+- ret = _wstat64(wpath, st);
+- free(wpath);
+- return ret;
+-}
+-#else
+-typedef struct stat dvdstat_t;
+-static inline int dvdstat(const char *file, dvdstat_t *st) {
+- return stat(file, st);
+-}
+-#endif
+-
+-#if defined(_WIN32)
+-/* UTF-8 aware version of opendir()/readdir() */
+-
+-#include <io.h>
+-
+-typedef struct {
+- intptr_t handle;
+- struct _wfinddata_t went;
+- struct dirent ent;
+-} win32_dir_t;
+-
+-win32_dir_t *win32_opendir(const char *path)
+-{
+- char *filespec;
+- wchar_t *wfilespec;
+- win32_dir_t *d;
+-
+- d = calloc(1, sizeof(*d));
+- if (!d)
+- return NULL;
+-
+- filespec = malloc(strlen(path) + 3);
+- if (!filespec) {
+- goto fail;
+- }
+- sprintf(filespec, "%s\\*", path);
+-
+- wfilespec = _utf8_to_wchar(filespec);
+- free(filespec);
+- if (!wfilespec) {
+- goto fail;
+- }
+-
+- d->handle = _wfindfirst(wfilespec, &d->went);
+- free(wfilespec);
+- if (d->handle != -1) {
+- return d;
+- }
+-
+- fail:
+- free(d);
+- return NULL;
+-}
+-
+-static struct dirent *win32_readdir(win32_dir_t *dir)
+-{
+- if (dir->went.name[0]) {
+- if (!WideCharToMultiByte(CP_UTF8, 0, dir->went.name, -1, dir->ent.d_name, sizeof(dir->ent.d_name), NULL, NULL))
+- dir->ent.d_name[0] = 0; /* allow reading next */
+- dir->went.name[0] = 0;
+- _wfindnext(dir->handle, &dir->went);
+- return &dir->ent;
+- }
+-
+- return NULL;
+-}
+-
+-static void win32_closedir(win32_dir_t *dir)
+-{
+- _findclose(dir->handle);
+- free(dir);
+-}
+-
+-#define DIR win32_dir_t
+-#define opendir win32_opendir
+-#define readdir win32_readdir
+-#define closedir win32_closedir
+-
+-#endif /* _WIN32 */
+-
+ #define DEFAULT_UDF_CACHE_LEVEL 1
+
+ struct dvd_reader_device_s {
+@@ -338,7 +230,7 @@ static dvd_reader_device_t *DVDOpenImageFile( dvd_reader_t *ctx,
+ dvd_reader_device_t *dvd;
+ dvd_input_t dev;
+
+- dev = dvdinput_open( ctx->priv, &ctx->logcb, location, stream_cb );
++ dev = dvdinput_open( ctx->priv, &ctx->logcb, location, stream_cb, ctx->fs );
+ if( !dev ) {
+ Log0(ctx,"Can't open %s for reading", location );
+ return NULL;
+@@ -452,6 +344,13 @@ static dvd_reader_t *DVDOpenCommon( void *priv,
+ if(logcb)
+ ctx->logcb = *logcb;
+
++ ctx->fs = InitInternalFilesystem();
++ if (!ctx->fs)
++ {
++ free(ctx);
++ return NULL;
++ }
++
+ #if defined(_WIN32) || defined(__OS2__)
+ int len;
+ #endif
+@@ -490,7 +389,7 @@ static dvd_reader_t *DVDOpenCommon( void *priv,
+ }
+ #endif
+
+- ret = dvdstat( path, &fileinfo );
++ ret = ctx->fs->stat(ctx->fs, path, &fileinfo);
+
+ if( ret < 0 ) {
+
+@@ -513,9 +412,9 @@ static dvd_reader_t *DVDOpenCommon( void *priv,
+ }
+
+ /* First check if this is a block/char device or a file*/
+- if( S_ISBLK( fileinfo.st_mode ) ||
+- S_ISCHR( fileinfo.st_mode ) ||
+- S_ISREG( fileinfo.st_mode ) ) {
++ if( (fileinfo.st_mode & DVD_S_IFMT) == DVD_S_IFBLK ||
++ (fileinfo.st_mode & DVD_S_IFMT) == DVD_S_IFCHR ||
++ (fileinfo.st_mode & DVD_S_IFMT) == DVD_S_IFREG ) {
+
+ /**
+ * Block devices and regular files are assumed to be DVD-Video images.
+@@ -538,7 +437,7 @@ static dvd_reader_t *DVDOpenCommon( void *priv,
+ return NULL;
+ }
+ return ctx;
+- } else if( S_ISDIR( fileinfo.st_mode ) ) {
++ } else if ((fileinfo.st_mode & DVD_S_IFMT) == DVD_S_IFDIR ) {
+ #if defined(SYS_BSD)
+ struct fstab* fe;
+ #elif defined(__sun) || defined(__linux__)
+@@ -758,6 +657,9 @@ void DVDClose( dvd_reader_t *dvd )
+ if( dvd->rd->path_root ) free( dvd->rd->path_root );
+ if( dvd->rd->udfcache ) FreeUDFCache( dvd->rd->udfcache );
+ free( dvd->rd );
++ if (dvd->fs) {
++ dvd->fs->close(dvd->fs);
++ }
+ free( dvd );
+ }
+ }
+@@ -813,24 +715,33 @@ static dvd_file_t *DVDOpenFileUDF( dvd_reader_t *ctx, const char *filename,
+ * or -1 on file not found.
+ * or -2 on path not found.
+ */
+-static int findDirFile( const char *path, const char *file, char *filename )
++static int findDirFile(dvd_reader_t *ctx, const char *path, const char *file, char *filename )
+ {
+- DIR *dir;
+- struct dirent *ent;
+-
+- dir = opendir( path );
+- if( !dir ) return -2;
++ dvd_dirent_t entry;
++ dvd_dir_h *dir = ctx->fs->dir_open(ctx->fs, path);
++ if( !dir ) {
++ Log0(ctx, "findDirFile: Could not open dir %s ", path);
++ return -2;
++ }
+
+- while( ( ent = readdir( dir ) ) != NULL ) {
+- if( !strcasecmp( ent->d_name, file ) ) {
++ int result = 0;
++ do
++ {
++ result = dir->read(dir, &entry);
++ if (result < 0) {
++ Log0(ctx, "findDirFile: Error reading dir %s (errorno: %d)", path, result);
++ return -1;
++ }
++ if( !strcasecmp( entry.d_name, file ) ) {
+ sprintf( filename, "%s%s%s", path,
+ ( ( path[ strlen( path ) - 1 ] == '/' ) ? "" : "/" ),
+- ent->d_name );
+- closedir(dir);
++ entry.d_name );
++ dir->close(dir);
+ return 0;
+ }
+- }
+- closedir(dir);
++ } while (result == 0);
++
++ dir->close(dir);
+ return -1;
+ }
+
+@@ -846,17 +757,17 @@ static int findDVDFile( dvd_reader_t *dvd, const char *file, char *filename )
+ nodirfile = file;
+ }
+
+- ret = findDirFile( dvd->rd->path_root, nodirfile, filename );
++ ret = findDirFile(dvd, dvd->rd->path_root, nodirfile, filename );
+ if( ret < 0 ) {
+ char video_path[ PATH_MAX + 1 ];
+
+ /* Try also with adding the path, just in case. */
+ sprintf( video_path, "%s/VIDEO_TS/", dvd->rd->path_root );
+- ret = findDirFile( video_path, nodirfile, filename );
++ ret = findDirFile(dvd, video_path, nodirfile, filename );
+ if( ret < 0 ) {
+ /* Try with the path, but in lower case. */
+ sprintf( video_path, "%s/video_ts/", dvd->rd->path_root );
+- ret = findDirFile( video_path, nodirfile, filename );
++ ret = findDirFile(dvd, video_path, nodirfile, filename );
+ if( ret < 0 ) {
+ return 0;
+ }
+@@ -882,7 +793,7 @@ static dvd_file_t *DVDOpenFilePath( dvd_reader_t *ctx, const char *filename )
+ return NULL;
+ }
+
+- dev = dvdinput_open( ctx->priv, &ctx->logcb, full_path, NULL );
++ dev = dvdinput_open( ctx->priv, &ctx->logcb, full_path, NULL, ctx->fs );
+ if( !dev ) {
+ Log0(ctx, "DVDOpenFilePath:dvdinput_open %s failed", full_path );
+ return NULL;
+@@ -896,13 +807,13 @@ static dvd_file_t *DVDOpenFilePath( dvd_reader_t *ctx, const char *filename )
+ }
+ dvd_file->ctx = ctx;
+
+- if( dvdstat( full_path, &fileinfo ) < 0 ) {
++ if (ctx->fs->stat(ctx->fs, full_path, &fileinfo) < 0) {
+ Log0(ctx, "Can't stat() %s.", filename );
+ free( dvd_file );
+ dvdinput_close( dev );
+ return NULL;
+ }
+- dvd_file->title_sizes[ 0 ] = fileinfo.st_size / DVD_VIDEO_LB_LEN;
++ dvd_file->title_sizes[ 0 ] = fileinfo.size / DVD_VIDEO_LB_LEN;
+ dvd_file->title_devs[ 0 ] = dev;
+ dvd_file->filesize = dvd_file->title_sizes[ 0 ];
+
+@@ -979,23 +890,22 @@ static dvd_file_t *DVDOpenVOBPath( dvd_reader_t *ctx, int title, int menu )
+ return NULL;
+ }
+
+- dev = dvdinput_open( ctx->priv, &ctx->logcb, full_path, NULL );
++ dev = dvdinput_open( ctx->priv, &ctx->logcb, full_path, NULL, ctx->fs );
+ if( dev == NULL ) {
+ free( dvd_file );
+ return NULL;
+ }
+
+- if( dvdstat( full_path, &fileinfo ) < 0 ) {
++ if (ctx->fs->stat(ctx->fs, full_path, &fileinfo) > 0) {
+ Log0(ctx, "Can't stat() %s.", filename );
+ dvdinput_close(dev);
+ free( dvd_file );
+ return NULL;
+ }
+- dvd_file->title_sizes[ 0 ] = fileinfo.st_size / DVD_VIDEO_LB_LEN;
++ dvd_file->title_sizes[ 0 ] = fileinfo.size / DVD_VIDEO_LB_LEN;
+ dvd_file->title_devs[ 0 ] = dev;
+ dvdinput_title( dvd_file->title_devs[0], 0);
+ dvd_file->filesize = dvd_file->title_sizes[ 0 ];
+-
+ } else {
+ int i;
+
+@@ -1006,13 +916,13 @@ static dvd_file_t *DVDOpenVOBPath( dvd_reader_t *ctx, int title, int menu )
+ break;
+ }
+
+- if( dvdstat( full_path, &fileinfo ) < 0 ) {
++ if (ctx->fs->stat(ctx->fs, full_path, &fileinfo) < 0) {
+ Log0(ctx, "Can't stat() %s.", filename );
+ break;
+ }
+
+- dvd_file->title_sizes[ i ] = fileinfo.st_size / DVD_VIDEO_LB_LEN;
+- dvd_file->title_devs[ i ] = dvdinput_open( ctx->priv, &ctx->logcb, full_path, NULL );
++ dvd_file->title_sizes[ i ] = fileinfo.size / DVD_VIDEO_LB_LEN;
++ dvd_file->title_devs[ i ] = dvdinput_open( ctx->priv, &ctx->logcb, full_path, NULL, ctx->fs );
+ dvdinput_title( dvd_file->title_devs[ i ], 0 );
+ dvd_file->filesize += dvd_file->title_sizes[ i ];
+ }
+@@ -1105,8 +1015,8 @@ static int DVDFileStatVOBUDF( dvd_reader_t *dvd, int title,
+ {
+ char filename[ MAX_UDF_FILE_NAME_LEN ];
+ uint32_t size;
+- off_t tot_size;
+- off_t parts_size[ 9 ];
++ int64_t tot_size;
++ int64_t parts_size[ 9 ];
+ int nr_parts = 0;
+ int n;
+
+@@ -1151,8 +1061,8 @@ static int DVDFileStatVOBPath( dvd_reader_t *dvd, int title,
+ char filename[ MAX_UDF_FILE_NAME_LEN ];
+ char full_path[ PATH_MAX + 1 ];
+ dvdstat_t fileinfo;
+- off_t tot_size;
+- off_t parts_size[ 9 ];
++ int64_t tot_size;
++ int64_t parts_size[ 9 ];
+ int nr_parts = 0;
+ int n;
+
+@@ -1164,14 +1074,14 @@ static int DVDFileStatVOBPath( dvd_reader_t *dvd, int title,
+ if( !findDVDFile( dvd, filename, full_path ) )
+ return -1;
+
+- if( dvdstat( full_path, &fileinfo ) < 0 ) {
++ if (dvd->fs->stat(dvd->fs, full_path, &fileinfo) < 0) {
+ Log1(dvd, "Can't stat() %s.", filename );
+ return -1;
+ }
+
+- tot_size = fileinfo.st_size;
++ tot_size = fileinfo.size;
+ nr_parts = 1;
+- parts_size[ 0 ] = fileinfo.st_size;
++ parts_size[ 0 ] = fileinfo.size;
+
+ if( !menu ) {
+ int cur;
+@@ -1180,12 +1090,12 @@ static int DVDFileStatVOBPath( dvd_reader_t *dvd, int title,
+ if( !findDVDFile( dvd, filename, full_path ) )
+ break;
+
+- if( dvdstat( full_path, &fileinfo ) < 0 ) {
++ if (dvd->fs->stat(dvd->fs, full_path, &fileinfo) < 0) {
+ Log1(dvd, "Can't stat() %s.", filename );
+ break;
+ }
+
+- parts_size[ nr_parts ] = fileinfo.st_size;
++ parts_size[ nr_parts ] = fileinfo.size;
+ tot_size += parts_size[ nr_parts ];
+ nr_parts++;
+ }
+@@ -1263,10 +1173,10 @@ int DVDFileStat( dvd_reader_t *reader, int titlenum,
+ char full_path[ PATH_MAX + 1 ];
+
+ if( findDVDFile( reader, filename, full_path ) ) {
+- if( dvdstat( full_path, &fileinfo ) < 0 )
++ if (reader->fs->stat(reader->fs, full_path, &fileinfo) < 0)
+ Log1(reader, "Can't stat() %s.", filename );
+ else {
+- statbuf->size = fileinfo.st_size;
++ statbuf->size = fileinfo.size;
+ statbuf->nr_parts = 1;
+ statbuf->parts_size[ 0 ] = statbuf->size;
+ return 0;
+@@ -1318,8 +1228,8 @@ static int DVDReadBlocksUDF( const dvd_file_t *dvd_file, uint32_t offset,
+
+ /* Copy the cache at a specified offset into data. offset and block_count
+ * must be converted into bytes */
+- memcpy( data, dvd_file->cache + (off_t)offset * (off_t)DVD_VIDEO_LB_LEN,
+- (off_t)block_count * (off_t)DVD_VIDEO_LB_LEN );
++ memcpy( data, dvd_file->cache + (int64_t)offset * (int64_t)DVD_VIDEO_LB_LEN,
++ (int64_t)block_count * (int64_t)DVD_VIDEO_LB_LEN );
+
+ /* return the amount of blocks copied */
+ return block_count;
+diff --git a/libdvdread-embedded/src/dvdread/dvd_filesystem.h b/libdvdread-embedded/src/dvdread/dvd_filesystem.h
+new file mode 100644
+index 0000000..291f4d9
+--- /dev/null
++++ b/libdvdread-embedded/src/dvdread/dvd_filesystem.h
+@@ -0,0 +1,124 @@
++/*
++ * This file is part of libdvdread
++ * Copyright (C) 2022 VideoLAN
++ *
++ * This file is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU Lesser General Public
++ * License as published by the Free Software Foundation; either
++ * version 2.1 of the License, or (at your option) any later version.
++ *
++ * This file is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ * Lesser General Public License for more details.
++ *
++ * You should have received a copy of the GNU Lesser General Public
++ * License along with this library. If not, see
++ * <http://www.gnu.org/licenses/>.
++ */
++
++#ifndef DVDREAD_FILESYSTEM_H_
++#define DVDREAD_FILESYSTEM_H_
++
++#include <stdint.h>
++#include <sys/types.h>
++
++/*
++ * directory access
++ */
++
++/**
++ * The dvd_dirent_t struct abstracts dirent usage from the respective platform implementation.
++ * For this reason, it only includes the parts the lib cares about (in this case d_name - the directory name)
++ */
++typedef struct
++{
++ char d_name[256];
++} dvd_dirent_t;
++
++typedef struct dvd_filesystem_dir_s dvd_dir_h;
++/**
++ * Abstraction for directory access
++ * internal - opaque handler internal to the specific implementation used to store the data type of directory stream objects.
++ * This is tipically a dir handler (e.g. a DIR* in posix)
++ * close(dvd_dir_h *dir) - called to close the directory and cleanup any alloc'd dir structures
++ * read(dvd_dir_h *dir, dvd_dirent_t *entry) - provided the dvd_dirent_t, reads the respective directory and returns -1 if the
++ * directory could not be read, 0 if successfully read.
++ */
++struct dvd_filesystem_dir_s
++{
++ void *internal;
++ void (*close)(dvd_dir_h *dir);
++ int (*read)(dvd_dir_h *dir, dvd_dirent_t *entry);
++};
++
++/*
++ * Stat access
++ */
++
++#define DVD_S_IFMT 0170000 /* These bits determine file type. */
++
++#define DVD_S_IFCHR 0020000 /* character special */
++#define DVD_S_IFDIR 0040000 /* directory */
++#define DVD_S_IFBLK 0060000 /* block special */
++#define DVD_S_IFREG 0100000 /* regular */
++
++/**
++ * Abstraction for stat buffer structure
++ * size - size of the stat'd file
++ * st_mode - file mode
++ */
++typedef struct
++{
++ off_t size;
++ unsigned int st_mode;
++} dvdstat_t;
++
++
++/*
++ * file access
++ */
++
++/**
++ * Abstraction for file access
++ * internal - opaque handler internal to the specific implementation used to store the data type of the file object.
++ * This is tipically a file reference (e.g. the file descriptor/fd)
++ * close(dvd_file_h *file) - called to close the file and cleanup any alloc'd file structs
++ * seek(dvd_file_h *file, int64_t offset, int32_t origin) - used to seek into the given file (provided the offset and the origin). Returns
++ * the position on the file after seek.
++ * read(dvd_file_h *file, char *buf, int64_t size) - used to read the file into the passed buffer, given the read size. Returns the read
++ * read from the file
++ */
++typedef struct dvd_filesystem_file_s dvd_file_h;
++struct dvd_filesystem_file_s
++{
++ void *internal;
++ int (*close) (dvd_file_h *file);
++ int64_t (*seek) (dvd_file_h *file, int64_t offset, int32_t origin);
++ ssize_t (*read) (dvd_file_h *file, char *buf, size_t size);
++};
++
++/*
++ * Filesystem implementation
++ */
++
++/**
++ * Groups all filesystem operations into a common struct. This is the struct external applications should override to
++ * provide custom filesystem implementations:
++ * internal - opaque data pointer to user data (used to convey custom data within the filesystem struct)
++ * close(dvd_reader_filesystem_h *fs) - called to destroy the filesystem implementation (free any alloc'd structs)
++ * stat(dvd_reader_filesystem_h *fs, const char *path, dvdstat_t* statbuf) - stat a file/dir provided the statbuf, initializes the dvdstat_t.
++ * dir_open(dvd_reader_filesystem_h *fs, const char* dirname) - open the provided dir, initializes dvd_dir_h
++ * file_open(dvd_reader_filesystem_h *fs, const char* filename, const char *mode) - open a file, initializes dvd_file_h
++ */
++typedef struct dvd_reader_filesystem_s dvd_reader_filesystem_h;
++struct dvd_reader_filesystem_s
++{
++ void *internal;
++ void (*close) (dvd_reader_filesystem_h *fs);
++ int (*stat) (dvd_reader_filesystem_h *fs, const char *path, dvdstat_t *statbuf);
++ dvd_dir_h* (*dir_open) (dvd_reader_filesystem_h *fs, const char *dirname);
++ dvd_file_h* (*file_open) (dvd_reader_filesystem_h *fs, const char *filename);
++};
++
++#endif /* DVDREAD_FILESYSTEM_H_ */
+diff --git a/libdvdread-embedded/src/dvdread/dvd_reader.h b/libdvdread-embedded/src/dvdread/dvd_reader.h
+index 54ef5dd..5b15704 100644
+--- a/libdvdread-embedded/src/dvdread/dvd_reader.h
++++ b/libdvdread-embedded/src/dvdread/dvd_reader.h
+@@ -23,13 +23,6 @@
+ #ifndef LIBDVDREAD_DVD_READER_H
+ #define LIBDVDREAD_DVD_READER_H
+
+-#ifdef _MSC_VER
+-#include <config.h>
+-
+-#include <stdio.h>
+-#include <stdlib.h>
+-#endif
+-
+ #include <sys/types.h>
+ #include <inttypes.h>
+ #include <stdarg.h>
+@@ -46,6 +39,12 @@
+ */
+ #include "version.h"
+
++/**
++ * Filesystem types
++ */
++#include "dvd_filesystem.h"
++
++
+ /**
+ * The length of one Logical Block of a DVD.
+ */
+diff --git a/libdvdread-embedded/src/dvdread_internal.h b/libdvdread-embedded/src/dvdread_internal.h
+index bf4e2e1..1a35059 100644
+--- a/libdvdread-embedded/src/dvdread_internal.h
++++ b/libdvdread-embedded/src/dvdread_internal.h
+@@ -39,6 +39,7 @@ struct dvd_reader_s
+ dvd_reader_device_t *rd;
+ void *priv; /* User provided context */
+ dvd_logger_cb logcb;
++ dvd_reader_filesystem_h* fs;
+ /* Set 100 flags for BUP fallback, most signifiant left
+ [0] for upper remaining VTS, [1] for the first Main + 63 VTS */
+ uint64_t ifoBUPflags[2];
+diff --git a/libdvdread-embedded/src/file/dir_posix.c b/libdvdread-embedded/src/file/dir_posix.c
+new file mode 100644
+index 0000000..f55e62a
+--- /dev/null
++++ b/libdvdread-embedded/src/file/dir_posix.c
+@@ -0,0 +1,98 @@
++/*
++ * This file is part of libdvdread
++ * Copyright (C) 2022 VideoLAN
++ *
++ * This file is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU Lesser General Public
++ * License as published by the Free Software Foundation; either
++ * version 2.1 of the License, or (at your option) any later version.
++ *
++ * This file is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ * Lesser General Public License for more details.
++ *
++ * You should have received a copy of the GNU Lesser General Public
++ * License along with this library. If not, see
++ * <http://www.gnu.org/licenses/>.
++ */
++
++#include "config.h"
++
++#include <stdlib.h>
++#include <string.h>
++#if HAVE_DIRENT_H
++#include <dirent.h>
++#endif
++
++#if defined(__GLIBC__) && defined(__GLIBC_MINOR__)
++# if __GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 24)
++# define USE_READDIR
++# include <errno.h>
++# endif
++#endif
++
++#include <dvdread/dvd_filesystem.h>
++#include "filesystem.h"
++
++void _dir_close_posix(dvd_dir_h *dir)
++{
++ if (dir) {
++ closedir((DIR *)dir->internal);
++ free(dir);
++ dir = NULL;
++ }
++}
++
++int _dir_read_posix(dvd_dir_h *dir, dvd_dirent_t *entry)
++{
++ struct dirent *p_e;
++
++#ifdef USE_READDIR
++ errno = 0;
++ p_e = readdir((DIR*)dir->internal);
++ if (!p_e && errno) {
++ return -errno;
++ }
++#else /* USE_READDIR */
++ int result;
++ struct dirent e;
++
++ result = readdir_r((DIR*)dir->internal, &e, &p_e);
++ if (result) {
++ return -result;
++ }
++#endif /* USE_READDIR */
++
++ if (p_e == NULL) {
++ return 1;
++ }
++ strncpy(entry->d_name, p_e->d_name, sizeof(entry->d_name));
++ entry->d_name[sizeof(entry->d_name) - 1] = 0;
++
++ return 0;
++}
++
++dvd_dir_h *dir_open_default(dvd_reader_filesystem_h *fs, const char* dirname)
++{
++ if (!fs)
++ return NULL;
++
++ dvd_dir_h *dir = calloc(1, sizeof(dvd_dir_h));
++
++ if (!dir) {
++ return NULL;
++ }
++
++ dir->close = _dir_close_posix;
++ dir->read = _dir_read_posix;
++
++ if ((dir->internal = opendir(dirname))) {
++ return dir;
++ }
++
++ free(dir);
++ dir = NULL;
++
++ return NULL;
++}
+diff --git a/libdvdread-embedded/src/file/dir_win32.c b/libdvdread-embedded/src/file/dir_win32.c
+new file mode 100644
+index 0000000..cb89728
+--- /dev/null
++++ b/libdvdread-embedded/src/file/dir_win32.c
+@@ -0,0 +1,108 @@
++/*
++ * This file is part of libdvdread
++ * Copyright (C) 2022 VideoLAN
++ *
++ * This file is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU Lesser General Public
++ * License as published by the Free Software Foundation; either
++ * version 2.1 of the License, or (at your option) any later version.
++ *
++ * This file is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ * Lesser General Public License for more details.
++ *
++ * You should have received a copy of the GNU Lesser General Public
++ * License along with this library. If not, see
++ * <http://www.gnu.org/licenses/>.
++ */
++
++#include <io.h>
++#include <stdlib.h>
++#include <string.h>
++#include <stdio.h>
++
++#include <windows.h>
++#include "../msvc/contrib/win32_cs.h"
++
++
++#include <dvdread/dvd_filesystem.h>
++#include "filesystem.h"
++
++
++typedef struct {
++ intptr_t handle;
++ struct _wfinddata_t went;
++} win32_dir_t;
++
++
++void _dir_close_win32(dvd_dir_h *dir)
++{
++ if (dir) {
++ _findclose(((win32_dir_t*)dir->internal)->handle);
++ free((win32_dir_t*)dir->internal);
++ free(dir);
++ dir = NULL;
++ }
++}
++
++int _dir_read_win32(dvd_dir_h *dir, dvd_dirent_t *entry)
++{
++ win32_dir_t *wdir = (win32_dir_t*)dir->internal;
++ if (wdir->went.name[0]) {
++ if (!WideCharToMultiByte(CP_UTF8, 0, wdir->went.name, -1, entry->d_name, sizeof(entry->d_name), NULL, NULL))
++ entry->d_name[0] = 0; /* allow reading next */
++ wdir->went.name[0] = 0;
++ _wfindnext(wdir->handle, &wdir->went);
++ return 0;
++ }
++ return -1;
++}
++
++dvd_dir_h *dir_open_default(dvd_reader_filesystem_h *fs, const char* dirname)
++{
++ if (!fs)
++ return NULL;
++
++ char *filespec;
++ wchar_t *wfilespec;
++ win32_dir_t *d;
++ dvd_dir_h *dir = calloc(1, sizeof(dvd_dir_h));
++
++ if (!dir) {
++ return NULL;
++ }
++
++ d = calloc(1, sizeof(*d));
++ if (!d)
++ {
++ free(dir);
++ return NULL;
++ }
++
++ filespec = malloc(strlen(dirname) + 3);
++ if (!filespec) {
++ goto fail;
++ }
++ sprintf(filespec, "%s\\*", dirname);
++
++ wfilespec = _utf8_to_wchar(filespec);
++ free(filespec);
++ if (!wfilespec) {
++ goto fail;
++ }
++
++ d->handle = _wfindfirst(wfilespec, &d->went);
++ free(wfilespec);
++ if (d->handle != -1) {
++ dir->internal = (void*)d;
++ dir->close = _dir_close_win32;
++ dir->read = _dir_read_win32;
++ return dir;
++ }
++
++ fail:
++ free(d);
++ free(dir);
++ return NULL;
++}
+diff --git a/libdvdread-embedded/src/file/file_posix.c b/libdvdread-embedded/src/file/file_posix.c
+new file mode 100644
+index 0000000..cbdbd58
+--- /dev/null
++++ b/libdvdread-embedded/src/file/file_posix.c
+@@ -0,0 +1,113 @@
++/*
++ * This file is part of libdvdread
++ * Copyright (C) 2022 VideoLAN
++ *
++ * This file is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU Lesser General Public
++ * License as published by the Free Software Foundation; either
++ * version 2.1 of the License, or (at your option) any later version.
++ *
++ * This file is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ * Lesser General Public License for more details.
++ *
++ * You should have received a copy of the GNU Lesser General Public
++ * License along with this library. If not, see
++ * <http://www.gnu.org/licenses/>.
++ */
++
++
++#include <stdlib.h>
++#include <unistd.h>
++#include <stdio.h>
++#include <errno.h>
++
++
++#include <sys/stat.h>
++#include <fcntl.h>
++
++#include <dvdread/dvd_filesystem.h>
++
++#include "filesystem.h"
++
++#ifdef __ANDROID__
++# undef lseek
++# define lseek lseek64
++# undef off_t
++# define off_t off64_t
++#endif
++
++
++int _file_close(dvd_file_h *file)
++{
++ if (file) {
++ int ret = close((int)(intptr_t)file->internal);
++ free(file);
++ return ret;
++ }
++ return 0;
++}
++
++int64_t _file_seek(dvd_file_h *file, int64_t offset, int32_t origin)
++{
++ off_t result = lseek((int)(intptr_t)file->internal, offset, origin);
++ if (result == (off_t)-1) {
++ return -1;
++ }
++ return (int64_t)result;
++}
++
++ssize_t _file_read(dvd_file_h *file, char *buf, size_t size)
++{
++ ssize_t result;
++
++ if (size <= 0) {
++ return 0;
++ }
++
++ result = read((int)(intptr_t)file->internal, buf, size);
++ return result;
++}
++
++
++dvd_file_h* file_open_default(dvd_reader_filesystem_h *fs, const char* filename)
++{
++ if (!fs)
++ return NULL;
++
++ dvd_file_h *file;
++ int fd = -1;
++ int flags = 0;
++ int mode = 0;
++
++ #if defined(__OS2__) // not posix but kept here for legacy compatibility reasons
++ flags = O_RDONLY | O_BINARY;
++ #else
++ flags = O_RDONLY;
++ #endif
++
++#ifdef O_CLOEXEC
++ flags |= O_CLOEXEC;
++#endif
++#ifdef O_BINARY
++ flags |= O_BINARY;
++#endif
++
++ if ((fd = open(filename, flags, mode)) < 0) {
++ return NULL;
++ }
++
++ file = calloc(1, sizeof(dvd_file_h));
++ if (!file) {
++ close(fd);
++ return NULL;
++ }
++
++ file->close = _file_close;
++ file->read = _file_read;
++ file->seek = _file_seek;
++ file->internal = (void*)(intptr_t)fd;
++
++ return file;
++}
+diff --git a/libdvdread-embedded/src/file/file_win32.c b/libdvdread-embedded/src/file/file_win32.c
+new file mode 100644
+index 0000000..9787076
+--- /dev/null
++++ b/libdvdread-embedded/src/file/file_win32.c
+@@ -0,0 +1,98 @@
++/*
++ * This file is part of libdvdread
++ * Copyright (C) 2022 VideoLAN
++ *
++ * This file is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU Lesser General Public
++ * License as published by the Free Software Foundation; either
++ * version 2.1 of the License, or (at your option) any later version.
++ *
++ * This file is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ * Lesser General Public License for more details.
++ *
++ * You should have received a copy of the GNU Lesser General Public
++ * License along with this library. If not, see
++ * <http://www.gnu.org/licenses/>.
++ */
++
++#include <stdlib.h>
++#include <unistd.h>
++#include <stdio.h>
++#include <errno.h>
++
++#include <sys/stat.h>
++#include <fcntl.h>
++
++#include <windows.h>
++#include "../msvc/contrib/win32_cs.h"
++
++#include <dvdread/dvd_filesystem.h>
++#include "filesystem.h"
++
++
++int _file_close_win32(dvd_file_h *file)
++{
++ if (file) {
++ int ret = close((int)(intptr_t)file->internal);
++ free(file);
++ return ret;
++ }
++ return 0;
++}
++
++int64_t _file_seek_win32(dvd_file_h *file, int64_t offset, int32_t origin)
++{
++ off64_t result = _lseeki64((int)(intptr_t)file->internal, offset, origin);
++ if (result == (off64_t)-1) {
++ return -1;
++ }
++ return (int64_t)result;
++}
++
++ssize_t _file_read_win32(dvd_file_h *file, char *buf, size_t size)
++{
++ ssize_t result;
++
++ if (size <= 0) {
++ return 0;
++ }
++
++ result = read((int)(intptr_t)file->internal, buf, size);
++ return result;
++}
++
++
++dvd_file_h* file_open_default(dvd_reader_filesystem_h *fs, const char* filename)
++{
++ if (!fs)
++ return NULL;
++
++ dvd_file_h *file;
++ int fd = -1;
++ wchar_t *wpath;
++
++ wpath = _utf8_to_wchar(filename);
++ if (!wpath) {
++ return NULL;
++ }
++
++ if ((fd = _wopen(wpath, O_RDONLY | O_BINARY)) < 0) {
++ free(wpath);
++ return NULL;
++ }
++
++ file = calloc(1, sizeof(dvd_file_h));
++ if (!file) {
++ close(fd);
++ return NULL;
++ }
++
++ file->close = _file_close_win32;
++ file->read = _file_read_win32;
++ file->seek = _file_seek_win32;
++ file->internal = (void*)(intptr_t)fd;
++
++ return file;
++}
+diff --git a/libdvdread-embedded/src/file/filesystem.c b/libdvdread-embedded/src/file/filesystem.c
+new file mode 100644
+index 0000000..b79edae
+--- /dev/null
++++ b/libdvdread-embedded/src/file/filesystem.c
+@@ -0,0 +1,37 @@
++/*
++ * This file is part of libdvdread.
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU Lesser General Public License as published by
++ * the Free Software Foundation; either version 2.1 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU Lesser General Public License for more details.
++ *
++ * You should have received a copy of the GNU Lesser General Public License
++ * along with this program; if not, write to the Free Software Foundation,
++ * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
++ */
++
++#include "filesystem.h"
++
++#include <stdlib.h>
++
++static void default_filesystem_close(dvd_reader_filesystem_h *fs) {
++ free(fs);
++}
++
++dvd_reader_filesystem_h* InitInternalFilesystem() {
++ dvd_reader_filesystem_h* fs = calloc( 1, sizeof(dvd_reader_filesystem_h));
++ if (!fs) {
++ return NULL;
++ }
++ fs->dir_open = dir_open_default;
++ fs->stat = stat_default;
++ fs->file_open = file_open_default;
++ fs->close = default_filesystem_close;
++ return fs;
++}
+diff --git a/libdvdread-embedded/src/file/filesystem.h b/libdvdread-embedded/src/file/filesystem.h
+new file mode 100644
+index 0000000..1b8a014
+--- /dev/null
++++ b/libdvdread-embedded/src/file/filesystem.h
+@@ -0,0 +1,46 @@
++/*
++ * This file is part of libdvdread.
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU Lesser General Public License as published by
++ * the Free Software Foundation; either version 2.1 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU Lesser General Public License for more details.
++ *
++ * You should have received a copy of the GNU Lesser General Public License
++ * along with this program; if not, write to the Free Software Foundation,
++ * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
++ */
++
++#ifndef LIBDVDREAD_FILESYSTEM_H
++#define LIBDVDREAD_FILESYSTEM_H
++
++#include "dvdread/dvd_filesystem.h"
++
++/**
++ * Prototype definition for default file open function (implemented by each platform)
++ */
++dvd_file_h* file_open_default(dvd_reader_filesystem_h *fs, const char* filename);
++
++/**
++ * Prototype definition for default dir open function (implemented by each platform)
++ */
++dvd_dir_h* dir_open_default(dvd_reader_filesystem_h *fs, const char* dirname);
++
++/**
++ * Prototype definition for default stat function (implemented by each platform)
++ */
++int stat_default(dvd_reader_filesystem_h *fs, const char *path, dvdstat_t* statbuf);
++
++/**
++ * Inits the internal (platform specific) filesystem implementation
++ * bundled with libdvdread. This includes initializing the default internal
++ * implmentations of file_open, dir_open, stat, etc.
++ */
++dvd_reader_filesystem_h* InitInternalFilesystem();
++
++#endif
+diff --git a/libdvdread-embedded/src/file/stat_posix.c b/libdvdread-embedded/src/file/stat_posix.c
+new file mode 100644
+index 0000000..61670fc
+--- /dev/null
++++ b/libdvdread-embedded/src/file/stat_posix.c
+@@ -0,0 +1,36 @@
++/*
++ * This file is part of libdvdread
++ * Copyright (C) 2022 VideoLAN
++ *
++ * This file is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU Lesser General Public
++ * License as published by the Free Software Foundation; either
++ * version 2.1 of the License, or (at your option) any later version.
++ *
++ * This file is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ * Lesser General Public License for more details.
++ *
++ * You should have received a copy of the GNU Lesser General Public
++ * License along with this library. If not, see
++ * <http://www.gnu.org/licenses/>.
++ */
++
++#include <stdlib.h>
++#include <sys/stat.h>
++
++#include <dvdread/dvd_filesystem.h>
++#include "filesystem.h"
++
++int stat_default(dvd_reader_filesystem_h *fs, const char *path, dvdstat_t* statbuf)
++{
++ if (!fs)
++ return -1;
++
++ struct stat posixstatbuf;
++ int ret = stat(path, &posixstatbuf);
++ statbuf->size = posixstatbuf.st_size;
++ statbuf->st_mode = posixstatbuf.st_mode;
++ return ret;
++}
+diff --git a/libdvdread-embedded/src/file/stat_win32.c b/libdvdread-embedded/src/file/stat_win32.c
+new file mode 100644
+index 0000000..0b8245d
+--- /dev/null
++++ b/libdvdread-embedded/src/file/stat_win32.c
+@@ -0,0 +1,53 @@
++/*
++ * This file is part of libdvdread
++ * Copyright (C) 2022 VideoLAN
++ *
++ * This file is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU Lesser General Public
++ * License as published by the Free Software Foundation; either
++ * version 2.1 of the License, or (at your option) any later version.
++ *
++ * This file is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ * Lesser General Public License for more details.
++ *
++ * You should have received a copy of the GNU Lesser General Public
++ * License along with this library. If not, see
++ * <http://www.gnu.org/licenses/>.
++ */
++
++#include <stdlib.h>
++#include <sys/stat.h>
++
++#include <windows.h>
++#include "../msvc/contrib/win32_cs.h"
++
++#include <dvdread/dvd_filesystem.h>
++#include "filesystem.h"
++
++
++int stat_default(dvd_reader_filesystem_h *fs, const char *path, dvdstat_t* statbuf)
++{
++ if (!fs)
++ return -1;
++
++ struct _stat64 win32statbuf;
++
++ wchar_t *wpath, *it;
++
++ wpath = _utf8_to_wchar(path);
++ if (!wpath) {
++ return -1;
++ }
++
++ /* need to strip possible trailing \\ */
++ for (it = wpath; *it; it++)
++ if ((*it == '\\' || *it == '/') && *(it+1) == 0)
++ *it = 0;
++
++ int ret = _wstat64(wpath, &win32statbuf);
++ statbuf->size = win32statbuf.st_size;
++ statbuf->st_mode = win32statbuf.st_mode;
++ return ret;
++}
+--
+2.35.1
+
+
+From 7215ed052b632be49c4f1ed444c7c9447e2d4c61 Mon Sep 17 00:00:00 2001
+From: Miguel Borges de Freitas <enen92@kodi.tv>
+Date: Fri, 29 Jul 2022 12:50:24 +0100
+Subject: [PATCH 2/3] Decouple dvdinput_setup providing dvdinput_setup_builtin
+ for minimal/internal fs access
+
+---
+ libdvdread-embedded/src/dvd_input.c | 23 +++++++++++++++++------
+ libdvdread-embedded/src/dvd_input.h | 8 ++++++++
+ 2 files changed, 25 insertions(+), 6 deletions(-)
+
+diff --git a/libdvdread-embedded/src/dvd_input.c b/libdvdread-embedded/src/dvd_input.c
+index 1baf8f7..70f31b3 100644
+--- a/libdvdread-embedded/src/dvd_input.c
++++ b/libdvdread-embedded/src/dvd_input.c
+@@ -446,12 +446,23 @@ int dvdinput_setup(void *priv, dvd_logger_cb *logcb)
+ DVDReadLog(priv, logcb, DVD_LOGGER_LEVEL_WARN,
+ "Encrypted DVD support unavailable.");
+
+- /* libdvdcss replacement functions */
+- dvdinput_open = file_open;
+- dvdinput_close = file_close;
+- dvdinput_seek = file_seek;
+- dvdinput_title = file_title;
+- dvdinput_read = file_read;
++ dvdinput_setup_builtin(priv, logcb);
+ return 0;
+ }
+ }
++
++/**
++ * Setup read functions with the builtin libdvdread implementation (minimal DVD access without css).
++ */
++void dvdinput_setup_builtin(void *priv, dvd_logger_cb *logcb)
++{
++ DVDReadLog(priv, logcb, DVD_LOGGER_LEVEL_INFO,
++ "Setting up builtin libdvdread implementation");
++
++ /* libdvdcss replacement functions */
++ dvdinput_open = file_open;
++ dvdinput_close = file_close;
++ dvdinput_seek = file_seek;
++ dvdinput_title = file_title;
++ dvdinput_read = file_read;
++}
+diff --git a/libdvdread-embedded/src/dvd_input.h b/libdvdread-embedded/src/dvd_input.h
+index 56fe170..36fe279 100644
+--- a/libdvdread-embedded/src/dvd_input.h
++++ b/libdvdread-embedded/src/dvd_input.h
+@@ -46,7 +46,15 @@ extern int (*dvdinput_read) (dvd_input_t, void *, int, int);
+
+ /**
+ * Setup function accessed by dvd_reader.c. Returns 1 if there is CSS support.
++ * Otherwise it falls back to the internal dvdread implementation (without css support)
++ * which is basically the same as calling dvdinput_setup_builtin.
+ */
+ int dvdinput_setup(void *, dvd_logger_cb *);
+
++/**
++ * Setup function accessed by dvd_reader.c using the builtin libdvdread implementation
++ * (without css support)
++ */
++void dvdinput_setup_builtin(void *, dvd_logger_cb *);
++
+ #endif /* LIBDVDREAD_DVD_INPUT_H */
+--
+2.35.1
+
+
+From 665a98ee15896e97aa8f0c0d6499b281d0602e60 Mon Sep 17 00:00:00 2001
+From: Miguel Borges de Freitas <enen92@kodi.tv>
+Date: Fri, 29 Jul 2022 12:55:19 +0100
+Subject: [PATCH 3/3] Add DVDOpenFiles supporting caller provided filesystem
+ implementation
+
+---
+ libdvdread-embedded/src/dvd_reader.c | 32 +++++++++++++++++++++++++++-----
+ libdvdread-embedded/src/dvdread/dvd_reader.h | 13 +++++++++++++
+ 2 files changed, 40 insertions(+), 5 deletions(-)
+
+diff --git a/libdvdread-embedded/src/dvd_reader.c b/libdvdread-embedded/src/dvd_reader.c
+index 5a21056..84bef88 100644
+--- a/libdvdread-embedded/src/dvd_reader.c
++++ b/libdvdread-embedded/src/dvd_reader.c
+@@ -330,7 +330,8 @@ static char *bsd_block2char( const char *path )
+ static dvd_reader_t *DVDOpenCommon( void *priv,
+ const dvd_logger_cb *logcb,
+ const char *ppath,
+- dvd_reader_stream_cb *stream_cb )
++ dvd_reader_stream_cb *stream_cb,
++ dvd_reader_filesystem_h * fs )
+ {
+ dvdstat_t fileinfo;
+ int ret, have_css, cdir = -1;
+@@ -344,6 +345,21 @@ static dvd_reader_t *DVDOpenCommon( void *priv,
+ if(logcb)
+ ctx->logcb = *logcb;
+
++ // open files using the provided filesystem implementation
++ if (fs != NULL && ppath != NULL)
++ {
++ ctx->fs = fs;
++ dvdinput_setup_builtin(ctx->priv, &ctx->logcb);
++ ctx->rd = DVDOpenPath(ppath);
++ if (!ctx->rd)
++ {
++ free(ctx);
++ return NULL;
++ }
++ return ctx;
++ }
++
++ // create the internal filesystem
+ ctx->fs = InitInternalFilesystem();
+ if (!ctx->fs)
+ {
+@@ -629,25 +645,31 @@ DVDOpen_error:
+
+ dvd_reader_t *DVDOpen( const char *ppath )
+ {
+- return DVDOpenCommon( NULL, NULL, ppath, NULL );
++ return DVDOpenCommon( NULL, NULL, ppath, NULL, NULL );
+ }
+
+ dvd_reader_t *DVDOpenStream( void *stream,
+ dvd_reader_stream_cb *stream_cb )
+ {
+- return DVDOpenCommon( stream, NULL, NULL, stream_cb );
++ return DVDOpenCommon( stream, NULL, NULL, stream_cb, NULL );
+ }
+
+ dvd_reader_t *DVDOpen2( void *priv, const dvd_logger_cb *logcb,
+ const char *ppath )
+ {
+- return DVDOpenCommon( priv, logcb, ppath, NULL );
++ return DVDOpenCommon( priv, logcb, ppath, NULL, NULL );
+ }
+
+ dvd_reader_t *DVDOpenStream2( void *priv, const dvd_logger_cb *logcb,
+ dvd_reader_stream_cb *stream_cb )
+ {
+- return DVDOpenCommon( priv, logcb, NULL, stream_cb );
++ return DVDOpenCommon( priv, logcb, NULL, stream_cb, NULL );
++}
++
++dvd_reader_t *DVDOpenFiles( void *priv, const dvd_logger_cb *logcb,
++ const char *ppath, dvd_reader_filesystem_h *fs)
++{
++ return DVDOpenCommon( priv, logcb, ppath, NULL, fs);
+ }
+
+ void DVDClose( dvd_reader_t *dvd )
+diff --git a/libdvdread-embedded/src/dvdread/dvd_reader.h b/libdvdread-embedded/src/dvdread/dvd_reader.h
+index 5b15704..40ddaf2 100644
+--- a/libdvdread-embedded/src/dvdread/dvd_reader.h
++++ b/libdvdread-embedded/src/dvdread/dvd_reader.h
+@@ -153,6 +153,19 @@ dvd_reader_t *DVDOpenStream( void *, dvd_reader_stream_cb * );
+ dvd_reader_t *DVDOpen2( void *, const dvd_logger_cb *, const char * );
+ dvd_reader_t *DVDOpenStream2( void *, const dvd_logger_cb *, dvd_reader_stream_cb * );
+
++/**
++ * Open unencrypted DVD files providing the respective filesystem implementation
++ * Useful to open files located on virtual file systems
++ *
++ * @param path Specifies the file or directory to use
++ * @param priv is a private handle
++ * @param logcb is a custom logger callback struct, or NULL if none needed
++ * @param fs is a struct containing the filesystem implementation
++ * @return If successful a read handle is returned. Otherwise 0 is returned.
++ *
++ */
++dvd_reader_t *DVDOpenFiles( void *priv, const dvd_logger_cb *logcb, const char * path, dvd_reader_filesystem_h *fs);
++
+ /**
+ * Closes and cleans up the DVD reader object.
+ *
+--
+2.35.1
+