using System; using System.Collections.Generic; using System.Globalization; using System.IO; using System.Text; using Nikse.SubtitleEdit.Core.Interfaces; namespace Nikse.SubtitleEdit.Core.SubtitleFormats { public class Cavena890 : SubtitleFormat, IBinaryPersistableSubtitle { public const int LanguageIdDanish = 0x07; public const int LanguageIdEnglish = 0x09; public const int LanguageIdRussian = 0x56; public const int LanguageIdArabic = 0x80; public const int LanguageIdHebrew = 0x8f; public const int LanguageIdChineseTraditional = 0x90; public const int LanguageIdChineseSimplified = 0x91; public const int LanguageIdRomanian = 0x22; private static readonly List HebrewCodes = new List { 0x40, // א 0x41, // ב 0x42, // ג 0x43, // ד 0x44, // ה 0x45, // ו 0x46, // ז 0x47, // ח 0x49, // י 0x4c, // ל 0x4d, // ם 0x4e, // מ 0x4f, // ן 0x50, // נ 0x51, // ס 0x52, // ע 0x54, // פ 0x56, // צ 0x57, // ק 0x58, // ר 0x59, // ש 0x5A, // ת 0x4b, // כ 0x4a, // ך 0x48, // ט 0x53, // ף 0x55, // ץ 0xB1, // "a" 0xB2, // "b" 0xB3, // "c" 0xB4, // "d" 0xB5, // "e" 0xB6, // "f" 0xB7, // "g" 0xB8, // "h" 0xB9, // "i" 0xBA, // "j" 0xBB, // "k" 0xBC, // "l" 0xBD, // "m" 0xBE, // "n" 0xBF, // "o" 0xC0, // "p" 0xC1, // "q" 0xC2, // "r" 0xC3, // "s" 0xC4, // "t" 0xC5, // "u" 0xC6, // "v" 0xC7, // "w" 0xC8, // "x" 0xC9, // "y" 0xCA, // "z" 0x91, // "A" 0xDB, // "B" -- weird 0x93, // "C" 0xDC, // "D" -- weird 0x95, // "E" 0x96, // "F" 0x97, // "G" 0xAB, // "H" -- weird 0x99, // "I" 0x9A, // "J" 0x9B, // "K" 0x9C, // "L" 0xDD, // "M" 0xDE, // "N" 0x9F, // "O" 0xA0, // "P" 0xA1, // "Q" 0xA2, // "R" 0xA3, // "S" 0xA4, // "T" 0xA5, // "U" 0xA6, // "V" 0xA7, // "W" 0xA8, // "X" - weird 0xA9, // "Y" 0xAA, // "Z" - weird }; private static readonly List HebrewLetters = new List { "א", "ב", "ג", "ד", "ה", "ו", "ז", "ח", "י", "ל", "ם", "מ", "ן", "נ", "ס", "ע", "פ", "צ", "ק", "ר", "ש", "ת", "כ", "ך", "ט", "ף", "ץ", "a", // 0xB1 "b", // 0xB2 "c", // 0xB3 "d", // 0xB4 "e", // 0xB5 "f", // 0xB6 "g", // 0xB7 "h", // 0xB8 "i", // 0xB9 "j", // 0xBA "k", // 0xBB "l", // 0xBC "m", // 0xBD "n", // 0xBE "o", // 0xBF "p", // 0xC0 "q", // 0xC1 "r", // 0xC2 "s", // 0xC3 "t", // 0xC4 "u", // 0xC5 "v", // 0xC6 "w", // 0xC7 "x", // 0xC8 "y", // 0xC9 "z", // 0xCA "A", // 0x91, "B", // 0xDB, "C", // 0x93, "D", // 0xDC, "E", // 0x95, "F", // 0x96, "G", // 0x97, "H", // 0xAB, "I", // 0x99, "J", // 0x9A, "K", // 0x9B, "L", // 0x9C, "M", // 0xDD, "N", // 0xDE, "O", // 0x9F, "P", // 0xA0, "Q", // 0xA1, "R", // 0xA2, "S", // 0xA3, "T", // 0xA4, "U", // 0xA5, "V", // 0xA6, "W", // 0xA7, "X", // 0xA8, "Y", // 0xA9, "Z", // 0xAA, }; private static readonly List RussianCodes = new List { 0x42, // Б 0x45, // Е 0x5A, // З 0x56, // В 0x49, // И 0x4E, // Н 0x58, // Ы 0x51, // Я 0x56, // V 0x53, // С 0x72, // р 0x69, // и 0x71, // я 0x6E, // н 0x74, // т 0x5C, // Э 0x77, // ю 0x46, // Ф 0x5E, // Ч 0x44, // Д 0x62, // б 0x73, // с 0x75, // у 0x64, // д 0x60, // ж 0x6A, // й 0x6C, // л 0x47, // Г 0x78, // ы 0x7A, // з 0x7E, // ч 0x6D, // м 0x67, // г 0x79, // ь 0x70, // п 0x76, // в 0x55, // У 0x7D, // щ 0x66, // ф 0x7C, // э 0x7B, // ш 0x50, // П 0x52, // П 0x68, // П }; private static readonly List RussianLetters = new List { "Б", "Е", "З", "В", "И", "Н", "Ы", "Я", "V", "С", "р", "и", "я", "н", "т", "Э", "ю", "Ф", "Ч", "Д", "б", "с", "у", "д", "ж", "й", "л", "Г", "ы", "з", "ч", "м", "г", "ь", "п", "в", "У", "щ", "ф", "э", "ш", "П", "Р", "х", }; public override string Extension => ".890"; public const string NameOfFormat = "Cavena 890"; public override string Name => NameOfFormat; public override bool IsTimeBased => false; private int _languageIdLine1 = LanguageIdEnglish; private int _languageIdLine2 = LanguageIdEnglish; public bool Save(string fileName, Subtitle subtitle, bool batchMode = false) { using (var fs = new FileStream(fileName, FileMode.Create, FileAccess.Write)) { return Save(fileName, fs, subtitle, batchMode); } } public bool Save(string fileName, Stream stream, Subtitle subtitle, bool batchMode) { int russianCount = 0; char[] logoGrams = { '的', '是', '啊', '吧', '好', '吧', '亲', '爱', '的', '早', '上' }; char[] russianChars = { 'я', 'д', 'й', 'л', 'щ', 'ж', 'ц', 'ф', 'ы' }; foreach (Paragraph p in subtitle.Paragraphs) { if (p.Text.Contains(logoGrams)) { _languageIdLine1 = LanguageIdChineseSimplified; _languageIdLine2 = LanguageIdChineseSimplified; break; } if (p.Text.Contains(russianChars)) { russianCount++; if (russianCount > 10) { _languageIdLine1 = LanguageIdRussian; _languageIdLine2 = LanguageIdRussian; // or 0x09? break; } } } if (Configuration.Settings.SubtitleSettings.CurrentCavena89LanguageId > 0) { _languageIdLine1 = Configuration.Settings.SubtitleSettings.CurrentCavena89LanguageId; _languageIdLine2 = Configuration.Settings.SubtitleSettings.CurrentCavena89LanguageId; } else { var language = LanguageAutoDetect.AutoDetectGoogleLanguage(subtitle); switch (language) { case "he": _languageIdLine1 = LanguageIdHebrew; _languageIdLine2 = LanguageIdHebrew; // or 0x09 break; case "ru": _languageIdLine1 = LanguageIdRussian; _languageIdLine2 = LanguageIdRussian; // or 0x09? break; case "zh": _languageIdLine1 = LanguageIdChineseSimplified; _languageIdLine2 = LanguageIdChineseSimplified; break; case "da": _languageIdLine1 = LanguageIdDanish; _languageIdLine2 = LanguageIdDanish; break; } } // prompt??? //if (Configuration.Settings.SubtitleSettings.CurrentCavena890LanguageIdLine1 >= 0) // _languageIdLine1 = Configuration.Settings.SubtitleSettings.CurrentCavena890LanguageIdLine1; //if (Configuration.Settings.SubtitleSettings.CurrentCavena890LanguageIdLine2 >= 0) // _languageIdLine2 = Configuration.Settings.SubtitleSettings.CurrentCavena890LanguageIdLine2; // write file header (some fields are known, some are not...) stream.WriteByte(0); // ? stream.WriteByte(0); // ? // tape number (20 bytes) for (int i = 0; i < 20; i++) { stream.WriteByte(0); } // ? for (int i = 0; i < 18; i++) { stream.WriteByte(0); } // translated programme title (28 bytes) string title = Path.GetFileNameWithoutExtension(fileName) ?? string.Empty; if (title.Length > 28) { title = title.Substring(0, 28); } if (!string.IsNullOrWhiteSpace(Configuration.Settings.SubtitleSettings.CurrentCavena89Title) && Configuration.Settings.SubtitleSettings.CurrentCavena89Title.Length <= 28) { title = Configuration.Settings.SubtitleSettings.CurrentCavena89Title; } var buffer = Encoding.ASCII.GetBytes(title); stream.Write(buffer, 0, buffer.Length); for (int i = 0; i < 28 - buffer.Length; i++) { stream.WriteByte(0); } // translator (28 bytes) if (!string.IsNullOrWhiteSpace(Configuration.Settings.SubtitleSettings.CurrentCavena890Translator) && Configuration.Settings.SubtitleSettings.CurrentCavena890Translator.Length <= 28) { buffer = Encoding.ASCII.GetBytes(Configuration.Settings.SubtitleSettings.CurrentCavena890Translator); stream.Write(buffer, 0, buffer.Length); for (int i = 0; i < 28 - buffer.Length; i++) { stream.WriteByte(0); } } else { for (int i = 0; i < 28; i++) { stream.WriteByte(0); } } // ? for (int i = 0; i < 9; i++) { stream.WriteByte(0); } // translated episode title (11 bytes) for (int i = 0; i < 11; i++) { stream.WriteByte(0); } // ? for (int i = 0; i < 18; i++) { stream.WriteByte(0); } // ? + language codes buffer = new byte[] { 0xA0, 0x05, 0x04, 0x03, 0x06, 0x06, 0x08, 0x90, 0x00, 0x00, 0x00, 0x00, (byte)_languageIdLine1, (byte)_languageIdLine2 }; stream.Write(buffer, 0, buffer.Length); // comments (24 bytes) buffer = Encoding.ASCII.GetBytes(""); if (!string.IsNullOrWhiteSpace(Configuration.Settings.SubtitleSettings.CurrentCavena89Comment) && Configuration.Settings.SubtitleSettings.CurrentCavena89Comment.Length <= 24) { buffer = Encoding.ASCII.GetBytes(Configuration.Settings.SubtitleSettings.CurrentCavena89Comment); } stream.Write(buffer, 0, buffer.Length); for (int i = 0; i < 24 - buffer.Length; i++) { stream.WriteByte(0); } // ?? buffer = new byte[] { 0x08, 0x90, 0x00, 0x00, 0x00, 0x00, 0x00 }; stream.Write(buffer, 0, buffer.Length); // number of subtitles stream.WriteByte((byte)(subtitle.Paragraphs.Count % 256)); stream.WriteByte((byte)(subtitle.Paragraphs.Count / 256)); // write font - prefix with binary zeroes buffer = GetFontBytesFromLanguageId(_languageIdLine1); // also TBX308VFONTL.V for english... for (int i = 0; i < 14 - buffer.Length; i++) { stream.WriteByte(0); } stream.Write(buffer, 0, buffer.Length); // ? for (int i = 0; i < 13; i++) { stream.WriteByte(0); } // number of subtitles again stream.WriteByte((byte)(subtitle.Paragraphs.Count % 256)); stream.WriteByte((byte)(subtitle.Paragraphs.Count / 256)); // number of subtitles again again stream.WriteByte((byte)(subtitle.Paragraphs.Count % 256)); stream.WriteByte((byte)(subtitle.Paragraphs.Count / 256)); // ? for (int i = 0; i < 6; i++) { stream.WriteByte(0); } // original programme title (28 chars) if (!string.IsNullOrWhiteSpace(Configuration.Settings.SubtitleSettings.CurrentCavena890riginalTitle) && Configuration.Settings.SubtitleSettings.CurrentCavena890riginalTitle.Length <= 28) { buffer = Encoding.ASCII.GetBytes(Configuration.Settings.SubtitleSettings.CurrentCavena890riginalTitle); stream.Write(buffer, 0, buffer.Length); for (int i = 0; i < 28 - buffer.Length; i++) { stream.WriteByte(0); } } else { for (int i = 0; i < 28; i++) { stream.WriteByte(0); } } // write font (use same font id from line 1) buffer = GetFontBytesFromLanguageId(_languageIdLine1); stream.Write(buffer, 0, buffer.Length); // ? stream.WriteByte(0x3d); stream.WriteByte(0x8d); // start of message time string startOfMessage = "10:00:00:00"; if (Configuration.Settings.SubtitleSettings.Cavena890StartOfMessage != null && Configuration.Settings.SubtitleSettings.Cavena890StartOfMessage.Length == startOfMessage.Length) { startOfMessage = Configuration.Settings.SubtitleSettings.Cavena890StartOfMessage; } buffer = Encoding.ASCII.GetBytes(startOfMessage); stream.Write(buffer, 0, buffer.Length); buffer = new byte[] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x42, 0x54, 0x44 }; stream.Write(buffer, 0, buffer.Length); for (int i = 0; i < 92; i++) { stream.WriteByte(0); } // paragraphs int number = 16; foreach (Paragraph p in subtitle.Paragraphs) { // number stream.WriteByte((byte)(number / 256)); stream.WriteByte((byte)(number % 256)); WriteTime(stream, p.StartTime); WriteTime(stream, p.EndTime); if (p.Text.StartsWith("{\\an1}")) { stream.WriteByte(0x50); // left } else if (p.Text.StartsWith("{\\an3}")) { stream.WriteByte(0x52); // left } else { stream.WriteByte(0x54); // center } buffer = new byte[] { 0, 0, 0, 0, 0, 0, 0 }; // 0x16 }; -- the last two bytes might be something with vertical alignment... stream.Write(buffer, 0, buffer.Length); bool hasBox = Utilities.RemoveSsaTags(p.Text).StartsWith(""); var text = p.Text.Replace("", string.Empty).Replace("", string.Empty); text = HtmlUtil.RemoveOpenCloseTags(Utilities.RemoveSsaTags(text), HtmlUtil.TagBold, HtmlUtil.TagFont, HtmlUtil.TagBold); WriteText(stream, text, p == subtitle.Paragraphs[subtitle.Paragraphs.Count - 1], _languageIdLine1, hasBox); number += 16; } return true; } private static byte[] GetFontBytesFromLanguageId(int languageId) { var buffer = Encoding.ASCII.GetBytes("HLV23N.V"); if (languageId == LanguageIdChineseTraditional || languageId == LanguageIdChineseSimplified) { buffer = Encoding.ASCII.GetBytes("CCKM44.V"); } else if (languageId == LanguageIdArabic) { buffer = Encoding.ASCII.GetBytes("ARA19N.V"); } else if (languageId == LanguageIdRussian) { buffer = Encoding.ASCII.GetBytes("KYRIL4.V"); } else if (languageId == LanguageIdHebrew) { buffer = Encoding.ASCII.GetBytes("HEBNOA.V"); } else if (languageId == LanguageIdDanish) { buffer = Encoding.ASCII.GetBytes("VFONTL.V"); } return buffer; } private static void WriteText(Stream fs, string text, bool isLast, int languageIdLine, bool useBox) { string line1 = string.Empty; string line2 = string.Empty; var lines = text.SplitToLines(); if (lines.Count > 2) { lines = Utilities.AutoBreakLine(text).SplitToLines(); } if (lines.Count > 1) { line1 = lines[0]; line2 = lines[1]; } else { line2 = lines[0]; } var buffer = GetTextAsBytes(line1, languageIdLine); fs.Write(buffer, 0, buffer.Length); buffer = new byte[] { 00, 00, 00, 00, 00, 00 }; if (useBox) { buffer[3] = 0xa0; } fs.Write(buffer, 0, buffer.Length); buffer = GetTextAsBytes(line2, languageIdLine); fs.Write(buffer, 0, buffer.Length); buffer = new byte[] { 00, 00, 00, 00 }; if (!isLast) { fs.Write(buffer, 0, buffer.Length); } } private static byte[] GetTextAsBytes(string text, int languageId) { var buffer = new byte[51]; int skipCount = 0; for (int i = 0; i < buffer.Length; i++) { buffer[i] = 0x7F; } if (languageId == LanguageIdChineseTraditional || languageId == LanguageIdChineseSimplified) { for (int i = 0; i < buffer.Length; i++) { buffer[i] = 0; } } else if (languageId == LanguageIdHebrew) { text = Utilities.ReverseNumbers(text); if (!Configuration.Settings.General.RightToLeftMode) { text = Utilities.ReverseStartAndEndingForRightToLeft(text); } } var encoding = Encoding.Default; int index = 0; if (languageId == LanguageIdHebrew) { text = ReverseAnsi(text); } for (int i = 0; i < text.Length; i++) { var current = text[i]; if (skipCount > 0) { skipCount--; } else if (languageId == LanguageIdHebrew) { int letterIndex = HebrewLetters.IndexOf(current.ToString(CultureInfo.InvariantCulture)); if (letterIndex >= 0) { buffer[index] = (byte)HebrewCodes[letterIndex]; } else if (i + 3 < text.Length && text.Substring(i, 3) == "") { buffer[index] = 0x88; skipCount = 2; } else if (i + 4 <= text.Length && text.Substring(i, 4) == "") { buffer[index] = 0x98; skipCount = 2; } else { buffer[index] = encoding.GetBytes(new[] { current })[0]; } index++; } else if (languageId == LanguageIdChineseTraditional || languageId == LanguageIdChineseSimplified) { encoding = Encoding.GetEncoding(1201); if (index < 49) { if (i + 3 < text.Length && text.Substring(i, 3) == "") { buffer[index] = 0x88; skipCount = 2; } else if (i + 4 <= text.Length && text.Substring(i, 4) == "") { buffer[index] = 0x98; skipCount = 3; } else { buffer[index] = encoding.GetBytes(new[] { current })[0]; index++; } } } else { if (index < 50) { if (current == 'æ') { buffer[index] = 0x1B; } else if (current == 'ø') { buffer[index] = 0x1C; } else if (current == 'å') { buffer[index] = 0x1D; } else if (current == 'Æ') { buffer[index] = 0x5B; } else if (current == 'Ø') { buffer[index] = 0x5C; } else if (current == 'Å') { buffer[index] = 0x5D; } // ăĂ şŞ ţŢ (romanian) else if (current == 'ă') { AddTwo(buffer, ref index, 0x89, 0x61); } else if (current == 'Ă') { AddTwo(buffer, ref index, 0x89, 0x41); } else if (current == 'ş') { AddTwo(buffer, ref index, 0x87, 0x73); } else if (current == 'Ş') { AddTwo(buffer, ref index, 0x87, 0x53); } else if (current == 'ţ') { AddTwo(buffer, ref index, 0x87, 0x74); } else if (current == 'Ţ') { AddTwo(buffer, ref index, 0x87, 0x54); } // Next mapping of diacritics is reverse engineered, // and currently only maps characters from latin alphabets according to https://en.wikipedia.org/wiki/Latin_alphabets // capitals with accent grave else if (current == 'À') { AddTwo(buffer, ref index, 0x81, 0x41); } else if (current == 'È') { AddTwo(buffer, ref index, 0x81, 0x45); } else if (current == 'Ì') { AddTwo(buffer, ref index, 0x81, 0x49); } else if (current == 'Ò') { AddTwo(buffer, ref index, 0x81, 0x4F); } else if (current == 'Ù') { AddTwo(buffer, ref index, 0x81, 0x55); } else if (current == 'Ẁ') { AddTwo(buffer, ref index, 0x81, 0x57); } // lowercase with accent grave else if (current == 'à') { AddTwo(buffer, ref index, 0x81, 0x61); } else if (current == 'è') { AddTwo(buffer, ref index, 0x81, 0x65); } else if (current == 'ì') { AddTwo(buffer, ref index, 0x81, 0x69); } else if (current == 'ò') { AddTwo(buffer, ref index, 0x81, 0x6F); } else if (current == 'ù') { AddTwo(buffer, ref index, 0x81, 0x75); } else if (current == 'ẁ') { AddTwo(buffer, ref index, 0x81, 0x75); } // capitals with accent aigu else if (current == 'Á') { AddTwo(buffer, ref index, 0x82, 0x41); } else if (current == 'Ć') { AddTwo(buffer, ref index, 0x82, 0x43); } else if (current == 'É') { AddTwo(buffer, ref index, 0x82, 0x45); } else if (current == 'Í') { AddTwo(buffer, ref index, 0x82, 0x49); } else if (current == 'Ĺ') { AddTwo(buffer, ref index, 0x82, 0x4C); } else if (current == 'Ń') { AddTwo(buffer, ref index, 0x82, 0x4E); } else if (current == 'Ó') { AddTwo(buffer, ref index, 0x82, 0x4F); } else if (current == 'Ŕ') { AddTwo(buffer, ref index, 0x82, 0x52); } else if (current == 'Ś') { AddTwo(buffer, ref index, 0x82, 0x53); } else if (current == 'Ú') { AddTwo(buffer, ref index, 0x82, 0x55); } else if (current == 'Ẃ') { AddTwo(buffer, ref index, 0x82, 0x57); } else if (current == 'Ý') { AddTwo(buffer, ref index, 0x82, 0x59); } else if (current == 'Ź') { AddTwo(buffer, ref index, 0x82, 0x5A); } // lowercase with accent aigu else if (current == 'á') { AddTwo(buffer, ref index, 0x82, 0x61); } else if (current == 'ć') { AddTwo(buffer, ref index, 0x82, 0x63); } else if (current == 'é') { AddTwo(buffer, ref index, 0x82, 0x65); } else if (current == 'í') { AddTwo(buffer, ref index, 0x82, 0x69); } else if (current == 'ĺ') { AddTwo(buffer, ref index, 0x82, 0x6C); } else if (current == 'ń') { AddTwo(buffer, ref index, 0x82, 0x6E); } else if (current == 'ó') { AddTwo(buffer, ref index, 0x82, 0x6F); } else if (current == 'ŕ') { AddTwo(buffer, ref index, 0x82, 0x72); } else if (current == 'ś') { AddTwo(buffer, ref index, 0x82, 0x73); } else if (current == 'ú') { AddTwo(buffer, ref index, 0x82, 0x75); } else if (current == 'ẃ') { AddTwo(buffer, ref index, 0x82, 0x77); } else if (current == 'ý') { AddTwo(buffer, ref index, 0x82, 0x79); } else if (current == 'ź') { AddTwo(buffer, ref index, 0x82, 0x7A); } // capitals with accent circonflexe else if (current == 'Â') { AddTwo(buffer, ref index, 0x83, 0x41); } else if (current == 'Ĉ') { AddTwo(buffer, ref index, 0x83, 0x43); } else if (current == 'Ê') { AddTwo(buffer, ref index, 0x83, 0x45); } else if (current == 'Ĝ') { AddTwo(buffer, ref index, 0x83, 0x47); } else if (current == 'Ĥ') { AddTwo(buffer, ref index, 0x83, 0x48); } else if (current == 'Î') { AddTwo(buffer, ref index, 0x83, 0x49); } else if (current == 'Ĵ') { AddTwo(buffer, ref index, 0x83, 0x4A); } else if (current == 'Ô') { AddTwo(buffer, ref index, 0x83, 0x4F); } else if (current == 'Ŝ') { AddTwo(buffer, ref index, 0x83, 0x53); } else if (current == 'Û') { AddTwo(buffer, ref index, 0x83, 0x55); } else if (current == 'Ŵ') { AddTwo(buffer, ref index, 0x83, 0x57); } else if (current == 'Ŷ') { AddTwo(buffer, ref index, 0x83, 0x59); } // lowercase with accent circonflexe else if (current == 'â') { AddTwo(buffer, ref index, 0x83, 0x61); } else if (current == 'ĉ') { AddTwo(buffer, ref index, 0x83, 0x63); } else if (current == 'ê') { AddTwo(buffer, ref index, 0x83, 0x65); } else if (current == 'ĝ') { AddTwo(buffer, ref index, 0x83, 0x67); } else if (current == 'ĥ') { AddTwo(buffer, ref index, 0x83, 0x68); } else if (current == 'î') { AddTwo(buffer, ref index, 0x83, 0x69); } else if (current == 'ĵ') { AddTwo(buffer, ref index, 0x83, 0x6A); } else if (current == 'ô') { AddTwo(buffer, ref index, 0x83, 0x6F); } else if (current == 'ŝ') { AddTwo(buffer, ref index, 0x83, 0x73); } else if (current == 'û') { AddTwo(buffer, ref index, 0x83, 0x75); } else if (current == 'ŵ') { AddTwo(buffer, ref index, 0x83, 0x77); } else if (current == 'ŷ') { AddTwo(buffer, ref index, 0x83, 0x79); } // capitals with caron else if (current == 'Ǎ') { AddTwo(buffer, ref index, 0x84, 0x41); } else if (current == 'Č') { AddTwo(buffer, ref index, 0x84, 0x43); } else if (current == 'Ď') { AddTwo(buffer, ref index, 0x84, 0x44); } else if (current == 'Ě') { AddTwo(buffer, ref index, 0x84, 0x45); } else if (current == 'Ǧ') { AddTwo(buffer, ref index, 0x84, 0x47); } else if (current == 'Ǐ') { AddTwo(buffer, ref index, 0x84, 0x49); } else if (current == 'Ľ') { AddTwo(buffer, ref index, 0x84, 0x4C); } else if (current == 'Ň') { AddTwo(buffer, ref index, 0x84, 0x4E); } else if (current == 'Ř') { AddTwo(buffer, ref index, 0x84, 0x52); } else if (current == 'Š') { AddTwo(buffer, ref index, 0x84, 0x53); } else if (current == 'Ť') { AddTwo(buffer, ref index, 0x84, 0x54); } else if (current == 'Ž') { AddTwo(buffer, ref index, 0x84, 0x5A); } // lowercase with caron else if (current == 'ǎ') { AddTwo(buffer, ref index, 0x84, 0x61); } else if (current == 'č') { AddTwo(buffer, ref index, 0x84, 0x63); } else if (current == 'ď') { AddTwo(buffer, ref index, 0x84, 0x64); } else if (current == 'ě') { AddTwo(buffer, ref index, 0x84, 0x65); } else if (current == 'ǧ') { AddTwo(buffer, ref index, 0x84, 0x67); } else if (current == 'ǐ') { AddTwo(buffer, ref index, 0x84, 0x69); } else if (current == 'ľ') { AddTwo(buffer, ref index, 0x84, 0x6C); } else if (current == 'ň') { AddTwo(buffer, ref index, 0x84, 0x6E); } else if (current == 'ř') { AddTwo(buffer, ref index, 0x84, 0x72); } else if (current == 'š') { AddTwo(buffer, ref index, 0x84, 0x73); } else if (current == 'ť') { AddTwo(buffer, ref index, 0x84, 0x74); } else if (current == 'ž') { AddTwo(buffer, ref index, 0x84, 0x7A); } // capitals with tilde else if (current == 'Ã') { AddTwo(buffer, ref index, 0x85, 0x41); } else if (current == 'Ĩ') { AddTwo(buffer, ref index, 0x85, 0x49); } else if (current == 'Ñ') { AddTwo(buffer, ref index, 0x85, 0x4E); } else if (current == 'Õ') { AddTwo(buffer, ref index, 0x85, 0x4F); } else if (current == 'Ũ') { AddTwo(buffer, ref index, 0x85, 0x55); } // lowercase with tilde else if (current == 'ã') { AddTwo(buffer, ref index, 0x85, 0x61); } else if (current == 'ĩ') { AddTwo(buffer, ref index, 0x85, 0x69); } else if (current == 'ñ') { AddTwo(buffer, ref index, 0x85, 0x6E); } else if (current == 'õ') { AddTwo(buffer, ref index, 0x85, 0x6F); } else if (current == 'ũ') { AddTwo(buffer, ref index, 0x85, 0x75); } // capitals with trema else if (current == 'Ä') { AddTwo(buffer, ref index, 0x86, 0x41); } else if (current == 'Ë') { AddTwo(buffer, ref index, 0x86, 0x45); } else if (current == 'Ï') { AddTwo(buffer, ref index, 0x86, 0x49); } else if (current == 'Ö') { AddTwo(buffer, ref index, 0x86, 0x4F); } else if (current == 'Ü') { AddTwo(buffer, ref index, 0x86, 0x55); } else if (current == 'Ẅ') { AddTwo(buffer, ref index, 0x86, 0x57); } else if (current == 'Ÿ') { AddTwo(buffer, ref index, 0x86, 0x59); } // lowercase with trema else if (current == 'ä') { AddTwo(buffer, ref index, 0x86, 0x61); } else if (current == 'ë') { AddTwo(buffer, ref index, 0x86, 0x65); } else if (current == 'ï') { AddTwo(buffer, ref index, 0x86, 0x69); } else if (current == 'ö') { AddTwo(buffer, ref index, 0x86, 0x6F); } else if (current == 'ü') { AddTwo(buffer, ref index, 0x86, 0x75); } else if (current == 'ẅ') { AddTwo(buffer, ref index, 0x86, 0x77); } else if (current == 'ÿ') { AddTwo(buffer, ref index, 0x86, 0x79); } else if (i + 3 < text.Length && text.Substring(i, 3) == "") { buffer[index] = 0x88; skipCount = 2; } else if (i + 4 <= text.Length && text.Substring(i, 4) == "") { buffer[index] = 0x98; skipCount = 3; } else { buffer[index] = encoding.GetBytes(new[] { current })[0]; } index++; } } } return buffer; } private static string ReverseAnsi(string text) { var sb = new StringBuilder(); var ansi = new StringBuilder(); foreach (var ch in text) { if (ch > 255) { if (ansi.Length > 0) { sb.Append(Utilities.ReverseString(ansi.ToString())); ansi.Clear(); } sb.Append(ch); } else { ansi.Append(ch); } } if (ansi.Length > 0) { sb.Append(Utilities.ReverseString(ansi.ToString())); } return sb.ToString(); } private static void AddTwo(byte[] buffer, ref int index, byte b1, byte b2) { buffer[index] = b1; index++; buffer[index] = b2; } private static void WriteTime(Stream fs, TimeCode timeCode) { double totalMilliseconds = timeCode.TotalMilliseconds; int frames = (int)Math.Round(totalMilliseconds / (TimeCode.BaseUnit / Configuration.Settings.General.CurrentFrameRate)); fs.WriteByte((byte)(frames / 256 / 256)); fs.WriteByte((byte)(frames / 256)); fs.WriteByte((byte)(frames % 256)); } public override bool IsMine(List lines, string fileName) { if (!string.IsNullOrEmpty(fileName) && File.Exists(fileName)) { var fi = new FileInfo(fileName); if (fi.Length >= 512 && fi.Length < 1024000) // not too small or too big { if (!fileName.EndsWith(".890", StringComparison.Ordinal)) { return false; } return base.IsMine(lines, fileName); } } return false; } public override string ToText(Subtitle subtitle, string title) { return "Not supported!"; } public override void LoadSubtitle(Subtitle subtitle, List lines, string fileName) { const int textLength = 51; subtitle.Paragraphs.Clear(); subtitle.Header = null; byte[] buffer = FileUtil.ReadAllBytesShared(fileName); _languageIdLine1 = buffer[146]; if (_languageIdLine1 == 0) { _languageIdLine1 = LanguageIdEnglish; } Configuration.Settings.SubtitleSettings.CurrentCavena890LanguageIdLine1 = _languageIdLine1; _languageIdLine2 = buffer[147]; if (_languageIdLine2 == 0) { _languageIdLine2 = LanguageIdEnglish; } Configuration.Settings.SubtitleSettings.CurrentCavena890LanguageIdLine2 = _languageIdLine2; var fontNameLine1 = Encoding.ASCII.GetString(buffer, 187, 6); var fontNameLine2 = Encoding.ASCII.GetString(buffer, 246, 6); // Hebrew if (_languageIdLine1 == LanguageIdHebrew || fontNameLine1 == "HEBNOA" || fontNameLine2 == "HEBNOA") { _languageIdLine1 = LanguageIdHebrew; _languageIdLine2 = LanguageIdHebrew; } // Russian else if (_languageIdLine1 == LanguageIdRussian || fontNameLine1.StartsWith("KYRIL", StringComparison.Ordinal) || fontNameLine2.StartsWith("KYRIL", StringComparison.Ordinal)) { _languageIdLine1 = LanguageIdRussian; _languageIdLine2 = LanguageIdRussian; } // Chinese else if (_languageIdLine1 == LanguageIdChineseSimplified) { _languageIdLine1 = LanguageIdChineseSimplified; _languageIdLine2 = LanguageIdChineseSimplified; } else if (_languageIdLine1 == LanguageIdChineseTraditional || fontNameLine1 == "CCKM44" || fontNameLine2 == "CCKM44") { _languageIdLine1 = LanguageIdChineseTraditional; _languageIdLine2 = LanguageIdChineseTraditional; } int i = 455; int lastNumber = -1; while (i < buffer.Length - 20) { int start = i - textLength; int number = buffer[start - 16] * 256 + buffer[start - 15]; var p = new Paragraph(); double startFrame = buffer[start - 14] * 256 * 256 + buffer[start - 13] * 256 + buffer[start - 12]; double endFrame = buffer[start - 11] * 256 * 256 + buffer[start - 10] * 256 + buffer[start - 9]; byte boxType = buffer[start + textLength + 3]; string line1 = FixText(buffer, start, textLength, _languageIdLine1); string line2 = FixText(buffer, start + textLength + 6, textLength, _languageIdLine2); if (lastNumber == number) { p = subtitle.Paragraphs[subtitle.Paragraphs.Count - 1]; string temp = (line1.TrimEnd() + Environment.NewLine + line2).TrimEnd(); if (temp.Length > 0) { p.Text = temp; } } else { subtitle.Paragraphs.Add(p); p.StartTime.TotalMilliseconds = (TimeCode.BaseUnit / Configuration.Settings.General.CurrentFrameRate) * startFrame; p.EndTime.TotalMilliseconds = (TimeCode.BaseUnit / Configuration.Settings.General.CurrentFrameRate) * endFrame; p.Text = (line1.TrimEnd() + Environment.NewLine + line2).TrimEnd(); } if (boxType >= 0xa0 && boxType <= 0xa9 && !string.IsNullOrEmpty(p.Text)) // box { if (p.Text.StartsWith("{\\") && p.Text.Contains("}")) { p.Text = p.Text.Insert(p.Text.IndexOf('}', 3) + 1, "") + ""; } else { p.Text = "" + p.Text + ""; } } lastNumber = number; i += 128; } subtitle.Renumber(); } private static string FixText(byte[] buffer, int start, int textLength, int languageId) { string text; if (languageId == LanguageIdRussian) { var encoding = Encoding.GetEncoding(1252); var sb = new StringBuilder(); for (int i = 0; i < textLength; i++) { int b = buffer[start + i]; int idx = RussianCodes.IndexOf(b); if (idx >= 0) { sb.Append(RussianLetters[idx]); } else { sb.Append(encoding.GetString(buffer, start + i, 1)); } } text = sb.ToString(); text = text.Replace(encoding.GetString(new byte[] { 0x7F }), string.Empty); // Used to fill empty space upto 51 bytes text = text.Replace(encoding.GetString(new byte[] { 0xBE }), string.Empty); // Unknown? text = FixColors(text); if (text.Contains("")) { text = text.Replace("", ""); } if (text.Contains("") && !text.Contains("")) { text += ""; } } else if (languageId == LanguageIdHebrew) // (_language == "HEBNOA") { var encoding = Encoding.GetEncoding(1252); var sb = new StringBuilder(); for (int i = 0; i < textLength; i++) { int b = buffer[start + i]; int idx = HebrewCodes.IndexOf(b); if (idx >= 0) { sb.Append(HebrewLetters[idx]); } else { sb.Append(encoding.GetString(buffer, start + i, 1)); } } text = sb.ToString(); text = text.Replace(encoding.GetString(new byte[] { 0x7F }), string.Empty); // Used to fill empty space upto 51 bytes text = text.Replace(encoding.GetString(new byte[] { 0xBE }), string.Empty); // Unknown? text = FixColors(text); text = ReverseAnsi(text); text = Utilities.ReverseStartAndEndingForRightToLeft(text); } else if (languageId == LanguageIdChineseTraditional || languageId == LanguageIdChineseSimplified) // (_language == "CCKM44" || _language == "TVB000") { int index = start; while (textLength >= 1 && index + textLength < buffer.Length && (buffer[index + textLength - 1] == 0)) { textLength--; } if (textLength > 0) { text = Encoding.GetEncoding(1201).GetString(buffer, index, textLength).Replace("\0", string.Empty); } else { text = string.Empty; } var encoding = Encoding.Default; // which encoding?? Encoding.GetEncoding("ISO-8859-5") text = text.Replace(encoding.GetString(new byte[] { 0x7F }), string.Empty); // Used to fill empty space upto 51 bytes text = text.Replace(encoding.GetString(new byte[] { 0xBE }), string.Empty); // Unknown? text = FixColors(text); text = text.Replace(encoding.GetString(new byte[] { 0x88 }), ""); text = text.Replace(encoding.GetString(new byte[] { 0x98 }), ""); if (text.Contains("")) { text = text.Replace("", ""); } if (text.Contains("") && !text.Contains("")) { text += ""; } } else { var encoding = Encoding.GetEncoding(1252); text = encoding.GetString(buffer, start, textLength).Replace("\0", string.Empty); text = text.Replace(encoding.GetString(new byte[] { 0x7F }), string.Empty); // Used to fill empty space upto 51 bytes text = text.Replace(encoding.GetString(new byte[] { 0xBE }), string.Empty); // Unknown? text = FixColors(text); text = text.Replace(encoding.GetString(new byte[] { 0x1B }), "æ"); text = text.Replace(encoding.GetString(new byte[] { 0x1C }), "ø"); text = text.Replace(encoding.GetString(new byte[] { 0x1D }), "å"); text = text.Replace(encoding.GetString(new byte[] { 0x1E }), "Æ"); text = text.Replace(encoding.GetString(new byte[] { 0x1F }), "Ø"); text = text.Replace(encoding.GetString(new byte[] { 0x5B }), "Æ"); text = text.Replace(encoding.GetString(new byte[] { 0x5C }), "Ø"); text = text.Replace(encoding.GetString(new byte[] { 0x5D }), "Å"); // capitals with accent grave text = text.Replace(encoding.GetString(new byte[] { 0x81, 0x41 }), "À"); text = text.Replace(encoding.GetString(new byte[] { 0x81, 0x45 }), "È"); text = text.Replace(encoding.GetString(new byte[] { 0x81, 0x49 }), "Ì"); text = text.Replace(encoding.GetString(new byte[] { 0x81, 0x4f }), "Ò"); text = text.Replace(encoding.GetString(new byte[] { 0x81, 0x55 }), "Ù"); // lowercase with accent grave text = text.Replace(encoding.GetString(new byte[] { 0x81, 0x61 }), "à"); text = text.Replace(encoding.GetString(new byte[] { 0x81, 0x65 }), "è"); text = text.Replace(encoding.GetString(new byte[] { 0x81, 0x69 }), "ì"); text = text.Replace(encoding.GetString(new byte[] { 0x81, 0x6F }), "ò"); text = text.Replace(encoding.GetString(new byte[] { 0x81, 0x75 }), "ù"); // capitals with accent aigu text = text.Replace(encoding.GetString(new byte[] { 0x82, 0x41 }), "Á"); text = text.Replace(encoding.GetString(new byte[] { 0x82, 0x43 }), "Ć"); text = text.Replace(encoding.GetString(new byte[] { 0x82, 0x45 }), "É"); text = text.Replace(encoding.GetString(new byte[] { 0x82, 0x49 }), "Í"); text = text.Replace(encoding.GetString(new byte[] { 0x82, 0x4C }), "Ĺ"); text = text.Replace(encoding.GetString(new byte[] { 0x82, 0x4E }), "Ń"); text = text.Replace(encoding.GetString(new byte[] { 0x82, 0x4F }), "Ó"); text = text.Replace(encoding.GetString(new byte[] { 0x82, 0x52 }), "Ŕ"); text = text.Replace(encoding.GetString(new byte[] { 0x82, 0x53 }), "Ś"); text = text.Replace(encoding.GetString(new byte[] { 0x82, 0x55 }), "Ú"); text = text.Replace(encoding.GetString(new byte[] { 0x82, 0x57 }), "Ẃ"); text = text.Replace(encoding.GetString(new byte[] { 0x82, 0x59 }), "Ý"); text = text.Replace(encoding.GetString(new byte[] { 0x82, 0x5A }), "Ź"); // lowercase with accent aigu text = text.Replace(encoding.GetString(new byte[] { 0x82, 0x61 }), "á"); text = text.Replace(encoding.GetString(new byte[] { 0x82, 0x63 }), "ć"); text = text.Replace(encoding.GetString(new byte[] { 0x82, 0x65 }), "é"); text = text.Replace(encoding.GetString(new byte[] { 0x82, 0x69 }), "í"); text = text.Replace(encoding.GetString(new byte[] { 0x82, 0x6C }), "ĺ"); text = text.Replace(encoding.GetString(new byte[] { 0x82, 0x6E }), "ń"); text = text.Replace(encoding.GetString(new byte[] { 0x82, 0x6F }), "ó"); text = text.Replace(encoding.GetString(new byte[] { 0x82, 0x72 }), "ŕ"); text = text.Replace(encoding.GetString(new byte[] { 0x82, 0x73 }), "ś"); text = text.Replace(encoding.GetString(new byte[] { 0x82, 0x75 }), "ú"); text = text.Replace(encoding.GetString(new byte[] { 0x82, 0x77 }), "ẃ"); text = text.Replace(encoding.GetString(new byte[] { 0x82, 0x79 }), "ý"); text = text.Replace(encoding.GetString(new byte[] { 0x82, 0x7A }), "ź"); // capitals with accent circonflexe text = text.Replace(encoding.GetString(new byte[] { 0x83, 0x41 }), "Â"); text = text.Replace(encoding.GetString(new byte[] { 0x83, 0x43 }), "Ĉ"); text = text.Replace(encoding.GetString(new byte[] { 0x83, 0x45 }), "Ê"); text = text.Replace(encoding.GetString(new byte[] { 0x83, 0x47 }), "Ĝ"); text = text.Replace(encoding.GetString(new byte[] { 0x83, 0x48 }), "Ĥ"); text = text.Replace(encoding.GetString(new byte[] { 0x83, 0x49 }), "Î"); text = text.Replace(encoding.GetString(new byte[] { 0x83, 0x4A }), "Ĵ"); text = text.Replace(encoding.GetString(new byte[] { 0x83, 0x4F }), "Ô"); text = text.Replace(encoding.GetString(new byte[] { 0x83, 0x53 }), "Ŝ"); text = text.Replace(encoding.GetString(new byte[] { 0x83, 0x55 }), "Û"); text = text.Replace(encoding.GetString(new byte[] { 0x83, 0x57 }), "Ŵ"); text = text.Replace(encoding.GetString(new byte[] { 0x83, 0x59 }), "Ŷ"); // lowercase with accent circonflexe text = text.Replace(encoding.GetString(new byte[] { 0x83, 0x61 }), "â"); text = text.Replace(encoding.GetString(new byte[] { 0x83, 0x63 }), "ĉ"); text = text.Replace(encoding.GetString(new byte[] { 0x83, 0x65 }), "ê"); text = text.Replace(encoding.GetString(new byte[] { 0x83, 0x67 }), "ĝ"); text = text.Replace(encoding.GetString(new byte[] { 0x83, 0x68 }), "ĥ"); text = text.Replace(encoding.GetString(new byte[] { 0x83, 0x69 }), "î"); text = text.Replace(encoding.GetString(new byte[] { 0x83, 0x6A }), "ĵ"); text = text.Replace(encoding.GetString(new byte[] { 0x83, 0x6F }), "ô"); text = text.Replace(encoding.GetString(new byte[] { 0x83, 0x73 }), "ŝ"); text = text.Replace(encoding.GetString(new byte[] { 0x83, 0x75 }), "û"); text = text.Replace(encoding.GetString(new byte[] { 0x83, 0x77 }), "ŵ"); text = text.Replace(encoding.GetString(new byte[] { 0x83, 0x79 }), "ŷ"); // capitals with caron text = text.Replace(encoding.GetString(new byte[] { 0x84, 0x41 }), "Ǎ"); text = text.Replace(encoding.GetString(new byte[] { 0x84, 0x43 }), "Č"); text = text.Replace(encoding.GetString(new byte[] { 0x84, 0x44 }), "Ď"); text = text.Replace(encoding.GetString(new byte[] { 0x84, 0x45 }), "Ě"); text = text.Replace(encoding.GetString(new byte[] { 0x84, 0x47 }), "Ǧ"); text = text.Replace(encoding.GetString(new byte[] { 0x84, 0x49 }), "Ǐ"); text = text.Replace(encoding.GetString(new byte[] { 0x84, 0x4C }), "Ľ"); text = text.Replace(encoding.GetString(new byte[] { 0x84, 0x4E }), "Ň"); text = text.Replace(encoding.GetString(new byte[] { 0x84, 0x52 }), "Ř"); text = text.Replace(encoding.GetString(new byte[] { 0x84, 0x53 }), "Š"); text = text.Replace(encoding.GetString(new byte[] { 0x84, 0x54 }), "Ť"); text = text.Replace(encoding.GetString(new byte[] { 0x84, 0x5A }), "Ž"); // lowercase with caron text = text.Replace(encoding.GetString(new byte[] { 0x84, 0x61 }), "ǎ"); text = text.Replace(encoding.GetString(new byte[] { 0x84, 0x63 }), "č"); text = text.Replace(encoding.GetString(new byte[] { 0x84, 0x64 }), "ď"); text = text.Replace(encoding.GetString(new byte[] { 0x84, 0x65 }), "ě"); text = text.Replace(encoding.GetString(new byte[] { 0x84, 0x67 }), "ǧ"); text = text.Replace(encoding.GetString(new byte[] { 0x84, 0x69 }), "ǐ"); text = text.Replace(encoding.GetString(new byte[] { 0x84, 0x6C }), "ľ"); text = text.Replace(encoding.GetString(new byte[] { 0x84, 0x6E }), "ň"); text = text.Replace(encoding.GetString(new byte[] { 0x84, 0x72 }), "ř"); text = text.Replace(encoding.GetString(new byte[] { 0x84, 0x73 }), "š"); text = text.Replace(encoding.GetString(new byte[] { 0x84, 0x74 }), "ť"); text = text.Replace(encoding.GetString(new byte[] { 0x84, 0x7A }), "ž"); // capitals with tilde text = text.Replace(encoding.GetString(new byte[] { 0x85, 0x41 }), "Ã"); text = text.Replace(encoding.GetString(new byte[] { 0x85, 0x49 }), "Ĩ"); text = text.Replace(encoding.GetString(new byte[] { 0x85, 0x4E }), "Ñ"); text = text.Replace(encoding.GetString(new byte[] { 0x85, 0x4F }), "Õ"); text = text.Replace(encoding.GetString(new byte[] { 0x85, 0x55 }), "Ũ"); // lowercase with tilde text = text.Replace(encoding.GetString(new byte[] { 0x85, 0x61 }), "ã"); text = text.Replace(encoding.GetString(new byte[] { 0x85, 0x69 }), "ĩ"); text = text.Replace(encoding.GetString(new byte[] { 0x85, 0x6E }), "ñ"); text = text.Replace(encoding.GetString(new byte[] { 0x85, 0x6F }), "õ"); text = text.Replace(encoding.GetString(new byte[] { 0x85, 0x75 }), "ũ"); // capitals with trema text = text.Replace(encoding.GetString(new byte[] { 0x86, 0x41 }), "Ä"); text = text.Replace(encoding.GetString(new byte[] { 0x86, 0x45 }), "Ë"); text = text.Replace(encoding.GetString(new byte[] { 0x86, 0x49 }), "Ï"); text = text.Replace(encoding.GetString(new byte[] { 0x86, 0x4F }), "Ö"); text = text.Replace(encoding.GetString(new byte[] { 0x86, 0x55 }), "Ü"); text = text.Replace(encoding.GetString(new byte[] { 0x86, 0x59 }), "Ÿ"); // lowercase with trema text = text.Replace(encoding.GetString(new byte[] { 0x86, 0x61 }), "ä"); text = text.Replace(encoding.GetString(new byte[] { 0x86, 0x65 }), "ë"); text = text.Replace(encoding.GetString(new byte[] { 0x86, 0x69 }), "ï"); text = text.Replace(encoding.GetString(new byte[] { 0x86, 0x6F }), "ö"); text = text.Replace(encoding.GetString(new byte[] { 0x86, 0x75 }), "ü"); text = text.Replace(encoding.GetString(new byte[] { 0x86, 0x79 }), "ÿ"); // with ring text = text.Replace(encoding.GetString(new byte[] { 0x8C, 0x61 }), "å"); text = text.Replace(encoding.GetString(new byte[] { 0x8C, 0x41 }), "Å"); text = text.Replace(encoding.GetString(new byte[] { 0x88 }), ""); text = text.Replace(encoding.GetString(new byte[] { 0x98 }), ""); // ăĂ şŞ ţŢ (romanian) text = text.Replace(encoding.GetString(new byte[] { 0x89, 0x61 }), "ă"); text = text.Replace(encoding.GetString(new byte[] { 0x89, 0x41 }), "Ă"); text = text.Replace(encoding.GetString(new byte[] { 0x87, 0x73 }), "ş"); text = text.Replace(encoding.GetString(new byte[] { 0x87, 0x53 }), "Ş"); text = text.Replace(encoding.GetString(new byte[] { 0x87, 0x74 }), "ţ"); text = text.Replace(encoding.GetString(new byte[] { 0x87, 0x54 }), "Ţ"); if (text.Contains("")) { text = text.Replace("", ""); } if (text.Contains("") && !text.Contains("")) { text += ""; } } return text; } private static string FixColors(string text) { Encoding encoding = Encoding.GetEncoding(1252); bool fontColorOn = false; var sb = new StringBuilder(); for (int i = 0; i < text.Length; i++) { var s = text.Substring(i, 1); if (s == encoding.GetString(new byte[] { 0xf1 })) { if (fontColorOn) { sb.Append(""); // white } sb.Append(""); // red fontColorOn = true; } else if (s == encoding.GetString(new byte[] { 0xf2 })) { if (fontColorOn) { sb.Append(""); // white } sb.Append(""); // green fontColorOn = true; } else if (s == encoding.GetString(new byte[] { 0xf3 })) { if (fontColorOn) { sb.Append(""); // white } sb.Append(""); // yellow fontColorOn = true; } else if (s == encoding.GetString(new byte[] { 0xf4 })) { if (fontColorOn) { sb.Append(""); // white } sb.Append(""); // purple fontColorOn = true; } else if (s == encoding.GetString(new byte[] { 0xf5 })) { if (fontColorOn) { sb.Append(""); // white } sb.Append(""); // magenta fontColorOn = true; } else if (s == encoding.GetString(new byte[] { 0xf6 })) { if (fontColorOn) { sb.Append(""); // white } sb.Append(""); // cyan fontColorOn = true; } else if (s == encoding.GetString(new byte[] { 0xf7 })) { if (fontColorOn) { sb.Append(""); // white fontColorOn = false; } } else if (s == encoding.GetString(new byte[] { 0xf8 })) { sb.Append(""); // orange fontColorOn = true; } else { sb.Append(s); } } if (fontColorOn) { sb.Append(""); // white } return sb.ToString(); } } }