From 4ee816e8bcc76b45565b257e9c3dd759e9781737 Mon Sep 17 00:00:00 2001 From: goyuken Date: Sun, 12 Oct 2014 04:24:31 +0000 Subject: [PATCH] code to use 7zip (unmanaged) to write archives, not active for the moment, still stuff to do --- BizHawk.Client.Common/BinarySaveStates.cs | 12 +- .../BizHawk.Client.Common.csproj | 1 + BizHawk.Client.Common/IonicZipWriter.cs | 4 +- BizHawk.Client.Common/SavestateManager.cs | 3 +- BizHawk.Client.Common/SevenZipWriter.cs | 275 ++++++++++++++++++ BizHawk.Client.Common/SharpZipWriter.cs | 6 +- .../movie/bk2/Bk2Movie.IO.cs | 3 +- .../movie/tasproj/TasMovie.IO.cs | 3 +- .../Blobs/Blob_WaveFile.cs | 6 +- 9 files changed, 292 insertions(+), 21 deletions(-) create mode 100644 BizHawk.Client.Common/SevenZipWriter.cs diff --git a/BizHawk.Client.Common/BinarySaveStates.cs b/BizHawk.Client.Common/BinarySaveStates.cs index 3d095e4c17..b72284579e 100644 --- a/BizHawk.Client.Common/BinarySaveStates.cs +++ b/BizHawk.Client.Common/BinarySaveStates.cs @@ -252,14 +252,12 @@ namespace BizHawk.Client.Common sw.Flush(); } - /// - /// - /// - /// not closed when finished! - public BinaryStateSaver(Stream s, bool stateVersionTag = true) // stateVersionTag is a hack for reusing this for movie code + + public BinaryStateSaver(string path, bool stateVersionTag = true) // stateVersionTag is a hack for reusing this for movie code { - _zip = new IonicZipWriter(s, Global.Config.SaveStateCompressionLevelNormal); - //_zip = new SharpZipWriter(s, Global.Config.SaveStateCompressionLevelNormal); + _zip = new IonicZipWriter(path, Global.Config.SaveStateCompressionLevelNormal); + //_zip = new SharpZipWriter(path, Global.Config.SaveStateCompressionLevelNormal); + //_zip = new SevenZipWriter(path, Global.Config.SaveStateCompressionLevelNormal); if (stateVersionTag) { diff --git a/BizHawk.Client.Common/BizHawk.Client.Common.csproj b/BizHawk.Client.Common/BizHawk.Client.Common.csproj index 85265a57d7..605bd10acf 100644 --- a/BizHawk.Client.Common/BizHawk.Client.Common.csproj +++ b/BizHawk.Client.Common/BizHawk.Client.Common.csproj @@ -190,6 +190,7 @@ + diff --git a/BizHawk.Client.Common/IonicZipWriter.cs b/BizHawk.Client.Common/IonicZipWriter.cs index 0450656134..532825829b 100644 --- a/BizHawk.Client.Common/IonicZipWriter.cs +++ b/BizHawk.Client.Common/IonicZipWriter.cs @@ -13,10 +13,10 @@ namespace BizHawk.Client.Common private ZipOutputStream z; private int level; - public IonicZipWriter(Stream s, int compressionlevel) + public IonicZipWriter(string path, int compressionlevel) { level = compressionlevel; - z = new ZipOutputStream(s, true) + z = new ZipOutputStream(path) { EnableZip64 = Zip64Option.Never, CompressionLevel = (Ionic.Zlib.CompressionLevel)level diff --git a/BizHawk.Client.Common/SavestateManager.cs b/BizHawk.Client.Common/SavestateManager.cs index 1ec6be7034..945141c890 100644 --- a/BizHawk.Client.Common/SavestateManager.cs +++ b/BizHawk.Client.Common/SavestateManager.cs @@ -13,8 +13,7 @@ namespace BizHawk.Client.Common { // the old method of text savestate save is now gone. // a text savestate is just like a binary savestate, but with a different core lump - using (var fs = new FileStream(filename, FileMode.Create, FileAccess.Write)) - using (var bs = new BinaryStateSaver(fs)) + using (var bs = new BinaryStateSaver(filename)) { if (Global.Config.SaveStateType == Config.SaveStateTypeE.Text || (Global.Config.SaveStateType == Config.SaveStateTypeE.Default && !Global.Emulator.BinarySaveStatesPreferred)) diff --git a/BizHawk.Client.Common/SevenZipWriter.cs b/BizHawk.Client.Common/SevenZipWriter.cs new file mode 100644 index 0000000000..f15d1f9425 --- /dev/null +++ b/BizHawk.Client.Common/SevenZipWriter.cs @@ -0,0 +1,275 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.IO; +using System.Threading.Tasks; + +namespace BizHawk.Client.Common +{ + public class SevenZipWriter : IZipWriter + { + private class RangBuffer + { + const int LEN = 4096; + const int MASK = 4095; + byte[] buff = new byte[LEN]; + + int wpos = 0; + int rpos = 0; + + bool writeclosed; + bool readclosed; + + object sharedlock = new object(); + + public Stream W { get; private set; } + public Stream R { get; private set; } + + public RangBuffer() + { + W = new WStream(this); + R = new RStream(this); + } + + public int Read(byte[] buffer, int offset, int count) + { + int ret = 0; + while (count > 0) + { + lock (sharedlock) + { + int start = rpos; + int end = wpos; + if (end < start) // wrap + end = LEN; + if (end - start > count) + end = start + count; + + int c = end - start; + if (c > 0) + { + Buffer.BlockCopy(buff, start, buffer, offset, c); + count -= c; + ret += c; + offset += c; + rpos = end & MASK; + } + else if (writeclosed) + { + break; + } + else + { + // todo: don't spin here + } + } + } + return ret; + } + + public void CloseRead() + { + lock (sharedlock) + readclosed = true; + } + + public int Write(byte[] buffer, int offset, int count) + { + int ret = 0; + while (count > 0) + { + lock (sharedlock) + { + int start = wpos; + int end = (rpos - 1) & MASK; + if (end < start) // wrap + end = LEN; + if (end - start > count) + end = start + count; + + int c = end - start; + if (c > 0) + { + Buffer.BlockCopy(buffer, offset, buff, start, c); + count -= c; + ret += c; + offset += c; + wpos = end & MASK; + } + else if (readclosed) + { + break; + } + else + { + // todo: don't spin here + } + } + } + return ret; + } + + public void CloseWrite() + { + lock (sharedlock) + writeclosed = true; + } + + private class WStream : Stream + { + public override bool CanRead { get { return false; } } + public override bool CanSeek { get { return false; } } + public override bool CanWrite { get { return true; } } + public override void Flush() { } + public override long Length { get { throw new NotSupportedException(); } } + public override long Seek(long offset, SeekOrigin origin) { throw new NotSupportedException(); } + public override void SetLength(long value) { throw new NotSupportedException(); } + public override long Position + { + get { throw new NotSupportedException(); } + set { throw new NotSupportedException(); } + } + + private RangBuffer _r; + private long _total; // bytes written so far + public WStream(RangBuffer r) + { + this._r = r; + } + + public override int Read(byte[] buffer, int offset, int count) + { + throw new NotSupportedException(); + } + + public override void Write(byte[] buffer, int offset, int count) + { + int cnt = _r.Write(buffer, offset, count); + _total += cnt; + if (cnt < count) + throw new IOException("broken pipe"); + } + + protected override void Dispose(bool disposing) + { + if (disposing && _r != null) + { + _r.CloseWrite(); + _r = null; + } + base.Dispose(disposing); + } + } + private class RStream : Stream + { + public override bool CanRead { get { return true; } } + public override bool CanSeek { get { return false; } } + public override bool CanWrite { get { return false; } } + public override void Flush() { } + public override long Length { get { return 1; } } // { get { throw new NotSupportedException(); } } + public override long Seek(long offset, SeekOrigin origin) { return 0; } // { throw new NotSupportedException(); } + public override void SetLength(long value) { throw new NotSupportedException(); } + public override long Position + { + get { throw new NotSupportedException(); } + set { throw new NotSupportedException(); } + } + + private RangBuffer _r; + private long _total; // bytes read so far + public RStream(RangBuffer r) + { + this._r = r; + } + + public override int Read(byte[] buffer, int offset, int count) + { + int cnt = _r.Read(buffer, offset, count); + _total += cnt; + return cnt; + } + + public override void Write(byte[] buffer, int offset, int count) + { + throw new NotSupportedException(); + } + + protected override void Dispose(bool disposing) + { + if (disposing && _r != null) + { + _r.CloseRead(); + _r = null; + } + base.Dispose(disposing); + } + } + } + + SevenZip.SevenZipCompressor svc; + + bool first = true; + string path; + int compressionlevel; + + public SevenZipWriter(string path, int compressionlevel) + { + this.path = path; + this.compressionlevel = compressionlevel; + + svc = new SevenZip.SevenZipCompressor(); + svc.ArchiveFormat = SevenZip.OutArchiveFormat.Zip; + + switch (compressionlevel) + { + default: + case 0: svc.CompressionLevel = SevenZip.CompressionLevel.None; break; + case 1: + case 2: svc.CompressionLevel = SevenZip.CompressionLevel.Fast; break; + case 3: + case 4: svc.CompressionLevel = SevenZip.CompressionLevel.Low; break; + case 5: + case 6: svc.CompressionLevel = SevenZip.CompressionLevel.Normal; break; + case 7: + case 8: svc.CompressionLevel = SevenZip.CompressionLevel.High; break; + case 9: svc.CompressionLevel = SevenZip.CompressionLevel.Ultra; break; + } + } + + public void WriteItem(string name, Action callback) + { + var dict = new Dictionary(); + var r = new RangBuffer(); + dict[name] = r.R; + if (first) + { + first = false; + svc.CompressionMode = SevenZip.CompressionMode.Create; + } + else + { + svc.CompressionMode = SevenZip.CompressionMode.Append; + } + + var task = Task.Factory.StartNew(() => + { + svc.CompressStreamDictionary(dict, path); + }); + try + { + callback(r.W); + } + finally + { + r.W.Dispose(); + } + task.Wait(); + } + + public void Dispose() + { + // nothing to do + } + } +} diff --git a/BizHawk.Client.Common/SharpZipWriter.cs b/BizHawk.Client.Common/SharpZipWriter.cs index 5277cd4ffc..1845c24559 100644 --- a/BizHawk.Client.Common/SharpZipWriter.cs +++ b/BizHawk.Client.Common/SharpZipWriter.cs @@ -13,12 +13,12 @@ namespace BizHawk.Client.Common private ZipOutputStream z; private int level; - public SharpZipWriter(Stream s, int compressionlevel) + public SharpZipWriter(string path, int compressionlevel) { level = compressionlevel; - z = new ZipOutputStream(s) + z = new ZipOutputStream(new FileStream(path, FileMode.Create, FileAccess.Write)) { - IsStreamOwner = false, + IsStreamOwner = true, UseZip64 = UseZip64.Off }; z.SetLevel(level); diff --git a/BizHawk.Client.Common/movie/bk2/Bk2Movie.IO.cs b/BizHawk.Client.Common/movie/bk2/Bk2Movie.IO.cs index eaf136748b..1d2b58050b 100644 --- a/BizHawk.Client.Common/movie/bk2/Bk2Movie.IO.cs +++ b/BizHawk.Client.Common/movie/bk2/Bk2Movie.IO.cs @@ -147,8 +147,7 @@ namespace BizHawk.Client.Common Directory.CreateDirectory(file.Directory.ToString()); } - using (var fs = new FileStream(fn, FileMode.Create, FileAccess.Write)) - using (var bs = new BinaryStateSaver(fs, false)) + using (var bs = new BinaryStateSaver(fn, false)) { bs.PutLump(BinaryStateLump.Movieheader, tw => tw.WriteLine(Header.ToString())); bs.PutLump(BinaryStateLump.Comments, tw => tw.WriteLine(CommentsString())); diff --git a/BizHawk.Client.Common/movie/tasproj/TasMovie.IO.cs b/BizHawk.Client.Common/movie/tasproj/TasMovie.IO.cs index 3f4ec30565..dc966cfc3c 100644 --- a/BizHawk.Client.Common/movie/tasproj/TasMovie.IO.cs +++ b/BizHawk.Client.Common/movie/tasproj/TasMovie.IO.cs @@ -18,8 +18,7 @@ namespace BizHawk.Client.Common Directory.CreateDirectory(file.Directory.ToString()); } - using (var fs = new FileStream(fn, FileMode.Create, FileAccess.Write)) - using (var bs = new BinaryStateSaver(fs, false)) + using (var bs = new BinaryStateSaver(fn, false)) { bs.PutLump(BinaryStateLump.Movieheader, tw => tw.WriteLine(Header.ToString())); bs.PutLump(BinaryStateLump.Comments, tw => tw.WriteLine(CommentsString())); diff --git a/BizHawk.Emulation.DiscSystem/Blobs/Blob_WaveFile.cs b/BizHawk.Emulation.DiscSystem/Blobs/Blob_WaveFile.cs index 3a8f88fb99..8f99575cf6 100644 --- a/BizHawk.Emulation.DiscSystem/Blobs/Blob_WaveFile.cs +++ b/BizHawk.Emulation.DiscSystem/Blobs/Blob_WaveFile.cs @@ -92,12 +92,12 @@ namespace BizHawk.Emulation.DiscSystem long mDataLength; public long Length { get { return mDataLength; } } - public void Dispose() + public void Dispose() { - if(RiffSource != null) + if (RiffSource != null) RiffSource.Dispose(); RiffSource = null; } } } -} \ No newline at end of file +}