mirror of
https://github.com/crskycode/GARbro.git
synced 2024-11-23 05:35:34 +08:00
Merge remote-tracking branch 'upstream/master'
This commit is contained in:
commit
8b4fc93fbe
@ -63,6 +63,7 @@
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Buffers, Version=4.0.3.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\System.Buffers.4.5.1\lib\net461\System.Buffers.dll</HintPath>
|
||||
<HintPath>..\packages\System.Buffers.4.5.1\lib\netstandard1.1\System.Buffers.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.ComponentModel.Composition" />
|
||||
<Reference Include="System.Core" />
|
||||
@ -92,6 +93,15 @@
|
||||
</Reference>
|
||||
<Reference Include="System.ValueTuple, Version=4.0.3.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\System.ValueTuple.4.5.0\lib\net461\System.ValueTuple.dll</HintPath>
|
||||
<Reference Include="System.Memory, Version=4.0.1.1, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\System.Memory.4.5.4\lib\netstandard1.1\System.Memory.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Numerics" />
|
||||
<Reference Include="System.Runtime.CompilerServices.Unsafe, Version=4.0.5.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\System.Runtime.CompilerServices.Unsafe.4.6.0\lib\netstandard1.0\System.Runtime.CompilerServices.Unsafe.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.ValueTuple, Version=4.0.3.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\System.ValueTuple.4.5.0\lib\netstandard1.0\System.ValueTuple.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Xaml" />
|
||||
<Reference Include="System.Xml.Linq" />
|
||||
@ -120,6 +130,8 @@
|
||||
<Compile Include="AdvSys\ImageGWD.cs" />
|
||||
<Compile Include="Ail\ArcLNK2.cs" />
|
||||
<Compile Include="BlueGale\ImageBBM.cs" />
|
||||
<Compile Include="Hypatia\ArcLPK.cs" />
|
||||
<Compile Include="Hypatia\ImageLSG.cs" />
|
||||
<Compile Include="JamCreation\ArcDAT.cs" />
|
||||
<Compile Include="JamCreation\ImageDPO.cs" />
|
||||
<Compile Include="AliceSoft\ArcAAR.cs" />
|
||||
@ -226,6 +238,7 @@
|
||||
<Compile Include="Ivory\ArcSG.cs" />
|
||||
<Compile Include="Kaguya\ArcPL00.cs" />
|
||||
<Compile Include="Kaguya\ArcPL10.cs" />
|
||||
<Compile Include="Kaguya\ArcPLT.cs" />
|
||||
<Compile Include="Key\ArcPAK.cs" />
|
||||
<Compile Include="Key\AudioOGGPAK.cs" />
|
||||
<Compile Include="Key\ImageCZ.cs" />
|
||||
@ -324,6 +337,7 @@
|
||||
<Compile Include="Qlie\DelphiDeserializer.cs" />
|
||||
<Compile Include="Qlie\Encryption.cs" />
|
||||
<Compile Include="Qlie\ImageABMP.cs" />
|
||||
<Compile Include="Qlie\ImageARGB.cs" />
|
||||
<Compile Include="RealLive\ArcKOE.cs" />
|
||||
<Compile Include="RealLive\ArcSEEN.cs" />
|
||||
<Compile Include="RealLive\ImageG00Jpeg.cs" />
|
||||
@ -336,6 +350,7 @@
|
||||
<Compile Include="ScenePlayer\ArcPMX.cs" />
|
||||
<Compile Include="Scoop\ArcGX.cs" />
|
||||
<Compile Include="Scoop\ImageSCP.cs" />
|
||||
<Compile Include="Seraphim\ArcArchAngel.cs" />
|
||||
<Compile Include="Seraphim\ArcCP3.cs" />
|
||||
<Compile Include="Seraphim\ArcMC.cs" />
|
||||
<Compile Include="Seraphim\ArcSCN.cs" />
|
||||
@ -652,6 +667,7 @@
|
||||
<Compile Include="TanukiSoft\ArcTAC.cs" />
|
||||
<Compile Include="TanukiSoft\ImageAF.cs" />
|
||||
<Compile Include="Taskforce\ArcDAT.cs" />
|
||||
<Compile Include="TechnoBrain\ArcIPQ.cs" />
|
||||
<Compile Include="TechnoBrain\AudioWAPE.cs" />
|
||||
<Compile Include="TechnoBrain\ImageIPF.cs" />
|
||||
<Compile Include="TechnoBrain\ImageIPH.cs" />
|
||||
@ -792,12 +808,14 @@
|
||||
<Compile Include="BlackCyc\ArcVPK.cs" />
|
||||
<Compile Include="Unity\ArcASSET.cs" />
|
||||
<Compile Include="Unity\ArcBIN.cs" />
|
||||
<Compile Include="Unity\ArcDSM.cs" />
|
||||
<Compile Include="Unity\ArcSpVM.cs" />
|
||||
<Compile Include="Unity\ArcUnityFS.cs" />
|
||||
<Compile Include="Unity\Asset.cs" />
|
||||
<Compile Include="Unity\AssetReader.cs" />
|
||||
<Compile Include="Unity\AudioClip.cs" />
|
||||
<Compile Include="Unity\AudioFSB5.cs" />
|
||||
<Compile Include="Unity\Bc7Decoder.cs" />
|
||||
<Compile Include="Unity\BundleStream.cs" />
|
||||
<None Include="packages.config" />
|
||||
<None Include="Unity\Gx4Lib\ArcDAT.cs" />
|
||||
|
@ -40,13 +40,13 @@ namespace GameRes.Formats
|
||||
{
|
||||
get
|
||||
{
|
||||
return (long)(m_reader.DecodedTime.TotalSeconds * m_reader.SampleRate * m_reader.Channels * sizeof(float));
|
||||
return (long)(m_reader.TimePosition.TotalSeconds * m_reader.SampleRate * m_reader.Channels * sizeof(float));
|
||||
}
|
||||
set
|
||||
{
|
||||
if (value < 0 || value > Length) throw new ArgumentOutOfRangeException("value");
|
||||
|
||||
m_reader.DecodedTime = TimeSpan.FromSeconds((double)value / m_reader.SampleRate / m_reader.Channels / sizeof(float));
|
||||
m_reader.TimePosition = TimeSpan.FromSeconds((double)value / m_reader.SampleRate / m_reader.Channels / sizeof(float));
|
||||
}
|
||||
}
|
||||
|
||||
@ -75,7 +75,7 @@ namespace GameRes.Formats
|
||||
|
||||
public override void Reset ()
|
||||
{
|
||||
m_reader.DecodedTime = TimeSpan.FromSeconds (0);
|
||||
m_reader.TimePosition = TimeSpan.FromSeconds (0);
|
||||
}
|
||||
|
||||
// This buffer can be static because it can only be used by 1 instance per thread
|
||||
|
@ -205,7 +205,10 @@ namespace GameRes.Formats.Cyberworks
|
||||
string game_name = arc_name != "Arc06.dat" ? TryParseMeta (VFS.CombinePath (dir_name, "Arc06.dat")) : null;
|
||||
Tuple<string, int> parsed = null;
|
||||
if (string.IsNullOrEmpty (game_name))
|
||||
{
|
||||
game_name = TryParseMeta (VFS.CombinePath (dir_name, "Arc00.dat"));
|
||||
parsed = s_name_parsers.Select (p => p.ParseName (arc_name)).FirstOrDefault (p => p != null);
|
||||
}
|
||||
else // Shukujo no Tsuyagoto special case
|
||||
parsed = OldDatOpener.ArcNameParser.ParseName (arc_name);
|
||||
if (null == parsed)
|
||||
@ -217,7 +220,7 @@ namespace GameRes.Formats.Cyberworks
|
||||
var toc = ReadToc (toc_name, 8);
|
||||
if (null == toc)
|
||||
return null;
|
||||
using (var index = new ArcIndexReader (toc, file, arc_idx))
|
||||
using (var index = new ArcIndexReader (toc, file, arc_idx, game_name))
|
||||
{
|
||||
if (!index.Read())
|
||||
return null;
|
||||
@ -311,10 +314,8 @@ namespace GameRes.Formats.Cyberworks
|
||||
if ('c' == type || 'b' == type)
|
||||
{
|
||||
uint img_size = Binary.BigEndian (input.ReadUInt32());
|
||||
if (input.Length - 5 == img_size)
|
||||
{
|
||||
input = BinaryStream.FromStream (new StreamRegion (input.AsStream, 5, img_size), input.Name);
|
||||
}
|
||||
long start_pos = input.Length - img_size;
|
||||
input = BinaryStream.FromStream (new StreamRegion (input.AsStream, start_pos, img_size), input.Name);
|
||||
}
|
||||
else if (scheme != null && ('a' == type || 'd' == type) && input.Length > 21)
|
||||
{
|
||||
@ -618,9 +619,13 @@ namespace GameRes.Formats.Cyberworks
|
||||
return true;
|
||||
}
|
||||
|
||||
uint m_fault_id = 100000;
|
||||
|
||||
internal PackedEntry ReadEntryInfo ()
|
||||
{
|
||||
uint id = m_index.ReadUInt32();
|
||||
if (id > m_fault_id)
|
||||
id = m_fault_id++;
|
||||
var entry = new PackedEntry { Name = id.ToString ("D6") };
|
||||
entry.UnpackedSize = m_index.ReadUInt32();
|
||||
entry.Size = m_index.ReadUInt32();
|
||||
@ -650,10 +655,14 @@ namespace GameRes.Formats.Cyberworks
|
||||
internal class ArcIndexReader : IndexReader
|
||||
{
|
||||
int m_arc_number;
|
||||
string m_game_name;
|
||||
bool m_ignore_b_files = false;
|
||||
|
||||
public ArcIndexReader (byte[] toc, ArcView file, int arc_number) : base (toc, file)
|
||||
public ArcIndexReader (byte[] toc, ArcView file, int arc_number, string game_name = null) : base (toc, file)
|
||||
{
|
||||
m_arc_number = arc_number;
|
||||
m_game_name = game_name;
|
||||
m_ignore_b_files = m_game_name == "ドキドキ母娘レッスン ~教えて♪Hなお勉強~";
|
||||
}
|
||||
|
||||
char[] m_type = new char[2];
|
||||
@ -677,7 +686,7 @@ namespace GameRes.Formats.Cyberworks
|
||||
ext = new string (m_type);
|
||||
else
|
||||
ext = new string (m_type[0], 1);
|
||||
if ("b0" == ext || "n0" == ext || "o0" == ext || "0b" == ext || "b" == ext)
|
||||
if ("b0" == ext || "n0" == ext || "o0" == ext || "0b" == ext || ("b" == ext && !m_ignore_b_files))
|
||||
{
|
||||
entry.Type = "image";
|
||||
HasImages = true;
|
||||
|
@ -2,7 +2,7 @@
|
||||
//! \date Fri Jun 17 18:49:04 2016
|
||||
//! \brief Tinker Bell encrypted image file.
|
||||
//
|
||||
// Copyright (C) 2016-2017 by morkt
|
||||
// Copyright (C) 2016-2022 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
|
||||
@ -28,6 +28,7 @@ using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Media.Imaging;
|
||||
using GameRes.Utility;
|
||||
|
||||
namespace GameRes.Formats.Cyberworks
|
||||
{
|
||||
@ -145,9 +146,17 @@ namespace GameRes.Formats.Cyberworks
|
||||
{
|
||||
var size_buf = new byte[4];
|
||||
input.Read (size_buf, 0 , 4);
|
||||
var decoder = new PngBitmapDecoder (input, BitmapCreateOptions.None,
|
||||
BitmapCacheOption.OnLoad);
|
||||
BitmapSource frame = decoder.Frames[0];
|
||||
int png_size = BigEndian.ToInt32 (size_buf, 0);
|
||||
BitmapSource frame;
|
||||
// work-around for possible extra padding before PNG data
|
||||
using (var membuf = new MemoryStream (png_size+4))
|
||||
{
|
||||
input.CopyTo (membuf);
|
||||
membuf.Seek (-png_size, SeekOrigin.End);
|
||||
var decoder = new PngBitmapDecoder (membuf, BitmapCreateOptions.None,
|
||||
BitmapCacheOption.OnLoad);
|
||||
frame = decoder.Frames[0];
|
||||
}
|
||||
Info.Width = (uint)frame.PixelWidth;
|
||||
Info.Height = (uint)frame.PixelHeight;
|
||||
if (frame.Format.BitsPerPixel != 32)
|
||||
|
@ -1,4 +1,4 @@
|
||||
// Copyright (C) 2019 by morkt
|
||||
// Copyright (C) 2022 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
|
||||
|
@ -1,4 +1,4 @@
|
||||
// Copyright (C) 2019 by morkt
|
||||
// Copyright (C) 2022 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
|
||||
|
@ -1,4 +1,4 @@
|
||||
// Copyright (C) 2019 by morkt
|
||||
// Copyright (C) 2022 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
|
||||
|
61
ArcFormats/Hypatia/ArcLPC.cs
Normal file
61
ArcFormats/Hypatia/ArcLPC.cs
Normal file
@ -0,0 +1,61 @@
|
||||
//! \file ArcLPC.cs
|
||||
//! \date 2019 Jan 15
|
||||
//! \brief Kogado Stduio multi-frame image.
|
||||
//
|
||||
// Copyright (C) 2019 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;
|
||||
|
||||
namespace GameRes.Formats.Kogado
|
||||
{
|
||||
[Export(typeof(ArchiveFormat))]
|
||||
public class LpcOpener : ArchiveFormat
|
||||
{
|
||||
public override string Tag { get { return "LPC"; } }
|
||||
public override string Description { get { return "Kogado Studio multi-frame image"; } }
|
||||
public override uint Signature { get { return 0; } }
|
||||
public override bool IsHierarchic { get { return false; } }
|
||||
public override bool CanWrite { get { return false; } }
|
||||
|
||||
public override ArcFile TryOpen (ArcView file)
|
||||
{
|
||||
if (!file.Name.HasExtension ("LPC"))
|
||||
return null;
|
||||
int count = file.View.ReadInt32 (4);
|
||||
if (!IsSaneCount (count))
|
||||
return null;
|
||||
|
||||
var dir = new List<Entry> (count);
|
||||
for (int i = 0; i < count; ++i)
|
||||
{
|
||||
var entry = Create<Entry> (name);
|
||||
if (!entry.CheckPlacement (file.MaxOffset))
|
||||
return null;
|
||||
dir.Add (entry);
|
||||
}
|
||||
return new ArcFile (file, this, dir);
|
||||
}
|
||||
}
|
||||
}
|
78
ArcFormats/Hypatia/ArcLPK.cs
Normal file
78
ArcFormats/Hypatia/ArcLPK.cs
Normal file
@ -0,0 +1,78 @@
|
||||
//! \file ArcLPK.cs
|
||||
//! \date 2022 Apr 12
|
||||
//! \brief Kogado resource archive.
|
||||
//
|
||||
// Copyright (C) 2022 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;
|
||||
|
||||
namespace GameRes.Formats.Kogado
|
||||
{
|
||||
[Export(typeof(ArchiveFormat))]
|
||||
public class LpkOpener : ArchiveFormat
|
||||
{
|
||||
public override string Tag { get { return "LPK/KOGADO"; } }
|
||||
public override string Description { get { return "Kogado resource archive"; } }
|
||||
public override uint Signature { get { return 0; } }
|
||||
public override bool IsHierarchic { get { return false; } }
|
||||
public override bool CanWrite { get { return false; } }
|
||||
|
||||
public override ArcFile TryOpen (ArcView file)
|
||||
{
|
||||
if (!file.Name.HasExtension (".lpk") || file.MaxOffset < 0x2800)
|
||||
return null;
|
||||
uint index_offset = 0;
|
||||
var dir = new List<Entry> ();
|
||||
for (int i = 0; i < 0x200; ++i)
|
||||
{
|
||||
if (file.View.ReadByte (index_offset) == 0)
|
||||
break;
|
||||
var name = file.View.ReadString (index_offset, 0x10);
|
||||
if (!IsValidEntryName (name))
|
||||
return null;
|
||||
index_offset += 0x10;
|
||||
var entry = Create<Entry> (name);
|
||||
dir.Add (entry);
|
||||
}
|
||||
if (0 == dir.Count)
|
||||
return null;
|
||||
index_offset = 0x2000;
|
||||
uint base_offset = 0x2800;
|
||||
uint offset = file.View.ReadUInt32 (index_offset);
|
||||
foreach (var entry in dir)
|
||||
{
|
||||
index_offset += 4;
|
||||
uint next_offset = file.View.ReadUInt32 (index_offset);
|
||||
uint size = next_offset - offset;
|
||||
entry.Offset = offset + base_offset;
|
||||
entry.Size = size;
|
||||
if (!entry.CheckPlacement (file.MaxOffset))
|
||||
return null;
|
||||
offset = next_offset;
|
||||
}
|
||||
return new ArcFile (file, this, dir);
|
||||
}
|
||||
}
|
||||
}
|
100
ArcFormats/Hypatia/ImageLSG.cs
Normal file
100
ArcFormats/Hypatia/ImageLSG.cs
Normal file
@ -0,0 +1,100 @@
|
||||
//! \file ImageLSG.cs
|
||||
//! \date 2022 Apr 12
|
||||
//! \brief Kogado image format.
|
||||
//
|
||||
// Copyright (C) 2022 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 System.Windows.Media;
|
||||
using System.Windows.Media.Imaging;
|
||||
|
||||
namespace GameRes.Formats.Kogado
|
||||
{
|
||||
internal class LsgMetaData : ImageMetaData
|
||||
{
|
||||
public int BitmapSize;
|
||||
}
|
||||
|
||||
[Export(typeof(ImageFormat))]
|
||||
public class LsgFormat : ImageFormat
|
||||
{
|
||||
public override string Tag { get { return "LSG"; } }
|
||||
public override string Description { get { return "Kogado image format"; } }
|
||||
public override uint Signature { get { return 0x4D42; } } // 'BM'
|
||||
|
||||
public override ImageMetaData ReadMetaData (IBinaryStream file)
|
||||
{
|
||||
var header = file.ReadHeader (0x14);
|
||||
var info = new LsgMetaData {
|
||||
Width = header.ToUInt32 (0x0C),
|
||||
Height = header.ToUInt32 (0x10),
|
||||
BPP = header.ToInt32 (8),
|
||||
BitmapSize = header.ToInt32 (4),
|
||||
};
|
||||
if (info.BPP != 8 && info.BPP != 24)
|
||||
return null;
|
||||
return info;
|
||||
}
|
||||
|
||||
static readonly string DefaultPaletteName = "base.pal";
|
||||
|
||||
public override ImageData Read (IBinaryStream file, ImageMetaData info)
|
||||
{
|
||||
var meta = (LsgMetaData)info;
|
||||
file.Position = 0x14;
|
||||
var pixels = file.ReadBytes (meta.BitmapSize);
|
||||
PixelFormat format;
|
||||
BitmapPalette palette = null;
|
||||
if (meta.BPP == 8)
|
||||
{
|
||||
format = PixelFormats.Indexed8;
|
||||
palette = ReadDefaultPalette (file.Name);
|
||||
if (null == palette)
|
||||
format = PixelFormats.Gray8;
|
||||
}
|
||||
else
|
||||
{
|
||||
format = PixelFormats.Bgr24;
|
||||
}
|
||||
return ImageData.Create (info, format, palette, pixels);
|
||||
}
|
||||
|
||||
public override void Write (Stream file, ImageData image)
|
||||
{
|
||||
throw new System.NotImplementedException ("LsgFormat.Write not implemented");
|
||||
}
|
||||
|
||||
internal BitmapPalette ReadDefaultPalette (string filename)
|
||||
{
|
||||
var pal_name = Path.ChangeExtension (filename, ".pal");
|
||||
if (!VFS.FileExists (pal_name))
|
||||
pal_name = VFS.ChangeFileName (filename, DefaultPaletteName);
|
||||
if (!VFS.FileExists (pal_name))
|
||||
return null;
|
||||
using (var input = VFS.OpenStream (pal_name))
|
||||
{
|
||||
return ReadPalette (input, 0x100, PaletteFormat.Rgb);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -23,7 +23,6 @@
|
||||
// IN THE SOFTWARE.
|
||||
//
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.Composition;
|
||||
using System.IO;
|
||||
@ -42,60 +41,110 @@ namespace GameRes.Formats.Kaguya
|
||||
}
|
||||
}
|
||||
|
||||
[Export(typeof(ArchiveFormat))]
|
||||
public class AnmOpener : ArchiveFormat
|
||||
internal class AnmEntry : Entry
|
||||
{
|
||||
public long ImageDataOffset;
|
||||
public uint ImageDataSize;
|
||||
}
|
||||
|
||||
internal interface IAnmReader
|
||||
{
|
||||
List<Entry> GetFramesList (IBinaryStream input);
|
||||
}
|
||||
|
||||
public abstract class AnmOpenerBase : ArchiveFormat, IAnmReader
|
||||
{
|
||||
public override string Tag { get { return "ANM/KAGUYA"; } }
|
||||
public override string Description { get { return "KaGuYa script engine animation resource"; } }
|
||||
public override uint Signature { get { return 0x30304E41; } } // 'AN00'
|
||||
public override bool IsHierarchic { get { return false; } }
|
||||
public override bool CanWrite { get { return false; } }
|
||||
|
||||
public AnmOpener ()
|
||||
public AnmOpenerBase ()
|
||||
{
|
||||
Extensions = new string[] { "anm" };
|
||||
}
|
||||
|
||||
public override ArcFile TryOpen (ArcView file)
|
||||
{
|
||||
int frame_count = file.View.ReadInt16 (0x14);
|
||||
uint current_offset = 0x18 + (uint)frame_count * 4;
|
||||
int count = file.View.ReadInt16 (current_offset);
|
||||
if (!IsSaneCount (count))
|
||||
return null;
|
||||
var base_info = new ImageMetaData
|
||||
using (var input = file.CreateStream())
|
||||
{
|
||||
OffsetX = file.View.ReadInt32 (4),
|
||||
OffsetY = file.View.ReadInt32 (8),
|
||||
Width = file.View.ReadUInt32 (0x0C),
|
||||
Height = file.View.ReadUInt32 (0x10),
|
||||
BPP = 32,
|
||||
};
|
||||
current_offset += 2;
|
||||
string base_name = Path.GetFileNameWithoutExtension (file.Name);
|
||||
var dir = new List<Entry> (count);
|
||||
for (int i = 0; i < count; ++i)
|
||||
{
|
||||
uint width = file.View.ReadUInt32 (current_offset+8);
|
||||
uint height = file.View.ReadUInt32 (current_offset+12);
|
||||
var entry = new Entry
|
||||
var dir = GetFramesList (input);
|
||||
if (null == dir)
|
||||
return null;
|
||||
var base_info = GetBaseInfo (input);
|
||||
string base_name = Path.GetFileNameWithoutExtension (file.Name);
|
||||
int i = 0;
|
||||
foreach (var entry in dir)
|
||||
{
|
||||
Name = string.Format ("{0}#{1:D2}", base_name, i),
|
||||
Type = "image",
|
||||
Offset = current_offset,
|
||||
Size = 0x10 + 4*width*height,
|
||||
};
|
||||
dir.Add (entry);
|
||||
current_offset += entry.Size;
|
||||
entry.Name = string.Format ("{0}#{1:D2}", base_name, i++);
|
||||
entry.Type = "image";
|
||||
}
|
||||
return new AnmArchive (file, this, dir, base_info);
|
||||
}
|
||||
return new AnmArchive (file, this, dir, base_info);
|
||||
}
|
||||
|
||||
public override IImageDecoder OpenImage (ArcFile arc, Entry entry)
|
||||
{
|
||||
var base_info = ((AnmArchive)arc).ImageInfo;
|
||||
var input = arc.File.CreateStream (entry.Offset, entry.Size);
|
||||
return new An00Decoder (input, base_info);
|
||||
return CreateDecoder (input, base_info);
|
||||
}
|
||||
|
||||
internal virtual ImageMetaData GetBaseInfo (IBinaryStream input)
|
||||
{
|
||||
input.Position = 4;
|
||||
return new ImageMetaData
|
||||
{
|
||||
OffsetX = input.ReadInt32(),
|
||||
OffsetY = input.ReadInt32(),
|
||||
Width = input.ReadUInt32(),
|
||||
Height = input.ReadUInt32(),
|
||||
BPP = 32,
|
||||
};
|
||||
}
|
||||
|
||||
public abstract List<Entry> GetFramesList (IBinaryStream input);
|
||||
|
||||
public abstract IImageDecoder CreateDecoder (IBinaryStream input, ImageMetaData info);
|
||||
}
|
||||
|
||||
[Export(typeof(ArchiveFormat))]
|
||||
public class AnmOpener : AnmOpenerBase
|
||||
{
|
||||
public override string Tag { get { return "ANM/KAGUYA"; } }
|
||||
public override uint Signature { get { return 0x30304E41; } } // 'AN00'
|
||||
|
||||
public override List<Entry> GetFramesList (IBinaryStream file)
|
||||
{
|
||||
file.Position = 0x14;
|
||||
int frame_count = file.ReadInt16();
|
||||
file.Position = 0x18 + frame_count * 4;
|
||||
int count = file.ReadInt16();
|
||||
if (!IsSaneCount (count))
|
||||
return null;
|
||||
var current_offset = file.Position;
|
||||
var dir = new List<Entry> (count);
|
||||
for (int i = 0; i < count; ++i)
|
||||
{
|
||||
file.Position = current_offset + 8;
|
||||
uint width = file.ReadUInt32();
|
||||
uint height = file.ReadUInt32();
|
||||
uint image_size = 4*width*height;
|
||||
var entry = new AnmEntry
|
||||
{
|
||||
Offset = current_offset,
|
||||
Size = 0x10 + image_size,
|
||||
ImageDataOffset = current_offset + 0x10,
|
||||
ImageDataSize = image_size,
|
||||
};
|
||||
dir.Add (entry);
|
||||
current_offset += entry.Size;
|
||||
}
|
||||
return dir;
|
||||
}
|
||||
|
||||
public override IImageDecoder CreateDecoder (IBinaryStream input, ImageMetaData info)
|
||||
{
|
||||
return new An00Decoder (input, info);
|
||||
}
|
||||
}
|
||||
|
||||
@ -123,75 +172,146 @@ namespace GameRes.Formats.Kaguya
|
||||
}
|
||||
|
||||
[Export(typeof(ArchiveFormat))]
|
||||
public class An20Opener : ArchiveFormat
|
||||
public class An10Opener : AnmOpenerBase, IAnmReader
|
||||
{
|
||||
public override string Tag { get { return "AN20/KAGUYA"; } }
|
||||
public override string Description { get { return "KaGuYa script engine animation resource"; } }
|
||||
public override uint Signature { get { return 0x30324E41; } } // 'AN20'
|
||||
public override bool IsHierarchic { get { return false; } }
|
||||
public override bool CanWrite { get { return false; } }
|
||||
public override string Tag { get { return "AN10/KAGUYA"; } }
|
||||
public override uint Signature { get { return 0x30314E41; } } // 'AN10'
|
||||
|
||||
public An20Opener ()
|
||||
public override List<Entry> GetFramesList (IBinaryStream file)
|
||||
{
|
||||
Extensions = new string[] { "anm" };
|
||||
}
|
||||
|
||||
public override ArcFile TryOpen (ArcView file)
|
||||
{
|
||||
int table_count = file.View.ReadInt16 (4);
|
||||
uint current_offset = 8;
|
||||
for (int i = 0; i < table_count; ++i)
|
||||
{
|
||||
switch (file.View.ReadByte (current_offset++))
|
||||
{
|
||||
case 0: break;
|
||||
case 1: current_offset += 8; break;
|
||||
case 2:
|
||||
case 3:
|
||||
case 4:
|
||||
case 5: current_offset += 4; break;
|
||||
default: return null;
|
||||
}
|
||||
}
|
||||
current_offset += 2 + file.View.ReadUInt16 (current_offset) * 8u;
|
||||
int count = file.View.ReadInt16 (current_offset);
|
||||
file.Position = 0x14;
|
||||
int frame_count = file.ReadInt16();
|
||||
file.Position = 0x18 + frame_count * 4;
|
||||
int count = file.ReadInt16();
|
||||
if (!IsSaneCount (count))
|
||||
return null;
|
||||
current_offset += 2;
|
||||
var base_info = new ImageMetaData
|
||||
{
|
||||
OffsetX = file.View.ReadInt32 (current_offset),
|
||||
OffsetY = file.View.ReadInt32 (current_offset+4),
|
||||
Width = file.View.ReadUInt32 (current_offset+8),
|
||||
Height = file.View.ReadUInt32 (current_offset+12),
|
||||
BPP = 32,
|
||||
};
|
||||
current_offset += 0x10;
|
||||
string base_name = Path.GetFileNameWithoutExtension (file.Name);
|
||||
var current_offset = file.Position;
|
||||
var dir = new List<Entry> (count);
|
||||
for (int i = 0; i < count; ++i)
|
||||
{
|
||||
uint width = file.View.ReadUInt32 (current_offset+8);
|
||||
uint height = file.View.ReadUInt32 (current_offset+0x0C);
|
||||
uint depth = file.View.ReadUInt32 (current_offset+0x10);
|
||||
var entry = new Entry
|
||||
file.Position = current_offset + 8;
|
||||
uint width = file.ReadUInt32();
|
||||
uint height = file.ReadUInt32();
|
||||
uint channels = file.ReadUInt32();
|
||||
uint image_size = channels*width*height;
|
||||
var entry = new AnmEntry
|
||||
{
|
||||
Name = string.Format ("{0}#{1:D2}", base_name, i),
|
||||
Type = "image",
|
||||
Offset = current_offset,
|
||||
Size = 0x14 + depth*width*height,
|
||||
Size = 0x14 + image_size,
|
||||
ImageDataOffset = current_offset + 0x14,
|
||||
ImageDataSize = image_size,
|
||||
};
|
||||
dir.Add (entry);
|
||||
current_offset += entry.Size;
|
||||
}
|
||||
return new AnmArchive (file, this, dir, base_info);
|
||||
return dir;
|
||||
}
|
||||
|
||||
public override IImageDecoder OpenImage (ArcFile arc, Entry entry)
|
||||
public override IImageDecoder CreateDecoder (IBinaryStream input, ImageMetaData info)
|
||||
{
|
||||
var base_info = ((AnmArchive)arc).ImageInfo;
|
||||
var input = arc.File.CreateStream (entry.Offset, entry.Size);
|
||||
return new An20Decoder (input, base_info);
|
||||
return new An10Decoder (input, info);
|
||||
}
|
||||
}
|
||||
|
||||
internal class An10Decoder : BinaryImageDecoder
|
||||
{
|
||||
public An10Decoder (IBinaryStream input, ImageMetaData base_info) : base (input)
|
||||
{
|
||||
Info = new ImageMetaData
|
||||
{
|
||||
OffsetX = base_info.OffsetX + m_input.ReadInt32(),
|
||||
OffsetY = base_info.OffsetY + m_input.ReadInt32(),
|
||||
Width = m_input.ReadUInt32(),
|
||||
Height = m_input.ReadUInt32(),
|
||||
BPP = m_input.ReadInt32() * 8,
|
||||
};
|
||||
}
|
||||
|
||||
protected override ImageData GetImageData ()
|
||||
{
|
||||
m_input.Position = 0x14;
|
||||
int stride = Info.BPP / 8 * Info.iWidth;
|
||||
var pixels = m_input.ReadBytes (stride*Info.iHeight);
|
||||
PixelFormat format = 24 == Info.BPP ? PixelFormats.Bgr24 : PixelFormats.Bgra32;
|
||||
return ImageData.CreateFlipped (Info, format, null, pixels, stride);
|
||||
}
|
||||
}
|
||||
|
||||
[Export(typeof(ArchiveFormat))]
|
||||
public class An20Opener : AnmOpenerBase
|
||||
{
|
||||
public override string Tag { get { return "AN20/KAGUYA"; } }
|
||||
public override uint Signature { get { return 0x30324E41; } } // 'AN20'
|
||||
|
||||
public override List<Entry> GetFramesList (IBinaryStream file)
|
||||
{
|
||||
if (!SkipFrameTable (file))
|
||||
return null;
|
||||
int count = file.ReadInt16();
|
||||
if (!IsSaneCount (count))
|
||||
return null;
|
||||
long current_offset = file.Position + 0x10;
|
||||
var dir = new List<Entry> (count);
|
||||
for (int i = 0; i < count; ++i)
|
||||
{
|
||||
file.Position = current_offset + 8;
|
||||
uint width = file.ReadUInt32();
|
||||
uint height = file.ReadUInt32();
|
||||
uint depth = file.ReadUInt32();
|
||||
uint image_size = depth*width*height;
|
||||
var entry = new AnmEntry
|
||||
{
|
||||
Offset = current_offset,
|
||||
Size = 0x14 + image_size,
|
||||
ImageDataOffset = current_offset + 0x14,
|
||||
ImageDataSize = image_size,
|
||||
};
|
||||
dir.Add (entry);
|
||||
current_offset += entry.Size;
|
||||
}
|
||||
return dir;
|
||||
}
|
||||
|
||||
internal override ImageMetaData GetBaseInfo (IBinaryStream input)
|
||||
{
|
||||
SkipFrameTable (input);
|
||||
input.ReadInt16();
|
||||
return new ImageMetaData
|
||||
{
|
||||
OffsetX = input.ReadInt32(),
|
||||
OffsetY = input.ReadInt32(),
|
||||
Width = input.ReadUInt32(),
|
||||
Height = input.ReadUInt32(),
|
||||
BPP = 32,
|
||||
};
|
||||
}
|
||||
|
||||
bool SkipFrameTable (IBinaryStream file)
|
||||
{
|
||||
file.Position = 4;
|
||||
int table_count = file.ReadInt16();
|
||||
file.Position = 8;
|
||||
for (int i = 0; i < table_count; ++i)
|
||||
{
|
||||
switch (file.ReadByte())
|
||||
{
|
||||
case 0: break;
|
||||
case 1: file.Seek (8, SeekOrigin.Current); break;
|
||||
case 2:
|
||||
case 3:
|
||||
case 4:
|
||||
case 5: file.Seek (4, SeekOrigin.Current); break;
|
||||
default: return false;
|
||||
}
|
||||
}
|
||||
int count = file.ReadUInt16();
|
||||
file.Seek (count * 8, SeekOrigin.Current);
|
||||
return true;
|
||||
}
|
||||
|
||||
public override IImageDecoder CreateDecoder (IBinaryStream input, ImageMetaData info)
|
||||
{
|
||||
return new An20Decoder (input, info);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -90,7 +90,7 @@ namespace GameRes.Formats.Kaguya
|
||||
}
|
||||
}
|
||||
|
||||
byte[] UnpackLzss (IBinaryStream input, uint unpacked_size)
|
||||
internal static byte[] UnpackLzss (IBinaryStream input, uint unpacked_size)
|
||||
{
|
||||
var output = new byte[unpacked_size];
|
||||
var frame = new byte[0x100];
|
||||
|
@ -65,7 +65,7 @@ namespace GameRes.Formats.Kaguya
|
||||
{
|
||||
int version = file.View.ReadByte (4) - '0';
|
||||
if (version < 3 || version > 6)
|
||||
return null;
|
||||
return ReadOldIndex (file);
|
||||
|
||||
using (var reader = LinkReader.Create (file, version))
|
||||
{
|
||||
@ -87,7 +87,22 @@ namespace GameRes.Formats.Kaguya
|
||||
{
|
||||
var lent = entry as LinkEntry;
|
||||
if (null == lent || (!lent.IsPacked && !lent.IsEncrypted))
|
||||
{
|
||||
if (entry.Size > 8)
|
||||
{
|
||||
uint unpacked_size = arc.File.View.ReadUInt32 (entry.Offset);
|
||||
int id = arc.File.View.ReadUInt16 (entry.Offset+5);
|
||||
if (id == 0x4D42) // 'BM'
|
||||
{
|
||||
using (var input = arc.File.CreateStream (entry.Offset+4, entry.Size-4, entry.Name))
|
||||
{
|
||||
var data = Lin2Opener.UnpackLzss (input, unpacked_size);
|
||||
return new BinMemoryStream (data, entry.Name);
|
||||
}
|
||||
}
|
||||
}
|
||||
return base.OpenEntry (arc, entry);
|
||||
}
|
||||
if (lent.IsEncrypted)
|
||||
{
|
||||
var larc = arc as LinkArchive;
|
||||
@ -102,6 +117,35 @@ namespace GameRes.Formats.Kaguya
|
||||
return new BinMemoryStream (bmr.Data, entry.Name);
|
||||
}
|
||||
}
|
||||
|
||||
internal ArcFile ReadOldIndex (ArcView file)
|
||||
{
|
||||
int count = file.View.ReadInt32 (4);
|
||||
if (!IsSaneCount (count))
|
||||
return null;
|
||||
|
||||
var dir = new List<Entry> (count);
|
||||
using (var index = file.CreateStream())
|
||||
{
|
||||
index.Position = 8;
|
||||
uint names_size = index.ReadUInt32();
|
||||
for (int i = 0; i < count; ++i)
|
||||
{
|
||||
var name = index.ReadCString();
|
||||
var entry = FormatCatalog.Instance.Create<Entry> (name);
|
||||
dir.Add (entry);
|
||||
}
|
||||
index.Position = 12 + names_size;
|
||||
foreach (var entry in dir)
|
||||
{
|
||||
entry.Offset = index.ReadUInt32();
|
||||
entry.Size = index.ReadUInt32();
|
||||
if (!entry.CheckPlacement (file.MaxOffset))
|
||||
return null;
|
||||
}
|
||||
}
|
||||
return new ArcFile (file, this, dir);
|
||||
}
|
||||
}
|
||||
|
||||
internal class LinkReader : IDisposable
|
||||
@ -440,9 +484,15 @@ namespace GameRes.Formats.Kaguya
|
||||
var header = input.ReadHeader (0x11);
|
||||
if (header.AsciiEqual ("[SCR-PARAMS]v0"))
|
||||
{
|
||||
var version = Version.Parse (header.GetCString (13, 4));
|
||||
Version version;
|
||||
if ('.' == header[15])
|
||||
version = Version.Parse (header.GetCString (13, 4));
|
||||
else
|
||||
version = new Version (header[14] - '0', 0);
|
||||
if (2 == version.Major)
|
||||
return new ParamsV2Deserializer (input, version);
|
||||
else if (version.Major < 5)
|
||||
return new ParamsV4Deserializer (input, version);
|
||||
else if (5 == version.Major && (version.Minor >= 4 && version.Minor <= 7))
|
||||
return new ParamsV5Deserializer (input, version);
|
||||
}
|
||||
@ -499,6 +549,22 @@ namespace GameRes.Formats.Kaguya
|
||||
SkipString();
|
||||
}
|
||||
}
|
||||
|
||||
protected void ReadHeader (int start)
|
||||
{
|
||||
m_input.Position = start;
|
||||
SkipChunk();
|
||||
m_title = ReadString();
|
||||
if (m_version.Major < 3)
|
||||
m_input.ReadCString();
|
||||
SkipString();
|
||||
SkipString();
|
||||
m_input.ReadByte();
|
||||
SkipString();
|
||||
SkipString();
|
||||
SkipDict();
|
||||
m_input.ReadByte();
|
||||
}
|
||||
}
|
||||
|
||||
internal class ParamsV2Deserializer : ParamsDeserializer
|
||||
@ -515,17 +581,7 @@ namespace GameRes.Formats.Kaguya
|
||||
|
||||
public override byte[] GetKey ()
|
||||
{
|
||||
m_input.Position = 0x17;
|
||||
SkipChunk();
|
||||
m_title = ReadString();
|
||||
m_input.ReadCString();
|
||||
SkipString();
|
||||
SkipString();
|
||||
m_input.ReadByte();
|
||||
SkipString();
|
||||
SkipString();
|
||||
SkipDict();
|
||||
m_input.ReadByte();
|
||||
ReadHeader (0x17);
|
||||
|
||||
if ("幼なじみと甘~くエッチに過ごす方法" == m_title)
|
||||
{
|
||||
@ -565,6 +621,37 @@ namespace GameRes.Formats.Kaguya
|
||||
}
|
||||
}
|
||||
|
||||
internal class ParamsV4Deserializer : ParamsDeserializer
|
||||
{
|
||||
public ParamsV4Deserializer (IBinaryStream input, Version version) : base (input, version)
|
||||
{
|
||||
}
|
||||
|
||||
public override byte[] GetKey ()
|
||||
{
|
||||
ReadHeader (0x19);
|
||||
|
||||
Skip (m_version.Major < 5 ? 12 : 11);
|
||||
int count = m_input.ReadUInt8();
|
||||
for (int i = 0; i < count; ++i)
|
||||
{
|
||||
m_input.ReadByte();
|
||||
SkipChunk();
|
||||
SkipArray();
|
||||
SkipArray();
|
||||
}
|
||||
SkipDict();
|
||||
count = m_input.ReadUInt8();
|
||||
for (int i = 0; i < count; ++i)
|
||||
{
|
||||
SkipChunk();
|
||||
SkipArray();
|
||||
SkipArray();
|
||||
}
|
||||
return ReadKey();
|
||||
}
|
||||
}
|
||||
|
||||
internal class ParamsV5Deserializer : ParamsDeserializer
|
||||
{
|
||||
public ParamsV5Deserializer (IBinaryStream input, Version version) : base (input, version)
|
||||
@ -573,18 +660,9 @@ namespace GameRes.Formats.Kaguya
|
||||
|
||||
public override byte[] GetKey ()
|
||||
{
|
||||
// ハラミタマ
|
||||
m_input.Position = 0x1B;
|
||||
SkipChunk();
|
||||
m_title = ReadString();
|
||||
SkipString();
|
||||
SkipString();
|
||||
m_input.ReadByte();
|
||||
SkipString();
|
||||
SkipString();
|
||||
SkipDict();
|
||||
ReadHeader (0x1B);
|
||||
|
||||
Skip (m_version.Minor <= 4 ? 0x10 : 0x11);
|
||||
Skip (m_version.Minor <= 4 ? 15 : 16);
|
||||
for (int i = 0; i < 3; ++i)
|
||||
{
|
||||
if (0 != m_input.ReadUInt8())
|
||||
@ -633,6 +711,11 @@ namespace GameRes.Formats.Kaguya
|
||||
|
||||
delegate Stream Decryptor (LinkArchive arc, LinkEntry entry);
|
||||
|
||||
static readonly ResourceInstance<AnmOpener> An00 = new ResourceInstance<AnmOpener> ("ANM/KAGUYA");
|
||||
static readonly ResourceInstance<An10Opener> An10 = new ResourceInstance<An10Opener> ("AN10/KAGUYA");
|
||||
static readonly ResourceInstance<An20Opener> An20 = new ResourceInstance<An20Opener> ("AN20/KAGUYA");
|
||||
static readonly ResourceInstance<Pl00Opener> Pl00 = new ResourceInstance<Pl00Opener> ("PLT/KAGUYA");
|
||||
|
||||
public LinkEncryption (byte[] key, bool anm_encrypted = true)
|
||||
{
|
||||
if (null == key || 0 == key.Length)
|
||||
@ -675,13 +758,12 @@ namespace GameRes.Formats.Kaguya
|
||||
return new PrefixStream (header, body);
|
||||
}
|
||||
|
||||
Stream DecryptAn00 (LinkArchive arc, LinkEntry entry)
|
||||
Stream DecryptAnm (LinkArchive arc, LinkEntry entry, IAnmReader reader)
|
||||
{
|
||||
var data = arc.File.View.ReadBytes (entry.Offset, entry.Size);
|
||||
int frame_offset = 0x18 + data.ToUInt16 (0x14) * 4;
|
||||
int count = data.ToUInt16 (frame_offset);
|
||||
frame_offset += 10;
|
||||
for (int i = 0; i < count; ++i)
|
||||
var input = new BinMemoryStream (data, entry.Name);
|
||||
var dir = reader.GetFramesList (input);
|
||||
if (dir != null)
|
||||
{
|
||||
int w = data.ToInt32 (frame_offset);
|
||||
int h = data.ToInt32 (frame_offset+4);
|
||||
|
101
ArcFormats/Kaguya/ArcPLT.cs
Normal file
101
ArcFormats/Kaguya/ArcPLT.cs
Normal file
@ -0,0 +1,101 @@
|
||||
//! \file ArcPLT.cs
|
||||
//! \date 2022 May 03
|
||||
//! \brief KaGuYa script engine animation resource.
|
||||
//
|
||||
// Copyright (C) 2022 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.Windows.Media;
|
||||
|
||||
namespace GameRes.Formats.Kaguya
|
||||
{
|
||||
[Export(typeof(ArchiveFormat))]
|
||||
public class Pl00Opener : AnmOpenerBase
|
||||
{
|
||||
public override string Tag { get { return "PLT/KAGUYA"; } }
|
||||
public override uint Signature { get { return 0x30304C50; } } // 'PL00'
|
||||
|
||||
public Pl00Opener ()
|
||||
{
|
||||
Extensions = new string[] { "plt" };
|
||||
}
|
||||
|
||||
public override List<Entry> GetFramesList (IBinaryStream file)
|
||||
{
|
||||
file.Position = 4;
|
||||
int count = file.ReadInt16();
|
||||
if (!IsSaneCount (count))
|
||||
return null;
|
||||
file.Position = 0x16;
|
||||
var current_offset = file.Position;
|
||||
var dir = new List<Entry> (count);
|
||||
for (int i = 0; i < count; ++i)
|
||||
{
|
||||
file.Position = current_offset + 8;
|
||||
uint width = file.ReadUInt32();
|
||||
uint height = file.ReadUInt32();
|
||||
uint depth = file.ReadUInt32();
|
||||
uint image_size = depth*width*height;
|
||||
var entry = new AnmEntry
|
||||
{
|
||||
Offset = current_offset,
|
||||
Size = 0x14 + image_size,
|
||||
ImageDataOffset = current_offset + 0x14,
|
||||
ImageDataSize = image_size,
|
||||
};
|
||||
dir.Add (entry);
|
||||
current_offset += entry.Size;
|
||||
}
|
||||
return dir;
|
||||
}
|
||||
|
||||
public override IImageDecoder CreateDecoder (IBinaryStream input, ImageMetaData info)
|
||||
{
|
||||
return new Pl00Decoder (input, info);
|
||||
}
|
||||
}
|
||||
|
||||
internal class Pl00Decoder : BinaryImageDecoder
|
||||
{
|
||||
public Pl00Decoder (IBinaryStream input, ImageMetaData base_info) : base (input)
|
||||
{
|
||||
Info = new ImageMetaData
|
||||
{
|
||||
OffsetX = base_info.OffsetX + m_input.ReadInt32(),
|
||||
OffsetY = base_info.OffsetY + m_input.ReadInt32(),
|
||||
Width = m_input.ReadUInt32(),
|
||||
Height = m_input.ReadUInt32(),
|
||||
BPP = m_input.ReadInt32() * 8,
|
||||
};
|
||||
}
|
||||
|
||||
protected override ImageData GetImageData ()
|
||||
{
|
||||
m_input.Position = 0x14;
|
||||
int stride = Info.BPP * Info.iWidth / 8;
|
||||
var pixels = m_input.ReadBytes (stride*Info.iHeight);
|
||||
PixelFormat format = 24 == Info.BPP ? PixelFormats.Bgr24 : PixelFormats.Bgra32;
|
||||
return ImageData.CreateFlipped (Info, format, null, pixels, stride);
|
||||
}
|
||||
}
|
||||
}
|
@ -39,38 +39,62 @@ namespace GameRes.Formats.Liar
|
||||
public override string Tag { get { return "XFL"; } }
|
||||
public override string Description { get { return Strings.arcStrings.XFLDescription; } }
|
||||
public override uint Signature { get { return 0x0001424c; } }
|
||||
public override bool IsHierarchic { get { return false; } }
|
||||
public override bool IsHierarchic { get { return true; } }
|
||||
public override bool CanWrite { get { return true; } }
|
||||
|
||||
public override ArcFile TryOpen (ArcView file)
|
||||
{
|
||||
uint dir_size = file.View.ReadUInt32 (4);
|
||||
int count = file.View.ReadInt32 (8);
|
||||
if (count <= 0)
|
||||
var dir = ReadDirectory (file, 0, file.MaxOffset, "");
|
||||
if (dir != null)
|
||||
return new ArcFile (file, this, dir);
|
||||
else
|
||||
return null;
|
||||
long max_offset = file.MaxOffset;
|
||||
uint base_offset = dir_size + 12;
|
||||
if (dir_size >= max_offset || base_offset >= max_offset)
|
||||
}
|
||||
|
||||
internal List<Entry> ReadDirectory (ArcView file, long base_offset, long max_offset, string base_dir)
|
||||
{
|
||||
uint dir_size = file.View.ReadUInt32 (base_offset+4);
|
||||
int count = file.View.ReadInt32 (base_offset+8);
|
||||
if (!IsSaneCount (count))
|
||||
return null;
|
||||
long data_offset = base_offset + dir_size + 12;
|
||||
if (dir_size >= max_offset || data_offset >= max_offset)
|
||||
return null;
|
||||
|
||||
file.View.Reserve (0, base_offset);
|
||||
long cur_offset = 12;
|
||||
file.View.Reserve (base_offset, (uint)(data_offset - base_offset));
|
||||
long cur_offset = base_offset + 12;
|
||||
|
||||
var dir = new List<Entry> (count);
|
||||
for (int i = 0; i < count; ++i)
|
||||
{
|
||||
if (cur_offset+40 > base_offset)
|
||||
if (cur_offset+40 > data_offset)
|
||||
return null;
|
||||
string name = file.View.ReadString (cur_offset, 32);
|
||||
var entry = FormatCatalog.Instance.Create<Entry> (name);
|
||||
entry.Offset = base_offset + file.View.ReadUInt32 (cur_offset+32);
|
||||
entry.Size = file.View.ReadUInt32 (cur_offset+36);
|
||||
if (!entry.CheckPlacement (max_offset))
|
||||
return null;
|
||||
dir.Add (entry);
|
||||
var entry_offset = data_offset + file.View.ReadUInt32 (cur_offset+32);
|
||||
var entry_size = file.View.ReadUInt32 (cur_offset+36);
|
||||
List<Entry> subdir = null;
|
||||
name = VFS.CombinePath (base_dir, name);
|
||||
if (name.HasExtension (".xfl") && file.View.ReadUInt32 (entry_offset) == Signature)
|
||||
{
|
||||
subdir = ReadDirectory (file, entry_offset, entry_offset + entry_size, name);
|
||||
}
|
||||
if (subdir != null && subdir.Count > 0)
|
||||
{
|
||||
dir.AddRange (subdir);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
var entry = FormatCatalog.Instance.Create<Entry> (name);
|
||||
entry.Offset = entry_offset;
|
||||
entry.Size = entry_size;
|
||||
if (!entry.CheckPlacement (max_offset))
|
||||
return null;
|
||||
dir.Add (entry);
|
||||
}
|
||||
cur_offset += 40;
|
||||
}
|
||||
return new ArcFile (file, this, dir);
|
||||
return dir;
|
||||
}
|
||||
|
||||
public override void Create (Stream output, IEnumerable<Entry> list, ResourceOptions options,
|
||||
|
@ -61,9 +61,9 @@ namespace GameRes.Formats.Maika
|
||||
|
||||
public Mk2Opener ()
|
||||
{
|
||||
// 'MK2.0' 'BL2.0'. 'SL1.0', 'LS2.0', 'AR2.0'
|
||||
// 'MK2.0' 'BL2.0'. 'SL1.0', 'LS2.0', 'AR2.0', 'MP2.0'
|
||||
Signatures = new uint[] {
|
||||
0x2E324B4D, 0x2E324C42, 0x2E314C53, 0x2E32534C, 0x2E325241
|
||||
0x2E324B4D, 0x2E324C42, 0x2E314C53, 0x2E32534C, 0x2E325241, 0x2E32504D
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -32,5 +32,5 @@ using System.Runtime.InteropServices;
|
||||
// You can specify all the values or you can default the Build and Revision Numbers
|
||||
// by using the '*' as shown below:
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion ("1.2.48.2153")]
|
||||
[assembly: AssemblyFileVersion ("1.2.48.2153")]
|
||||
[assembly: AssemblyVersion ("1.2.48.2176")]
|
||||
[assembly: AssemblyFileVersion ("1.2.48.2176")]
|
||||
|
@ -84,7 +84,7 @@ namespace GameRes.Formats.Qlie
|
||||
public PackOpener ()
|
||||
{
|
||||
Extensions = new string [] { "pack" };
|
||||
ContainedFormats = new[] { "ABMP/QLIE", "DPNG", "PNG", "JPEG", "OGG", "WAV" };
|
||||
ContainedFormats = new[] { "ABMP/QLIE", "DPNG", "ARGB", "PNG", "JPEG", "OGG", "WAV" };
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
114
ArcFormats/Qlie/ImageARGB.cs
Normal file
114
ArcFormats/Qlie/ImageARGB.cs
Normal file
@ -0,0 +1,114 @@
|
||||
//! \file ImageARGB.cs
|
||||
//! \date 2022 Apr 22
|
||||
//! \brief QLIE image format.
|
||||
//
|
||||
// Copyright (C) 2022 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 System.Windows.Media;
|
||||
using System.Windows.Media.Imaging;
|
||||
|
||||
namespace GameRes.Formats.Qlie
|
||||
{
|
||||
internal class ArgbMetaData : ImageMetaData
|
||||
{
|
||||
public uint ImageOffset;
|
||||
public uint ImageLength;
|
||||
public uint MaskLength;
|
||||
}
|
||||
|
||||
[Export(typeof(ImageFormat))]
|
||||
public class ArgbFormat : ImageFormat
|
||||
{
|
||||
public override string Tag { get { return "ARGB"; } }
|
||||
public override string Description { get { return "QLIE image format"; } }
|
||||
public override uint Signature { get { return 0x42475241; } } // 'ARGB'
|
||||
|
||||
public override ImageMetaData ReadMetaData (IBinaryStream file)
|
||||
{
|
||||
var header = file.ReadHeader (0x19);
|
||||
if (!header.AsciiEqual ("ARGBSaveData1\0") || header[0x10] != 3)
|
||||
return null;
|
||||
const uint image_offset = 0x19;
|
||||
uint image_size = header.ToUInt32 (0x11);
|
||||
uint mask_size = header.ToUInt32 (0x15);
|
||||
using (var jpeg = OpenStreamRegion (file, image_offset, image_size))
|
||||
{
|
||||
var info = Jpeg.ReadMetaData (jpeg);
|
||||
if (null == info)
|
||||
return null;
|
||||
return new ArgbMetaData {
|
||||
Width = info.Width,
|
||||
Height = info.Height,
|
||||
BPP = 32,
|
||||
ImageOffset = image_offset,
|
||||
ImageLength = image_size,
|
||||
MaskLength = mask_size,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
internal IBinaryStream OpenStreamRegion (IBinaryStream file, long offset, uint length)
|
||||
{
|
||||
var input = new StreamRegion (file.AsStream, offset, length, true);
|
||||
return new BinaryStream (input, file.Name);
|
||||
}
|
||||
|
||||
public override ImageData Read (IBinaryStream file, ImageMetaData info)
|
||||
{
|
||||
var meta = (ArgbMetaData)info;
|
||||
file.Position = meta.ImageOffset;
|
||||
var jpeg = new JpegBitmapDecoder (file.AsStream, BitmapCreateOptions.None, BitmapCacheOption.OnLoad);
|
||||
BitmapSource bitmap = jpeg.Frames[0];
|
||||
|
||||
file.Position = meta.ImageOffset + meta.ImageLength;
|
||||
var png = new PngBitmapDecoder (file.AsStream, BitmapCreateOptions.None, BitmapCacheOption.OnLoad);
|
||||
BitmapSource mask = png.Frames[0];
|
||||
if (mask.PixelWidth != bitmap.PixelWidth || mask.PixelHeight != bitmap.PixelHeight)
|
||||
throw new InvalidFormatException ("ARGB bitmap and mask dimensions mismatch");
|
||||
|
||||
if (bitmap.Format.BitsPerPixel != 32)
|
||||
bitmap = new FormatConvertedBitmap (bitmap, PixelFormats.Bgr32, null, 0);
|
||||
int stride = bitmap.PixelWidth * 4;
|
||||
var pixels = new byte[stride * bitmap.PixelHeight];
|
||||
bitmap.CopyPixels (pixels, stride, 0);
|
||||
|
||||
if (mask.Format.BitsPerPixel != 8)
|
||||
mask = new FormatConvertedBitmap (mask, PixelFormats.Gray8, null, 0);
|
||||
var alpha = new byte[mask.PixelWidth * mask.PixelHeight];
|
||||
mask.CopyPixels (alpha, mask.PixelWidth, 0);
|
||||
|
||||
int src = 0;
|
||||
for (int dst = 3; dst < pixels.Length; dst += 4)
|
||||
{
|
||||
pixels[dst] = alpha[src++];
|
||||
}
|
||||
return ImageData.Create (info, PixelFormats.Bgra32, null, pixels);
|
||||
}
|
||||
|
||||
public override void Write (Stream file, ImageData image)
|
||||
{
|
||||
throw new System.NotImplementedException ("ArgbFormat.Write not implemented");
|
||||
}
|
||||
}
|
||||
}
|
132
ArcFormats/Seraphim/ArcArchAngel.cs
Normal file
132
ArcFormats/Seraphim/ArcArchAngel.cs
Normal file
@ -0,0 +1,132 @@
|
||||
//! \file ArcArchAngel.cs
|
||||
//! \date 2022 May 01
|
||||
//! \brief ArchAngel engine resource archive.
|
||||
//
|
||||
// Copyright (C) 2022 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;
|
||||
|
||||
namespace GameRes.Formats.ArchAngel
|
||||
{
|
||||
[Export(typeof(ArchiveFormat))]
|
||||
public class DatOpener : ArchiveFormat
|
||||
{
|
||||
public override string Tag { get { return "DAT/ARCH"; } }
|
||||
public override string Description { get { return "ArchAngel engine resource archive"; } }
|
||||
public override uint Signature { get { return 0; } }
|
||||
public override bool IsHierarchic { get { return false; } }
|
||||
public override bool CanWrite { get { return false; } }
|
||||
|
||||
public DatOpener ()
|
||||
{
|
||||
ContainedFormats = new[] { "CB" };
|
||||
}
|
||||
|
||||
static readonly string[] DefaultSections = { "image", "script", null };
|
||||
|
||||
public override ArcFile TryOpen (ArcView file)
|
||||
{
|
||||
if (file.MaxOffset > uint.MaxValue
|
||||
|| !VFS.IsPathEqualsToFileName (file.Name, "ARCHPAC.DAT"))
|
||||
return null;
|
||||
int file_count = file.View.ReadInt16 (0);
|
||||
if (!IsSaneCount (file_count))
|
||||
return null;
|
||||
uint index_pos = 2;
|
||||
var size_table = new uint[file_count];
|
||||
for (int i = 0; i < file_count; ++i)
|
||||
{
|
||||
size_table[i] = file.View.ReadUInt32 (index_pos);
|
||||
index_pos += 4;
|
||||
}
|
||||
var section_table = new SortedDictionary<int, uint>();
|
||||
uint min_offset = (uint)file.MaxOffset;
|
||||
while (index_pos + 6 <= min_offset)
|
||||
{
|
||||
uint offset = file.View.ReadUInt32 (index_pos);
|
||||
int index = file.View.ReadInt16 (index_pos+4);
|
||||
if (index < 0 || index > file_count || offset > file.MaxOffset)
|
||||
return null;
|
||||
if (offset < min_offset)
|
||||
min_offset = offset;
|
||||
section_table[index] = offset;
|
||||
index_pos += 6;
|
||||
}
|
||||
var dir = new List<Entry> (file_count);
|
||||
int section_num = 0;
|
||||
foreach (var section in section_table)
|
||||
{
|
||||
int i = section.Key;
|
||||
uint base_offset = section.Value;
|
||||
do
|
||||
{
|
||||
uint size = size_table[i];
|
||||
var entry = new PackedEntry {
|
||||
Name = string.Format ("{0}-{1:D6}", section_num, i),
|
||||
Offset = base_offset,
|
||||
Size = size,
|
||||
};
|
||||
if (!entry.CheckPlacement (file.MaxOffset))
|
||||
return null;
|
||||
if (section_num < DefaultSections.Length && DefaultSections[section_num] != null)
|
||||
entry.Type = DefaultSections[section_num];
|
||||
if ("script" == entry.Type)
|
||||
entry.IsPacked = true;
|
||||
dir.Add (entry);
|
||||
base_offset += size;
|
||||
++i;
|
||||
}
|
||||
while (i < file_count && !section_table.ContainsKey (i));
|
||||
++section_num;
|
||||
}
|
||||
return new ArcFile (file, this, dir);
|
||||
}
|
||||
|
||||
public override Stream OpenEntry (ArcFile arc, Entry entry)
|
||||
{
|
||||
if (0 == entry.Size)
|
||||
return Stream.Null;
|
||||
var pent = entry as PackedEntry;
|
||||
if (null == pent || !pent.IsPacked || pent.Size <= 4)
|
||||
return base.OpenEntry (arc, entry);
|
||||
var input = arc.File.CreateStream (entry.Offset, entry.Size);
|
||||
if (0 == pent.UnpackedSize)
|
||||
pent.UnpackedSize = input.Signature;
|
||||
try
|
||||
{
|
||||
var data = Seraphim.ScnOpener.LzDecompress (input);
|
||||
return new BinMemoryStream (data, entry.Name);
|
||||
}
|
||||
catch
|
||||
{
|
||||
return arc.File.CreateStream (entry.Offset, entry.Size);
|
||||
}
|
||||
finally
|
||||
{
|
||||
input.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -112,7 +112,7 @@ namespace GameRes.Formats.Seraphim
|
||||
}
|
||||
}
|
||||
|
||||
internal byte[] LzDecompress (IBinaryStream input)
|
||||
internal static byte[] LzDecompress (IBinaryStream input)
|
||||
{
|
||||
int unpacked_size = input.ReadInt32();
|
||||
var data = new byte[unpacked_size];
|
||||
|
@ -82,6 +82,7 @@ namespace GameRes.Formats.Seraphim
|
||||
public ArchPacOpener ()
|
||||
{
|
||||
Extensions = new string[] { "dat" };
|
||||
ContainedFormats = new[] { "CB" };
|
||||
}
|
||||
|
||||
public override ArcFile TryOpen (ArcView file)
|
||||
|
@ -124,6 +124,7 @@ namespace GameRes.Formats.Seraphim
|
||||
{
|
||||
// common case for 256-colors images
|
||||
Signatures = new uint[] { 0x01004243, 0 };
|
||||
Extensions = new string[] { "CB", "CLB" };
|
||||
}
|
||||
|
||||
public override ImageMetaData ReadMetaData (IBinaryStream stream)
|
||||
@ -133,18 +134,18 @@ namespace GameRes.Formats.Seraphim
|
||||
return null;
|
||||
int colors = header.ToUInt16 (2);
|
||||
int packed_size = header.ToInt32 (12);
|
||||
if (packed_size <= 0 || packed_size > stream.Length-0x10)
|
||||
if (packed_size <= 0 /*|| packed_size > stream.Length-0x10*/)
|
||||
return null;
|
||||
uint width = header.ToUInt16 (8);
|
||||
uint height = header.ToUInt16 (10);
|
||||
if (0 == width || 0 == height)
|
||||
int width = header.ToInt16 (8);
|
||||
int height = header.ToInt16 (10);
|
||||
if (width <= 0 || height <= 0 || colors > 0x100)
|
||||
return null;
|
||||
return new SeraphMetaData
|
||||
{
|
||||
OffsetX = header.ToInt16 (4),
|
||||
OffsetY = header.ToInt16 (6),
|
||||
Width = width,
|
||||
Height = height,
|
||||
Width = (uint)width,
|
||||
Height = (uint)height,
|
||||
BPP = 8,
|
||||
PackedSize = packed_size,
|
||||
Colors = colors,
|
||||
@ -363,7 +364,7 @@ namespace GameRes.Formats.Seraphim
|
||||
private byte[] UnpackBytes () // sub_403ED0
|
||||
{
|
||||
int total = m_width * m_height;
|
||||
var output = new byte[total];
|
||||
var output = new byte[total + m_width];
|
||||
int dst = 0;
|
||||
while ( dst < total )
|
||||
{
|
||||
@ -450,9 +451,9 @@ namespace GameRes.Formats.Seraphim
|
||||
}
|
||||
else
|
||||
{
|
||||
int v36 = m_input.ReadByte() | ((next & 0xF) << 8);
|
||||
int offset = m_input.ReadByte() | ((next & 0xF) << 8);
|
||||
count = m_input.ReadByte() + 1;
|
||||
int src = dst - 1 - v36;
|
||||
int src = dst - 1 - offset;
|
||||
Binary.CopyOverlapped (output, src, dst, count);
|
||||
}
|
||||
dst += count;
|
||||
|
116
ArcFormats/TechnoBrain/ArcIPQ.cs
Normal file
116
ArcFormats/TechnoBrain/ArcIPQ.cs
Normal file
@ -0,0 +1,116 @@
|
||||
//! \file ArcIPQ.cs
|
||||
//! \date 2022 May 02
|
||||
//! \brief TechnoBrain's animation resource.
|
||||
//
|
||||
// Copyright (C) 2022 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;
|
||||
|
||||
namespace GameRes.Formats.TechnoBrain
|
||||
{
|
||||
internal class IpqArchive : ArcFile
|
||||
{
|
||||
public readonly IpfMetaData Info;
|
||||
|
||||
public IpqArchive (ArcView arc, ArchiveFormat impl, ICollection<Entry> dir, IpfMetaData info)
|
||||
: base (arc, impl, dir)
|
||||
{
|
||||
Info = info;
|
||||
}
|
||||
}
|
||||
|
||||
[Export(typeof(ArchiveFormat))]
|
||||
public class IpqOpener : ArchiveFormat
|
||||
{
|
||||
public override string Tag { get { return "IPQ"; } }
|
||||
public override string Description { get { return "TechnoBrain's animation resource"; } }
|
||||
public override uint Signature { get { return 0; } } // 'RIFF'
|
||||
public override bool IsHierarchic { get { return false; } }
|
||||
public override bool CanWrite { get { return false; } }
|
||||
|
||||
static readonly ResourceInstance<IpfFormat> Ipf = new ResourceInstance<IpfFormat>("IPF");
|
||||
|
||||
public override ArcFile TryOpen (ArcView file)
|
||||
{
|
||||
if (file.View.ReadUInt32 (0) != 0x46464952 // 'RIFF'
|
||||
|| !file.View.AsciiEqual (8, "IPQ fmt "))
|
||||
return null;
|
||||
IpfMetaData ipq_info;
|
||||
using (var ipq = file.CreateStream())
|
||||
{
|
||||
ipq_info = Ipf.Value.ReadIpfHeader (ipq);
|
||||
if (null == ipq_info || ipq_info.FormatString != "IPQ fmt ")
|
||||
return null;
|
||||
ipq.Position = ipq_info.DataOffset;
|
||||
if (ipq.ReadUInt32() != 0x6D696E61) // "anim"
|
||||
return null;
|
||||
uint index_size = ipq.ReadUInt32();
|
||||
int count = ipq.ReadInt32();
|
||||
if (!IsSaneCount (count))
|
||||
return null;
|
||||
|
||||
var base_name = Path.GetFileNameWithoutExtension (file.Name);
|
||||
var dir = new List<Entry> (count);
|
||||
for (int i = 0; i < count; ++i)
|
||||
{
|
||||
var entry = new Entry {
|
||||
Name = string.Format ("{0}#{1:D3}", base_name, i),
|
||||
Type = "image",
|
||||
Offset = ipq.ReadUInt32(),
|
||||
};
|
||||
dir.Add (entry);
|
||||
}
|
||||
long last_offset = file.MaxOffset;
|
||||
for (int i = count-1; i >= 0; --i)
|
||||
{
|
||||
dir[i].Size = (uint)(last_offset - dir[i].Offset);
|
||||
last_offset = dir[i].Offset;
|
||||
}
|
||||
return new IpqArchive (file, this, dir, ipq_info);
|
||||
}
|
||||
}
|
||||
|
||||
public override IImageDecoder OpenImage (ArcFile arc, Entry entry)
|
||||
{
|
||||
var ipq = arc as IpqArchive;
|
||||
if (null == ipq)
|
||||
return base.OpenImage (arc, entry);
|
||||
var info = ipq.Info.Clone() as IpfMetaData;
|
||||
var file = arc.File.CreateStream();
|
||||
try
|
||||
{
|
||||
file.Position = entry.Offset;
|
||||
if (!Ipf.Value.ReadBmpInfo (file, info))
|
||||
throw new InvalidFormatException ("Invalid 'bmp' section.");
|
||||
return new IpfReader (file, info, Ipf.Value);
|
||||
}
|
||||
catch
|
||||
{
|
||||
file.Dispose();
|
||||
throw;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -23,6 +23,7 @@
|
||||
// IN THE SOFTWARE.
|
||||
//
|
||||
|
||||
using System;
|
||||
using System.ComponentModel.Composition;
|
||||
using System.IO;
|
||||
using System.Windows.Media;
|
||||
@ -31,13 +32,21 @@ using GameRes.Utility;
|
||||
|
||||
namespace GameRes.Formats.TechnoBrain
|
||||
{
|
||||
internal class IpfMetaData : ImageMetaData
|
||||
internal class IpfMetaData : ImageMetaData, ICloneable
|
||||
{
|
||||
public bool HasPalette;
|
||||
public bool HasBitmap;
|
||||
public bool IsCompressed;
|
||||
public long PalOffset;
|
||||
public int PalSize;
|
||||
public long BmpOffset;
|
||||
public long DataOffset;
|
||||
public string FormatString;
|
||||
|
||||
public object Clone ()
|
||||
{
|
||||
return MemberwiseClone();
|
||||
}
|
||||
}
|
||||
|
||||
[Export(typeof(ImageFormat))]
|
||||
@ -47,24 +56,25 @@ namespace GameRes.Formats.TechnoBrain
|
||||
public override string Description { get { return "TechnoBrain's 'Inteligent Picture Format'"; } }
|
||||
public override uint Signature { get { return 0; } } // 'RIFF'
|
||||
|
||||
public override ImageMetaData ReadMetaData (IBinaryStream file)
|
||||
internal IpfMetaData ReadIpfHeader (IBinaryStream file)
|
||||
{
|
||||
// 'RIFF' isn't included into signature to avoid auto-detection of the WAV files as IPF images.
|
||||
if (0x46464952 != file.Signature) // 'RIFF'
|
||||
return null;
|
||||
var header = file.ReadHeader (0x14);
|
||||
if (!header.AsciiEqual (8, "IPF fmt "))
|
||||
if (!header.AsciiEqual (0xC, "fmt "))
|
||||
return null;
|
||||
int fmt_size = header.ToInt32 (0x10);
|
||||
if (fmt_size < 0x24)
|
||||
return null;
|
||||
header = file.ReadHeader (0x14 + fmt_size);
|
||||
bool has_palette = header.ToInt32 (0x18) != 0;
|
||||
bool has_bitmap = header.ToInt32 (0x28) != 0;
|
||||
if (!has_bitmap)
|
||||
return null;
|
||||
var info = new IpfMetaData { BPP = 8, HasPalette = has_palette };
|
||||
if (has_palette)
|
||||
var info = new IpfMetaData {
|
||||
BPP = 8,
|
||||
HasPalette = header.ToInt32 (0x18) != 0,
|
||||
HasBitmap = header.ToInt32 (0x28) != 0,
|
||||
FormatString = header.GetCString (8, 8),
|
||||
};
|
||||
if (info.HasPalette)
|
||||
{
|
||||
if (0x206C6170 != file.ReadInt32()) // 'pal '
|
||||
return null;
|
||||
@ -74,24 +84,43 @@ namespace GameRes.Formats.TechnoBrain
|
||||
info.PalOffset = file.Position;
|
||||
file.Position = info.PalOffset + info.PalSize;
|
||||
}
|
||||
info.DataOffset = file.Position;
|
||||
return info;
|
||||
}
|
||||
|
||||
internal bool ReadBmpInfo (IBinaryStream file, IpfMetaData info)
|
||||
{
|
||||
if (0x20706D62 != file.ReadInt32()) // 'bmp '
|
||||
return null;
|
||||
return false;
|
||||
int bmp_size = file.ReadInt32();
|
||||
if (bmp_size <= 0x20)
|
||||
return null;
|
||||
return false;
|
||||
info.BmpOffset = file.Position + 0x18;
|
||||
info.Width = file.ReadUInt16();
|
||||
info.Height = file.ReadUInt16();
|
||||
file.Seek (0xE, SeekOrigin.Current);
|
||||
file.ReadUInt32();
|
||||
info.OffsetX = file.ReadInt16();
|
||||
info.OffsetY = file.ReadInt16();
|
||||
file.Seek (6, SeekOrigin.Current);
|
||||
info.IsCompressed = 0 != (file.ReadByte() & 1);
|
||||
return true;
|
||||
}
|
||||
|
||||
public override ImageMetaData ReadMetaData (IBinaryStream file)
|
||||
{
|
||||
var info = ReadIpfHeader (file);
|
||||
if (null == info || info.FormatString != "IPF fmt " || !info.HasBitmap)
|
||||
return null;
|
||||
file.Position = info.DataOffset;
|
||||
if (!ReadBmpInfo (file, info))
|
||||
return null;
|
||||
return info;
|
||||
}
|
||||
|
||||
public override ImageData Read (IBinaryStream file, ImageMetaData info)
|
||||
{
|
||||
var reader = new IpfReader (file, (IpfMetaData)info);
|
||||
var pixels = reader.Unpack();
|
||||
return ImageData.Create (info, reader.Format, reader.Palette, pixels);
|
||||
var reader = new IpfReader (file, (IpfMetaData)info, this);
|
||||
return reader.Image;
|
||||
}
|
||||
|
||||
public override void Write (Stream file, ImageData image)
|
||||
@ -100,22 +129,34 @@ namespace GameRes.Formats.TechnoBrain
|
||||
}
|
||||
}
|
||||
|
||||
internal sealed class IpfReader
|
||||
internal sealed class IpfReader : IImageDecoder
|
||||
{
|
||||
IBinaryStream m_input;
|
||||
IpfMetaData m_info;
|
||||
byte[] m_output;
|
||||
ImageData m_image;
|
||||
|
||||
public BitmapPalette Palette { get; private set; }
|
||||
public PixelFormat Format { get; private set; }
|
||||
public byte[] Data { get { return m_output; } }
|
||||
|
||||
public IpfReader (IBinaryStream input, IpfMetaData info)
|
||||
public Stream Source { get { return m_input.AsStream; } }
|
||||
public ImageMetaData Info { get { return m_info; } }
|
||||
public ImageData Image { get { return m_image ?? (m_image = GetImageData()); } }
|
||||
public ImageFormat SourceFormat { get; private set; }
|
||||
|
||||
public IpfReader (IBinaryStream input, IpfMetaData info, ImageFormat impl)
|
||||
{
|
||||
m_input = input;
|
||||
m_info = info;
|
||||
m_output = new byte[m_info.Width*m_info.Height];
|
||||
Format = m_info.HasPalette ? PixelFormats.Indexed8 : PixelFormats.Gray8;
|
||||
SourceFormat = impl;
|
||||
}
|
||||
|
||||
private ImageData GetImageData ()
|
||||
{
|
||||
var pixels = Unpack();
|
||||
return ImageData.Create (m_info, Format, Palette, pixels);
|
||||
}
|
||||
|
||||
public byte[] Unpack ()
|
||||
@ -151,7 +192,7 @@ namespace GameRes.Formats.TechnoBrain
|
||||
for (int j = 0; j < 8; ++j)
|
||||
{
|
||||
int dst = (i << 3) + j;
|
||||
if (dst >= 0x0A && 0 != (bits & 0x80))
|
||||
if (dst >= min_index && 0 != (bits & 0x80))
|
||||
{
|
||||
if (dst >= min_index && dst <= max_index)
|
||||
{
|
||||
@ -199,5 +240,18 @@ namespace GameRes.Formats.TechnoBrain
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#region IDisposable members
|
||||
bool m_disposed = false;
|
||||
public void Dispose ()
|
||||
{
|
||||
if (!m_disposed)
|
||||
{
|
||||
m_input.Dispose();
|
||||
m_disposed = true;
|
||||
}
|
||||
GC.SuppressFinalize (this);
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
@ -42,12 +42,19 @@ namespace GameRes.Formats.Unity
|
||||
public override ArcFile TryOpen (ArcView file)
|
||||
{
|
||||
uint header_size = Binary.BigEndian (file.View.ReadUInt32 (0));
|
||||
uint file_size = Binary.BigEndian (file.View.ReadUInt32 (4));
|
||||
if (file_size != file.MaxOffset || header_size > file_size || 0 == header_size)
|
||||
return null;
|
||||
long file_size = Binary.BigEndian (file.View.ReadUInt32 (4));
|
||||
int format = Binary.BigEndian (file.View.ReadInt32 (8));
|
||||
uint data_offset = Binary.BigEndian (file.View.ReadUInt32 (12));
|
||||
if (format <= 0 || format > 0x100 || data_offset >= file_size || data_offset < header_size)
|
||||
if (format <= 0 || format > 0x100)
|
||||
return null;
|
||||
long data_offset = Binary.BigEndian (file.View.ReadUInt32 (12));
|
||||
if (format >= 22)
|
||||
{
|
||||
header_size = Binary.BigEndian (file.View.ReadUInt32 (0x14));
|
||||
file_size = Binary.BigEndian (file.View.ReadInt64 (0x18));
|
||||
data_offset = Binary.BigEndian (file.View.ReadInt64 (0x20));
|
||||
}
|
||||
if (file_size != file.MaxOffset || header_size > file_size || 0 == header_size
|
||||
|| data_offset >= file_size || data_offset < header_size)
|
||||
return null;
|
||||
using (var stream = file.CreateStream())
|
||||
using (var input = new AssetReader (stream))
|
||||
@ -84,7 +91,7 @@ namespace GameRes.Formats.Unity
|
||||
{
|
||||
reader.SetupReaders (obj.Asset);
|
||||
var tex = new Texture2D();
|
||||
tex.Load (reader, obj.Asset.Tree.Version);
|
||||
tex.Load (reader, obj.Asset.Tree);
|
||||
if (0 == tex.m_DataLength)
|
||||
{
|
||||
reader.Dispose();
|
||||
|
98
ArcFormats/Unity/ArcDSM.cs
Normal file
98
ArcFormats/Unity/ArcDSM.cs
Normal file
@ -0,0 +1,98 @@
|
||||
//! \file ArcDSM.cs
|
||||
//! \date 2022 Apr 30
|
||||
//! \brief Encrypted DSM script file as an archive.
|
||||
//
|
||||
// Copyright (C) 2022 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 System.Security.Cryptography;
|
||||
using System.Text;
|
||||
|
||||
namespace GameRes.Formats.Unity
|
||||
{
|
||||
[Export(typeof(ArchiveFormat))]
|
||||
public class DsmOpener : ArchiveFormat
|
||||
{
|
||||
public override string Tag { get { return "DSM/UNITY"; } }
|
||||
public override string Description { get { return "Unity engine encrypted script file"; } }
|
||||
public override uint Signature { get { return 0; } }
|
||||
public override bool IsHierarchic { get { return false; } }
|
||||
public override bool CanWrite { get { return false; } }
|
||||
|
||||
const string DefaultPassword = "pass";
|
||||
|
||||
public override ArcFile TryOpen (ArcView file)
|
||||
{
|
||||
if (!VFS.IsPathEqualsToFileName (file.Name, "data.dsm")
|
||||
|| (file.View.ReadUInt32 (0) & 0xFFFFFF) != 0xBFBBEF) // UTF-8 BOM
|
||||
return null;
|
||||
|
||||
var dir = new List<Entry> {
|
||||
new Entry {
|
||||
Name = "data.txt",
|
||||
Type = "script",
|
||||
Offset = 0,
|
||||
Size = (uint)file.MaxOffset / 4 * 3,
|
||||
}
|
||||
};
|
||||
return new ArcFile (file, this, dir);
|
||||
}
|
||||
|
||||
public override Stream OpenEntry (ArcFile arc, Entry entry)
|
||||
{
|
||||
using (var input = arc.File.CreateStream())
|
||||
using (var reader = new StreamReader (input))
|
||||
{
|
||||
var sourceString = reader.ReadToEnd();
|
||||
var text = DecryptString (sourceString, DefaultPassword);
|
||||
return new BinMemoryStream (text, entry.Name);
|
||||
}
|
||||
}
|
||||
|
||||
static byte[] DecryptString (string sourceString, string password)
|
||||
{
|
||||
var rijndaelManaged = new RijndaelManaged();
|
||||
byte[] key, iv;
|
||||
GenerateKeyFromPassword (password, rijndaelManaged.KeySize, out key, rijndaelManaged.BlockSize, out iv);
|
||||
rijndaelManaged.Key = key;
|
||||
rijndaelManaged.IV = iv;
|
||||
var array = Convert.FromBase64String (sourceString);
|
||||
using (var cryptoTransform = rijndaelManaged.CreateDecryptor())
|
||||
{
|
||||
return cryptoTransform.TransformFinalBlock (array, 0, array.Length);
|
||||
}
|
||||
}
|
||||
|
||||
static readonly byte[] DefaultSalt = Encoding.UTF8.GetBytes("saltは必ず8バイト以上");
|
||||
|
||||
static void GenerateKeyFromPassword (string password, int keySize, out byte[] key, int blockSize, out byte[] iv)
|
||||
{
|
||||
var rfc2898DeriveBytes = new Rfc2898DeriveBytes (password, DefaultSalt);
|
||||
rfc2898DeriveBytes.IterationCount = 1000;
|
||||
key = rfc2898DeriveBytes.GetBytes (keySize / 8);
|
||||
iv = rfc2898DeriveBytes.GetBytes (blockSize / 8);
|
||||
}
|
||||
}
|
||||
}
|
@ -87,6 +87,7 @@ namespace GameRes.Formats.Unity
|
||||
case 1:
|
||||
index_data = UnpackLzma (packed, index_size);
|
||||
break;
|
||||
case 2:
|
||||
case 3:
|
||||
index_data = new byte[index_size];
|
||||
Lz4Compressor.DecompressBlock (packed, packed.Length, index_data, index_data.Length);
|
||||
|
@ -41,7 +41,7 @@ namespace GameRes.Formats.Unity
|
||||
internal class Asset
|
||||
{
|
||||
int m_format;
|
||||
uint m_data_offset;
|
||||
long m_data_offset;
|
||||
bool m_is_little_endian;
|
||||
UnityTypeData m_tree = new UnityTypeData();
|
||||
Dictionary<long, int> m_adds;
|
||||
@ -63,6 +63,13 @@ namespace GameRes.Formats.Unity
|
||||
m_data_offset = input.ReadUInt32();
|
||||
if (m_format >= 9)
|
||||
m_is_little_endian = 0 == input.ReadInt32();
|
||||
if (m_format >= 22)
|
||||
{
|
||||
input.ReadInt32(); // header_size
|
||||
input.ReadInt64(); // file_size
|
||||
m_data_offset = input.ReadInt64();
|
||||
input.ReadInt64();
|
||||
}
|
||||
input.SetupReaders (this);
|
||||
m_tree.Load (input);
|
||||
|
||||
@ -176,7 +183,8 @@ namespace GameRes.Formats.Unity
|
||||
public void Load (AssetReader reader)
|
||||
{
|
||||
PathId = reader.ReadId();
|
||||
Offset = reader.ReadUInt32() + Asset.DataOffset;
|
||||
Offset = reader.ReadOffset();
|
||||
Offset += Asset.DataOffset;
|
||||
Size = reader.ReadUInt32();
|
||||
if (Asset.Format < 17)
|
||||
{
|
||||
|
@ -65,6 +65,7 @@ namespace GameRes.Formats.Unity
|
||||
public Func<int> ReadInt32;
|
||||
public Func<long> ReadInt64;
|
||||
public Func<long> ReadId;
|
||||
public Func<long> ReadOffset;
|
||||
|
||||
public void SetupReaders (Asset asset)
|
||||
{
|
||||
@ -109,6 +110,10 @@ namespace GameRes.Formats.Unity
|
||||
ReadId = ReadInt64;
|
||||
else
|
||||
ReadId = () => ReadInt32();
|
||||
if (m_format >= 22)
|
||||
ReadOffset = ReadInt64;
|
||||
else
|
||||
ReadOffset = () => ReadUInt32();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -122,6 +127,11 @@ namespace GameRes.Formats.Unity
|
||||
ReadId = () => ReadInt32();
|
||||
}
|
||||
|
||||
public void Skip (int count)
|
||||
{
|
||||
m_input.Seek (count, SeekOrigin.Current);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read bytes into specified buffer.
|
||||
/// </summary>
|
||||
|
@ -97,13 +97,13 @@ namespace GameRes.Formats.Unity
|
||||
|
||||
internal class StreamingInfo
|
||||
{
|
||||
public uint Offset;
|
||||
public long Offset;
|
||||
public uint Size;
|
||||
public string Path;
|
||||
|
||||
public void Load (AssetReader reader)
|
||||
{
|
||||
Offset = reader.ReadUInt32();
|
||||
Offset = reader.ReadOffset();
|
||||
Size = reader.ReadUInt32();
|
||||
Path = reader.ReadString();
|
||||
}
|
||||
|
571
ArcFormats/Unity/Bc7Decoder.cs
Normal file
571
ArcFormats/Unity/Bc7Decoder.cs
Normal file
@ -0,0 +1,571 @@
|
||||
//! \file Bc7Decoder.cs
|
||||
//! \date 2022 May 03
|
||||
//! \brief BC7 texture compression decoder.
|
||||
//
|
||||
// Based on the [bc7enc](https://github.com/richgel999/bc7enc)
|
||||
//
|
||||
// Copyright(c) 2020 Richard Geldreich, Jr.
|
||||
//
|
||||
// C# port copyright (C) 2022 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 GameRes.Utility;
|
||||
|
||||
namespace GameRes.Formats.Unity
|
||||
{
|
||||
public class Bc7Decoder
|
||||
{
|
||||
byte[] m_input;
|
||||
int m_width;
|
||||
int m_height;
|
||||
int m_output_stride;
|
||||
byte[] m_output;
|
||||
byte[] m_block = new byte[64];
|
||||
|
||||
public Bc7Decoder (byte[] input, ImageMetaData info)
|
||||
{
|
||||
m_input = input;
|
||||
m_width = info.iWidth;
|
||||
m_output_stride = m_width * 4;
|
||||
m_height = info.iHeight;
|
||||
m_output = new byte[m_output_stride*m_height];
|
||||
}
|
||||
|
||||
public byte[] Unpack ()
|
||||
{
|
||||
int block_step_y = m_output_stride * 4;
|
||||
int block_step_x = 16;
|
||||
int src = 0;
|
||||
for (int y = 0; y < m_output.Length; y += block_step_y)
|
||||
for (int x = 0; x < m_output_stride; x += block_step_x)
|
||||
{
|
||||
DecompressBc7Block (src);
|
||||
int dst = y + x;
|
||||
int block_src = 0;
|
||||
for (int i = 0; i < 4; ++i)
|
||||
{
|
||||
int row_dst = dst;
|
||||
for (int j = 0; j < 4; ++j)
|
||||
{
|
||||
m_output[row_dst++] = m_block[block_src+2];
|
||||
m_output[row_dst++] = m_block[block_src+1];
|
||||
m_output[row_dst++] = m_block[block_src ];
|
||||
m_output[row_dst++] = m_block[block_src+3];
|
||||
block_src += 4;
|
||||
}
|
||||
dst += m_output_stride;
|
||||
}
|
||||
src += 16;
|
||||
}
|
||||
return m_output;
|
||||
}
|
||||
|
||||
private bool DecompressBc7Block (int src)
|
||||
{
|
||||
byte first_byte = m_input[src];
|
||||
for (int mode = 0; mode < 8; ++mode)
|
||||
{
|
||||
if ((first_byte & (1u << mode)) != 0)
|
||||
{
|
||||
switch (mode)
|
||||
{
|
||||
case 0:
|
||||
case 2:
|
||||
return UnpackBc7Mode0_2 (mode, src);
|
||||
case 1:
|
||||
case 3:
|
||||
case 7:
|
||||
return UnpackBc7Mode1_3_7 (mode, src);
|
||||
case 4:
|
||||
case 5:
|
||||
return UnpackBc7Mode4_5 (mode, src);
|
||||
case 6:
|
||||
return UnpackBc7Mode6 (src);
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
int m_bit_offset;
|
||||
|
||||
uint ReadBits32 (int src, int codesize)
|
||||
{
|
||||
uint bits = 0;
|
||||
int total_bits = 0;
|
||||
|
||||
while (total_bits < codesize)
|
||||
{
|
||||
int byte_bit_offset = m_bit_offset & 7;
|
||||
int bits_to_read = Math.Min (codesize - total_bits, 8 - byte_bit_offset);
|
||||
|
||||
uint byte_bits = (uint)m_input[src + (m_bit_offset >> 3)] >> byte_bit_offset;
|
||||
byte_bits &= ((1u << bits_to_read) - 1u);
|
||||
|
||||
bits |= (byte_bits << total_bits);
|
||||
|
||||
total_bits += bits_to_read;
|
||||
m_bit_offset += bits_to_read;
|
||||
}
|
||||
return bits;
|
||||
}
|
||||
|
||||
byte[] endpoints = new byte[8 * 4];
|
||||
uint[] pbits = new uint[6];
|
||||
uint[] weights = new uint[16];
|
||||
uint[] a_weights = new uint[16];
|
||||
int[] weight_bits = new int[2];
|
||||
byte[,] block_colors= new byte[3,32];
|
||||
|
||||
bool UnpackBc7Mode0_2 (int mode, int src)
|
||||
{
|
||||
const uint ENDPOINTS = 6;
|
||||
const uint COMPS = 3;
|
||||
int WEIGHT_BITS = (mode == 0) ? 3 : 2;
|
||||
int ENDPOINT_BITS = (mode == 0) ? 4 : 5;
|
||||
int PBITS = (mode == 0) ? 6 : 0;
|
||||
uint WEIGHT_VALS = 1u << WEIGHT_BITS;
|
||||
|
||||
m_bit_offset = 0;
|
||||
|
||||
if (ReadBits32 (src, mode + 1) != (1u << mode))
|
||||
return false;
|
||||
|
||||
uint part = ReadBits32 (src, (mode == 0) ? 4 : 6);
|
||||
|
||||
for (uint c = 0; c < COMPS; c++)
|
||||
for (uint e = 0; e < ENDPOINTS * 4; e += 4)
|
||||
endpoints[e+c] = (byte)ReadBits32(src, ENDPOINT_BITS);
|
||||
|
||||
for (uint p = 0; p < PBITS; p++)
|
||||
pbits[p] = ReadBits32 (src, 1);
|
||||
|
||||
for (uint i = 0; i < 16; i++)
|
||||
weights[i] = ReadBits32 (src, ((i == 0) || (i == s_bc7_table_anchor_index_third_subset_1[part]) || (i == s_bc7_table_anchor_index_third_subset_2[part])) ? (WEIGHT_BITS - 1) : WEIGHT_BITS);
|
||||
|
||||
for (uint e = 0; e < ENDPOINTS * 4; e += 4)
|
||||
for (uint c = 0; c < 4; c++)
|
||||
endpoints[e+c] = (byte)((c == 3) ? 0xFF : (PBITS != 0 ? bc7_dequant(endpoints[e+c], pbits[e/4], ENDPOINT_BITS) : bc7_dequant(endpoints[e+c], ENDPOINT_BITS)));
|
||||
|
||||
for (uint s = 0; s < 3; s++)
|
||||
for (uint i = 0; i < WEIGHT_VALS*4; i += 4)
|
||||
{
|
||||
for (uint c = 0; c < 3; c++)
|
||||
block_colors[s,i+c] = (byte)bc7_interp(endpoints[s * 8 + c], endpoints[s * 8 + 4 + c], i/4, WEIGHT_BITS);
|
||||
block_colors[s,i+3] = 0xFF;
|
||||
}
|
||||
|
||||
for (uint i = 0; i < 16*4; i += 4)
|
||||
{
|
||||
int b = s_bc7_partition3[part * 16 + i/4];
|
||||
uint c = weights[i/4] * 4;
|
||||
m_block[i ] = block_colors[b,c];
|
||||
m_block[i+1] = block_colors[b,c+1];
|
||||
m_block[i+2] = block_colors[b,c+2];
|
||||
m_block[i+3] = block_colors[b,c+3];
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool UnpackBc7Mode1_3_7 (int mode, int src)
|
||||
{
|
||||
const uint ENDPOINTS = 4;
|
||||
int COMPS = (mode == 7) ? 4 : 3;
|
||||
int WEIGHT_BITS = (mode == 1) ? 3 : 2;
|
||||
int ENDPOINT_BITS = (mode == 7) ? 5 : ((mode == 1) ? 6 : 7);
|
||||
int PBITS = (mode == 1) ? 2 : 4;
|
||||
bool SHARED_PBITS = mode == 1;
|
||||
uint WEIGHT_VALS = 1u << WEIGHT_BITS;
|
||||
|
||||
m_bit_offset = 0;
|
||||
|
||||
if (ReadBits32 (src, mode + 1) != (1u << mode))
|
||||
return false;
|
||||
|
||||
uint part = ReadBits32 (src, 6);
|
||||
|
||||
for (uint c = 0; c < COMPS; c++)
|
||||
for (uint e = 0; e < ENDPOINTS * 4; e += 4)
|
||||
endpoints[e+c] = (byte)ReadBits32(src, ENDPOINT_BITS);
|
||||
|
||||
for (uint p = 0; p < PBITS; p++)
|
||||
pbits[p] = ReadBits32 (src, 1);
|
||||
|
||||
for (uint i = 0; i < 16; i++)
|
||||
weights[i] = ReadBits32(src, ((i == 0) || (i == s_bc7_table_anchor_index_second_subset[part])) ? (WEIGHT_BITS - 1) : WEIGHT_BITS);
|
||||
|
||||
for (uint e = 0; e < ENDPOINTS*4; e += 4)
|
||||
for (uint c = 0; c < 4; c++)
|
||||
endpoints[e+c] = (byte)((c == ((mode == 7u) ? 4u : 3u)) ? 0xFF : bc7_dequant(endpoints[e+c], pbits[SHARED_PBITS ? ((e/4) >> 1) : (e/4)], ENDPOINT_BITS));
|
||||
|
||||
for (uint s = 0; s < 2; s++)
|
||||
for (uint i = 0; i < WEIGHT_VALS*4; i += 4)
|
||||
{
|
||||
for (uint c = 0; c < COMPS; c++)
|
||||
block_colors[s,i+c] = (byte)bc7_interp(endpoints[(s * 2)*4+c], endpoints[(s * 2 + 1)*4+c], i/4, WEIGHT_BITS);
|
||||
block_colors[s,i+3] = (COMPS == 3) ? (byte)0xFF : block_colors[s,i+3];
|
||||
}
|
||||
|
||||
for (uint i = 0; i < 16*4; i += 4)
|
||||
{
|
||||
int b = s_bc7_partition2[part * 16 + i/4];
|
||||
uint c = weights[i/4] * 4;
|
||||
m_block[i ] = block_colors[b,c];
|
||||
m_block[i+1] = block_colors[b,c+1];
|
||||
m_block[i+2] = block_colors[b,c+2];
|
||||
m_block[i+3] = block_colors[b,c+3];
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool UnpackBc7Mode4_5 (int mode, int src)
|
||||
{
|
||||
const uint ENDPOINTS = 2;
|
||||
const uint COMPS = 4;
|
||||
const int WEIGHT_BITS = 2;
|
||||
int A_WEIGHT_BITS = (mode == 4) ? 3 : 2;
|
||||
int ENDPOINT_BITS = (mode == 4) ? 5 : 7;
|
||||
int A_ENDPOINT_BITS = (mode == 4) ? 6 : 8;
|
||||
|
||||
m_bit_offset = 0;
|
||||
|
||||
if (ReadBits32(src, mode + 1) != (1u << mode))
|
||||
return false;
|
||||
|
||||
uint comp_rot = ReadBits32 (src, 2);
|
||||
uint index_mode = (mode == 4) ? ReadBits32 (src, 1) : 0;
|
||||
|
||||
for (uint c = 0; c < COMPS; c++)
|
||||
for (uint e = 0; e < ENDPOINTS*4; e += 4)
|
||||
endpoints[e+c] = (byte)ReadBits32(src, (c == 3) ? A_ENDPOINT_BITS : ENDPOINT_BITS);
|
||||
|
||||
weight_bits[0] = index_mode != 0 ? A_WEIGHT_BITS : WEIGHT_BITS;
|
||||
weight_bits[1] = index_mode != 0 ? WEIGHT_BITS : A_WEIGHT_BITS;
|
||||
|
||||
uint[] w_array = index_mode != 0 ? a_weights : weights;
|
||||
for (uint i = 0; i < 16; i++)
|
||||
w_array[i] = ReadBits32 (src, weight_bits[index_mode] - ((i == 0) ? 1 : 0));
|
||||
|
||||
w_array = index_mode != 0 ? weights : a_weights;
|
||||
for (uint i = 0; i < 16; i++)
|
||||
w_array[i] = ReadBits32 (src, weight_bits[1 - index_mode] - ((i == 0) ? 1 : 0));
|
||||
|
||||
for (uint e = 0; e < ENDPOINTS*4; e += 4)
|
||||
for (uint c = 0; c < 4; c++)
|
||||
endpoints[e+c] = (byte)bc7_dequant(endpoints[e+c], (c == 3) ? A_ENDPOINT_BITS : ENDPOINT_BITS);
|
||||
|
||||
for (uint i = 0; i < (1U << weight_bits[0]) * 4; i += 4)
|
||||
for (uint c = 0; c < 3; c++)
|
||||
block_colors[0,i+c] = (byte)bc7_interp(endpoints[c], endpoints[4+c], i/4, weight_bits[0]);
|
||||
|
||||
for (uint i = 0; i < (1U << weight_bits[1]) * 4; i += 4)
|
||||
block_colors[0,i+3] = (byte)bc7_interp(endpoints[3], endpoints[4+3], i/4, weight_bits[1]);
|
||||
|
||||
for (uint i = 0; i < 16*4; i += 4)
|
||||
{
|
||||
uint w = weights[i / 4] * 4;
|
||||
m_block[i ] = block_colors[0,w];
|
||||
m_block[i+1] = block_colors[0,w+1];
|
||||
m_block[i+2] = block_colors[0,w+2];
|
||||
m_block[i+3] = block_colors[0,a_weights[i/4]*4+3];
|
||||
if (comp_rot >= 1)
|
||||
{
|
||||
byte a = m_block[i+3];
|
||||
m_block[i+3] = m_block[i+comp_rot-1];
|
||||
m_block[i+comp_rot-1] = a;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
internal class Bc7Mode_6
|
||||
{
|
||||
public struct Lo
|
||||
{
|
||||
public byte mode ; //: 7;
|
||||
public byte r0 ; //: 7;
|
||||
public byte r1 ; //: 7;
|
||||
public byte g0 ; //: 7;
|
||||
public byte g1 ; //: 7;
|
||||
public byte b0 ; //: 7;
|
||||
public byte b1 ; //: 7;
|
||||
public byte a0 ; //: 7;
|
||||
public byte a1 ; //: 7;
|
||||
public byte p0 ; //: 1;
|
||||
}
|
||||
public struct Hi
|
||||
{
|
||||
public byte p1 ; //: 1;
|
||||
public byte s00 ; //: 3;
|
||||
public byte s10 ; //: 4;
|
||||
public byte s20 ; //: 4;
|
||||
public byte s30 ; //: 4;
|
||||
|
||||
public byte s01 ; //: 4;
|
||||
public byte s11 ; //: 4;
|
||||
public byte s21 ; //: 4;
|
||||
public byte s31 ; //: 4;
|
||||
|
||||
public byte s02 ; //: 4;
|
||||
public byte s12 ; //: 4;
|
||||
public byte s22 ; //: 4;
|
||||
public byte s32 ; //: 4;
|
||||
|
||||
public byte s03 ; //: 4;
|
||||
public byte s13 ; //: 4;
|
||||
public byte s23 ; //: 4;
|
||||
public byte s33 ; //: 4;
|
||||
}
|
||||
public Lo m_lo;
|
||||
public Hi m_hi;
|
||||
|
||||
public void Unpack (byte[] input, int src)
|
||||
{
|
||||
ulong lo_bits = input.ToUInt64 (src);
|
||||
ulong hi_bits = input.ToUInt64 (src+8);
|
||||
m_lo.mode = (byte)( lo_bits & 0x7F);
|
||||
m_lo.r0 = (byte)((lo_bits >> 7) & 0x7F);
|
||||
m_lo.r1 = (byte)((lo_bits >> 14) & 0x7F);
|
||||
m_lo.g0 = (byte)((lo_bits >> 21) & 0x7F);
|
||||
m_lo.g1 = (byte)((lo_bits >> 28) & 0x7F);
|
||||
m_lo.b0 = (byte)((lo_bits >> 35) & 0x7F);
|
||||
m_lo.b1 = (byte)((lo_bits >> 42) & 0x7F);
|
||||
m_lo.a0 = (byte)((lo_bits >> 49) & 0x7F);
|
||||
m_lo.a1 = (byte)((lo_bits >> 56) & 0x7F);
|
||||
m_lo.p0 = (byte)((lo_bits >> 63));
|
||||
|
||||
m_hi.p1 = (byte)((hi_bits & 1));
|
||||
m_hi.s00 = (byte)((hi_bits >> 1) & 0x7);
|
||||
m_hi.s10 = (byte)((hi_bits >> 4) & 0xF);
|
||||
m_hi.s20 = (byte)((hi_bits >> 8) & 0xF);
|
||||
m_hi.s30 = (byte)((hi_bits >> 12) & 0xF);
|
||||
m_hi.s01 = (byte)((hi_bits >> 16) & 0xF);
|
||||
m_hi.s11 = (byte)((hi_bits >> 20) & 0xF);
|
||||
m_hi.s21 = (byte)((hi_bits >> 24) & 0xF);
|
||||
m_hi.s31 = (byte)((hi_bits >> 28) & 0xF);
|
||||
m_hi.s02 = (byte)((hi_bits >> 32) & 0xF);
|
||||
m_hi.s12 = (byte)((hi_bits >> 36) & 0xF);
|
||||
m_hi.s22 = (byte)((hi_bits >> 40) & 0xF);
|
||||
m_hi.s32 = (byte)((hi_bits >> 44) & 0xF);
|
||||
m_hi.s03 = (byte)((hi_bits >> 48) & 0xF);
|
||||
m_hi.s13 = (byte)((hi_bits >> 52) & 0xF);
|
||||
m_hi.s23 = (byte)((hi_bits >> 56) & 0xF);
|
||||
m_hi.s33 = (byte)((hi_bits >> 60));
|
||||
}
|
||||
}
|
||||
|
||||
Bc7Mode_6 mode_6_block = new Bc7Mode_6();
|
||||
uint[] vals = new uint[16];
|
||||
|
||||
bool UnpackBc7Mode6(int src)
|
||||
{
|
||||
mode_6_block.Unpack (m_input, src);
|
||||
var block = mode_6_block;
|
||||
|
||||
if (block.m_lo.mode != (1 << 6))
|
||||
return false;
|
||||
|
||||
uint r0 = (uint)((block.m_lo.r0 << 1) | block.m_lo.p0);
|
||||
uint g0 = (uint)((block.m_lo.g0 << 1) | block.m_lo.p0);
|
||||
uint b0 = (uint)((block.m_lo.b0 << 1) | block.m_lo.p0);
|
||||
uint a0 = (uint)((block.m_lo.a0 << 1) | block.m_lo.p0);
|
||||
uint r1 = (uint)((block.m_lo.r1 << 1) | block.m_hi.p1);
|
||||
uint g1 = (uint)((block.m_lo.g1 << 1) | block.m_hi.p1);
|
||||
uint b1 = (uint)((block.m_lo.b1 << 1) | block.m_hi.p1);
|
||||
uint a1 = (uint)((block.m_lo.a1 << 1) | block.m_hi.p1);
|
||||
|
||||
for (int i = 0; i < 16; i++)
|
||||
{
|
||||
uint w = s_bc7_weights4[i];
|
||||
uint iw = 64 - w;
|
||||
SetNoclampRgba(vals, i,
|
||||
(r0 * iw + r1 * w + 32u) >> 6,
|
||||
(g0 * iw + g1 * w + 32u) >> 6,
|
||||
(b0 * iw + b1 * w + 32u) >> 6,
|
||||
(a0 * iw + a1 * w + 32u) >> 6);
|
||||
}
|
||||
|
||||
LittleEndian.Pack (vals[block.m_hi.s00], m_block, 0);
|
||||
LittleEndian.Pack (vals[block.m_hi.s10], m_block, 4);
|
||||
LittleEndian.Pack (vals[block.m_hi.s20], m_block, 8);
|
||||
LittleEndian.Pack (vals[block.m_hi.s30], m_block, 12);
|
||||
|
||||
LittleEndian.Pack (vals[block.m_hi.s01], m_block, 16);
|
||||
LittleEndian.Pack (vals[block.m_hi.s11], m_block, 20);
|
||||
LittleEndian.Pack (vals[block.m_hi.s21], m_block, 24);
|
||||
LittleEndian.Pack (vals[block.m_hi.s31], m_block, 28);
|
||||
|
||||
LittleEndian.Pack (vals[block.m_hi.s02], m_block, 32);
|
||||
LittleEndian.Pack (vals[block.m_hi.s12], m_block, 36);
|
||||
LittleEndian.Pack (vals[block.m_hi.s22], m_block, 40);
|
||||
LittleEndian.Pack (vals[block.m_hi.s32], m_block, 44);
|
||||
|
||||
LittleEndian.Pack (vals[block.m_hi.s03], m_block, 48);
|
||||
LittleEndian.Pack (vals[block.m_hi.s13], m_block, 52);
|
||||
LittleEndian.Pack (vals[block.m_hi.s23], m_block, 56);
|
||||
LittleEndian.Pack (vals[block.m_hi.s33], m_block, 60);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void SetNoclampRgba (uint[] vals, int dst, uint sr, uint sg, uint sb, uint sa)
|
||||
{
|
||||
vals[dst] = (sr & 0xFF) | ((sg & 0xFF) << 8) | ((sb & 0xFF) << 16) | ((sa & 0xFF) << 24);
|
||||
}
|
||||
|
||||
static uint bc7_dequant (uint val, uint pbit, int val_bits)
|
||||
{
|
||||
int total_bits = val_bits + 1;
|
||||
val = (val << 1) | pbit;
|
||||
val <<= (8 - total_bits);
|
||||
val |= (val >> total_bits);
|
||||
return val;
|
||||
}
|
||||
|
||||
static uint bc7_dequant (uint val, int val_bits)
|
||||
{
|
||||
val <<= (8 - val_bits);
|
||||
val |= (val >> val_bits);
|
||||
return val;
|
||||
}
|
||||
|
||||
static uint bc7_interp2 (uint l, uint h, uint w)
|
||||
{
|
||||
return (l * (64 - s_bc7_weights2[w]) + h * s_bc7_weights2[w] + 32) >> 6;
|
||||
}
|
||||
|
||||
static uint bc7_interp3 (uint l, uint h, uint w)
|
||||
{
|
||||
return (l * (64 - s_bc7_weights3[w]) + h * s_bc7_weights3[w] + 32) >> 6;
|
||||
}
|
||||
|
||||
static uint bc7_interp4 (uint l, uint h, uint w)
|
||||
{
|
||||
return (l * (64 - s_bc7_weights4[w]) + h * s_bc7_weights4[w] + 32) >> 6;
|
||||
}
|
||||
|
||||
static uint bc7_interp (uint l, uint h, uint w, int bits)
|
||||
{
|
||||
switch (bits)
|
||||
{
|
||||
case 2: return bc7_interp2 (l, h, w);
|
||||
case 3: return bc7_interp3 (l, h, w);
|
||||
case 4: return bc7_interp4 (l, h, w);
|
||||
default: return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static readonly uint[] s_bc7_weights2 = { 0, 21, 43, 64 };
|
||||
static readonly uint[] s_bc7_weights3 = { 0, 9, 18, 27, 37, 46, 55, 64 };
|
||||
static readonly uint[] s_bc7_weights4 = { 0, 4, 9, 13, 17, 21, 26, 30, 34, 38, 43, 47, 51, 55, 60, 64 };
|
||||
|
||||
static readonly byte[] s_bc7_partition2 = {
|
||||
0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1, 0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,
|
||||
0,1,1,1,0,1,1,1,0,1,1,1,0,1,1,1, 0,0,0,1,0,0,1,1,0,0,1,1,0,1,1,1,
|
||||
0,0,0,0,0,0,0,1,0,0,0,1,0,0,1,1, 0,0,1,1,0,1,1,1,0,1,1,1,1,1,1,1,
|
||||
0,0,0,1,0,0,1,1,0,1,1,1,1,1,1,1, 0,0,0,0,0,0,0,1,0,0,1,1,0,1,1,1,
|
||||
0,0,0,0,0,0,0,0,0,0,0,1,0,0,1,1, 0,0,1,1,0,1,1,1,1,1,1,1,1,1,1,1,
|
||||
0,0,0,0,0,0,0,1,0,1,1,1,1,1,1,1, 0,0,0,0,0,0,0,0,0,0,0,1,0,1,1,1,
|
||||
0,0,0,1,0,1,1,1,1,1,1,1,1,1,1,1, 0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,
|
||||
0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1, 0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,
|
||||
0,0,0,0,1,0,0,0,1,1,1,0,1,1,1,1, 0,1,1,1,0,0,0,1,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,1,0,0,0,1,1,1,0, 0,1,1,1,0,0,1,1,0,0,0,1,0,0,0,0,
|
||||
0,0,1,1,0,0,0,1,0,0,0,0,0,0,0,0, 0,0,0,0,1,0,0,0,1,1,0,0,1,1,1,0,
|
||||
0,0,0,0,0,0,0,0,1,0,0,0,1,1,0,0, 0,1,1,1,0,0,1,1,0,0,1,1,0,0,0,1,
|
||||
0,0,1,1,0,0,0,1,0,0,0,1,0,0,0,0, 0,0,0,0,1,0,0,0,1,0,0,0,1,1,0,0,
|
||||
0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0, 0,0,1,1,0,1,1,0,0,1,1,0,1,1,0,0,
|
||||
0,0,0,1,0,1,1,1,1,1,1,0,1,0,0,0, 0,0,0,0,1,1,1,1,1,1,1,1,0,0,0,0,
|
||||
0,1,1,1,0,0,0,1,1,0,0,0,1,1,1,0, 0,0,1,1,1,0,0,1,1,0,0,1,1,1,0,0,
|
||||
0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1, 0,0,0,0,1,1,1,1,0,0,0,0,1,1,1,1,
|
||||
0,1,0,1,1,0,1,0,0,1,0,1,1,0,1,0, 0,0,1,1,0,0,1,1,1,1,0,0,1,1,0,0,
|
||||
0,0,1,1,1,1,0,0,0,0,1,1,1,1,0,0, 0,1,0,1,0,1,0,1,1,0,1,0,1,0,1,0,
|
||||
0,1,1,0,1,0,0,1,0,1,1,0,1,0,0,1, 0,1,0,1,1,0,1,0,1,0,1,0,0,1,0,1,
|
||||
0,1,1,1,0,0,1,1,1,1,0,0,1,1,1,0, 0,0,0,1,0,0,1,1,1,1,0,0,1,0,0,0,
|
||||
0,0,1,1,0,0,1,0,0,1,0,0,1,1,0,0, 0,0,1,1,1,0,1,1,1,1,0,1,1,1,0,0,
|
||||
0,1,1,0,1,0,0,1,1,0,0,1,0,1,1,0, 0,0,1,1,1,1,0,0,1,1,0,0,0,0,1,1,
|
||||
0,1,1,0,0,1,1,0,1,0,0,1,1,0,0,1, 0,0,0,0,0,1,1,0,0,1,1,0,0,0,0,0,
|
||||
0,1,0,0,1,1,1,0,0,1,0,0,0,0,0,0, 0,0,1,0,0,1,1,1,0,0,1,0,0,0,0,0,
|
||||
0,0,0,0,0,0,1,0,0,1,1,1,0,0,1,0, 0,0,0,0,0,1,0,0,1,1,1,0,0,1,0,0,
|
||||
0,1,1,0,1,1,0,0,1,0,0,1,0,0,1,1, 0,0,1,1,0,1,1,0,1,1,0,0,1,0,0,1,
|
||||
0,1,1,0,0,0,1,1,1,0,0,1,1,1,0,0, 0,0,1,1,1,0,0,1,1,1,0,0,0,1,1,0,
|
||||
0,1,1,0,1,1,0,0,1,1,0,0,1,0,0,1, 0,1,1,0,0,0,1,1,0,0,1,1,1,0,0,1,
|
||||
0,1,1,1,1,1,1,0,1,0,0,0,0,0,0,1, 0,0,0,1,1,0,0,0,1,1,1,0,0,1,1,1,
|
||||
0,0,0,0,1,1,1,1,0,0,1,1,0,0,1,1, 0,0,1,1,0,0,1,1,1,1,1,1,0,0,0,0,
|
||||
0,0,1,0,0,0,1,0,1,1,1,0,1,1,1,0, 0,1,0,0,0,1,0,0,0,1,1,1,0,1,1,1
|
||||
};
|
||||
|
||||
static readonly byte[] s_bc7_partition3 = {
|
||||
0,0,1,1,0,0,1,1,0,2,2,1,2,2,2,2, 0,0,0,1,0,0,1,1,2,2,1,1,2,2,2,1,
|
||||
0,0,0,0,2,0,0,1,2,2,1,1,2,2,1,1, 0,2,2,2,0,0,2,2,0,0,1,1,0,1,1,1,
|
||||
0,0,0,0,0,0,0,0,1,1,2,2,1,1,2,2, 0,0,1,1,0,0,1,1,0,0,2,2,0,0,2,2,
|
||||
0,0,2,2,0,0,2,2,1,1,1,1,1,1,1,1, 0,0,1,1,0,0,1,1,2,2,1,1,2,2,1,1,
|
||||
0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2, 0,0,0,0,1,1,1,1,1,1,1,1,2,2,2,2,
|
||||
0,0,0,0,1,1,1,1,2,2,2,2,2,2,2,2, 0,0,1,2,0,0,1,2,0,0,1,2,0,0,1,2,
|
||||
0,1,1,2,0,1,1,2,0,1,1,2,0,1,1,2, 0,1,2,2,0,1,2,2,0,1,2,2,0,1,2,2,
|
||||
0,0,1,1,0,1,1,2,1,1,2,2,1,2,2,2, 0,0,1,1,2,0,0,1,2,2,0,0,2,2,2,0,
|
||||
0,0,0,1,0,0,1,1,0,1,1,2,1,1,2,2, 0,1,1,1,0,0,1,1,2,0,0,1,2,2,0,0,
|
||||
0,0,0,0,1,1,2,2,1,1,2,2,1,1,2,2, 0,0,2,2,0,0,2,2,0,0,2,2,1,1,1,1,
|
||||
0,1,1,1,0,1,1,1,0,2,2,2,0,2,2,2, 0,0,0,1,0,0,0,1,2,2,2,1,2,2,2,1,
|
||||
0,0,0,0,0,0,1,1,0,1,2,2,0,1,2,2, 0,0,0,0,1,1,0,0,2,2,1,0,2,2,1,0,
|
||||
0,1,2,2,0,1,2,2,0,0,1,1,0,0,0,0, 0,0,1,2,0,0,1,2,1,1,2,2,2,2,2,2,
|
||||
0,1,1,0,1,2,2,1,1,2,2,1,0,1,1,0, 0,0,0,0,0,1,1,0,1,2,2,1,1,2,2,1,
|
||||
0,0,2,2,1,1,0,2,1,1,0,2,0,0,2,2, 0,1,1,0,0,1,1,0,2,0,0,2,2,2,2,2,
|
||||
0,0,1,1,0,1,2,2,0,1,2,2,0,0,1,1, 0,0,0,0,2,0,0,0,2,2,1,1,2,2,2,1,
|
||||
0,0,0,0,0,0,0,2,1,1,2,2,1,2,2,2, 0,2,2,2,0,0,2,2,0,0,1,2,0,0,1,1,
|
||||
0,0,1,1,0,0,1,2,0,0,2,2,0,2,2,2, 0,1,2,0,0,1,2,0,0,1,2,0,0,1,2,0,
|
||||
0,0,0,0,1,1,1,1,2,2,2,2,0,0,0,0, 0,1,2,0,1,2,0,1,2,0,1,2,0,1,2,0,
|
||||
0,1,2,0,2,0,1,2,1,2,0,1,0,1,2,0, 0,0,1,1,2,2,0,0,1,1,2,2,0,0,1,1,
|
||||
0,0,1,1,1,1,2,2,2,2,0,0,0,0,1,1, 0,1,0,1,0,1,0,1,2,2,2,2,2,2,2,2,
|
||||
0,0,0,0,0,0,0,0,2,1,2,1,2,1,2,1, 0,0,2,2,1,1,2,2,0,0,2,2,1,1,2,2,
|
||||
0,0,2,2,0,0,1,1,0,0,2,2,0,0,1,1, 0,2,2,0,1,2,2,1,0,2,2,0,1,2,2,1,
|
||||
0,1,0,1,2,2,2,2,2,2,2,2,0,1,0,1, 0,0,0,0,2,1,2,1,2,1,2,1,2,1,2,1,
|
||||
0,1,0,1,0,1,0,1,0,1,0,1,2,2,2,2, 0,2,2,2,0,1,1,1,0,2,2,2,0,1,1,1,
|
||||
0,0,0,2,1,1,1,2,0,0,0,2,1,1,1,2, 0,0,0,0,2,1,1,2,2,1,1,2,2,1,1,2,
|
||||
0,2,2,2,0,1,1,1,0,1,1,1,0,2,2,2, 0,0,0,2,1,1,1,2,1,1,1,2,0,0,0,2,
|
||||
0,1,1,0,0,1,1,0,0,1,1,0,2,2,2,2, 0,0,0,0,0,0,0,0,2,1,1,2,2,1,1,2,
|
||||
0,1,1,0,0,1,1,0,2,2,2,2,2,2,2,2, 0,0,2,2,0,0,1,1,0,0,1,1,0,0,2,2,
|
||||
0,0,2,2,1,1,2,2,1,1,2,2,0,0,2,2, 0,0,0,0,0,0,0,0,0,0,0,0,2,1,1,2,
|
||||
0,0,0,2,0,0,0,1,0,0,0,2,0,0,0,1, 0,2,2,2,1,2,2,2,0,2,2,2,1,2,2,2,
|
||||
0,1,0,1,2,2,2,2,2,2,2,2,2,2,2,2, 0,1,1,1,2,0,1,1,2,2,0,1,2,2,2,0,
|
||||
};
|
||||
|
||||
static readonly byte[] s_bc7_table_anchor_index_second_subset = {
|
||||
15,15,15,15,15,15,15,15, 15,15,15,15,15,15,15,15,
|
||||
15, 2, 8, 2, 2, 8, 8,15, 2, 8, 2, 2, 8, 8, 2, 2,
|
||||
15,15, 6, 8, 2, 8,15,15, 2, 8, 2, 2, 2,15,15, 6,
|
||||
6, 2, 6, 8,15,15, 2, 2, 15,15,15,15,15, 2, 2,15
|
||||
};
|
||||
|
||||
static readonly byte[] s_bc7_table_anchor_index_third_subset_1 = {
|
||||
3, 3,15,15, 8, 3,15,15, 8, 8, 6, 6, 6, 5, 3, 3,
|
||||
3, 3, 8,15, 3, 3, 6,10, 5, 8, 8, 6, 8, 5,15,15,
|
||||
8,15, 3, 5, 6,10, 8,15, 15, 3,15, 5,15,15,15,15,
|
||||
3,15, 5, 5, 5, 8, 5,10, 5,10, 8,13,15,12, 3, 3
|
||||
};
|
||||
|
||||
static readonly byte[] s_bc7_table_anchor_index_third_subset_2 = {
|
||||
15, 8, 8, 3,15,15, 3, 8, 15,15,15,15,15,15,15, 8,
|
||||
15, 8,15, 3,15, 8,15, 8, 3,15, 6,10,15,15,10, 8,
|
||||
15, 3,15,10,10, 8, 9,10, 6,15, 8,15, 3, 6, 6, 8,
|
||||
15, 3,15,15,15,15,15,15, 15,15,15,15, 3,15,15, 8
|
||||
};
|
||||
}
|
||||
}
|
@ -118,7 +118,7 @@ namespace GameRes.Formats.Unity
|
||||
m_packed = new byte[segment.PackedSize];
|
||||
int packed_size = m_input.Read (m_packed, 0, (int)segment.PackedSize);
|
||||
var output = PrepareBuffer (segment.UnpackedSize);
|
||||
if (3 == method)
|
||||
if (3 == method || 2 == method)
|
||||
m_buffer_len = Lz4Compressor.DecompressBlock (m_packed, packed_size, output, (int)segment.UnpackedSize);
|
||||
else
|
||||
throw new NotImplementedException ("Not supported Unity asset bundle compression.");
|
||||
|
@ -208,7 +208,7 @@ namespace GameRes.Formats.Vorbis
|
||||
GranuleVals[LacingFill + i] = GranulePos;
|
||||
}
|
||||
LacingVals[LacingFill + i] = bytes % 0xFF;
|
||||
GranulePos = GranuleVals[LacingFill+i] = GranulePos;
|
||||
GranulePos = GranuleVals[LacingFill+i] = op.GranulePos;
|
||||
|
||||
// flag the first segment as the beginning of the packet
|
||||
LacingVals[LacingFill] |= 0x100;
|
||||
|
@ -61,7 +61,7 @@ namespace GameRes.Formats.Unity
|
||||
case 28: // Texture2D
|
||||
{
|
||||
var tex = new Texture2D();
|
||||
tex.Load (input, asset.Tree.Version);
|
||||
tex.Load (input, asset.Tree);
|
||||
if (0 == tex.m_DataLength)
|
||||
{
|
||||
var stream_data = new StreamingInfo();
|
||||
|
@ -97,12 +97,17 @@ namespace GameRes.Formats.Unity
|
||||
m_DataLength = reader.ReadInt32();
|
||||
}
|
||||
|
||||
public void Load (AssetReader reader, string version)
|
||||
public void Load (AssetReader reader, UnityTypeData type)
|
||||
{
|
||||
if (version != "2017.3.1f1")
|
||||
if ("2021.1.3f1" == type.Version) // type.Hashes[28] == [0D 08 41 4C FD 5B DB 0D 22 79 20 11 BD A9 AB 26]
|
||||
{
|
||||
Load2021 (reader);
|
||||
return;
|
||||
}
|
||||
if (type.Version != "2017.3.1f1")
|
||||
{
|
||||
Load (reader);
|
||||
if (0 == m_DataLength && version.StartsWith ("2017.")) // "2017.2.0f3" || "2017.1.1p1"
|
||||
if (0 == m_DataLength && type.Version.StartsWith ("2017.")) // "2017.2.0f3" || "2017.1.1p1"
|
||||
reader.ReadInt64();
|
||||
return;
|
||||
}
|
||||
@ -130,6 +135,35 @@ namespace GameRes.Formats.Unity
|
||||
m_DataLength = reader.ReadInt32();
|
||||
}
|
||||
|
||||
public void Load2021 (AssetReader reader)
|
||||
{
|
||||
m_Name = reader.ReadString();
|
||||
reader.Align();
|
||||
reader.ReadInt32(); // m_ForcedFallbackFormat
|
||||
reader.ReadInt32(); // m_DownscaleFallback
|
||||
m_Width = reader.ReadInt32();
|
||||
m_Height = reader.ReadInt32();
|
||||
m_CompleteImageSize = reader.ReadInt32();
|
||||
reader.ReadInt32(); // m_MipsStripped;
|
||||
m_TextureFormat = (TextureFormat)reader.ReadInt32();
|
||||
m_MipCount = reader.ReadInt32();
|
||||
m_IsReadable = reader.ReadBool();
|
||||
reader.Align();
|
||||
reader.ReadInt32(); // m_StreamingMipmapsPriority
|
||||
m_ImageCount = reader.ReadInt32();
|
||||
m_TextureDimension = reader.ReadInt32();
|
||||
m_FilterMode = reader.ReadInt32();
|
||||
m_Aniso = reader.ReadInt32();
|
||||
m_MipBias = reader.ReadFloat();
|
||||
m_WrapMode = reader.ReadInt32(); // m_WrapU
|
||||
reader.ReadInt32(); // m_WrapV
|
||||
reader.ReadInt32(); // m_WrapW
|
||||
reader.ReadInt32(); // m_LightmapFormat
|
||||
m_ColorSpace = reader.ReadInt32();
|
||||
reader.ReadInt32();
|
||||
m_DataLength = reader.ReadInt32();
|
||||
}
|
||||
|
||||
public void LoadData (AssetReader reader)
|
||||
{
|
||||
m_Data = reader.ReadBytes (m_DataLength);
|
||||
@ -243,6 +277,12 @@ namespace GameRes.Formats.Unity
|
||||
pixels = ConvertArgb16 (m_texture.m_Data);
|
||||
break;
|
||||
|
||||
case TextureFormat.BC7:
|
||||
{
|
||||
var decoder = new Bc7Decoder (m_texture.m_Data, Info);
|
||||
pixels = decoder.Unpack();
|
||||
break;
|
||||
}
|
||||
default:
|
||||
throw new NotImplementedException (string.Format ("Not supported Unity Texture2D format '{0}'.", m_texture.m_TextureFormat));
|
||||
}
|
||||
|
@ -226,7 +226,7 @@
|
||||
</dependentAssembly>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="System.Runtime.CompilerServices.Unsafe" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-6.0.0.0" newVersion="6.0.0.0" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-4.0.5.0" newVersion="4.0.5.0" />
|
||||
</dependentAssembly>
|
||||
</assemblyBinding>
|
||||
</runtime>
|
||||
|
@ -1,14 +1,13 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<packages>
|
||||
<package id="NVorbis" version="0.10.4" targetFramework="net461" />
|
||||
<package id="SharpZipLib" version="1.3.3" targetFramework="net461" />
|
||||
<package id="System.Buffers" version="4.5.1" targetFramework="net461" />
|
||||
<package id="System.IO.FileSystem" version="4.3.0" targetFramework="net461" />
|
||||
<package id="System.IO.FileSystem.Primitives" version="4.3.0" targetFramework="net461" />
|
||||
<package id="System.Memory" version="4.5.4" targetFramework="net461" />
|
||||
<package id="System.Numerics.Vectors" version="4.5.0" targetFramework="net461" />
|
||||
<package id="System.Runtime.CompilerServices.Unsafe" version="6.0.0" targetFramework="net461" />
|
||||
<package id="System.Security.Cryptography.Algorithms" version="4.3.1" targetFramework="net461" />
|
||||
<package id="System.Security.Cryptography.Primitives" version="4.3.0" targetFramework="net461" />
|
||||
<package id="System.ValueTuple" version="4.5.0" targetFramework="net461" />
|
||||
<package id="NVorbis" version="0.10.4" targetFramework="net46" />
|
||||
<package id="SharpZipLib" version="1.3.3" targetFramework="net46" />
|
||||
<package id="System.Buffers" version="4.5.1" targetFramework="net46" />
|
||||
<package id="System.IO.FileSystem" version="4.3.0" targetFramework="net46" />
|
||||
<package id="System.IO.FileSystem.Primitives" version="4.3.0" targetFramework="net46" />
|
||||
<package id="System.Memory" version="4.5.4" targetFramework="net46" />
|
||||
<package id="System.Runtime.CompilerServices.Unsafe" version="4.6.0" targetFramework="net46" />
|
||||
<package id="System.Security.Cryptography.Algorithms" version="4.3.1" targetFramework="net46" />
|
||||
<package id="System.Security.Cryptography.Primitives" version="4.3.0" targetFramework="net46" />
|
||||
<package id="System.ValueTuple" version="4.5.0" targetFramework="net46" />
|
||||
</packages>
|
@ -96,7 +96,7 @@ namespace GARbro
|
||||
return;
|
||||
}
|
||||
var tag = args[argn+1];
|
||||
m_image_format = FindFormat (tag);
|
||||
m_image_format = ImageFormat.FindByTag (tag);
|
||||
if (null == m_image_format)
|
||||
{
|
||||
Console.Error.WriteLine ("{0}: unknown format specified", tag);
|
||||
@ -132,7 +132,7 @@ namespace GARbro
|
||||
{
|
||||
VFS.ChDir (m_arc_name);
|
||||
}
|
||||
catch (Exception X)
|
||||
catch (Exception)
|
||||
{
|
||||
Console.Error.WriteLine ("{0}: unknown format", m_arc_name);
|
||||
continue;
|
||||
@ -174,8 +174,9 @@ namespace GARbro
|
||||
static void Usage ()
|
||||
{
|
||||
Console.WriteLine ("Usage: gameres [OPTIONS] ARC [ENTRIES]");
|
||||
Console.WriteLine (" -l list recognized archive formats");
|
||||
Console.WriteLine (" -x extract all files");
|
||||
Console.WriteLine (" -l list recognized archive formats");
|
||||
Console.WriteLine (" -x extract all files");
|
||||
Console.WriteLine (" -c FORMAT convert images to specified format");
|
||||
Console.WriteLine ("Without options displays contents of specified archive.");
|
||||
}
|
||||
|
||||
|
@ -54,6 +54,7 @@
|
||||
</Reference>
|
||||
<Reference Include="Concentus.Oggfile, Version=1.0.4.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Concentus.Oggfile.1.0.4\lib\net45\Concentus.Oggfile.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.Deployment.Compression, Version=3.0.0.0, Culture=neutral, PublicKeyToken=ce35f76fcda82bad, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\MSFTCompressionCab.1.0.0\lib\Microsoft.Deployment.Compression.dll</HintPath>
|
||||
@ -68,6 +69,8 @@
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.AppContext, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\System.AppContext.4.3.0\lib\net46\System.AppContext.dll</HintPath>
|
||||
<Reference Include="System.Buffers, Version=4.0.3.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\System.Buffers.4.5.1\lib\netstandard1.1\System.Buffers.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.ComponentModel.Composition" />
|
||||
<Reference Include="System.Console, Version=4.0.1.1, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||
@ -116,6 +119,23 @@
|
||||
</Reference>
|
||||
<Reference Include="System.Security.Cryptography.X509Certificates, Version=4.1.1.2, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\System.Security.Cryptography.X509Certificates.4.3.2\lib\net461\System.Security.Cryptography.X509Certificates.dll</HintPath>
|
||||
<Reference Include="System.IO.Compression, Version=4.1.2.0, Culture=neutral, PublicKeyToken=b77a5c561934e089, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\System.IO.Compression.4.3.0\lib\net46\System.IO.Compression.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="System.Memory, Version=4.0.1.1, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\System.Memory.4.5.4\lib\netstandard1.1\System.Memory.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Net.Http, Version=4.1.1.3, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\System.Net.Http.4.3.4\lib\net46\System.Net.Http.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Numerics" />
|
||||
<Reference Include="System.Runtime.CompilerServices.Unsafe, Version=4.0.5.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\System.Runtime.CompilerServices.Unsafe.4.6.0\lib\netstandard1.0\System.Runtime.CompilerServices.Unsafe.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Runtime.Serialization" />
|
||||
<Reference Include="System.Security.Cryptography.X509Certificates, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\System.Security.Cryptography.X509Certificates.4.3.2\lib\net46\System.Security.Cryptography.X509Certificates.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Web.Extensions" />
|
||||
<Reference Include="System.Xaml" />
|
||||
@ -128,6 +148,9 @@
|
||||
<HintPath>..\packages\System.Xml.ReaderWriter.4.3.1\lib\net46\System.Xml.ReaderWriter.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="WindowsBase" />
|
||||
<Reference Include="ZstdNet, Version=1.4.5.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\ZstdNet.1.4.5\lib\net45\ZstdNet.dll</HintPath>
|
||||
</Reference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="Artemis\ImageIPT.cs" />
|
||||
@ -140,6 +163,7 @@
|
||||
<Compile Include="RPGMaker\AudioRPGMV.cs" />
|
||||
<Compile Include="RPGMaker\ImageRPGMV.cs" />
|
||||
<Compile Include="Artemis\ShiftReduceParserCode.cs" />
|
||||
<Compile Include="SakanaGL\ArcSX.cs" />
|
||||
<Compile Include="WebP\ImageWEBP.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
@ -188,6 +212,16 @@
|
||||
</None>
|
||||
<None Include="Artemis\IPT.parser" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="x64\libzstd.dll">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="x86\libzstd.dll">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="YltParsers">
|
||||
<Names>ipt</Names>
|
||||
</PropertyGroup>
|
||||
@ -204,6 +238,15 @@ exit 0</PreBuildEvent>
|
||||
<PropertyGroup Label="GenerateIPTProperties">
|
||||
<IPTParser>$(ProjectDir)Artemis\IPT</IPTParser>
|
||||
</PropertyGroup>
|
||||
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
|
||||
<PropertyGroup>
|
||||
<ErrorText>This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
|
||||
</PropertyGroup>
|
||||
<Error Condition="!Exists('$(SolutionDir)\.nuget\NuGet.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\.nuget\NuGet.targets'))" />
|
||||
<Error Condition="!Exists('..\packages\ZstdNet.1.4.5\build\ZstdNet.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\ZstdNet.1.4.5\build\ZstdNet.targets'))" />
|
||||
<Error Condition="!Exists('..\packages\Stub.System.Data.SQLite.Core.NetFramework.1.0.115.5\build\net46\Stub.System.Data.SQLite.Core.NetFramework.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Stub.System.Data.SQLite.Core.NetFramework.1.0.115.5\build\net46\Stub.System.Data.SQLite.Core.NetFramework.targets'))" />
|
||||
</Target>
|
||||
<Import Project="$(SolutionDir)\.nuget\NuGet.targets" Condition="Exists('$(SolutionDir)\.nuget\NuGet.targets')" />
|
||||
<Target Name="BeforeBuild" DependsOnTargets="YltBuildGen" />
|
||||
<Target Name="YltBuildGen" DependsOnTargets="GenerateIPT" />
|
||||
<Target Name="GenerateIPT" Inputs="$(IPTParser).Language.analyzer.lex;$(IPTParser).Language.grammar.y" Outputs="$(IPTParser).Scanner.Generated.cs;$(IPTParser).Parser.Generated.cs">
|
||||
@ -224,6 +267,7 @@ exit 0</PreBuildEvent>
|
||||
<Error Condition="!Exists('..\packages\NETStandard.Library.2.0.3\build\netstandard2.0\NETStandard.Library.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\NETStandard.Library.2.0.3\build\netstandard2.0\NETStandard.Library.targets'))" />
|
||||
<Error Condition="!Exists('..\packages\Stub.System.Data.SQLite.Core.NetFramework.1.0.115.5\build\net46\Stub.System.Data.SQLite.Core.NetFramework.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Stub.System.Data.SQLite.Core.NetFramework.1.0.115.5\build\net46\Stub.System.Data.SQLite.Core.NetFramework.targets'))" />
|
||||
</Target>
|
||||
<Import Project="..\packages\ZstdNet.1.4.5\build\ZstdNet.targets" Condition="Exists('..\packages\ZstdNet.1.4.5\build\ZstdNet.targets')" />
|
||||
<Import Project="..\packages\Stub.System.Data.SQLite.Core.NetFramework.1.0.115.5\build\net46\Stub.System.Data.SQLite.Core.NetFramework.targets" Condition="Exists('..\packages\Stub.System.Data.SQLite.Core.NetFramework.1.0.115.5\build\net46\Stub.System.Data.SQLite.Core.NetFramework.targets')" />
|
||||
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
||||
Other similar extension points exist, see Microsoft.Common.targets.
|
||||
|
@ -32,5 +32,5 @@ using System.Runtime.InteropServices;
|
||||
// You can specify all the values or you can default the Build and Revision Numbers
|
||||
// by using the '*' as shown below:
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion ("1.0.16.39")]
|
||||
[assembly: AssemblyFileVersion ("1.0.16.39")]
|
||||
[assembly: AssemblyVersion ("1.0.16.40")]
|
||||
[assembly: AssemblyFileVersion ("1.0.16.40")]
|
||||
|
226
Experimental/SakanaGL/ArcSX.cs
Normal file
226
Experimental/SakanaGL/ArcSX.cs
Normal file
@ -0,0 +1,226 @@
|
||||
//! \file ArcSX.cs
|
||||
//! \date 2022 Apr 29
|
||||
//! \brief SakanaGL resource archive implementation.
|
||||
//
|
||||
// Copyright (C) 2022 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 GameRes.Utility;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.Composition;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
|
||||
namespace GameRes.Formats.Sakana
|
||||
{
|
||||
internal class SxEntry : PackedEntry
|
||||
{
|
||||
public ushort Flags;
|
||||
|
||||
public bool IsEncrypted { get { return 0 == (Flags & 0x10); } }
|
||||
}
|
||||
|
||||
[Export(typeof(ArchiveFormat))]
|
||||
public class SxOpener : ArchiveFormat
|
||||
{
|
||||
public override string Tag { get { return "SXSTORAGE"; } }
|
||||
public override string Description { get { return "SakanaGL engine resource archive"; } }
|
||||
public override uint Signature { get { return 0; } }
|
||||
public override bool IsHierarchic { get { return true; } }
|
||||
public override bool CanWrite { get { return false; } }
|
||||
|
||||
const uint DefaultKey = 0x2E76034B;
|
||||
|
||||
public override ArcFile TryOpen (ArcView file)
|
||||
{
|
||||
var base_name = Path.GetFileName (file.Name);
|
||||
var sx_name = base_name.Substring (0, 4) + "(00).sx";
|
||||
sx_name = VFS.ChangeFileName (file.Name, sx_name);
|
||||
if (!VFS.FileExists (sx_name) || file.Name.Equals (sx_name, StringComparison.InvariantCultureIgnoreCase))
|
||||
return null;
|
||||
byte[] index_data;
|
||||
using (var sx = VFS.OpenView (sx_name))
|
||||
{
|
||||
if (sx.MaxOffset <= 0x10)
|
||||
return null;
|
||||
if (!sx.View.AsciiEqual (0, "SSXXDEFL"))
|
||||
return null;
|
||||
int key = Binary.BigEndian (sx.View.ReadInt32 (8));
|
||||
int length = (int)(sx.MaxOffset - 0x10);
|
||||
var index_packed = sx.View.ReadBytes (0x10, (uint)length);
|
||||
|
||||
long lkey = (long)key + length;
|
||||
lkey = key ^ (961 * lkey - 124789) ^ DefaultKey;
|
||||
uint key_lo = (uint)lkey;
|
||||
uint key_hi = (uint)(lkey >> 32) ^ 0x2E6;
|
||||
DecryptData (index_packed, key_lo, key_hi);
|
||||
|
||||
index_data = UnpackZstd (index_packed);
|
||||
}
|
||||
using (var index = new BinMemoryStream (index_data))
|
||||
{
|
||||
var reader = new SxIndexDeserializer (index, file.MaxOffset);
|
||||
var dir = reader.Deserialize();
|
||||
return new ArcFile (file, this, dir);
|
||||
}
|
||||
}
|
||||
|
||||
public override Stream OpenEntry (ArcFile arc, Entry entry)
|
||||
{
|
||||
var sx_entry = entry as SxEntry;
|
||||
if (null == sx_entry || (!sx_entry.IsEncrypted && !sx_entry.IsPacked))
|
||||
return base.OpenEntry (arc, entry);
|
||||
var input = arc.File.View.ReadBytes (entry.Offset, entry.Size);
|
||||
if (sx_entry.IsEncrypted)
|
||||
{
|
||||
uint key_lo = (uint)(entry.Offset >> 4) ^ (entry.Size << 16) ^ DefaultKey;
|
||||
uint key_hi = (entry.Size >> 16) ^ 0x2E6;
|
||||
DecryptData (input, key_lo, key_hi);
|
||||
}
|
||||
if (sx_entry.IsPacked)
|
||||
input = UnpackZstd (input);
|
||||
return new BinMemoryStream (input, entry.Name);
|
||||
}
|
||||
|
||||
internal static byte[] UnpackZstd (byte[] data)
|
||||
{
|
||||
int unpacked_size = BigEndian.ToInt32 (data, 0);
|
||||
using (var dec = new ZstdNet.Decompressor())
|
||||
{
|
||||
var packed = new ArraySegment<byte> (data, 4, data.Length - 4);
|
||||
return dec.Unwrap (packed, unpacked_size);
|
||||
}
|
||||
}
|
||||
|
||||
internal static void DecryptData (byte[] data, uint key_lo, uint key_hi)
|
||||
{
|
||||
if (data.Length < 4)
|
||||
return;
|
||||
key_lo ^= 0x159A55E5;
|
||||
key_hi ^= 0x075BCD15;
|
||||
uint v1 = key_hi ^ (key_hi << 11) ^ ((key_hi ^ (key_hi << 11)) >> 8) ^ 0x549139A;
|
||||
uint v2 = v1 ^ key_lo ^ (key_lo << 11) ^ ((key_lo ^ (key_lo << 11) ^ (v1 >> 11)) >> 8);
|
||||
uint v3 = v2 ^ (v2 >> 19) ^ 0x8E415C26;
|
||||
uint v4 = v3 ^ (v3 >> 19) ^ 0x4D9D5BB8;
|
||||
int count = data.Length / 4;
|
||||
unsafe
|
||||
{
|
||||
fixed (byte* data_raw = data)
|
||||
{
|
||||
uint* data32 = (uint*)&data_raw[0];
|
||||
for (int i = 0; i < count; ++i)
|
||||
{
|
||||
uint t1 = v4 ^ v1 ^ (v1 << 11) ^ ((v1 ^ (v1 << 11) ^ (v4 >> 11)) >> 8);
|
||||
uint t2 = v2 ^ (v2 << 11);
|
||||
v2 = v4;
|
||||
v4 = t1 ^ t2 ^ ((t2 ^ (t1 >> 11)) >> 8);
|
||||
data32[i] ^= (t1 >> 4) ^ (v4 << 12);
|
||||
v1 = v3;
|
||||
v3 = t1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal class SxIndexDeserializer
|
||||
{
|
||||
IBinaryStream m_index;
|
||||
long m_max_offset;
|
||||
string[] m_name_list;
|
||||
List<Entry> m_dir;
|
||||
|
||||
public SxIndexDeserializer (IBinaryStream index, long max_offset)
|
||||
{
|
||||
m_index = index;
|
||||
m_max_offset = max_offset;
|
||||
}
|
||||
|
||||
public List<Entry> Deserialize ()
|
||||
{
|
||||
m_index.Position = 8;
|
||||
int count = Binary.BigEndian (m_index.ReadInt32());
|
||||
m_name_list = new string[count];
|
||||
for (int i = 0; i < count; ++i)
|
||||
{
|
||||
int length = m_index.ReadUInt8();
|
||||
m_name_list[i] = m_index.ReadCString (length, Encoding.UTF8);
|
||||
}
|
||||
|
||||
count = Binary.BigEndian (m_index.ReadInt32());
|
||||
m_dir = new List<Entry> (count);
|
||||
for (int i = 0; i < count; ++i)
|
||||
{
|
||||
m_index.ReadUInt16();
|
||||
ushort flags = Binary.BigEndian (m_index.ReadUInt16());
|
||||
uint offset = Binary.BigEndian (m_index.ReadUInt32());
|
||||
uint size = Binary.BigEndian (m_index.ReadUInt32());
|
||||
var entry = new SxEntry {
|
||||
Flags = flags,
|
||||
Offset = (long)offset << 4,
|
||||
Size = size,
|
||||
IsPacked = 0 != (flags & 0x03),
|
||||
};
|
||||
if (!entry.CheckPlacement (m_max_offset))
|
||||
return null;
|
||||
m_dir.Add (entry);
|
||||
}
|
||||
|
||||
count = Binary.BigEndian (m_index.ReadUInt16());
|
||||
for (int i = 0; i < count; ++i)
|
||||
{
|
||||
m_index.ReadUInt32();
|
||||
m_index.ReadUInt32();
|
||||
m_index.ReadUInt32();
|
||||
Binary.BigEndian (m_index.ReadUInt32()); // archive body length
|
||||
m_index.ReadUInt64();
|
||||
m_index.Seek (16, SeekOrigin.Current); // MD5 sum
|
||||
}
|
||||
|
||||
count = Binary.BigEndian (m_index.ReadUInt16());
|
||||
if (count > 0)
|
||||
m_index.Seek (count * 24, SeekOrigin.Current);
|
||||
DeserializeTree();
|
||||
return m_dir;
|
||||
}
|
||||
|
||||
void DeserializeTree (string path = "")
|
||||
{
|
||||
int count = Binary.BigEndian (m_index.ReadUInt16());
|
||||
int name_index = Binary.BigEndian (m_index.ReadInt32());
|
||||
int file_index = Binary.BigEndian (m_index.ReadInt32());
|
||||
var name = Path.Combine (path, m_name_list[name_index]);
|
||||
if (-1 == file_index)
|
||||
{
|
||||
for (int i = 0; i < count; ++i)
|
||||
{
|
||||
DeserializeTree (name);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
m_dir[file_index].Name = name;
|
||||
m_dir[file_index].Type = FormatCatalog.Instance.GetTypeFromName (name);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -8,8 +8,8 @@
|
||||
</dependentAssembly>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="System.Runtime.CompilerServices.Unsafe" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-6.0.0.0" newVersion="6.0.0.0" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-4.0.5.0" newVersion="4.0.5.0" />
|
||||
</dependentAssembly>
|
||||
</assemblyBinding>
|
||||
</runtime>
|
||||
<startup><supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6.1" /></startup></configuration>
|
||||
</configuration>
|
@ -1,27 +1,31 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<packages>
|
||||
<package id="Concentus" version="1.1.7" targetFramework="net461" />
|
||||
<package id="Concentus.Oggfile" version="1.0.4" targetFramework="net461" />
|
||||
<package id="Microsoft.NETCore.Platforms" version="6.0.1" targetFramework="net461" />
|
||||
<package id="Microsoft.Win32.Primitives" version="4.3.0" targetFramework="net461" />
|
||||
<package id="MSFTCompressionCab" version="1.0.0" targetFramework="net461" />
|
||||
<package id="NETStandard.Library" version="2.0.3" targetFramework="net461" />
|
||||
<package id="Stub.System.Data.SQLite.Core.NetFramework" version="1.0.115.5" targetFramework="net461" />
|
||||
<package id="System.AppContext" version="4.3.0" targetFramework="net461" />
|
||||
<package id="System.Console" version="4.3.1" targetFramework="net461" />
|
||||
<package id="System.Data.SQLite.Core" version="1.0.115.5" targetFramework="net461" />
|
||||
<package id="System.Globalization.Calendars" version="4.3.0" targetFramework="net461" />
|
||||
<package id="System.IO.Compression" version="4.3.0" targetFramework="net461" />
|
||||
<package id="System.IO.Compression.ZipFile" version="4.3.0" targetFramework="net461" />
|
||||
<package id="System.IO.FileSystem" version="4.3.0" targetFramework="net461" />
|
||||
<package id="System.IO.FileSystem.Primitives" version="4.3.0" targetFramework="net461" />
|
||||
<package id="System.Net.Http" version="4.3.4" targetFramework="net461" />
|
||||
<package id="System.Net.Sockets" version="4.3.0" targetFramework="net461" />
|
||||
<package id="System.Runtime.InteropServices.RuntimeInformation" version="4.3.0" targetFramework="net461" />
|
||||
<package id="System.Security.Cryptography.Algorithms" version="4.3.1" targetFramework="net461" />
|
||||
<package id="System.Security.Cryptography.Encoding" version="4.3.0" targetFramework="net461" />
|
||||
<package id="System.Security.Cryptography.Primitives" version="4.3.0" targetFramework="net461" />
|
||||
<package id="System.Security.Cryptography.X509Certificates" version="4.3.2" targetFramework="net461" />
|
||||
<package id="System.Xml.ReaderWriter" version="4.3.1" targetFramework="net461" />
|
||||
<package id="YaccLexTools" version="0.2.2" targetFramework="net461" />
|
||||
<package id="Concentus" version="1.1.7" targetFramework="net46" />
|
||||
<package id="Concentus.Oggfile" version="1.0.4" targetFramework="net46" />
|
||||
<package id="Microsoft.NETCore.Platforms" version="6.0.3" targetFramework="net46" />
|
||||
<package id="Microsoft.Win32.Primitives" version="4.3.0" targetFramework="net46" />
|
||||
<package id="MSFTCompressionCab" version="1.0.0" targetFramework="net46" />
|
||||
<package id="NETStandard.Library" version="2.0.3" targetFramework="net46" />
|
||||
<package id="Stub.System.Data.SQLite.Core.NetFramework" version="1.0.115.5" targetFramework="net46" />
|
||||
<package id="System.AppContext" version="4.3.0" targetFramework="net46" />
|
||||
<package id="System.Buffers" version="4.5.1" targetFramework="net46" />
|
||||
<package id="System.Console" version="4.3.1" targetFramework="net46" />
|
||||
<package id="System.Data.SQLite.Core" version="1.0.115.5" targetFramework="net46" />
|
||||
<package id="System.Globalization.Calendars" version="4.3.0" targetFramework="net46" />
|
||||
<package id="System.IO.Compression" version="4.3.0" targetFramework="net46" />
|
||||
<package id="System.IO.Compression.ZipFile" version="4.3.0" targetFramework="net46" />
|
||||
<package id="System.IO.FileSystem" version="4.3.0" targetFramework="net46" />
|
||||
<package id="System.IO.FileSystem.Primitives" version="4.3.0" targetFramework="net46" />
|
||||
<package id="System.Memory" version="4.5.4" targetFramework="net46" />
|
||||
<package id="System.Net.Http" version="4.3.4" targetFramework="net46" />
|
||||
<package id="System.Net.Sockets" version="4.3.0" targetFramework="net46" />
|
||||
<package id="System.Runtime.CompilerServices.Unsafe" version="4.6.0" targetFramework="net46" />
|
||||
<package id="System.Runtime.InteropServices.RuntimeInformation" version="4.3.0" targetFramework="net46" />
|
||||
<package id="System.Security.Cryptography.Algorithms" version="4.3.1" targetFramework="net46" />
|
||||
<package id="System.Security.Cryptography.Encoding" version="4.3.0" targetFramework="net46" />
|
||||
<package id="System.Security.Cryptography.Primitives" version="4.3.0" targetFramework="net46" />
|
||||
<package id="System.Security.Cryptography.X509Certificates" version="4.3.2" targetFramework="net46" />
|
||||
<package id="System.Xml.ReaderWriter" version="4.3.1" targetFramework="net46" />
|
||||
<package id="YaccLexTools" version="0.2.2" targetFramework="net46" />
|
||||
<package id="ZstdNet" version="1.4.5" targetFramework="net46" />
|
||||
</packages>
|
@ -228,24 +228,39 @@ namespace GARbro.GUI
|
||||
var src_format = ImageFormat.FindFormat (file);
|
||||
if (null == src_format)
|
||||
return;
|
||||
if (src_format.Item1 == m_image_format && m_image_format.Extensions.Any (ext => ext == source_ext))
|
||||
return;
|
||||
file.Position = 0;
|
||||
var image = src_format.Item1.Read (file, src_format.Item2);
|
||||
var output = CreateNewFile (target_name);
|
||||
Stream output = null;
|
||||
try
|
||||
{
|
||||
m_image_format.Write (output, image);
|
||||
if (src_format.Item1 == m_image_format && m_image_format.Extensions.Any (ext => ext == source_ext))
|
||||
{
|
||||
if (AreSamePaths (filename, target_name))
|
||||
return;
|
||||
output = CreateNewFile (target_name);
|
||||
file.Position = 0;
|
||||
file.AsStream.CopyTo (output);
|
||||
}
|
||||
else
|
||||
{
|
||||
file.Position = 0;
|
||||
var image = src_format.Item1.Read (file, src_format.Item2);
|
||||
output = CreateNewFile (target_name);
|
||||
m_image_format.Write (output, image);
|
||||
}
|
||||
}
|
||||
catch // delete destination file on conversion failure
|
||||
{
|
||||
// FIXME if user chooses to overwrite file, and conversion results in error,
|
||||
// then original file will be lost.
|
||||
output.Dispose();
|
||||
output = null;
|
||||
File.Delete (target_name);
|
||||
throw;
|
||||
}
|
||||
output.Dispose();
|
||||
finally
|
||||
{
|
||||
if (output != null)
|
||||
output.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -264,5 +279,12 @@ namespace GARbro.GUI
|
||||
m_main.ListViewFocus();
|
||||
m_main.RefreshView();
|
||||
}
|
||||
|
||||
static internal bool AreSamePaths (string filename1, string filename2)
|
||||
{
|
||||
filename1 = Path.GetFullPath (filename1);
|
||||
filename2 = Path.GetFullPath (filename2);
|
||||
return string.Equals (filename1, filename2, StringComparison.OrdinalIgnoreCase);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -240,7 +240,7 @@ namespace GARbro.GUI
|
||||
{
|
||||
using (var data = VFS.OpenImage (preview.Entry))
|
||||
{
|
||||
SetPreviewImage (preview, data.Image.Bitmap);
|
||||
SetPreviewImage (preview, data.Image.Bitmap, data.SourceFormat);
|
||||
}
|
||||
}
|
||||
catch (Exception X)
|
||||
@ -250,7 +250,7 @@ namespace GARbro.GUI
|
||||
}
|
||||
}
|
||||
|
||||
void SetPreviewImage (PreviewFile preview, BitmapSource bitmap)
|
||||
void SetPreviewImage (PreviewFile preview, BitmapSource bitmap, ImageFormat format)
|
||||
{
|
||||
if (bitmap.DpiX != Desktop.DpiX || bitmap.DpiY != Desktop.DpiY)
|
||||
{
|
||||
@ -271,7 +271,7 @@ namespace GARbro.GUI
|
||||
ImageCanvas.Source = bitmap;
|
||||
ApplyDownScaleSetting();
|
||||
SetStatusText (string.Format (guiStrings.MsgImageSize, bitmap.PixelWidth,
|
||||
bitmap.PixelHeight, bitmap.Format.BitsPerPixel));
|
||||
bitmap.PixelHeight, bitmap.Format.BitsPerPixel, format?.Tag ?? "?"));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -1133,13 +1133,13 @@ namespace GARbro.GUI
|
||||
try
|
||||
{
|
||||
var file_list = items.Select (entry => Path.Combine (CurrentPath, entry.Name));
|
||||
GARbro.Shell.File.Delete (file_list);
|
||||
if (!GARbro.Shell.File.Delete (file_list, new WindowInteropHelper(this).Handle))
|
||||
throw new ApplicationException ("Delete operation failed.");
|
||||
count = file_list.Count();
|
||||
}
|
||||
catch
|
||||
finally
|
||||
{
|
||||
ResumeWatchDirectoryChanges();
|
||||
throw;
|
||||
}
|
||||
RefreshView();
|
||||
SetStatusText (Localization.Format ("MsgDeletedItems", count));
|
||||
|
@ -51,5 +51,5 @@ using System.Windows;
|
||||
// You can specify all the values or you can default the Build and Revision Numbers
|
||||
// by using the '*' as shown below:
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion ("1.5.44.2904")]
|
||||
[assembly: AssemblyFileVersion ("1.5.44.2904")]
|
||||
[assembly: AssemblyVersion ("1.5.44.2938")]
|
||||
[assembly: AssemblyFileVersion ("1.5.44.2938")]
|
||||
|
93
GUI/Shell.cs
93
GUI/Shell.cs
@ -119,42 +119,86 @@ namespace GARbro.Shell
|
||||
/// <summary>
|
||||
/// SHFILEOPSTRUCT for SHFileOperation from COM
|
||||
/// </summary>
|
||||
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto, Pack = 1)]
|
||||
private struct SHFILEOPSTRUCT
|
||||
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode, Pack = 1)]
|
||||
private struct SHFILEOPSTRUCT32
|
||||
{
|
||||
|
||||
public IntPtr hwnd;
|
||||
[MarshalAs(UnmanagedType.U4)]
|
||||
public FileOperationType wFunc;
|
||||
[MarshalAs(UnmanagedType.LPTStr)]
|
||||
public string pFrom;
|
||||
[MarshalAs(UnmanagedType.LPTStr)]
|
||||
public string pTo;
|
||||
public FileOperationFlags fFlags;
|
||||
[MarshalAs(UnmanagedType.Bool)]
|
||||
public bool fAnyOperationsAborted;
|
||||
public IntPtr hNameMappings;
|
||||
[MarshalAs(UnmanagedType.LPTStr)]
|
||||
public string lpszProgressTitle;
|
||||
}
|
||||
|
||||
[DllImport("shell32.dll", CharSet = CharSet.Auto)]
|
||||
private static extern int SHFileOperation (ref SHFILEOPSTRUCT FileOp);
|
||||
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
|
||||
public struct SHFILEOPSTRUCT64
|
||||
{
|
||||
public IntPtr hwnd;
|
||||
[MarshalAs(UnmanagedType.U4)]
|
||||
public FileOperationType wFunc;
|
||||
[MarshalAs(UnmanagedType.LPTStr)]
|
||||
public string pFrom;
|
||||
[MarshalAs(UnmanagedType.LPTStr)]
|
||||
public string pTo;
|
||||
public FileOperationFlags fFlags;
|
||||
public bool fAnyOperationsAborted;
|
||||
public IntPtr hNameMappings;
|
||||
[MarshalAs(UnmanagedType.LPTStr)]
|
||||
public string lpszProgressTitle;
|
||||
}
|
||||
|
||||
[DllImport("shell32.dll", EntryPoint = "SHFileOperationW", CharSet = CharSet.Unicode)]
|
||||
private static extern int SHFileOperation32 (ref SHFILEOPSTRUCT32 FileOp);
|
||||
|
||||
[DllImport("shell32.dll", EntryPoint = "SHFileOperationW", CharSet = CharSet.Unicode)]
|
||||
private static extern int SHFileOperation64 (ref SHFILEOPSTRUCT64 lpFileOp);
|
||||
|
||||
private static int SHFileOperation (FileOperationType func, string path, FileOperationFlags flags, IntPtr parent)
|
||||
{
|
||||
if (Marshal.SizeOf(typeof(IntPtr)) == 4)
|
||||
{
|
||||
var fs = new SHFILEOPSTRUCT32
|
||||
{
|
||||
hwnd = parent,
|
||||
wFunc = func,
|
||||
pFrom = path,
|
||||
fFlags = flags
|
||||
};
|
||||
return SHFileOperation32 (ref fs);
|
||||
}
|
||||
else
|
||||
{
|
||||
var fs = new SHFILEOPSTRUCT64
|
||||
{
|
||||
hwnd = parent,
|
||||
wFunc = func,
|
||||
pFrom = path,
|
||||
fFlags = flags
|
||||
};
|
||||
return SHFileOperation64 (ref fs);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Send file to recycle bin
|
||||
/// </summary>
|
||||
/// <param name="path">Location of directory or file to recycle</param>
|
||||
/// <param name="flags">FileOperationFlags to add in addition to FOF_ALLOWUNDO</param>
|
||||
public static bool Delete (string path, FileOperationFlags flags)
|
||||
public static bool Delete (string path, FileOperationFlags flags, IntPtr parent = default(IntPtr))
|
||||
{
|
||||
var fs = new SHFILEOPSTRUCT
|
||||
{
|
||||
wFunc = FileOperationType.FO_DELETE,
|
||||
pFrom = path + '\0' + '\0',
|
||||
fFlags = FileOperationFlags.FOF_ALLOWUNDO | flags
|
||||
};
|
||||
return 0 == SHFileOperation (ref fs);
|
||||
return 0 == SHFileOperation (FileOperationType.FO_DELETE, path+'\0'+'\0',
|
||||
FileOperationFlags.FOF_ALLOWUNDO | flags, parent);
|
||||
}
|
||||
|
||||
public static bool Delete (IEnumerable<string> file_list, FileOperationFlags flags)
|
||||
public static bool Delete (IEnumerable<string> file_list, FileOperationFlags flags, IntPtr parent = default(IntPtr))
|
||||
{
|
||||
var files = new StringBuilder();
|
||||
foreach (var file in file_list)
|
||||
@ -165,36 +209,31 @@ namespace GARbro.Shell
|
||||
if (0 == files.Length)
|
||||
return false;
|
||||
files.Append ('\0');
|
||||
var fs = new SHFILEOPSTRUCT
|
||||
{
|
||||
wFunc = FileOperationType.FO_DELETE,
|
||||
pFrom = files.ToString(),
|
||||
fFlags = FileOperationFlags.FOF_ALLOWUNDO | flags
|
||||
};
|
||||
return 0 == SHFileOperation (ref fs);
|
||||
return 0 == SHFileOperation (FileOperationType.FO_DELETE, files.ToString(),
|
||||
FileOperationFlags.FOF_ALLOWUNDO | flags, parent);
|
||||
}
|
||||
|
||||
public static bool Delete (IEnumerable<string> file_list)
|
||||
public static bool Delete (IEnumerable<string> file_list, IntPtr parent = default(IntPtr))
|
||||
{
|
||||
return Delete (file_list, FileOperationFlags.FOF_WANTNUKEWARNING);
|
||||
return Delete (file_list, FileOperationFlags.FOF_WANTNUKEWARNING, parent);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Send file to recycle bin. Display dialog, display warning if files are too big to fit (FOF_WANTNUKEWARNING)
|
||||
/// </summary>
|
||||
/// <param name="path">Location of directory or file to recycle</param>
|
||||
public static bool Delete (string path)
|
||||
public static bool Delete (string path, IntPtr parent = default(IntPtr))
|
||||
{
|
||||
return Delete (path, FileOperationFlags.FOF_NOCONFIRMATION | FileOperationFlags.FOF_WANTNUKEWARNING);
|
||||
return Delete (path, FileOperationFlags.FOF_NOCONFIRMATION | FileOperationFlags.FOF_WANTNUKEWARNING, parent);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Send file silently to recycle bin. Surpress dialog, surpress errors, delete if too large.
|
||||
/// </summary>
|
||||
/// <param name="path">Location of directory or file to recycle</param>
|
||||
public static bool MoveToRecycleBin (string path)
|
||||
public static bool MoveToRecycleBin (string path, IntPtr parent = default(IntPtr))
|
||||
{
|
||||
return Delete (path, FileOperationFlags.FOF_NOCONFIRMATION | FileOperationFlags.FOF_NOERRORUI | FileOperationFlags.FOF_SILENT);
|
||||
return Delete (path, FileOperationFlags.FOF_NOCONFIRMATION | FileOperationFlags.FOF_NOERRORUI | FileOperationFlags.FOF_SILENT, parent);
|
||||
|
||||
}
|
||||
|
||||
|
@ -270,7 +270,7 @@
|
||||
<comment>Extracting files from {0} to {1}</comment>
|
||||
</data>
|
||||
<data name="MsgImageSize" xml:space="preserve">
|
||||
<value>イメージ {0} x {1} x {2}bpp</value>
|
||||
<value>イメージ {0} x {1} x {2}bpp [{3}]</value>
|
||||
<comment>Image {0} x {1} x {2}bpp</comment>
|
||||
</data>
|
||||
<data name="MsgNoFiles" xml:space="preserve">
|
||||
|
@ -232,7 +232,7 @@
|
||||
<value>{0}에서 {1}로 파일 추출하기</value>
|
||||
</data>
|
||||
<data name="MsgImageSize" xml:space="preserve">
|
||||
<value>이미지 {0} x {1} x {2}bpp</value>
|
||||
<value>이미지 {0} x {1} x {2}bpp [{3}]</value>
|
||||
</data>
|
||||
<data name="MsgNoFiles" xml:space="preserve">
|
||||
<value>추출할 파일이 없음</value>
|
||||
|
@ -232,7 +232,7 @@
|
||||
<value>Extracting files from {0} to {1}</value>
|
||||
</data>
|
||||
<data name="MsgImageSize" xml:space="preserve">
|
||||
<value>Image {0} x {1} x {2}bpp</value>
|
||||
<value>Image {0} x {1} x {2}bpp [{3}]</value>
|
||||
</data>
|
||||
<data name="MsgNoFiles" xml:space="preserve">
|
||||
<value>no files to extract</value>
|
||||
|
@ -226,7 +226,7 @@
|
||||
<value>Извлекаются файлы из {0} в {1}</value>
|
||||
</data>
|
||||
<data name="MsgImageSize" xml:space="preserve">
|
||||
<value>Изображение {0} x {1} x {2}bpp</value>
|
||||
<value>Изображение {0} x {1} x {2}bpp [{3}]</value>
|
||||
</data>
|
||||
<data name="MsgNoFiles" xml:space="preserve">
|
||||
<value>отсутствуют файлы, удовлетворяющие выбранным критериям</value>
|
||||
|
@ -232,7 +232,7 @@
|
||||
<value>正在从{0}中提取文件至{1}……</value>
|
||||
</data>
|
||||
<data name="MsgImageSize" xml:space="preserve">
|
||||
<value>图像 {0} x {1} x {2}bpp</value>
|
||||
<value>图像 {0} x {1} x {2}bpp [{3}]</value>
|
||||
</data>
|
||||
<data name="MsgNoFiles" xml:space="preserve">
|
||||
<value>没有可以提取的文件。</value>
|
||||
|
@ -1,7 +1,7 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<packages>
|
||||
<package id="NAudio" version="1.10.0" targetFramework="net461" />
|
||||
<package id="WindowsAPICodePack-Core" version="1.1.2" targetFramework="net461" />
|
||||
<package id="WindowsAPICodePack-Shell" version="1.1.1" targetFramework="net461" />
|
||||
<package id="WPFToolkit" version="3.5.50211.1" targetFramework="net461" />
|
||||
<package id="NAudio" version="1.10.0" targetFramework="net46" />
|
||||
<package id="WindowsAPICodePack-Core" version="1.1.2" targetFramework="net46" />
|
||||
<package id="WindowsAPICodePack-Shell" version="1.1.1" targetFramework="net46" />
|
||||
<package id="WPFToolkit" version="3.5.50211.1" targetFramework="net46" />
|
||||
</packages>
|
@ -32,5 +32,5 @@ using System.Runtime.InteropServices;
|
||||
// You can specify all the values or you can default the Build and Revision Numbers
|
||||
// by using the '*' as shown below:
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion ("1.5.44.319")]
|
||||
[assembly: AssemblyFileVersion ("1.5.44.319")]
|
||||
[assembly: AssemblyVersion ("1.5.44.320")]
|
||||
[assembly: AssemblyFileVersion ("1.5.44.320")]
|
||||
|
@ -1,4 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<packages>
|
||||
<package id="NAudio" version="1.10.0" targetFramework="net461" />
|
||||
<package id="NAudio" version="1.10.0" targetFramework="net46" />
|
||||
</packages>
|
75
Legacy/Gsx/ImageK4.cs
Normal file
75
Legacy/Gsx/ImageK4.cs
Normal file
@ -0,0 +1,75 @@
|
||||
//! \file ImageK4.cs
|
||||
//! \date 2019 Feb 07
|
||||
//! \brief Toyo GSX image format.
|
||||
//
|
||||
// Copyright (C) 2019 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 System.Windows.Media;
|
||||
|
||||
// [030825][Mirai] Hoshi no Oujo
|
||||
|
||||
namespace GameRes.Formats.Gsx
|
||||
{
|
||||
internal class K4MetaData : ImageMetaData
|
||||
{
|
||||
public bool HasAlpha;
|
||||
public int FrameCount;
|
||||
}
|
||||
|
||||
[Export(typeof(ImageFormat))]
|
||||
public class K4Format : ImageFormat
|
||||
{
|
||||
public override string Tag { get { return "K4"; } }
|
||||
public override string Description { get { return "Toyo GSX image format"; } }
|
||||
public override uint Signature { get { return 0x0201344B; } } // 'K4'
|
||||
|
||||
public override ImageMetaData ReadMetaData (IBinaryStream file)
|
||||
{
|
||||
var header = file.ReadHeader (0x10);
|
||||
if (!header.AsciiEqual ("K4"))
|
||||
return null;
|
||||
if (header[2] != 1 || header[3] != 2)
|
||||
return null;
|
||||
return new K4MetaData {
|
||||
Width = header.ToUInt16 (4),
|
||||
Height = header.ToUInt16 (6),
|
||||
BPP = header[0xF],
|
||||
HasAlpha = header[0xB] != 0,
|
||||
FrameCount = header.ToUInt16 (0xC),
|
||||
};
|
||||
}
|
||||
|
||||
public override ImageData Read (IBinaryStream file, ImageMetaData info)
|
||||
{
|
||||
var meta = (K4MetaData)info;
|
||||
|
||||
return ImageData.Create (info, format, palette, pixels);
|
||||
}
|
||||
|
||||
public override void Write (Stream file, ImageData image)
|
||||
{
|
||||
throw new System.NotImplementedException ("K4Format.Write not implemented");
|
||||
}
|
||||
}
|
||||
}
|
62
Legacy/HyperWorks/ImageI24.cs
Normal file
62
Legacy/HyperWorks/ImageI24.cs
Normal file
@ -0,0 +1,62 @@
|
||||
//! \file ImageI24.cs
|
||||
//! \date 2019 Jun 22
|
||||
//! \brief HyperWorks image format.
|
||||
//
|
||||
// Copyright (C) 2019 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 System.Windows.Media;
|
||||
|
||||
namespace GameRes.Formats.HyperWorks
|
||||
{
|
||||
[Export(typeof(ImageFormat))]
|
||||
public class I24Format : ImageFormat
|
||||
{
|
||||
public override string Tag { get { return "I24"; } }
|
||||
public override string Description { get { return "HyperWorks image format"; } }
|
||||
public override uint Signature { get { return 0x41343249; } } // 'I24A'
|
||||
|
||||
public override ImageMetaData ReadMetaData (IBinaryStream file)
|
||||
{
|
||||
var header = file.ReadHeader (0x18);
|
||||
int bpp = header.ToInt16 (0x10);
|
||||
if (bpp != 24)
|
||||
return null;
|
||||
return new ImageMetaData {
|
||||
Width = header.ToUInt16 (0xC),
|
||||
Height = header.ToUInt16 (0xE),
|
||||
BPP = bpp,
|
||||
};
|
||||
}
|
||||
|
||||
public override ImageData Read (IBinaryStream file, ImageMetaData info)
|
||||
{
|
||||
return ImageData.Create (info, format, palette, pixels);
|
||||
}
|
||||
|
||||
public override void Write (Stream file, ImageData image)
|
||||
{
|
||||
throw new System.NotImplementedException ("I24Format.Write not implemented");
|
||||
}
|
||||
}
|
||||
}
|
@ -39,10 +39,17 @@ namespace GameRes.Formats.KApp
|
||||
public override string Description { get { return "KApp compressed image format"; } }
|
||||
public override uint Signature { get { return 0x6F6F746B; } } // 'ktool210'
|
||||
|
||||
public CgdFormat ()
|
||||
{
|
||||
Signatures = new uint[] { 0x6F6F746B, 0x65697073 };
|
||||
}
|
||||
|
||||
public override ImageMetaData ReadMetaData (IBinaryStream file)
|
||||
{
|
||||
var header = file.ReadHeader (0x18);
|
||||
if (!header.AsciiEqual ("ktool210") || header.ToInt32 (8) != 1)
|
||||
if (header.ToInt32 (8) != 1)
|
||||
return null;
|
||||
if (!header.AsciiEqual ("ktool210") && !header.AsciiEqual ("spiel100"))
|
||||
return null;
|
||||
uint offset = header.ToUInt32 (0x10) & 0x7FFFFFFF;
|
||||
return CgdMetaData.FromStream (file, offset);
|
||||
|
@ -103,6 +103,7 @@
|
||||
<Compile Include="FazeX\ImageFGP.cs" />
|
||||
<Compile Include="HillField\ImageIMA.cs" />
|
||||
<Compile Include="HillField\ImageIMG.cs" />
|
||||
<Compile Include="hmp\ImageALP.cs" />
|
||||
<Compile Include="KApp\ArcASD.cs" />
|
||||
<Compile Include="KApp\ImageCGD.cs" />
|
||||
<Compile Include="Kasane\ArcAR2.cs" />
|
||||
@ -226,6 +227,7 @@
|
||||
<Compile Include="Nekotaro\ArcNSC.cs" />
|
||||
<Compile Include="Nekotaro\ImageGCmp.cs" />
|
||||
<Compile Include="PlanTech\ArcPAC.cs" />
|
||||
<Compile Include="Zenos\ImagePNX.cs" />
|
||||
<Compile Include="Zone\ArcPKD.cs" />
|
||||
<Compile Include="Zone\ImageBM_.cs" />
|
||||
<None Include="app.config" />
|
||||
|
@ -27,6 +27,7 @@ using System;
|
||||
using System.ComponentModel.Composition;
|
||||
using System.IO;
|
||||
using System.Windows;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Media.Imaging;
|
||||
|
||||
namespace GameRes.Formats.Pochette
|
||||
@ -93,15 +94,21 @@ namespace GameRes.Formats.Pochette
|
||||
|
||||
BitmapSource BlendBaseLine (BitmapSource overlay, GdtMetaData meta)
|
||||
{
|
||||
string base_name = VFS.ChangeFileName (meta.FileName, meta.BaseLine+".gdt");
|
||||
string base_name = VFS.ChangeFileName (meta.FileName, meta.BaseLine);
|
||||
if (!VFS.FileExists (base_name))
|
||||
return overlay;
|
||||
{
|
||||
base_name += ".gdt";
|
||||
if (!VFS.FileExists (base_name))
|
||||
return overlay;
|
||||
}
|
||||
using (var base_file = VFS.OpenBinaryStream (base_name))
|
||||
{
|
||||
var base_info = ReadMetaData (base_file) as GdtMetaData;
|
||||
if (null == base_info)
|
||||
return overlay;
|
||||
var base_image = ReadBitmapSource (base_file, base_info);
|
||||
if (base_image.Format.BitsPerPixel < 24)
|
||||
base_image = new FormatConvertedBitmap (base_image, PixelFormats.Bgr32, null, 0);
|
||||
var canvas = new WriteableBitmap (base_image);
|
||||
int canvas_bpp = canvas.Format.BitsPerPixel;
|
||||
if (canvas_bpp != overlay.Format.BitsPerPixel)
|
||||
|
@ -32,5 +32,5 @@ using System.Runtime.InteropServices;
|
||||
// You can specify all the values or you can default the Build and Revision Numbers
|
||||
// by using the '*' as shown below:
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion ("1.0.10.196")]
|
||||
[assembly: AssemblyFileVersion ("1.0.10.196")]
|
||||
[assembly: AssemblyVersion ("1.0.10.198")]
|
||||
[assembly: AssemblyFileVersion ("1.0.10.198")]
|
||||
|
64
Legacy/Zenos/ImagePNX.cs
Normal file
64
Legacy/Zenos/ImagePNX.cs
Normal file
@ -0,0 +1,64 @@
|
||||
//! \file ImagePNX.cs
|
||||
//! \date 2022 Apr 14
|
||||
//! \brief Obfuscated PNG image.
|
||||
//
|
||||
// Copyright (C) 2022 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 System.Windows.Media;
|
||||
|
||||
namespace GameRes.Formats.Zenos
|
||||
{
|
||||
[Export(typeof(ImageFormat))]
|
||||
public class PnxFormat : PngFormat
|
||||
{
|
||||
public override string Tag { get { return "PNX/ZENOS"; } }
|
||||
public override string Description { get { return "Obfuscated PNG image"; } }
|
||||
public override uint Signature { get { return 0x584E5089; } }
|
||||
public override bool CanWrite { get { return false; } }
|
||||
|
||||
public override ImageMetaData ReadMetaData (IBinaryStream file)
|
||||
{
|
||||
using (var input = DeobfuscateStream (file))
|
||||
return base.ReadMetaData (input);
|
||||
}
|
||||
|
||||
public override ImageData Read (IBinaryStream file, ImageMetaData info)
|
||||
{
|
||||
using (var input = DeobfuscateStream (file))
|
||||
return base.Read (input, info);
|
||||
}
|
||||
|
||||
IBinaryStream DeobfuscateStream (IBinaryStream file)
|
||||
{
|
||||
var body = new StreamRegion (file.AsStream, 8, file.Length-8, true);
|
||||
var png = new PrefixStream (HeaderBytes, body);
|
||||
return new BinaryStream (png, file.Name);
|
||||
}
|
||||
|
||||
public override void Write (Stream file, ImageData image)
|
||||
{
|
||||
throw new System.NotImplementedException ("PnxFormat.Write not implemented");
|
||||
}
|
||||
}
|
||||
}
|
@ -8,8 +8,8 @@
|
||||
</dependentAssembly>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="System.Runtime.CompilerServices.Unsafe" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-6.0.0.0" newVersion="6.0.0.0" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-4.0.5.0" newVersion="4.0.5.0" />
|
||||
</dependentAssembly>
|
||||
</assemblyBinding>
|
||||
</runtime>
|
||||
<startup><supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6.1" /></startup></configuration>
|
||||
</configuration>
|
60
Legacy/hmp/ImageALP.cs
Normal file
60
Legacy/hmp/ImageALP.cs
Normal file
@ -0,0 +1,60 @@
|
||||
//! \file ImageALP.cs
|
||||
//! \date 2022 Apr 22
|
||||
//! \brief BeF bitmap mask
|
||||
//
|
||||
// Copyright (C) 2022 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 System.Windows.Media;
|
||||
|
||||
namespace GameRes.Formats.Hmp
|
||||
{
|
||||
[Export(typeof(ImageFormat))]
|
||||
[ExportMetadata("Priority", -1)]
|
||||
public class AlpFormat : ImageFormat
|
||||
{
|
||||
public override string Tag { get { return "ALP/BeF"; } }
|
||||
public override string Description { get { return "BeF bitmap mask format"; } }
|
||||
public override uint Signature { get { return 0; } }
|
||||
|
||||
public override ImageMetaData ReadMetaData (IBinaryStream file)
|
||||
{
|
||||
if (!file.Name.HasExtension (".alp") || file.Length != 0x25800)
|
||||
return null;
|
||||
return new ImageMetaData { Width = 320, Height = 480, BPP = 8 };
|
||||
}
|
||||
|
||||
public override ImageData Read (IBinaryStream file, ImageMetaData info)
|
||||
{
|
||||
var pixels = file.ReadBytes (0x25800);
|
||||
for (int i = 0; i < pixels.Length; ++i)
|
||||
pixels[i] = (byte)(pixels[i] * 0xFF / 0x40);
|
||||
return ImageData.Create (info, PixelFormats.Gray8, null, pixels);
|
||||
}
|
||||
|
||||
public override void Write (Stream file, ImageData image)
|
||||
{
|
||||
throw new System.NotImplementedException ("AlpFormat.Write not implemented");
|
||||
}
|
||||
}
|
||||
}
|
@ -9,11 +9,7 @@ use File::Spec;
|
||||
use File::Temp;
|
||||
|
||||
sub get_git_exe {
|
||||
my $user_app_data = Win32::GetFolderPath (Win32::CSIDL_LOCAL_APPDATA);
|
||||
my $git_glob = File::Spec->catfile ($user_app_data, 'GitHub', 'PortableGit_*', 'cmd', 'git.exe');
|
||||
my $git_path = glob ($git_glob);
|
||||
die "PortableGit not found\n" unless -x $git_path;
|
||||
return $git_path;
|
||||
return "git.exe";
|
||||
}
|
||||
|
||||
sub match_version {
|
||||
|
Loading…
Reference in New Issue
Block a user