コード例 #1
0
        public void ToBinary_ShouldMatchSourceBinary_Version1BigEndian()
        {
            var binary    = MessageScriptBinary.FromFile("TestResources\\Version1BigEndian.bmd");
            var script    = MessageScript.FromBinary(binary);
            var newBinary = script.ToBinary();

            Compare(binary, newBinary);
        }
コード例 #2
0
        public void ToStream_StreamNotNullOrEmptyAndLengthEqualToFileSize_Version1()
        {
            var script = MessageScriptBinary.FromFile("TestResources\\Version1.bmd");
            var stream = script.ToStream();

            Assert.IsNotNull(stream);
            Assert.AreNotEqual(0, stream.Length);
            Assert.AreEqual(script.Header.FileSize, stream.Length);
        }
コード例 #3
0
 public void WriteBinary(MessageScriptBinary binary)
 {
     WriteHeader(ref binary.mHeader);
     WriteDialogHeaders(binary.mDialogHeaders);
     WriteSpeakerHeader(ref binary.mSpeakerTableHeader);
     WriteDialogs(binary.mDialogHeaders);
     WriteSpeakerNameOffsets(ref binary.mSpeakerTableHeader);
     WriteSpeakerNames(ref binary.mSpeakerTableHeader);
     WriteRelocationTable(ref binary.mHeader.RelocationTable);
 }
コード例 #4
0
        /// <summary>
        /// Deserializes and creates a <see cref="MessageScript"/> from a file.
        /// </summary>
        public static MessageScript FromFile(string path, FormatVersion version = FormatVersion.Version1, Encoding encoding = null)
        {
            if (path == null)
            {
                throw new ArgumentNullException(nameof(path));
            }

            var binary = MessageScriptBinary.FromFile(path);

            return(FromBinary(binary, version, encoding));
        }
コード例 #5
0
        /// <summary>
        /// Deserializes and creates a <see cref="MessageScript"/> from a stream.
        /// </summary>
        public static MessageScript FromStream(Stream stream, FormatVersion version = FormatVersion.Version1, Encoding encoding = null, bool leaveOpen = false)
        {
            if (stream == null)
            {
                throw new ArgumentNullException(nameof(stream));
            }

            var binary = MessageScriptBinary.FromStream(stream, leaveOpen);

            return(FromBinary(binary, version, encoding));
        }
コード例 #6
0
        static void ScanForMessageScripts(string prettyFileName, Stream stream, CancellationToken cancellationToken)
        {
            byte[] magic = new byte[4];

            while (stream.Position <= stream.Length)
            {
                if (cancellationToken.IsCancellationRequested)
                {
                    break;
                }

                if (stream.Position + BinaryHeader.SIZE < stream.Length)
                {
                    // Read 4 bytes
                    magic[0] = ( byte )stream.ReadByte();
                    magic[1] = ( byte )stream.ReadByte();
                    magic[2] = ( byte )stream.ReadByte();
                    magic[3] = ( byte )stream.ReadByte();

                    if (magic.SequenceEqual(BinaryHeader.MAGIC_V0) ||
                        magic.SequenceEqual(BinaryHeader.MAGIC_V1) ||
                        magic.SequenceEqual(BinaryHeader.MAGIC_V1_BE))
                    {
                        long scriptStartPosition = stream.Position - 12;
                        var  scriptBinary        = MessageScriptBinary.FromStream(new StreamView(stream, scriptStartPosition, stream.Length - scriptStartPosition));
                        var  script = MessageScript.FromBinary(scriptBinary);

                        Console.WriteLine($"Found message script at 0x{scriptStartPosition:X8}. Writing to file...");

                        if (UseDecompiler)
                        {
                            WriteMessageScriptWithDecompiler($"{prettyFileName} @ 0x{scriptStartPosition:X8}", script);
                        }
                        else
                        {
                            WriteMessageScript($"{prettyFileName} @ 0x{scriptStartPosition:X8}", script);
                        }

                        stream.Position = scriptStartPosition + scriptBinary.Header.FileSize;
                    }
                    else if (DisableScanAlignment)
                    {
                        // Scan alignment is disabled, so we make sure to retry every byte
                        // 4 steps forward, 3 steps back
                        stream.Position -= 3;
                    }
                }
                else
                {
                    break;
                }
            }
        }
