mirror of
https://github.com/crskycode/GARbro.git
synced 2024-12-24 20:04:13 +08:00
(UnityFS): deserialize textures with "StreamingInfo".
This commit is contained in:
parent
d6f00029fd
commit
740a604c50
@ -99,7 +99,7 @@ namespace GameRes.Formats.Unity
|
||||
using (var input = new BinMemoryStream (index_data))
|
||||
index.Parse (input);
|
||||
var dir = index.LoadObjects();
|
||||
return new UnityBundle (file, this, dir, index.Segments);
|
||||
return new UnityBundle (file, this, dir, index.Segments, index.Bundles);
|
||||
}
|
||||
|
||||
public override Stream OpenEntry (ArcFile arc, Entry entry)
|
||||
@ -126,12 +126,37 @@ namespace GameRes.Formats.Unity
|
||||
return base.OpenImage (arc, entry);
|
||||
var uarc = (UnityBundle)arc;
|
||||
var obj = aent.AssetObject;
|
||||
Stream input = new BundleStream (uarc.File, uarc.Segments);
|
||||
input = new StreamRegion (input, obj.Offset, obj.Size);
|
||||
var bundles = new BundleStream (uarc.File, uarc.Segments);
|
||||
var input = new StreamRegion (bundles, obj.Offset, obj.Size);
|
||||
var reader = new AssetReader (input, entry.Name);
|
||||
reader.SetupReaders (obj.Asset);
|
||||
var tex = new Texture2D();
|
||||
Texture2D tex = null;
|
||||
if (obj.Asset.Tree.TypeTrees.ContainsKey (obj.TypeId))
|
||||
{
|
||||
var type = obj.Asset.Tree.TypeTrees[obj.TypeId];
|
||||
if (type.Children.Any (t => t.Type == "StreamingInfo"))
|
||||
{
|
||||
var fields = obj.Deserialize (reader);
|
||||
tex = new Texture2D();
|
||||
tex.Import (fields);
|
||||
var info = fields["m_StreamData"] as StreamingInfo;
|
||||
if (info != null)
|
||||
{
|
||||
var bundle = uarc.Bundles.FirstOrDefault (b => VFS.IsPathEqualsToFileName (info.Path, b.Name));
|
||||
if (bundle != null)
|
||||
{
|
||||
tex.m_DataLength = (int)info.Size;
|
||||
input = new StreamRegion (bundles, bundle.Offset+info.Offset, info.Size);
|
||||
reader = new AssetReader (input, entry.Name);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (null == tex)
|
||||
{
|
||||
tex = new Texture2D();
|
||||
tex.Load (reader);
|
||||
}
|
||||
return new Texture2DDecoder (tex, reader);
|
||||
}
|
||||
|
||||
@ -166,11 +191,13 @@ namespace GameRes.Formats.Unity
|
||||
internal class UnityBundle : ArcFile
|
||||
{
|
||||
public readonly List<BundleSegment> Segments;
|
||||
public readonly List<BundleEntry> Bundles;
|
||||
|
||||
public UnityBundle (ArcView arc, ArchiveFormat impl, ICollection<Entry> dir, List<BundleSegment> segments)
|
||||
public UnityBundle (ArcView arc, ArchiveFormat impl, ICollection<Entry> dir, List<BundleSegment> segments, List<BundleEntry> bundles)
|
||||
: base (arc, impl, dir)
|
||||
{
|
||||
Segments = segments;
|
||||
Bundles = bundles;
|
||||
}
|
||||
}
|
||||
|
||||
@ -193,6 +220,7 @@ namespace GameRes.Formats.Unity
|
||||
List<BundleEntry> m_bundles;
|
||||
|
||||
public List<BundleSegment> Segments { get { return m_segments; } }
|
||||
public List<BundleEntry> Bundles { get { return m_bundles; } }
|
||||
|
||||
public AssetDeserializer (ArcView file, long data_offset)
|
||||
{
|
||||
@ -239,8 +267,10 @@ namespace GameRes.Formats.Unity
|
||||
{
|
||||
foreach (BundleEntry bundle in m_bundles)
|
||||
{
|
||||
if (bundle.Name.EndsWith (".resource"))
|
||||
if (bundle.Name.HasAnyOfExtensions (".resource", ".resS"))
|
||||
continue;
|
||||
var res_s_name = bundle.Name + ".resS";
|
||||
var res_s = m_bundles.FirstOrDefault (b => b.Name == res_s_name);
|
||||
using (var asset_stream = new StreamRegion (stream, bundle.Offset, bundle.Size, true))
|
||||
using (var reader = new AssetReader (asset_stream, bundle.Name))
|
||||
{
|
||||
|
@ -28,9 +28,11 @@
|
||||
//
|
||||
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using GameRes.Utility;
|
||||
|
||||
@ -209,6 +211,71 @@ namespace GameRes.Formats.Unity
|
||||
{
|
||||
return string.Format ("<{0} {1}>", Type, ClassId);
|
||||
}
|
||||
|
||||
public IDictionary Deserialize (AssetReader input)
|
||||
{
|
||||
var type_tree = Asset.Tree.TypeTrees;
|
||||
if (!type_tree.ContainsKey (TypeId))
|
||||
return null;
|
||||
var type_map = new Hashtable();
|
||||
var type = type_tree[TypeId];
|
||||
foreach (var node in type.Children)
|
||||
{
|
||||
type_map[node.Name] = DeserializeType (input, node);
|
||||
}
|
||||
return type_map;
|
||||
}
|
||||
|
||||
object DeserializeType (AssetReader input, TypeTree node)
|
||||
{
|
||||
object obj = null;
|
||||
if (node.IsArray)
|
||||
{
|
||||
int size = input.ReadInt32();
|
||||
var data_field = node.Children.FirstOrDefault (n => n.Name == "data");
|
||||
if (data_field != null)
|
||||
{
|
||||
if ("TypelessData" == node.Type)
|
||||
obj = input.ReadBytes (size * data_field.Size);
|
||||
else
|
||||
obj = DeserializeArray (input, size, data_field);
|
||||
}
|
||||
}
|
||||
else if (node.Size < 0)
|
||||
{
|
||||
if (node.Type == "string")
|
||||
{
|
||||
obj = input.ReadString();
|
||||
if (node.Children[0].IsAligned)
|
||||
input.Align();
|
||||
}
|
||||
else if (node.Type == "StreamingInfo")
|
||||
{
|
||||
var info = new StreamingInfo();
|
||||
info.Load (input);
|
||||
obj = info;
|
||||
}
|
||||
else
|
||||
throw new NotImplementedException ("Unknown class encountered in asset deserialzation.");
|
||||
}
|
||||
else if ("int" == node.Type)
|
||||
obj = input.ReadInt32();
|
||||
else if ("bool" == node.Type)
|
||||
obj = input.ReadBool();
|
||||
else
|
||||
input.Position += node.Size;
|
||||
if (node.IsAligned)
|
||||
input.Align();
|
||||
return obj;
|
||||
}
|
||||
|
||||
object[] DeserializeArray (AssetReader input, int length, TypeTree elem)
|
||||
{
|
||||
var array = new object[length];
|
||||
for (int i = 0; i < length; ++i)
|
||||
array[i] = DeserializeType (input, elem);
|
||||
return array;
|
||||
}
|
||||
}
|
||||
|
||||
internal class TypeTree
|
||||
@ -226,6 +293,8 @@ namespace GameRes.Formats.Unity
|
||||
|
||||
public IList<TypeTree> Children { get { return m_children; } }
|
||||
|
||||
public bool IsAligned { get { return (Flags & 0x4000) != 0; } }
|
||||
|
||||
static readonly string Null = "(null)";
|
||||
static readonly Lazy<byte[]> StringsDat = new Lazy<byte[]> (() => LoadResource ("strings.dat"));
|
||||
|
||||
|
@ -39,6 +39,8 @@ namespace GameRes.Formats.Unity
|
||||
IBinaryStream m_input;
|
||||
int m_format;
|
||||
|
||||
const int MaxStringLength = 0x100000;
|
||||
|
||||
public Stream Source { get { return m_input.AsStream; } }
|
||||
public int Format { get { return m_format; } }
|
||||
public long Position {
|
||||
@ -144,6 +146,8 @@ namespace GameRes.Formats.Unity
|
||||
int length = ReadInt32();
|
||||
if (0 == length)
|
||||
return string.Empty;
|
||||
if (length < 0 || length > MaxStringLength)
|
||||
throw new InvalidFormatException();
|
||||
var bytes = ReadBytes (length);
|
||||
return Encoding.UTF8.GetString (bytes);
|
||||
}
|
||||
|
@ -24,6 +24,7 @@
|
||||
//
|
||||
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.IO;
|
||||
using System.Windows.Media;
|
||||
using GameRes.Formats.DirectDraw;
|
||||
@ -100,6 +101,20 @@ namespace GameRes.Formats.Unity
|
||||
{
|
||||
m_Data = reader.ReadBytes (m_DataLength);
|
||||
}
|
||||
|
||||
public void Import (IDictionary fields)
|
||||
{
|
||||
m_Name = fields["m_Name"] as string ?? "";
|
||||
m_Width = (int)(fields["m_Width"] ?? 0);
|
||||
m_Height = (int)(fields["m_Height"] ?? 0);
|
||||
m_CompleteImageSize = (int)(fields["m_CompleteImageSize"] ?? 0);
|
||||
m_TextureFormat = (TextureFormat)(fields["m_TextureFormat"] ?? 0);
|
||||
m_MipCount = (int)(fields["m_MipCount"] ?? 0);
|
||||
m_ImageCount = (int)(fields["m_ImageCount"] ?? 0);
|
||||
m_TextureDimension = (int)(fields["m_TextureDimension"] ?? 0);
|
||||
m_IsReadable = (bool)(fields["m_IsReadable"] ?? false);
|
||||
m_Data = fields["image data"] as byte[] ?? Array.Empty<byte>();
|
||||
}
|
||||
}
|
||||
|
||||
internal class Texture2DDecoder : IImageDecoder
|
||||
|
Loading…
x
Reference in New Issue
Block a user