diff options
| author | LukePulverenti <luke.pulverenti@gmail.com> | 2013-02-20 20:33:05 -0500 |
|---|---|---|
| committer | LukePulverenti <luke.pulverenti@gmail.com> | 2013-02-20 20:33:05 -0500 |
| commit | 767cdc1f6f6a63ce997fc9476911e2c361f9d402 (patch) | |
| tree | 49add55976f895441167c66cfa95e5c7688d18ce /MediaBrowser.Common/IO | |
| parent | 845554722efaed872948a9e0f7202e3ef52f1b6e (diff) | |
Pushing missing changes
Diffstat (limited to 'MediaBrowser.Common/IO')
| -rw-r--r-- | MediaBrowser.Common/IO/FileSystem.cs | 339 | ||||
| -rw-r--r-- | MediaBrowser.Common/IO/FileSystemRepository.cs | 211 | ||||
| -rw-r--r-- | MediaBrowser.Common/IO/IIsoManager.cs | 27 | ||||
| -rw-r--r-- | MediaBrowser.Common/IO/IIsoMount.cs | 22 | ||||
| -rw-r--r-- | MediaBrowser.Common/IO/ProgressStream.cs | 210 | ||||
| -rw-r--r-- | MediaBrowser.Common/IO/StreamDefaults.cs | 19 |
6 files changed, 828 insertions, 0 deletions
diff --git a/MediaBrowser.Common/IO/FileSystem.cs b/MediaBrowser.Common/IO/FileSystem.cs new file mode 100644 index 0000000000..e1abe7833b --- /dev/null +++ b/MediaBrowser.Common/IO/FileSystem.cs @@ -0,0 +1,339 @@ +using System.Collections.Specialized; +using MediaBrowser.Common.Logging; +using MediaBrowser.Common.Win32; +using System; +using System.Collections.Generic; +using System.IO; +using System.Runtime.InteropServices; +using System.Text; + +namespace MediaBrowser.Common.IO +{ + /// <summary> + /// Class FileSystem + /// </summary> + public static class FileSystem + { + /// <summary> + /// Gets information about a path + /// </summary> + /// <param name="path">The path.</param> + /// <returns>System.Nullable{WIN32_FIND_DATA}.</returns> + /// <exception cref="System.ArgumentNullException">path</exception> + /// <exception cref="System.IO.IOException">GetFileData failed for + path</exception> + public static WIN32_FIND_DATA? GetFileData(string path) + { + if (string.IsNullOrEmpty(path)) + { + throw new ArgumentNullException("path"); + } + + WIN32_FIND_DATA data; + var handle = NativeMethods.FindFirstFileEx(path, FINDEX_INFO_LEVELS.FindExInfoBasic, out data, + FINDEX_SEARCH_OPS.FindExSearchNameMatch, IntPtr.Zero, FindFirstFileExFlags.NONE); + + var getFilename = false; + + if (handle == NativeMethods.INVALID_HANDLE_VALUE && !Path.HasExtension(path)) + { + if (!path.EndsWith("*", StringComparison.OrdinalIgnoreCase)) + { + Logger.LogInfo("Handle came back invalid for {0}. This might be a network share. Since this is a directory we'll try appending " + Path.DirectorySeparatorChar + "*.", path); + + NativeMethods.FindClose(handle); + + handle = NativeMethods.FindFirstFileEx(Path.Combine(path, "*"), FINDEX_INFO_LEVELS.FindExInfoBasic, out data, + FINDEX_SEARCH_OPS.FindExSearchNameMatch, IntPtr.Zero, FindFirstFileExFlags.NONE); + + getFilename = true; + } + } + + if (handle == IntPtr.Zero) + { + throw new IOException("GetFileData failed for " + path); + } + + NativeMethods.FindClose(handle); + + // According to MSDN documentation, this will default to 1601 for paths that don't exist. + if (data.CreationTimeUtc.Year == 1601) + { + return null; + } + + if (getFilename) + { + data.cFileName = Path.GetFileName(path); + } + + data.Path = path; + return data; + } + + /// <summary> + /// Gets all files within a folder + /// </summary> + /// <param name="path">The path.</param> + /// <param name="searchPattern">The search pattern.</param> + /// <returns>IEnumerable{WIN32_FIND_DATA}.</returns> + public static IEnumerable<WIN32_FIND_DATA> GetFiles(string path, string searchPattern = "*") + { + return GetFileSystemEntries(path, searchPattern, includeDirectories: false); + } + + /// <summary> + /// Gets all sub-directories within a folder + /// </summary> + /// <param name="path">The path.</param> + /// <returns>IEnumerable{WIN32_FIND_DATA}.</returns> + public static IEnumerable<WIN32_FIND_DATA> GetDirectories(string path) + { + return GetFileSystemEntries(path, includeFiles: false); + } + + /// <summary> + /// Gets all file system entries within a foler + /// </summary> + /// <param name="path">The path.</param> + /// <param name="searchPattern">The search pattern.</param> + /// <param name="includeFiles">if set to <c>true</c> [include files].</param> + /// <param name="includeDirectories">if set to <c>true</c> [include directories].</param> + /// <returns>IEnumerable{WIN32_FIND_DATA}.</returns> + /// <exception cref="System.ArgumentNullException">path</exception> + /// <exception cref="System.IO.IOException">GetFileSystemEntries failed</exception> + public static IEnumerable<WIN32_FIND_DATA> GetFileSystemEntries(string path, string searchPattern = "*", bool includeFiles = true, bool includeDirectories = true) + { + if (string.IsNullOrEmpty(path)) + { + throw new ArgumentNullException("path"); + } + + var lpFileName = Path.Combine(path, searchPattern); + + WIN32_FIND_DATA lpFindFileData; + var handle = NativeMethods.FindFirstFileEx(lpFileName, FINDEX_INFO_LEVELS.FindExInfoBasic, out lpFindFileData, + FINDEX_SEARCH_OPS.FindExSearchNameMatch, IntPtr.Zero, FindFirstFileExFlags.FIND_FIRST_EX_LARGE_FETCH); + + if (handle == IntPtr.Zero) + { + var hr = Marshal.GetLastWin32Error(); + if (hr != 2 && hr != 0x12) + { + throw new IOException("GetFileSystemEntries failed"); + } + yield break; + } + + if (IncludeInFindFileOutput(lpFindFileData.cFileName, lpFindFileData.dwFileAttributes, includeFiles, includeDirectories)) + { + lpFindFileData.Path = Path.Combine(path, lpFindFileData.cFileName); + + yield return lpFindFileData; + } + + while (NativeMethods.FindNextFile(handle, out lpFindFileData) != IntPtr.Zero) + { + if (IncludeInFindFileOutput(lpFindFileData.cFileName, lpFindFileData.dwFileAttributes, includeFiles, includeDirectories)) + { + lpFindFileData.Path = Path.Combine(path, lpFindFileData.cFileName); + yield return lpFindFileData; + } + } + + NativeMethods.FindClose(handle); + } + + /// <summary> + /// Includes the in find file output. + /// </summary> + /// <param name="cFileName">Name of the c file.</param> + /// <param name="attributes">The attributes.</param> + /// <param name="includeFiles">if set to <c>true</c> [include files].</param> + /// <param name="includeDirectories">if set to <c>true</c> [include directories].</param> + /// <returns><c>true</c> if XXXX, <c>false</c> otherwise</returns> + public static bool IncludeInFindFileOutput(string cFileName, FileAttributes attributes, bool includeFiles, bool includeDirectories) + { + if (cFileName.Equals(".", StringComparison.OrdinalIgnoreCase)) + { + return false; + } + if (cFileName.Equals("..", StringComparison.OrdinalIgnoreCase)) + { + return false; + } + + if (!includeFiles && !attributes.HasFlag(FileAttributes.Directory)) + { + return false; + } + + if (!includeDirectories && attributes.HasFlag(FileAttributes.Directory)) + { + return false; + } + + return true; + } + + /// <summary> + /// The space char + /// </summary> + private const char SpaceChar = ' '; + /// <summary> + /// The invalid file name chars + /// </summary> + private static readonly char[] InvalidFileNameChars = Path.GetInvalidFileNameChars(); + + /// <summary> + /// Takes a filename and removes invalid characters + /// </summary> + /// <param name="filename">The filename.</param> + /// <returns>System.String.</returns> + /// <exception cref="System.ArgumentNullException">filename</exception> + public static string GetValidFilename(string filename) + { + if (string.IsNullOrEmpty(filename)) + { + throw new ArgumentNullException("filename"); + } + + foreach (var c in InvalidFileNameChars) + { + filename = filename.Replace(c, SpaceChar); + } + + return filename; + } + + /// <summary> + /// Resolves the shortcut. + /// </summary> + /// <param name="filename">The filename.</param> + /// <returns>System.String.</returns> + /// <exception cref="System.ArgumentNullException">filename</exception> + public static string ResolveShortcut(string filename) + { + if (string.IsNullOrEmpty(filename)) + { + throw new ArgumentNullException("filename"); + } + + var link = new ShellLink(); + ((IPersistFile)link).Load(filename, NativeMethods.STGM_READ); + // TODO: if I can get hold of the hwnd call resolve first. This handles moved and renamed files. + // ((IShellLinkW)link).Resolve(hwnd, 0) + var sb = new StringBuilder(NativeMethods.MAX_PATH); + WIN32_FIND_DATA data; + ((IShellLinkW)link).GetPath(sb, sb.Capacity, out data, 0); + return sb.ToString(); + } + + /// <summary> + /// Creates a shortcut file pointing to a specified path + /// </summary> + /// <param name="shortcutPath">The shortcut path.</param> + /// <param name="target">The target.</param> + /// <exception cref="System.ArgumentNullException">shortcutPath</exception> + public static void CreateShortcut(string shortcutPath, string target) + { + if (string.IsNullOrEmpty(shortcutPath)) + { + throw new ArgumentNullException("shortcutPath"); + } + + if (string.IsNullOrEmpty(target)) + { + throw new ArgumentNullException("target"); + } + + var link = new ShellLink(); + + ((IShellLinkW)link).SetPath(target); + + ((IPersistFile)link).Save(shortcutPath, true); + } + + /// <summary> + /// Determines whether the specified filename is shortcut. + /// </summary> + /// <param name="filename">The filename.</param> + /// <returns><c>true</c> if the specified filename is shortcut; otherwise, <c>false</c>.</returns> + /// <exception cref="System.ArgumentNullException">filename</exception> + public static bool IsShortcut(string filename) + { + if (string.IsNullOrEmpty(filename)) + { + throw new ArgumentNullException("filename"); + } + + return string.Equals(Path.GetExtension(filename), ".lnk", StringComparison.OrdinalIgnoreCase); + } + + /// <summary> + /// Copies all. + /// </summary> + /// <param name="source">The source.</param> + /// <param name="target">The target.</param> + /// <exception cref="System.ArgumentNullException">source</exception> + /// <exception cref="System.ArgumentException">The source and target directories are the same</exception> + public static void CopyAll(string source, string target) + { + if (string.IsNullOrEmpty(source)) + { + throw new ArgumentNullException("source"); + } + if (string.IsNullOrEmpty(target)) + { + throw new ArgumentNullException("target"); + } + + if (source.Equals(target, StringComparison.OrdinalIgnoreCase)) + { + throw new ArgumentException("The source and target directories are the same"); + } + + // Check if the target directory exists, if not, create it. + if (!Directory.Exists(target)) + { + Directory.CreateDirectory(target); + } + + foreach (var file in Directory.EnumerateFiles(source)) + { + File.Copy(file, Path.Combine(target, Path.GetFileName(file)), true); + } + + // Copy each subdirectory using recursion. + foreach (var dir in Directory.EnumerateDirectories(source)) + { + CopyAll(dir, Path.Combine(target, Path.GetFileName(dir))); + } + } + + /// <summary> + /// Parses the ini file. + /// </summary> + /// <param name="path">The path.</param> + /// <returns>NameValueCollection.</returns> + public static NameValueCollection ParseIniFile(string path) + { + var values = new NameValueCollection(); + + foreach (var line in File.ReadAllLines(path)) + { + var data = line.Split('='); + + if (data.Length < 2) continue; + + var key = data[0]; + + var value = data.Length == 2 ? data[1] : string.Join(string.Empty, data, 1, data.Length - 1); + + values[key] = value; + } + + return values; + } + } +} diff --git a/MediaBrowser.Common/IO/FileSystemRepository.cs b/MediaBrowser.Common/IO/FileSystemRepository.cs new file mode 100644 index 0000000000..24ad04a926 --- /dev/null +++ b/MediaBrowser.Common/IO/FileSystemRepository.cs @@ -0,0 +1,211 @@ +using MediaBrowser.Common.Extensions; +using System; +using System.Collections.Concurrent; +using System.IO; +using System.Threading.Tasks; + +namespace MediaBrowser.Common.IO +{ + /// <summary> + /// This is a wrapper for storing large numbers of files within a directory on a file system. + /// Simply pass a filename into GetResourcePath and it will return a full path location of where the file should be stored. + /// </summary> + public class FileSystemRepository : IDisposable + { + /// <summary> + /// Contains the list of subfolders under the main directory + /// The directory entry is created when the item is first added to the dictionary + /// </summary> + private readonly ConcurrentDictionary<string, string> _subFolderPaths = new ConcurrentDictionary<string, string>(); + + /// <summary> + /// The _file locks + /// </summary> + private readonly NamedLock _fileLocks = new NamedLock(); + + /// <summary> + /// Gets or sets the path. + /// </summary> + /// <value>The path.</value> + protected string Path { get; set; } + + /// <summary> + /// Initializes a new instance of the <see cref="FileSystemRepository" /> class. + /// </summary> + /// <param name="path">The path.</param> + /// <exception cref="System.ArgumentNullException"></exception> + public FileSystemRepository(string path) + { + if (string.IsNullOrEmpty(path)) + { + throw new ArgumentNullException(); + } + + Path = path; + Initialize(); + } + + /// <summary> + /// Initializes this instance. + /// </summary> + protected void Initialize() + { + if (!Directory.Exists(Path)) + { + Directory.CreateDirectory(Path); + } + } + + /// <summary> + /// Gets the full path of where a resource should be stored within the repository + /// </summary> + /// <param name="uniqueName">Name of the unique.</param> + /// <param name="fileExtension">The file extension.</param> + /// <returns>System.String.</returns> + /// <exception cref="System.ArgumentNullException"></exception> + public string GetResourcePath(string uniqueName, string fileExtension) + { + if (string.IsNullOrEmpty(uniqueName)) + { + throw new ArgumentNullException(); + } + + if (string.IsNullOrEmpty(fileExtension)) + { + throw new ArgumentNullException(); + } + + var filename = uniqueName.GetMD5() + fileExtension; + + return GetResourcePath(filename); + } + + /// <summary> + /// Gets the full path of where a file should be stored within the repository + /// </summary> + /// <param name="filename">The filename.</param> + /// <returns>System.String.</returns> + /// <exception cref="System.ArgumentNullException"></exception> + public string GetResourcePath(string filename) + { + if (string.IsNullOrEmpty(filename)) + { + throw new ArgumentNullException(); + } + + return GetInternalResourcePath(filename); + } + + /// <summary> + /// Takes a filename and returns the full path of where it should be stored + /// </summary> + /// <param name="filename">The filename.</param> + /// <returns>System.String.</returns> + private string GetInternalResourcePath(string filename) + { + var prefix = filename.Substring(0, 1); + + var folder = _subFolderPaths.GetOrAdd(prefix, GetCachePath); + + return System.IO.Path.Combine(folder, filename); + } + + /// <summary> + /// Creates a subfolder under the image cache directory and returns the full path + /// </summary> + /// <param name="prefix">The prefix.</param> + /// <returns>System.String.</returns> + private string GetCachePath(string prefix) + { + var path = System.IO.Path.Combine(Path, prefix); + + if (!Directory.Exists(path)) + { + Directory.CreateDirectory(path); + } + + return path; + } + + /// <summary> + /// Determines if a resource is present in the repository + /// </summary> + /// <param name="uniqueName">Name of the unique.</param> + /// <param name="fileExtension">The file extension.</param> + /// <returns><c>true</c> if the specified unique name contains resource; otherwise, <c>false</c>.</returns> + public bool ContainsResource(string uniqueName, string fileExtension) + { + return ContainsFilePath(GetResourcePath(uniqueName, fileExtension)); + } + + /// <summary> + /// Determines if a file with a given name is present in the repository + /// </summary> + /// <param name="filename">The filename.</param> + /// <returns><c>true</c> if the specified filename contains filename; otherwise, <c>false</c>.</returns> + /// <exception cref="System.ArgumentNullException"></exception> + public bool ContainsFilename(string filename) + { + if (string.IsNullOrEmpty(filename)) + { + throw new ArgumentNullException(); + } + + return ContainsFilePath(GetInternalResourcePath(filename)); + } + + /// <summary> + /// Determines if a file is present in the repository + /// </summary> + /// <param name="path">The path.</param> + /// <returns><c>true</c> if [contains file path] [the specified path]; otherwise, <c>false</c>.</returns> + /// <exception cref="System.ArgumentNullException"></exception> + public bool ContainsFilePath(string path) + { + if (string.IsNullOrEmpty(path)) + { + throw new ArgumentNullException(); + } + + return File.Exists(path); + } + + /// <summary> + /// Waits for lock. + /// </summary> + /// <param name="resourcePath">The resource path.</param> + public Task WaitForLockAsync(string resourcePath) + { + return _fileLocks.WaitAsync(resourcePath); + } + + /// <summary> + /// Releases the lock. + /// </summary> + /// <param name="resourcePath">The resource path.</param> + public void ReleaseLock(string resourcePath) + { + _fileLocks.Release(resourcePath); + } + + /// <summary> + /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. + /// </summary> + public void Dispose() + { + Dispose(true); + } + + /// <summary> + /// Releases unmanaged and - optionally - managed resources. + /// </summary> + /// <param name="dispose"><c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only unmanaged resources.</param> + protected virtual void Dispose(bool dispose) + { + if (dispose) + { + _fileLocks.Dispose(); + } + } + } +} diff --git a/MediaBrowser.Common/IO/IIsoManager.cs b/MediaBrowser.Common/IO/IIsoManager.cs new file mode 100644 index 0000000000..8e94189c4a --- /dev/null +++ b/MediaBrowser.Common/IO/IIsoManager.cs @@ -0,0 +1,27 @@ +using System; +using System.Threading; +using System.Threading.Tasks; + +namespace MediaBrowser.Common.IO +{ + public interface IIsoManager : IDisposable + { + /// <summary> + /// Mounts the specified iso path. + /// </summary> + /// <param name="isoPath">The iso path.</param> + /// <param name="cancellationToken">The cancellation token.</param> + /// <param name="visibleToAllProcesses">if set to <c>true</c> [visible to all processes].</param> + /// <returns>IsoMount.</returns> + /// <exception cref="System.ArgumentNullException">isoPath</exception> + /// <exception cref="System.IO.IOException">Unable to create mount.</exception> + Task<IIsoMount> Mount(string isoPath, CancellationToken cancellationToken, bool visibleToAllProcesses = true); + + /// <summary> + /// Determines whether this instance can mount the specified path. + /// </summary> + /// <param name="path">The path.</param> + /// <returns><c>true</c> if this instance can mount the specified path; otherwise, <c>false</c>.</returns> + bool CanMount(string path); + } +}
\ No newline at end of file diff --git a/MediaBrowser.Common/IO/IIsoMount.cs b/MediaBrowser.Common/IO/IIsoMount.cs new file mode 100644 index 0000000000..c6dabc3b9d --- /dev/null +++ b/MediaBrowser.Common/IO/IIsoMount.cs @@ -0,0 +1,22 @@ +using System; + +namespace MediaBrowser.Common.IO +{ + /// <summary> + /// Interface IIsoMount + /// </summary> + public interface IIsoMount : IDisposable + { + /// <summary> + /// Gets or sets the iso path. + /// </summary> + /// <value>The iso path.</value> + string IsoPath { get; } + + /// <summary> + /// Gets the mounted path. + /// </summary> + /// <value>The mounted path.</value> + string MountedPath { get; } + } +}
\ No newline at end of file diff --git a/MediaBrowser.Common/IO/ProgressStream.cs b/MediaBrowser.Common/IO/ProgressStream.cs new file mode 100644 index 0000000000..d41c715d9c --- /dev/null +++ b/MediaBrowser.Common/IO/ProgressStream.cs @@ -0,0 +1,210 @@ +using System; +using System.IO; + +namespace MediaBrowser.Common.IO +{ + /// <summary> + /// Measures progress when reading from a stream or writing to one + /// </summary> + public class ProgressStream : Stream + { + /// <summary> + /// Gets the base stream. + /// </summary> + /// <value>The base stream.</value> + public Stream BaseStream { get; private set; } + + /// <summary> + /// Gets or sets the bytes processed. + /// </summary> + /// <value>The bytes processed.</value> + private long BytesProcessed { get; set; } + /// <summary> + /// Gets or sets the length of the write. + /// </summary> + /// <value>The length of the write.</value> + private long WriteLength { get; set; } + + /// <summary> + /// Gets or sets the length of the read. + /// </summary> + /// <value>The length of the read.</value> + private long? ReadLength { get; set; } + + /// <summary> + /// Gets or sets the progress action. + /// </summary> + /// <value>The progress action.</value> + private Action<double> ProgressAction { get; set; } + + /// <summary> + /// Creates the read progress stream. + /// </summary> + /// <param name="baseStream">The base stream.</param> + /// <param name="progressAction">The progress action.</param> + /// <param name="readLength">Length of the read.</param> + /// <returns>ProgressStream.</returns> + public static ProgressStream CreateReadProgressStream(Stream baseStream, Action<double> progressAction, long? readLength = null) + { + return new ProgressStream + { + BaseStream = baseStream, + ProgressAction = progressAction, + ReadLength = readLength + }; + } + + /// <summary> + /// Creates the write progress stream. + /// </summary> + /// <param name="baseStream">The base stream.</param> + /// <param name="progressAction">The progress action.</param> + /// <param name="writeLength">Length of the write.</param> + /// <returns>ProgressStream.</returns> + public static ProgressStream CreateWriteProgressStream(Stream baseStream, Action<double> progressAction, long writeLength) + { + return new ProgressStream + { + BaseStream = baseStream, + ProgressAction = progressAction, + WriteLength = writeLength + }; + } + + /// <summary> + /// When overridden in a derived class, gets a value indicating whether the current stream supports reading. + /// </summary> + /// <value><c>true</c> if this instance can read; otherwise, <c>false</c>.</value> + /// <returns>true if the stream supports reading; otherwise, false.</returns> + public override bool CanRead + { + get { return BaseStream.CanRead; } + } + + /// <summary> + /// When overridden in a derived class, gets a value indicating whether the current stream supports seeking. + /// </summary> + /// <value><c>true</c> if this instance can seek; otherwise, <c>false</c>.</value> + /// <returns>true if the stream supports seeking; otherwise, false.</returns> + public override bool CanSeek + { + get { return BaseStream.CanSeek; } + } + + /// <summary> + /// When overridden in a derived class, gets a value indicating whether the current stream supports writing. + /// </summary> + /// <value><c>true</c> if this instance can write; otherwise, <c>false</c>.</value> + /// <returns>true if the stream supports writing; otherwise, false.</returns> + public override bool CanWrite + { + get { return BaseStream.CanWrite; } + } + + /// <summary> + /// When overridden in a derived class, clears all buffers for this stream and causes any buffered data to be written to the underlying device. + /// </summary> + public override void Flush() + { + BaseStream.Flush(); + } + + /// <summary> + /// When overridden in a derived class, gets the length in bytes of the stream. + /// </summary> + /// <value>The length.</value> + /// <returns>A long value representing the length of the stream in bytes.</returns> + public override long Length + { + get { return BaseStream.Length; } + } + + /// <summary> + /// When overridden in a derived class, gets or sets the position within the current stream. + /// </summary> + /// <value>The position.</value> + /// <returns>The current position within the stream.</returns> + public override long Position + { + get { return BaseStream.Position; } + set + { + BaseStream.Position = value; + } + } + + /// <summary> + /// When overridden in a derived class, reads a sequence of bytes from the current stream and advances the position within the stream by the number of bytes read. + /// </summary> + /// <param name="buffer">An array of bytes. When this method returns, the buffer contains the specified byte array with the values between <paramref name="offset" /> and (<paramref name="offset" /> + <paramref name="count" /> - 1) replaced by the bytes read from the current source.</param> + /// <param name="offset">The zero-based byte offset in <paramref name="buffer" /> at which to begin storing the data read from the current stream.</param> + /// <param name="count">The maximum number of bytes to be read from the current stream.</param> + /// <returns>The total number of bytes read into the buffer. This can be less than the number of bytes requested if that many bytes are not currently available, or zero (0) if the end of the stream has been reached.</returns> + public override int Read(byte[] buffer, int offset, int count) + { + var read = BaseStream.Read(buffer, offset, count); + + BytesProcessed += read; + + double percent = BytesProcessed; + percent /= (ReadLength ?? BaseStream.Length); + percent *= 100; + + ProgressAction(percent); + + return read; + } + + /// <summary> + /// When overridden in a derived class, sets the position within the current stream. + /// </summary> + /// <param name="offset">A byte offset relative to the <paramref name="origin" /> parameter.</param> + /// <param name="origin">A value of type <see cref="T:System.IO.SeekOrigin" /> indicating the reference point used to obtain the new position.</param> + /// <returns>The new position within the current stream.</returns> + public override long Seek(long offset, SeekOrigin origin) + { + return BaseStream.Seek(offset, origin); + } + + /// <summary> + /// When overridden in a derived class, sets the length of the current stream. + /// </summary> + /// <param name="value">The desired length of the current stream in bytes.</param> + public override void SetLength(long value) + { + BaseStream.SetLength(value); + } + + /// <summary> + /// When overridden in a derived class, writes a sequence of bytes to the current stream and advances the current position within this stream by the number of bytes written. + /// </summary> + /// <param name="buffer">An array of bytes. This method copies <paramref name="count" /> bytes from <paramref name="buffer" /> to the current stream.</param> + /// <param name="offset">The zero-based byte offset in <paramref name="buffer" /> at which to begin copying bytes to the current stream.</param> + /// <param name="count">The number of bytes to be written to the current stream.</param> + public override void Write(byte[] buffer, int offset, int count) + { + BaseStream.Write(buffer, offset, count); + + BytesProcessed += count; + + double percent = BytesProcessed; + percent /= WriteLength; + percent *= 100; + + ProgressAction(percent); + } + + /// <summary> + /// Releases the unmanaged resources used by the <see cref="T:System.IO.Stream" /> and optionally releases the managed resources. + /// </summary> + /// <param name="disposing">true to release both managed and unmanaged resources; false to release only unmanaged resources.</param> + protected override void Dispose(bool disposing) + { + if (disposing) + { + BaseStream.Dispose(); + } + base.Dispose(disposing); + } + } +} diff --git a/MediaBrowser.Common/IO/StreamDefaults.cs b/MediaBrowser.Common/IO/StreamDefaults.cs new file mode 100644 index 0000000000..0cbf1643fb --- /dev/null +++ b/MediaBrowser.Common/IO/StreamDefaults.cs @@ -0,0 +1,19 @@ + +namespace MediaBrowser.Common.IO +{ + /// <summary> + /// Class StreamDefaults + /// </summary> + public static class StreamDefaults + { + /// <summary> + /// The default copy to buffer size + /// </summary> + public const int DefaultCopyToBufferSize = 81920; + + /// <summary> + /// The default file stream buffer size + /// </summary> + public const int DefaultFileStreamBufferSize = 4096; + } +} |