コード例 #7
0
        public MessageScriptBinary ReadBinary()
        {
            var binary = new MessageScriptBinary
            {
                mHeader = ReadHeader()
            };

            binary.mDialogHeaders      = ReadDialogHeaders(binary.mHeader.DialogCount);
            binary.mSpeakerTableHeader = ReadSpeakerTableHeader();
            binary.mFormatVersion      = mVersion;

            return(binary);
        }
コード例 #8
0
 public void ToFile_ResultShouldPassIntegrityCheck_Version1BigEndian()
 {
     try
     {
         var script = MessageScriptBinary.FromFile("TestResources\\Version1BigEndian.bmd");
         script.ToFile("TestResources\\Version1BigEndian_ToFile.bmd");
         script = MessageScriptBinary.FromFile("TestResources\\Version1BigEndian_ToFile.bmd");
         PerformIntegrityCheckForVersion1BigEndian(script);
     }
     finally
     {
         File.Delete("TestResources\\Version1BigEndian_ToFile.bmd");
     }
 }
コード例 #9
0
        private void PerformIntegrityCheckForVersion1(MessageScriptBinary script)
        {
            PrintSpeakerIdsIfHigherThanTotalSpeakers(script);

            // header checks
            Assert.AreEqual(7, script.Header.FileType);
            Assert.AreEqual(false, script.Header.Format);
            Assert.AreEqual(0, script.Header.UserId);
            Assert.AreEqual(0x987A, script.Header.FileSize);
            Assert.IsTrue(script.Header.Magic.SequenceEqual(BinaryHeader.MAGIC_V1));
            Assert.AreEqual(0, script.Header.ExtSize);
            Assert.AreEqual(0x96EC, script.Header.RelocationTable.Offset);
            Assert.AreEqual(0x018E, script.Header.RelocationTable.Value.Length);
            Assert.AreEqual(0x018E, script.Header.RelocationTableSize);
            Assert.AreEqual(0x9B, script.Header.DialogCount);
            Assert.AreEqual(0x9B, script.DialogHeaders.Count);
            Assert.AreEqual(false, script.Header.IsRelocated);
            Assert.AreEqual(2, script.Header.Version);

            // check some message headers
            Assert.AreEqual(BinaryDialogKind.Selection, script.DialogHeaders[0].Kind);
            Assert.AreEqual(0x04E8, script.DialogHeaders[0].Data.Offset);

            Assert.AreEqual(BinaryDialogKind.Message, script.DialogHeaders[26].Kind);
            Assert.AreEqual(0x1B68, script.DialogHeaders[26].Data.Offset);

            // check some messages
            Assert.AreEqual("combine_sel", (( BinarySelectionDialog )script.DialogHeaders[0].Data.Value).Name);
            Assert.AreEqual(0, (( BinarySelectionDialog )script.DialogHeaders[0].Data.Value).Ext);
            Assert.AreEqual(2, (( BinarySelectionDialog )script.DialogHeaders[0].Data.Value).OptionCount);
            Assert.AreEqual(BinarySelectionDialogPattern.Top, (( BinarySelectionDialog )script.DialogHeaders[0].Data.Value).Pattern);
            Assert.AreEqual(0, (( BinarySelectionDialog )script.DialogHeaders[0].Data.Value).Reserved);
            Assert.AreEqual(2, (( BinarySelectionDialog )script.DialogHeaders[0].Data.Value).OptionStartAddresses.Length);
            Assert.AreEqual(0x0514, (( BinarySelectionDialog )script.DialogHeaders[0].Data.Value).OptionStartAddresses[0]);
            Assert.AreEqual(0x051E, (( BinarySelectionDialog )script.DialogHeaders[0].Data.Value).OptionStartAddresses[1]);
            Assert.AreEqual(0x14, (( BinarySelectionDialog )script.DialogHeaders[0].Data.Value).TextBufferSize);
            Assert.AreEqual(0x14, (( BinarySelectionDialog )script.DialogHeaders[0].Data.Value).TextBuffer.Length);

            Assert.AreEqual("book_bonus004", (( BinaryMessageDialog )script.DialogHeaders[26].Data.Value).Name);
            Assert.AreEqual(0x0A, (( BinaryMessageDialog )script.DialogHeaders[26].Data.Value).PageCount);
            Assert.AreEqual(0x01, (( BinaryMessageDialog )script.DialogHeaders[26].Data.Value).SpeakerId);
            Assert.AreEqual(0x0A, (( BinaryMessageDialog )script.DialogHeaders[26].Data.Value).PageStartAddresses.Length);
            Assert.AreEqual(0x1BB0, (( BinaryMessageDialog )script.DialogHeaders[26].Data.Value).PageStartAddresses[0]);
            Assert.AreEqual(0x1C1C, (( BinaryMessageDialog )script.DialogHeaders[26].Data.Value).PageStartAddresses[1]);
            Assert.AreEqual(0x02CE, (( BinaryMessageDialog )script.DialogHeaders[26].Data.Value).TextBufferSize);
            Assert.AreEqual(0x02CE, (( BinaryMessageDialog )script.DialogHeaders[26].Data.Value).TextBuffer.Length);
        }
