mirror of
https://git.huckle.dev/Huckles-Minecraft-Archive/PCK-Studio.git
synced 2026-06-18 05:31:53 +00:00
Rename MinecraftUSkinEditor -> PCK-Studio, PckStudio.Installer
-> `PCK-Studio.Installer` and rename solution
This commit is contained in:
4
.github/workflows/CI.yml
vendored
4
.github/workflows/CI.yml
vendored
@@ -15,7 +15,7 @@ jobs:
|
||||
uses: NuGet/setup-nuget@v1.0.6
|
||||
|
||||
- name: Restore NuGet Packages
|
||||
run: nuget restore MinecraftUSkinEditor.sln
|
||||
run: nuget restore PCK_Studio.sln
|
||||
|
||||
- name: Build Solution
|
||||
run: msbuild MinecraftUSkinEditor.sln
|
||||
run: msbuild PCK_Studio.sln
|
||||
|
||||
@@ -1,100 +0,0 @@
|
||||
namespace PckStudio
|
||||
{
|
||||
partial class addMeta
|
||||
{
|
||||
/// <summary>
|
||||
/// Required designer variable.
|
||||
/// </summary>
|
||||
private System.ComponentModel.IContainer components = null;
|
||||
|
||||
/// <summary>
|
||||
/// Clean up any resources being used.
|
||||
/// </summary>
|
||||
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing && (components != null))
|
||||
{
|
||||
components.Dispose();
|
||||
}
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
#region Windows Form Designer generated code
|
||||
|
||||
/// <summary>
|
||||
/// Required method for Designer support - do not modify
|
||||
/// the contents of this method with the code editor.
|
||||
/// </summary>
|
||||
private void InitializeComponent()
|
||||
{
|
||||
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(addMeta));
|
||||
this.textBox1 = new System.Windows.Forms.TextBox();
|
||||
this.textBox2 = new System.Windows.Forms.TextBox();
|
||||
this.label1 = new System.Windows.Forms.Label();
|
||||
this.label2 = new System.Windows.Forms.Label();
|
||||
this.button1 = new System.Windows.Forms.Button();
|
||||
this.SuspendLayout();
|
||||
//
|
||||
// textBox1
|
||||
//
|
||||
this.textBox1.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
|
||||
resources.ApplyResources(this.textBox1, "textBox1");
|
||||
this.textBox1.Name = "textBox1";
|
||||
//
|
||||
// textBox2
|
||||
//
|
||||
this.textBox2.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
|
||||
resources.ApplyResources(this.textBox2, "textBox2");
|
||||
this.textBox2.Name = "textBox2";
|
||||
//
|
||||
// label1
|
||||
//
|
||||
resources.ApplyResources(this.label1, "label1");
|
||||
this.label1.ForeColor = System.Drawing.Color.White;
|
||||
this.label1.Name = "label1";
|
||||
//
|
||||
// label2
|
||||
//
|
||||
resources.ApplyResources(this.label2, "label2");
|
||||
this.label2.ForeColor = System.Drawing.Color.White;
|
||||
this.label2.Name = "label2";
|
||||
//
|
||||
// button1
|
||||
//
|
||||
resources.ApplyResources(this.button1, "button1");
|
||||
this.button1.ForeColor = System.Drawing.Color.White;
|
||||
this.button1.Name = "button1";
|
||||
this.button1.UseVisualStyleBackColor = true;
|
||||
this.button1.Click += new System.EventHandler(this.button1_Click);
|
||||
//
|
||||
// addMeta
|
||||
//
|
||||
resources.ApplyResources(this, "$this");
|
||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||
this.Controls.Add(this.button1);
|
||||
this.Controls.Add(this.label2);
|
||||
this.Controls.Add(this.label1);
|
||||
this.Controls.Add(this.textBox2);
|
||||
this.Controls.Add(this.textBox1);
|
||||
this.MaximizeBox = false;
|
||||
this.MinimizeBox = false;
|
||||
this.Name = "addMeta";
|
||||
this.Resizable = false;
|
||||
this.ShadowType = MetroFramework.Forms.MetroFormShadowType.DropShadow;
|
||||
this.Style = MetroFramework.MetroColorStyle.Silver;
|
||||
this.Theme = MetroFramework.MetroThemeStyle.Dark;
|
||||
this.ResumeLayout(false);
|
||||
this.PerformLayout();
|
||||
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private System.Windows.Forms.TextBox textBox1;
|
||||
private System.Windows.Forms.TextBox textBox2;
|
||||
private System.Windows.Forms.Label label1;
|
||||
private System.Windows.Forms.Label label2;
|
||||
private System.Windows.Forms.Button button1;
|
||||
}
|
||||
}
|
||||
|
Before Width: | Height: | Size: 1.7 KiB After Width: | Height: | Size: 1.7 KiB |
|
Before Width: | Height: | Size: 32 KiB After Width: | Height: | Size: 32 KiB |
|
Before Width: | Height: | Size: 146 KiB After Width: | Height: | Size: 146 KiB |
@@ -65,9 +65,9 @@ namespace PckStudio.Classes
|
||||
|
||||
//RenderBox
|
||||
System.Drawing.Image source = Textures[0].Source;
|
||||
Object3D object3D = new Box(source, new System.Drawing.Rectangle(8, 0, 0x10, 8), new System.Drawing.Rectangle(0, 8, 0x20, 8), new Point3D(0f, 0f, 0f), Effects.None);
|
||||
Object3D object3D2 = new Box(source, new System.Drawing.Rectangle(0x28, 0, 0x10, 8), new System.Drawing.Rectangle(0x20, 8, 0x20, 8), new Point3D(0f, 0f, 0f), Effects.None);
|
||||
Object3D object3D3 = new Box(source, new System.Drawing.Rectangle(0x2C, 0x10, 8, 4), new System.Drawing.Rectangle(0x28, 0x14, 0x20, 0xC), new Point3D(0f, 4f, 0f), Effects.FlipHorizontally);
|
||||
Object3D object3D = new Box(source, new Rectangle(8, 0, 0x10, 8), new Rectangle(0, 8, 0x20, 8), new Point3D(0f, 0f, 0f), Effects.None);
|
||||
Object3D object3D2 = new Box(source, new Rectangle(0x28, 0, 0x10, 8), new Rectangle(0x20, 8, 0x20, 8), new Point3D(0f, 0f, 0f), Effects.None);
|
||||
Object3D object3D3 = new Box(source, new Rectangle(0x2C, 0x10, 8, 4), new Rectangle(0x28, 0x14, 0x20, 0xC), new Point3D(0f, 4f, 0f), Effects.FlipHorizontally);
|
||||
|
||||
|
||||
//RenderGroup
|
||||
@@ -11,11 +11,10 @@ namespace PckStudio.Classes.FileTypes
|
||||
{
|
||||
public class InvalidLanguageException : Exception
|
||||
{
|
||||
private string _language;
|
||||
public string Language => _language;
|
||||
public string Language { get; }
|
||||
public InvalidLanguageException(string message, string language) : base(message)
|
||||
{
|
||||
_language = language;
|
||||
Language = language;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -104,6 +103,7 @@ namespace PckStudio.Classes.FileTypes
|
||||
foreach (var locKeyValue in locKeyValuePairs)
|
||||
AddLocKey(locKeyValue.Item1, locKeyValue.Item2);
|
||||
}
|
||||
|
||||
private Dictionary<string, string> GetTranslation(string locKey)
|
||||
{
|
||||
if (!LocKeys.ContainsKey(locKey))
|
||||
@@ -68,7 +68,7 @@ namespace PckStudio.Classes.FileTypes
|
||||
public int type { get; set; }
|
||||
public byte[] data => _data;
|
||||
public int size => _size;
|
||||
public PCKProperties properties { get; set; } = new PCKProperties();
|
||||
public PCKProperties properties { get; } = new PCKProperties();
|
||||
|
||||
private byte[] _data = new byte[0];
|
||||
private int _size = 0;
|
||||
@@ -109,8 +109,8 @@ namespace PckStudio.Classes.FileTypes
|
||||
var LUT = new List<string>();
|
||||
Files.ForEach(file => file.properties.ForEach(pair =>
|
||||
{
|
||||
if (!LUT.Contains(pair.Item1))
|
||||
LUT.Add(pair.Item1);
|
||||
if (!LUT.Contains(pair.property))
|
||||
LUT.Add(pair.property);
|
||||
})
|
||||
);
|
||||
return LUT;
|
||||
@@ -127,19 +127,6 @@ namespace PckStudio.Classes.FileTypes
|
||||
return GetFile(filepath, type) is FileData;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tries to get a file with <paramref name="filepath"/> and <paramref name="type"/>.
|
||||
/// </summary>
|
||||
/// <param name="filepath">Path to the file in the pck</param>
|
||||
/// <param name="type">Type of the file <see cref="FileData.EDLCType"/></param>
|
||||
/// <param name="file"></param>
|
||||
/// <returns></returns>
|
||||
public bool TryGetFile(string filepath, int type, out FileData file)
|
||||
{
|
||||
file = GetFile(filepath, type);
|
||||
return file is FileData;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the first file that Equals <paramref name="filepath"/> and <paramref name="type"/>
|
||||
/// </summary>
|
||||
@@ -150,5 +137,18 @@ namespace PckStudio.Classes.FileTypes
|
||||
{
|
||||
return Files.FirstOrDefault(file => file.filepath.Equals(filepath) && file.type.Equals(type));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tries to get a file with <paramref name="filepath"/> and <paramref name="type"/>.
|
||||
/// </summary>
|
||||
/// <param name="filepath">Path to the file in the pck</param>
|
||||
/// <param name="type">Type of the file <see cref="FileData.EDLCType"/></param>
|
||||
/// <param name="file">If succeeded <paramref name="file"/> will be non-null, otherwise null</param>
|
||||
/// <returns>True if succeeded, otherwise false</returns>
|
||||
public bool TryGetFile(string filepath, int type, out FileData file)
|
||||
{
|
||||
file = GetFile(filepath, type);
|
||||
return file is FileData;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -6,16 +6,26 @@ using System.Threading.Tasks;
|
||||
|
||||
namespace PckStudio.Classes.FileTypes
|
||||
{
|
||||
public class PCKProperties : List<ValueTuple<string, string>> // class because `using` is file scoped :|
|
||||
public class PCKProperties : List<(string property, string value)>
|
||||
{
|
||||
public bool HasProperty(string property)
|
||||
{
|
||||
return GetProperty(property) != default;
|
||||
}
|
||||
|
||||
public ValueTuple<string, string> GetProperty(string property)
|
||||
public (string, string) GetProperty(string property)
|
||||
{
|
||||
return this.FirstOrDefault(p => p.Item1.Equals(property));
|
||||
return this.FirstOrDefault(p => p.property.Equals(property));
|
||||
}
|
||||
|
||||
public (string, string)[] GetProperties(string property)
|
||||
{
|
||||
return FindAll(p => p.property == property).ToArray();
|
||||
}
|
||||
|
||||
public bool HasMoreThanOneOf(string property)
|
||||
{
|
||||
return GetProperties(property).Length > 1;
|
||||
}
|
||||
|
||||
public void SetProperty(string property, string value)
|
||||
785
PCK-Studio/Classes/Utils/grf/lzxDecoder.cs
Normal file
785
PCK-Studio/Classes/Utils/grf/lzxDecoder.cs
Normal file
@@ -0,0 +1,785 @@
|
||||
#region HEADER
|
||||
/* This file was derived from libmspack
|
||||
* (C) 2003-2004 Stuart Caie.
|
||||
* (C) 2011 Ali Scissons.
|
||||
*
|
||||
* The LZX method was created by Jonathan Forbes and Tomi Poutanen, adapted
|
||||
* by Microsoft Corporation.
|
||||
*
|
||||
* This source file is Dual licensed; meaning the end-user of this source file
|
||||
* may redistribute/modify it under the LGPL 2.1 or MS-PL licenses.
|
||||
*/
|
||||
#region LGPL License
|
||||
/* GNU LESSER GENERAL PUBLIC LICENSE version 2.1
|
||||
* LzxDecoder is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU Lesser General Public License (LGPL) version 2.1
|
||||
*/
|
||||
#endregion
|
||||
#region MS-PL License
|
||||
/*
|
||||
* MICROSOFT PUBLIC LICENSE
|
||||
* This source code is subject to the terms of the Microsoft Public License (Ms-PL).
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification,
|
||||
* is permitted provided that redistributions of the source code retain the above
|
||||
* copyright notices and this file header.
|
||||
*
|
||||
* Additional copyright notices should be appended to the list above.
|
||||
*
|
||||
* For details, see <http://www.opensource.org/licenses/ms-pl.html>.
|
||||
*/
|
||||
#endregion
|
||||
/*
|
||||
* This derived work is recognized by Stuart Caie and is authorized to adapt
|
||||
* any changes made to lzxd.c in his libmspack library and will still retain
|
||||
* this dual licensing scheme. Big thanks to Stuart Caie!
|
||||
*
|
||||
* DETAILS
|
||||
* This file is a pure C# port of the lzxd.c file from libmspack, with minor
|
||||
* changes towards the decompression of XNB files. The original decompression
|
||||
* software of LZX encoded data was written by Suart Caie in his
|
||||
* libmspack/cabextract projects, which can be located at
|
||||
* http://http://www.cabextract.org.uk/
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace Microsoft.Xna.Framework.Content
|
||||
{
|
||||
using System.IO;
|
||||
|
||||
class LzxDecoder
|
||||
{
|
||||
public static uint[] position_base = null;
|
||||
public static byte[] extra_bits = null;
|
||||
|
||||
private LzxState m_state;
|
||||
|
||||
public LzxDecoder(int window)
|
||||
{
|
||||
uint wndsize = (uint)(1 << window);
|
||||
int posn_slots;
|
||||
|
||||
// setup proper exception
|
||||
if (window < 15 || window > 21) throw new UnsupportedWindowSizeRange();
|
||||
|
||||
// let's initialise our state
|
||||
m_state = new LzxState();
|
||||
m_state.actual_size = 0;
|
||||
m_state.window = new byte[wndsize];
|
||||
for (int i = 0; i < wndsize; i++) m_state.window[i] = 0xDC;
|
||||
m_state.actual_size = wndsize;
|
||||
m_state.window_size = wndsize;
|
||||
m_state.window_posn = 0;
|
||||
|
||||
/* initialize static tables */
|
||||
if (extra_bits == null)
|
||||
{
|
||||
extra_bits = new byte[52];
|
||||
for (int i = 0, j = 0; i <= 50; i += 2)
|
||||
{
|
||||
extra_bits[i] = extra_bits[i + 1] = (byte)j;
|
||||
if ((i != 0) && (j < 17)) j++;
|
||||
}
|
||||
}
|
||||
if (position_base == null)
|
||||
{
|
||||
position_base = new uint[51];
|
||||
for (int i = 0, j = 0; i <= 50; i++)
|
||||
{
|
||||
position_base[i] = (uint)j;
|
||||
j += 1 << extra_bits[i];
|
||||
}
|
||||
}
|
||||
|
||||
/* calculate required position slots */
|
||||
if (window == 20) posn_slots = 42;
|
||||
else if (window == 21) posn_slots = 50;
|
||||
else posn_slots = window << 1;
|
||||
|
||||
m_state.R0 = m_state.R1 = m_state.R2 = 1;
|
||||
m_state.main_elements = (ushort)(LzxConstants.NUM_CHARS + (posn_slots << 3));
|
||||
m_state.header_read = 0;
|
||||
m_state.frames_read = 0;
|
||||
m_state.block_remaining = 0;
|
||||
m_state.block_type = LzxConstants.BLOCKTYPE.INVALID;
|
||||
m_state.intel_curpos = 0;
|
||||
m_state.intel_started = 0;
|
||||
|
||||
// yo dawg i herd u liek arrays so we put arrays in ur arrays so u can array while u array
|
||||
m_state.PRETREE_table = new ushort[(1 << LzxConstants.PRETREE_TABLEBITS) + (LzxConstants.PRETREE_MAXSYMBOLS << 1)];
|
||||
m_state.PRETREE_len = new byte[LzxConstants.PRETREE_MAXSYMBOLS + LzxConstants.LENTABLE_SAFETY];
|
||||
m_state.MAINTREE_table = new ushort[(1 << LzxConstants.MAINTREE_TABLEBITS) + (LzxConstants.MAINTREE_MAXSYMBOLS << 1)];
|
||||
m_state.MAINTREE_len = new byte[LzxConstants.MAINTREE_MAXSYMBOLS + LzxConstants.LENTABLE_SAFETY];
|
||||
m_state.LENGTH_table = new ushort[(1 << LzxConstants.LENGTH_TABLEBITS) + (LzxConstants.LENGTH_MAXSYMBOLS << 1)];
|
||||
m_state.LENGTH_len = new byte[LzxConstants.LENGTH_MAXSYMBOLS + LzxConstants.LENTABLE_SAFETY];
|
||||
m_state.ALIGNED_table = new ushort[(1 << LzxConstants.ALIGNED_TABLEBITS) + (LzxConstants.ALIGNED_MAXSYMBOLS << 1)];
|
||||
m_state.ALIGNED_len = new byte[LzxConstants.ALIGNED_MAXSYMBOLS + LzxConstants.LENTABLE_SAFETY];
|
||||
/* initialise tables to 0 (because deltas will be applied to them) */
|
||||
for (int i = 0; i < LzxConstants.MAINTREE_MAXSYMBOLS; i++) m_state.MAINTREE_len[i] = 0;
|
||||
for (int i = 0; i < LzxConstants.LENGTH_MAXSYMBOLS; i++) m_state.LENGTH_len[i] = 0;
|
||||
}
|
||||
|
||||
public int Decompress(Stream inData, int inLen, Stream outData, int outLen)
|
||||
{
|
||||
BitBuffer bitbuf = new BitBuffer(inData);
|
||||
long startpos = inData.Position;
|
||||
long endpos = inData.Position + inLen;
|
||||
|
||||
byte[] window = m_state.window;
|
||||
|
||||
uint window_posn = m_state.window_posn;
|
||||
uint window_size = m_state.window_size;
|
||||
uint R0 = m_state.R0;
|
||||
uint R1 = m_state.R1;
|
||||
uint R2 = m_state.R2;
|
||||
uint i, j;
|
||||
|
||||
int togo = outLen, this_run, main_element, match_length, match_offset, length_footer, extra, verbatim_bits;
|
||||
int rundest, runsrc, copy_length, aligned_bits;
|
||||
|
||||
bitbuf.InitBitStream();
|
||||
|
||||
/* read header if necessary */
|
||||
if (m_state.header_read == 0)
|
||||
{
|
||||
uint intel = bitbuf.ReadBits(1);
|
||||
if (intel != 0)
|
||||
{
|
||||
// read the filesize
|
||||
i = bitbuf.ReadBits(16); j = bitbuf.ReadBits(16);
|
||||
m_state.intel_filesize = (int)((i << 16) | j);
|
||||
}
|
||||
m_state.header_read = 1;
|
||||
}
|
||||
|
||||
/* main decoding loop */
|
||||
while (togo > 0)
|
||||
{
|
||||
/* last block finished, new block expected */
|
||||
if (m_state.block_remaining == 0)
|
||||
{
|
||||
// TODO may screw something up here
|
||||
if (m_state.block_type == LzxConstants.BLOCKTYPE.UNCOMPRESSED)
|
||||
{
|
||||
if ((m_state.block_length & 1) == 1) inData.ReadByte(); /* realign bitstream to word */
|
||||
bitbuf.InitBitStream();
|
||||
}
|
||||
|
||||
m_state.block_type = (LzxConstants.BLOCKTYPE)bitbuf.ReadBits(3); ;
|
||||
i = bitbuf.ReadBits(16);
|
||||
j = bitbuf.ReadBits(8);
|
||||
m_state.block_remaining = m_state.block_length = (uint)((i << 8) | j);
|
||||
|
||||
switch (m_state.block_type)
|
||||
{
|
||||
case LzxConstants.BLOCKTYPE.ALIGNED:
|
||||
for (i = 0, j = 0; i < 8; i++) { j = bitbuf.ReadBits(3); m_state.ALIGNED_len[i] = (byte)j; }
|
||||
MakeDecodeTable(LzxConstants.ALIGNED_MAXSYMBOLS, LzxConstants.ALIGNED_TABLEBITS,
|
||||
m_state.ALIGNED_len, m_state.ALIGNED_table);
|
||||
/* rest of aligned header is same as verbatim */
|
||||
goto case LzxConstants.BLOCKTYPE.VERBATIM;
|
||||
|
||||
case LzxConstants.BLOCKTYPE.VERBATIM:
|
||||
ReadLengths(m_state.MAINTREE_len, 0, 256, bitbuf);
|
||||
ReadLengths(m_state.MAINTREE_len, 256, m_state.main_elements, bitbuf);
|
||||
MakeDecodeTable(LzxConstants.MAINTREE_MAXSYMBOLS, LzxConstants.MAINTREE_TABLEBITS,
|
||||
m_state.MAINTREE_len, m_state.MAINTREE_table);
|
||||
if (m_state.MAINTREE_len[0xE8] != 0) m_state.intel_started = 1;
|
||||
|
||||
ReadLengths(m_state.LENGTH_len, 0, LzxConstants.NUM_SECONDARY_LENGTHS, bitbuf);
|
||||
MakeDecodeTable(LzxConstants.LENGTH_MAXSYMBOLS, LzxConstants.LENGTH_TABLEBITS,
|
||||
m_state.LENGTH_len, m_state.LENGTH_table);
|
||||
break;
|
||||
|
||||
case LzxConstants.BLOCKTYPE.UNCOMPRESSED:
|
||||
m_state.intel_started = 1; /* because we can't assume otherwise */
|
||||
bitbuf.EnsureBits(16); /* get up to 16 pad bits into the buffer */
|
||||
if (bitbuf.GetBitsLeft() > 16) inData.Seek(-2, SeekOrigin.Current); /* and align the bitstream! */
|
||||
byte hi, mh, ml, lo;
|
||||
lo = (byte)inData.ReadByte(); ml = (byte)inData.ReadByte(); mh = (byte)inData.ReadByte(); hi = (byte)inData.ReadByte();
|
||||
R0 = (uint)(lo | ml << 8 | mh << 16 | hi << 24);
|
||||
lo = (byte)inData.ReadByte(); ml = (byte)inData.ReadByte(); mh = (byte)inData.ReadByte(); hi = (byte)inData.ReadByte();
|
||||
R1 = (uint)(lo | ml << 8 | mh << 16 | hi << 24);
|
||||
lo = (byte)inData.ReadByte(); ml = (byte)inData.ReadByte(); mh = (byte)inData.ReadByte(); hi = (byte)inData.ReadByte();
|
||||
R2 = (uint)(lo | ml << 8 | mh << 16 | hi << 24);
|
||||
break;
|
||||
|
||||
default:
|
||||
return -1; // TODO throw proper exception
|
||||
}
|
||||
}
|
||||
|
||||
/* buffer exhaustion check */
|
||||
if (inData.Position > (startpos + inLen))
|
||||
{
|
||||
/* it's possible to have a file where the next run is less than
|
||||
* 16 bits in size. In this case, the READ_HUFFSYM() macro used
|
||||
* in building the tables will exhaust the buffer, so we should
|
||||
* allow for this, but not allow those accidentally read bits to
|
||||
* be used (so we check that there are at least 16 bits
|
||||
* remaining - in this boundary case they aren't really part of
|
||||
* the compressed data)
|
||||
*/
|
||||
//Debug.WriteLine("WTF");
|
||||
|
||||
if (inData.Position > (startpos + inLen + 2) || bitbuf.GetBitsLeft() < 16) return -1; //TODO throw proper exception
|
||||
}
|
||||
|
||||
while ((this_run = (int)m_state.block_remaining) > 0 && togo > 0)
|
||||
{
|
||||
if (this_run > togo) this_run = togo;
|
||||
togo -= this_run;
|
||||
m_state.block_remaining -= (uint)this_run;
|
||||
|
||||
/* apply 2^x-1 mask */
|
||||
window_posn &= window_size - 1;
|
||||
/* runs can't straddle the window wraparound */
|
||||
if ((window_posn + this_run) > window_size)
|
||||
return -1; //TODO throw proper exception
|
||||
|
||||
switch (m_state.block_type)
|
||||
{
|
||||
case LzxConstants.BLOCKTYPE.VERBATIM:
|
||||
while (this_run > 0)
|
||||
{
|
||||
main_element = (int)ReadHuffSym(m_state.MAINTREE_table, m_state.MAINTREE_len,
|
||||
LzxConstants.MAINTREE_MAXSYMBOLS, LzxConstants.MAINTREE_TABLEBITS,
|
||||
bitbuf);
|
||||
if (main_element < LzxConstants.NUM_CHARS)
|
||||
{
|
||||
/* literal: 0 to NUM_CHARS-1 */
|
||||
window[window_posn++] = (byte)main_element;
|
||||
this_run--;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* match: NUM_CHARS + ((slot<<3) | length_header (3 bits)) */
|
||||
main_element -= LzxConstants.NUM_CHARS;
|
||||
|
||||
match_length = main_element & LzxConstants.NUM_PRIMARY_LENGTHS;
|
||||
if (match_length == LzxConstants.NUM_PRIMARY_LENGTHS)
|
||||
{
|
||||
length_footer = (int)ReadHuffSym(m_state.LENGTH_table, m_state.LENGTH_len,
|
||||
LzxConstants.LENGTH_MAXSYMBOLS, LzxConstants.LENGTH_TABLEBITS,
|
||||
bitbuf);
|
||||
match_length += length_footer;
|
||||
}
|
||||
match_length += LzxConstants.MIN_MATCH;
|
||||
|
||||
match_offset = main_element >> 3;
|
||||
|
||||
if (match_offset > 2)
|
||||
{
|
||||
/* not repeated offset */
|
||||
if (match_offset != 3)
|
||||
{
|
||||
extra = extra_bits[match_offset];
|
||||
verbatim_bits = (int)bitbuf.ReadBits((byte)extra);
|
||||
match_offset = (int)position_base[match_offset] - 2 + verbatim_bits;
|
||||
}
|
||||
else
|
||||
{
|
||||
match_offset = 1;
|
||||
}
|
||||
|
||||
/* update repeated offset LRU queue */
|
||||
R2 = R1; R1 = R0; R0 = (uint)match_offset;
|
||||
}
|
||||
else if (match_offset == 0)
|
||||
{
|
||||
match_offset = (int)R0;
|
||||
}
|
||||
else if (match_offset == 1)
|
||||
{
|
||||
match_offset = (int)R1;
|
||||
R1 = R0; R0 = (uint)match_offset;
|
||||
}
|
||||
else /* match_offset == 2 */
|
||||
{
|
||||
match_offset = (int)R2;
|
||||
R2 = R0; R0 = (uint)match_offset;
|
||||
}
|
||||
|
||||
rundest = (int)window_posn;
|
||||
this_run -= match_length;
|
||||
|
||||
/* copy any wrapped around source data */
|
||||
if (window_posn >= match_offset)
|
||||
{
|
||||
/* no wrap */
|
||||
runsrc = rundest - match_offset;
|
||||
}
|
||||
else
|
||||
{
|
||||
runsrc = rundest + ((int)window_size - match_offset);
|
||||
copy_length = match_offset - (int)window_posn;
|
||||
if (copy_length < match_length)
|
||||
{
|
||||
match_length -= copy_length;
|
||||
window_posn += (uint)copy_length;
|
||||
while (copy_length-- > 0) window[rundest++] = window[runsrc++];
|
||||
runsrc = 0;
|
||||
}
|
||||
}
|
||||
window_posn += (uint)match_length;
|
||||
|
||||
/* copy match data - no worries about destination wraps */
|
||||
while (match_length-- > 0) window[rundest++] = window[runsrc++];
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case LzxConstants.BLOCKTYPE.ALIGNED:
|
||||
while (this_run > 0)
|
||||
{
|
||||
main_element = (int)ReadHuffSym(m_state.MAINTREE_table, m_state.MAINTREE_len,
|
||||
LzxConstants.MAINTREE_MAXSYMBOLS, LzxConstants.MAINTREE_TABLEBITS,
|
||||
bitbuf);
|
||||
|
||||
if (main_element < LzxConstants.NUM_CHARS)
|
||||
{
|
||||
/* literal 0 to NUM_CHARS-1 */
|
||||
window[window_posn++] = (byte)main_element;
|
||||
this_run--;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* match: NUM_CHARS + ((slot<<3) | length_header (3 bits)) */
|
||||
main_element -= LzxConstants.NUM_CHARS;
|
||||
|
||||
match_length = main_element & LzxConstants.NUM_PRIMARY_LENGTHS;
|
||||
if (match_length == LzxConstants.NUM_PRIMARY_LENGTHS)
|
||||
{
|
||||
length_footer = (int)ReadHuffSym(m_state.LENGTH_table, m_state.LENGTH_len,
|
||||
LzxConstants.LENGTH_MAXSYMBOLS, LzxConstants.LENGTH_TABLEBITS,
|
||||
bitbuf);
|
||||
match_length += length_footer;
|
||||
}
|
||||
match_length += LzxConstants.MIN_MATCH;
|
||||
|
||||
match_offset = main_element >> 3;
|
||||
|
||||
if (match_offset > 2)
|
||||
{
|
||||
/* not repeated offset */
|
||||
extra = extra_bits[match_offset];
|
||||
match_offset = (int)position_base[match_offset] - 2;
|
||||
if (extra > 3)
|
||||
{
|
||||
/* verbatim and aligned bits */
|
||||
extra -= 3;
|
||||
verbatim_bits = (int)bitbuf.ReadBits((byte)extra);
|
||||
match_offset += (verbatim_bits << 3);
|
||||
aligned_bits = (int)ReadHuffSym(m_state.ALIGNED_table, m_state.ALIGNED_len,
|
||||
LzxConstants.ALIGNED_MAXSYMBOLS, LzxConstants.ALIGNED_TABLEBITS,
|
||||
bitbuf);
|
||||
match_offset += aligned_bits;
|
||||
}
|
||||
else if (extra == 3)
|
||||
{
|
||||
/* aligned bits only */
|
||||
aligned_bits = (int)ReadHuffSym(m_state.ALIGNED_table, m_state.ALIGNED_len,
|
||||
LzxConstants.ALIGNED_MAXSYMBOLS, LzxConstants.ALIGNED_TABLEBITS,
|
||||
bitbuf);
|
||||
match_offset += aligned_bits;
|
||||
}
|
||||
else if (extra > 0) /* extra==1, extra==2 */
|
||||
{
|
||||
/* verbatim bits only */
|
||||
verbatim_bits = (int)bitbuf.ReadBits((byte)extra);
|
||||
match_offset += verbatim_bits;
|
||||
}
|
||||
else /* extra == 0 */
|
||||
{
|
||||
/* ??? */
|
||||
match_offset = 1;
|
||||
}
|
||||
|
||||
/* update repeated offset LRU queue */
|
||||
R2 = R1; R1 = R0; R0 = (uint)match_offset;
|
||||
}
|
||||
else if (match_offset == 0)
|
||||
{
|
||||
match_offset = (int)R0;
|
||||
}
|
||||
else if (match_offset == 1)
|
||||
{
|
||||
match_offset = (int)R1;
|
||||
R1 = R0; R0 = (uint)match_offset;
|
||||
}
|
||||
else /* match_offset == 2 */
|
||||
{
|
||||
match_offset = (int)R2;
|
||||
R2 = R0; R0 = (uint)match_offset;
|
||||
}
|
||||
|
||||
rundest = (int)window_posn;
|
||||
this_run -= match_length;
|
||||
|
||||
/* copy any wrapped around source data */
|
||||
if (window_posn >= match_offset)
|
||||
{
|
||||
/* no wrap */
|
||||
runsrc = rundest - match_offset;
|
||||
}
|
||||
else
|
||||
{
|
||||
runsrc = rundest + ((int)window_size - match_offset);
|
||||
copy_length = match_offset - (int)window_posn;
|
||||
if (copy_length < match_length)
|
||||
{
|
||||
match_length -= copy_length;
|
||||
window_posn += (uint)copy_length;
|
||||
while (copy_length-- > 0) window[rundest++] = window[runsrc++];
|
||||
runsrc = 0;
|
||||
}
|
||||
}
|
||||
window_posn += (uint)match_length;
|
||||
|
||||
/* copy match data - no worries about destination wraps */
|
||||
while (match_length-- > 0) window[rundest++] = window[runsrc++];
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case LzxConstants.BLOCKTYPE.UNCOMPRESSED:
|
||||
if ((inData.Position + this_run) > endpos) return -1; //TODO throw proper exception
|
||||
byte[] temp_buffer = new byte[this_run];
|
||||
inData.Read(temp_buffer, 0, this_run);
|
||||
temp_buffer.CopyTo(window, (int)window_posn);
|
||||
window_posn += (uint)this_run;
|
||||
break;
|
||||
|
||||
default:
|
||||
return -1; //TODO throw proper exception
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (togo != 0) return -1; //TODO throw proper exception
|
||||
int start_window_pos = (int)window_posn;
|
||||
if (start_window_pos == 0) start_window_pos = (int)window_size;
|
||||
start_window_pos -= outLen;
|
||||
outData.Write(window, start_window_pos, outLen);
|
||||
|
||||
m_state.window_posn = window_posn;
|
||||
m_state.R0 = R0;
|
||||
m_state.R1 = R1;
|
||||
m_state.R2 = R2;
|
||||
|
||||
// TODO finish intel E8 decoding
|
||||
/* intel E8 decoding */
|
||||
if ((m_state.frames_read++ < 32768) && m_state.intel_filesize != 0)
|
||||
{
|
||||
if (outLen <= 6 || m_state.intel_started == 0)
|
||||
{
|
||||
m_state.intel_curpos += outLen;
|
||||
}
|
||||
else
|
||||
{
|
||||
int dataend = outLen - 10;
|
||||
uint curpos = (uint)m_state.intel_curpos;
|
||||
|
||||
m_state.intel_curpos = (int)curpos + outLen;
|
||||
|
||||
while (outData.Position < dataend)
|
||||
{
|
||||
if (outData.ReadByte() != 0xE8) { curpos++; continue; }
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// READ_LENGTHS(table, first, last)
|
||||
// if(lzx_read_lens(LENTABLE(table), first, last, bitsleft))
|
||||
// return ERROR (ILLEGAL_DATA)
|
||||
//
|
||||
|
||||
// TODO make returns throw exceptions
|
||||
private int MakeDecodeTable(uint nsyms, uint nbits, byte[] length, ushort[] table)
|
||||
{
|
||||
ushort sym;
|
||||
uint leaf;
|
||||
byte bit_num = 1;
|
||||
uint fill;
|
||||
uint pos = 0; /* the current position in the decode table */
|
||||
uint table_mask = (uint)(1 << (int)nbits);
|
||||
uint bit_mask = table_mask >> 1; /* don't do 0 length codes */
|
||||
uint next_symbol = bit_mask; /* base of allocation for long codes */
|
||||
|
||||
/* fill entries for codes short enough for a direct mapping */
|
||||
while (bit_num <= nbits)
|
||||
{
|
||||
for (sym = 0; sym < nsyms; sym++)
|
||||
{
|
||||
if (length[sym] == bit_num)
|
||||
{
|
||||
leaf = pos;
|
||||
|
||||
if ((pos += bit_mask) > table_mask) return 1; /* table overrun */
|
||||
|
||||
/* fill all possible lookups of this symbol with the symbol itself */
|
||||
fill = bit_mask;
|
||||
while (fill-- > 0) table[leaf++] = sym;
|
||||
}
|
||||
}
|
||||
bit_mask >>= 1;
|
||||
bit_num++;
|
||||
}
|
||||
|
||||
/* if there are any codes longer than nbits */
|
||||
if (pos != table_mask)
|
||||
{
|
||||
/* clear the remainder of the table */
|
||||
for (sym = (ushort)pos; sym < table_mask; sym++) table[sym] = 0;
|
||||
|
||||
/* give ourselves room for codes to grow by up to 16 more bits */
|
||||
pos <<= 16;
|
||||
table_mask <<= 16;
|
||||
bit_mask = 1 << 15;
|
||||
|
||||
while (bit_num <= 16)
|
||||
{
|
||||
for (sym = 0; sym < nsyms; sym++)
|
||||
{
|
||||
if (length[sym] == bit_num)
|
||||
{
|
||||
leaf = pos >> 16;
|
||||
for (fill = 0; fill < bit_num - nbits; fill++)
|
||||
{
|
||||
/* if this path hasn't been taken yet, 'allocate' two entries */
|
||||
if (table[leaf] == 0)
|
||||
{
|
||||
table[(next_symbol << 1)] = 0;
|
||||
table[(next_symbol << 1) + 1] = 0;
|
||||
table[leaf] = (ushort)(next_symbol++);
|
||||
}
|
||||
/* follow the path and select either left or right for next bit */
|
||||
leaf = (uint)(table[leaf] << 1);
|
||||
if (((pos >> (int)(15 - fill)) & 1) == 1) leaf++;
|
||||
}
|
||||
table[leaf] = sym;
|
||||
|
||||
if ((pos += bit_mask) > table_mask) return 1;
|
||||
}
|
||||
}
|
||||
bit_mask >>= 1;
|
||||
bit_num++;
|
||||
}
|
||||
}
|
||||
|
||||
/* full talbe? */
|
||||
if (pos == table_mask) return 0;
|
||||
|
||||
/* either erroneous table, or all elements are 0 - let's find out. */
|
||||
for (sym = 0; sym < nsyms; sym++) if (length[sym] != 0) return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// TODO throw exceptions instead of returns
|
||||
private void ReadLengths(byte[] lens, uint first, uint last, BitBuffer bitbuf)
|
||||
{
|
||||
uint x, y;
|
||||
int z;
|
||||
|
||||
// hufftbl pointer here?
|
||||
|
||||
for (x = 0; x < 20; x++)
|
||||
{
|
||||
y = bitbuf.ReadBits(4);
|
||||
m_state.PRETREE_len[x] = (byte)y;
|
||||
}
|
||||
MakeDecodeTable(LzxConstants.PRETREE_MAXSYMBOLS, LzxConstants.PRETREE_TABLEBITS,
|
||||
m_state.PRETREE_len, m_state.PRETREE_table);
|
||||
|
||||
for (x = first; x < last;)
|
||||
{
|
||||
z = (int)ReadHuffSym(m_state.PRETREE_table, m_state.PRETREE_len,
|
||||
LzxConstants.PRETREE_MAXSYMBOLS, LzxConstants.PRETREE_TABLEBITS, bitbuf);
|
||||
if (z == 17)
|
||||
{
|
||||
y = bitbuf.ReadBits(4); y += 4;
|
||||
while (y-- != 0) lens[x++] = 0;
|
||||
}
|
||||
else if (z == 18)
|
||||
{
|
||||
y = bitbuf.ReadBits(5); y += 20;
|
||||
while (y-- != 0) lens[x++] = 0;
|
||||
}
|
||||
else if (z == 19)
|
||||
{
|
||||
y = bitbuf.ReadBits(1); y += 4;
|
||||
z = (int)ReadHuffSym(m_state.PRETREE_table, m_state.PRETREE_len,
|
||||
LzxConstants.PRETREE_MAXSYMBOLS, LzxConstants.PRETREE_TABLEBITS, bitbuf);
|
||||
z = lens[x] - z; if (z < 0) z += 17;
|
||||
while (y-- != 0) lens[x++] = (byte)z;
|
||||
}
|
||||
else
|
||||
{
|
||||
z = lens[x] - z; if (z < 0) z += 17;
|
||||
lens[x++] = (byte)z;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private uint ReadHuffSym(ushort[] table, byte[] lengths, uint nsyms, uint nbits, BitBuffer bitbuf)
|
||||
{
|
||||
uint i, j;
|
||||
bitbuf.EnsureBits(16);
|
||||
if ((i = table[bitbuf.PeekBits((byte)nbits)]) >= nsyms)
|
||||
{
|
||||
j = (uint)(1 << (int)((sizeof(uint) * 8) - nbits));
|
||||
do
|
||||
{
|
||||
j >>= 1; i <<= 1; i |= (bitbuf.GetBuffer() & j) != 0 ? (uint)1 : 0;
|
||||
if (j == 0) return 0; // TODO throw proper exception
|
||||
} while ((i = table[i]) >= nsyms);
|
||||
}
|
||||
j = lengths[i];
|
||||
bitbuf.RemoveBits((byte)j);
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
#region Our BitBuffer Class
|
||||
private class BitBuffer
|
||||
{
|
||||
uint buffer;
|
||||
byte bitsleft;
|
||||
Stream byteStream;
|
||||
|
||||
public BitBuffer(Stream stream)
|
||||
{
|
||||
byteStream = stream;
|
||||
InitBitStream();
|
||||
}
|
||||
|
||||
public void InitBitStream()
|
||||
{
|
||||
buffer = 0;
|
||||
bitsleft = 0;
|
||||
}
|
||||
|
||||
public void EnsureBits(byte bits)
|
||||
{
|
||||
while (bitsleft < bits)
|
||||
{
|
||||
int lo = (byte)byteStream.ReadByte();
|
||||
int hi = (byte)byteStream.ReadByte();
|
||||
//int amount2shift = sizeof(uint)*8 - 16 - bitsleft;
|
||||
buffer |= (uint)(((hi << 8) | lo) << (sizeof(uint) * 8 - 16 - bitsleft));
|
||||
bitsleft += 16;
|
||||
}
|
||||
}
|
||||
|
||||
public uint PeekBits(byte bits)
|
||||
{
|
||||
return (buffer >> ((sizeof(uint) * 8) - bits));
|
||||
}
|
||||
|
||||
public void RemoveBits(byte bits)
|
||||
{
|
||||
buffer <<= bits;
|
||||
bitsleft -= bits;
|
||||
}
|
||||
|
||||
public uint ReadBits(byte bits)
|
||||
{
|
||||
uint ret = 0;
|
||||
|
||||
if (bits > 0)
|
||||
{
|
||||
EnsureBits(bits);
|
||||
ret = PeekBits(bits);
|
||||
RemoveBits(bits);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
public uint GetBuffer()
|
||||
{
|
||||
return buffer;
|
||||
}
|
||||
|
||||
public byte GetBitsLeft()
|
||||
{
|
||||
return bitsleft;
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
struct LzxState
|
||||
{
|
||||
public uint R0, R1, R2; /* for the LRU offset system */
|
||||
public ushort main_elements; /* number of main tree elements */
|
||||
public int header_read; /* have we started decoding at all yet? */
|
||||
public LzxConstants.BLOCKTYPE block_type; /* type of this block */
|
||||
public uint block_length; /* uncompressed length of this block */
|
||||
public uint block_remaining; /* uncompressed bytes still left to decode */
|
||||
public uint frames_read; /* the number of CFDATA blocks processed */
|
||||
public int intel_filesize; /* magic header value used for transform */
|
||||
public int intel_curpos; /* current offset in transform space */
|
||||
public int intel_started; /* have we seen any translateable data yet? */
|
||||
|
||||
public ushort[] PRETREE_table;
|
||||
public byte[] PRETREE_len;
|
||||
public ushort[] MAINTREE_table;
|
||||
public byte[] MAINTREE_len;
|
||||
public ushort[] LENGTH_table;
|
||||
public byte[] LENGTH_len;
|
||||
public ushort[] ALIGNED_table;
|
||||
public byte[] ALIGNED_len;
|
||||
|
||||
// NEEDED MEMBERS
|
||||
// CAB actualsize
|
||||
// CAB window
|
||||
// CAB window_size
|
||||
// CAB window_posn
|
||||
public uint actual_size;
|
||||
public byte[] window;
|
||||
public uint window_size;
|
||||
public uint window_posn;
|
||||
}
|
||||
}
|
||||
|
||||
/* CONSTANTS */
|
||||
struct LzxConstants
|
||||
{
|
||||
public const ushort MIN_MATCH = 2;
|
||||
public const ushort MAX_MATCH = 257;
|
||||
public const ushort NUM_CHARS = 256;
|
||||
public enum BLOCKTYPE
|
||||
{
|
||||
INVALID = 0,
|
||||
VERBATIM = 1,
|
||||
ALIGNED = 2,
|
||||
UNCOMPRESSED = 3
|
||||
}
|
||||
public const ushort PRETREE_NUM_ELEMENTS = 20;
|
||||
public const ushort ALIGNED_NUM_ELEMENTS = 8;
|
||||
public const ushort NUM_PRIMARY_LENGTHS = 7;
|
||||
public const ushort NUM_SECONDARY_LENGTHS = 249;
|
||||
|
||||
public const ushort PRETREE_MAXSYMBOLS = PRETREE_NUM_ELEMENTS;
|
||||
public const ushort PRETREE_TABLEBITS = 6;
|
||||
public const ushort MAINTREE_MAXSYMBOLS = NUM_CHARS + 50 * 8;
|
||||
public const ushort MAINTREE_TABLEBITS = 12;
|
||||
public const ushort LENGTH_MAXSYMBOLS = NUM_SECONDARY_LENGTHS + 1;
|
||||
public const ushort LENGTH_TABLEBITS = 12;
|
||||
public const ushort ALIGNED_MAXSYMBOLS = ALIGNED_NUM_ELEMENTS;
|
||||
public const ushort ALIGNED_TABLEBITS = 7;
|
||||
|
||||
public const ushort LENTABLE_SAFETY = 64;
|
||||
}
|
||||
|
||||
/* EXCEPTIONS */
|
||||
class UnsupportedWindowSizeRange : Exception
|
||||
{
|
||||
}
|
||||
}
|
||||
155
PCK-Studio/Classes/Utils/grf/xmemdecompress.cs
Normal file
155
PCK-Studio/Classes/Utils/grf/xmemdecompress.cs
Normal file
@@ -0,0 +1,155 @@
|
||||
// MonoGame - Copyright (C) The MonoGame Team
|
||||
// This file is subject to the terms and conditions defined in
|
||||
// file 'LICENSE.txt', which is part of this source code package.
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
using Microsoft.Xna.Framework.Content;
|
||||
|
||||
namespace MonoGame.Framework.Utilities
|
||||
{
|
||||
internal class LzxDecoderStream : Stream
|
||||
{
|
||||
LzxDecoder dec;
|
||||
MemoryStream decompressedStream;
|
||||
|
||||
public LzxDecoderStream(Stream input, int decompressedSize, int compressedSize)
|
||||
{
|
||||
dec = new LzxDecoder(16);
|
||||
|
||||
// TODO: Rewrite using block decompression like Lz4DecoderStream
|
||||
Decompress(input, decompressedSize, compressedSize);
|
||||
}
|
||||
|
||||
// Decompress into MemoryStream
|
||||
private void Decompress(Stream stream, int decompressedSize, int compressedSize)
|
||||
{
|
||||
//thanks to ShinAli (https://bitbucket.org/alisci01/xnbdecompressor)
|
||||
// default window size for XNB encoded files is 64Kb (need 16 bits to represent it)
|
||||
decompressedStream = new MemoryStream(decompressedSize);
|
||||
long startPos = stream.Position;
|
||||
long pos = startPos;
|
||||
|
||||
while (pos - startPos < compressedSize)
|
||||
{
|
||||
// the compressed stream is seperated into blocks that will decompress
|
||||
// into 32Kb or some other size if specified.
|
||||
// normal, 32Kb output blocks will have a short indicating the size
|
||||
// of the block before the block starts
|
||||
// blocks that have a defined output will be preceded by a byte of value
|
||||
// 0xFF (255), then a short indicating the output size and another
|
||||
// for the block size
|
||||
// all shorts for these cases are encoded in big endian order
|
||||
int hi = stream.ReadByte();
|
||||
int lo = stream.ReadByte();
|
||||
int block_size = (hi << 8) | lo;
|
||||
int frame_size = 0x8000; // frame size is 32Kb by default
|
||||
// does this block define a frame size?
|
||||
if (hi == 0xFF)
|
||||
{
|
||||
hi = lo;
|
||||
lo = (byte)stream.ReadByte();
|
||||
frame_size = (hi << 8) | lo;
|
||||
hi = (byte)stream.ReadByte();
|
||||
lo = (byte)stream.ReadByte();
|
||||
block_size = (hi << 8) | lo;
|
||||
pos += 5;
|
||||
}
|
||||
else
|
||||
pos += 2;
|
||||
|
||||
// either says there is nothing to decode
|
||||
if (block_size == 0 || frame_size == 0)
|
||||
break;
|
||||
|
||||
dec.Decompress(stream, block_size, decompressedStream, frame_size);
|
||||
pos += block_size;
|
||||
|
||||
// reset the position of the input just incase the bit buffer
|
||||
// read in some unused bytes
|
||||
stream.Seek(pos, SeekOrigin.Begin);
|
||||
}
|
||||
|
||||
Console.WriteLine(decompressedStream.Position);
|
||||
Console.WriteLine(decompressedSize);
|
||||
//if (decompressedStream.Position != decompressedSize)
|
||||
//{
|
||||
// throw new Exception("Decompression failed.");
|
||||
//}
|
||||
|
||||
decompressedStream.Seek(0, SeekOrigin.Begin);
|
||||
using (var fs = File.OpenWrite("xmem_test.grf"))
|
||||
{
|
||||
decompressedStream.CopyTo(fs);
|
||||
}
|
||||
decompressedStream.Seek(0, SeekOrigin.Begin);
|
||||
}
|
||||
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
base.Dispose(disposing);
|
||||
if (disposing)
|
||||
{
|
||||
decompressedStream.Dispose();
|
||||
}
|
||||
dec = null;
|
||||
decompressedStream = null;
|
||||
}
|
||||
|
||||
#region Stream internals
|
||||
|
||||
public override int Read(byte[] buffer, int offset, int count)
|
||||
{
|
||||
return decompressedStream.Read(buffer, offset, count);
|
||||
}
|
||||
|
||||
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 { throw new NotSupportedException(); }
|
||||
}
|
||||
|
||||
public override long Position
|
||||
{
|
||||
get { throw new NotSupportedException(); }
|
||||
set { throw new NotSupportedException(); }
|
||||
}
|
||||
|
||||
|
||||
public override long Seek(long offset, SeekOrigin origin)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public override void SetLength(long value)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public override void Write(byte[] buffer, int offset, int count)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user