mirror of
https://github.com/crskycode/GARbro.git
synced 2024-12-24 03:44:13 +08:00
RFC1950-compatible wrapper around DeflateStream class.
This commit is contained in:
parent
15b6d6156f
commit
8eea67faee
230
ArcFormats/ZLibStream.cs
Normal file
230
ArcFormats/ZLibStream.cs
Normal file
@ -0,0 +1,230 @@
|
||||
//! \file ZLibStream.cs
|
||||
//! \date Tue Jul 28 04:34:13 2015
|
||||
//! \brief RFC 1950 compatible wrapper around .Net DeflateStream class.
|
||||
//
|
||||
// Copyright (C) 2015 by morkt
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to
|
||||
// deal in the Software without restriction, including without limitation the
|
||||
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
// sell copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
// IN THE SOFTWARE.
|
||||
//
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.IO.Compression;
|
||||
using GameRes.Utility;
|
||||
|
||||
namespace GameRes.Compression
|
||||
{
|
||||
public enum CompressionMode
|
||||
{
|
||||
Compress,
|
||||
Decompress
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Enum for backwards compatibility with ZLibNet
|
||||
/// </summary>
|
||||
public enum CompressionLevel
|
||||
{
|
||||
NoCompression = 0,
|
||||
BestSpeed = 1,
|
||||
BestCompression = 9,
|
||||
Default = 6,
|
||||
Level0 = 0,
|
||||
Level1 = 1,
|
||||
Level2 = 2,
|
||||
Level3 = 3,
|
||||
Level4 = 4,
|
||||
Level5 = 5,
|
||||
Level6 = 6,
|
||||
Level7 = 7,
|
||||
Level8 = 8,
|
||||
Level9 = 9
|
||||
}
|
||||
|
||||
public class ZLibStream : Stream
|
||||
{
|
||||
DeflateStream m_stream;
|
||||
CheckedStream m_adler;
|
||||
bool m_writing;
|
||||
int m_total_in = 0;
|
||||
|
||||
public Stream BaseStream { get { return m_stream.BaseStream; } }
|
||||
|
||||
/// <summary>
|
||||
/// When compressing: returns total number of uncompressed bytes. Undefined for decompression streams.
|
||||
/// </summary>
|
||||
public int TotalIn { get { return m_total_in; } }
|
||||
|
||||
public ZLibStream (Stream stream, CompressionMode mode, bool leave_open = false)
|
||||
: this (stream, mode, CompressionLevel.Default, leave_open)
|
||||
{
|
||||
}
|
||||
|
||||
public ZLibStream (Stream stream, CompressionMode mode, CompressionLevel level, bool leave_open = false)
|
||||
{
|
||||
if (CompressionMode.Decompress == mode)
|
||||
InitDecompress (stream, leave_open);
|
||||
else
|
||||
InitCompress (stream, level, leave_open);
|
||||
}
|
||||
|
||||
private void InitDecompress (Stream stream, bool leave_open)
|
||||
{
|
||||
int b1 = stream.ReadByte();
|
||||
int b2 = stream.ReadByte();
|
||||
if (0x78 != b1 || 0 != (b1 << 8 | b2) % 31)
|
||||
throw new InvalidDataException ("Data not recoginzed as zlib-compressed stream");
|
||||
m_stream = new DeflateStream (stream, System.IO.Compression.CompressionMode.Decompress, leave_open);
|
||||
m_writing = false;
|
||||
}
|
||||
|
||||
private void InitCompress (Stream stream, CompressionLevel level, bool leave_open)
|
||||
{
|
||||
int flevel = (int)level;
|
||||
System.IO.Compression.CompressionLevel sys_level;
|
||||
if (0 == flevel)
|
||||
{
|
||||
sys_level = System.IO.Compression.CompressionLevel.NoCompression;
|
||||
}
|
||||
else if (flevel > 5)
|
||||
{
|
||||
sys_level = System.IO.Compression.CompressionLevel.Optimal;
|
||||
flevel = 3;
|
||||
}
|
||||
else
|
||||
{
|
||||
sys_level = System.IO.Compression.CompressionLevel.Fastest;
|
||||
flevel = 1;
|
||||
}
|
||||
int cmf = 0x7800 | flevel << 6;
|
||||
cmf = ((cmf + 30) / 31) * 31;
|
||||
stream.WriteByte ((byte)(cmf >> 8));
|
||||
stream.WriteByte ((byte)cmf);
|
||||
m_stream = new DeflateStream (stream, sys_level, leave_open);
|
||||
m_adler = new CheckedStream (m_stream, new Adler32());
|
||||
m_writing = true;
|
||||
}
|
||||
|
||||
#region IO.Stream Members
|
||||
public override bool CanRead { get { return !m_writing; } }
|
||||
public override bool CanSeek { get { return false; } }
|
||||
public override bool CanWrite { get { return m_writing; } }
|
||||
public override long Length { get { return m_stream.Length; } }
|
||||
public override long Position
|
||||
{
|
||||
get { return m_stream.Position; }
|
||||
set { m_stream.Position = value; }
|
||||
}
|
||||
|
||||
public override int Read (byte[] buffer, int offset, int count)
|
||||
{
|
||||
return m_stream.Read (buffer, offset, count);
|
||||
}
|
||||
|
||||
public override int ReadByte ()
|
||||
{
|
||||
return m_stream.ReadByte();
|
||||
}
|
||||
|
||||
public override void Flush()
|
||||
{
|
||||
m_stream.Flush();
|
||||
}
|
||||
|
||||
public override long Seek (long offset, SeekOrigin origin)
|
||||
{
|
||||
throw new NotSupportedException ("ZLibStream.Seek method not supported");
|
||||
}
|
||||
|
||||
public override void SetLength (long length)
|
||||
{
|
||||
throw new NotSupportedException ("ZLibStream.SetLength method not supported");
|
||||
}
|
||||
|
||||
public override void Write (byte[] buffer, int offset, int count)
|
||||
{
|
||||
m_adler.Write (buffer, offset, count);
|
||||
m_total_in += count;
|
||||
}
|
||||
|
||||
public override void WriteByte (byte value)
|
||||
{
|
||||
m_adler.WriteByte (value);
|
||||
m_total_in++;
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region IDisposable Members
|
||||
bool m_disposed = false;
|
||||
protected override void Dispose (bool disposing)
|
||||
{
|
||||
if (!m_disposed)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (disposing)
|
||||
{
|
||||
if (m_writing)
|
||||
{
|
||||
uint checksum = m_adler.CheckSumValue;
|
||||
m_stream.Flush();
|
||||
m_stream.BaseStream.WriteByte ((byte)(checksum >> 24));
|
||||
m_stream.BaseStream.WriteByte ((byte)(checksum >> 16));
|
||||
m_stream.BaseStream.WriteByte ((byte)(checksum >> 8));
|
||||
m_stream.BaseStream.WriteByte ((byte)(checksum));
|
||||
m_adler.Dispose();
|
||||
}
|
||||
m_stream.Dispose();
|
||||
}
|
||||
m_disposed = true;
|
||||
}
|
||||
finally
|
||||
{
|
||||
base.Dispose (disposing);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
|
||||
public class ZLibCompressor
|
||||
{
|
||||
public static MemoryStream Compress (Stream source)
|
||||
{
|
||||
var dest = new MemoryStream();
|
||||
using (var zs = new ZLibStream (dest, CompressionMode.Compress, true))
|
||||
{
|
||||
source.CopyTo (zs);
|
||||
}
|
||||
dest.Position = 0;
|
||||
return dest;
|
||||
}
|
||||
|
||||
public static MemoryStream DeCompress (Stream source)
|
||||
{
|
||||
var dest = new MemoryStream();
|
||||
using (var zs = new ZLibStream (source, CompressionMode.Decompress, true))
|
||||
{
|
||||
zs.CopyTo (dest);
|
||||
}
|
||||
dest.Position = 0;
|
||||
return dest;
|
||||
}
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user