コード例 #10
0
        private void PerformIntegrityCheckForVersion1BigEndian(MessageScriptBinary script)
        {
            PrintSpeakerIdsIfHigherThanTotalSpeakers(script);

            // header checks
            Assert.AreEqual(7, script.Header.FileType);
            Assert.AreEqual(0, script.Header.Format);
            Assert.AreEqual(0, script.Header.UserId);
            Assert.AreEqual(0x6F89, script.Header.FileSize);
            Assert.IsTrue(script.Header.Magic.SequenceEqual(BinaryHeader.MAGIC_V1_BE));
            Assert.AreEqual(0, script.Header.ExtSize);
            Assert.AreEqual(0x6E50, script.Header.RelocationTable.Offset);
            Assert.AreEqual(0x0139, script.Header.RelocationTableSize);
            Assert.AreEqual(script.Header.RelocationTableSize, script.Header.RelocationTable.Value.Length);
            Assert.AreEqual(0x76, script.Header.DialogCount);
            Assert.AreEqual(script.Header.DialogCount, script.DialogHeaders.Count);
            Assert.AreEqual(false, script.Header.IsRelocated);
            Assert.AreEqual(2, script.Header.Version);

            // check some message headers
            Assert.AreEqual(BinaryDialogKind.Selection, script.DialogHeaders[0].Kind);
            Assert.AreEqual(0x03C0, script.DialogHeaders[0].Data.Offset);

            Assert.AreEqual(BinaryDialogKind.Message, script.DialogHeaders[26].Kind);
            Assert.AreEqual(0x0F24, script.DialogHeaders[26].Data.Offset);

            // check some messages
            Assert.AreEqual("FCL_MSG_COMBINE_SELECT", (( BinarySelectionDialog )script.DialogHeaders[0].Data.Value).Name);
            Assert.AreEqual(0, (( BinarySelectionDialog )script.DialogHeaders[0].Data.Value).Ext);
            Assert.AreEqual(2, (( BinarySelectionDialog )script.DialogHeaders[0].Data.Value).OptionCount);
            Assert.AreEqual(BinarySelectionDialogPattern.Top, (( BinarySelectionDialog )script.DialogHeaders[0].Data.Value).Pattern);
            Assert.AreEqual(BinarySelectionDialogPattern.Top, (( BinarySelectionDialog )script.DialogHeaders[0].Data.Value).Pattern);
            Assert.AreEqual(2, (( BinarySelectionDialog )script.DialogHeaders[0].Data.Value).OptionStartAddresses.Length);
            Assert.AreEqual(0x03EC, (( BinarySelectionDialog )script.DialogHeaders[0].Data.Value).OptionStartAddresses[0]);
            Assert.AreEqual(0x03FC, (( BinarySelectionDialog )script.DialogHeaders[0].Data.Value).OptionStartAddresses[1]);
            Assert.AreEqual(0x23, (( BinarySelectionDialog )script.DialogHeaders[0].Data.Value).TextBufferSize);
            Assert.AreEqual(0x23, (( BinarySelectionDialog )script.DialogHeaders[0].Data.Value).TextBuffer.Length);

            Assert.AreEqual("FCL_MSG_COMBINE_CELL_HOU", (( BinaryMessageDialog )script.DialogHeaders[26].Data.Value).Name);
            Assert.AreEqual(0x01, (( BinaryMessageDialog )script.DialogHeaders[26].Data.Value).PageCount);
            Assert.AreEqual(0x01, (( BinaryMessageDialog )script.DialogHeaders[26].Data.Value).SpeakerId);
            Assert.AreEqual(0x01, (( BinaryMessageDialog )script.DialogHeaders[26].Data.Value).PageStartAddresses.Length);
            Assert.AreEqual(0x0F48, (( BinaryMessageDialog )script.DialogHeaders[26].Data.Value).PageStartAddresses[0]);
            Assert.AreEqual(0x40, (( BinaryMessageDialog )script.DialogHeaders[26].Data.Value).TextBufferSize);
            Assert.AreEqual(0x40, (( BinaryMessageDialog )script.DialogHeaders[26].Data.Value).TextBuffer.Length);
        }
