protected override IList <Subtitle> GetSubtitles()
        {
            var result = new List <Subtitle>();

            var dictionary = new Dictionary <string, bool>();

            string text = System.IO.File.ReadAllText(Path, FileEncoding);

            text = text.Replace("\n", "\\n");

            string[] items = text.Split('■');
            for (int i = 0; i < items.Length - 1; i++)
            {
                var data = items[i].Split('◆');

                if (!dictionary.ContainsKey(data[0]))
                {
                    var subtitle = new SubtitleWithId
                    {
                        Id          = data[0],
                        Offset      = 0,
                        Text        = data[1],
                        Loaded      = data[1],
                        Translation = data[1]
                    };
                    subtitle.PropertyChanged += SubtitlePropertyChanged;
                    result.Add(subtitle);
                    dictionary.Add(data[0], true);
                }
            }

            LoadChanges(result);

            return(result);
        }
        protected override IList <Subtitle> GetSubtitles()
        {
            var result = new List <Subtitle>();

            using (var fs = new FileStream(Path, FileMode.Open))
                using (var input = new ExtendedBinaryReader(fs, FileEncoding))
                {
                    int arraySize = input.ReadInt32();
                    for (int i = 0; i < arraySize; i++)
                    {
                        string focusObj = input.ReadStringSerialized(0x04);

                        string text = input.ReadStringSerialized(0x04);

                        var subtitle = new SubtitleWithId
                        {
                            Id          = focusObj,
                            Offset      = 0,
                            Text        = text,
                            Loaded      = text,
                            Translation = text
                        };

                        subtitle.PropertyChanged += SubtitlePropertyChanged;
                        result.Add(subtitle);
                    }
                }

            LoadChanges(result);

            return(result);
        }
