Handle invalid StreamingInfo

* Resolves #1769
This commit is contained in:
ds5678 2025-05-07 14:11:34 -07:00
parent 0a7bb5095a
commit f9ba7978fe
5 changed files with 110 additions and 79 deletions

View File

@ -23,64 +23,62 @@ namespace AssetRipper.Export.UnityProjects.Project
private bool ExportMesh(IExportContainer container, string filePath, string dirPath, IMesh mesh, FileSystem fileSystem) private bool ExportMesh(IExportContainer container, string filePath, string dirPath, IMesh mesh, FileSystem fileSystem)
{ {
if (!mesh.Has_StreamData())
{
return base.ExportInner(container, filePath, dirPath, fileSystem);
}
bool result; bool result;
if (mesh.Has_StreamData()) mesh.StreamData.GetValues(out Utf8String path, out ulong offset, out uint size);
{ if (mesh.VertexData.Data.Length != 0)
ulong offset = mesh.StreamData.GetOffset();
Utf8String path = mesh.StreamData.Path;
uint size = mesh.StreamData.Size;
if (mesh.VertexData is not null && mesh.VertexData.Data.Length == 0 && mesh.StreamData.IsSet())
{
mesh.VertexData.Data = mesh.StreamData.GetContent(mesh.Collection);
mesh.StreamData.ClearValues();
result = base.ExportInner(container, filePath, dirPath, fileSystem);
mesh.VertexData.Data = Array.Empty<byte>();
}
else
{ {
mesh.StreamData.ClearValues(); mesh.StreamData.ClearValues();
result = base.ExportInner(container, filePath, dirPath, fileSystem); result = base.ExportInner(container, filePath, dirPath, fileSystem);
} }
mesh.StreamData.SetOffset(offset);
mesh.StreamData.Path = path;
mesh.StreamData.Size = size;
}
else else
{ {
result = base.ExportInner(container, filePath, dirPath, fileSystem); byte[]? data = mesh.StreamData.GetContent(mesh.Collection);
if (data.IsNullOrEmpty())
{
return false;
} }
mesh.VertexData.Data = data;
mesh.StreamData.ClearValues();
result = base.ExportInner(container, filePath, dirPath, fileSystem);
mesh.VertexData.Data = [];
}
mesh.StreamData.SetValues(path, offset, size);
return result; return result;
} }
private bool ExportTexture(IExportContainer container, string filePath, string dirPath, IImageTexture texture, FileSystem fileSystem) private bool ExportTexture(IExportContainer container, string filePath, string dirPath, IImageTexture texture, FileSystem fileSystem)
{ {
if (!texture.Has_StreamData_C189())
{
return base.ExportInner(container, filePath, dirPath, fileSystem);
}
bool result; bool result;
if (texture.Has_StreamData_C189()) texture.StreamData_C189.GetValues(out Utf8String path, out ulong offset, out uint size);
{ if (texture.ImageData_C189.Length != 0)
ulong offset = texture.StreamData_C189.GetOffset();
Utf8String path = texture.StreamData_C189.Path;
uint size = texture.StreamData_C189.Size;
if (texture.ImageData_C189.Length == 0 && texture.StreamData_C189.IsSet())
{
texture.ImageData_C189 = texture.StreamData_C189.GetContent(texture.Collection);
texture.StreamData_C189.ClearValues();
result = base.ExportInner(container, filePath, dirPath, fileSystem);
texture.ImageData_C189 = Array.Empty<byte>();
}
else
{ {
texture.StreamData_C189.ClearValues(); texture.StreamData_C189.ClearValues();
result = base.ExportInner(container, filePath, dirPath, fileSystem); result = base.ExportInner(container, filePath, dirPath, fileSystem);
} }
texture.StreamData_C189.SetOffset(offset);
texture.StreamData_C189.Path = path;
texture.StreamData_C189.Size = size;
}
else else
{ {
result = base.ExportInner(container, filePath, dirPath, fileSystem); byte[]? data = texture.StreamData_C189.GetContent(texture.Collection);
if (data.IsNullOrEmpty())
{
return false;
} }
texture.ImageData_C189 = data;
texture.StreamData_C189.ClearValues();
result = base.ExportInner(container, filePath, dirPath, fileSystem);
texture.ImageData_C189 = [];
}
texture.StreamData_C189.SetValues(path, offset, size);
return result; return result;
} }

View File

@ -26,7 +26,7 @@ public static class CubemapArrayExtensions
} }
else else
{ {
return Array.Empty<byte>(); return [];
} }
} }

View File

@ -131,7 +131,7 @@ namespace AssetRipper.SourceGenerated.Extensions
} }
else else
{ {
return mesh.VertexData?.Data ?? Array.Empty<byte>(); return mesh.VertexData?.Data ?? [];
} }
} }

View File

