using FSO.Files.Utils; using System; using System.Collections.Generic; using System.IO; namespace FSO.Files.Formats.IFF.Chunks { public class TREE : IffChunk { public static TREE GenerateEmpty(BHAV bhav) { var result = new TREE(); result.ChunkLabel = ""; result.ChunkID = bhav.ChunkID; result.AddedByPatch = true; result.ChunkProcessed = true; result.RuntimeInfo = ChunkRuntimeState.Modified; result.ChunkType = "TREE"; result.CorrectConnections(bhav); return result; /* var additionID = bhav.Instructions.Length; Func resolveTrueFalse = (byte pointer) => { switch (pointer) { case 253: return -1; case 255: //generate false case 254: //generate true } if (pointer == 255) return -1; else if (pointer == 2) }; //make an entry for each instruction. positions and sizes don't matter - we have a runtime flag to indicate they are not valid for (int i=0; i Entries = new List(); public int PrimitiveCount => Entries.FindLastIndex(x => x.Type == TREEBoxType.Primitive) + 1; //runtime public uint TreeVersion = 0; public override void Read(IffFile iff, Stream stream) { using (var io = IoBuffer.FromStream(stream, ByteOrder.LITTLE_ENDIAN)) { var zero = io.ReadInt32(); var version = io.ReadInt32(); if (version > 1) throw new Exception("Unexpected TREE version: " + version); string magic = io.ReadCString(4); //HBGN if (magic != "EERT") throw new Exception("Magic number should be 'EERT', got " + magic); var entryCount = io.ReadInt32(); Entries.Clear(); for (int i=0; i= after) box.InternalID += (short)delta; if (box.TruePointer >= after) box.TruePointer += (short)delta; if (box.FalsePointer >= after) box.FalsePointer += (short)delta; } } public void CorrectConnections(BHAV bhav) { //make sure there are enough primitives for the bhav var realPrimCount = bhav.Instructions.Length; var treePrimCount = Entries.FindLastIndex(x => x.Type == TREEBoxType.Primitive) + 1; ApplyPointerDelta(realPrimCount-treePrimCount, treePrimCount); if (realPrimCount > treePrimCount) { //add new treeboxes for (int i=treePrimCount; i realPrimCount) { //remove treeboxes for (int i=treePrimCount; i>realPrimCount; i--) { Entries.RemoveAt(i-1); } } //make sure connections for each of the primitives match the BHAV //if they don't, reconnect them or generate new boxes (true/false endpoints, maybe gotos in future) for (int i=0; i= Entries.Count) return null; return Entries[pointer]; } } public class TREEBox { //runtime public short InternalID = -1; public bool PosisionInvalid; //forces a regeneration of position using the default tree algorithm public TREE Parent; public byte TrueID { get { switch (Type) { case TREEBoxType.Primitive: return (byte)InternalID; case TREEBoxType.Goto: return LabelTrueID(new HashSet()); case TREEBoxType.Label: return 253; //arrows cannot point to a label case TREEBoxType.True: return 254; case TREEBoxType.False: return 255; } return 253; } } public byte LabelTrueID(HashSet visited) { if (Type != TREEBoxType.Goto) return TrueID; if (visited.Contains(InternalID)) return 253; //error visited.Add(InternalID); return Parent?.GetBox(Parent.GetBox(TruePointer)?.TruePointer ?? -1)?.LabelTrueID(visited) ?? 253; } //data public TREEBoxType Type; public ushort Unknown; public short Width; public short Height; public short X; public short Y; public short CommentSize = 0x10; public short TruePointer = -1; public short Special; //0 or -1... unknown. public int FalsePointer = -1; public string Comment = ""; public int TrailingZero = 0; public TREEBox(TREE parent) { Parent = parent; } public void Read(IoBuffer io, int version) { Type = (TREEBoxType)io.ReadUInt16(); Unknown = io.ReadUInt16(); Width = io.ReadInt16(); Height = io.ReadInt16(); X = io.ReadInt16(); Y = io.ReadInt16(); CommentSize = io.ReadInt16(); TruePointer = io.ReadInt16(); Special = io.ReadInt16(); FalsePointer = io.ReadInt32(); Comment = io.ReadNullTerminatedString(); if (Comment.Length % 2 == 0) io.ReadByte(); //padding to 2 byte align if (version > 0) TrailingZero = io.ReadInt32(); if (!Enum.IsDefined(typeof(TREEBoxType), Type)) throw new Exception("Unexpected TREE box type: " + Type.ToString()); if (Special < -1 || Special > 0) throw new Exception("Unexpected TREE special: " + Special); if (Unknown != 0) throw new Exception("Unexpected Unknown: " + Unknown); if (TrailingZero != 0) Console.WriteLine("Unexpected TrailingZero: " + TrailingZero); } public void Write(IoWriter io) { io.WriteUInt16((ushort)Type); io.WriteUInt16(Unknown); io.WriteInt16(Width); io.WriteInt16(Height); io.WriteInt16(X); io.WriteInt16(Y); io.WriteInt16(CommentSize); io.WriteInt16(TruePointer); io.WriteInt16(Special); io.WriteInt32(FalsePointer); io.WriteCString(Comment); if (Comment.Length % 2 == 0) io.WriteByte(0xCD); //padding to 2 byte align io.WriteInt32(TrailingZero); } public override string ToString() { return Type.ToString() + " (" + TruePointer + ((FalsePointer == -1) ? "" : ("/"+FalsePointer)) + "): " + Comment; } } public enum TREEBoxType : ushort { Primitive = 0, True = 1, False = 2, Comment = 3, Label = 4, Goto = 5 //no comment size, roughly primitive sized (180, 48), pointer goes to Label } }