コード例 #11
0
        private void PrintSpeakerIdsIfHigherThanTotalSpeakers(MessageScriptBinary script)
        {
            foreach (var messageHeader in script.DialogHeaders)
            {
                if (messageHeader.Kind != BinaryDialogKind.Message)
                {
                    continue;
                }

                var message = ( BinaryMessageDialog )messageHeader.Data.Value;

                if (message.SpeakerId > (script.SpeakerTableHeader.SpeakerCount - 1))
                {
                    Trace.WriteLine($"SpeakerId: {message.SpeakerId:X4}");
                }
            }
        }
コード例 #12
0
        public void FromFile_NoException_Batch()
        {
            foreach (var path in Directory.EnumerateFiles("TestResources\\Batch\\", "*.bmd"))
            {
                var script = MessageScriptBinary.FromFile(path);

                PrintSpeakerIdsIfHigherThanTotalSpeakers(script);

                if (script.SpeakerTableHeader.ExtDataOffset != 0)
                {
                    Trace.WriteLine($"{nameof( MessageScriptBinary )}.{nameof( script.SpeakerTableHeader )}.{nameof( script.SpeakerTableHeader.ExtDataOffset )} = {script.SpeakerTableHeader.ExtDataOffset}");
                }

                if (script.SpeakerTableHeader.Reserved != 0)
                {
                    Trace.WriteLine($"{nameof( MessageScriptBinary )}.{nameof( script.SpeakerTableHeader )}.{nameof( script.SpeakerTableHeader.Reserved )} = {script.SpeakerTableHeader.Reserved}");
                }
            }
        }
コード例 #13
0
        public void FromStream_ShouldPassIntegrityCheck_Version1BigEndian()
        {
            var script = MessageScriptBinary.FromStream(File.OpenRead("TestResources\\Version1BigEndian.bmd"));

            PerformIntegrityCheckForVersion1BigEndian(script);
        }
