using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.IO;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Runtime.CompilerServices;
using Microsoft.CSharp.RuntimeBinder;
using NIFLib.Enums;
using NIFLib.Nodes;
using Binder = Microsoft.CSharp.RuntimeBinder.Binder;
namespace NIFLib.Core
{
public class NiFile : IDisposable
{
private readonly BinaryReader _reader;
[CompilerGenerated]
[SuppressMessage("ReSharper", "InconsistentNaming")]
private static class O__11
{
///
/// The P__0
///
public static CallSite> p__0;
///
/// The P__1
///
public static CallSite> p__1;
///
/// The P__2
///
public static CallSite> p__2;
///
/// The P__3
///
public static CallSite> p__3;
///
/// The P__4
///
public static CallSite> p__4;
///
/// The P__5
///
public static CallSite> p__5;
///
/// The P__6
///
public static CallSite> p__6;
}
public const uint InvalidRef = 4294967295u;
public const string CmdTopLevelObject = "Top Level Object";
public const string CmdEndOfFile = "End Of File";
public NiHeader Header;
public NiFooter Footer;
public readonly Dictionary ObjectsByRef = new Dictionary();
public NifVersion Version => Header.Version;
public NiFile(string filePath) : this(new BinaryReader(File.OpenRead(filePath))) { }
public NiFile(BinaryReader reader)
{
_reader = reader;
Header = new NiHeader(this, reader);
ReadNiObjects();
Footer = new NiFooter(this, reader);
FixRefs();
}
private void ReadNiObjects()
{
var num = 0;
string text;
while (true)
{
if (Version >= NifVersion.VER_5_0_0_1)
{
if (Version <= NifVersion.VER_10_1_0_106 && _reader.ReadUInt32() != 0u)
{
break;
}
text = Header.BlockTypes[Header.BlockTypeIndex[num]].Value;
}
else
{
var num2 = _reader.ReadUInt32();
if (num2 > 30u || num2 < 6u)
{
goto IL_74;
}
text = new string(_reader.ReadChars((int)num2));
if (Header.Version < NifVersion.VER_3_3_0_13)
{
switch (text)
{
case "Top Level Object":
continue;
case "End Of File":
return;
}
}
}
uint key;
if (Version < NifVersion.VER_3_3_0_13)
{
key = _reader.ReadUInt32();
}
else
{
key = (uint)num;
}
var exprE7 = Type.GetType("Niflib." + text);
if (exprE7 == null)
{
goto Block_8;
}
var value = (NiObject)Activator.CreateInstance(exprE7, this, _reader);
ObjectsByRef.Add(key, value);
if (Version < NifVersion.VER_3_3_0_13) continue;
num++;
if (num >= Header.NumBlocks)
{
return;
}
}
throw new Exception("Check value is not zero! Invalid file?");
IL_74:
throw new Exception("Invalid object type string length!");
Block_8:
throw new NotImplementedException(text);
}
private void FixRefs()
{
// Fix Object Refs
foreach (var current in ObjectsByRef.Values)
{
FixRefs(current);
}
// Fix Footer Refs
foreach (var niRef in Footer.RootNodes)
{
niRef.SetRef(this);
}
}
[SuppressMessage("ReSharper", "InconsistentNaming")]
private void FixRefs(object obj)
{
var fields = obj.GetType().GetFields();
foreach (var fieldInfo in fields)
{
if (fieldInfo.FieldType.Name.Contains("NiRef"))
{
if (fieldInfo.FieldType.IsArray)
{
var enumerable = (IEnumerable)fieldInfo.GetValue(obj);
if (enumerable == null)
{
goto IL_303;
}
var enumerator = enumerable.GetEnumerator();
try
{
while (enumerator.MoveNext())
{
var current = enumerator.Current;
if (O__11.p__0 == null)
{
O__11.p__0 = CallSite>.Create(Binder.InvokeMember(CSharpBinderFlags.ResultDiscarded, "SetRef", null, typeof(NiFile), new[]
{
CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null),
CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.UseCompileTimeType, null)
}));
}
O__11.p__0.Target(O__11.p__0, current, this);
if (fieldInfo.Name == "Children")
{
if (O__11.p__2 == null)
{
O__11.p__2 = CallSite>.Create(Binder.UnaryOperation(CSharpBinderFlags.None, ExpressionType.IsTrue, typeof(NiFile), new[]
{
CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null)
}));
}
var arg_16A_0 = O__11.p__2.Target;
CallSite arg_16A_1 = O__11.p__2;
if (O__11.p__1 == null)
{
O__11.p__1 = CallSite>.Create(Binder.InvokeMember(CSharpBinderFlags.None, "IsValid", null, typeof(NiFile), new[]
{
CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null)
}));
}
if (arg_16A_0(arg_16A_1, O__11.p__1.Target(O__11.p__1, current)))
{
if (O__11.p__3 == null)
{
O__11.p__3 = CallSite>.Create(Binder.GetMember(CSharpBinderFlags.None, "Object", typeof(NiFile), new[]
{
CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null)
}));
}
if (!(O__11.p__3.Target(O__11.p__3, current) is NiAVObject expr_1C2))
{
throw new Exception("no child");
}
expr_1C2.Parent = (NiNode)obj;
}
}
}
goto IL_303;
}
finally
{
if (enumerator is IDisposable disposable)
{
disposable.Dispose();
}
}
}
var value = fieldInfo.GetValue(obj);
if (O__11.p__5 == null)
{
O__11.p__5 = CallSite>.Create(Binder.UnaryOperation(CSharpBinderFlags.None, ExpressionType.IsTrue, typeof(NiFile), new[]
{
CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null)
}));
}
var arg_2A0_0 = O__11.p__5.Target;
CallSite arg_2A0_1 = O__11.p__5;
if (O__11.p__4 == null)
{
O__11.p__4 = CallSite>.Create(Binder.BinaryOperation(CSharpBinderFlags.None, ExpressionType.Equal, typeof(NiFile), new[]
{
CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null),
CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.Constant, null)
}));
}
if (!arg_2A0_0(arg_2A0_1, O__11.p__4.Target(O__11.p__4, value, null)))
{
if (O__11.p__6 == null)
{
O__11.p__6 = CallSite>.Create(Binder.InvokeMember(CSharpBinderFlags.ResultDiscarded, "SetRef", null, typeof(NiFile), new[]
{
CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null),
CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.UseCompileTimeType, null)
}));
}
O__11.p__6.Target(O__11.p__6, value, this);
}
}
IL_303:;
}
}
public NiAVObject FindRoot()
{
var niAvObject = (from obj in ObjectsByRef.Values.OfType()
select obj).FirstOrDefault();
if (niAvObject == null)
{
return null;
}
while (niAvObject.Parent != null)
{
niAvObject = niAvObject.Parent;
}
return niAvObject;
}
public void PrintNifTree()
{
var niAvObject = FindRoot();
if (niAvObject == null)
{
Console.WriteLine("No Root!");
return;
}
const int depth = 0;
PrintNifNode(niAvObject, depth);
}
private static void PrintNifNode(NiObjectNET root, int depth)
{
var text = string.Empty;
for (var i = 0; i < depth; i++)
{
text += "*";
}
text += " ";
Console.WriteLine(text + " " + root.Name);
if (!(root is NiNode niNode)) return;
var children = niNode.Children;
foreach (var niRef in children)
{
if (niRef.IsValid())
{
PrintNifNode(niRef.Object, depth + 1);
}
}
}
public void Dispose()
{
_reader?.Dispose();
}
}
}