(ODN): sometimes scripts are not encrypted.

added possible image dimensions.
This commit is contained in:
morkt 2018-10-25 16:54:16 +04:00
parent 657368812e
commit cd527552b8

View File

@ -55,6 +55,11 @@ namespace GameRes.Formats.Valkyria
} }
} }
internal class OdnEntry : Entry
{
public bool IsEncrypted;
}
[Export(typeof(ArchiveFormat))] [Export(typeof(ArchiveFormat))]
sealed public class OdnOpener : ArchiveFormat sealed public class OdnOpener : ArchiveFormat
{ {
@ -67,9 +72,11 @@ namespace GameRes.Formats.Valkyria
public OdnOpener () public OdnOpener ()
{ {
Settings = new[] { AudioSampleRate }; Settings = new[] { AudioSampleRate };
Extensions = new[] { "odn", "dat" }; Extensions = RequiredExtensions;
} }
static string[] RequiredExtensions = new[] { "odn", "dat", "pni" };
FixedSetSetting AudioSampleRate = new FixedSetSetting (Properties.Settings.Default) { FixedSetSetting AudioSampleRate = new FixedSetSetting (Properties.Settings.Default) {
Name = "ODNAudioSampleRate", Name = "ODNAudioSampleRate",
Text = arcStrings.ODNAudioSampleRate, Text = arcStrings.ODNAudioSampleRate,
@ -78,7 +85,7 @@ namespace GameRes.Formats.Valkyria
public override ArcFile TryOpen (ArcView file) public override ArcFile TryOpen (ArcView file)
{ {
if (!file.Name.HasAnyOfExtensions ("odn", "dat")) if (!file.Name.HasAnyOfExtensions (RequiredExtensions))
return null; return null;
var reader = new OdnIndexReader (file); var reader = new OdnIndexReader (file);
var dir = reader.ReadIndex(); var dir = reader.ReadIndex();
@ -87,14 +94,15 @@ namespace GameRes.Formats.Valkyria
return new ArcFile (file, this, dir); return new ArcFile (file, this, dir);
} }
internal static readonly Regex Image24NameRe = new Regex ("^(?:back|phii)"); internal static readonly Regex Image24NameRe = new Regex ("^(?:back|phii|psss)");
internal static readonly Regex Image32NameRe = new Regex ("^(?:data|codn|cccc|fund)"); internal static readonly Regex Image32NameRe = new Regex ("^(?:data|codn|cccc|fund|puni|wind)");
internal static readonly Regex ScriptNameRe = new Regex ("^(?:scrp|menu|sysm)"); internal static readonly Regex ScriptNameRe = new Regex ("^(?:scrp|menu|sysm)");
internal static readonly Regex AudioNameRe = new Regex ("^hime"); internal static readonly Regex AudioNameRe = new Regex ("^hime");
public override Stream OpenEntry (ArcFile arc, Entry entry) public override Stream OpenEntry (ArcFile arc, Entry entry)
{ {
if (ScriptNameRe.IsMatch (entry.Name)) var oent = entry as OdnEntry;
if (oent != null && oent.IsEncrypted)
{ {
byte key = (byte)~entry.Offset; byte key = (byte)~entry.Offset;
var data = arc.File.View.ReadBytes (entry.Offset, entry.Size); var data = arc.File.View.ReadBytes (entry.Offset, entry.Size);
@ -140,6 +148,11 @@ namespace GameRes.Formats.Valkyria
try try
{ {
UnpackImage (input, output, pixel_size); UnpackImage (input, output, pixel_size);
if (entry.Name.StartsWith ("wind") && output.Length == 1024 * 256 * pixel_size)
{
var info = new ImageMetaData { Width = 1024, Height = 256, BPP = pixel_size * 8 };
return new OdnImageDecoder (output, info);
}
return CreateImageDecoder (output, pixel_size); return CreateImageDecoder (output, pixel_size);
} }
catch { /* try different pixel size */ } catch { /* try different pixel size */ }
@ -169,8 +182,10 @@ namespace GameRes.Formats.Valkyria
static readonly Size[] ImageDimensions = new Size[] static readonly Size[] ImageDimensions = new Size[]
{ {
new Size (1024, 768), new Size (1024, 768),
new Size (1024, 512),
new Size (800, 600), new Size (800, 600),
new Size (640, 480), new Size (640, 480),
new Size (512, 512),
new Size (400, 600), new Size (400, 600),
new Size (400, 200), new Size (400, 200),
}; };
@ -221,6 +236,7 @@ namespace GameRes.Formats.Valkyria
byte[] m_entry_buf = new byte[0x20]; byte[] m_entry_buf = new byte[0x20];
List<Entry> m_dir = new List<Entry>(); List<Entry> m_dir = new List<Entry>();
Encoding m_enc; Encoding m_enc;
bool m_scripts_encrypted = true;
public OdnIndexReader (ArcView file) public OdnIndexReader (ArcView file)
{ {
@ -265,6 +281,11 @@ namespace GameRes.Formats.Valkyria
index_offset += 0x10; index_offset += 0x10;
if (m_entry_buf.AsciiEqual (0, "END_ffffffffffff")) if (m_entry_buf.AsciiEqual (0, "END_ffffffffffff"))
break; break;
else if (m_entry_buf.AsciiEqual (0, "ffffffffffffffff"))
{
m_scripts_encrypted = false;
break;
}
else if (m_entry_buf.AsciiEqual (0, "HIME_END")) else if (m_entry_buf.AsciiEqual (0, "HIME_END"))
{ {
index_offset += 8; index_offset += 8;
@ -272,10 +293,10 @@ namespace GameRes.Formats.Valkyria
} }
var name = m_enc.GetString (m_entry_buf, 0, 8); var name = m_enc.GetString (m_entry_buf, 0, 8);
var offset = m_enc.GetString (m_entry_buf, 8, 8); var offset = m_enc.GetString (m_entry_buf, 8, 8);
var entry = new Entry { Name = name, Offset = Convert.ToUInt32 (offset, 16) }; var entry = new OdnEntry { Name = name, Offset = Convert.ToUInt32 (offset, 16) };
m_dir.Add (entry); m_dir.Add (entry);
} }
foreach (var entry in m_dir) foreach (OdnEntry entry in m_dir)
entry.Offset += index_offset; entry.Offset += index_offset;
if (m_dir.Any() && m_dir[m_dir.Count-1].Offset == m_file.MaxOffset) if (m_dir.Any() && m_dir[m_dir.Count-1].Offset == m_file.MaxOffset)
m_dir.RemoveAt (m_dir.Count-1); m_dir.RemoveAt (m_dir.Count-1);
@ -293,7 +314,7 @@ namespace GameRes.Formats.Valkyria
if (m_file.MaxOffset == offset) if (m_file.MaxOffset == offset)
break; break;
var name = m_enc.GetString (m_entry_buf, 0, 8); var name = m_enc.GetString (m_entry_buf, 0, 8);
var entry = new Entry { Name = name, Offset = offset }; var entry = new OdnEntry { Name = name, Offset = offset };
m_dir.Add (entry); m_dir.Add (entry);
index_offset += record_size; index_offset += record_size;
if (record_size != m_file.View.Read (index_offset, m_entry_buf, 0, record_size)) if (record_size != m_file.View.Read (index_offset, m_entry_buf, 0, record_size))
@ -311,7 +332,7 @@ namespace GameRes.Formats.Valkyria
break; break;
var name = m_enc.GetString (m_entry_buf, 0, 8); var name = m_enc.GetString (m_entry_buf, 0, 8);
var offset = m_enc.GetString (m_entry_buf, 8, 8); var offset = m_enc.GetString (m_entry_buf, 8, 8);
var entry = new Entry { Name = name, Offset = Convert.ToUInt32 (offset, 16) }; var entry = new OdnEntry { Name = name, Offset = Convert.ToUInt32 (offset, 16) };
m_dir.Add (entry); m_dir.Add (entry);
if (0x10 != m_file.View.Read (index_offset, m_entry_buf, 0, 0x10)) if (0x10 != m_file.View.Read (index_offset, m_entry_buf, 0, 0x10))
throw new InvalidFormatException(); throw new InvalidFormatException();
@ -333,7 +354,7 @@ namespace GameRes.Formats.Valkyria
{ {
for (int i = 0; i < m_dir.Count; ++i) for (int i = 0; i < m_dir.Count; ++i)
{ {
var entry = m_dir[i]; var entry = (OdnEntry)m_dir[i];
long next_offset = i+1 < m_dir.Count ? m_dir[i+1].Offset : m_file.MaxOffset; long next_offset = i+1 < m_dir.Count ? m_dir[i+1].Offset : m_file.MaxOffset;
entry.Size = (uint)(next_offset - entry.Offset); entry.Size = (uint)(next_offset - entry.Offset);
@ -345,6 +366,7 @@ namespace GameRes.Formats.Valkyria
else if (OdnOpener.ScriptNameRe.IsMatch (entry.Name)) else if (OdnOpener.ScriptNameRe.IsMatch (entry.Name))
{ {
entry.Type = "script"; entry.Type = "script";
entry.IsEncrypted = m_scripts_encrypted;
} }
else if (OdnOpener.AudioNameRe.IsMatch (entry.Name)) else if (OdnOpener.AudioNameRe.IsMatch (entry.Name))
{ {