コード例 #14
0
        // TODO: maybe move the parsing functions to a seperate class
        /// <summary>
        /// Creates a <see cref="MessageScript"/> from a <see cref="MessageScriptBinary"/>.
        /// </summary>
        public static MessageScript FromBinary(MessageScriptBinary binary, FormatVersion version = FormatVersion.Detect, Encoding encoding = null)
        {
            if (binary == null)
            {
                throw new ArgumentNullException(nameof(binary));
            }

            if (binary.DialogHeaders == null)
            {
                throw new ArgumentNullException(nameof(binary));
            }

            // Create new script instance & set user id, format version
            var instance = new MessageScript
            {
                Id            = binary.Header.UserId,
                FormatVersion = version == FormatVersion.Detect ? ( FormatVersion)binary.FormatVersion : version,
                Encoding      = encoding
            };

            // Convert the binary messages to their counterpart
            var labelOccurences = new Dictionary <string, int>();

            foreach (var messageHeader in binary.DialogHeaders)
            {
                IDialog              message;
                IReadOnlyList <int>  pageStartAddresses;
                IReadOnlyList <byte> buffer;
                int pageCount;

                switch (messageHeader.Kind)
                {
                case BinaryDialogKind.Message:
                {
                    var binaryMessage = (BinaryMessageDialog)messageHeader.Data.Value;
                    pageStartAddresses = binaryMessage.PageStartAddresses;
                    buffer             = binaryMessage.TextBuffer;
                    pageCount          = binaryMessage.PageCount;

                    // check for duplicates
                    var name = ResolveName(labelOccurences, binaryMessage.Name);

                    if (binaryMessage.SpeakerId == 0xFFFF)
                    {
                        message = new MessageDialog(name);
                    }
                    else if ((binaryMessage.SpeakerId & 0x8000) == 0x8000)
                    {
                        Trace.WriteLine(binaryMessage.SpeakerId.ToString("X4"));

                        message = new MessageDialog(name, new VariableSpeaker(binaryMessage.SpeakerId & 0x0FFF));
                    }
                    else
                    {
                        if (binary.SpeakerTableHeader.SpeakerNameArray.Value == null)
                        {
                            throw new InvalidDataException("Speaker name array is null while being referenced");
                        }

                        TokenText speakerName = null;
                        if (binaryMessage.SpeakerId < binary.SpeakerTableHeader.SpeakerCount)
                        {
                            speakerName = ParseSpeakerText(binary.SpeakerTableHeader.SpeakerNameArray
                                                           .Value[binaryMessage.SpeakerId].Value, instance.FormatVersion, encoding == null ? Encoding.ASCII : encoding);
                        }

                        message = new MessageDialog(name, new NamedSpeaker(speakerName));
                    }
                }
                break;

                case BinaryDialogKind.Selection:
                {
                    var binaryMessage = ( BinarySelectionDialog )messageHeader.Data.Value;
                    pageStartAddresses = binaryMessage.OptionStartAddresses;
                    buffer             = binaryMessage.TextBuffer;
                    pageCount          = binaryMessage.OptionCount;
                    var name = ResolveName(labelOccurences, binaryMessage.Name);
                    message = new SelectionDialog(name, (SelectionDialogPattern)binaryMessage.Pattern);
                }
                break;

                default:
                    throw new InvalidDataException("Unknown message type");
                }

                if (pageCount != 0)
                {
                    // Parse the line data
                    ParsePages(message, pageStartAddresses, buffer, instance.FormatVersion, encoding == null ? Encoding.ASCII : encoding);
                }

                // Add it to the message list
                instance.Dialogs.Add(message);
            }

            return(instance);
        }
コード例 #15
0
        public void FromFile_ShouldPassIntegrityCheck_Version1BigEndianWithVersion1Argument()
        {
            var script = MessageScriptBinary.FromFile("TestResources\\Version1BigEndian.bmd", BinaryFormatVersion.Version1);

            PerformIntegrityCheckForVersion1BigEndian(script);
        }
コード例 #16
0
 public void FromFile_ShouldThrowException_EmptyStringArgument()
 {
     Assert.ThrowsException <ArgumentException>(() => MessageScriptBinary.FromFile(String.Empty));
 }
コード例 #17
0
 public void FromFile_ShouldThrowException_NullArgument()
 {
     Assert.ThrowsException <ArgumentNullException>(() => MessageScriptBinary.FromFile(null));
 }
コード例 #18
0
 public void SetMessageScriptSection(MessageScript messageScriptSection)
 {
     mMessageScriptSection = messageScriptSection.ToBinary() ?? throw new ArgumentNullException(nameof(messageScriptSection));
 }
