Files
PCK-Studio/MinecraftUSkinEditor/Classes/IO/GRF/GRFFileReader.cs

147 lines
4.7 KiB
C#

using PckStudio.Classes.FileTypes;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using ICSharpCode.SharpZipLib.Zip.Compression.Streams;
using PckStudio.Classes.Utils;
namespace PckStudio.Classes.IO.GRF
{
internal class GRFFileReader : StreamDataReader
{
internal List<string> TagNames;
internal GRFFile _file;
public static GRFFile Read(Stream stream)
{
return new GRFFileReader().read(stream);
}
private GRFFileReader() : base(false)
{ }
private GRFFile read(Stream stream)
{
stream = ReadHeader(stream);
ReadBody(stream);
return _file;
}
private Stream ReadHeader(Stream stream)
{
int x = ReadShort(stream);
if (((x >> 31) | x) == 0)
{
// 14 bools ?...
ReadBytes(stream, 14);
return stream;
}
GRFFile.eCompressionType compression_type = (GRFFile.eCompressionType)stream.ReadByte();
int crc = ReadInt(stream);
int byte1 = stream.ReadByte();
int byte2 = stream.ReadByte();
int byte3 = stream.ReadByte();
int byte4 = stream.ReadByte();
if (byte4 > 0)
{
compression_type = (GRFFile.eCompressionType)byte4;
}
_file = new GRFFile(crc, byte4 > 0);
if (compression_type == GRFFile.eCompressionType.None && byte4 == 0)
return stream;
int buf_size = ReadInt(stream);
var new_stream = stream;
if (byte4 != 0)
{
new_stream = new MemoryStream(ReadBytes(stream, buf_size));
buf_size = ReadInt(new_stream);
}
else
{
ReadInt(stream); // ignored cuz rest of data is compressed
}
var decompressed_stream = DecompressZLX(new_stream);
new_stream.Dispose();
if (compression_type > GRFFile.eCompressionType.Zlib)
{
byte[] data = ReadBytes(decompressed_stream, buf_size);
byte[] decoded_data = RLE<byte>.Decode(data).ToArray();
decompressed_stream.Dispose();
decompressed_stream = new MemoryStream(decoded_data);
}
if (byte4 != 0)
ReadBytes(decompressed_stream, 23);
return decompressed_stream;
}
private void ReadBody(Stream stream)
{
ReadTagNames(stream);
ReadRootTag(stream);
}
private Stream DecompressZLX(Stream compressedStream)
{
Stream outputstream = new MemoryStream();
using (var inputStream = new InflaterInputStream(compressedStream))
{
inputStream.IsStreamOwner = false;
inputStream.CopyTo(outputstream);
outputstream.Position = 0;
};
return outputstream;
}
private void ReadTagNames(Stream stream)
{
int name_count = ReadInt(stream);
TagNames = new List<string>(name_count);
for (int i = 0; i < name_count; i++)
{
string s = ReadString(stream);
TagNames.Add(s);
//Console.WriteLine(s);
}
}
private void ReadRootTag(Stream stream)
{
string Name = GetTagName(stream);
Console.WriteLine($"[GRFFileReader] root_name: {Name}");
_file.RootTag.Tags = ReadGRFTreeHierarchy(stream, _file.RootTag).ToList();
}
private IEnumerable<GRFFile.GRFTag> ReadGRFTreeHierarchy(Stream stream, GRFFile.GRFTag parent)
{
int count = ReadInt(stream);
for (int i = 0; i < count; i++)
{
string parameterName = GetTagName(stream);
int parameterCount = ReadInt(stream);
var tag = new GRFFile.GRFTag(parameterName, parent);
for (int j = 0; j < parameterCount; j++)
{
tag.Parameters.Add(GetTagName(stream), ReadString(stream));
}
tag.Tags = ReadGRFTreeHierarchy(stream, tag).ToList();
yield return tag;
}
yield break;
}
private string GetTagName(Stream stream) => TagNames[ReadInt(stream)];
private string ReadString(Stream stream)
{
short stringLength = ReadShort(stream);
return ReadString(stream, stringLength, Encoding.ASCII);
}
}
}