public void ToBinary_ShouldMatchSourceBinary_Version1BigEndian() { var binary = MessageScriptBinary.FromFile("TestResources\\Version1BigEndian.bmd"); var script = MessageScript.FromBinary(binary); var newBinary = script.ToBinary(); Compare(binary, newBinary); }
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); }
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); }
/// <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)); }
/// <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)); }
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; } } }
public MessageScriptBinary ReadBinary() { var binary = new MessageScriptBinary { mHeader = ReadHeader() }; binary.mDialogHeaders = ReadDialogHeaders(binary.mHeader.DialogCount); binary.mSpeakerTableHeader = ReadSpeakerTableHeader(); binary.mFormatVersion = mVersion; return(binary); }
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"); } }
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); }
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); }
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}"); } } }
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}"); } } }
public void FromStream_ShouldPassIntegrityCheck_Version1BigEndian() { var script = MessageScriptBinary.FromStream(File.OpenRead("TestResources\\Version1BigEndian.bmd")); PerformIntegrityCheckForVersion1BigEndian(script); }
// 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); }
public void FromFile_ShouldPassIntegrityCheck_Version1BigEndianWithVersion1Argument() { var script = MessageScriptBinary.FromFile("TestResources\\Version1BigEndian.bmd", BinaryFormatVersion.Version1); PerformIntegrityCheckForVersion1BigEndian(script); }
public void FromFile_ShouldThrowException_EmptyStringArgument() { Assert.ThrowsException <ArgumentException>(() => MessageScriptBinary.FromFile(String.Empty)); }
public void FromFile_ShouldThrowException_NullArgument() { Assert.ThrowsException <ArgumentNullException>(() => MessageScriptBinary.FromFile(null)); }
public void SetMessageScriptSection(MessageScript messageScriptSection) { mMessageScriptSection = messageScriptSection.ToBinary() ?? throw new ArgumentNullException(nameof(messageScriptSection)); }
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); } }
public void FromFile_ShouldThrowException_InvalidFileFormat() { Assert.ThrowsException <InvalidDataException>(() => MessageScriptBinary.FromFile("TestResources\\dummy_big.bin")); }
public void FromBinary_ShouldNotThrow_Version1BigEndian() { var binary = MessageScriptBinary.FromFile("TestResources\\Version1BigEndian.bmd"); var script = MessageScript.FromBinary(binary); }
public void FromFile_ShouldPassIntegrityCheck_Version1WithUnknownVersionArgument() { var script = MessageScriptBinary.FromFile("TestResources\\Version1.bmd"); PerformIntegrityCheckForVersion1(script); }