Example #3
0
        protected override IList <Subtitle> GetSubtitles()
        {
            var result = new List <Subtitle>();

            using (var fs = new FileStream(Path, FileMode.Open))
                using (var input = new ExtendedBinaryReader(fs, FileEncoding))
                {
                    var count = input.ReadInt32();
                    for (int i = 0; i < count; i++)
                    {
                        // UILabel
                        input.Skip(0x04);
                        input.Skip(0x08);
                        var strJap = input.ReadStringSerialized(0x04);
                        var strEng = input.ReadStringSerialized(0x04);

                        var subtitle = new SubtitleWithId
                        {
                            Id          = (i + 1).ToString(),
                            Offset      = 0,
                            Text        = strEng,
                            Loaded      = strEng,
                            Translation = strEng
                        };

                        subtitle.PropertyChanged += SubtitlePropertyChanged;
                        result.Add(subtitle);
                    }
                }

            LoadChanges(result);

            return(result);
        }
        protected override IList <Subtitle> GetSubtitles()
        {
            var result = new List <Subtitle>();

            using (var fs = new FileStream(Path, FileMode.Open))
                using (var input = new ExtendedBinaryReader(fs, FileEncoding))
                {
                    // Material
                    input.Skip(0x04);
                    input.Skip(0x08);

                    // ColorRGBA
                    input.Skip(4 * 0x04);

                    // RaycastTarget
                    input.Skip(0x04);

                    // CullStateChangedEvent
                    int persistentCallCount = input.ReadInt32();
                    for (int i = 0; i < persistentCallCount; i++)
                    {
                        // PersistentCall
                    }

                    // FontData
                    input.Skip(0x04);
                    input.Skip(0x08);
                    input.Skip(0x04); // Font size
                    input.Skip(0x04); // Font style
                    input.Skip(0x04); // Best Fit
                    input.Skip(0x04); // Min size
                    input.Skip(0x04); // Max size
                    input.Skip(0x04); // Alignment
                    input.Skip(0x04); // Align by geometry
                    input.Skip(0x04); // Rich Text
                    input.Skip(0x04); // Horizontal Overflow
                    input.Skip(0x04); // Vertical Overflow
                    input.Skip(0x04); // Line spacing

                    string sub = input.ReadStringSerialized(0x04);

                    var subtitle = new SubtitleWithId
                    {
                        Id          = sub,
                        Offset      = 0,
                        Text        = sub,
                        Loaded      = sub,
                        Translation = sub
                    };

                    subtitle.PropertyChanged += SubtitlePropertyChanged;
                    result.Add(subtitle);
                }

            LoadChanges(result);

            return(result);
        }
        protected override IList <Subtitle> GetSubtitles()
        {
            var result = new List <Subtitle>();

            using (var fs = new FileStream(Path, FileMode.Open))
                using (var input = new ExtendedBinaryReader(fs, FileEncoding))
                {
                    input.Skip(0x0C);

                    int termCount = input.ReadInt32();

                    for (int termIndex = 0; termIndex < termCount; termIndex++)
                    {
                        string term     = input.ReadStringSerialized(0x04);
                        int    termType = input.ReadInt32();

                        string description = input.ReadStringSerialized(0x04);

                        int languageCount = input.ReadInt32();

                        for (int i = 0; i < languageCount; i++)
                        {
                            string sub = input.ReadStringSerialized(0x04);

                            if (i == LanguageIndex && !string.IsNullOrEmpty(sub))
                            {
                                var subtitle = new SubtitleWithId
                                {
                                    Id          = term,
                                    Offset      = 0,
                                    Text        = sub,
                                    Loaded      = sub,
                                    Translation = sub
                                };

                                subtitle.PropertyChanged += SubtitlePropertyChanged;
                                result.Add(subtitle);
                            }
                        }

                        int flagCount = input.ReadInt32();
                        input.Skip(flagCount);
                        input.SkipPadding(0x04);

                        int languageTouchCount = input.ReadInt32();
                        for (int i = 0; i < languageTouchCount; i++)
                        {
                            input.ReadStringSerialized(0x04);
                        }
                    }
                }

            LoadChanges(result);

            return(result);
        }
        protected override IList <Subtitle> GetSubtitles()
        {
            var result = new List <Subtitle>();

            using (var fs = new FileStream(Path, FileMode.Open))
                using (var input = new ExtendedBinaryReader(fs, FileEncoding))
                {
                    // AnchorPoints
                    for (int i = 0; i < 4; i++)
                    {
                        input.Skip(0x0C);
                        input.Skip(0x08);
                    }

                    input.Skip(0x04);     // updateAnchors
                    input.Skip(4 * 0x04); // Color
                    input.Skip(0x04);     // pivot
                    input.Skip(0x04);     // width
                    input.Skip(0x04);     // height
                    input.Skip(0x04);     // depth
                    input.Skip(0x04);     // autoresizeBoxCollider
                    input.Skip(0x04);     // hideIfOffScreen
                    input.Skip(0x04);     // keepAspectRatio
                    input.Skip(0x04);     // aspectRatio
                    input.Skip(0x04);     // keepCrispWhenShrunk
                    input.Skip(0x0C);     // truetypefont
                    input.Skip(0x0C);     // font

                    var str = input.ReadStringSerialized(0x04);

                    var subtitle = new SubtitleWithId
                    {
                        Id          = str,
                        Offset      = 0,
                        Text        = str,
                        Loaded      = str,
                        Translation = str
                    };

                    subtitle.PropertyChanged += SubtitlePropertyChanged;
                    result.Add(subtitle);
                }

            LoadChanges(result);

            return(result);
        }
        protected override IList <Subtitle> GetSubtitles()
        {
            var tempFile = System.IO.Path.GetTempFileName();

            UnderRailTool.Run("r", Path, tempFile, string.Empty);

            var result = new List <Subtitle>();

            if (System.IO.File.Exists(tempFile))
            {
                var lines = System.IO.File.ReadAllLines(tempFile);
                System.IO.File.Delete(tempFile);

                if (lines.Length > 0)
                {
                    var dictionary = lines.Select(line => line.Split(new[] { "<Split>" }, StringSplitOptions.None))
                                     .ToDictionary(split => split[0], split => split[1]);

                    foreach (var pair in dictionary)
                    {
                        var sub = new SubtitleWithId
                        {
                            Id          = pair.Key,
                            Text        = pair.Value,
                            Loaded      = pair.Value,
                            Translation = pair.Value,
                            Offset      = 0,
                        };
                        sub.PropertyChanged += SubtitlePropertyChanged;

                        result.Add(sub);
                    }

                    LoadChanges(result);
                }
            }

            return(result);
        }
        protected override IList <Subtitle> GetSubtitles()
        {
            var         result = new List <Subtitle>();
            ModuleDefMD module = ModuleDefMD.Load(Path);

            foreach (TypeDef t in module.Types)
            {
                foreach (MethodDef m in t.Methods)
                {
                    if (!m.HasBody)
                    {
                        continue;
                    }

                    foreach (Instruction instr in m.Body.Instructions)
                    {
                        if (instr.OpCode != OpCodes.Ldstr)
                        {
                            continue;
                        }

                        string str      = (string)instr.Operand;
                        var    subtitle = new SubtitleWithId {
                            Text = str, Loaded = str, Translation = str, Id = $"{t.Name}/{m.Name}/{m.RVA.ToString()}/{instr.Offset}"
                        };
                        subtitle.PropertyChanged += SubtitlePropertyChanged;
                        result.Add(subtitle);
                    }
                }
            }

            result.Sort();
            LoadChanges(result);

            return(result);
        }
        protected override IList <Subtitle> GetSubtitles()
        {
            var result = new List <Subtitle>();
            var module = ModuleDefMD.Load(Path);

            foreach (var t in module.Types)
            {
                foreach (var a in t.CustomAttributes)
                {
                    for (var i = a.ConstructorArguments.Count - 1; i >= 0; i--)
                    {
                        var arg = a.ConstructorArguments[i];
                        if (arg.Type.FullName == "System.String")
                        {
                            var str      = ((UTF8String)arg.Value).String.Replace("\r\n", "\\r\\n");
                            var id       = $"{t.Name}_attr_{a.TypeFullName}_arg_{i}";
                            var subtitle = new SubtitleWithId {
                                Id = id, Text = str, Loaded = str, Translation = str, Offset = 0
                            };
                            subtitle.PropertyChanged += SubtitlePropertyChanged;
                            result.Add(subtitle);
                        }
                    }
                }

                foreach (var f in t.Fields)
                {
                    var str = string.Empty;
                    if (f.HasConstant && f.FieldType.FullName == "System.String")
                    {
                        str = ((string)f.Constant.Value).Replace("\r\n", "\\r\\n");
                    }
                    else if (f.HasConstant && translatableEnums.Contains(f.FieldType.FullName))
                    {
                        str = f.Name.String;
                    }

                    if (!string.IsNullOrEmpty(str))
                    {
                        var id       = $"{t.Name}_field_{f.Name.String}";
                        var subtitle = new SubtitleWithId {
                            Id = id, Text = str, Loaded = str, Translation = str, Offset = 0
                        };
                        subtitle.PropertyChanged += SubtitlePropertyChanged;
                        result.Add(subtitle);
                    }
                }

                foreach (var m in t.Methods)
                {
                    if (!m.HasBody)
                    {
                        continue;
                    }

                    foreach (var instr in m.Body.Instructions)
                    {
                        if (instr.OpCode != OpCodes.Ldstr)
                        {
                            continue;
                        }

                        var str = ((string)(instr.Operand)).Replace("\r\n", "\\r\\n");

                        var id       = $"{t.Name}_method_{m.Name}_rva_{m.RVA}_{instr.Offset}";
                        var subtitle = new SubtitleWithId {
                            Id = id, Text = str, Loaded = str, Translation = str, Offset = 0
                        };
                        subtitle.PropertyChanged += SubtitlePropertyChanged;
                        result.Add(subtitle);
                    }
                }
            }

            result.Sort();
            LoadChanges(result);

            return(result);
        }
        protected void Rebuild(ExtendedBinaryReader input, ExtendedBinaryWriter output,
                               Dictionary <string, SubtitleWithId> dictionary)
        {
            string version = input.ReadStringSerialized(0x04);

            output.WriteStringSerialized(version, 0x04);
            string author = input.ReadStringSerialized(0x04);

            output.WriteStringSerialized(author, 0x04);
            string description = input.ReadStringSerialized(0x04);

            output.WriteStringSerialized(description, 0x04);
            string globalUserScript = input.ReadStringSerialized(0x04);

            output.WriteStringSerialized(globalUserScript, 0x04);

            int emphasisSettingCount = input.ReadInt32();

            output.Write(emphasisSettingCount);
            output.Write(input.ReadBytes(emphasisSettingCount * 0x04 * 0x07));

            int actorCount = input.ReadInt32();

            output.Write(actorCount);
            for (int i = 0; i < actorCount; i++)
            {
                int id = input.ReadInt32();
                output.Write(id);
                int fieldCount = input.ReadInt32();
                output.Write(fieldCount);

                var fields = new Dictionary <string, Field>(fieldCount);
                for (int j = 0; j < fieldCount; j++)
                {
                    var field = new Field();
                    field.Title      = input.ReadStringSerialized(0x04);
                    field.Value      = input.ReadStringSerialized(0x04);
                    field.Type       = input.ReadInt32();
                    field.TypeString = input.ReadStringSerialized(0x04);

                    fields.Add(field.Title, field);
                }

                var translatableFields = new string[] { "Name", "LongDescription", "short_description" };
                foreach (KeyValuePair <string, Field> kvp in fields)
                {
                    output.WriteStringSerialized(kvp.Value.Title, 0x04);
                    if (translatableFields.Contains(kvp.Value.Title) && !string.IsNullOrEmpty(kvp.Value.Value))
                    {
                        string         key      = $"Actor_{id}_{kvp.Value.Title}";
                        SubtitleWithId subtitle = dictionary[key];
                        output.WriteStringSerialized(subtitle.Translation, 0x04);
                    }
                    else
                    {
                        output.WriteStringSerialized(kvp.Value.Value, 0x04);
                    }

                    output.Write(kvp.Value.Type);
                    output.WriteStringSerialized(kvp.Value.TypeString, 0x04);
                }

                output.Write(input.ReadBytes(0x0C)); // portrait
                output.Write(input.ReadBytes(0x0C)); // spritePortrait
                output.Write(input.ReadBytes(0x04)); // alternatePortraits
                output.Write(input.ReadBytes(0x04)); // spritePortraits
            }

            int itemCount = input.ReadInt32();

            output.Write(itemCount);
            for (int i = 0; i < itemCount; i++)
            {
                int id = input.ReadInt32();
                output.Write(id);
                int fieldCount = input.ReadInt32();
                output.Write(fieldCount);

                var fields = new Dictionary <string, Field>(fieldCount);
                for (int j = 0; j < fieldCount; j++)
                {
                    var field = new Field();
                    field.Title      = input.ReadStringSerialized(0x04);
                    field.Value      = input.ReadStringSerialized(0x04);
                    field.Type       = input.ReadInt32();
                    field.TypeString = input.ReadStringSerialized(0x04);

                    fields.Add(field.Title, field);
                }

                var translatableFields = new string[]
                {
                    "Description", "displayname", "description", "fixtureBonus", "requirement", "bonus",
                    "fixtureDescription"
                };
                foreach (KeyValuePair <string, Field> kvp in fields)
                {
                    output.WriteStringSerialized(kvp.Value.Title, 0x04);
                    if (translatableFields.Contains(kvp.Value.Title) && !string.IsNullOrEmpty(kvp.Value.Value))
                    {
                        string         key      = $"Item_{id}_{kvp.Value.Title}";
                        SubtitleWithId subtitle = dictionary[key];
                        output.WriteStringSerialized(subtitle.Translation, 0x04);
                    }
                    else
                    {
                        output.WriteStringSerialized(kvp.Value.Value, 0x04);
                    }

                    output.Write(kvp.Value.Type);
                    output.WriteStringSerialized(kvp.Value.TypeString, 0x04);
                }
            }

            int locationCount = input.ReadInt32();

            output.Write(locationCount);
            for (int i = 0; i < locationCount; i++)
            {
                int id = input.ReadInt32();
                output.Write(id);
                int fieldCount = input.ReadInt32();
                output.Write(fieldCount);

                var fields = new Dictionary <string, Field>(fieldCount);
                for (int j = 0; j < fieldCount; j++)
                {
                    var field = new Field();
                    field.Title      = input.ReadStringSerialized(0x04);
                    field.Value      = input.ReadStringSerialized(0x04);
                    field.Type       = input.ReadInt32();
                    field.TypeString = input.ReadStringSerialized(0x04);

                    fields.Add(field.Title, field);
                }

                var translatableFields = new string[] { "Name" };
                foreach (KeyValuePair <string, Field> kvp in fields)
                {
                    output.WriteStringSerialized(kvp.Value.Title, 0x04);
                    if (translatableFields.Contains(kvp.Value.Title) && !string.IsNullOrEmpty(kvp.Value.Value))
                    {
                        string         key      = $"Location_{id}_{kvp.Value.Title}";
                        SubtitleWithId subtitle = dictionary[key];
                        output.WriteStringSerialized(subtitle.Translation, 0x04);
                    }
                    else
                    {
                        output.WriteStringSerialized(kvp.Value.Value, 0x04);
                    }

                    output.Write(kvp.Value.Type);
                    output.WriteStringSerialized(kvp.Value.TypeString, 0x04);
                }
            }

            int variableCount = input.ReadInt32();

            output.Write(variableCount);
            for (int i = 0; i < variableCount; i++)
            {
                int id = input.ReadInt32();
                output.Write(id);
                int fieldCount = input.ReadInt32();
                output.Write(fieldCount);

                var fields = new Dictionary <string, Field>(fieldCount);
                for (int j = 0; j < fieldCount; j++)
                {
                    var field = new Field();
                    field.Title      = input.ReadStringSerialized(0x04);
                    field.Value      = input.ReadStringSerialized(0x04);
                    field.Type       = input.ReadInt32();
                    field.TypeString = input.ReadStringSerialized(0x04);

                    fields.Add(field.Title, field);
                }

                var translatableFields = new string[] { "Description" };
                foreach (KeyValuePair <string, Field> kvp in fields)
                {
                    output.WriteStringSerialized(kvp.Value.Title, 0x04);
                    if (translatableFields.Contains(kvp.Value.Title) && !string.IsNullOrEmpty(kvp.Value.Value))
                    {
                        string         key      = $"Variable_{id}_{kvp.Value.Title}";
                        SubtitleWithId subtitle = dictionary[key];
                        output.WriteStringSerialized(subtitle.Translation, 0x04);
                    }
                    else
                    {
                        output.WriteStringSerialized(kvp.Value.Value, 0x04);
                    }

                    output.Write(kvp.Value.Type);
                    output.WriteStringSerialized(kvp.Value.TypeString, 0x04);
                }
            }

            int conversationCount = input.ReadInt32();

            output.Write(conversationCount);
            for (int i = 0; i < conversationCount; i++)
            {
                int id = input.ReadInt32();
                output.Write(id);
                int fieldCount = input.ReadInt32();
                output.Write(fieldCount);

                var fields = new Dictionary <string, Field>(fieldCount);
                for (int j = 0; j < fieldCount; j++)
                {
                    var field = new Field();
                    field.Title      = input.ReadStringSerialized(0x04);
                    field.Value      = input.ReadStringSerialized(0x04);
                    field.Type       = input.ReadInt32();
                    field.TypeString = input.ReadStringSerialized(0x04);

                    fields.Add(field.Title, field);
                }

                var translatableFields = new string[]
                {
                    "Title", "Description",
                    "subtask_title_01", "subtask_title_02",
                    "subtask_title_03", "subtask_title_04",
                    "subtask_title_05", "subtask_title_06",
                    "subtask_title_07", "subtask_title_08",
                    "subtask_title_09", "subtask_title_10",
                };
                foreach (KeyValuePair <string, Field> kvp in fields)
                {
                    output.WriteStringSerialized(kvp.Value.Title, 0x04);
                    if (translatableFields.Contains(kvp.Value.Title) && !string.IsNullOrEmpty(kvp.Value.Value))
                    {
                        string         key      = $"Conversation_{id}_{kvp.Value.Title}";
                        SubtitleWithId subtitle = dictionary[key];
                        output.WriteStringSerialized(subtitle.Translation, 0x04);
                    }
                    else
                    {
                        output.WriteStringSerialized(kvp.Value.Value, 0x04);
                    }

                    output.Write(kvp.Value.Type);
                    output.WriteStringSerialized(kvp.Value.TypeString, 0x04);
                }

                // ConversationOverrideDisplaySettings
                output.Write(input.ReadBytes(0x28));
                for (int j = 0; j < 3; j++)
                {
                    output.WriteStringSerialized(input.ReadStringSerialized(0x04), 0x04);
                }

                output.Write(input.ReadBytes(0x10));

                output.WriteStringSerialized(input.ReadStringSerialized(0x04), 0x04); // nodeColor

                // DialogueEntry
                int dialogueEntryCount = input.ReadInt32();
                output.Write(dialogueEntryCount);
                for (int j = 0; j < dialogueEntryCount; j++)
                {
                    int dialogueEntryId = input.ReadInt32();
                    output.Write(dialogueEntryId);
                    int fieldCount2 = input.ReadInt32();
                    output.Write(fieldCount2);

                    var fields2 = new Dictionary <string, Field>(fieldCount2);
                    for (int k = 0; k < fieldCount2; k++)
                    {
                        var field = new Field();
                        field.Title      = input.ReadStringSerialized(0x04);
                        field.Value      = input.ReadStringSerialized(0x04);
                        field.Type       = input.ReadInt32();
                        field.TypeString = input.ReadStringSerialized(0x04);

                        fields2.Add($"{field.Title}", field);
                    }

                    var translatableFields2 = new string[]
                    {
                        "Dialogue Text", "Alternate1", "Alternate2", "Alternate3", "Alternate4", "tooltip1", "tooltip2",
                        "tooltip3", "tooltip4", "tooltip5", "tooltip6", "tooltip7", "tooltip8", "tooltip9", "tooltip10"
                    };
                    foreach (KeyValuePair <string, Field> kvp in fields2)
                    {
                        output.WriteStringSerialized(kvp.Value.Title, 0x04);
                        if (translatableFields2.Contains(kvp.Value.Title) && !string.IsNullOrEmpty(kvp.Value.Value))
                        {
                            string         key      = $"Conversation_{id}_Entry_{dialogueEntryId}_{kvp.Value.Title}";
                            SubtitleWithId subtitle = dictionary[key];
                            output.WriteStringSerialized(subtitle.Translation, 0x04);
                        }
                        else
                        {
                            output.WriteStringSerialized(kvp.Value.Value, 0x04);
                        }

                        output.Write(kvp.Value.Type);
                        output.WriteStringSerialized(kvp.Value.TypeString, 0x04);
                    }

                    output.Write(input.ReadBytes(0x0C));
                    output.WriteStringSerialized(input.ReadStringSerialized(0x04), 0x04); // nodeColor
                    output.Write(input.ReadBytes(0x04));
                    output.WriteStringSerialized(input.ReadStringSerialized(0x04), 0x04); // falseConditionAction
                    output.Write(input.ReadBytes(0x04));

                    int outgoingLinksCount = input.ReadInt32();
                    output.Write(outgoingLinksCount);
                    output.Write(input.ReadBytes(outgoingLinksCount * 0x04 * 0x06));

                    output.WriteStringSerialized(input.ReadStringSerialized(0x04), 0x04); // conditionsString
                    string userScript = input.ReadStringSerialized(0x04);                 // userScript

                    if (userScript.StartsWith("NewspaperEndgame("))
                    {
                        var   regex = new Regex(@"NewspaperEndgame\(""(?<Id>[^""]+)"",""(?<Headline>[^""]+)"",""(?<Text>[^""\\]*(?:\\.[^""\\]*)*)""\)");
                        Match match = regex.Match(userScript);

                        while (match.Success)
                        {
                            string endId = match.Groups["Id"].Value;

                            string headlineKey = $"Conversation_{id}_Entry_{dialogueEntryId}_EndHeadline";
                            string textKey     = $"Conversation_{id}_Entry_{dialogueEntryId}_EndText";

                            if (!dictionary.ContainsKey(headlineKey) || !dictionary.ContainsKey(textKey))
                            {
                                output.WriteStringSerialized(userScript, 0x04);
                            }
                            else
                            {
                                SubtitleWithId headline = dictionary[headlineKey];
                                SubtitleWithId text     = dictionary[textKey];

                                string escapedText = text.Translation.Replace("\"", "\\\"").Replace("\\n", "<NewLine>");
                                output.WriteStringSerialized($@"NewspaperEndgame(""{endId}"",""{headline}"",""{escapedText}"")", 0x04);
                            }

                            match = match.NextMatch();
                        }
                    }
                    else
                    {
                        output.WriteStringSerialized(userScript, 0x04);
                    }

                    // onExecute
                    output.Write(input.ReadBytes(0x04));

                    output.Write(input.ReadBytes(0x10)); // Canvas rect
                }

                output.Write(input.ReadBytes(0x08)); // canvasScrollPosition
                output.Write(input.ReadBytes(0x04)); // canvasZoom
            }

            int remainderLength = (int)(input.Length - input.Position);

            byte[] remainder = input.ReadBytes(remainderLength);
            output.Write(remainder);
        }
        protected IList <Subtitle> GetSubtitles(ExtendedBinaryReader input)
        {
            var result = new List <Subtitle>();

            string version          = input.ReadStringSerialized(0x04);
            string author           = input.ReadStringSerialized(0x04);
            string description      = input.ReadStringSerialized(0x04);
            string globalUserScript = input.ReadStringSerialized(0x04);

            int emphasisSettingCount = input.ReadInt32();

            input.Skip(emphasisSettingCount * 0x04 * 0x07);

            int actorCount = input.ReadInt32();

            for (int i = 0; i < actorCount; i++)
            {
                int id         = input.ReadInt32();
                int fieldCount = input.ReadInt32();

                var fields = new Dictionary <string, Field>(fieldCount);
                for (int j = 0; j < fieldCount; j++)
                {
                    var field = new Field();
                    field.Title      = input.ReadStringSerialized(0x04);
                    field.Value      = input.ReadStringSerialized(0x04);
                    field.Type       = input.ReadInt32();
                    field.TypeString = input.ReadStringSerialized(0x04);

                    fields.Add(field.Title, field);
                }

                var translatableFields = new string[] { "Name", "LongDescription", "short_description" };
                foreach (string translatableField in translatableFields)
                {
                    if (fields.TryGetValue(translatableField, out Field field))
                    {
                        if (!string.IsNullOrEmpty(field.Value))
                        {
                            var subtitle = new SubtitleWithId
                            {
                                Id          = $"Actor_{id}_{translatableField}",
                                Offset      = 0,
                                Text        = field.Value,
                                Loaded      = field.Value,
                                Translation = field.Value
                            };

                            subtitle.PropertyChanged += SubtitlePropertyChanged;
                            result.Add(subtitle);
                        }
                    }
                }

                input.Skip(0x0C); // portrait
                input.Skip(0x0C); // spritePortrait
                input.Skip(0x04); // alternatePortraits
                input.Skip(0x04); // spritePortraits
            }

            int itemCount = input.ReadInt32();

            for (int i = 0; i < itemCount; i++)
            {
                int id         = input.ReadInt32();
                int fieldCount = input.ReadInt32();

                var fields = new Dictionary <string, Field>(fieldCount);
                for (int j = 0; j < fieldCount; j++)
                {
                    var field = new Field();
                    field.Title      = input.ReadStringSerialized(0x04);
                    field.Value      = input.ReadStringSerialized(0x04);
                    field.Type       = input.ReadInt32();
                    field.TypeString = input.ReadStringSerialized(0x04);

                    fields.Add(field.Title, field);
                }

                var translatableFields = new string[]
                {
                    "Description", "displayname", "description", "fixtureBonus", "requirement", "bonus",
                    "fixtureDescription"
                };
                foreach (string translatableField in translatableFields)
                {
                    if (fields.TryGetValue(translatableField, out Field field))
                    {
                        if (!string.IsNullOrEmpty(field.Value))
                        {
                            var subtitle = new SubtitleWithId
                            {
                                Id          = $"Item_{id}_{translatableField}",
                                Offset      = 0,
                                Text        = field.Value,
                                Loaded      = field.Value,
                                Translation = field.Value
                            };

                            subtitle.PropertyChanged += SubtitlePropertyChanged;
                            result.Add(subtitle);
                        }
                    }
                }
            }

            int locationCount = input.ReadInt32();

            for (int i = 0; i < locationCount; i++)
            {
                int id         = input.ReadInt32();
                int fieldCount = input.ReadInt32();

                var fields = new Dictionary <string, Field>(fieldCount);
                for (int j = 0; j < fieldCount; j++)
                {
                    var field = new Field();
                    field.Title      = input.ReadStringSerialized(0x04);
                    field.Value      = input.ReadStringSerialized(0x04);
                    field.Type       = input.ReadInt32();
                    field.TypeString = input.ReadStringSerialized(0x04);

                    fields.Add(field.Title, field);
                }

                var translatableFields = new string[] { "Name" };
                foreach (string translatableField in translatableFields)
                {
                    if (fields.TryGetValue(translatableField, out Field field))
                    {
                        if (!string.IsNullOrEmpty(field.Value))
                        {
                            var subtitle = new SubtitleWithId
                            {
                                Id          = $"Location_{id}_{translatableField}",
                                Offset      = 0,
                                Text        = field.Value,
                                Loaded      = field.Value,
                                Translation = field.Value
                            };

                            subtitle.PropertyChanged += SubtitlePropertyChanged;
                            result.Add(subtitle);
                        }
                    }
                }
            }

            int variableCount = input.ReadInt32();

            for (int i = 0; i < variableCount; i++)
            {
                int id         = input.ReadInt32();
                int fieldCount = input.ReadInt32();

                var fields = new Dictionary <string, Field>(fieldCount);
                for (int j = 0; j < fieldCount; j++)
                {
                    var field = new Field();
                    field.Title      = input.ReadStringSerialized(0x04);
                    field.Value      = input.ReadStringSerialized(0x04);
                    field.Type       = input.ReadInt32();
                    field.TypeString = input.ReadStringSerialized(0x04);

                    fields.Add(field.Title, field);
                }

                var translatableFields = new string[] { "Description" };
                foreach (string translatableField in translatableFields)
                {
                    if (fields.TryGetValue(translatableField, out Field field))
                    {
                        if (!string.IsNullOrEmpty(field.Value))
                        {
                            var subtitle = new SubtitleWithId
                            {
                                Id          = $"Variable_{id}_{translatableField}",
                                Offset      = 0,
                                Text        = field.Value,
                                Loaded      = field.Value,
                                Translation = field.Value
                            };

                            subtitle.PropertyChanged += SubtitlePropertyChanged;
                            result.Add(subtitle);
                        }
                    }
                }
            }

            int conversationCount = input.ReadInt32();

            for (int i = 0; i < conversationCount; i++)
            {
                int id         = input.ReadInt32();
                int fieldCount = input.ReadInt32();

                var fields = new Dictionary <string, Field>(fieldCount);
                for (int j = 0; j < fieldCount; j++)
                {
                    var field = new Field();
                    field.Title      = input.ReadStringSerialized(0x04);
                    field.Value      = input.ReadStringSerialized(0x04);
                    field.Type       = input.ReadInt32();
                    field.TypeString = input.ReadStringSerialized(0x04);

                    fields.Add(field.Title, field);
                }

                var translatableFields = new string[]
                {
                    "Title", "Description",
                    "subtask_title_01", "subtask_title_02",
                    "subtask_title_03", "subtask_title_04",
                    "subtask_title_05", "subtask_title_06",
                    "subtask_title_07", "subtask_title_08",
                    "subtask_title_09", "subtask_title_10",
                };

                foreach (string translatableField in translatableFields)
                {
                    if (fields.TryGetValue(translatableField, out Field field))
                    {
                        if (!string.IsNullOrEmpty(field.Value))
                        {
                            var subtitle = new SubtitleWithId
                            {
                                Id          = $"Conversation_{id}_{translatableField}",
                                Offset      = 0,
                                Text        = field.Value,
                                Loaded      = field.Value,
                                Translation = field.Value
                            };

                            subtitle.PropertyChanged += SubtitlePropertyChanged;
                            result.Add(subtitle);
                        }
                    }
                }

                // ConversationOverrideDisplaySettings
                input.Skip(0x28);
                for (int j = 0; j < 3; j++)
                {
                    input.ReadStringSerialized(0x04);
                }

                input.Skip(0x10);

                input.ReadStringSerialized(0x04); // nodeColor

                // DialogueEntry
                int dialogueEntryCount = input.ReadInt32();
                for (int j = 0; j < dialogueEntryCount; j++)
                {
                    int dialogueEntryId = input.ReadInt32();
                    int fieldCount2     = input.ReadInt32();

                    var fields2 = new Dictionary <string, Field>(fieldCount2);
                    for (int k = 0; k < fieldCount2; k++)
                    {
                        var field = new Field();
                        field.Title      = input.ReadStringSerialized(0x04);
                        field.Value      = input.ReadStringSerialized(0x04);
                        field.Type       = input.ReadInt32();
                        field.TypeString = input.ReadStringSerialized(0x04);

                        fields2.Add($"{field.Title}", field);
                    }

                    var translatableFields2 = new string[]
                    {
                        "Dialogue Text", "Alternate1", "Alternate2", "Alternate3", "Alternate4", "tooltip1", "tooltip2",
                        "tooltip3", "tooltip4", "tooltip5", "tooltip6", "tooltip7", "tooltip8", "tooltip9", "tooltip10"
                    };
                    foreach (string translatableField in translatableFields2)
                    {
                        if (fields2.TryGetValue(translatableField, out Field field))
                        {
                            if (!string.IsNullOrEmpty(field.Value))
                            {
                                var subtitle = new SubtitleWithId
                                {
                                    Id          = $"Conversation_{id}_Entry_{dialogueEntryId}_{translatableField}",
                                    Offset      = 0,
                                    Text        = field.Value,
                                    Loaded      = field.Value,
                                    Translation = field.Value
                                };

                                subtitle.PropertyChanged += SubtitlePropertyChanged;
                                result.Add(subtitle);
                            }
                        }
                    }

                    input.Skip(0x0C);
                    input.ReadStringSerialized(0x04); // nodeColor
                    input.Skip(0x04);
                    input.ReadStringSerialized(0x04); // falseConditionAction
                    input.Skip(0x04);
                    int outgoingLinksCount = input.ReadInt32();
                    input.Skip(outgoingLinksCount * 0x04 * 0x06);

                    input.ReadStringSerialized(0x04);                     // conditionsString
                    string userScript = input.ReadStringSerialized(0x04); // userScript

                    if (userScript.StartsWith("NewspaperEndgame("))
                    {
                        var   regex = new Regex(@"NewspaperEndgame\(""(?<Id>[^""]+)"",""(?<Headline>[^""]+)"",""(?<Text>[^""\\]*(?:\\.[^""\\]*)*)""\)");
                        Match match = regex.Match(userScript);

                        while (match.Success)
                        {
                            string endId    = match.Groups["Id"].Value;
                            string headline = match.Groups["Headline"].Value;
                            string text     = match.Groups["Text"].Value;

                            var subtitle = new SubtitleWithId
                            {
                                Id          = $"Conversation_{id}_Entry_{dialogueEntryId}_EndHeadline",
                                Offset      = 0,
                                Text        = headline,
                                Loaded      = headline,
                                Translation = headline
                            };

                            subtitle.PropertyChanged += SubtitlePropertyChanged;
                            result.Add(subtitle);

                            text     = text.Replace("<NewLine>", "\\n").Replace("\\\"", "\"");
                            subtitle = new SubtitleWithId
                            {
                                Id          = $"Conversation_{id}_Entry_{dialogueEntryId}_EndText",
                                Offset      = 0,
                                Text        = text,
                                Loaded      = text,
                                Translation = text
                            };

                            subtitle.PropertyChanged += SubtitlePropertyChanged;
                            result.Add(subtitle);

                            match = match.NextMatch();
                        }
                    }

                    // onExecute
                    input.Skip(0x04);

                    input.Skip(0x10); // Canvas rect
                }

                input.Skip(0x08); // canvasScrollPosition
                input.Skip(0x04); // canvasZoom
            }

            LoadChanges(result);

            return(result);
        }