mirror of
https://github.com/crskycode/GARbro.git
synced 2024-12-24 20:04:13 +08:00
implemented various Leaf resources.
This commit is contained in:
parent
8c5164a3a5
commit
ca52730701
@ -92,6 +92,7 @@
|
|||||||
<Compile Include="Cmvs\ArcPBZ.cs" />
|
<Compile Include="Cmvs\ArcPBZ.cs" />
|
||||||
<Compile Include="Cmvs\AudioMV.cs" />
|
<Compile Include="Cmvs\AudioMV.cs" />
|
||||||
<Compile Include="Cmvs\ImagePSB.cs" />
|
<Compile Include="Cmvs\ImagePSB.cs" />
|
||||||
|
<Compile Include="Crc32.cs" />
|
||||||
<Compile Include="Crowd\ImageGAX.cs" />
|
<Compile Include="Crowd\ImageGAX.cs" />
|
||||||
<Compile Include="Cyberworks\ArcDAT.cs" />
|
<Compile Include="Cyberworks\ArcDAT.cs" />
|
||||||
<Compile Include="Cyberworks\AudioTINK.cs" />
|
<Compile Include="Cyberworks\AudioTINK.cs" />
|
||||||
@ -110,6 +111,12 @@
|
|||||||
<Compile Include="Ipac\AudioWST.cs" />
|
<Compile Include="Ipac\AudioWST.cs" />
|
||||||
<Compile Include="Ipac\ImageIES.cs" />
|
<Compile Include="Ipac\ImageIES.cs" />
|
||||||
<Compile Include="Kiss\ArcARC.cs" />
|
<Compile Include="Kiss\ArcARC.cs" />
|
||||||
|
<Compile Include="Leaf\ArcA.cs" />
|
||||||
|
<Compile Include="Leaf\ArcAM.cs" />
|
||||||
|
<Compile Include="Leaf\ArcLAC.cs" />
|
||||||
|
<Compile Include="Leaf\AudioG.cs" />
|
||||||
|
<Compile Include="Leaf\AudioW.cs" />
|
||||||
|
<Compile Include="Leaf\ImagePX.cs" />
|
||||||
<Compile Include="LiveMaker\ArcVF.cs" />
|
<Compile Include="LiveMaker\ArcVF.cs" />
|
||||||
<Compile Include="ArcZIP.cs" />
|
<Compile Include="ArcZIP.cs" />
|
||||||
<Compile Include="AudioVOC.cs" />
|
<Compile Include="AudioVOC.cs" />
|
||||||
|
86
ArcFormats/Leaf/ArcA.cs
Normal file
86
ArcFormats/Leaf/ArcA.cs
Normal file
@ -0,0 +1,86 @@
|
|||||||
|
//! \file ArcA.cs
|
||||||
|
//! \date Wed Aug 17 17:32:54 2016
|
||||||
|
//! \brief Leaf resource archive.
|
||||||
|
//
|
||||||
|
// Copyright (C) 2016 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
|
||||||
|
// deal in the Software without restriction, including without limitation the
|
||||||
|
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||||
|
// sell copies of the Software, and to permit persons to whom the Software is
|
||||||
|
// furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in
|
||||||
|
// all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||||
|
// IN THE SOFTWARE.
|
||||||
|
//
|
||||||
|
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.ComponentModel.Composition;
|
||||||
|
using System.IO;
|
||||||
|
using GameRes.Compression;
|
||||||
|
|
||||||
|
namespace GameRes.Formats.Leaf
|
||||||
|
{
|
||||||
|
[Export(typeof(ArchiveFormat))]
|
||||||
|
public class AOpener : ArchiveFormat
|
||||||
|
{
|
||||||
|
public override string Tag { get { return "A/Leaf"; } }
|
||||||
|
public override string Description { get { return "Leaf resource archive"; } }
|
||||||
|
public override uint Signature { get { return 0; } }
|
||||||
|
public override bool IsHierarchic { get { return false; } }
|
||||||
|
public override bool CanCreate { get { return false; } }
|
||||||
|
|
||||||
|
public AOpener ()
|
||||||
|
{
|
||||||
|
Extensions = new string[] { "a" };
|
||||||
|
}
|
||||||
|
|
||||||
|
public override ArcFile TryOpen (ArcView file)
|
||||||
|
{
|
||||||
|
if (0xAF1E != file.View.ReadUInt16 (0))
|
||||||
|
return null;
|
||||||
|
int count = file.View.ReadUInt16 (2);
|
||||||
|
if (!IsSaneCount (count))
|
||||||
|
return null;
|
||||||
|
|
||||||
|
long base_offset = 4 + 0x20 * count;
|
||||||
|
uint index_offset = 4;
|
||||||
|
var dir = new List<Entry> (count);
|
||||||
|
for (int i = 0; i < count; ++i)
|
||||||
|
{
|
||||||
|
var name = file.View.ReadString (index_offset, 0x17);
|
||||||
|
if (string.IsNullOrEmpty (name))
|
||||||
|
return null;
|
||||||
|
var entry = FormatCatalog.Instance.Create<PackedEntry> (name);
|
||||||
|
entry.IsPacked = 0 != file.View.ReadByte (index_offset+0x17);
|
||||||
|
entry.Size = file.View.ReadUInt32 (index_offset+0x18);
|
||||||
|
entry.Offset = base_offset + file.View.ReadUInt32 (index_offset+0x1C);
|
||||||
|
if (!entry.CheckPlacement (file.MaxOffset))
|
||||||
|
return null;
|
||||||
|
dir.Add (entry);
|
||||||
|
index_offset += 0x20;
|
||||||
|
}
|
||||||
|
return new ArcFile (file, this, dir);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override Stream OpenEntry (ArcFile arc, Entry entry)
|
||||||
|
{
|
||||||
|
var pent = entry as PackedEntry;
|
||||||
|
if (null == pent || !pent.IsPacked)
|
||||||
|
return base.OpenEntry (arc, entry);
|
||||||
|
if (0 == pent.UnpackedSize)
|
||||||
|
pent.UnpackedSize = arc.File.View.ReadUInt32 (entry.Offset);
|
||||||
|
var input = arc.File.CreateStream (entry.Offset+4, entry.Size-4);
|
||||||
|
return new LzssStream (input);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
130
ArcFormats/Leaf/ArcAM.cs
Normal file
130
ArcFormats/Leaf/ArcAM.cs
Normal file
@ -0,0 +1,130 @@
|
|||||||
|
//! \file ArcAM.cs
|
||||||
|
//! \date Wed Aug 17 18:31:08 2016
|
||||||
|
//! \brief Leaf video resources archive.
|
||||||
|
//
|
||||||
|
// Copyright (C) 2016 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
|
||||||
|
// deal in the Software without restriction, including without limitation the
|
||||||
|
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||||
|
// sell copies of the Software, and to permit persons to whom the Software is
|
||||||
|
// furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in
|
||||||
|
// all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||||
|
// IN THE SOFTWARE.
|
||||||
|
//
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.ComponentModel.Composition;
|
||||||
|
using System.IO;
|
||||||
|
using GameRes.Utility;
|
||||||
|
|
||||||
|
namespace GameRes.Formats.Leaf
|
||||||
|
{
|
||||||
|
[Export(typeof(ArchiveFormat))]
|
||||||
|
public class AmOpener : ArchiveFormat
|
||||||
|
{
|
||||||
|
public override string Tag { get { return "AM/Leaf"; } }
|
||||||
|
public override string Description { get { return "Leaf video resources archive"; } }
|
||||||
|
public override uint Signature { get { return 0x30306D61; } } // 'am00'
|
||||||
|
public override bool IsHierarchic { get { return false; } }
|
||||||
|
public override bool CanCreate { get { return false; } }
|
||||||
|
|
||||||
|
public AmOpener ()
|
||||||
|
{
|
||||||
|
Extensions = new string[] { "am" };
|
||||||
|
}
|
||||||
|
|
||||||
|
public override ArcFile TryOpen (ArcView file)
|
||||||
|
{
|
||||||
|
uint index_size = file.View.ReadUInt32 (4);
|
||||||
|
byte key = file.View.ReadByte (8);
|
||||||
|
var index = file.View.ReadBytes (9, index_size);
|
||||||
|
if (index.Length != index_size)
|
||||||
|
return null;
|
||||||
|
for (int i = 0; i < index.Length; ++i)
|
||||||
|
index[i] ^= key;
|
||||||
|
|
||||||
|
uint base_offset = 9 + index_size;
|
||||||
|
int index_offset = 0;
|
||||||
|
var dir = new List<Entry>();
|
||||||
|
while (index_offset < index.Length)
|
||||||
|
{
|
||||||
|
int name_end = Array.IndexOf<byte> (index, 0, index_offset);
|
||||||
|
if (-1 == name_end || name_end == index_offset)
|
||||||
|
return null;
|
||||||
|
var name = Encodings.cp932.GetString (index, index_offset, name_end-index_offset);
|
||||||
|
index_offset = name_end+1;
|
||||||
|
var entry = FormatCatalog.Instance.Create<Entry> (name);
|
||||||
|
entry.Offset = base_offset + LittleEndian.ToUInt32 (index, index_offset);
|
||||||
|
entry.Size = LittleEndian.ToUInt32 (index, index_offset+4);
|
||||||
|
if (!entry.CheckPlacement (file.MaxOffset))
|
||||||
|
return null;
|
||||||
|
dir.Add (entry);
|
||||||
|
index_offset += 8;
|
||||||
|
}
|
||||||
|
return new ArcFile (file, this, dir);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override Stream OpenEntry (ArcFile arc, Entry entry)
|
||||||
|
{
|
||||||
|
var input = arc.File.CreateStream (entry.Offset, entry.Size);
|
||||||
|
if (null == DecryptTable)
|
||||||
|
return input;
|
||||||
|
return new AmStream (input, DecryptTable);
|
||||||
|
}
|
||||||
|
|
||||||
|
static byte[] DecryptTable = null;
|
||||||
|
|
||||||
|
public override ResourceScheme Scheme
|
||||||
|
{
|
||||||
|
get { return new AmScheme { DecryptTable = DecryptTable }; }
|
||||||
|
set { DecryptTable = ((AmScheme)value).DecryptTable; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal class AmStream : InputProxyStream
|
||||||
|
{
|
||||||
|
byte[] m_table;
|
||||||
|
|
||||||
|
public AmStream (Stream input, byte[] table) : base (input)
|
||||||
|
{
|
||||||
|
m_table = table;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override int Read (byte[] buffer, int offset, int count)
|
||||||
|
{
|
||||||
|
int pos = (int)Position;
|
||||||
|
int read = BaseStream.Read (buffer, offset, count);
|
||||||
|
for (int i = 0; i < read; ++i)
|
||||||
|
{
|
||||||
|
buffer[offset+i] ^= m_table[(pos+i) & 0xFFFF];
|
||||||
|
}
|
||||||
|
return read;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override int ReadByte ()
|
||||||
|
{
|
||||||
|
int b = BaseStream.ReadByte();
|
||||||
|
if (-1 != b)
|
||||||
|
b ^= m_table[(Position-1) & 0xFFFF];
|
||||||
|
return b;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Serializable]
|
||||||
|
public class AmScheme : ResourceScheme
|
||||||
|
{
|
||||||
|
public byte[] DecryptTable;
|
||||||
|
}
|
||||||
|
}
|
81
ArcFormats/Leaf/ArcLAC.cs
Normal file
81
ArcFormats/Leaf/ArcLAC.cs
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
//! \file ArcLAC.cs
|
||||||
|
//! \date Wed Aug 17 15:59:38 2016
|
||||||
|
//! \brief Leaf resource archive.
|
||||||
|
//
|
||||||
|
// Copyright (C) 2016 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
|
||||||
|
// deal in the Software without restriction, including without limitation the
|
||||||
|
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||||
|
// sell copies of the Software, and to permit persons to whom the Software is
|
||||||
|
// furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in
|
||||||
|
// all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||||
|
// IN THE SOFTWARE.
|
||||||
|
//
|
||||||
|
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.ComponentModel.Composition;
|
||||||
|
using System.IO;
|
||||||
|
using GameRes.Compression;
|
||||||
|
|
||||||
|
namespace GameRes.Formats.Leaf
|
||||||
|
{
|
||||||
|
[Export(typeof(ArchiveFormat))]
|
||||||
|
public class LacOpener : ArchiveFormat
|
||||||
|
{
|
||||||
|
public override string Tag { get { return "LAC"; } }
|
||||||
|
public override string Description { get { return "Leaf resource archive"; } }
|
||||||
|
public override uint Signature { get { return 0x43414C; } } // 'LAC'
|
||||||
|
public override bool IsHierarchic { get { return false; } }
|
||||||
|
public override bool CanCreate { get { return false; } }
|
||||||
|
|
||||||
|
public override ArcFile TryOpen (ArcView file)
|
||||||
|
{
|
||||||
|
int count = file.View.ReadInt32 (4);
|
||||||
|
if (!IsSaneCount (count))
|
||||||
|
return null;
|
||||||
|
|
||||||
|
uint index_offset = 8;
|
||||||
|
var dir = new List<Entry> (count);
|
||||||
|
for (int i = 0; i < count; ++i)
|
||||||
|
{
|
||||||
|
var name = file.View.ReadString (index_offset, 0x3E);
|
||||||
|
if (string.IsNullOrEmpty (name))
|
||||||
|
return null;
|
||||||
|
index_offset += 0x3E;
|
||||||
|
var entry = FormatCatalog.Instance.Create<PackedEntry> (name);
|
||||||
|
entry.IsPacked = 0 != file.View.ReadByte (index_offset);
|
||||||
|
index_offset += 0xE;
|
||||||
|
entry.Size = file.View.ReadUInt32 (index_offset);
|
||||||
|
entry.UnpackedSize = file.View.ReadUInt32 (index_offset+4);
|
||||||
|
entry.Offset = file.View.ReadInt64 (index_offset+0xC);
|
||||||
|
index_offset += 0x2C;
|
||||||
|
if (!entry.CheckPlacement (file.MaxOffset))
|
||||||
|
return null;
|
||||||
|
dir.Add (entry);
|
||||||
|
}
|
||||||
|
return new ArcFile (file, this, dir);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override Stream OpenEntry (ArcFile arc, Entry entry)
|
||||||
|
{
|
||||||
|
var input = base.OpenEntry (arc, entry);
|
||||||
|
var pent = entry as PackedEntry;
|
||||||
|
if (null == pent || !pent.IsPacked)
|
||||||
|
return input;
|
||||||
|
var lzs = new LzssStream (input);
|
||||||
|
lzs.Config.FrameFill = 0x20;
|
||||||
|
return lzs;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
269
ArcFormats/Leaf/AudioG.cs
Normal file
269
ArcFormats/Leaf/AudioG.cs
Normal file
@ -0,0 +1,269 @@
|
|||||||
|
//! \file AudioG.cs
|
||||||
|
//! \date Thu Aug 18 15:50:27 2016
|
||||||
|
//! \brief Leaf audio format.
|
||||||
|
//
|
||||||
|
// Copyright (C) 2016 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
|
||||||
|
// deal in the Software without restriction, including without limitation the
|
||||||
|
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||||
|
// sell copies of the Software, and to permit persons to whom the Software is
|
||||||
|
// furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in
|
||||||
|
// all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||||
|
// IN THE SOFTWARE.
|
||||||
|
//
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.ComponentModel.Composition;
|
||||||
|
using System.IO;
|
||||||
|
using GameRes.Utility;
|
||||||
|
|
||||||
|
namespace GameRes.Formats.Leaf
|
||||||
|
{
|
||||||
|
[Export(typeof(AudioFormat))]
|
||||||
|
public class GAudio : AudioFormat
|
||||||
|
{
|
||||||
|
public override string Tag { get { return "G/Leaf"; } }
|
||||||
|
public override string Description { get { return "Leaf audio format (Ogg/Vorbis)"; } }
|
||||||
|
public override uint Signature { get { return 0; } }
|
||||||
|
|
||||||
|
public GAudio ()
|
||||||
|
{
|
||||||
|
Extensions = new string[] { "g" };
|
||||||
|
}
|
||||||
|
|
||||||
|
public override SoundInput TryOpen (Stream file)
|
||||||
|
{
|
||||||
|
var header = new byte[0x1C];
|
||||||
|
if (header.Length != file.Read (header, 0, header.Length))
|
||||||
|
return null;
|
||||||
|
if (header[4] != 0 || header[5] != 2 || LittleEndian.ToInt64 (header, 6) != 0)
|
||||||
|
return null;
|
||||||
|
file.Position = 0;
|
||||||
|
var input = new GStream (file);
|
||||||
|
return new OggInput (new SeekableStream (input));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal class GStream : InputProxyStream
|
||||||
|
{
|
||||||
|
IEnumerator<int> m_pages;
|
||||||
|
bool m_eof;
|
||||||
|
|
||||||
|
byte[] m_page = new byte[0x10000];
|
||||||
|
int m_page_pos = 0;
|
||||||
|
int m_page_length = 0;
|
||||||
|
|
||||||
|
public GStream (Stream source) : base (source)
|
||||||
|
{
|
||||||
|
m_pages = EnumeratePages();
|
||||||
|
m_eof = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
#region IO.Stream methods
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
public override int Read (byte[] buffer, int offset, int count)
|
||||||
|
{
|
||||||
|
int total_read = 0;
|
||||||
|
while (count > 0 && !m_eof)
|
||||||
|
{
|
||||||
|
if (m_page_pos == m_page_length)
|
||||||
|
{
|
||||||
|
NextPage();
|
||||||
|
}
|
||||||
|
if (m_eof)
|
||||||
|
break;
|
||||||
|
int available = Math.Min (m_page_length - m_page_pos, count);
|
||||||
|
Buffer.BlockCopy (m_page, m_page_pos, buffer, offset, available);
|
||||||
|
m_page_pos += available;
|
||||||
|
offset += available;
|
||||||
|
count -= available;
|
||||||
|
total_read += available;
|
||||||
|
}
|
||||||
|
return total_read;
|
||||||
|
}
|
||||||
|
|
||||||
|
void NextPage ()
|
||||||
|
{
|
||||||
|
m_eof = !m_pages.MoveNext();
|
||||||
|
m_page_pos = 0;
|
||||||
|
m_page_length = !m_eof ? m_pages.Current : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
enum State
|
||||||
|
{
|
||||||
|
Header,
|
||||||
|
Comment,
|
||||||
|
Setup,
|
||||||
|
Payload,
|
||||||
|
Broken,
|
||||||
|
};
|
||||||
|
|
||||||
|
IEnumerator<int> EnumeratePages ()
|
||||||
|
{
|
||||||
|
var state = State.Header;
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
int page_length = 0x1B;
|
||||||
|
int read = BaseStream.Read (m_page, 0, page_length);
|
||||||
|
if (read < page_length)
|
||||||
|
{
|
||||||
|
if (read != 0)
|
||||||
|
yield return read;
|
||||||
|
yield break;
|
||||||
|
}
|
||||||
|
PutString (0, "OggS");
|
||||||
|
int segment_count = m_page[0x1A];
|
||||||
|
if (0 == segment_count)
|
||||||
|
{
|
||||||
|
UpdateCrc (page_length);
|
||||||
|
yield return page_length;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
read = BaseStream.Read (m_page, page_length, segment_count);
|
||||||
|
page_length += read;
|
||||||
|
if (read < segment_count)
|
||||||
|
{
|
||||||
|
UpdateCrc (page_length);
|
||||||
|
yield return page_length;
|
||||||
|
yield break;
|
||||||
|
}
|
||||||
|
int segments_size = 0;
|
||||||
|
for (int i = 0; i < segment_count; ++i)
|
||||||
|
{
|
||||||
|
segments_size += m_page[0x1B+i];
|
||||||
|
}
|
||||||
|
int id, next;
|
||||||
|
switch (state)
|
||||||
|
{
|
||||||
|
case State.Header:
|
||||||
|
id = BaseStream.ReadByte();
|
||||||
|
if (-1 == id)
|
||||||
|
break;
|
||||||
|
|
||||||
|
m_page[page_length++] = (byte)id;
|
||||||
|
next = BaseStream.ReadByte();
|
||||||
|
segments_size -= 2;
|
||||||
|
if (1 == id)
|
||||||
|
{
|
||||||
|
PutString (page_length, "vorbis");
|
||||||
|
page_length += 6;
|
||||||
|
m_page[0x1B] += 5;
|
||||||
|
state = State.Comment;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_page[page_length++] = (byte)next;
|
||||||
|
state = State.Broken;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case State.Comment:
|
||||||
|
id = BaseStream.ReadByte();
|
||||||
|
if (-1 == id)
|
||||||
|
break;
|
||||||
|
|
||||||
|
m_page[page_length++] = (byte)id;
|
||||||
|
next = BaseStream.ReadByte();
|
||||||
|
segments_size -= 2;
|
||||||
|
if (3 == id)
|
||||||
|
{
|
||||||
|
PutString (page_length, "vorbis");
|
||||||
|
page_length += 6;
|
||||||
|
read = BaseStream.Read (m_page, page_length, m_page[0x1B]-2);
|
||||||
|
page_length += read;
|
||||||
|
segments_size -= read;
|
||||||
|
m_page[0x1B] += 5;
|
||||||
|
state = State.Setup;
|
||||||
|
if (segments_size > 0)
|
||||||
|
goto case State.Setup;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_page[page_length++] = (byte)next;
|
||||||
|
state = State.Broken;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case State.Setup:
|
||||||
|
id = BaseStream.ReadByte();
|
||||||
|
if (-1 == id)
|
||||||
|
break;
|
||||||
|
|
||||||
|
m_page[page_length++] = (byte)id;
|
||||||
|
next = BaseStream.ReadByte();
|
||||||
|
segments_size -= 2;
|
||||||
|
if (5 == id)
|
||||||
|
{
|
||||||
|
PutString (page_length, "vorbis");
|
||||||
|
page_length += 6;
|
||||||
|
m_page[0x1B+segment_count-1] += 5;
|
||||||
|
state = State.Payload;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_page[page_length++] = (byte)next;
|
||||||
|
state = State.Broken;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
read = BaseStream.Read (m_page, page_length, segments_size);
|
||||||
|
page_length += read;
|
||||||
|
UpdateCrc (page_length);
|
||||||
|
yield return page_length;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void PutString (int pos, string s)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < s.Length; ++i)
|
||||||
|
m_page[pos+i] = (byte)s[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
void UpdateCrc (int page_length)
|
||||||
|
{
|
||||||
|
LittleEndian.Pack (0, m_page, 0x16);
|
||||||
|
uint crc = Crc32Normal.UpdateCrc (0, m_page, 0, page_length);
|
||||||
|
LittleEndian.Pack (crc, m_page, 0x16);
|
||||||
|
}
|
||||||
|
|
||||||
|
#region IDisposable Members
|
||||||
|
bool _g_disposed = false;
|
||||||
|
protected override void Dispose (bool disposing)
|
||||||
|
{
|
||||||
|
if (_g_disposed)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (disposing)
|
||||||
|
{
|
||||||
|
m_pages.Dispose();
|
||||||
|
}
|
||||||
|
_g_disposed = true;
|
||||||
|
base.Dispose (disposing);
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
}
|
68
ArcFormats/Leaf/AudioW.cs
Normal file
68
ArcFormats/Leaf/AudioW.cs
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
//! \file AudioW.cs
|
||||||
|
//! \date Thu Aug 18 06:04:50 2016
|
||||||
|
//! \brief Leaf PCM audio.
|
||||||
|
//
|
||||||
|
// Copyright (C) 2016 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
|
||||||
|
// deal in the Software without restriction, including without limitation the
|
||||||
|
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||||
|
// sell copies of the Software, and to permit persons to whom the Software is
|
||||||
|
// furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in
|
||||||
|
// all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||||
|
// IN THE SOFTWARE.
|
||||||
|
//
|
||||||
|
|
||||||
|
using System.ComponentModel.Composition;
|
||||||
|
using System.IO;
|
||||||
|
using GameRes.Utility;
|
||||||
|
|
||||||
|
namespace GameRes.Formats.Leaf
|
||||||
|
{
|
||||||
|
[Export(typeof(AudioFormat))]
|
||||||
|
public class WAudio : AudioFormat
|
||||||
|
{
|
||||||
|
public override string Tag { get { return "W/Leaf"; } }
|
||||||
|
public override string Description { get { return "Leaf PCM audio"; } }
|
||||||
|
public override uint Signature { get { return 0; } }
|
||||||
|
|
||||||
|
public WAudio ()
|
||||||
|
{
|
||||||
|
Extensions = new string[] { "w" };
|
||||||
|
}
|
||||||
|
|
||||||
|
public override SoundInput TryOpen (Stream file)
|
||||||
|
{
|
||||||
|
var header = new byte[0x12];
|
||||||
|
if (header.Length != file.Read (header, 0, header.Length))
|
||||||
|
return null;
|
||||||
|
var format = new WaveFormat
|
||||||
|
{
|
||||||
|
FormatTag = 1,
|
||||||
|
Channels = header[0],
|
||||||
|
SamplesPerSecond = LittleEndian.ToUInt16 (header, 2),
|
||||||
|
AverageBytesPerSecond = LittleEndian.ToUInt32 (header, 6),
|
||||||
|
BlockAlign = header[1],
|
||||||
|
BitsPerSample = LittleEndian.ToUInt16 (header, 4),
|
||||||
|
};
|
||||||
|
uint pcm_size = LittleEndian.ToUInt32 (header, 0xA);
|
||||||
|
if (0 == pcm_size || 0 == format.AverageBytesPerSecond || format.BitsPerSample < 8
|
||||||
|
|| 0 == format.Channels || format.Channels > 8
|
||||||
|
|| (format.BlockAlign * format.SamplesPerSecond != format.AverageBytesPerSecond)
|
||||||
|
|| (pcm_size + 0x12 != file.Length))
|
||||||
|
return null;
|
||||||
|
var pcm = new StreamRegion (file, 0x12, pcm_size);
|
||||||
|
return new RawPcmInput (pcm, format);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
217
ArcFormats/Leaf/ImagePX.cs
Normal file
217
ArcFormats/Leaf/ImagePX.cs
Normal file
@ -0,0 +1,217 @@
|
|||||||
|
//! \file ImagePX.cs
|
||||||
|
//! \date Thu Aug 18 05:35:34 2016
|
||||||
|
//! \brief Leaf image format.
|
||||||
|
//
|
||||||
|
// Copyright (C) 2016 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
|
||||||
|
// deal in the Software without restriction, including without limitation the
|
||||||
|
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||||
|
// sell copies of the Software, and to permit persons to whom the Software is
|
||||||
|
// furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in
|
||||||
|
// all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||||
|
// IN THE SOFTWARE.
|
||||||
|
//
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.ComponentModel.Composition;
|
||||||
|
using System.IO;
|
||||||
|
using System.Windows.Media;
|
||||||
|
using GameRes.Utility;
|
||||||
|
|
||||||
|
namespace GameRes.Formats.Leaf
|
||||||
|
{
|
||||||
|
internal class PxMetaData : ImageMetaData
|
||||||
|
{
|
||||||
|
public int Type;
|
||||||
|
public int FrameCount;
|
||||||
|
public int BlockSize;
|
||||||
|
public int BlocksWidth;
|
||||||
|
public int BlocksHeight;
|
||||||
|
}
|
||||||
|
|
||||||
|
// XXX this format changes significantly from game to game
|
||||||
|
|
||||||
|
[Export(typeof(ImageFormat))]
|
||||||
|
public class PxFormat : ImageFormat
|
||||||
|
{
|
||||||
|
public override string Tag { get { return "PX"; } }
|
||||||
|
public override string Description { get { return "Leaf image format"; } }
|
||||||
|
public override uint Signature { get { return 0; } }
|
||||||
|
|
||||||
|
public override ImageMetaData ReadMetaData (Stream stream)
|
||||||
|
{
|
||||||
|
var header = new byte[0x20];
|
||||||
|
if (header.Length != stream.Read (header, 0, header.Length))
|
||||||
|
return null;
|
||||||
|
int type = LittleEndian.ToUInt16 (header, 0x10);
|
||||||
|
if (0x0C == type)
|
||||||
|
{
|
||||||
|
int count = LittleEndian.ToInt32 (header, 0);
|
||||||
|
if (!ArchiveFormat.IsSaneCount (count))
|
||||||
|
return null;
|
||||||
|
int block_size = LittleEndian.ToInt32 (header, 4);
|
||||||
|
if (block_size <= 0)
|
||||||
|
return null;
|
||||||
|
int bpp = LittleEndian.ToUInt16 (header, 0x12);
|
||||||
|
uint width = LittleEndian.ToUInt16 (header, 0x14);
|
||||||
|
uint height = LittleEndian.ToUInt16 (header, 0x16);
|
||||||
|
if (bpp != 32 || 0 == width || 0 == height)
|
||||||
|
return null;
|
||||||
|
return new PxMetaData
|
||||||
|
{
|
||||||
|
Width = width,
|
||||||
|
Height = height,
|
||||||
|
BPP = bpp,
|
||||||
|
Type = type,
|
||||||
|
FrameCount = count,
|
||||||
|
BlockSize = block_size,
|
||||||
|
BlocksWidth = LittleEndian.ToUInt16 (header, 0x1C),
|
||||||
|
BlocksHeight = LittleEndian.ToUInt16 (header, 0x1E),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
else if (0x80 == type || 0x90 == type)
|
||||||
|
{
|
||||||
|
if (!Binary.AsciiEqual (header, 0x14, "Leaf"))
|
||||||
|
return null;
|
||||||
|
int count = LittleEndian.ToInt32 (header, 4);
|
||||||
|
if (!ArchiveFormat.IsSaneCount (count))
|
||||||
|
return null;
|
||||||
|
if (0x20 != stream.Read (header, 0, 0x20))
|
||||||
|
return null;
|
||||||
|
if (0x0A != LittleEndian.ToUInt16 (header, 0x10))
|
||||||
|
return null;
|
||||||
|
return new PxMetaData
|
||||||
|
{
|
||||||
|
Width = LittleEndian.ToUInt32 (header, 0),
|
||||||
|
Height = LittleEndian.ToUInt32 (header, 0),
|
||||||
|
BPP = LittleEndian.ToUInt16 (header, 0x12),
|
||||||
|
Type = type,
|
||||||
|
FrameCount = count,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override ImageData Read (Stream stream, ImageMetaData info)
|
||||||
|
{
|
||||||
|
using (var reader = new PxReader (stream, (PxMetaData)info))
|
||||||
|
{
|
||||||
|
var pixels = reader.Unpack();
|
||||||
|
return ImageData.Create (info, reader.Format, null, pixels, reader.Stride);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Write (Stream file, ImageData image)
|
||||||
|
{
|
||||||
|
throw new System.NotImplementedException ("PxFormat.Write not implemented");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal sealed class PxReader : IDisposable
|
||||||
|
{
|
||||||
|
BinaryReader m_input;
|
||||||
|
PxMetaData m_info;
|
||||||
|
byte[] m_output;
|
||||||
|
int m_pixel_size;
|
||||||
|
int m_stride;
|
||||||
|
|
||||||
|
public PixelFormat Format { get { return PixelFormats.Bgra32; } }
|
||||||
|
public byte[] Data { get { return m_output; } }
|
||||||
|
public int Stride { get { return m_stride; } }
|
||||||
|
public int FrameCount { get { return m_info.FrameCount; } }
|
||||||
|
|
||||||
|
public PxReader (Stream input, PxMetaData info)
|
||||||
|
{
|
||||||
|
m_input = new ArcView.Reader (input);
|
||||||
|
m_info = info;
|
||||||
|
m_pixel_size = m_info.BPP / 8;
|
||||||
|
m_stride = (int)m_info.Width * m_pixel_size;
|
||||||
|
m_output = new byte[m_stride * (int)m_info.Height];
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte[] Unpack (int frame = 0)
|
||||||
|
{
|
||||||
|
if (frame < 0 || frame >= FrameCount)
|
||||||
|
throw new ArgumentException ("[PX] Invalid frame number", "frame");
|
||||||
|
switch (m_info.Type)
|
||||||
|
{
|
||||||
|
case 0x0C: Unpack0C (frame); break;
|
||||||
|
case 0x90: Unpack90 (frame); break;
|
||||||
|
case 0x80: Unpack80 (frame); break;
|
||||||
|
default: throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
return m_output;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Unpack0C (int frame)
|
||||||
|
{
|
||||||
|
var stream = m_input.BaseStream;
|
||||||
|
int block_count = m_info.BlocksWidth * m_info.BlocksHeight;
|
||||||
|
var block_table = new ushort[block_count];
|
||||||
|
stream.Position = 0x20 + frame * block_count * 2;
|
||||||
|
for (int i = 0; i < block_count; ++i)
|
||||||
|
block_table[i] = m_input.ReadUInt16();
|
||||||
|
int data_pos = 0x20 + FrameCount * block_count * 2;
|
||||||
|
int block_length = 2 + (m_info.BlockSize + 2) * (m_info.BlockSize + 2) * m_pixel_size;
|
||||||
|
int current_block = 0;
|
||||||
|
int dst_line = 0;
|
||||||
|
for (int by = 0; by < m_info.BlocksHeight; ++by)
|
||||||
|
{
|
||||||
|
for (int bx = 0; bx < m_info.BlocksWidth; ++bx)
|
||||||
|
{
|
||||||
|
int dst = dst_line + bx * m_info.BlockSize * m_pixel_size;
|
||||||
|
int block_num = block_table[current_block++];
|
||||||
|
if (block_num != 0)
|
||||||
|
{
|
||||||
|
stream.Position = data_pos + (block_num - 1) * block_length;
|
||||||
|
int block_width = m_input.ReadByte() - 2;
|
||||||
|
int block_height = m_input.ReadByte() - 2;
|
||||||
|
int line_length = block_width * m_pixel_size;
|
||||||
|
for (int y = 0; y < block_height; ++y)
|
||||||
|
{
|
||||||
|
m_input.Read (m_output, dst, line_length);
|
||||||
|
dst += m_stride;
|
||||||
|
stream.Seek (8, SeekOrigin.Current);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
dst_line += m_info.BlockSize * m_stride;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Unpack90 (int frame)
|
||||||
|
{
|
||||||
|
m_input.BaseStream.Position = 0x40 + frame * (0x20 + m_output.Length);
|
||||||
|
if (m_output.Length != m_input.Read (m_output, 0, m_output.Length))
|
||||||
|
throw new EndOfStreamException();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Unpack80 (int frame)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
#region IDisposable Members
|
||||||
|
bool _disposed = false;
|
||||||
|
public void Dispose ()
|
||||||
|
{
|
||||||
|
if (!_disposed)
|
||||||
|
{
|
||||||
|
m_input.Dispose();
|
||||||
|
_disposed = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
}
|
@ -89,6 +89,7 @@ Utatemeguri<br/>
|
|||||||
<tr class="odd"><td>*.pak<br/>*.dat</td><td><tt>PACKDAT.</tt></td><td>No</td><td>SYSTEM-ε</td><td>
|
<tr class="odd"><td>*.pak<br/>*.dat</td><td><tt>PACKDAT.</tt></td><td>No</td><td>SYSTEM-ε</td><td>
|
||||||
Aoiro Rinne<br/>
|
Aoiro Rinne<br/>
|
||||||
Cartagra<br/>
|
Cartagra<br/>
|
||||||
|
Houkago no Senpai<br/>
|
||||||
PP -Pianissimo-<br/>
|
PP -Pianissimo-<br/>
|
||||||
Ryoujoku Guerilla Gari 3<br/>
|
Ryoujoku Guerilla Gari 3<br/>
|
||||||
Nagomibako<br/>
|
Nagomibako<br/>
|
||||||
@ -1052,6 +1053,13 @@ Boku no Te no Naka no Rakuen<br/>
|
|||||||
<tr class="odd"><td>*.dat</td><td><tt>YOX</tt></td><td>No</td><td>Shelf</td><td>
|
<tr class="odd"><td>*.dat</td><td><tt>YOX</tt></td><td>No</td><td>Shelf</td><td>
|
||||||
Kagiroi ~Shaku Kei~<br/>
|
Kagiroi ~Shaku Kei~<br/>
|
||||||
</td></tr>
|
</td></tr>
|
||||||
|
<tr><td>*.lac</td><td><tt>LAC</tt></td><td>No</td><td rowspan="5">Leaf</td><td rowspan="5">
|
||||||
|
ToHeart2 AnotherDays<br/>
|
||||||
|
</td></tr>
|
||||||
|
<tr><td>*.a</td><td><tt>\x1E\xAF</tt></td><td>No</td></tr>
|
||||||
|
<tr><td>*.am</td><td><tt>am00</tt></td><td>No</td></tr>
|
||||||
|
<tr><td>*.g</td><td>-</td><td>No</td></tr>
|
||||||
|
<tr><td>*.w</td><td>-</td><td>No</td></tr>
|
||||||
</table>
|
</table>
|
||||||
<p><a name="note-1" class="footnote">1</a> Non-encrypted only</p>
|
<p><a name="note-1" class="footnote">1</a> Non-encrypted only</p>
|
||||||
</body>
|
</body>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user