Esempio n. 1
0
        private static bool TryDoFlowScriptDisassembly()
        {
            // load binary file
            Logger.Info("Loading binary FlowScript file...");

            FlowScriptBinary script = null;
            var format = GetFlowScriptFormatVersion();

            if (!TryPerformAction("Failed to load flow script from file.", () =>
            {
                script = FlowScriptBinary.FromFile(InputFilePath, (BinaryFormatVersion)format);
            }))
            {
                return(false);
            }

            Logger.Info("Disassembling FlowScript...");
            if (!TryPerformAction("Failed to disassemble flow script to file.", () =>
            {
                var disassembler = new FlowScriptBinaryDisassembler(OutputFilePath);
                disassembler.Disassemble(script);
                disassembler.Dispose();
            }))
            {
                return(false);
            }

            return(true);
        }
        private void FromFile_ResultNotNullAndFormatIsEqualToParameter(BinaryFormatVersion version, BinaryFormatVersion actualVersion)
        {
            var script = FlowScriptBinary.FromFile($"TestResources\\{actualVersion}.bf", version);

            Assert.IsNotNull(script, "Script object should not be null");
            Assert.AreEqual(actualVersion, script.FormatVersion);
        }
Esempio n. 3
0
        public void WriteBinary(FlowScriptBinary binary)
        {
            WriteHeader(ref binary.mHeader);
            WriteSectionHeaders(binary.mSectionHeaders);
            for (int i = 0; i < binary.mSectionHeaders.Length; i++)
            {
                ref var sectionHeader = ref binary.mSectionHeaders[i];

                switch (sectionHeader.SectionType)
                {
                case BinarySectionType.ProcedureLabelSection:
                    WriteLabelSection(ref sectionHeader, binary.mProcedureLabelSection);
                    break;

                case BinarySectionType.JumpLabelSection:
                    WriteLabelSection(ref sectionHeader, binary.mJumpLabelSection);
                    break;

                case BinarySectionType.TextSection:
                    WriteTextSection(ref sectionHeader, binary.mTextSection);
                    break;

                case BinarySectionType.MessageScriptSection:
                    WriteMessageScriptSection(ref sectionHeader, binary.mMessageScriptSection);
                    break;

                case BinarySectionType.StringSection:
                    WriteStringSection(ref sectionHeader, binary.mStringSection);
                    break;

                default:
                    throw new Exception("Unknown section type");
                }
            }
        public void DisassembleTest()
        {
            var script = FlowScriptBinary.FromFile("TestResources\\Version1.bf");

            using (var disassembler = new FlowScriptBinaryDisassembler(new StringWriter()))
                disassembler.Disassemble(script);
        }
        private void DisassembleToFileTestBase(string path)
        {
            var script = FlowScriptBinary.FromFile(path, BinaryFormatVersion.Unknown);

            using (var disassembler = new FlowScriptBinaryDisassembler(Path.ChangeExtension(path, "asm")))
                disassembler.Disassemble(script);
        }
Esempio n. 6
0
        public void Disassemble(FlowScriptBinary script)
        {
            mScript           = script ?? throw new ArgumentNullException(nameof(script));
            mInstructionIndex = 0;

            WriteDisassembly();
        }
        public void FromFileTest_Batch()
        {
            foreach (var path in Directory.EnumerateFiles("TestResources\\Batch\\", "*.bf"))
            {
                var script = FlowScriptBinary.FromFile(path, BinaryFormatVersion.Version3BigEndian);

                Assert.IsNotNull(script);
            }
        }
        public void FromStreamTest()
        {
            using (var fileStream = File.OpenRead("TestResources\\Version3BigEndian.bf"))
            {
                var script = FlowScriptBinary.FromStream(fileStream, BinaryFormatVersion.Version3BigEndian);

                Assert.IsNotNull(script);
                Assert.AreEqual(BinaryFormatVersion.Version3BigEndian, script.FormatVersion);
            }
        }
        public void FromBinary_ContentsShouldMatchThatOfBinary_Version3BigEndian()
        {
            var binary = FlowScriptBinary.FromFile("TestResources\\Version3BigEndian.bf", BinaryFormatVersion.Version3BigEndian);
            var script = FlowScript.FromBinary(binary);

            Assert.AreEqual(script.UserId, binary.Header.UserId);

            // Compare label names
            for (int i = 0; i < script.Procedures.Count; i++)
            {
                Assert.AreEqual(binary.ProcedureLabelSection[i].Name, script.Procedures[i].Name);
            }

            /*
             * for ( int i = 0; i < script.JumpLabels.Count; i++ )
             * {
             *  Assert.AreEqual( binary.JumpLabelSection[i].Name, script.JumpLabels[i].Name );
             * }
             */

            // Compare instructions
            int binaryIndex = 0;

            foreach (var instruction in script.EnumerateInstructions())
            {
                var binaryInstruction = binary.TextSection[binaryIndex++];
                Assert.AreEqual(binaryInstruction.Opcode, instruction.Opcode);

                if (instruction.Operand != null)
                {
                    switch (instruction.Operand.Kind)
                    {
                    case Operand.ValueKind.Int16:
                        if (instruction.Opcode != Opcode.IF && instruction.Opcode != Opcode.GOTO)
                        {
                            Assert.AreEqual(binaryInstruction.OperandShort, instruction.Operand.Int16Value);
                        }
                        break;

                    case Operand.ValueKind.Int32:
                        Assert.AreEqual(binary.TextSection[binaryIndex++].OperandInt, instruction.Operand.Int32Value);
                        break;

                    case Operand.ValueKind.Single:
                        Assert.AreEqual(binary.TextSection[binaryIndex++].OperandFloat, instruction.Operand.SingleValue);
                        break;

                    case Operand.ValueKind.String:
                        break;
                    }
                }
            }
        }
        public FlowScriptBinary ReadBinary()
        {
            FlowScriptBinary instance = new FlowScriptBinary
            {
                mHeader = ReadHeader()
            };

            instance.mSectionHeaders = ReadSectionHeaders(ref instance.mHeader);

            for (int i = 0; i < instance.mSectionHeaders.Length; i++)
            {
                ref var sectionHeader = ref instance.mSectionHeaders[i];

                switch (sectionHeader.SectionType)
                {
                case BinarySectionType.ProcedureLabelSection:
                    instance.mProcedureLabelSection = ReadLabelSection(ref sectionHeader);
                    break;

                case BinarySectionType.JumpLabelSection:
                    instance.mJumpLabelSection = ReadLabelSection(ref sectionHeader);
                    break;

                case BinarySectionType.TextSection:
                    instance.mTextSection = ReadTextSection(ref sectionHeader);
                    break;

                case BinarySectionType.MessageScriptSection:
                    instance.mMessageScriptSection = ReadMessageScriptSection(ref sectionHeader);
                    break;

                case BinarySectionType.StringSection:

                    // fix for early, broken files
                    // see: nocturne e500.bf
                    if (sectionHeader.FirstElementAddress == instance.mHeader.FileSize)
                    {
                        instance.mHeader.FileSize  = ( int )(mReader.BaseStreamLength - mPositionBase);
                        sectionHeader.ElementCount = instance.mHeader.FileSize - sectionHeader.FirstElementAddress;
                    }

                    instance.mStringSection = ReadStringSection(ref sectionHeader);
                    break;

                default:
                    throw new InvalidDataException("Unknown section type");
                }
            }
Esempio n. 11
0
        public FieldLocalData(string directoryPath, int major, int minor)
            : this()
        {
            var fieldPak    = LoadFieldPak(directoryPath, major, minor, "f{0:D3}_{1:D3}.pac");
            var fieldNpcPak = LoadFieldPak(directoryPath, major, minor, "fnpc{0:D3}_{1:D3}.pac");

            DefaultCamera = TryLoadFile(fieldPak, $"data/f{major:D3}_{minor:D3}.CMR", stream => new CmrBinary(stream, true));

            // Load layers
            for (int layerIndex = 0; true; layerIndex++)
            {
                var layer = new FieldLayer();
                layer.ObjectPlacement = TryLoadFile(fieldPak, $"data/f{major:D3}_{minor:D3}_{layerIndex:D2}.FBN", stream => new FbnBinary(stream, true));
                layer.HitTable        = TryLoadFile(fieldPak, $"hit/f{major:D3}_{minor:D3}_{layerIndex:D2}.HTB", stream => new HtbBinary(stream, true));
                layer.HitScript       = TryLoadFile(fieldPak, $"hit/fhit_{major:D3}_{minor:D3}_{layerIndex:D2}.bf", stream => FlowScriptBinary.FromStream(stream, true));
                layer.NpcScript       = TryLoadFile(fieldNpcPak, $"npc/fnpc{major:D3}_{minor:D3}_{layerIndex:D2}.bf", stream => FlowScriptBinary.FromStream(stream, true));
                //layer.Fnt = TryLoadFile( fieldNpcPak, $"npc/fnt{major:D3}_{minor:D3}_{layerIndex:D2}.bf", stream => new FntBinary( stream, true ) );
                //layer.Fpt = TryLoadFile( fieldNpcPak, $"npc/fpt{major:D3}_{minor:D3}_{layerIndex:D2}.bf", stream => new FptBinary( stream, true ) );

                if (layer.ObjectPlacement == null &&
                    layer.HitTable == null &&
                    layer.HitScript == null &&
                    layer.NpcScript == null &&
                    layer.Fnt == null &&
                    layer.Fpt == null)
                {
                    // Layer was empty, so assume there are no more layers
                    break;
                }

                Layers.Add(layer);
            }

            //for ( int i = 1; i < 9; i++ )
            //    Pcds[ i ] = TryLoadFile( fieldPak, $"data/f{major:D3}_{minor:D3}_{i:D3}.PCD", stream => new PcdBinary( stream, true ) );

            //Fpa = TryLoadFile( fieldPak, $"data/f{major:D3}_{minor:D3}.FPA", stream => new FpaBinary( stream, true ) );
            //Culling = TryLoadFile( fieldPak, $"culling/f{major:D3}_{minor:D3}.CHD", stream => new ChdBinary( stream, true ) );
            //Enemies = TryLoadFile( fieldPak, $"enemy/f{major:D3}_{minor:D3}.FEL", stream => new FelBinary( stream, true ) );
            InitScript = TryLoadFile(fieldPak, $"init/fini_{major:D3}_{minor:D3}.bf", stream => FlowScriptBinary.FromStream(stream, true));
            //Map = TryLoadFile( fieldPak, $"map/d{major:D3}_{minor:D3}.map", stream => new MapBinary( stream, true ) );
            //Objects = TryLoadFile( fieldPak, $"map/d{major:D3}_{minor:D3}.OBL", stream => new OblBinary( stream, true ) );
            ObjectHitTable  = TryLoadFile(fieldPak, $"object_hit/f{major:D3}_{minor:D3}.HTB", stream => new HtbBinary(stream, true));
            ObjectHitScript = TryLoadFile(fieldPak, $"object_hit/fhit{major:D3}_{minor:D3}.bf", stream => FlowScriptBinary.FromStream(stream, true));
            //Sht = TryLoadFile( fieldPak, $"sht/f{major:D3}_{minor:D3}.SHT", stream => new ShtBinary( stream, true ) );
            //Tbl = TryLoadFile( fieldPak, $"fext{major:D3}_{minor:D3}.tbl", stream => new TblBinary( stream, true ) );

            AddUncategorizedFiles(fieldPak, UncategorizedFiles);

            if (fieldNpcPak != null)
            {
                AddUncategorizedFiles(fieldNpcPak, UncategorizedNpcFiles);
            }
        }
 public void FromFileTest_InvalidFileFormat_Big()
 {
     Assert.ThrowsException <InvalidDataException>(() => FlowScriptBinary.FromFile("TestResources\\dummy_big.bin", BinaryFormatVersion.Unknown));
 }
        public void ToBinary_ContentsShouldMatchThatOfSourceBinary_Version3BigEndian()
        {
            var binaryIn  = FlowScriptBinary.FromFile("TestResources\\Version3BigEndian.bf");
            var script    = FlowScript.FromBinary(binaryIn);
            var binaryOut = script.ToBinary();

            // Compare headers
            Assert.AreEqual(binaryIn.Header.FileType, binaryOut.Header.FileType);
            Assert.AreEqual(binaryIn.Header.Compressed, binaryOut.Header.Compressed);
            Assert.AreEqual(binaryIn.Header.UserId, binaryOut.Header.UserId);
            Assert.AreEqual(binaryIn.Header.FileSize, binaryOut.Header.FileSize);
            Assert.IsTrue(binaryIn.Header.Magic.SequenceEqual(binaryOut.Header.Magic));
            Assert.AreEqual(binaryIn.Header.Field0C, binaryOut.Header.Field0C);
            Assert.AreEqual(binaryIn.Header.SectionCount, binaryOut.Header.SectionCount);
            Assert.AreEqual(binaryIn.Header.LocalIntVariableCount, binaryOut.Header.LocalIntVariableCount);
            Assert.AreEqual(binaryIn.Header.LocalFloatVariableCount, binaryOut.Header.LocalFloatVariableCount);
            Assert.AreEqual(binaryIn.Header.Endianness, binaryOut.Header.Endianness);
            Assert.AreEqual(binaryIn.Header.Field1A, binaryOut.Header.Field1A);
            Assert.AreEqual(binaryIn.Header.Padding, binaryOut.Header.Padding);

            // Compare section headers
            for (int i = 0; i < binaryIn.SectionHeaders.Count; i++)
            {
                Assert.AreEqual(binaryIn.SectionHeaders[i].SectionType, binaryOut.SectionHeaders[i].SectionType);
                Assert.AreEqual(binaryIn.SectionHeaders[i].ElementSize, binaryOut.SectionHeaders[i].ElementSize);
                Assert.AreEqual(binaryIn.SectionHeaders[i].ElementCount, binaryOut.SectionHeaders[i].ElementCount);
                Assert.AreEqual(binaryIn.SectionHeaders[i].FirstElementAddress, binaryOut.SectionHeaders[i].FirstElementAddress);
            }

            // Compare labels
            for (int i = 0; i < binaryIn.ProcedureLabelSection.Count; i++)
            {
                Assert.AreEqual(binaryIn.ProcedureLabelSection[i].Name, binaryOut.ProcedureLabelSection[i].Name);
                Assert.AreEqual(binaryIn.ProcedureLabelSection[i].InstructionIndex, binaryOut.ProcedureLabelSection[i].InstructionIndex);
                Assert.AreEqual(binaryIn.ProcedureLabelSection[i].Reserved, binaryOut.ProcedureLabelSection[i].Reserved);
            }

            for (int i = 0; i < binaryIn.JumpLabelSection.Count; i++)
            {
                Assert.AreEqual(binaryIn.JumpLabelSection[i].Name, binaryOut.JumpLabelSection[i].Name);
                Assert.AreEqual(binaryIn.JumpLabelSection[i].InstructionIndex, binaryOut.JumpLabelSection[i].InstructionIndex);
                Assert.AreEqual(binaryIn.JumpLabelSection[i].Reserved, binaryOut.JumpLabelSection[i].Reserved);
            }

            // Compare instructions
            for (int i = 0; i < binaryIn.TextSection.Count; i++)
            {
                var inInstruction  = binaryIn.TextSection[i];
                var outInstruction = binaryOut.TextSection[i];

                Assert.AreEqual(inInstruction.Opcode, outInstruction.Opcode);

                if (inInstruction.Opcode == Opcode.PUSHI || inInstruction.Opcode == Opcode.PUSHF)
                {
                    ++i;
                    continue;
                }

                if (inInstruction.Opcode == Opcode.IF || inInstruction.Opcode == Opcode.GOTO)
                {
                    Assert.AreEqual(binaryIn.JumpLabelSection[inInstruction.OperandShort].Name, binaryOut.JumpLabelSection[outInstruction.OperandShort].Name);
                }
                else
                {
                    Assert.AreEqual(inInstruction.OperandShort, outInstruction.OperandShort);
                }
            }

            // Compare message script
            //Assert.IsTrue(binaryIn.MessageScriptSection.SequenceEqual(binaryOut.MessageScriptSection));

            // Compare strings
            Assert.IsTrue(binaryIn.StringSection.SequenceEqual(binaryOut.StringSection));
        }
Esempio n. 14
0
        static void ExtractMessageScript(string file, Stream stream, string parentArchiveFile)
        {
            string prettyFileName;

            if (parentArchiveFile == null)
            {
                prettyFileName = file.Remove(0, DirectoryPath.Length);
            }
            else
            {
                prettyFileName = Path.Combine(parentArchiveFile, file);
            }

            // print some useful info
            if (parentArchiveFile == null)
            {
                Console.WriteLine($"Processing file: {prettyFileName}");
            }
            else
            {
                Console.WriteLine($"Processing archive file: {prettyFileName}");
            }

            // extract script
            MessageScript script        = null;
            string        fileExtension = Path.GetExtension(file);

            // Check if it is a plain message script file
            if (fileExtension.Equals(".bmd", StringComparison.InvariantCultureIgnoreCase))
            {
                script = MessageScript.FromStream(stream, FormatVersion.Detect, Encoding, true);
            }
            // Check if it is a flow script file that can maybe contain a message script
            else if (fileExtension.Equals(".bf", StringComparison.InvariantCultureIgnoreCase))
            {
                var flowScriptBinary = FlowScriptBinary.FromStream(stream, true);
                if (flowScriptBinary.MessageScriptSection != null)
                {
                    script = MessageScript.FromBinary(flowScriptBinary.MessageScriptSection, FormatVersion.Detect, Encoding);
                }
                else
                {
                    return;
                }
            }

            if (script != null)
            {
                // We have found a script, yay!
                Console.WriteLine("Writing message script to file...");
                if (UseDecompiler)
                {
                    WriteMessageScriptWithDecompiler(prettyFileName, script);
                }
                else
                {
                    WriteMessageScript(prettyFileName, script);
                }
            }
            else
            {
                // Try to open the file as an archive

                if (!Archive.TryOpenArchive(stream, out var archive))
                {
                    // If we can't open the file as an archive, try brute force scanning if it is enabled
                    if (EnableBruteforceScanning &&
                        (BruteforceExclusionList == null || BruteforceExclusionList != null && !BruteforceExclusionList.Any(x => x.Equals(fileExtension, StringComparison.InvariantCultureIgnoreCase))) &&
                        (BruteforceInclusionList == null || BruteforceInclusionList != null && BruteforceInclusionList.Any(x => x.Equals(fileExtension, StringComparison.InvariantCultureIgnoreCase)))
                        )
                    {
                        Console.WriteLine($"Bruteforce scanning...");

                        var scanCancel = new CancellationTokenSource();
                        var scanTask   = Task.Factory.StartNew(() => ScanForMessageScripts(prettyFileName, stream, scanCancel.Token));

                        while (!scanTask.IsCompleted)
                        {
                            // Don't want to block, so wait for key to be available
                            if (Console.KeyAvailable)
                            {
                                // Blocking is fine after this point
                                var key = Console.ReadKey(true);

                                if (key.Key == ConsoleKey.S)
                                {
                                    Console.WriteLine("Do you want to skip scanning this file? Y/N");
                                    if (Console.ReadKey(true).Key == ConsoleKey.Y)
                                    {
                                        scanCancel.Cancel();

                                        Console.WriteLine("Do you want to add this file extension to the list of excluded files? Y/N");
                                        if (Console.ReadKey(true).Key == ConsoleKey.Y)
                                        {
                                            if (BruteforceExclusionList == null)
                                            {
                                                BruteforceExclusionList = new List <string>();
                                            }

                                            BruteforceExclusionList.Add(Path.GetExtension(prettyFileName));
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
                else
                {
                    foreach (var entry in archive)
                    {
                        ExtractMessageScript(entry, archive.OpenFile(entry), prettyFileName);
                    }
                }
            }
        }
Esempio n. 15
0
        /// <summary>
        /// Creates a <see cref="FlowScript"/> from a <see cref="FlowScriptBinary"/> object.
        /// </summary>
        /// <param name="binary">A <see cref="FlowScriptBinary"/> instance.</param>
        /// <returns>A <see cref="FlowScript"/> instance.</returns>
        public static FlowScript FromBinary(FlowScriptBinary binary, Encoding encoding = null)
        {
            var instance = new FlowScript
            {
                mUserId = binary.Header.UserId
            };

            // assign labels later after convert the instructions because we need to update the instruction indices
            // to reference the instructions in the list, and not the instructions in the array of instructions in the binary

            // assign strings before instructions so we can assign proper string indices as we convert the instructions
            var stringBinaryIndexToListIndexMap = new Dictionary <short, short>();
            var strings = new List <string>();

            if (binary.StringSection != null)
            {
                short curStringBinaryIndex = 0;
                var   curStringBytes       = new List <byte>();

                for (short i = 0; i < binary.StringSection.Count; i++)
                {
                    // check for string terminator or end of string section
                    if (binary.StringSection[i] == 0 || i + 1 == binary.StringSection.Count)
                    {
                        strings.Add(ShiftJISEncoding.Instance.GetString(curStringBytes.ToArray()));
                        stringBinaryIndexToListIndexMap[curStringBinaryIndex] = ( short )(strings.Count - 1);

                        // next string will start at the next byte if there are any left
                        curStringBinaryIndex = ( short )(i + 1);
                        curStringBytes       = new List <byte>();
                    }
                    else
                    {
                        curStringBytes.Add(binary.StringSection[i]);
                    }
                }
            }

            var instructionBinaryIndexToListIndexMap = new Dictionary <int, int>();
            var instructions = new List <Instruction>();

            // assign instructions
            // TODO: optimize this away later as i don't feel like it right now
            if (binary.TextSection != null)
            {
                int instructionIndex       = 0;
                int instructionBinaryIndex = 0;

                while (instructionBinaryIndex < binary.TextSection.Count)
                {
                    // Convert each instruction
                    var binaryInstruction = binary.TextSection[instructionBinaryIndex];

                    Instruction instruction;

                    // Handle instructions we need to alter seperately
                    if (binaryInstruction.Opcode == Opcode.PUSHSTR)
                    {
                        // Update the string offset to reference the strings inside of the string list
                        instruction = Instruction.PUSHSTR(strings[stringBinaryIndexToListIndexMap[binaryInstruction.OperandShort]]);
                    }
                    else if (binaryInstruction.Opcode == Opcode.PUSHI)
                    {
                        instruction = Instruction.PUSHI(binary.TextSection[instructionBinaryIndex + 1].OperandInt);
                    }
                    else if (binaryInstruction.Opcode == Opcode.PUSHF)
                    {
                        instruction = Instruction.PUSHF(binary.TextSection[instructionBinaryIndex + 1].OperandFloat);
                    }
                    else
                    {
                        instruction = Instruction.FromBinaryInstruction(binaryInstruction);
                    }

                    // Add to list
                    instructions.Add(instruction);
                    instructionBinaryIndexToListIndexMap[instructionBinaryIndex] = instructionIndex++;

                    // Increment the instruction binary index by 2 if the current instruction takes up 2 instructions
                    if (instruction.UsesTwoBinaryInstructions)
                    {
                        instructionBinaryIndex += 2;
                    }
                    else
                    {
                        instructionBinaryIndex += 1;
                    }
                }
            }

            // assign labels as the instruction index remap table has been built
            var sortedProcedureLabels = binary.ProcedureLabelSection.OrderBy(x => x.InstructionIndex).ToList();

            for (int i = 0; i < binary.ProcedureLabelSection.Count; i++)
            {
                var procedureLabel          = binary.ProcedureLabelSection[i];
                int procedureListStartIndex = instructionBinaryIndexToListIndexMap[procedureLabel.InstructionIndex];
                int nextProcedureLabelIndex = sortedProcedureLabels.FindIndex(x => x.InstructionIndex == procedureLabel.InstructionIndex) + 1;
                int procedureInstructionCount;
                int procedureBinaryEndIndex; // inclusive

                // Calculate the number of instructions in the procedure
                bool isLastProcedure = nextProcedureLabelIndex == binary.ProcedureLabelSection.Count;
                if (isLastProcedure)
                {
                    procedureInstructionCount = (instructions.Count - procedureListStartIndex);
                    procedureBinaryEndIndex   = binary.TextSection.Count - 1;
                }
                else
                {
                    var nextProcedureLabel = binary.ProcedureLabelSection[nextProcedureLabelIndex];
                    procedureInstructionCount = (instructionBinaryIndexToListIndexMap[nextProcedureLabel.InstructionIndex] - procedureListStartIndex);
                    procedureBinaryEndIndex   = nextProcedureLabel.InstructionIndex - 1;
                }

                // Copy the instruction range
                var procedureInstructions = new List <Instruction>(procedureInstructionCount);
                for (int j = 0; j < procedureInstructionCount; j++)
                {
                    procedureInstructions.Add(instructions[procedureListStartIndex + j]);
                }

                // Create the new procedure representation
                Procedure procedure;

                if (binary.JumpLabelSection != null)
                {
                    // Find jump labels within instruction range of procedure
                    var procedureBinaryJumpLabels = binary.JumpLabelSection
                                                    .Where(x => x.InstructionIndex >= procedureLabel.InstructionIndex && x.InstructionIndex <= procedureBinaryEndIndex)
                                                    .ToList();

                    if (procedureBinaryJumpLabels.Count > 0)
                    {
                        // Generate mapping between label name and the procedure-local index of the label
                        var procedureJumpLabelNameToLocalIndexMap = new Dictionary <string, int>(procedureBinaryJumpLabels.Count);

                        for (int k = 0; k < procedureBinaryJumpLabels.Count; k++)
                        {
                            procedureJumpLabelNameToLocalIndexMap[procedureBinaryJumpLabels[k].Name] = k;
                        }

                        // Convert the labels to the new representation
                        var procedureJumpLabels = new List <Label>(procedureBinaryJumpLabels.Count);
                        foreach (var procedureBinaryJumpLabel in procedureBinaryJumpLabels)
                        {
                            int globalInstructionListIndex = instructionBinaryIndexToListIndexMap[procedureBinaryJumpLabel.InstructionIndex];
                            int localInstructionListIndex  = globalInstructionListIndex - procedureListStartIndex;
                            procedureJumpLabels.Add(new Label(procedureBinaryJumpLabel.Name, localInstructionListIndex));
                        }

                        // Create the procedure
                        procedure = new Procedure(procedureLabel.Name, procedureInstructions, procedureJumpLabels);

                        // Loop over the instructions and update the instructions that reference labels
                        // so that they refer to the proper procedure-local label index
                        for (int j = 0; j < procedure.Instructions.Count; j++)
                        {
                            var instruction = procedure.Instructions[j];
                            if (instruction.Opcode == Opcode.GOTO || instruction.Opcode == Opcode.IF)
                            {
                                short globalIndex = instruction.Operand.Int16Value;
                                var   binaryLabel = binary.JumpLabelSection[globalIndex];

                                short localIndex = ( short )procedureJumpLabelNameToLocalIndexMap[binaryLabel.Name];
                                instruction.Operand.Int16Value = localIndex;

                                Debug.Assert(procedure.Labels[localIndex].Name == binaryLabel.Name);
                            }

                            procedure.Instructions[j] = instruction;
                        }
                    }
                    else
                    {
                        // Create the procedure
                        procedure = new Procedure(procedureLabel.Name, procedureInstructions);
                    }
                }
                else
                {
                    // Create the procedure
                    procedure = new Procedure(procedureLabel.Name, procedureInstructions);
                }

                instance.mProcedures.Add(procedure);
            }

            // assign message script
            if (binary.MessageScriptSection != null)
            {
                instance.mMessageScript = MessageScript.FromBinary(binary.MessageScriptSection, MessageScriptLanguage.FormatVersion.Detect, encoding);
            }

            // strings have already been assigned previously,
            // so last up is the version
            instance.mFormatVersion = (FormatVersion)binary.FormatVersion;

            // everything is assigned, return the constructed instance
            return(instance);
        }
Esempio n. 16
0
        /// <summary>
        /// Creates a <see cref="FlowScript"/> by loading it from a stream in the specified format version.
        /// </summary>
        /// <param name="stream">Data stream.</param>
        /// <param name="version">Format version the loader should use.</param>
        /// <returns>A <see cref="FlowScript"/> instance.</returns>
        public static FlowScript FromStream(Stream stream, Encoding encoding, FormatVersion version, bool leaveOpen)
        {
            FlowScriptBinary binary = FlowScriptBinary.FromStream(stream, (BinaryFormatVersion)version, leaveOpen);

            return(FromBinary(binary, encoding));
        }