diff --git a/SharpPhysFS/Interop.cs b/SharpPhysFS/Interop.cs index 698c59d..c608c89 100644 --- a/SharpPhysFS/Interop.cs +++ b/SharpPhysFS/Interop.cs @@ -98,10 +98,8 @@ namespace SharpPhysFS #endregion } - static class Interop + class Interop { - public static bool init = false; - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] public delegate void FnGetLinkedVersion(ref Version v); [UnmanagedFunctionPointer(CallingConvention.Cdecl)] @@ -148,53 +146,61 @@ namespace SharpPhysFS // When the callbacks are not yet initialized, instead of throwing a // null reference exception we explain the problem. // I think it makes for a more graceful failure. - public static FnGetLinkedVersion PHYSFS_getLinkedVersion = (ref Version v) => { throw new InvalidOperationException("Callbacks not initialized yet"); }; - public static FnInit PHYSFS_init = (a) => { throw new InvalidOperationException("Callbacks not initialized yet"); }; - public static FnDeinit PHYSFS_deinit = () => { throw new InvalidOperationException("Callbacks not initialized yet"); }; - public static FnSupportedArchiveTypes PHYSFS_supportedArchiveTypes = () => { throw new InvalidOperationException("Callbacks not initialized yet"); }; - public static FnFreeList PHYSFS_freeList = (a) => { throw new InvalidOperationException("Callbacks not initialized yet"); }; - public static FnGetLastError PHYSFS_getLastError = () => { throw new InvalidOperationException("Callbacks not initialized yet"); }; - public static FnGetLastError PHYSFS_getDirSeparator = () => { throw new InvalidOperationException("Callbacks not initialized yet"); }; - public static FnPermitSymbolicLinks PHYSFS_permitSymbolicLinks = (a) => { throw new InvalidOperationException("Callbacks not initialized yet"); }; - public static FnSupportedArchiveTypes PHYSFS_getCdRomDirs = () => { throw new InvalidOperationException("Callbacks not initialized yet"); }; - public static FnGetLastError PHYSFS_getBaseDir = () => { throw new InvalidOperationException("Callbacks not initialized yet"); }; - public static FnGetLastError PHYSFS_getUserDir = () => { throw new InvalidOperationException("Callbacks not initialized yet"); }; - public static FnGetLastError PHYSFS_getWriteDir = () => { throw new InvalidOperationException("Callbacks not initialized yet"); }; - public static FnSetWriteDir PHYSFS_setWriteDir = (a) => { throw new InvalidOperationException("Callbacks not initialized yet"); }; - public static FnAddToSearchPath PHYSFS_addToSearchPath = (a, b) => { throw new InvalidOperationException("Callbacks not initialized yet"); }; - public static FnSetWriteDir PHYSFS_removeFromSearchPath = (a) => { throw new InvalidOperationException("Callbacks not initialized yet"); }; - public static FnSupportedArchiveTypes PHYSFS_getSearchPath = () => { throw new InvalidOperationException("Callbacks not initialized yet"); }; - public static FnSetSaneConfig PHYSFS_setSaneConfig = (a, b, c, d, e) => { throw new InvalidOperationException("Callbacks not initialized yet"); }; - public static FnSetWriteDir PHYSFS_mkdir = (a) => { throw new InvalidOperationException("Callbacks not initialized yet"); }; - public static FnSetWriteDir PHYSFS_delete = (a) => { throw new InvalidOperationException("Callbacks not initialized yet"); }; - public static FnEnumerateFiles PHYSFS_getRealDir = (a) => { throw new InvalidOperationException("Callbacks not initialized yet"); }; - public static FnEnumerateFiles PHYSFS_enumerateFiles = (a) => { throw new InvalidOperationException("Callbacks not initialized yet"); }; - public static FnSetWriteDir PHYSFS_exists = (a) => { throw new InvalidOperationException("Callbacks not initialized yet"); }; - public static FnSetWriteDir PHYSFS_isDirectory = (a) => { throw new InvalidOperationException("Callbacks not initialized yet"); }; - public static FnSetWriteDir PHYSFS_isSymbolicLink = (a) => { throw new InvalidOperationException("Callbacks not initialized yet"); }; - public static FnGetLastModTime PHYSFS_getLastModTime = (a) => { throw new InvalidOperationException("Callbacks not initialized yet"); }; - public static FnEnumerateFiles PHYSFS_openWrite = (a) => { throw new InvalidOperationException("Callbacks not initialized yet"); }; - public static FnEnumerateFiles PHYSFS_openAppend = (a) => { throw new InvalidOperationException("Callbacks not initialized yet"); }; - public static FnEnumerateFiles PHYSFS_openRead = (a) => { throw new InvalidOperationException("Callbacks not initialized yet"); }; - public static FnClose PHYSFS_close = (a) => { throw new InvalidOperationException("Callbacks not initialized yet"); }; - public static FnRead PHYSFS_read = (a, b, c, d) => { throw new InvalidOperationException("Callbacks not initialized yet"); }; - public static FnRead PHYSFS_write = (a, b, c,d ) => { throw new InvalidOperationException("Callbacks not initialized yet"); }; - public static FnClose PHYSFS_eof = (a) => { throw new InvalidOperationException("Callbacks not initialized yet"); }; - public static FnTell PHYSFS_tell = (a) => { throw new InvalidOperationException("Callbacks not initialized yet"); }; - public static FnSeek PHYSFS_seek = (a, b) => { throw new InvalidOperationException("Callbacks not initialized yet"); }; - public static FnFileLength PHYSFS_fileLength = (a) => { throw new InvalidOperationException("Callbacks not initialized yet"); }; - public static FnSeek PHYSFS_setBuffer = (a, b) => { throw new InvalidOperationException("Callbacks not initialized yet"); }; - public static FnClose PHYSFS_flush = (a) => { throw new InvalidOperationException("Callbacks not initialized yet"); }; - public static FnDeinit PHYSFS_isInit = () => { throw new InvalidOperationException("Callbacks not initialized yet"); }; - public static FnDeinit PHYSFS_symbolicLinksPermitted = () => { throw new InvalidOperationException("Callbacks not initialized yet"); }; - public static FnSetAllocator PHYSFS_setAllocator = (a) => { throw new InvalidOperationException("Callbacks not initialized yet"); }; - public static FnMount PHYSFS_mount = (a, b, c) => { throw new InvalidOperationException("Callbacks not initialized yet"); }; - public static FnEnumerateFiles PHYSFS_getMountPoint = (a) => { throw new InvalidOperationException("Callbacks not initialized yet"); }; - public static FnGetCdRomDirsCallback PHYSFS_getCdRomDirsCallback = (a, b) => { throw new InvalidOperationException("Callbacks not initialized yet"); }; - public static FnGetCdRomDirsCallback PHYSFS_getSearchPathCallback = (a, b) => { throw new InvalidOperationException("Callbacks not initialized yet"); }; - public static FnEnumerateFilesCallback PHYSFS_enumerateFilesCallback = (a, b, c) => { throw new InvalidOperationException("Callbacks not initialized yet"); }; + public FnGetLinkedVersion PHYSFS_getLinkedVersion = (ref Version v) => { throw new InvalidOperationException("Callbacks not initialized yet"); }; + public FnInit PHYSFS_init = (a) => { throw new InvalidOperationException("Callbacks not initialized yet"); }; + public FnDeinit PHYSFS_deinit = () => { throw new InvalidOperationException("Callbacks not initialized yet"); }; + public FnSupportedArchiveTypes PHYSFS_supportedArchiveTypes = () => { throw new InvalidOperationException("Callbacks not initialized yet"); }; + public FnFreeList PHYSFS_freeList = (a) => { throw new InvalidOperationException("Callbacks not initialized yet"); }; + public FnGetLastError PHYSFS_getLastError = () => { throw new InvalidOperationException("Callbacks not initialized yet"); }; + public FnGetLastError PHYSFS_getDirSeparator = () => { throw new InvalidOperationException("Callbacks not initialized yet"); }; + public FnPermitSymbolicLinks PHYSFS_permitSymbolicLinks = (a) => { throw new InvalidOperationException("Callbacks not initialized yet"); }; + public FnSupportedArchiveTypes PHYSFS_getCdRomDirs = () => { throw new InvalidOperationException("Callbacks not initialized yet"); }; + public FnGetLastError PHYSFS_getBaseDir = () => { throw new InvalidOperationException("Callbacks not initialized yet"); }; + public FnGetLastError PHYSFS_getUserDir = () => { throw new InvalidOperationException("Callbacks not initialized yet"); }; + public FnGetLastError PHYSFS_getWriteDir = () => { throw new InvalidOperationException("Callbacks not initialized yet"); }; + public FnSetWriteDir PHYSFS_setWriteDir = (a) => { throw new InvalidOperationException("Callbacks not initialized yet"); }; + public FnAddToSearchPath PHYSFS_addToSearchPath = (a, b) => { throw new InvalidOperationException("Callbacks not initialized yet"); }; + public FnSetWriteDir PHYSFS_removeFromSearchPath = (a) => { throw new InvalidOperationException("Callbacks not initialized yet"); }; + public FnSupportedArchiveTypes PHYSFS_getSearchPath = () => { throw new InvalidOperationException("Callbacks not initialized yet"); }; + public FnSetSaneConfig PHYSFS_setSaneConfig = (a, b, c, d, e) => { throw new InvalidOperationException("Callbacks not initialized yet"); }; + public FnSetWriteDir PHYSFS_mkdir = (a) => { throw new InvalidOperationException("Callbacks not initialized yet"); }; + public FnSetWriteDir PHYSFS_delete = (a) => { throw new InvalidOperationException("Callbacks not initialized yet"); }; + public FnEnumerateFiles PHYSFS_getRealDir = (a) => { throw new InvalidOperationException("Callbacks not initialized yet"); }; + public FnEnumerateFiles PHYSFS_enumerateFiles = (a) => { throw new InvalidOperationException("Callbacks not initialized yet"); }; + public FnSetWriteDir PHYSFS_exists = (a) => { throw new InvalidOperationException("Callbacks not initialized yet"); }; + public FnSetWriteDir PHYSFS_isDirectory = (a) => { throw new InvalidOperationException("Callbacks not initialized yet"); }; + public FnSetWriteDir PHYSFS_isSymbolicLink = (a) => { throw new InvalidOperationException("Callbacks not initialized yet"); }; + public FnGetLastModTime PHYSFS_getLastModTime = (a) => { throw new InvalidOperationException("Callbacks not initialized yet"); }; + public FnEnumerateFiles PHYSFS_openWrite = (a) => { throw new InvalidOperationException("Callbacks not initialized yet"); }; + public FnEnumerateFiles PHYSFS_openAppend = (a) => { throw new InvalidOperationException("Callbacks not initialized yet"); }; + public FnEnumerateFiles PHYSFS_openRead = (a) => { throw new InvalidOperationException("Callbacks not initialized yet"); }; + public FnClose PHYSFS_close = (a) => { throw new InvalidOperationException("Callbacks not initialized yet"); }; + public FnRead PHYSFS_read = (a, b, c, d) => { throw new InvalidOperationException("Callbacks not initialized yet"); }; + public FnRead PHYSFS_write = (a, b, c,d ) => { throw new InvalidOperationException("Callbacks not initialized yet"); }; + public FnClose PHYSFS_eof = (a) => { throw new InvalidOperationException("Callbacks not initialized yet"); }; + public FnTell PHYSFS_tell = (a) => { throw new InvalidOperationException("Callbacks not initialized yet"); }; + public FnSeek PHYSFS_seek = (a, b) => { throw new InvalidOperationException("Callbacks not initialized yet"); }; + public FnFileLength PHYSFS_fileLength = (a) => { throw new InvalidOperationException("Callbacks not initialized yet"); }; + public FnSeek PHYSFS_setBuffer = (a, b) => { throw new InvalidOperationException("Callbacks not initialized yet"); }; + public FnClose PHYSFS_flush = (a) => { throw new InvalidOperationException("Callbacks not initialized yet"); }; + public FnDeinit PHYSFS_isInit = () => { throw new InvalidOperationException("Callbacks not initialized yet"); }; + public FnDeinit PHYSFS_symbolicLinksPermitted = () => { throw new InvalidOperationException("Callbacks not initialized yet"); }; + public FnSetAllocator PHYSFS_setAllocator = (a) => { throw new InvalidOperationException("Callbacks not initialized yet"); }; + public FnMount PHYSFS_mount = (a, b, c) => { throw new InvalidOperationException("Callbacks not initialized yet"); }; + public FnEnumerateFiles PHYSFS_getMountPoint = (a) => { throw new InvalidOperationException("Callbacks not initialized yet"); }; + public FnGetCdRomDirsCallback PHYSFS_getCdRomDirsCallback = (a, b) => { throw new InvalidOperationException("Callbacks not initialized yet"); }; + public FnGetCdRomDirsCallback PHYSFS_getSearchPathCallback = (a, b) => { throw new InvalidOperationException("Callbacks not initialized yet"); }; + public FnEnumerateFilesCallback PHYSFS_enumerateFilesCallback = (a, b, c) => { throw new InvalidOperationException("Callbacks not initialized yet"); }; - public static void SetUpInterop() + public Interop() + : this("physfs.dll", "libphysfs.dylib", "libphysfs.so") + { } + + public Interop(string libname) + : this($"{libname}.dll", $"{libname}.dylib", $"{libname}.so") + { } + + public Interop(string winlib, string maclib, string unixlib) { /* This method is used to dynamically load the physfs * library. It works by detecting the current platform @@ -215,19 +221,19 @@ namespace SharpPhysFS { loadLibrary = DynamicLoader.LoadLibrary; loadSymbol = DynamicLoader.GetProcAddress; - libraryName = "physfs.dll"; + libraryName = winlib; } else if(Environment.OSVersion.Platform == PlatformID.MacOSX) { loadLibrary = n => DynamicLoader.osx_dlopen(n, 1); loadSymbol = DynamicLoader.osx_dlsym; - libraryName = "libphysfs.dylib"; + libraryName = maclib; } else { loadLibrary = n => DynamicLoader.unix_dlopen(n, 1); loadSymbol = DynamicLoader.unix_dlsym; - libraryName = "libphysfs.so"; + libraryName = unixlib; } library = loadLibrary(libraryName); @@ -245,8 +251,6 @@ namespace SharpPhysFS field.SetValue(null, del); } - - init = true; } } } diff --git a/SharpPhysFS/PhysFS.LowLevel.cs b/SharpPhysFS/PhysFS.LowLevel.cs new file mode 100644 index 0000000..d1db0b1 --- /dev/null +++ b/SharpPhysFS/PhysFS.LowLevel.cs @@ -0,0 +1,99 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace SharpPhysFS +{ + public partial class PhysFS + { + public static class LowLevel + { + public static IntPtr OpenWrite(string filename, PhysFS physFS) + { + var val = physFS.interop.PHYSFS_openWrite(filename); + if (val == null) + throw new PhysFSException(physFS); + return val; + } + + public static IntPtr OpenAppend(string filename, PhysFS physFS) + { + var val = physFS.interop.PHYSFS_openAppend(filename); + if (val == null) + throw new PhysFSException(physFS); + return val; + } + + public static IntPtr OpenRead(string filename, PhysFS physFS) + { + var val = physFS.interop.PHYSFS_openRead(filename); + if (val == null) + throw new PhysFSException(physFS); + return val; + } + + public static void Close(IntPtr file, PhysFS physFS) + { + int err = physFS.interop.PHYSFS_close(file); + physFS.ThrowException(err); + } + + public static long Read(IntPtr file, byte[] buffer, uint objSize, uint objCount, PhysFS physFS) + { + unsafe + { + fixed (void* ptr = buffer) + { + return physFS.interop.PHYSFS_read(file, (IntPtr)ptr, objSize, objCount); + } + } + } + + public static long Write(IntPtr file, byte[] buffer, uint objSize, uint objCount, PhysFS physFS) + { + unsafe + { + fixed (void* ptr = buffer) + { + return physFS.interop.PHYSFS_write(file, (IntPtr)ptr, objSize, objCount); + } + } + } + + public static bool EOF(IntPtr file, PhysFS physFS) + { + return physFS.interop.PHYSFS_eof(file) != 0; + } + + public static long Tell(IntPtr file, PhysFS physFS) + { + return physFS.interop.PHYSFS_tell(file); + } + + public static void Seek(IntPtr file, ulong pos, PhysFS physFS) + { + int err = physFS.interop.PHYSFS_seek(file, pos); + physFS.ThrowException(err); + } + + public static long FileLength(IntPtr file, PhysFS physFS) + { + return physFS.interop.PHYSFS_fileLength(file); + } + + public static void SetBuffer(IntPtr file, ulong bufSize, PhysFS physFS) + { + int err = physFS.interop.PHYSFS_setBuffer(file, bufSize); + physFS.ThrowException(err); + } + + public static void Flush(IntPtr file, PhysFS physFS) + { + int err = physFS.interop.PHYSFS_flush(file); + physFS.ThrowException(err); + } + } + } +} diff --git a/SharpPhysFS/PhysFS.cs b/SharpPhysFS/PhysFS.cs index 5314539..dee5389 100644 --- a/SharpPhysFS/PhysFS.cs +++ b/SharpPhysFS/PhysFS.cs @@ -4,13 +4,6 @@ using System.Runtime.InteropServices; namespace SharpPhysFS { - public class PhysFSException : Exception - { - public PhysFSException() - : base(PhysFS.GetLastError()) - { } - } - public class PhysFSLibNotFound : Exception { public PhysFSLibNotFound() @@ -21,94 +14,22 @@ namespace SharpPhysFS /// /// Main class for SharpPhysFS /// - public static class PhysFS + public partial class PhysFS + : IDisposable { - public static class LowLevel + public class PhysFSException : Exception { - public static IntPtr OpenWrite(string filename) - { - var val = Interop.PHYSFS_openWrite(filename); - if (val == null) - throw new PhysFSException(); - return val; - } + public PhysFSException(PhysFS physFS) + : base(physFS.GetLastError()) + { } + } - public static IntPtr OpenAppend(string filename) - { - var val = Interop.PHYSFS_openAppend(filename); - if (val == null) - throw new PhysFSException(); - return val; - } + Interop interop; - public static IntPtr OpenRead(string filename) - { - var val = Interop.PHYSFS_openRead(filename); - if (val == null) - throw new PhysFSException(); - return val; - } - - public static void Close(IntPtr file) - { - int err = Interop.PHYSFS_close(file); - ThrowException(err); - } - - public static long Read(IntPtr file, byte[] buffer, uint objSize, uint objCount) - { - unsafe - { - fixed (void* ptr = buffer) - { - return Interop.PHYSFS_read(file, (IntPtr)ptr, objSize, objCount); - } - } - } - - public static long Write(IntPtr file, byte[] buffer, uint objSize, uint objCount) - { - unsafe - { - fixed (void* ptr = buffer) - { - return Interop.PHYSFS_write(file, (IntPtr)ptr, objSize, objCount); - } - } - } - - public static bool EOF(IntPtr file) - { - return Interop.PHYSFS_eof(file) != 0; - } - - public static long Tell(IntPtr file) - { - return Interop.PHYSFS_tell(file); - } - - public static void Seek(IntPtr file, ulong pos) - { - int err = Interop.PHYSFS_seek(file, pos); - ThrowException(err); - } - - public static long FileLength(IntPtr file) - { - return Interop.PHYSFS_fileLength(file); - } - - public static void SetBuffer(IntPtr file, ulong bufSize) - { - int err = Interop.PHYSFS_setBuffer(file, bufSize); - ThrowException(err); - } - - public static void Flush(IntPtr file) - { - int err = Interop.PHYSFS_flush(file); - ThrowException(err); - } + public PhysFS(string argv0) + { + interop = new Interop(); + Init(argv0); } static T FromPtr(IntPtr ptr) @@ -116,38 +37,22 @@ namespace SharpPhysFS return (T)Marshal.PtrToStructure(ptr, typeof(T)); } - static void ThrowException(int err) + void ThrowException(int err) { if (err == 0) { - throw new PhysFSException(); + throw new PhysFSException(this); } } - /// - /// Sets up the library callbacks for use. - /// - /// - /// This method will dynamically load the right library according to the - /// current platform, whether it is Windows of *nix - /// - /// - /// This method must be called before any other method in this class is available. - /// Not doing so will result in NullReferenceException - /// - public static void InitializeCallbacks() - { - Interop.SetUpInterop(); - } - /// /// Get the version of PhysicsFS that is linked against your program /// /// The version of PhysicsFS that is linked against your program - public static Version GetLinkedVersion() + public Version GetLinkedVersion() { Version v = new Version(); - Interop.PHYSFS_getLinkedVersion(ref v); + interop.PHYSFS_getLinkedVersion(ref v); return v; } @@ -157,11 +62,12 @@ namespace SharpPhysFS /// /// Must be called before any other PhysicsFS function. /// This should be called prior to any attempts to change your process's current working directory. + /// NOTE: This is automatically called when the class is created. /// /// This should be the path of the executable (first arguments passed to main function in C programs) - public static void Init(string argv0) + public void Init(string argv0) { - int err = Interop.PHYSFS_init(argv0); + int err = interop.PHYSFS_init(argv0); ThrowException(err); } @@ -180,10 +86,11 @@ namespace SharpPhysFS /// close all write handles yourself before calling this function, so that you can gracefully handle a specific failure. /// Once successfully deinitialized, Init can be called again to restart the subsystem. /// All default API states are restored at this point, with the exception of any custom allocator you might have specified, which survives between initializations. + /// NOTE: This is called automatically on disposal. /// - public static void Deinit() + public void Deinit() { - int err = Interop.PHYSFS_deinit(); + int err = interop.PHYSFS_deinit(); ThrowException(err); } @@ -208,9 +115,9 @@ namespace SharpPhysFS /// directory or archive to add to the path, in platform-dependent notation. /// Location in the interpolated tree that this archive will be "mounted", in platform-independent notation. null or "" is equivalent to "/". /// True to append to search path, false to prepend. - public static void Mount(string dir, string mountPoint, bool appendToPath) + public void Mount(string dir, string mountPoint, bool appendToPath) { - int err = Interop.PHYSFS_mount(dir, mountPoint, appendToPath ? 1 : 0); + int err = interop.PHYSFS_mount(dir, mountPoint, appendToPath ? 1 : 0); ThrowException(err); } @@ -225,9 +132,9 @@ namespace SharpPhysFS /// It is safe to call this function at anytime, even before PhysFS.Init(). /// /// String of last error message. - public static string GetLastError() + public string GetLastError() { - return Marshal.PtrToStringAnsi(Interop.PHYSFS_getLastError()); + return Marshal.PtrToStringAnsi(interop.PHYSFS_getLastError()); } /// @@ -241,9 +148,9 @@ namespace SharpPhysFS /// This is only useful for setting up the search/write paths, since access into those dirs always use '/' (platform-independent notation) /// /// Platform-dependent dir separator string - public static string GetDirSeparator() + public string GetDirSeparator() { - return Marshal.PtrToStringAnsi(Interop.PHYSFS_getDirSeparator()); + return Marshal.PtrToStringAnsi(interop.PHYSFS_getDirSeparator()); } /// @@ -268,7 +175,7 @@ namespace SharpPhysFS /// /// /// Directory in platform-independent notation to enumerate. - public static string[] EnumerateFiles(string dir) + public string[] EnumerateFiles(string dir) { var list = new List(); EnumerateFilesCallback(dir, (d, o, f) => @@ -290,9 +197,9 @@ namespace SharpPhysFS /// The extension listed is merely convention: if we list "ZIP", you can open a PkZip-compatible archive with an extension of "XYZ", if you like. /// /// An enumeration of supported archive types - public static IEnumerable SupportedArchiveTypes() + public IEnumerable SupportedArchiveTypes() { - IntPtr archives = Interop.PHYSFS_supportedArchiveTypes(); + IntPtr archives = interop.PHYSFS_supportedArchiveTypes(); IntPtr i = archives; for (i = archives; Marshal.ReadIntPtr(i) != IntPtr.Zero; i = IntPtr.Add(i, IntPtr.Size)) { @@ -325,9 +232,9 @@ namespace SharpPhysFS /// That is, when setting up your search and write paths, etc, symlinks are never checked for. /// /// true to permit symlinks, false to deny linking. - public static void PermitSymbolicLinks(bool permit) + public void PermitSymbolicLinks(bool permit) { - Interop.PHYSFS_permitSymbolicLinks(permit ? 1 : 0); + interop.PHYSFS_permitSymbolicLinks(permit ? 1 : 0); } /// @@ -348,7 +255,7 @@ namespace SharpPhysFS /// This call may block while drives spin up. Be forewarned. /// /// An enumeration of paths to available CD-ROM drives. - public static string[] GetCdRomDirs() + public string[] GetCdRomDirs() { var list = new List(); GetCdRomDirsCallback((d, s) => @@ -365,9 +272,9 @@ namespace SharpPhysFS /// It is probably better to use managed methods for this. /// /// - public static string GetBaseDir() + public string GetBaseDir() { - return Marshal.PtrToStringAnsi(Interop.PHYSFS_getBaseDir()); + return Marshal.PtrToStringAnsi(interop.PHYSFS_getBaseDir()); } /// @@ -383,9 +290,9 @@ namespace SharpPhysFS /// You should probably use the user dir as the basis for your write dir, and also put it near the beginning of your search path. /// /// String of user dir in platform-dependent notation. - public static string GetUserDir() + public string GetUserDir() { - return Marshal.PtrToStringAnsi(Interop.PHYSFS_getUserDir()); + return Marshal.PtrToStringAnsi(interop.PHYSFS_getUserDir()); } /// @@ -395,9 +302,9 @@ namespace SharpPhysFS /// Get the current write dir. The default write dir is "". /// /// String of write dir in platform-dependent notation, OR null IF NO WRITE PATH IS CURRENTLY SET - public static string GetWriteDir() + public string GetWriteDir() { - return Marshal.PtrToStringAnsi(Interop.PHYSFS_getWriteDir()); + return Marshal.PtrToStringAnsi(interop.PHYSFS_getWriteDir()); } /// @@ -413,9 +320,9 @@ namespace SharpPhysFS /// The new directory to be the root of the write dir, specified in platform-dependent notation. /// Setting to null disables the write dir, so no files can be opened for writing via PhysicsFS. /// - public static void SetWriteDir(string path) + public void SetWriteDir(string path) { - int err = Interop.PHYSFS_setWriteDir(path); + int err = interop.PHYSFS_setWriteDir(path); ThrowException(err); } @@ -425,9 +332,9 @@ namespace SharpPhysFS /// Directory or archive to add to the path, in platform-dependent notation /// true to append to search path, false to prepend [Obsolete("AddToSearchPath is deprecated, please use Mount instead")] - public static void AddToSearchPath(string newDir, bool appendToPath) + public void AddToSearchPath(string newDir, bool appendToPath) { - int err = Interop.PHYSFS_addToSearchPath(newDir, appendToPath ? 1 : 0); + int err = interop.PHYSFS_addToSearchPath(newDir, appendToPath ? 1 : 0); ThrowException(err); } @@ -441,16 +348,16 @@ namespace SharpPhysFS /// This call will fail (and fail to remove from the path) if the element still has files open in it. /// /// dir/archive to remove. - public static void RemoveFromSearchPath(string oldDir) + public void RemoveFromSearchPath(string oldDir) { - int err = Interop.PHYSFS_removeFromSearchPath(oldDir); + int err = interop.PHYSFS_removeFromSearchPath(oldDir); ThrowException(err); } /// /// Get the current search path. /// - public static string[] GetSearchPath() + public string[] GetSearchPath() { //var dirs = Interop.PHYSFS_getSearchPath(); //return GenEnumerable(dirs); @@ -516,9 +423,9 @@ namespace SharpPhysFS /// then they may not be made available anyhow. You may want to specify false and handle the disc setup yourself. /// /// True to prepend the archives to the search path. False to append them. Ignored if !. - public static void SetSaneConfig(string organization, string appName, string archiveExt, bool includeCdRoms, bool archivesFirst) + public void SetSaneConfig(string organization, string appName, string archiveExt, bool includeCdRoms, bool archivesFirst) { - int err = Interop.PHYSFS_setSaneConfig(organization, appName, archiveExt, includeCdRoms ? 1 : 0, archivesFirst ? 1 : 0); + int err = interop.PHYSFS_setSaneConfig(organization, appName, archiveExt, includeCdRoms ? 1 : 0, archivesFirst ? 1 : 0); ThrowException(err); } @@ -536,9 +443,9 @@ namespace SharpPhysFS /// then the function leaves the created directory behind and reports failure. /// /// New dir to create. - public static void Mkdir(string dirName) + public void Mkdir(string dirName) { - int err = Interop.PHYSFS_mkdir(dirName); + int err = interop.PHYSFS_mkdir(dirName); ThrowException(err); } @@ -563,9 +470,9 @@ namespace SharpPhysFS /// Don't consider this a security method or anything. :) /// /// Filename to delete. - public static void Delete(string filename) + public void Delete(string filename) { - int err = Interop.PHYSFS_delete(filename); + int err = interop.PHYSFS_delete(filename); ThrowException(err); } @@ -587,9 +494,9 @@ namespace SharpPhysFS /// /// File to look for. /// String of element of search path containing the the file in question. null if not found. - public static string GetRealDir(string filename) + public string GetRealDir(string filename) { - return Marshal.PtrToStringAnsi(Interop.PHYSFS_getRealDir(filename)); + return Marshal.PtrToStringAnsi(interop.PHYSFS_getRealDir(filename)); } /// @@ -602,9 +509,9 @@ namespace SharpPhysFS /// /// Filename in platform-independent notation. /// True if filename exists. false otherwise. - public static bool Exists(string fname) + public bool Exists(string fname) { - return Interop.PHYSFS_exists(fname) != 0; + return interop.PHYSFS_exists(fname) != 0; } /// @@ -614,9 +521,9 @@ namespace SharpPhysFS /// Note that entries that are symlinks are ignored if PhysFS.PermitSymbolicLinks(true) hasn't been called, so you might end up further down in the search path than expected. /// Filename in platform-independent notation. /// True if filename exists and is a directory. False otherwise. - public static bool IsDirectory(string fname) + public bool IsDirectory(string fname) { - return Interop.PHYSFS_isDirectory(fname) != 0; + return interop.PHYSFS_isDirectory(fname) != 0; } /// @@ -626,9 +533,9 @@ namespace SharpPhysFS /// Note that entries that are symlinks are ignored if PhysFS.PermitSymbolicLinks(true) hasn't been called, and as such, this function will always return false in that case. /// Filename in platform-independent notation. /// True if filename exists and is a symlink. False otherwise. - public static bool IsSymbolicLink(string fname) + public bool IsSymbolicLink(string fname) { - return Interop.PHYSFS_isSymbolicLink(fname) != 0; + return interop.PHYSFS_isSymbolicLink(fname) != 0; } /// @@ -641,9 +548,9 @@ namespace SharpPhysFS /// /// Filename to check, in platform-independent notation. /// Last modified time of the file. -1 if it can't be determined. - public static long GetLastModTime(string fname) + public long GetLastModTime(string fname) { - return Interop.PHYSFS_getLastModTime(fname); + return interop.PHYSFS_getLastModTime(fname); } /// @@ -654,9 +561,9 @@ namespace SharpPhysFS /// Before a successful PhysFS.Init() and after PhysFS.Deinit() returns successfully, this will return false. This function is safe to call at any time. /// /// True if library is initialized, false if library is not. - public static bool IsInit() + public bool IsInit() { - return Interop.PHYSFS_isInit() != 0; + return interop.PHYSFS_isInit() != 0; } /// @@ -667,14 +574,14 @@ namespace SharpPhysFS /// If PhysFS.PermitSymbolicLinks() hasn't been called since the library was last initialized, symbolic links are implicitly disabled. /// /// True if symlinks are permitted, false if not. - public static bool SymbolicLinksPermitted() + public bool SymbolicLinksPermitted() { - return Interop.PHYSFS_symbolicLinksPermitted() != 0; + return interop.PHYSFS_symbolicLinksPermitted() != 0; } - public static void SetAllocator(Allocator allocator) + public void SetAllocator(Allocator allocator) { - int err = Interop.PHYSFS_setAllocator(allocator); + int err = interop.PHYSFS_setAllocator(allocator); ThrowException(err); } @@ -690,17 +597,17 @@ namespace SharpPhysFS /// This must match the string used when adding, even if your string would also reference the same file with a different string of characters. /// /// String of mount point if added to path - public static string GetMountPoint(string dir) + public string GetMountPoint(string dir) { - var s = Marshal.PtrToStringAnsi(Interop.PHYSFS_getMountPoint(dir)); + var s = Marshal.PtrToStringAnsi(interop.PHYSFS_getMountPoint(dir)); if(s == null) { - throw new PhysFSException(); + throw new PhysFSException(this); } return s; } - static StringCallback WrapStringCallback(Action c) + StringCallback WrapStringCallback(Action c) { return (d, s) => { @@ -709,10 +616,10 @@ namespace SharpPhysFS }; } - public static void GetCdRomDirsCallback(StringCallback c, object data) + public void GetCdRomDirsCallback(StringCallback c, object data) { GCHandle objHandle = GCHandle.Alloc(data); - Interop.PHYSFS_getCdRomDirsCallback(c, GCHandle.ToIntPtr(objHandle)); + interop.PHYSFS_getCdRomDirsCallback(c, GCHandle.ToIntPtr(objHandle)); objHandle.Free(); } @@ -722,15 +629,15 @@ namespace SharpPhysFS /// Type of data passed to callback /// Callback function to notify about detected drives. /// Application-defined data passed to callback. Can be null. - public static void GetCdRomDirsCallback(Action c, T data) + public void GetCdRomDirsCallback(Action c, T data) { GetCdRomDirsCallback(WrapStringCallback(c), data); } - public static void GetSearchPathCallback(StringCallback c, object data) + public void GetSearchPathCallback(StringCallback c, object data) { GCHandle objHandle = GCHandle.Alloc(data); - Interop.PHYSFS_getSearchPathCallback(c, GCHandle.ToIntPtr(objHandle)); + interop.PHYSFS_getSearchPathCallback(c, GCHandle.ToIntPtr(objHandle)); objHandle.Free(); } @@ -740,15 +647,15 @@ namespace SharpPhysFS /// Type of data passed to callback /// Callback function to notify about search path elements. /// Application-defined data passed to callback. Can be null. - public static void GetSearchPathCallback(Action c, T data) + public void GetSearchPathCallback(Action c, T data) { GetSearchPathCallback(WrapStringCallback(c), data); } - public static void EnumerateFilesCallback(string dir, EnumFilesCallback c, object data) + public void EnumerateFilesCallback(string dir, EnumFilesCallback c, object data) { GCHandle objHandle = GCHandle.Alloc(data); - Interop.PHYSFS_enumerateFilesCallback(dir, c, GCHandle.ToIntPtr(objHandle)); + interop.PHYSFS_enumerateFilesCallback(dir, c, GCHandle.ToIntPtr(objHandle)); objHandle.Free(); } @@ -759,7 +666,7 @@ namespace SharpPhysFS /// Directory, in platform-independent notation, to enumerate. /// Callback function to notify about search path elements. /// Application-defined data passed to callback. Can be null. - public static void EnumerateFilesCallback(string dir, Action c, T data) + public void EnumerateFilesCallback(string dir, Action c, T data) { EnumerateFilesCallback(dir, (d, o, n) => { @@ -767,5 +674,28 @@ namespace SharpPhysFS c(obj, o, n); }, data); } + + public PhysFSStream OpenAppend(string file) + { + var handle = LowLevel.OpenAppend(file, this); + return new PhysFSStream(this, handle, false); + } + + public PhysFSStream OpenRead(string file) + { + var handle = LowLevel.OpenRead(file, this); + return new PhysFSStream(this, handle, true); + } + + public PhysFSStream OpenWrite(string file) + { + var handle = LowLevel.OpenWrite(file, this); + return new PhysFSStream(this, handle, false); + } + + public void Dispose() + { + Deinit(); + } } } diff --git a/SharpPhysFS/PhysFSStream.cs b/SharpPhysFS/PhysFSStream.cs index 5d21cc7..d77e742 100644 --- a/SharpPhysFS/PhysFSStream.cs +++ b/SharpPhysFS/PhysFSStream.cs @@ -3,33 +3,17 @@ using System.IO; namespace SharpPhysFS { - public enum OpenMode - { - Append, - Read, - Write - } - public class PhysFSStream : Stream { IntPtr handle; bool readOnly = false; + PhysFS physFS; - public PhysFSStream(string filename, OpenMode mode) + internal PhysFSStream(PhysFS pfs, IntPtr ptr, bool readOnly) { - switch (mode) - { - case OpenMode.Append: - handle = PhysFS.LowLevel.OpenAppend(filename); - break; - case OpenMode.Read: - handle = PhysFS.LowLevel.OpenRead(filename); - readOnly = true; - break; - case OpenMode.Write: - handle = PhysFS.LowLevel.OpenAppend(filename); - break; - } + handle = ptr; + this.readOnly = readOnly; + physFS = pfs; } public override bool CanRead @@ -58,14 +42,14 @@ namespace SharpPhysFS public override void Flush() { - PhysFS.LowLevel.Flush(handle); + PhysFS.LowLevel.Flush(handle, physFS); } public override long Length { get { - return PhysFS.LowLevel.FileLength(handle); + return PhysFS.LowLevel.FileLength(handle, physFS); } } @@ -73,17 +57,17 @@ namespace SharpPhysFS { get { - return PhysFS.LowLevel.Tell(handle); + return PhysFS.LowLevel.Tell(handle, physFS); } set { - PhysFS.LowLevel.Seek(handle, (ulong)value); + PhysFS.LowLevel.Seek(handle, (ulong)value, physFS); } } public long Read(byte[] buffer, uint offset, uint count) { - return PhysFS.LowLevel.Read(handle, buffer, 1, count); + return PhysFS.LowLevel.Read(handle, buffer, 1, count, physFS); } public override int Read(byte[] buffer, int offset, int count) @@ -97,22 +81,17 @@ namespace SharpPhysFS if (origin == SeekOrigin.Begin) pos = 0; else if (origin == SeekOrigin.Current) - pos = PhysFS.LowLevel.Tell(handle); + pos = PhysFS.LowLevel.Tell(handle, physFS); else - pos = PhysFS.LowLevel.FileLength(handle); + pos = PhysFS.LowLevel.FileLength(handle, physFS); - PhysFS.LowLevel.Seek(handle, (ulong)(pos + offset)); + PhysFS.LowLevel.Seek(handle, (ulong)(pos + offset), physFS); return pos + offset; } - public override void SetLength(long value) - { - throw new NotImplementedException(); - } - public long Write(byte[] buffer, uint offset, uint count) { - return PhysFS.LowLevel.Write(handle, buffer, 1, count); + return PhysFS.LowLevel.Write(handle, buffer, 1, count, physFS); } public override void Write(byte[] buffer, int offset, int count) @@ -120,18 +99,20 @@ namespace SharpPhysFS Write(buffer, (uint)offset, (uint)count); } - public override void Close() + public override void SetLength(long value) { - PhysFS.LowLevel.Close(handle); - handle = IntPtr.Zero; - base.Close(); + throw new NotImplementedException(); } protected override void Dispose(bool disposing) { - if(handle != IntPtr.Zero) + if(disposing) { - Close(); + if (handle != IntPtr.Zero) + { + PhysFS.LowLevel.Close(handle, physFS); + handle = IntPtr.Zero; + } } base.Dispose(disposing); } diff --git a/SharpPhysFS/SharpPhysFS.csproj b/SharpPhysFS/SharpPhysFS.csproj index 6f9d7a1..9cc4be1 100644 --- a/SharpPhysFS/SharpPhysFS.csproj +++ b/SharpPhysFS/SharpPhysFS.csproj @@ -37,6 +37,7 @@ + diff --git a/Test/Program.cs b/Test/Program.cs index 09dcbed..73508e5 100644 --- a/Test/Program.cs +++ b/Test/Program.cs @@ -10,11 +10,13 @@ namespace Test { class Program { + static PhysFS physFS; + static void PrintSupportedArchives() { Console.Write("Supported archive types: "); bool any = false; - foreach (var archive in PhysFS.SupportedArchiveTypes()) + foreach (var archive in physFS.SupportedArchiveTypes()) { any = true; Console.WriteLine("\n - {0}: {1}", archive.extension, archive.description); @@ -103,7 +105,7 @@ namespace Test Console.WriteLine("append can only be true or false"); } - PhysFS.Mount(args[0], args[1], append); + physFS.Mount(args[0], args[1], append); return true; } @@ -115,7 +117,7 @@ namespace Test return false; } - foreach (var f in PhysFS.EnumerateFiles(args[0])) + foreach (var f in physFS.EnumerateFiles(args[0])) { Console.WriteLine(" - {0}", f); } @@ -124,19 +126,19 @@ namespace Test static bool GetLastError(string[] args) { - Console.WriteLine(PhysFS.GetLastError()); + Console.WriteLine(physFS.GetLastError()); return true; } static bool GetDirSeparator(string[] args) { - Console.WriteLine(PhysFS.GetDirSeparator()); + Console.WriteLine(physFS.GetDirSeparator()); return true; } static bool GetCdRomDirectories(string[] args) { - foreach(var d in PhysFS.GetCdRomDirs()) + foreach(var d in physFS.GetCdRomDirs()) { Console.WriteLine(" - {0}", d); } @@ -145,7 +147,7 @@ namespace Test static bool GetSearchPath(string[] args) { - foreach (var d in PhysFS.GetSearchPath()) + foreach (var d in physFS.GetSearchPath()) { Console.WriteLine(" - {0}", d); } @@ -154,19 +156,19 @@ namespace Test static bool GetBaseDirectory(string[] args) { - Console.WriteLine(PhysFS.GetBaseDir()); + Console.WriteLine(physFS.GetBaseDir()); return true; } static bool GetUserDirectory(string[] args) { - Console.WriteLine(PhysFS.GetUserDir()); + Console.WriteLine(physFS.GetUserDir()); return true; } static bool GetWriteDirectory(string[] args) { - Console.WriteLine(PhysFS.GetWriteDir()); + Console.WriteLine(physFS.GetWriteDir()); return true; } @@ -177,7 +179,7 @@ namespace Test Console.WriteLine("Usage: setwritedir "); return false; } - PhysFS.SetWriteDir(args[0]); + physFS.SetWriteDir(args[0]); return true; } @@ -193,7 +195,7 @@ namespace Test { Console.WriteLine("Usage: permitsymlinks "); } - PhysFS.PermitSymbolicLinks(permit); + physFS.PermitSymbolicLinks(permit); return true; } @@ -207,7 +209,7 @@ namespace Test bool includeCdRoms, archivesFirst; if(bool.TryParse(args[3], out includeCdRoms) && bool.TryParse(args[4], out archivesFirst)) { - PhysFS.SetSaneConfig(args[0], args[1], args[2], includeCdRoms, archivesFirst); + physFS.SetSaneConfig(args[0], args[1], args[2], includeCdRoms, archivesFirst); } else { @@ -223,7 +225,7 @@ namespace Test Console.WriteLine("Usage: mkdir "); return false; } - PhysFS.Mkdir(args[0]); + physFS.Mkdir(args[0]); return true; } @@ -234,7 +236,7 @@ namespace Test Console.WriteLine("Usage: delete "); return false; } - PhysFS.Delete(args[0]); + physFS.Delete(args[0]); return true; } @@ -245,7 +247,7 @@ namespace Test Console.WriteLine("Usage: getrealdir "); return false; } - Console.WriteLine(PhysFS.GetRealDir(args[0])); + Console.WriteLine(physFS.GetRealDir(args[0])); return true; } @@ -256,7 +258,7 @@ namespace Test Console.WriteLine("Usage: exists "); return false; } - Console.WriteLine(PhysFS.Exists(args[0])); + Console.WriteLine(physFS.Exists(args[0])); return true; } @@ -267,7 +269,7 @@ namespace Test Console.WriteLine("Usage: isdir "); return false; } - Console.WriteLine(PhysFS.IsDirectory(args[0])); + Console.WriteLine(physFS.IsDirectory(args[0])); return true; } @@ -278,7 +280,7 @@ namespace Test Console.WriteLine("Usage: issymlink "); return false; } - Console.WriteLine(PhysFS.IsSymbolicLink(args[0])); + Console.WriteLine(physFS.IsSymbolicLink(args[0])); return true; } @@ -289,7 +291,7 @@ namespace Test Console.WriteLine("Usage: cat "); return false; } - using (var reader = new System.IO.StreamReader(new PhysFSStream(args[0], OpenMode.Read))) + using (var reader = new System.IO.StreamReader(physFS.OpenRead(args[0]))) { Console.WriteLine(reader.ReadToEnd()); } @@ -303,7 +305,7 @@ namespace Test Console.WriteLine("Usage: filelength "); return false; } - using (var stream = new PhysFSStream(args[0], OpenMode.Read)) + using (var stream = physFS.OpenRead(args[0])) { Console.WriteLine(stream.Length); } @@ -316,7 +318,7 @@ namespace Test { try { - PhysFS.InitializeCallbacks(); + physFS = new PhysFS(""); } catch (PhysFSLibNotFound) { @@ -324,9 +326,8 @@ namespace Test Console.Error.WriteLine("ERROR: PhysFS could not be loaded. Are you sure it is installed or a suitable module is in your working directory?"); return; } - PhysFS.Init(""); - var version = PhysFS.GetLinkedVersion(); + var version = physFS.GetLinkedVersion(); Console.WriteLine("SharpPhysFS Test console"); Console.WriteLine("Loaded PhysFS version: {0}.{1}.{2}", version.major, version.minor, version.patch); @@ -382,7 +383,7 @@ namespace Test Console.WriteLine("Done."); } } - catch (PhysFSException e) + catch (PhysFS.PhysFSException e) { Console.ForegroundColor = ConsoleColor.Red; Console.Error.WriteLine("ERROR: {0}", e.Message); @@ -396,7 +397,7 @@ namespace Test } } - PhysFS.Deinit(); + physFS.Dispose(); } } }