mirror of
https://github.com/crskycode/GARbro.git
synced 2024-11-23 13:45:34 +08:00
(Entis): improved ErisaN compression handling.
This commit is contained in:
parent
cc6747c537
commit
e1771edc81
@ -2,7 +2,7 @@
|
|||||||
//! \date Thu Apr 23 15:57:17 2015
|
//! \date Thu Apr 23 15:57:17 2015
|
||||||
//! \brief Entis GLS engine archives implementation.
|
//! \brief Entis GLS engine archives implementation.
|
||||||
//
|
//
|
||||||
// Copyright (C) 2015-2016 by morkt
|
// Copyright (C) 2015-2018 by morkt
|
||||||
//
|
//
|
||||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
// of this software and associated documentation files (the "Software"), to
|
// of this software and associated documentation files (the "Software"), to
|
||||||
@ -77,7 +77,7 @@ namespace GameRes.Formats.Entis
|
|||||||
|
|
||||||
public NoaOpener ()
|
public NoaOpener ()
|
||||||
{
|
{
|
||||||
Extensions = new string[] { "noa", "dat", "rsa" };
|
Extensions = new string[] { "noa", "dat", "rsa", "arc" };
|
||||||
Settings = new[] { NoaEncoding };
|
Settings = new[] { NoaEncoding };
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -96,14 +96,14 @@ namespace GameRes.Formats.Entis
|
|||||||
var reader = new IndexReader (file, NoaEncoding.Get<Encoding>());
|
var reader = new IndexReader (file, NoaEncoding.Get<Encoding>());
|
||||||
if (!reader.ParseRoot() || 0 == reader.Dir.Count)
|
if (!reader.ParseRoot() || 0 == reader.Dir.Count)
|
||||||
return null;
|
return null;
|
||||||
if (!reader.HasEncrypted)
|
if (reader.HasEncrypted)
|
||||||
return new ArcFile (file, this, reader.Dir);
|
{
|
||||||
|
|
||||||
var password = GetArcPassword (file.Name);
|
var password = GetArcPassword (file.Name);
|
||||||
if (string.IsNullOrEmpty (password))
|
if (!string.IsNullOrEmpty (password))
|
||||||
return new ArcFile (file, this, reader.Dir);
|
|
||||||
return new NoaArchive (file, this, reader.Dir, password);
|
return new NoaArchive (file, this, reader.Dir, password);
|
||||||
}
|
}
|
||||||
|
return new ArcFile (file, this, reader.Dir);
|
||||||
|
}
|
||||||
|
|
||||||
public override Stream OpenEntry (ArcFile arc, Entry entry)
|
public override Stream OpenEntry (ArcFile arc, Entry entry)
|
||||||
{
|
{
|
||||||
@ -118,8 +118,8 @@ namespace GameRes.Formats.Entis
|
|||||||
|
|
||||||
if (EncType.ERISACode == nent.Encryption)
|
if (EncType.ERISACode == nent.Encryption)
|
||||||
{
|
{
|
||||||
using (var enc = arc.File.CreateStream (entry.Offset+0x10, (uint)size-4))
|
var enc = arc.File.CreateStream (entry.Offset+0x10, (uint)size-4);
|
||||||
return DecodeNemesis (enc);
|
return new ErisaNemesisStream (enc, (int)entry.Size);
|
||||||
}
|
}
|
||||||
|
|
||||||
var narc = arc as NoaArchive;
|
var narc = arc as NoaArchive;
|
||||||
@ -183,7 +183,7 @@ namespace GameRes.Formats.Entis
|
|||||||
if (null == cotomi)
|
if (null == cotomi)
|
||||||
continue;
|
continue;
|
||||||
using (var res = new MemoryStream (cotomi))
|
using (var res = new MemoryStream (cotomi))
|
||||||
using (var input = DecodeNemesis (res))
|
using (var input = new ErisaNemesisStream (res))
|
||||||
{
|
{
|
||||||
var xml = new XmlDocument();
|
var xml = new XmlDocument();
|
||||||
xml.Load (input);
|
xml.Load (input);
|
||||||
@ -210,24 +210,6 @@ namespace GameRes.Formats.Entis
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
Stream DecodeNemesis (Stream input)
|
|
||||||
{
|
|
||||||
var decoder = new NemesisDecodeContext();
|
|
||||||
decoder.AttachInputFile (input);
|
|
||||||
decoder.PrepareToDecodeERISANCode();
|
|
||||||
var file = new MemoryStream ((int)input.Length);
|
|
||||||
var buffer = new byte[0x10000];
|
|
||||||
for (;;)
|
|
||||||
{
|
|
||||||
int read = (int)decoder.DecodeNemesisCodeBytes (buffer, 0x10000);
|
|
||||||
if (0 == read)
|
|
||||||
break;
|
|
||||||
file.Write (buffer, 0, read);
|
|
||||||
}
|
|
||||||
file.Position = 0;
|
|
||||||
return file;
|
|
||||||
}
|
|
||||||
|
|
||||||
Stream DecodeBSHF (Stream input, string password)
|
Stream DecodeBSHF (Stream input, string password)
|
||||||
{
|
{
|
||||||
uint nTotalBytes = (uint)input.Length - 4;
|
uint nTotalBytes = (uint)input.Length - 4;
|
||||||
@ -317,10 +299,11 @@ namespace GameRes.Formats.Entis
|
|||||||
|
|
||||||
entry.Encryption = m_file.View.ReadUInt32 (dir_offset);
|
entry.Encryption = m_file.View.ReadUInt32 (dir_offset);
|
||||||
m_found_encrypted = m_found_encrypted || (EncType.Raw != entry.Encryption && EncType.ERISACode != entry.Encryption);
|
m_found_encrypted = m_found_encrypted || (EncType.Raw != entry.Encryption && EncType.ERISACode != entry.Encryption);
|
||||||
|
bool is_packed = EncType.ERISACode == entry.Encryption;
|
||||||
dir_offset += 4;
|
dir_offset += 4;
|
||||||
|
|
||||||
entry.Offset = base_offset + m_file.View.ReadInt64 (dir_offset);
|
entry.Offset = base_offset + m_file.View.ReadInt64 (dir_offset);
|
||||||
if (!entry.CheckPlacement (m_file.MaxOffset))
|
if (!is_packed && !entry.CheckPlacement (m_file.MaxOffset))
|
||||||
{
|
{
|
||||||
entry.Size = (uint)(m_file.MaxOffset - entry.Offset);
|
entry.Size = (uint)(m_file.MaxOffset - entry.Offset);
|
||||||
}
|
}
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
|
using System.IO;
|
||||||
|
|
||||||
namespace GameRes.Formats.Entis
|
namespace GameRes.Formats.Entis
|
||||||
{
|
{
|
||||||
@ -64,17 +65,16 @@ namespace GameRes.Formats.Entis
|
|||||||
|
|
||||||
public override uint DecodeBytes (Array ptrDst, uint nCount)
|
public override uint DecodeBytes (Array ptrDst, uint nCount)
|
||||||
{
|
{
|
||||||
return DecodeNemesisCodeBytes (ptrDst as byte[], nCount);
|
return DecodeNemesisCodeBytes (ptrDst as byte[], 0, nCount);
|
||||||
}
|
}
|
||||||
|
|
||||||
public uint DecodeNemesisCodeBytes (byte[] ptrDst, uint nCount)
|
public uint DecodeNemesisCodeBytes (byte[] ptrDst, int dst, uint nCount)
|
||||||
{
|
{
|
||||||
if (m_flagEOF)
|
if (m_flagEOF)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
ErisaProbBase pBase = m_pProbERISA;
|
ErisaProbBase pBase = m_pProbERISA;
|
||||||
uint nDecoded = 0;
|
uint nDecoded = 0;
|
||||||
int dst = 0;
|
|
||||||
byte bytSymbol;
|
byte bytSymbol;
|
||||||
while (nDecoded < nCount)
|
while (nDecoded < nCount)
|
||||||
{
|
{
|
||||||
@ -150,7 +150,6 @@ namespace GameRes.Formats.Entis
|
|||||||
if (nSymbol != ErisaProbModel.EscCode)
|
if (nSymbol != ErisaProbModel.EscCode)
|
||||||
{
|
{
|
||||||
pModel.AddSymbol ((short)nSymbol);
|
pModel.AddSymbol ((short)nSymbol);
|
||||||
iSym = -1;
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -214,7 +213,7 @@ namespace GameRes.Formats.Entis
|
|||||||
|
|
||||||
if ((pBase.dwWorkUsed < ErisaProbBase.SlotMax) && (iDeg < 4))
|
if ((pBase.dwWorkUsed < ErisaProbBase.SlotMax) && (iDeg < 4))
|
||||||
{
|
{
|
||||||
int iSymbol = ((byte)nSymbol) >> ErisaProbBase.m_nShiftCount[iDeg];
|
int iSymbol = bytSymbol >> ErisaProbBase.m_nShiftCount[iDeg];
|
||||||
if (iSymbol >= ErisaProbModel.SubSortMax)
|
if (iSymbol >= ErisaProbModel.SubSortMax)
|
||||||
throw new InvalidFormatException ("Invalid Nemesis encoding sequence");
|
throw new InvalidFormatException ("Invalid Nemesis encoding sequence");
|
||||||
if (++pModel.SubModel[iSymbol].Occured >= ErisaProbBase.m_nNewProbLimit[iDeg])
|
if (++pModel.SubModel[iSymbol].Occured >= ErisaProbBase.m_nNewProbLimit[iDeg])
|
||||||
@ -295,4 +294,45 @@ namespace GameRes.Formats.Entis
|
|||||||
public uint first;
|
public uint first;
|
||||||
public uint[] index = new uint[Nemesis.IndexLimit];
|
public uint[] index = new uint[Nemesis.IndexLimit];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal class ErisaNemesisStream : InputProxyStream
|
||||||
|
{
|
||||||
|
NemesisDecodeContext m_decoder;
|
||||||
|
int m_remaining;
|
||||||
|
bool m_eof = false;
|
||||||
|
|
||||||
|
public ErisaNemesisStream (Stream input, int output_length = 0) : base (input)
|
||||||
|
{
|
||||||
|
m_decoder = new NemesisDecodeContext();
|
||||||
|
m_decoder.AttachInputFile (input);
|
||||||
|
m_decoder.PrepareToDecodeERISANCode();
|
||||||
|
m_remaining = output_length > 0 ? output_length : int.MaxValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override int Read (byte[] buffer, int offset, int count)
|
||||||
|
{
|
||||||
|
int read = 0;
|
||||||
|
if (!m_eof && m_remaining > 0)
|
||||||
|
{
|
||||||
|
uint chunk_size = (uint)Math.Min (count, m_remaining);
|
||||||
|
read = (int)m_decoder.DecodeNemesisCodeBytes (buffer, offset, chunk_size);
|
||||||
|
m_eof = read < count;
|
||||||
|
m_remaining -= read;
|
||||||
|
}
|
||||||
|
return read;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool CanSeek { get { return false; } }
|
||||||
|
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 NotSupportedException();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user