コード例 #19
0
        private void Compare(MessageScriptBinary binary, MessageScriptBinary newBinary)
        {
            // compare headers
            Assert.AreEqual(binary.Header.FileType, newBinary.Header.FileType);
            Assert.AreEqual(binary.Header.IsCompressed, newBinary.Header.IsCompressed);
            Assert.AreEqual(binary.Header.UserId, newBinary.Header.UserId);
            Assert.AreEqual(binary.Header.FileSize, newBinary.Header.FileSize);
            CollectionAssert.AreEqual(binary.Header.Magic, newBinary.Header.Magic);
            Assert.AreEqual(binary.Header.Field0C, newBinary.Header.Field0C);
            Assert.AreEqual(binary.Header.RelocationTable.Offset, newBinary.Header.RelocationTable.Offset);
            CollectionAssert.AreEqual(binary.Header.RelocationTable.Value, newBinary.Header.RelocationTable.Value);
            Assert.AreEqual(binary.Header.RelocationTableSize, newBinary.Header.RelocationTableSize);
            Assert.AreEqual(binary.Header.DialogCount, newBinary.Header.DialogCount);
            Assert.AreEqual(binary.Header.IsRelocated, newBinary.Header.IsRelocated);
            Assert.AreEqual(binary.Header.Field1E, newBinary.Header.Field1E);

            for (var index = 0; index < binary.DialogHeaders.Count; index++)
            {
                var header    = binary.DialogHeaders[index];
                var newHeader = newBinary.DialogHeaders[index];

                // compare message headers
                Assert.AreEqual(header.DialogKind, newHeader.DialogKind);
                Assert.AreEqual(header.Dialog.Offset, newHeader.Dialog.Offset);

                // compare message data
                switch (header.DialogKind)
                {
                case BinaryDialogKind.Message:
                {
                    var dialogue    = ( BinaryMessageDialog )header.Dialog.Value;
                    var newDialogue = ( BinaryMessageDialog )newHeader.Dialog.Value;

                    Assert.AreEqual(dialogue.Name, newDialogue.Name);
                    Assert.AreEqual(dialogue.PageCount, newDialogue.PageCount);
                    Assert.AreEqual(dialogue.SpeakerId, newDialogue.SpeakerId);
                    CollectionAssert.AreEqual(dialogue.PageStartAddresses, newDialogue.PageStartAddresses);
                    Assert.AreEqual(dialogue.TextBufferSize, newDialogue.TextBufferSize);
                    CollectionAssert.AreEqual(dialogue.TextBuffer, newDialogue.TextBuffer);
                }
                break;

                case BinaryDialogKind.Selection:
                {
                    var selection    = ( BinarySelectionDialog )header.Dialog.Value;
                    var newSelection = ( BinarySelectionDialog )newHeader.Dialog.Value;

                    Assert.AreEqual(selection.Name, newSelection.Name);
                    Assert.AreEqual(selection.Field18, newSelection.Field18);
                    Assert.AreEqual(selection.OptionCount, newSelection.OptionCount);
                    Assert.AreEqual(selection.Field1C, newSelection.Field1C);
                    Assert.AreEqual(selection.Field1E, newSelection.Field1E);
                    CollectionAssert.AreEqual(selection.OptionStartAddresses, newSelection.OptionStartAddresses);
                    Assert.AreEqual(selection.TextBufferSize, newSelection.TextBufferSize);
                    CollectionAssert.AreEqual(selection.TextBuffer, newSelection.TextBuffer);
                }
                break;

                default:
                    throw new NotImplementedException(header.DialogKind.ToString());
                }
            }

            // compare speaker table header
            Assert.AreEqual(binary.SpeakerTableHeader.SpeakerNameArray.Offset, newBinary.SpeakerTableHeader.SpeakerNameArray.Offset);
            Assert.AreEqual(binary.SpeakerTableHeader.SpeakerCount, newBinary.SpeakerTableHeader.SpeakerCount);
            Assert.AreEqual(binary.SpeakerTableHeader.Field08, newBinary.SpeakerTableHeader.Field08);
            Assert.AreEqual(binary.SpeakerTableHeader.Field0C, newBinary.SpeakerTableHeader.Field0C);

            for (int i = 0; i < binary.SpeakerTableHeader.SpeakerNameArray.Value.Length; i++)
            {
                var speakername    = binary.SpeakerTableHeader.SpeakerNameArray.Value[i];
                var newSpeakername = newBinary.SpeakerTableHeader.SpeakerNameArray.Value[i];

                Assert.AreEqual(speakername.Offset, newSpeakername.Offset);
                CollectionAssert.AreEqual(speakername.Value, newSpeakername.Value);
            }
        }
コード例 #20
0
 public void FromFile_ShouldThrowException_InvalidFileFormat()
 {
     Assert.ThrowsException <InvalidDataException>(() => MessageScriptBinary.FromFile("TestResources\\dummy_big.bin"));
 }
コード例 #21
0
 public void FromBinary_ShouldNotThrow_Version1BigEndian()
 {
     var binary = MessageScriptBinary.FromFile("TestResources\\Version1BigEndian.bmd");
     var script = MessageScript.FromBinary(binary);
 }
コード例 #22
0
        public void FromFile_ShouldPassIntegrityCheck_Version1WithUnknownVersionArgument()
        {
            var script = MessageScriptBinary.FromFile("TestResources\\Version1.bmd");

            PerformIntegrityCheckForVersion1(script);
        }