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
|
||||
//! \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
|
||||
// of this software and associated documentation files (the "Software"), to
|
||||
@ -77,7 +77,7 @@ namespace GameRes.Formats.Entis
|
||||
|
||||
public NoaOpener ()
|
||||
{
|
||||
Extensions = new string[] { "noa", "dat", "rsa" };
|
||||
Extensions = new string[] { "noa", "dat", "rsa", "arc" };
|
||||
Settings = new[] { NoaEncoding };
|
||||
}
|
||||
|
||||
@ -96,13 +96,13 @@ namespace GameRes.Formats.Entis
|
||||
var reader = new IndexReader (file, NoaEncoding.Get<Encoding>());
|
||||
if (!reader.ParseRoot() || 0 == reader.Dir.Count)
|
||||
return null;
|
||||
if (!reader.HasEncrypted)
|
||||
return new ArcFile (file, this, reader.Dir);
|
||||
|
||||
var password = GetArcPassword (file.Name);
|
||||
if (string.IsNullOrEmpty (password))
|
||||
return new ArcFile (file, this, reader.Dir);
|
||||
return new NoaArchive (file, this, reader.Dir, password);
|
||||
if (reader.HasEncrypted)
|
||||
{
|
||||
var password = GetArcPassword (file.Name);
|
||||
if (!string.IsNullOrEmpty (password))
|
||||
return new NoaArchive (file, this, reader.Dir, password);
|
||||
}
|
||||
return new ArcFile (file, this, reader.Dir);
|
||||
}
|
||||
|
||||
public override Stream OpenEntry (ArcFile arc, Entry entry)
|
||||
@ -118,8 +118,8 @@ namespace GameRes.Formats.Entis
|
||||
|
||||
if (EncType.ERISACode == nent.Encryption)
|
||||
{
|
||||
using (var enc = arc.File.CreateStream (entry.Offset+0x10, (uint)size-4))
|
||||
return DecodeNemesis (enc);
|
||||
var enc = arc.File.CreateStream (entry.Offset+0x10, (uint)size-4);
|
||||
return new ErisaNemesisStream (enc, (int)entry.Size);
|
||||
}
|
||||
|
||||
var narc = arc as NoaArchive;
|
||||
@ -183,7 +183,7 @@ namespace GameRes.Formats.Entis
|
||||
if (null == cotomi)
|
||||
continue;
|
||||
using (var res = new MemoryStream (cotomi))
|
||||
using (var input = DecodeNemesis (res))
|
||||
using (var input = new ErisaNemesisStream (res))
|
||||
{
|
||||
var xml = new XmlDocument();
|
||||
xml.Load (input);
|
||||
@ -210,24 +210,6 @@ namespace GameRes.Formats.Entis
|
||||
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)
|
||||
{
|
||||
uint nTotalBytes = (uint)input.Length - 4;
|
||||
@ -317,10 +299,11 @@ namespace GameRes.Formats.Entis
|
||||
|
||||
entry.Encryption = m_file.View.ReadUInt32 (dir_offset);
|
||||
m_found_encrypted = m_found_encrypted || (EncType.Raw != entry.Encryption && EncType.ERISACode != entry.Encryption);
|
||||
bool is_packed = EncType.ERISACode == entry.Encryption;
|
||||
dir_offset += 4;
|
||||
|
||||
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);
|
||||
}
|
||||
|
@ -5,6 +5,7 @@
|
||||
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
|
||||
namespace GameRes.Formats.Entis
|
||||
{
|
||||
@ -64,17 +65,16 @@ namespace GameRes.Formats.Entis
|
||||
|
||||
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)
|
||||
return 0;
|
||||
|
||||
ErisaProbBase pBase = m_pProbERISA;
|
||||
uint nDecoded = 0;
|
||||
int dst = 0;
|
||||
byte bytSymbol;
|
||||
while (nDecoded < nCount)
|
||||
{
|
||||
@ -150,7 +150,6 @@ namespace GameRes.Formats.Entis
|
||||
if (nSymbol != ErisaProbModel.EscCode)
|
||||
{
|
||||
pModel.AddSymbol ((short)nSymbol);
|
||||
iSym = -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -214,7 +213,7 @@ namespace GameRes.Formats.Entis
|
||||
|
||||
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)
|
||||
throw new InvalidFormatException ("Invalid Nemesis encoding sequence");
|
||||
if (++pModel.SubModel[iSymbol].Occured >= ErisaProbBase.m_nNewProbLimit[iDeg])
|
||||
@ -295,4 +294,45 @@ namespace GameRes.Formats.Entis
|
||||
public uint first;
|
||||
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