@ -6,37 +6,71 @@ namespace AssetRipper.SourceGenerated.Extensions
{ {
public static class StreamedResourceExtensions public static class StreamedResourceExtensions
{ {
public static bool CheckIntegrity(this IStreamedResource streamedResource, AssetCollection file) internal static bool CheckIntegrity(Utf8String? path, ulong offset, ulong size, AssetCollection collection)
{ {
if (!streamedResource.IsSet()) if (Utf8String.IsNullOrEmpty(path))
{ {
return true; return true;
} }
if (streamedResource.Size == 0)
if (offset > long.MaxValue || size > long.MaxValue || offset + size > long.MaxValue)
{ {
// I think they read data by its type for this verison, so I can't even export raw data :/
return false; return false;
} }
return file.Bundle.ResolveResource(streamedResource.Source.String) != null; if (size == 0)
{
// Data might be read by its type for this verison, so we can't even export raw data.
return false;
}
ResourceFile? file = collection.Bundle.ResolveResource(path.String);
if (file == null)
{
return false;
}
return file.Stream.Length <= unchecked((long)(offset + size));
}
internal static byte[]? GetContent(Utf8String? path, ulong offset, ulong size, AssetCollection collection)
{
if (Utf8String.IsNullOrEmpty(path))
{
return null;
}
if (offset > long.MaxValue || size > long.MaxValue || offset + size > long.MaxValue)
{
return null;
}
if (size == 0)
{
// Data might be read by its type for this verison, so we can't even export raw data.
return null;
}
ResourceFile? file = collection.Bundle.ResolveResource(path.String);
if (file == null)
{
return null;
}
byte[] data = new byte[size];
file.Stream.Position = (long)offset;
file.Stream.ReadExactly(data);
return data;
}
public static bool CheckIntegrity(this IStreamedResource streamedResource, AssetCollection collection)
{
return CheckIntegrity(streamedResource.Source, streamedResource.Offset, streamedResource.Size, collection);
} }
public static byte[]? GetContent(this IStreamedResource streamedResource, AssetCollection file) public static byte[]? GetContent(this IStreamedResource streamedResource, AssetCollection file)
{ {
ResourceFile? res = file.Bundle.ResolveResource(streamedResource.Source.String); return GetContent(streamedResource.Source, streamedResource.Offset, streamedResource.Size, file);
if (res == null)
{
return null;
}
if (streamedResource.Size <= 0 || streamedResource.Offset > long.MaxValue)
{
return null;
}
byte[] data = new byte[streamedResource.Size];
res.Stream.Position = (long)streamedResource.Offset;
res.Stream.ReadExactly(data);
return data;
} }
public static bool TryGetContent(this IStreamedResource streamedResource, AssetCollection file, [NotNullWhen(true)] out byte[]? data) public static bool TryGetContent(this IStreamedResource streamedResource, AssetCollection file, [NotNullWhen(true)] out byte[]? data)
@ -45,6 +79,6 @@ namespace AssetRipper.SourceGenerated.Extensions
return !data.IsNullOrEmpty(); return !data.IsNullOrEmpty();
} }
public static bool IsSet(this IStreamedResource streamedResource) => !string.IsNullOrEmpty(streamedResource.Source?.String); public static bool IsSet(this IStreamedResource streamedResource) => !Utf8String.IsNullOrEmpty(streamedResource.Source);
} }
} }

View File

@ -1,6 +1,4 @@
using AssetRipper.Assets.Collections; using AssetRipper.Assets.Collections;
using AssetRipper.IO.Files.ResourceFiles;
using AssetRipper.Primitives;
using AssetRipper.SourceGenerated.Subclasses.StreamingInfo; using AssetRipper.SourceGenerated.Subclasses.StreamingInfo;
namespace AssetRipper.SourceGenerated.Extensions namespace AssetRipper.SourceGenerated.Extensions
@ -11,25 +9,12 @@ namespace AssetRipper.SourceGenerated.Extensions
public static bool CheckIntegrity(this IStreamingInfo streamingInfo, AssetCollection file) public static bool CheckIntegrity(this IStreamingInfo streamingInfo, AssetCollection file)
{ {
if (!streamingInfo.IsSet()) return StreamedResourceExtensions.CheckIntegrity(streamingInfo.Path, streamingInfo.GetOffset(), streamingInfo.Size, file);
{
return true;
}
return file.Bundle.ResolveResource(streamingInfo.Path.String) != null;
} }
public static byte[] GetContent(this IStreamingInfo streamingInfo, AssetCollection file) public static byte[] GetContent(this IStreamingInfo streamingInfo, AssetCollection file)
{ {
ResourceFile? res = file.Bundle.ResolveResource(streamingInfo.Path.String); return StreamedResourceExtensions.GetContent(streamingInfo.Path, streamingInfo.GetOffset(), streamingInfo.Size, file) ?? [];
if (res == null)
{
return Array.Empty<byte>();
}
byte[] data = new byte[streamingInfo.Size];
res.Stream.Position = (long)streamingInfo.GetOffset();
res.Stream.ReadExactly(data);
return data;
} }
public static ulong GetOffset(this IStreamingInfo streamingInfo) public static ulong GetOffset(this IStreamingInfo streamingInfo)
@ -63,5 +48,19 @@ namespace AssetRipper.SourceGenerated.Extensions
streamingInfo.Path = Utf8String.Empty; streamingInfo.Path = Utf8String.Empty;
streamingInfo.Size = default; streamingInfo.Size = default;
} }
public static void GetValues(this IStreamingInfo streamingInfo, out Utf8String path, out ulong offset, out uint size)
{
path = streamingInfo.Path;
offset = streamingInfo.GetOffset();
size = streamingInfo.Size;
}
public static void SetValues(this IStreamingInfo streamingInfo, Utf8String path, ulong offset, uint size)
{
streamingInfo.Path = path;
streamingInfo.SetOffset(offset);
streamingInfo.Size = size;
}
} }
} }