fix SZDD archive parsing thanks to GPLv2-licensed code :)
This commit is contained in:
parent
b63842ab15
commit
2f720bd471
@ -0,0 +1,414 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
|
||||
/*
|
||||
* SZDDComp.impl.cs: Microsoft "compress.exe/expand.exe" compatible compressor
|
||||
*
|
||||
* Copyright (c) 2000 Martin Hinner <mhi@penguin.cz>
|
||||
* Algorithm & data structures by M. Winterhoff <100326.2776@compuserve.com>
|
||||
* C# port Copyright (c) 2011 Francis Gagné <fragag@hotmail.com> (Compressor) / Michael Ratzlaff <sonicmike2@yahoo.com> (Decompressor)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2, 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
namespace UniversalEditor.DataFormats.FileSystem.Microsoft.MSCompressed.Internal
|
||||
{
|
||||
|
||||
public static class SZDDComp
|
||||
{
|
||||
private const int N = 0x1000;
|
||||
private const int F = 0x10;
|
||||
private const int THRESHOLD = 3;
|
||||
private const int NIL = -1;
|
||||
|
||||
private static readonly byte[] Magic = new byte[] { 0x53, 0x5A, 0x44, 0x44, 0x88, 0xF0, 0x27, 0x33, 0x41, 0x00 };
|
||||
|
||||
public static void Encode(Stream input, Stream output)
|
||||
{
|
||||
int ch, i, run, len, match, size, mask;
|
||||
byte[] buf = new byte[17];
|
||||
byte[] byteBuffer = new byte[8];
|
||||
|
||||
Buffer buffer = new Buffer();
|
||||
output.Write(Magic, 0, Magic.Length);
|
||||
Int32ToBytesLE(checked((int)(input.Length - input.Position)), byteBuffer);
|
||||
output.Write(byteBuffer, 0, 4);
|
||||
|
||||
size = mask = 1;
|
||||
buf[0] = 0;
|
||||
i = N - F - F;
|
||||
for (len = 0; len < F && (ch = input.ReadByte()) != -1; len++)
|
||||
{
|
||||
buffer.SetHead(i + F, (byte)ch);
|
||||
i = (i + 1) & (N - 1);
|
||||
}
|
||||
|
||||
run = len;
|
||||
do
|
||||
{
|
||||
ch = input.ReadByte();
|
||||
if (i >= N - F)
|
||||
{
|
||||
buffer.Delete(i + F - N);
|
||||
buffer.SetHead(i + F, (byte)ch);
|
||||
buffer.SetHead(i + F - N, (byte)ch);
|
||||
}
|
||||
else
|
||||
{
|
||||
buffer.Delete(i + F);
|
||||
buffer.SetHead(i + F, (byte)ch);
|
||||
}
|
||||
|
||||
match = buffer.Insert(i, run);
|
||||
if (ch == -1)
|
||||
{
|
||||
run--;
|
||||
len--;
|
||||
}
|
||||
|
||||
if (len++ >= run)
|
||||
{
|
||||
if (match >= THRESHOLD)
|
||||
{
|
||||
buf[size++] = (byte)buffer.Position;
|
||||
buf[size++] = (byte)(((buffer.Position >> 4) & 0xF0) + (match - 3));
|
||||
len -= match;
|
||||
}
|
||||
else
|
||||
{
|
||||
buf[0] |= (byte)mask;
|
||||
buf[size++] = buffer.GetHead(i);
|
||||
len--;
|
||||
}
|
||||
|
||||
mask += mask;
|
||||
if ((mask & 0xFF) == 0)
|
||||
{
|
||||
output.Write(buf, 0, size);
|
||||
size = mask = 1;
|
||||
buf[0] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
i = (i + 1) & (N - 1);
|
||||
} while (len > 0);
|
||||
|
||||
if (size > 1)
|
||||
{
|
||||
output.Write(buf, 0, size);
|
||||
}
|
||||
}
|
||||
|
||||
private static void Int32ToBytesLE(int value, byte[] bytes)
|
||||
{
|
||||
bytes[0] = (byte)value;
|
||||
bytes[1] = (byte)(value >> 8);
|
||||
bytes[2] = (byte)(value >> 16);
|
||||
bytes[3] = (byte)(value >> 24);
|
||||
}
|
||||
|
||||
private class Buffer
|
||||
{
|
||||
private const int DadOffset = 1;
|
||||
private const int LeftSonOffset = 1 + N;
|
||||
private const int RightSonOffset = 1 + N + N;
|
||||
private const int RootOffset = 1 + N + N + N;
|
||||
|
||||
int pos;
|
||||
byte[] head = new byte[N + F];
|
||||
int[] node = new int[N + 1 + N + N + 256];
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="Buffer" /> class.
|
||||
/// </summary>
|
||||
public Buffer()
|
||||
{
|
||||
for (int i = 0; i < 256; i++)
|
||||
{
|
||||
SetRoot(i, NIL);
|
||||
}
|
||||
|
||||
for (int i = NIL; i < N; i++)
|
||||
{
|
||||
SetDad(i, NIL);
|
||||
}
|
||||
}
|
||||
|
||||
public int Position
|
||||
{
|
||||
get { return this.pos; }
|
||||
}
|
||||
|
||||
public int Insert(int i, int run)
|
||||
{
|
||||
int c = 0, j, k, l, n, match;
|
||||
int idx;
|
||||
|
||||
k = l = 1;
|
||||
match = THRESHOLD - 1;
|
||||
idx = RootOffset + head[i];
|
||||
SetLeftSon(i, NIL);
|
||||
SetRightSon(i, NIL);
|
||||
|
||||
while ((j = node[idx]) != NIL)
|
||||
{
|
||||
n = Math.Min(k, l);
|
||||
while (n < run && (c = (head[j + n] - head[i + n])) == 0)
|
||||
{
|
||||
n++;
|
||||
}
|
||||
|
||||
if (n > match)
|
||||
{
|
||||
match = n;
|
||||
pos = j;
|
||||
}
|
||||
|
||||
if (c < 0)
|
||||
{
|
||||
idx = LeftSonOffset + j;
|
||||
k = n;
|
||||
}
|
||||
else if (c > 0)
|
||||
{
|
||||
idx = RightSonOffset + j;
|
||||
l = n;
|
||||
}
|
||||
else
|
||||
{
|
||||
SetDad(j, NIL);
|
||||
SetDad(GetLeftSon(j), LeftSonOffset + i);
|
||||
SetDad(GetRightSon(j), RightSonOffset + i);
|
||||
SetLeftSon(i, GetLeftSon(j));
|
||||
SetRightSon(i, GetRightSon(j));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
SetDad(i, idx);
|
||||
node[idx] = i;
|
||||
return match;
|
||||
}
|
||||
|
||||
public void Delete(int z)
|
||||
{
|
||||
if (GetDad(z) != NIL)
|
||||
{
|
||||
int j;
|
||||
|
||||
if (GetRightSon(z) == NIL)
|
||||
{
|
||||
j = GetLeftSon(z);
|
||||
}
|
||||
else if (GetLeftSon(z) == NIL)
|
||||
{
|
||||
j = GetRightSon(z);
|
||||
}
|
||||
else
|
||||
{
|
||||
j = GetLeftSon(z);
|
||||
if (GetRightSon(j) != NIL)
|
||||
{
|
||||
do
|
||||
{
|
||||
j = GetRightSon(j);
|
||||
} while (GetRightSon(j) != NIL);
|
||||
|
||||
node[GetDad(j)] = GetLeftSon(j);
|
||||
SetDad(GetLeftSon(j), GetDad(j));
|
||||
SetLeftSon(j, GetLeftSon(z));
|
||||
SetDad(GetLeftSon(z), LeftSonOffset + j);
|
||||
}
|
||||
|
||||
SetRightSon(j, GetRightSon(z));
|
||||
SetDad(GetRightSon(z), RightSonOffset + j);
|
||||
}
|
||||
|
||||
SetDad(j, GetDad(z));
|
||||
node[GetDad(z)] = j;
|
||||
SetDad(z, NIL);
|
||||
}
|
||||
}
|
||||
|
||||
public byte GetHead(int index)
|
||||
{
|
||||
return head[index];
|
||||
}
|
||||
|
||||
public void SetHead(int index, byte value)
|
||||
{
|
||||
head[index] = value;
|
||||
}
|
||||
|
||||
private int GetDad(int index)
|
||||
{
|
||||
return node[DadOffset + index];
|
||||
}
|
||||
|
||||
private int GetLeftSon(int index)
|
||||
{
|
||||
return node[LeftSonOffset + index];
|
||||
}
|
||||
|
||||
private int GetRightSon(int index)
|
||||
{
|
||||
return node[RightSonOffset + index];
|
||||
}
|
||||
|
||||
private void SetDad(int index, int value)
|
||||
{
|
||||
node[DadOffset + index] = value;
|
||||
}
|
||||
|
||||
private void SetLeftSon(int index, int value)
|
||||
{
|
||||
node[LeftSonOffset + index] = value;
|
||||
}
|
||||
|
||||
private void SetRightSon(int index, int value)
|
||||
{
|
||||
node[RightSonOffset + index] = value;
|
||||
}
|
||||
|
||||
private void SetRoot(int index, int value)
|
||||
{
|
||||
node[RootOffset + index] = value;
|
||||
}
|
||||
}
|
||||
|
||||
public static int Decode(Stream infile, Stream outfile)
|
||||
{
|
||||
int bits, ch, i, j, len, mask;
|
||||
byte[] tmpbuf;
|
||||
byte[] buffer;
|
||||
|
||||
uint magic1;
|
||||
uint magic2;
|
||||
uint magic3;
|
||||
ushort reserved;
|
||||
uint filesize;
|
||||
|
||||
tmpbuf = new byte[4];
|
||||
if (infile.Read(tmpbuf, 0, 4) == -1)
|
||||
{
|
||||
throw new Exception();
|
||||
}
|
||||
magic1 = BitConverter.ToUInt32(tmpbuf, 0);
|
||||
|
||||
if (magic1 == 0x44445A53U)
|
||||
{
|
||||
if (infile.Read(tmpbuf, 0, 4) == -1)
|
||||
{
|
||||
throw new Exception();
|
||||
}
|
||||
magic2 = BitConverter.ToUInt32(tmpbuf, 0);
|
||||
|
||||
if (infile.Read(tmpbuf, 0, 2) == -1)
|
||||
{
|
||||
throw new Exception();
|
||||
}
|
||||
reserved = BitConverter.ToUInt16(tmpbuf, 0);
|
||||
|
||||
if (infile.Read(tmpbuf, 0, 4) == -1)
|
||||
{
|
||||
throw new Exception();
|
||||
}
|
||||
filesize = BitConverter.ToUInt32(tmpbuf, 0);
|
||||
|
||||
if (magic2 != 0x3327F088L)
|
||||
{
|
||||
throw new Exception("This is not a MS-compressed file!");
|
||||
}
|
||||
}
|
||||
else if (magic1 == 0x4A41574BU)
|
||||
{
|
||||
if (infile.Read(tmpbuf, 0, 4) == -1)
|
||||
{
|
||||
throw new Exception();
|
||||
}
|
||||
magic2 = BitConverter.ToUInt32(tmpbuf, 0);
|
||||
|
||||
if (infile.Read(tmpbuf, 0, 4) == -1)
|
||||
{
|
||||
throw new Exception();
|
||||
}
|
||||
magic3 = BitConverter.ToUInt32(tmpbuf, 0);
|
||||
|
||||
if (infile.Read(tmpbuf, 0, 2) == -1)
|
||||
{
|
||||
throw new Exception();
|
||||
}
|
||||
reserved = BitConverter.ToUInt16(tmpbuf, 0);
|
||||
|
||||
if (magic2 != 0xD127F088L || magic3 != 0x00120003L)
|
||||
{
|
||||
throw new Exception("This is not a MS-compressed file!");
|
||||
}
|
||||
throw new Exception("Unsupported version 6.22!");
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new Exception("This is not a MS-compressed file!");
|
||||
}
|
||||
|
||||
|
||||
buffer = new byte[N];
|
||||
|
||||
for (int q = 0; q < buffer.Length; q++)
|
||||
buffer[q] = 0x20;
|
||||
|
||||
i = N - F;
|
||||
while (true)
|
||||
{
|
||||
bits = infile.ReadByte();
|
||||
if (bits == -1)
|
||||
break;
|
||||
|
||||
for (mask = 0x01; (mask & 0xFF) != 0; mask <<= 1)
|
||||
{
|
||||
if ((bits & mask) == 0)
|
||||
{
|
||||
j = infile.ReadByte();
|
||||
if (j == -1)
|
||||
break;
|
||||
len = infile.ReadByte();
|
||||
j += (len & 0xF0) << 4;
|
||||
len = (len & 15) + 3;
|
||||
while (len-- != 0)
|
||||
{
|
||||
buffer[i] = buffer[j];
|
||||
outfile.WriteByte(buffer[i]);
|
||||
j++;
|
||||
j %= N;
|
||||
i++;
|
||||
i %= N;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ch = infile.ReadByte();
|
||||
if (ch == -1)
|
||||
break;
|
||||
buffer[i] = (byte)ch;
|
||||
outfile.WriteByte(buffer[i]);
|
||||
i++;
|
||||
i %= N;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -6,6 +6,9 @@
|
||||
//
|
||||
// Copyright (c) 2011-2020 Mike Becker's Software
|
||||
//
|
||||
// Portions of this program use SZDDComp, licensed under GPLv2 or later.
|
||||
// See Internal/SZDDComp.cs for more information.
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
@ -20,6 +23,9 @@
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
using System;
|
||||
|
||||
using MBS.Framework;
|
||||
|
||||
using UniversalEditor.Accessors;
|
||||
using UniversalEditor.ObjectModels.FileSystem;
|
||||
|
||||
@ -29,111 +35,117 @@ namespace UniversalEditor.DataFormats.FileSystem.Microsoft.MSCompressed
|
||||
/// Provides a <see cref="DataFormat" /> for manipulating MSCompressed archive files.
|
||||
/// </summary>
|
||||
public class MSCompressedDataFormat : DataFormat
|
||||
{
|
||||
private readonly byte?[] KWAJsignal = new byte?[] { (byte)'K', (byte)'W', (byte)'A', (byte)'J', (byte)0x88, (byte)0xF0, (byte)0x27, (byte)0xD1 };
|
||||
private readonly byte?[] SZDDsignal = new byte?[] { (byte)'S', (byte)'Z', (byte)'D', (byte)'D', (byte)0x88, (byte)0xF0, (byte)0x27, (byte)0x33 };
|
||||
private readonly byte?[] SZsignal = new byte?[] { (byte)'S', (byte)'Z', (byte)' ', (byte)0x88, (byte)0xF0, (byte)0x27, (byte)0x33, (byte)0xD1 };
|
||||
{
|
||||
private readonly byte?[] KWAJsignal = new byte?[] { (byte)'K', (byte)'W', (byte)'A', (byte)'J', (byte)0x88, (byte)0xF0, (byte)0x27, (byte)0xD1 };
|
||||
private readonly byte?[] SZDDsignal = new byte?[] { (byte)'S', (byte)'Z', (byte)'D', (byte)'D', (byte)0x88, (byte)0xF0, (byte)0x27, (byte)0x33 };
|
||||
private readonly byte?[] SZsignal = new byte?[] { (byte)'S', (byte)'Z', (byte)' ', (byte)0x88, (byte)0xF0, (byte)0x27, (byte)0x33, (byte)0xD1 };
|
||||
|
||||
private static DataFormatReference _dfr = null;
|
||||
protected override DataFormatReference MakeReferenceInternal()
|
||||
{
|
||||
protected override DataFormatReference MakeReferenceInternal()
|
||||
{
|
||||
if (_dfr == null)
|
||||
{
|
||||
_dfr = base.MakeReferenceInternal();
|
||||
_dfr.Capabilities.Add(typeof(FileSystemObjectModel), DataFormatCapabilities.All);
|
||||
}
|
||||
return _dfr;
|
||||
}
|
||||
return _dfr;
|
||||
}
|
||||
|
||||
protected override void LoadInternal(ref ObjectModel objectModel)
|
||||
{
|
||||
FileSystemObjectModel fsom = (objectModel as FileSystemObjectModel);
|
||||
if (fsom == null) throw new ObjectModelNotSupportedException();
|
||||
protected override void LoadInternal(ref ObjectModel objectModel)
|
||||
{
|
||||
FileSystemObjectModel fsom = (objectModel as FileSystemObjectModel);
|
||||
if (fsom == null) throw new ObjectModelNotSupportedException();
|
||||
|
||||
IO.Reader br = base.Accessor.Reader;
|
||||
|
||||
MemoryAccessor ma = new MemoryAccessor();
|
||||
IO.Writer bw = new IO.Writer(ma);
|
||||
IO.Reader br = base.Accessor.Reader;
|
||||
|
||||
byte[] signal = br.ReadBytes(8);
|
||||
if (signal.Match(SZDDsignal))
|
||||
{
|
||||
// Compression mode: only "A" (0x41) is valid here
|
||||
byte compressonMode = br.ReadByte();
|
||||
MemoryAccessor ma = new MemoryAccessor();
|
||||
IO.Writer bw = new IO.Writer(ma);
|
||||
|
||||
// The character missing from the end of the filename (0=unknown)
|
||||
char fileNameExt = br.ReadChar();
|
||||
string fileName = Accessor.GetFileTitle();
|
||||
char fileNameExt = '\0';
|
||||
|
||||
// The integer length of the file when unpacked
|
||||
int unpackedLength = br.ReadInt32();
|
||||
byte[] signal = br.ReadBytes(8);
|
||||
if (signal.Match(SZDDsignal))
|
||||
{
|
||||
// Compression mode: only "A" (0x41) is valid here
|
||||
byte compressonMode = br.ReadByte();
|
||||
|
||||
Decompress(br, bw, MSCompressedCompressionMethod.SZDD);
|
||||
}
|
||||
else if (signal.Match(SZsignal))
|
||||
{
|
||||
// The integer length of the file when unpacked
|
||||
int unpackedLength = br.ReadInt32();
|
||||
// The character missing from the end of the filename (0=unknown)
|
||||
fileNameExt = br.ReadChar();
|
||||
|
||||
Decompress(br, bw, MSCompressedCompressionMethod.SZ);
|
||||
}
|
||||
else if (signal.Match(KWAJsignal))
|
||||
{
|
||||
// compression method (0-4)
|
||||
MSCompressedKWAJCompressionMethod compressionMethod = (MSCompressedKWAJCompressionMethod)br.ReadInt16();
|
||||
if (fileNameExt != '\0')
|
||||
fileName = fileName.Substring(fileName.Length - 1) + fileNameExt;
|
||||
|
||||
// file offset of compressed data
|
||||
short compressionFileOffset = br.ReadInt16();
|
||||
// The integer length of the file when unpacked
|
||||
int unpackedLength = br.ReadInt32();
|
||||
|
||||
MSCompressedKWAJHeaderFlags headerFlags = (MSCompressedKWAJHeaderFlags)br.ReadInt16();
|
||||
if ((headerFlags & MSCompressedKWAJHeaderFlags.HasDecompressedLength) == MSCompressedKWAJHeaderFlags.HasDecompressedLength)
|
||||
{
|
||||
int decompressedLength = br.ReadInt32();
|
||||
}
|
||||
if ((headerFlags & MSCompressedKWAJHeaderFlags.UnknownBit1) == MSCompressedKWAJHeaderFlags.UnknownBit1)
|
||||
{
|
||||
short unknown1 = br.ReadInt16();
|
||||
}
|
||||
if ((headerFlags & MSCompressedKWAJHeaderFlags.HasExtraData) == MSCompressedKWAJHeaderFlags.HasExtraData)
|
||||
{
|
||||
short dataLength = br.ReadInt16();
|
||||
byte[] extraData = br.ReadBytes(dataLength);
|
||||
}
|
||||
if ((headerFlags & MSCompressedKWAJHeaderFlags.HasFileName) == MSCompressedKWAJHeaderFlags.HasFileName)
|
||||
{
|
||||
string fileName = br.ReadNullTerminatedString();
|
||||
}
|
||||
if ((headerFlags & MSCompressedKWAJHeaderFlags.HasFileExtension) == MSCompressedKWAJHeaderFlags.HasFileExtension)
|
||||
{
|
||||
string fileExt = br.ReadNullTerminatedString();
|
||||
}
|
||||
if ((headerFlags & MSCompressedKWAJHeaderFlags.HasExtraText) == MSCompressedKWAJHeaderFlags.HasExtraText)
|
||||
{
|
||||
short dataLength = br.ReadInt16();
|
||||
string extraData = br.ReadFixedLengthString(dataLength);
|
||||
}
|
||||
Decompress(br, bw, MSCompressedCompressionMethod.SZDD);
|
||||
}
|
||||
else if (signal.Match(SZsignal))
|
||||
{
|
||||
// The integer length of the file when unpacked
|
||||
int unpackedLength = br.ReadInt32();
|
||||
|
||||
switch (compressionMethod)
|
||||
{
|
||||
case MSCompressedKWAJCompressionMethod.None:
|
||||
{
|
||||
Decompress(br, bw, MSCompressedCompressionMethod.None);
|
||||
break;
|
||||
}
|
||||
case MSCompressedKWAJCompressionMethod.XOR:
|
||||
{
|
||||
Decompress(br, bw, MSCompressedCompressionMethod.XOR);
|
||||
break;
|
||||
}
|
||||
case MSCompressedKWAJCompressionMethod.SZDD:
|
||||
{
|
||||
Decompress(br, bw, MSCompressedCompressionMethod.SZDD);
|
||||
break;
|
||||
}
|
||||
case MSCompressedKWAJCompressionMethod.JeffJohnson:
|
||||
{
|
||||
int ringBufferPos = 4096 - 17;
|
||||
Decompress(br, bw, MSCompressedCompressionMethod.SZ);
|
||||
}
|
||||
else if (signal.Match(KWAJsignal))
|
||||
{
|
||||
// compression method (0-4)
|
||||
MSCompressedKWAJCompressionMethod compressionMethod = (MSCompressedKWAJCompressionMethod)br.ReadInt16();
|
||||
|
||||
/*
|
||||
// file offset of compressed data
|
||||
short compressionFileOffset = br.ReadInt16();
|
||||
|
||||
MSCompressedKWAJHeaderFlags headerFlags = (MSCompressedKWAJHeaderFlags)br.ReadInt16();
|
||||
if ((headerFlags & MSCompressedKWAJHeaderFlags.HasDecompressedLength) == MSCompressedKWAJHeaderFlags.HasDecompressedLength)
|
||||
{
|
||||
int decompressedLength = br.ReadInt32();
|
||||
}
|
||||
if ((headerFlags & MSCompressedKWAJHeaderFlags.UnknownBit1) == MSCompressedKWAJHeaderFlags.UnknownBit1)
|
||||
{
|
||||
short unknown1 = br.ReadInt16();
|
||||
}
|
||||
if ((headerFlags & MSCompressedKWAJHeaderFlags.HasExtraData) == MSCompressedKWAJHeaderFlags.HasExtraData)
|
||||
{
|
||||
short dataLength = br.ReadInt16();
|
||||
byte[] extraData = br.ReadBytes(dataLength);
|
||||
}
|
||||
if ((headerFlags & MSCompressedKWAJHeaderFlags.HasFileName) == MSCompressedKWAJHeaderFlags.HasFileName)
|
||||
{
|
||||
fileName = br.ReadNullTerminatedString();
|
||||
}
|
||||
if ((headerFlags & MSCompressedKWAJHeaderFlags.HasFileExtension) == MSCompressedKWAJHeaderFlags.HasFileExtension)
|
||||
{
|
||||
string fileExt = br.ReadNullTerminatedString();
|
||||
}
|
||||
if ((headerFlags & MSCompressedKWAJHeaderFlags.HasExtraText) == MSCompressedKWAJHeaderFlags.HasExtraText)
|
||||
{
|
||||
short dataLength = br.ReadInt16();
|
||||
string extraData = br.ReadFixedLengthString(dataLength);
|
||||
}
|
||||
|
||||
switch (compressionMethod)
|
||||
{
|
||||
case MSCompressedKWAJCompressionMethod.None:
|
||||
{
|
||||
Decompress(br, bw, MSCompressedCompressionMethod.None);
|
||||
break;
|
||||
}
|
||||
case MSCompressedKWAJCompressionMethod.XOR:
|
||||
{
|
||||
Decompress(br, bw, MSCompressedCompressionMethod.XOR);
|
||||
break;
|
||||
}
|
||||
case MSCompressedKWAJCompressionMethod.SZDD:
|
||||
{
|
||||
Decompress(br, bw, MSCompressedCompressionMethod.SZDD);
|
||||
break;
|
||||
}
|
||||
case MSCompressedKWAJCompressionMethod.JeffJohnson:
|
||||
{
|
||||
int ringBufferPos = 4096 - 17;
|
||||
|
||||
/*
|
||||
selected table = MATCHLEN
|
||||
LOOP:
|
||||
code = read huffman code using selected table (MATCHLEN or MATCHLEN2)
|
||||
@ -150,88 +162,109 @@ namespace UniversalEditor.DataFormats.FileSystem.Microsoft.MSCompressed
|
||||
if x != 31, selected table = MATCHLEN2
|
||||
read {x+1} literals using LITERAL huffman table, copy as output and into the ring buffer
|
||||
*/
|
||||
break;
|
||||
}
|
||||
case MSCompressedKWAJCompressionMethod.MSZIP:
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case MSCompressedKWAJCompressionMethod.MSZIP:
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
bw.Flush();
|
||||
bw.Close();
|
||||
|
||||
private void Decompress(IO.Reader br, IO.Writer bw, MSCompressedCompressionMethod method)
|
||||
{
|
||||
switch (method)
|
||||
{
|
||||
case MSCompressedCompressionMethod.None:
|
||||
case MSCompressedCompressionMethod.XOR:
|
||||
{
|
||||
byte[] rest = br.ReadToEnd();
|
||||
if (method == MSCompressedCompressionMethod.XOR)
|
||||
{
|
||||
for (int i = 0; i < rest.Length; i++) rest[i] ^= 0xFF;
|
||||
}
|
||||
bw.WriteBytes(rest);
|
||||
break;
|
||||
}
|
||||
case MSCompressedCompressionMethod.SZDD:
|
||||
case MSCompressedCompressionMethod.SZ:
|
||||
{
|
||||
byte[] window = new byte[4096];
|
||||
int pos = 4096 - 16;
|
||||
if (method == MSCompressedCompressionMethod.SZ)
|
||||
{
|
||||
pos = 4096 - 18;
|
||||
}
|
||||
for (int i = 0; i < 4096; i++)
|
||||
{
|
||||
window[i] = 0x20;
|
||||
}
|
||||
fsom.Files.Add(fileName, ma.ToArray());
|
||||
}
|
||||
|
||||
System.IO.MemoryStream ms = new System.IO.MemoryStream();
|
||||
while (!br.EndOfStream)
|
||||
{
|
||||
byte control = br.ReadByte();
|
||||
for (int cbit = 0x01; ((cbit & 0xFF) == 0xFF); cbit <<= 1)
|
||||
{
|
||||
if ((control & cbit) == control)
|
||||
{
|
||||
// literal
|
||||
bw.WriteByte((byte)(window[pos++] = br.ReadByte()));
|
||||
}
|
||||
else
|
||||
{
|
||||
// match
|
||||
int matchpos = br.ReadByte();
|
||||
int matchlen = br.ReadByte();
|
||||
matchpos |= ((matchlen & 0xF0) << 4);
|
||||
matchlen = ((matchlen & 0x0F) + 3);
|
||||
while ((matchlen--) != 0)
|
||||
{
|
||||
bw.WriteByte((byte)(window[pos++] = window[matchpos++]));
|
||||
pos &= 4095; matchpos &= 4095;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case MSCompressedCompressionMethod.JeffJohnson:
|
||||
{
|
||||
break;
|
||||
}
|
||||
case MSCompressedCompressionMethod.MSZIP:
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
private void Decompress(IO.Reader br, IO.Writer bw, MSCompressedCompressionMethod method)
|
||||
{
|
||||
switch (method)
|
||||
{
|
||||
case MSCompressedCompressionMethod.None:
|
||||
case MSCompressedCompressionMethod.XOR:
|
||||
{
|
||||
byte[] rest = br.ReadToEnd();
|
||||
if (method == MSCompressedCompressionMethod.XOR)
|
||||
{
|
||||
for (int i = 0; i < rest.Length; i++) rest[i] ^= 0xFF;
|
||||
}
|
||||
bw.WriteBytes(rest);
|
||||
break;
|
||||
}
|
||||
case MSCompressedCompressionMethod.SZDD:
|
||||
case MSCompressedCompressionMethod.SZ:
|
||||
{
|
||||
br.Seek(-14, IO.SeekOrigin.Current); // SZDDComp expects to start reading at the beginning of the 'SZDD' signature
|
||||
|
||||
protected override void SaveInternal(ObjectModel objectModel)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
byte[] data = br.ReadToEnd();
|
||||
System.IO.MemoryStream msin = new System.IO.MemoryStream(data);
|
||||
System.IO.MemoryStream msout = new System.IO.MemoryStream();
|
||||
Internal.SZDDComp.Decode(msin, msout);
|
||||
bw.WriteBytes(msout.ToArray());
|
||||
|
||||
/*
|
||||
byte[] window = new byte[4096];
|
||||
window.Clear(0x20);
|
||||
|
||||
int pos = 4096 - 16;
|
||||
if (method == MSCompressedCompressionMethod.SZ)
|
||||
{
|
||||
pos = 4096 - 18;
|
||||
}
|
||||
|
||||
while (!br.EndOfStream)
|
||||
{
|
||||
byte control = br.ReadByte();
|
||||
if (br.EndOfStream)
|
||||
break;
|
||||
|
||||
for (int cbit = 0x01; ((cbit & 0xFF) != 0); cbit = (byte)(cbit << 1))
|
||||
{
|
||||
if ((control & cbit) != 0)
|
||||
{
|
||||
// literal
|
||||
try
|
||||
{
|
||||
bw.WriteByte((byte)(window[(pos++ ^ window.Length)] = br.ReadByte()));
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// match
|
||||
int matchpos = br.ReadByte();
|
||||
int matchlen = br.ReadByte();
|
||||
matchpos |= (byte)((matchlen & 0xF0) << 4);
|
||||
matchlen = (byte)((matchlen & 0x0F) + 3);
|
||||
while ((matchlen--) != 0)
|
||||
{
|
||||
bw.WriteByte((byte)(window[(pos++ ^ window.Length)] = window[matchpos++]));
|
||||
pos &= 4095; matchpos &= 4095;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
break;
|
||||
}
|
||||
case MSCompressedCompressionMethod.JeffJohnson:
|
||||
{
|
||||
break;
|
||||
}
|
||||
case MSCompressedCompressionMethod.MSZIP:
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected override void SaveInternal(ObjectModel objectModel)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -152,6 +152,7 @@
|
||||
<Compile Include="DataFormats\FileSystem\Microsoft\NTFS\Attributes\NTFSFileNameAttribute.cs" />
|
||||
<Compile Include="DataFormats\FileSystem\Microsoft\NTFS\Attributes\NTFSStandardInformationAttribute.cs" />
|
||||
<Compile Include="DataFormats\FileSystem\Microsoft\NTFS\Attributes\NTFSDataAttribute.cs" />
|
||||
<Compile Include="DataFormats\FileSystem\Microsoft\MSCompressed\Internal\SZDDComp.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\Libraries\UniversalEditor.Compression\UniversalEditor.Compression.csproj">
|
||||
@ -203,5 +204,6 @@
|
||||
<Folder Include="DataFormats\FileSystem\Microsoft\OLE\OLE1\" />
|
||||
<Folder Include="DataFormats\FileSystem\Microsoft\NTFS\" />
|
||||
<Folder Include="DataFormats\FileSystem\Microsoft\NTFS\Attributes\" />
|
||||
<Folder Include="DataFormats\FileSystem\Microsoft\MSCompressed\Internal\" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
Loading…
x
Reference in New Issue
Block a user