From 976be2c6e65ba307aae6fbcc943c399410053ca5 Mon Sep 17 00:00:00 2001 From: niksedk Date: Tue, 12 Oct 2010 11:21:51 +0000 Subject: [PATCH] Initial version git-svn-id: https://subtitleedit.googlecode.com/svn/trunk@13 99eadd0c-20b8-1223-b5c4-2a2b2df33de2 --- src/Logic/Configuration.cs | 36 + src/Logic/FastBitmap.cs | 86 ++ src/Logic/FindReplaceDialogHelper.cs | 164 ++++ src/Logic/HistoryItem.cs | 26 + src/Logic/IfoParser.cs | 408 ++++++++ src/Logic/ImageSplitter.cs | 361 +++++++ src/Logic/ImageSplitterItem.cs | 28 + src/Logic/Language.cs | 1362 ++++++++++++++++++++++++++ src/Logic/LanguageStructure.cs | 1160 ++++++++++++++++++++++ src/Logic/Paragraph.cs | 105 ++ src/Logic/PositionAndSize.cs | 15 + src/Logic/PositionsAndSizes.cs | 56 ++ src/Logic/Settings.cs | 902 +++++++++++++++++ src/Logic/StripableText.cs | 241 +++++ src/Logic/Subtitle.cs | 397 ++++++++ src/Logic/TimeCode.cs | 125 +++ src/Logic/Utilities.cs | 1335 +++++++++++++++++++++++++ src/Logic/Wave.cs | 22 + src/Logic/WavePeak.cs | 353 +++++++ src/Logic/ZipExtractor.cs | 433 ++++++++ 20 files changed, 7615 insertions(+) create mode 100644 src/Logic/Configuration.cs create mode 100644 src/Logic/FastBitmap.cs create mode 100644 src/Logic/FindReplaceDialogHelper.cs create mode 100644 src/Logic/HistoryItem.cs create mode 100644 src/Logic/IfoParser.cs create mode 100644 src/Logic/ImageSplitter.cs create mode 100644 src/Logic/ImageSplitterItem.cs create mode 100644 src/Logic/Language.cs create mode 100644 src/Logic/LanguageStructure.cs create mode 100644 src/Logic/Paragraph.cs create mode 100644 src/Logic/PositionAndSize.cs create mode 100644 src/Logic/PositionsAndSizes.cs create mode 100644 src/Logic/Settings.cs create mode 100644 src/Logic/StripableText.cs create mode 100644 src/Logic/Subtitle.cs create mode 100644 src/Logic/TimeCode.cs create mode 100644 src/Logic/Utilities.cs create mode 100644 src/Logic/Wave.cs create mode 100644 src/Logic/WavePeak.cs create mode 100644 src/Logic/ZipExtractor.cs diff --git a/src/Logic/Configuration.cs b/src/Logic/Configuration.cs new file mode 100644 index 000000000..19c572683 --- /dev/null +++ b/src/Logic/Configuration.cs @@ -0,0 +1,36 @@ +using System.IO; + +namespace Nikse.SubtitleEdit.Logic +{ + public class Configuration + { + static readonly Configuration Instance = new Configuration(); + string _baseDir; + Settings _settings; + + public static string BaseDirectory + { + get + { + if (Instance._baseDir == null) + { + System.Reflection.Assembly a = System.Reflection.Assembly.GetEntryAssembly(); + Instance._baseDir = Path.GetDirectoryName(a.Location); + if (!Instance._baseDir.EndsWith(Path.DirectorySeparatorChar.ToString())) + Instance._baseDir += Path.DirectorySeparatorChar; + } + return Instance._baseDir; + } + } + + public static Settings Settings + { + get + { + if (Instance._settings == null) + Instance._settings = Settings.GetSettings(); + return Instance._settings; + } + } + } +} diff --git a/src/Logic/FastBitmap.cs b/src/Logic/FastBitmap.cs new file mode 100644 index 000000000..725e1fa39 --- /dev/null +++ b/src/Logic/FastBitmap.cs @@ -0,0 +1,86 @@ +//Downloaded from Visual C# Kicks - http://www.vcskicks.com/ +using System; +using System.Drawing; +using System.Drawing.Imaging; + +namespace Nikse.SubtitleEdit.Logic +{ + unsafe public class FastBitmap + { + private struct PixelData + { + public byte Blue; + public byte Green; + public byte Red; + public byte Alpha; + + public override string ToString() + { + return "(" + Alpha + ", " + Red + ", " + Green + ", " + Blue + ")"; + } + } + + public int Width { get; set; } + public int Height { get; set; } + + private readonly Bitmap _workingBitmap; + private int _width; + private BitmapData _bitmapData; + private Byte* _pBase = null; + + public FastBitmap(Bitmap inputBitmap) + { + _workingBitmap = inputBitmap; + + Width = inputBitmap.Width; + Height = inputBitmap.Height; + } + + public void LockImage() + { + var bounds = new Rectangle(Point.Empty, _workingBitmap.Size); + + _width = bounds.Width * sizeof(PixelData); + if (_width % 4 != 0) _width = 4 * (_width / 4 + 1); + + //Lock Image + _bitmapData = _workingBitmap.LockBits(bounds, ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb); + _pBase = (Byte*)_bitmapData.Scan0.ToPointer(); + } + + private PixelData* _pixelData = null; + + public Color GetPixel(int x, int y) + { + _pixelData = (PixelData*)(_pBase + y * _width + x * sizeof(PixelData)); + return Color.FromArgb(_pixelData->Alpha, _pixelData->Red, _pixelData->Green, _pixelData->Blue); + } + + public Color GetPixelNext() + { + _pixelData++; + return Color.FromArgb(_pixelData->Alpha, _pixelData->Red, _pixelData->Green, _pixelData->Blue); + } + + public void SetPixel(int x, int y, Color color) + { + var data = (PixelData*)(_pBase + y * _width + x * sizeof(PixelData)); + data->Alpha = color.A; + data->Red = color.R; + data->Green = color.G; + data->Blue = color.B; + } + + public Bitmap GetBitmap() + { + return _workingBitmap; + } + + public void UnlockImage() + { + _workingBitmap.UnlockBits(_bitmapData); + _bitmapData = null; + _pBase = null; + } + } +} diff --git a/src/Logic/FindReplaceDialogHelper.cs b/src/Logic/FindReplaceDialogHelper.cs new file mode 100644 index 000000000..7f75a69ba --- /dev/null +++ b/src/Logic/FindReplaceDialogHelper.cs @@ -0,0 +1,164 @@ +using System.Text.RegularExpressions; +using System.Windows.Forms; +using Nikse.SubtitleEdit.Logic.Enums; + +namespace Nikse.SubtitleEdit.Logic +{ + public class FindReplaceDialogHelper + { + readonly string _findText = string.Empty; + readonly string _replaceText = string.Empty; + readonly Regex _regEx; + int _findTextLenght; + + public FindType FindType { get; set; } + public int SelectedIndex { get; set; } + public int SelectedPosition { get; set; } + public int WindowPositionLeft { get; set; } + public int WindowPositionTop { get; set; } + public int StartLineIndex { get; set; } + + public int FindTextLength + { + get + { + return _findTextLenght; + } + } + + public string FindText + { + get + { + return _findText; + } + } + + public string ReplaceText + { + get + { + return _replaceText; + } + } + + public FindReplaceDialogHelper(FindType findType, string findText, Regex regEx, string replaceText, int left, int top, int startLineIndex) + { + FindType = findType; + _findText = findText; + _replaceText = replaceText; + _regEx = regEx; + _findTextLenght = findText.Length; + WindowPositionLeft = left; + WindowPositionTop = top; + StartLineIndex = startLineIndex; + } + + public bool Find(Subtitle subtitle, int startIndex) + { + return FindNext(subtitle, startIndex, 0); + } + + public bool Find(TextBox textBox, int startIndex) + { + return FindNext(textBox, startIndex); + } + + private int FindPositionInText(string text, int startIndex) + { + if (startIndex >= text.Length) + return -1; + + switch (FindType) + { + case FindType.Normal: + return (text.ToLower().IndexOf(_findText.ToLower(), startIndex)); + case FindType.CaseSensitive: + return (text.IndexOf(_findText, startIndex)); + case FindType.RegEx: + { + Match match = _regEx.Match(text, startIndex); + if (match.Success) + { + _findTextLenght = match.Length; + return match.Index; + } + return -1; + } + } + return -1; + } + + public bool FindNext(Subtitle subtitle, int startIndex, int position) + { + int index = 0; + if (position < 0) + position = 0; + foreach (Paragraph p in subtitle.Paragraphs) + { + if (index >= startIndex) + { + int pos = FindPositionInText(p.Text, position); + if (pos >= 0) + { + SelectedIndex = index; + SelectedPosition = pos; + return true; + } + position = 0; + } + index++; + } + return false; + } + + public static ContextMenu GetRegExContextMenu(TextBox textBox) + { + var cm = new ContextMenu(); + cm.MenuItems.Add("Word boundary (\\b)", delegate { textBox.SelectedText = "\\b"; }); + cm.MenuItems.Add("Non word boundary (\\B)", delegate { textBox.SelectedText = "\\B"; }); + cm.MenuItems.Add("Carriage return + new line (\\r\\n)", delegate { textBox.SelectedText = "\\r\\n"; }); + cm.MenuItems.Add("Any digit (\\d)", delegate { textBox.SelectedText = "\\d"; }); + cm.MenuItems.Add("Any character (.)", delegate { textBox.SelectedText = "."; }); + cm.MenuItems.Add("Any whitespace", delegate { textBox.SelectedText = "\\s"; }); + cm.MenuItems.Add("Zero or more (*)", delegate { textBox.SelectedText = "*"; }); + cm.MenuItems.Add("One or more", delegate { textBox.SelectedText = "+"; }); + cm.MenuItems.Add("In character goup ([test])", delegate { textBox.SelectedText = "[test]"; }); + cm.MenuItems.Add("Not in character goup ([^test])", delegate { textBox.SelectedText = "[^test]"; }); + return cm; + } + + public static ContextMenu GetReplaceTextContextMenu(TextBox textBox) + { + var cm = new ContextMenu(); + cm.MenuItems.Add("Carriage return + new line (\\r\\n)", delegate { textBox.SelectedText = "\\r\\n"; }); + return cm; + } + + public bool FindNext(TextBox textBox, int startIndex) + { + startIndex++; + if (startIndex < textBox.Text.Length) + { + if (FindType == FindType.RegEx) + { + Match match = _regEx.Match(textBox.Text, startIndex); + if (match.Success) + { + _findTextLenght = match.Length; + SelectedIndex = match.Index; + } + return match.Success; + } + string searchText = textBox.Text.Substring(startIndex); + int pos = FindPositionInText(searchText, 0); + if (pos >= 0) + { + SelectedIndex = pos + startIndex; + return true; + } + } + return false; + } + } +} diff --git a/src/Logic/HistoryItem.cs b/src/Logic/HistoryItem.cs new file mode 100644 index 000000000..54c5783e2 --- /dev/null +++ b/src/Logic/HistoryItem.cs @@ -0,0 +1,26 @@ +using System; + +namespace Nikse.SubtitleEdit.Logic +{ + public class HistoryItem + { + public int Index { get; set; } + public DateTime Timestamp { get; set; } + public string Description { get; set; } + public string FileName { get; set; } + public DateTime FileModified { get; set; } + public Subtitle Subtitle { get; set; } + public string SubtitleFormatFriendlyName { get; set; } + + public HistoryItem(int index, Subtitle subtitle, string description, string fileName, DateTime fileModified, string subtitleFormatFriendlyName) + { + Index = index; + Timestamp = DateTime.Now; + Subtitle = new Subtitle(subtitle); + Description = description; + FileName = fileName; + FileModified = fileModified; + SubtitleFormatFriendlyName = subtitleFormatFriendlyName; + } + } +} diff --git a/src/Logic/IfoParser.cs b/src/Logic/IfoParser.cs new file mode 100644 index 000000000..145ced383 --- /dev/null +++ b/src/Logic/IfoParser.cs @@ -0,0 +1,408 @@ +using System; +using System.Collections.Generic; +using System.Drawing; +using System.IO; +using System.Text; + +namespace Nikse.SubtitleEdit.Logic +{ + public class IfoParser + { + public struct AudioStream + { + public int LangageTypeSpecified; + public string Langage; + public string LangageCode; + public string CodingMode; + public int Channels; + public string Extension; + }; + + public struct VideoStream + { + public string Aspect; + public string Standard; + public string CodingMode; + public string Resolution; + } + + public class VtsVobs + { + public int NumberOfAudioStreams; + public int NumberOfSubtitles; + public VideoStream VideoStream; + public List AudioStreams; + public List Subtitles; + + public VtsVobs() + { + VideoStream = new VideoStream(); + AudioStreams = new List(); + Subtitles = new List(); + } + }; + + public class ProgramChain + { + public int NumberOfPGC; + public int NumberOfCells; + public string PlaybackTime; + public List PGCEntryCells; + public List PGCPlaybackTimes; + public List PGCStartTimes; + public List AudioStreamsAvailable; + public List SubtitlesAvailable; + public List ColorLookupTable; + + public ProgramChain() + { + PGCEntryCells = new List(); + PGCPlaybackTimes = new List(); + PGCStartTimes = new List(); + AudioStreamsAvailable = new List(); + SubtitlesAvailable = new List(); + ColorLookupTable = new List(); + } + }; + + public class VtsPgci + { + public int NumberOfProgramChains; + public List ProgramChains; + + public VtsPgci() + { + ProgramChains = new List(); + } + }; + + + readonly List ArrayOfAudioMode = new List { "AC3", "...", "MPEG1", "MPEG2", "LPCM", "...", "DTS" }; + readonly List ArrayOfAudioExtension = new List { "unspecified", "normal", "for visually impaired", "director's comments", "alternate director's comments" }; + readonly List ArrayOfAspect = new List { "4:3", "...", "...", "16:9" }; + readonly List ArrayOfStandard = new List { "NTSC", "PAL", "...", "..." }; + readonly List ArrayOfCodingMode = new List { "MPEG1", "MPEG2" }; + readonly List ArrayOfNTSCResolution = new List { "720x480", "704x480", "352x480", "352x240" }; + readonly List ArrayOfPALResolution = new List { "720x576", "704x576", "352x576", "352x288" }; + readonly List ArrayOfLangageCode = new List { " ", "aa", "ab", "af", "am", "ar", "as", "ay", "az", "ba", "be", "bg", "bh", "bi", "bn", "bo", "br", "ca", "co", "cs", "cy", "da", "de", "dz", "el", + "en", "eo", "es", "et", "eu", "fa", "fi", "fj", "fo", "fr", "fy", "ga", "gd", "gl", "gn", "gu", "ha", "he", "hi", "hr", "hu", "hy", "ia", "id", "ie", "ik", + "in", "is", "it", "iu", "iw", "ja", "ji", "jw", "ka", "kk", "kl", "km", "kn", "ko", "ks", "ku", "ky", "la", "ln", "lo", "lt", "lv", "mg", "mi", "mk", "ml", + "mn", "mo", "mr", "ms", "mt", "my", "na", "ne", "nl", "no", "oc", "om", "or", "pa", "pl", "ps", "pt", "qu", "rm", "rn", "ro", "ru", "rw", "sa", "sd", "sg", + "sh", "si", "sk", "sl", "sm", "sn", "so", "sq", "sr", "ss", "st", "su", "sv", "sw", "ta", "te", "tg", "th", "ti", "tk", "tl", "tn", "to", "tr", "ts", "tt", + "tw", "ug", "uk", "ur", "uz", "vi", "vo", "wo", "xh", "yi", "yo", "za", "zh", "zu", ""}; + readonly List ArrayOfLangage = new List { "Not Specified", "Afar", "Abkhazian", "Afrikaans", "Amharic", "Arabic", "Assamese", "Aymara", "Azerbaijani", "Bashkir", "Byelorussian", "Bulgarian", "Bihari", "Bislama", "Bengali; Bangla", "Tibetan", "Breton", "Catalan", "Corsican", "Czech(Ceske)", "Welsh", "Dansk", "Deutsch", "Bhutani", "Greek", + "English", "Esperanto", "Espanol", "Estonian", "Basque", "Persian", "Suomi", "Fiji", "Faroese", "Français", "Frisian", "Irish", "Scots Gaelic", "Galician", "Guarani", "Gujarati", "Hausa", "Hebrew", "Hindi", "Hrvatski", "Magyar", "Armenian", "Interlingua", "Indonesian", "Interlingue", "Inupiak", + "Indonesian", "Islenska", "Italiano", "Inuktitut", "Hebrew", "Japanese", "Yiddish", "Javanese", "Georgian", "Kazakh", "Greenlandic", "Cambodian", "Kannada", "Korean", "Kashmiri", "Kurdish", "Kirghiz", "Latin", "Lingala", "Laothian", "Lithuanian", "Latvian, Lettish", "Malagasy", "Maori", "Macedonian", "Malayalam", + "Mongolian", "Moldavian", "Marathi", "Malay", "Maltese", "Burmese", "Nauru", "Nepali", "Nederlands", "Norsk", "Occitan", "(Afan) Oromo", "Oriya", "Punjabi", "Polish", "Pashto, Pushto", "Portugues", "Quechua", "Rhaeto-Romance", "Kirundi", "Romanian", "Russian", "Kinyarwanda", "Sanskrit", "Sindhi", "Sangho", + "Serbo-Croatian", "Sinhalese", "Slovak", "Slovenian", "Samoan", "Shona", "Somali", "Albanian", "Serbian", "Siswati", "Sesotho", "Sundanese", "Svenska", "Swahili", "Tamil", "Telugu", "Tajik", "Thai", "Tigrinya", "Turkmen", "Tagalog", "Setswana", "Tonga", "Turkish", "Tsonga", "Tatar", + "Twi", "Uighur", "Ukrainian", "Urdu", "Uzbek", "Vietnamese", "Volapuk", "Wolof", "Xhosa", "Yiddish", "Yoruba", "Zhuang", "Chinese", "Zulu", "???"}; + + public VtsPgci VideoTitleSetProgramChainTable { get { return _vtsPgci; } } + public VtsVobs VideoTitleSetVobs { get { return _vtsVobs; } } + public string ErrorMessage { get; private set; } + + private VtsVobs _vtsVobs = new VtsVobs(); + private VtsPgci _vtsPgci = new VtsPgci(); + FileStream _fs; + + public IfoParser(string fileName) + { + try + { + _fs = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.Read); + + byte[] buffer = new byte[12]; + _fs.Position = 0; + _fs.Read(buffer, 0, 12); + string id = Encoding.UTF8.GetString(buffer); + if (id != "DVDVIDEO-VTS") + { + ErrorMessage = string.Format("IFO type is '{0}' and not 'DVDVIDEO-VTS'.{1}Try another file than {2}", id, Environment.NewLine, fileName); + return; + } + ParseVtsVobs(); + ParseVtsPgci(); + _fs.Close(); + } + catch (Exception exception) + { + ErrorMessage = exception.Message + Environment.NewLine + exception.StackTrace; + } + } + + private void ParseVtsVobs() + { + string data; + byte[] buffer = new byte[16]; + + //retrieve video info + _fs.Position = 0x200; + data = IntToBin(GetEndian(2), 16); + _vtsVobs.VideoStream.CodingMode = ArrayOfCodingMode[BinToInt(MidStr(data, 0, 2))]; + _vtsVobs.VideoStream.Standard = ArrayOfStandard[BinToInt(MidStr(data, 2, 2))]; + _vtsVobs.VideoStream.Aspect = ArrayOfAspect[BinToInt(MidStr(data, 4, 2))]; + if (_vtsVobs.VideoStream.Standard == "PAL") + _vtsVobs.VideoStream.Resolution = ArrayOfPALResolution[BinToInt(MidStr(data, 13, 2))]; + else if (_vtsVobs.VideoStream.Standard == "NTSC") + _vtsVobs.VideoStream.Resolution = ArrayOfNTSCResolution[BinToInt(MidStr(data, 13, 2))]; + + //retrieve audio info + _fs.Position = 0x202; //useless but here for readability + _vtsVobs.NumberOfAudioStreams = GetEndian(2); + // _ifo.VtsVobs.AudioStreams = new List(); + for (int i = 0; i < _vtsVobs.NumberOfAudioStreams; i++) + { + AudioStream audioStream = new AudioStream(); + data = IntToBin(GetEndian(2), 16); + audioStream.LangageTypeSpecified = Convert.ToInt32(MidStr(data, 4, 2)); + audioStream.CodingMode = ArrayOfAudioMode[(BinToInt(MidStr(data, 0, 3)))]; + audioStream.Channels = BinToInt(MidStr(data, 13, 3)) + 1; + _fs.Read(buffer, 0, 2); + audioStream.LangageCode = Convert.ToChar(buffer[0]).ToString() + Convert.ToChar(buffer[1]).ToString(); + if (ArrayOfLangageCode.Contains(audioStream.LangageCode)) + audioStream.Langage = ArrayOfLangage[ArrayOfLangageCode.IndexOf(audioStream.LangageCode)]; + _fs.Seek(1, SeekOrigin.Current); + audioStream.Extension = ArrayOfAudioExtension[_fs.ReadByte()]; + _fs.Seek(2, SeekOrigin.Current); + _vtsVobs.AudioStreams.Add(audioStream); + } + + //retrieve subs info (only name) + _fs.Position = 0x254; + _vtsVobs.NumberOfSubtitles = GetEndian(2); + _fs.Position += 2; + for (int i = 0; i < _vtsVobs.NumberOfSubtitles; i++) + { + _fs.Read(buffer, 0, 2); + string languageTwoLetter = Convert.ToChar(buffer[0]).ToString() + Convert.ToChar(buffer[1]).ToString(); + _vtsVobs.Subtitles.Add(InterpretLangageCode(languageTwoLetter)); + + string subtitleFormat = string.Empty; + _fs.Read(buffer, 0, 2); // reserved for language code extension + code extension + switch (buffer[0]) // 4, 8, 10-12 unused + { + // http://dvd.sourceforge.net/dvdinfo/sprm.html + case 1: subtitleFormat = "(caption/normal size char)"; break; //0 = unspecified caption + case 2: subtitleFormat = "(caption/large size char)"; break; + case 3: subtitleFormat = "(caption for children)"; break; + case 5: subtitleFormat = "(closed caption/normal size char)"; break; + case 6: subtitleFormat = "(closed caption/large size char)"; break; + case 7: subtitleFormat = "(closed caption for children)"; break; + case 9: subtitleFormat = "(forced caption)"; break; + case 13: subtitleFormat = "(director comments/normal size char)"; break; + case 14: subtitleFormat = "(director comments/large size char)"; break; + case 15: subtitleFormat = "(director comments for children)"; break; + } + +//// int languageId = buffer[1] & Helper.B11111000; +// int languageId1 = buffer[0] & Helper.B11111000; +// int languageId2= buffer[1] & Helper.B11111000; +// System.Diagnostics.Debug.WriteLine(languageTwoLetter + " " + languageId1.ToString() + " " + languageId2.ToString() + " " + buffer[0].ToString() + " " + buffer[1].ToString()); + _fs.Position += 2; + } + } + + private int BinToInt(string p) + { + return Convert.ToInt32(p, 2); + } + + private string MidStr(string data, int start, int count) + { + return data.Substring(start, count); + } + + private string IntToBin(int value, int digits) + { + string result = string.Empty; + result = Convert.ToString(value, 2); + while (result.Length < digits) + result = "0" + result; + return result; + } + + private int GetEndian(int count) + { + int result = 0; + for (int i = count; i > 0; i--) + { + int b = _fs.ReadByte(); + result = (result << 8) + b; + } + return result; + } + + private string InterpretLangageCode(string code) + { + int i = 0; + while (ArrayOfLangageCode[i] != code && i < 143) + { + i++; + } + return ArrayOfLangage[i]; + } + + private void ParseVtsPgci() + { + const int SectorSize = 2048; + + _fs.Position = 0xCC; //Get VTS_PGCI adress + int tableStart = SectorSize * GetEndian(4); + + _fs.Position = tableStart; + _vtsPgci.NumberOfProgramChains = GetEndian(2); + _vtsPgci.ProgramChains = new List(); + + for (int i = 0; i < _vtsPgci.NumberOfProgramChains; i++) + { + //Parse PGC Header + ProgramChain programChain = new ProgramChain(); + _fs.Position = tableStart + 4 + 8 * (i + 1); //Get PGC adress + int programChainAdress = GetEndian(4); + _fs.Position = tableStart + programChainAdress + 2; //Move to PGC + programChain.NumberOfPGC = _fs.ReadByte(); + programChain.NumberOfCells = _fs.ReadByte(); + programChain.PlaybackTime = InterpretTime(GetEndian(4)); + _fs.Seek(4, SeekOrigin.Current); + + // check if audio streams are available for this PGC + _fs.Position = tableStart + programChainAdress + 0xC; + for (int j = 0; j < _vtsVobs.NumberOfAudioStreams; j++) + { + string temp = IntToBin(_fs.ReadByte(), 8); + programChain.AudioStreamsAvailable.Add(temp[0]); + _fs.Seek(1, SeekOrigin.Current); + } + + // check if subtitles are available for this PGC + _fs.Position = tableStart + programChainAdress + 0x1C; + for (int j = 0; j < _vtsVobs.NumberOfSubtitles; j++) + { + string temp = IntToBin(_fs.ReadByte(), 8); + programChain.SubtitlesAvailable.Add(temp[0]); + _fs.Seek(3, SeekOrigin.Current); + } + + //Parse Color LookUp Table (CLUT) - offset 00A4, 16*4 (0, Y, Cr, Cb) + _fs.Position = tableStart + programChainAdress + 0xA4; + for (int colorNumber = 0; colorNumber < 16; colorNumber++) + { + byte[] colors = new byte[4]; + _fs.Read(colors, 0, 4); + int y = colors[1]-16; + int cr = colors[2]-128; + int cb = colors[3]-128; + int r = (int)Math.Min(Math.Max(Math.Round(1.1644F * y + 1.596F * cr), 0), 255); + int g = (int)Math.Min(Math.Max(Math.Round(1.1644F * y - 0.813F * cr - 0.391F * cb), 0), 255); + int b = (int)Math.Min(Math.Max(Math.Round(1.1644F * y + 2.018F * cb), 0), 255); + + programChain.ColorLookupTable.Add(Color.FromArgb(r, g, b)); + } + + //Parse Program Map + _fs.Position = tableStart + programChainAdress + 0xE6; + _fs.Position = tableStart + programChainAdress + GetEndian(2); + for (int j = 0; j < programChain.NumberOfPGC; j++) + { + programChain.PGCEntryCells.Add((byte)_fs.ReadByte()); + } + + // Cell Playback Info Table to retrieve duration + _fs.Position = tableStart + programChainAdress + 0xE8; + _fs.Position = tableStart + programChainAdress + GetEndian(2); + int max = 0; + List timeArray = new List(); + for (int k = 0; k < programChain.NumberOfPGC; k++) + { + int time = 0; + if (k == programChain.NumberOfPGC - 1) + max = programChain.NumberOfCells; + else + max = programChain.PGCEntryCells[k + 1] - 1; + for (int j = programChain.PGCEntryCells[k]; j <= max; j++) + { + _fs.Seek(4, SeekOrigin.Current); + time += TimeToMs(GetEndian(4)); + _fs.Seek(16, SeekOrigin.Current); + } + programChain.PGCPlaybackTimes.Add(MsToTime(time)); + timeArray.Add(time); + + //convert to start time + time = 0; + for (int l = 1; l <= k; l++) + { + time += timeArray[l - 1]; + } + if (k == 0) + programChain.PGCStartTimes.Add(MsToTime(0)); + if (k > 0) + programChain.PGCStartTimes.Add(MsToTime(time)); + } + _vtsPgci.ProgramChains.Add(programChain); + } + } + + private int StrToInt(string s, int number) + { + return int.Parse(s); + } + + private int TimeToMs(int time) + { + int result; + string temp; + double fps; + + temp = IntToBin(time, 32); + result = StrToInt(IntToHex(BinToInt(MidStr(temp,0,8)),1))*3600000; + result = result + StrToInt(IntToHex(BinToInt(MidStr(temp,8,8)),2))*60000; + result = result + StrToInt(IntToHex(BinToInt(MidStr(temp,16,8)),2))*1000; + if (temp.Substring(24,2) == "11") + fps = 30; + else + fps = 25; + result += (int) Math.Round((double)(1000.0/fps)*StrToFloat(IntToHex(BinToInt(MidStr(temp,26,6)),3))); + return result; + } + + private double StrToFloat(string p) + { + return Convert.ToDouble(p); + } + + private int StrToInt(string p) + { + return int.Parse(p); + } + + private string IntToHex(int value, int digits) + { + string hex = value.ToString("X"); + + return hex.PadLeft(digits, '0'); + } + + private string MsToTime(double milliseconds) + { + TimeSpan ts = TimeSpan.FromMilliseconds(milliseconds); + string s = string.Format("{0:#0}:{1:00}:{2:00}.{3:000}", ts.Hours, ts.Minutes, ts.Seconds, ts.Milliseconds); + return s; + } + + private string InterpretTime(int timeNumber) + { + string timeBytes = IntToBin(timeNumber, 32); + int h = StrToInt(IntToHex(BinToInt(timeBytes.Substring(0,8)),1)); + int m = StrToInt(IntToHex(BinToInt(timeBytes.Substring(8,8)),2)); + int s = StrToInt(IntToHex(BinToInt(timeBytes.Substring(16,8)),2)); + int fps = 25; + if (timeBytes.Substring(24, 2) == "11") + fps = 30; + int milliseconds = (int)Math.Round((1000.0/fps)*StrToFloat(IntToHex(BinToInt(timeBytes.Substring(26,6)),3))); + TimeSpan ts = new TimeSpan(0, h, m, s, milliseconds); + return MsToTime(ts.TotalMilliseconds); + } + + } +} \ No newline at end of file diff --git a/src/Logic/ImageSplitter.cs b/src/Logic/ImageSplitter.cs new file mode 100644 index 000000000..224fc2a29 --- /dev/null +++ b/src/Logic/ImageSplitter.cs @@ -0,0 +1,361 @@ +using System; +using System.Collections.Generic; +using System.Drawing; + +namespace Nikse.SubtitleEdit.Logic +{ + public class ImageSplitter + { + public static bool IsColorClose(Color a, Color b, int tolerance) + { + int diff = (a.R + a.G + a.B) - (b.R + b.G + b.B); + return diff < tolerance && diff > -tolerance; + } + + public static Bitmap Copy(Bitmap sourceBitmap, Rectangle section) + { + // Create the new bitmap and associated graphics object + var bmp = new Bitmap(section.Width, section.Height); + Graphics g = Graphics.FromImage(bmp); + + // Draw the specified section of the source bitmap to the new one + g.DrawImage(sourceBitmap, 0, 0, section, GraphicsUnit.Pixel); + + // Clean up + g.Dispose(); + + // Return the bitmap + return bmp; + } + + private static Bitmap CropTopAndBottom(Bitmap bmp, out int topCropping) + { + int startTop = 0; + int maxTop = bmp.Height-2; + if (maxTop > bmp.Height) + maxTop = bmp.Height; + for (int y = 0; y < maxTop; y++) + { + bool allTransparent = true; + for (int x = 1; x < bmp.Width - 1; x++) + { + Color c = bmp.GetPixel(x, y); + if (c.A != 0) + { + allTransparent = false; + break; + } + } + if (!allTransparent) + break; + startTop++; + } + if (startTop > 9) + startTop -= 5; // if top space > 9, then allways leave blank 5 pixels on top (so . is not confused with '). + topCropping = startTop; + + for (int y = bmp.Height-1; y > 3; y--) + { + bool allTransparent = true; + for (int x = 1; x < bmp.Width-1; x++) + { + Color c = bmp.GetPixel(x, y); + if (c.A != 0) + { + allTransparent = false; + break; + } + } + if (allTransparent == false) + return Copy(bmp, new Rectangle(0, startTop, bmp.Width - 1, y-startTop+1)); + } + return bmp; + } + + public static List SplitVertical(Bitmap bmp) + { // split into lines + int startY = 0; + int size = 0; + var parts = new List(); + for (int y = 0; y < bmp.Height; y++) + { + bool allTransparent = true; + for (int x = 0; x < bmp.Width; x++) + { + Color c = bmp.GetPixel(x, y); + if (c.A != 0) + { + allTransparent = false; + break; + } + } + if (allTransparent) + { + if (size > 2 && size < 6) + { + size++; // at least 5 pixels, like top of 'i' + } + else + { + if (size > 2) + { + Bitmap part = Copy(bmp, new Rectangle(0, startY, bmp.Width, size+1)); +// part.Save("c:\\line_0_to_width.bmp"); + parts.Add(new ImageSplitterItem(0, startY, part)); +// bmp.Save("c:\\orginal.bmp"); + } + size = 0; + startY = y; + } + } + else + { + size++; + } + + } + if (size > 2) + { + Bitmap part = Copy(bmp, new Rectangle(0, startY, bmp.Width, size+1)); + parts.Add(new ImageSplitterItem(0, startY, part)); + } + return parts; + } + + public static int IsBitmapsAlike(Bitmap bmp1, Bitmap bmp2) + { + int different = 0; + + for (int x = 1; x < bmp1.Width; x++) + { + for (int y = 1; y < bmp1.Height; y++) + { + if (!IsColorClose(bmp1.GetPixel(x, y), bmp2.GetPixel(x, y), 20)) + different++; + } + } + return different; + } + + public static int IsBitmapsAlike(FastBitmap bmp1, Bitmap bmp2) + { + int different = 0; + + for (int x = 1; x < bmp1.Width; x++) + { + for (int y = 1; y < bmp1.Height; y++) + { + Color c1 = bmp1.GetPixel(x, y); + Color c2 = bmp1.GetPixel(x, y); + if (!IsColorClose(c1, c2, 20)) + different++; + } + } + return different; + } + + + private static List SplitHorizontal(ImageSplitterItem verticalItem, int xOrMorePixelsMakesSpace) + { // split line into letters + Bitmap bmp = verticalItem.Bitmap; + var parts = new List(); + int size = 0; + int startX = 0; + int lastEndX = 0; + int y = 0; + + for (int x = 0; x < bmp.Width - 1; x++) + { + bool allTransparent = IsVerticalLineTransparent(bmp, ref y, x); + + // check if line is transparent and cursive + bool cursiveOk = false; + int tempY = 0; + if (allTransparent == false && + size > 5 && + y > 3 && + x < bmp.Width-2 && + !IsVerticalLineTransparent(bmp, ref tempY, x + 1)) + { + var cursivePoints = new List(); + + cursiveOk = IsCursiveVerticalLineTransparent(bmp, size, y, x, cursivePoints); + + if (cursiveOk) + { + // make letter image + int end = x + 1 - startX; + if (startX > 0) + { + startX--; + end++; + } + Bitmap b1 = Copy(bmp, new Rectangle(startX, 0, end, bmp.Height)); +// b1.Save("c:\\cursive.bmp"); + + // make non-black/transparent stuff from other letter transparent + foreach (Point p in cursivePoints) + { + for (int fixY = p.Y; fixY < bmp.Height; fixY++) + b1.SetPixel(p.X - startX, fixY, Color.Transparent); + } + + RemoveBlackBarRight(b1); +// b1.Save("c:\\cursive-cleaned.bmp"); + + // crop and save image + int addY; + b1 = CropTopAndBottom(b1, out addY); + parts.Add(new ImageSplitterItem(startX, verticalItem.Y + addY, b1)); + size = 0; + startX = x + 1; + lastEndX = x; + } + } + + if (!cursiveOk) + { + if (allTransparent) + { + if (size > 0) + { + if (size > 1) + { + //Add space? + if (lastEndX > 0 && lastEndX + xOrMorePixelsMakesSpace < startX) + parts.Add(new ImageSplitterItem(" ")); + + if (startX > 0) + startX--; + lastEndX = x; + int end = x + 1 - startX; + Bitmap part = Copy(bmp, new Rectangle(startX, 0, end, bmp.Height)); + RemoveBlackBarRight(part); + int addY; + // part.Save("c:\\before" + startX.ToString() + ".bmp"); + part = CropTopAndBottom(part, out addY); + // part.Save("c:\\after" + startX.ToString() + ".bmp"); + parts.Add(new ImageSplitterItem(startX, verticalItem.Y + addY, part)); + } + size = 0; + } + startX = x + 1; + } + else + { + size++; + } + } + } + + if (size > 0) + { + if (lastEndX > 0 && lastEndX + xOrMorePixelsMakesSpace < startX) + parts.Add(new ImageSplitterItem(" ")); + + if (startX > 0) + startX--; + lastEndX = bmp.Width-1; + int end = lastEndX + 1 - startX; + Bitmap part = Copy(bmp, new Rectangle(startX, 0, end, bmp.Height - 1)); + int addY; + part = CropTopAndBottom(part, out addY); + parts.Add(new ImageSplitterItem(startX, verticalItem.Y + addY, part)); + } + return parts; + } + + private static void RemoveBlackBarRight(Bitmap bmp) + { + int xRemoveBlackBar = bmp.Width-1; + for (int yRemoveBlackBar = 0; yRemoveBlackBar < bmp.Height; yRemoveBlackBar++) + { + Color c = bmp.GetPixel(xRemoveBlackBar, yRemoveBlackBar); + if (c.A == 0 || IsColorClose(c, Color.Black, 280)) + { + if (bmp.GetPixel(xRemoveBlackBar - 1, yRemoveBlackBar).A == 0) + bmp.SetPixel(xRemoveBlackBar, yRemoveBlackBar, Color.Transparent); + } + } + } + + private static bool IsCursiveVerticalLineTransparent(Bitmap bmp, int size, int y, int x, List cursivePoints) + { + bool cursiveOk = true; + int newY = y; + int newX = x; + while (cursiveOk && newY < bmp.Height - 1) + { + Color c0 = bmp.GetPixel(newX, newY); + if (c0.A == 0 || IsColorClose(c0, Color.Black, 280)) + { + newY++; + } + else + { + Color c1 = bmp.GetPixel(newX - 1, newY - 1); + Color c2 = bmp.GetPixel(newX - 1, newY); + if ((c1.A == 0 || IsColorClose(c1, Color.Black, 280)) && // still dark color... + (c2.A == 0 || IsColorClose(c2, Color.Black, 280))) + { + cursivePoints.Add(new Point(newX, newY)); + newX--; + newY++; + } + else + { + cursiveOk = false; + } + } + + if (newX < x - size) + cursiveOk = false; + } + return cursiveOk; + } + + private static bool IsVerticalLineTransparent(Bitmap bmp, ref int y, int x) + { + bool allTransparent = true; + for (y = 0; y < bmp.Height - 1; y++) + { + Color c = bmp.GetPixel(x, y); + if (c.A == 0 || //c.ToArgb() == transparentColor.ToArgb() || + IsColorClose(c, Color.Black, 280)) // still dark color... + { + } + else + { + allTransparent = false; + break; + } + } + return allTransparent; + } + + public static List SplitBitmapToLetters(Bitmap bmp, int xOrMorePixelsMakesSpace) + { + var list = new List(); + + // split into seperate lines + List verticalBitmaps = SplitVertical(bmp); + + + // split into letters + int lineCount = 0; + foreach (ImageSplitterItem b in verticalBitmaps) + { + if (lineCount > 0) + list.Add(new ImageSplitterItem(Environment.NewLine)); + foreach (ImageSplitterItem item in SplitHorizontal(b, xOrMorePixelsMakesSpace)) + { + list.Add(item); + } + lineCount++; + } + + return list; + } + + } +} diff --git a/src/Logic/ImageSplitterItem.cs b/src/Logic/ImageSplitterItem.cs new file mode 100644 index 000000000..5b443e6fd --- /dev/null +++ b/src/Logic/ImageSplitterItem.cs @@ -0,0 +1,28 @@ +using System.Drawing; + +namespace Nikse.SubtitleEdit.Logic +{ + public class ImageSplitterItem + { + public int X { get; set; } + public int Y { get; set; } + public Bitmap Bitmap { get; set; } + public string SpecialCharacter { get; set; } + + public ImageSplitterItem(int x, int y, Bitmap bitmap) + { + X = x; + Y = y; + Bitmap = bitmap; + SpecialCharacter = null; + } + + public ImageSplitterItem(string specialCharacter) + { + X = 0; + Y = 0; + SpecialCharacter = specialCharacter; + Bitmap = null; + } + } +} diff --git a/src/Logic/Language.cs b/src/Logic/Language.cs new file mode 100644 index 000000000..2d8726509 --- /dev/null +++ b/src/Logic/Language.cs @@ -0,0 +1,1362 @@ +using System; +using System.IO; +using System.IO.Compression; +using System.Text; +using System.Xml; +using System.Xml.Serialization; + +namespace Nikse.SubtitleEdit.Logic +{ + public class Language + { + [XmlAttribute("Name")] + public string Name; + public LanguageStructure.General General; + public LanguageStructure.About About; + public LanguageStructure.AddToNames AddToNames; + public LanguageStructure.AddWareForm AddWaveForm; + public LanguageStructure.AdjustDisplayDuration AdjustDisplayDuration; + public LanguageStructure.AutoBreakUnbreakLines AutoBreakUnbreakLines; + public LanguageStructure.ChangeCasing ChangeCasing; + public LanguageStructure.ChangeCasingNames ChangeCasingNames; + public LanguageStructure.ChangeFrameRate ChangeFrameRate; + public LanguageStructure.ChooseEncoding ChooseEncoding; + public LanguageStructure.ChooseLanguage ChooseLanguage; + public LanguageStructure.CompareSubtitles CompareSubtitles; + public LanguageStructure.DvdSubRip DvdSubrip; + public LanguageStructure.DvdSubRipChooseLanguage DvdSubRipChooseLanguage; + public LanguageStructure.EffectKaraoke EffectKaraoke; + public LanguageStructure.EffectTypewriter EffectTypewriter; + public LanguageStructure.FindDialog FindDialog; + public LanguageStructure.FindSubtitleLine FindSubtitleLine; + public LanguageStructure.FixCommonErrors FixCommonErrors; + public LanguageStructure.GetDictionaries GetDictionaries; + public LanguageStructure.GoogleTranslate GoogleTranslate; + public LanguageStructure.GoToLine GoToLine; + public LanguageStructure.ImportText ImportText; + public LanguageStructure.Main Main; + public LanguageStructure.MatroskaSubtitleChooser MatroskaSubtitleChooser; + public LanguageStructure.MergeShortLines MergedShortLines; + public LanguageStructure.MultipleReplace MultipleReplace; + public LanguageStructure.RemoveTextFromHearImpaired RemoveTextFromHearImpaired; + public LanguageStructure.ReplaceDialog ReplaceDialog; + public LanguageStructure.SetMinimumDisplayTimeBetweenParagraphs SetMinimumDisplayTimeBetweenParagraphs; + public LanguageStructure.SetSyncPoint SetSyncPoint; + public LanguageStructure.Settings Settings; + public LanguageStructure.ShowEarlierLater ShowEarlierLater; + public LanguageStructure.ShowHistory ShowHistory; + public LanguageStructure.SpellCheck SpellCheck; + public LanguageStructure.SplitSubtitle SplitSubtitle; + public LanguageStructure.StartNumberingFrom StartNumberingFrom; + public LanguageStructure.PointSync PointSync; + public LanguageStructure.UnknownSubtitle UnknownSubtitle; + public LanguageStructure.VisualSync VisualSync; + public LanguageStructure.VobSubEditCharacters VobSubEditCharacters; + public LanguageStructure.VobSubOcr VobSubOcr; + public LanguageStructure.VobSubOcrCharacter VobSubOcrCharacter; + public LanguageStructure.VobSubOcrNewFolder VobSubOcrNewFolder; + public LanguageStructure.WaveForm WaveForm; + + public Language() + { + Name = "English"; + + General = new LanguageStructure.General + { + Title = "Subtitle Edit", + Version = "3.0", + TranslatedBy = "", + CultureName = "en-US", + OK = "&OK", + Cancel = "C&ancel", + Apply = "Apply", + None = "None", + Preview = "Preview", + SubtitleFiles = "Subtitle files", + AllFiles = "All files", + VideoFiles = "Video files", + OpenSubtitle = "Open subtitle...", + OpenVideoFile = "Open video file...", + NoVideoLoaded = "No video loaded", + VideoInformation = "Video info", + PositionX = "Position / duration: {0}", + StartTime = "Start time", + EndTime = "End time", + Duration = "Duration", + Number = "Number", + Text = "Text", + HourMinutesSecondsMilliseconds = "Hour:min:sec:msec", + Bold = "Bold", + Italic = "Italic", + Visible = "Visible", + FrameRate = "Frame rate", + Name = "Name", + SingleLineLengths = "Single line length: ", + TotalLengthX = "Total length: {0}", + TotalLengthXSplitLine = "Total length: {0} (split line!)", + NotAvailable = "N/A", + FileNameXAndSize = "File name: {0} ({1})", + ResolutionX = "Resolution: {0}", + FrameRateX = "Frame rate: {0:0.0###}", + TotalFramesX = "Total frames: {0:#,##0.##}", + VideoEncodingX = "Video encoding: {0}", + OverlapPreviousLineX = "Overlap prev line ({0:#,##0.###})", + OverlapX = "Overlap ({0:#,##0.###})", + OverlapNextX = "Overlap next ({0:#,##0.###})", + Negative = "Negative", + RegularExpressionIsNotValid = "Regular expression is not valid!", + SubtitleSaved = "Subtitle saved", + CurrentSubtitle = "Current subtitle", + OriginalText = "Original text", + OpenOriginalSubtitleFile = "Open original subtitle file...", + PleaseWait = "Please wait...", + }; + + About = new LanguageStructure.About + { + Title = "About Subtitle Edit", + AboutText1 = "Subtitle Edit is Free Software under the GNU Public License." + Environment.NewLine + + "You may distribute, modify and use it freely." + Environment.NewLine + + Environment.NewLine + + "C# source code is either available on web site or can be emailed on request." + Environment.NewLine + + Environment.NewLine + + "Visit www.nikse.dk for the latest version." + Environment.NewLine + + Environment.NewLine + + "Suggestions are very welcome." + Environment.NewLine + + Environment.NewLine + + "Email: mailto:nikse.dk@gmail.com", + }; + + AddToNames = new LanguageStructure.AddToNames + { + Title = "Add to names/etc list", + Description = "Add to names/noise list (case sensitive)", + }; + + AddWaveForm = new LanguageStructure.AddWareForm + { + Title = "Generate wave form data", + GenerateWaveFormData = "Generate wave form data", + SourceVideoFile = "Source video file:", + PleaseWait = "This may take a few minutes - please wait", + VlcMediaPlayerNotFoundTitle = "VLC Media Player not found", + VlcMediaPlayerNotFound = "Subtitle Edit needs VLC media player 1.1.x or newer for extracting audio data.", + GoToVlcMediaPlayerHomePage = "Do you want to go to the VLC media player home page?", + GeneratingPeakFile = "Generating peak file...", + ExtractingSeconds = "Extracting audio: {0:0.0} seconds", + ExtractingMinutes = "Extracting audio: {0}.{1:00} minutes", + }; + + AdjustDisplayDuration = new LanguageStructure.AdjustDisplayDuration + { + Title = "Adjust durations", + AdjustVia = "Adjust via", + AddSeconds = "Add seconds", + SetAsPercent = "Set as percent of duration", + Percent = "Percent", + Seconds = "Seconds", + Note = "Note: Display time will not overlap start time of next text", + PleaseSelectAValueFromTheDropDownList = "Please select a value from the dropdown list", + PleaseChoose =" - Please choose - ", + }; + + AutoBreakUnbreakLines = new LanguageStructure.AutoBreakUnbreakLines + { + TitleAutoBreak = "Auto balance selected lines", + TitleUnbreak = "Remove line breaks from selected lines", + LineNumber = "Line#", + Before = "Before", + After = "After", + LinesFoundX = "Lines found: {0}", + OnlyBreakLinesLongerThan = "Only break lines longer than", + OnlyUnbreakLinesShorterThan = "Only un-break lines shorter than", + }; + + ChangeCasing = new LanguageStructure.ChangeCasing + { + Title = "Change casing", + ChangeCasingTo = "Change casing to", + NormalCasing = "Normal casing. Sentences begin with uppercase letter.", + FixNamesCasing = @"Fix names casing (via Dictionaries\NamesEtc.xml)", + FixOnlyNamesCasing = @"Fix only names casing (via Dictionaries\NamesEtc.xml)", + OnlyChangeAllUppercaseLines = "Only change all upper case lines.", + AllUppercase = "ALL UPPERCASE", + AllLowercase = "all lowercase", + }; + + ChangeCasingNames = new LanguageStructure.ChangeCasingNames + { + Title = "Change casing - Names", + NamesFoundInSubtitleX = "Names found in subtitle: {0}", + Enabled = "Enabled", + Name = "Name", + LineNumber = "Line#", + Before = "Before", + After = "After", + LinesFoundX = "Lines found: {0}", + }; + + ChangeFrameRate = new LanguageStructure.ChangeFrameRate + { + Title = "Change frame rate", + ConvertFrameRateOfSubtitle = "Convert frame rate of subtitle", + FromFrameRate = "From frame rate", + ToFrameRate = "To frame rate", + }; + + ChooseEncoding = new LanguageStructure.ChooseEncoding + { + Title = "Choose encoding", + CodePage = "Code page", + DisplayName = "Display name", + PleaseSelectAnEncoding = "Please select an encoding", + }; + + ChooseLanguage = new LanguageStructure.ChooseLanguage + { + Title = "Choose language", + Language = "Language", + }; + + CompareSubtitles = new LanguageStructure.CompareSubtitles + { + Title = "Compare subtitles", + PreviousDifference = "&Previous difference", + NextDifference = "&Next difference", + SubtitlesNotAlike = "Subtitles have no similarities", + XNumberOfDifference = "Number of differences: {0}", + ShowOnlyDifferences = "Show only differences", + OnlyLookForDifferencesInText = "Only look for differences in text", + }; + + DvdSubrip = new LanguageStructure.DvdSubRip + { + Title = "Rip subtitles from ifo/vobs (dvd)", + DvdGroupTitle = "DVD files/info", + IfoFile = "IFO file", + IfoFiles = "IFO files", + VobFiles ="VOB files", + Add = "Add...", + Remove = "Remove", + Clear = "Clear", + MoveUp = "Move up", + MoveDown = "Move down", + Languages = "Languages", + PalNtsc = "PAL/NTSC", + Pal = "PAL (25fps)", + Ntsc = "NTSC (30fps)", + StartRipping = "Start ripping", + Abort = "Abort", + AbortedByUser = "Aborted by user", + ReadingSubtitleData = "Reading subtitle data...", + RippingVobFileXofYZ = "Ripping vob file {1} of {2}: {0}", + }; + + DvdSubRipChooseLanguage = new LanguageStructure.DvdSubRipChooseLanguage + { + Title = "Choose language", + ChooseLanguageStreamId = "Choose language (stream-id)", + UnknownLanguage = "Unknown language", + SubtitleImageXofYAndWidthXHeight = "Subtitle image {0}/{1} - {2}x{3} ", + }; + + EffectKaraoke = new LanguageStructure.EffectKaraoke + { + Title = "Karaoke effect", + ChooseColor = "Choose color:", + TotalMilliseconds = "Total millisecs.:", + EndDelayInMilliseconds = "End delay in millisecs.:" + }; + + EffectTypewriter = new LanguageStructure.EffectTypewriter + { + Title = "Typewriter effect", + TotalMilliseconds = "Total millisecs.:", + EndDelayInMillisecs = "End delay in millisecs.:" + }; + + FindDialog = new LanguageStructure.FindDialog + { + Title = "Find", + Find = "Find", + Normal = "Normal", + CaseSensitive = "Case sensitive", + RegularExpression = "Regular expression", + }; + + FindSubtitleLine = new LanguageStructure.FindSubtitleLine + { + Title = "Find subtitle line", + Find = "&Find", + FindNext = "Find &next", + }; + + FixCommonErrors = new LanguageStructure.FixCommonErrors + { + Title = "Fix common errors", + Step1 = "Step 1/2 - Choose which errors to fix", + WhatToFix = "What to fix", + Example = "Example", + SelectAll = "Select all", + InverseSelection = "Inverse selection", + Back = "< &Back", + Next = "&Next >", + Step2 = "Step 2/2 - Verify fixes", + Fixes = "Fixes", + Log = "Log", + LineNumber = "Line#", + Function = "Function", + Before = "Before", + After = "After", + RemovedEmptyLine = "Removed empty line", + RemovedEmptyLineAtTop = "Removed empty line at top", + RemovedEmptyLineAtBottom = "Removed empty line at bottom", + RemovedEmptyLinesUnsedLineBreaks = "Remove empty lines/unused line breaks", + EmptyLinesRemovedX = "Empty lines removed: {0}", + FixOverlappingDisplayTimes = "Fix overlapping display times", + FixShortDisplayTimes = "Fix short display times", + FixLongDisplayTimes = "Fix long display times", + FixInvalidItalicTags = "Fix invalid italic tags", + RemoveUnneededSpaces = "Remove unneeded spaces", + RemoveUnneededPeriods = "Remove unneeded periods", + FixMissingSpaces = "Fix missing spaces", + BreakLongLines = "Break long lines", + RemoveLineBreaks = "Remove line breaks in short texts with only one sentence", + FixUppercaseIInsindeLowercaseWords = "Fix uppercase 'i' inside lowercase words (ocr error)", + FixDoubleApostrophes = "Fix double apostrophe characters ('') to a single quote (\")", + AddPeriods = "Add period after lines where next line start with uppercase letter", + StartWithUppercaseLetterAfterParagraph = "Start with uppercase letter after paragraph", + StartWithUppercaseLetterAfterPeriodInsideParagraph = "Start with uppercase letter after period inside paragraph", + CommonOcrErrorsFixed = "Common OCR errors fixed (OcrReplaceList file used): {0}", + FixLowercaseIToUppercaseI = "Fix alone lowercase 'i' to 'I' (English)", + FixDanishLetterI = "Fix Danish letter 'i'", + FixSpanishInvertedQuestionAndExclamationMarks = "Fix Spanish inverted question and exclamation marks", + AddMissingQuote = "Add missing quote (\")", + AddMissingQuotes = "Add missing quotes (\")", + FixHyphens = "Fix lines beginning with hyphen (-)", + FixHyphen = "Fix line beginning with hyphen (-)", + XHyphensFixed = "Hyphens fixed: {0}", + AddMissingQuotesExample = "\"How are you? -> \"How are you?\"", + XMissingQuotesAdded = "Missing quotes added: {0}", + Fix3PlusLines = "Fix subtitles with more than two lines", + Fix3PlusLine = "Fix subtitle with more than two lines", + X3PlusLinesFixed = "Subtitles with more than two lines fixed: {0}", + Analysing = "Analyzing...", + NothingToFix = "Nothing to fix :)", + FixesFoundX = "Fixes found: {0}", + XFixesApplied = "Fixes applied: {0}", + NothingToFixBut = "Nothing to fix but a few things could be improved - see log for details", + FixLowercaseIToUppercaseICheckedButCurrentLanguageIsNotEnglish = "\"Fix alone lowercase 'i' to 'I' (English)\" is checked but currently loaded subtitle seems not be English.", + Continue = "Continue", + ContinueAnyway = "Continue anyway?", + UncheckedFixLowercaseIToUppercaseI = "Unchecked \"Fix alone lowercase 'i' to 'I' (English)\"", + XIsChangedToUppercase = "{0} i's changed to uppercase", + FixFirstLetterToUppercaseAfterParagraph = "Fix first letter to uppercase after paragraph", + MergeShortLine = "Merge short line", + XLineBreaksAdded = "{0} line breaks added", + BreakLongLine = "Break long line", + FixLongDisplayTime = "Fix long display time", + FixInvalidItalicTag = "Fix invalid italic tag", + FixShortDisplayTime = "Fix short display time", + FixOverlappingDisplayTime = "Fix overlapping display time", + FixInvalidItalicTagsExample = "What do i care. -> What do I care.", + RemoveUnneededSpacesExample = "Hey you , there. -> Hey you, there.", + RemoveUnneededPeriodsExample = "Hey you!. -> Hey you!", + FixMissingSpacesExample = "Hey.You. -> Hey. You.", + FixUppercaseIInsindeLowercaseWordsExample = "The earth is fIat. -> The earth is flat.", + FixLowercaseIToUppercaseIExample = "What do i care. -> What do I care.", + StartTimeLaterThanEndTime = "Text number {0}: Start time is later end end time: {4}{1} --> {2} {3}", + UnableToFixStartTimeLaterThanEndTime = "Unable to fix text number {0}: Start time is later end end time: {1}", + XFixedToYZ = "{0} fixed to: {1}{2}", + UnableToFixTextXY = "Unable to fix text number {0}: {1}", + XOverlappingTimestampsFixed = "{0} overlapping timestamps fixed", + XDisplayTimesProlonged = "{0} display times prolonged", + XInvalidHtmlTagsFixed = "{0} invalid html tags fixed", + XDisplayTimesShortned = "{0} display times shortened", + XLinesUnbreaked = "{0} lines unbreaked", + UnneededSpace = "Unneeded space", + XUnneededSpacesRemoved = "{0} unneeded spaces removed", + UnneededPeriod = "Unneeded period", + XUnneededPeriodsRemoved = "{0} unneeded periods removed", + FixMissingSpace = "Fix missing space", + XMissingSpacesAdded = "{0} missing spaces added", + FixUppercaseIInsideLowercaseWord = "Fix uppercase 'i' inside lowercase word", + XPeriodsAdded = "{0} periods added.", + FixMissingPeriodAtEndOfLine = "Add missing period at end of line", + XDoubleApostrophesFixed = "{0} double apostrophes fixed.", + XUppercaseIsFoundInsideLowercaseWords = "{0} uppercase 'i's found inside lowercase words", + ApplyFixes = "Apply selected fixes", + RefreshFixes ="Refresh available fixes", + FixDoubleDash = "Fix '--' -> '...' ", + FixDoubleGreaterThan = "Remove >> ", + FixEllipsesStart = "Remove leading '...'", + FixMissingOpenBracket = "Fix missing [ in line", + FixMusicNotation = "Replace music symbols (e.g. âTª) with prefered symbol", + FixDoubleDashs = "Fix '--'s -> '...'s ", + FixDoubleGreaterThans = "Remove >> from start", + FixEllipsesStarts = "Remove ... from start", + FixMissingOpenBrackets = "Fix missing ['s ", + FixMusicNotations = "Replace âTª's with *'s", + FixDoubleDashExample = "'Whoa-- um yeah!' --> 'Whoa... um yeah!'", + FixDoubleGreaterThanExample = "'>> Robert: Sup dude!' --> 'Robert: Sup dude!'", + FixEllipsesStartExample = "'... and then we' -> 'and then we'", + FixMissingOpenBracketExample = "'clanks] Look out!' --> '[clanks] Look out!'", + FixMusicNotationExample = "'âTª sweet dreams are' --> '♫ sweet dreams are'", + XFixDoubleDash = "{0} fixed '--' ", + XFixDoubleGreaterThan = "{0} removed >> ", + XFixEllipsesStart = "{0} remove starting '...'", + XFixMissingOpenBracket = "{0} fixed missing [ in line", + XFixMusicNotation = "{0} fix music notation in line", + AutoBreak = "Auto &br", + Unbreak = "&Unbreak", + FixCommonOcrErrors = "Fix common OCR errors (using OCR replace list)", + NumberOfImportantLogMessages = "{0} important log messages!", + }; + + GetDictionaries = new LanguageStructure.GetDictionaries + { + Title = "Need dictionaries?", + DescriptionLine1 = "Subtitle Edit's spell check is based on the NHunspell engine which", + DescriptionLine2 = "uses the spell checking dictionaries from Open Office.", + GetDictionariesHere = "Get dictionaries here:", + OpenOpenOfficeWiki = "Open Office Wiki Dictionaries list", + GetAllDictionaries = "Get all dictionaries", + OpenDictionariesFolder = "Open 'Dictionaries' folder", + Download = "Download", + ChooseLanguageAndClickDownload = "Choose your language and click download", + XDownloaded = "{0} has been downloaded and installed", + }; + + GoogleTranslate = new LanguageStructure.GoogleTranslate + { + Title = "Google translate", + From = "From:", + To = "To:", + Translate = "Translate", + PleaseWait = "Please wait... this may take a while", + PoweredByGoogleTranslate = "Powered by Google translate", + PoweredByMicrosoftTranslate = "Powered by Microsoft translate", + }; + + GoToLine = new LanguageStructure.GoToLine + { + Title = "Go to subtitle number", + XIsNotAValidNumber = "{0} is not a valid number", + }; + + ImportText = new LanguageStructure.ImportText + { + Title = "Import plain text", + OpenTextFile = "Open text file...", + ImportOptions = "Import options", + Splitting = "Splitting", + AutoSplitText = "Auto split text", + OneLineIsOneSubtitle = "One line is one subtitle", + MergeShortLines = "Merge short lines with continuation", + RemoveEmptyLines = "Remove empty lines", + RemoveLinesWithoutLetters = "Remove lines without letters", + GapBetweenSubtitles = "Gap between subtitles (milliseconds)", + Auto = "Auto", + Fixed = "Fixed", + Refresh = "&Refresh", + Next = "&Next >>", + TextFiles = "Text files", + PreviewLinesModifiedX = "Preview - paragraphs modified: {0}", + }; + + Main = new LanguageStructure.Main + { + SaveChangesToUntitled = "Save changes to untitled?", + SaveChangesToX = "Save changes to {0}?", + SaveSubtitleAs = "Save subtitle as...", + NoSubtitleLoaded = "No subtitle loaded", + VisualSyncSelectedLines = "Visual sync - selected lines", + VisualSyncTitle = "Visual sync", + BeforeVisualSync = "Before visual sync", + VisualSyncPerformedOnSelectedLines = "Visual sync performed on selected lines", + VisualSyncPerformed = "Visual sync performed", + ImportThisVobSubSubtitle = "Import this VobSub subtitle?", + FileXIsLargerThan10Mb = "File is larger than 10 MB: {0}", + ContinueAnyway = "Continue anyway?", + BeforeLoadOf = "Before load of {0}", + LoadedSubtitleX = "Loaded subtitle {0}", + LoadedEmptyOrShort = "Loaded empty or very short subtitle {0}", + FileIsEmptyOrShort = "File is empty or very short!", + FileNotFound = "File not found: {0}", + SavedSubtitleX = "Saved subtitle {0}", + FileOnDiskModified = "file on disk modified", + OverwriteModifiedFile = "Overwrite the file {0} modified at {1} {2}{3} with current file loaded from disk at {4} {5}?", + UnableToSaveSubtitleX = "Unable to save subtitle file {0}", + BeforeNew = "Before new", + New = "New", + BeforeConvertingToX = "Before converting to {0}", + ConvertedToX = "Converted to {0}", + BeforeShowEarlier = "Before show earlier", + BeforeShowLater = "Before show later", + LineNumberX = "Line number: {0:#,##0.##}", + OpenVideoFile = "Open video file...", + NewFrameRateUsedToCalculateTimeCodes = "New frame rate ({0}) was used for calculating start/end time codes", + NewFrameRateUsedToCalculateFrameNumbers = "New frame rate ({0}) was used for calculating start/end frame numbers", + FindContinueTitle = "Continue Find?", + FindContinue = "The search item was not found." + Environment.NewLine + + "Would you like to start from the top of the document and search one more time?", + XFoundAtLineNumberY = "'{0}' found at line number {1}", + XNotFound = "'{0}' not found", + BeforeReplace = "Before replace: {0}", + MatchFoundX = "Match found: {0}", + NoMatchFoundX = "No match found: {0}", + FoundNothingToReplace = "Found nothing found to replace", + ReplaceCountX = "Replace count: {0}", + NoXFoundAtLineY = "Match found at line {0}: {1}", + OneReplacementMade = "One replacement made.", + BeforeChangesMadeInSourceView = "Before changes made in source view", + UnableToParseSourceView = "Unable to parse source view text!", + GoToLineNumberX = "Go to line number {0}", + CreateAdjustChangesApplied = "Create/adjust lines changes applied", + SelectedLines = "selected lines", + BeforeDisplayTimeAdjustment = "Before display time adjustment", + DisplayTimeAdjustedX = "Display times adjusted: {0}", + BeforeCommonErrorFixes = "Before common error fixes", + CommonErrorsFixedInSelectedLines = "Common errors fixed in selected lines", + CommonErrorsFixed = "Common errors fixed", + BeforeRenumbering = "Before renumbering", + RenumberedStartingFromX = "Renumbered starting from: {0}", + BeforeRemovalOfTextingForHearingImpaired = "Before removal of texting for hearing impaired", + TextingForHearingImpairedRemovedOneLine = "Texting for hearing impaired removed : One line", + TextingForHearingImpairedRemovedXLines = "Texting for hearing impaired removed : {0} lines", + SubtitleSplitted = "Subtitle splitted", + SubtitleAppendPrompt = "This will append an existing subtitle to the currently loaded subtitle which should" + Environment.NewLine + + "already be in sync with video file." + Environment.NewLine + + Environment.NewLine + + "Continue?", + SubtitleAppendPromptTitle = "Append subtitle", + OpenSubtitleToAppend = "Open subtitle to append...", + AppendViaVisualSyncTitle = "Visual sync - append second part of subtitle", + AppendSynchronizedSubtitlePrompt = "Append this synchronized subtitle?", + BeforeAppend = "Before append", + SubtitleAppendedX = "Subtitle appended: {0}", + SubtitleNotAppended = "Subtitle NOT appended!", + GoogleTranslate = "Google translate", + MicrosoftTranslate = "Microsoft translate", + BeforeGoogleTranslation = "Before Google translation", + SelectedLinesTranslated = "Selected lines translated", + SubtitleTranslated = "Subtitle translated", + TranslateSwedishToDanish = "Translate currently loaded Swedish subtitle to danish", + TranslateSwedishToDanishWarning = "Translate currently loaded SWEDISH (are you sure it's swedish?) subtitle to Danish?", + TranslatingViaNikseDkMt = "Translating via www.nikse.dk/mt...", + BeforeSwedishToDanishTranslation = "Before Swedish to Danish translation", + TranslationFromSwedishToDanishComplete = "Translation from Swedish to Danish complete", + TranslationFromSwedishToDanishFailed = "Translation from Swedish to Danish failed", + BeforeUndo = "Before undo", + UndoPerformed = "Undo performed", + NothingToUndo = "Nothing to undo", + InvalidLanguageNameX = "Invalid language name: {0}", + UnableToChangeLanguage = "Unable to change language!", + NumberOfCorrectedWords = "Number of corrected words: {0}", + NumberOfSkippedWords = "Number of skipped words: {0}", + NumberOfCorrectWords = "Number of correct words: {0}", + NumberOfWordsAddedToDictionary = "Number of words added to dictionary: {0}", + NumberOfNameHits = "Number of name hits: {0}", + SpellCheck = "Spell check", + BeforeSpellCheck = "Before spell check", + SpellCheckChangedXToY = "Spell check: Changed '{0}' to '{1}'", + BeforeAddingTagX = "Before adding <{0}> tag", + TagXAdded = "<{0}> tags added", + LineXOfY = "line {0} of {1}", + XLinesDeleted = "{0} lines deleted", + BeforeDeletingXLines = "Before deleting {0} lines", + DeleteXLinesPrompt = "Delete {0} lines?", + OneLineDeleted = "Line deleted", + BeforeDeletingOneLine = "Before deleting one line", + DeleteOneLinePrompt = "Delete one line?", + BeforeInsertLine = "Before insert line", + BeforeLineUpdatedInListView = "Before line updated in listview", + LineInserted = "Line inserted", + BeforeSettingFontToNormal = "Before setting font to normal", + BeforeSplitLine = "Before split line", + LineSplitted = "Line splitted", + BeforeMergeLines = "Before merge lines", + LinesMerged = "Lines merged", + BeforeSettingColor = "Before setting color", + BeforeSettingFontName = "Before setting font name", + BeforeTypeWriterEffect = "Before typewriter effect", + BeforeKaraokeEffect = "Before karaoke effect", + BeforeImportingDvdSubtitle = "Before importing subtitle from dvd", + OpenMatroskaFile = "Open Matroska file...", + MatroskaFiles = "Matroska files", + NoSubtitlesFound = "No subtitles found", + NotAValidMatroskaFileX = "This is not a valid matroska file: {0}", + ParsingMatroskaFile = "Parsing Matroska file. Please wait...", + BeforeImportFromMatroskaFile = "Before import subtitle from Matroska file", + SubtitleImportedFromMatroskaFile = "Subtitle imported from Matroska file", + DropFileXNotAccepted = "Drop file '{0}' not accepted - file is too large", + DropOnlyOneFile = "You can only drop one file", + BeforeCreateAdjustLines = "Before create/adjust lines", + OpenAnsiSubtitle = "Open subtitle...", + BeforeChangeCasing = "Before change casing", + CasingCompleteMessage = "Number of lines with casing changed: {0}/{1}, changed casing for names: {2}", + CasingCompleteMessageNoNames = "Number of lines with casing changed: {0}/{1}", + CasingCompleteMessageOnlyNames = "Number of lines with names casing changed: {0}/{1}", + BeforeChangeFrameRate = "Before change frame rate", + FrameRateChangedFromXToY = "Frame rate changed from {0} to {1}", + IdxFileNotFoundWarning = "{0} not found! Import VobSub file anyway?", + InvalidVobSubHeader = "Header not valid VobSub file: {0}", + OpenVobSubFile = "Open VobSub (sub/idx) subtitle...", + VobSubFiles = "VobSub subtitle files", + BeforeImportingVobSubFile = "Before importing VobSub subtitle", + BeforeShowSelectedLinesEarlierLater = "Before show selected lines earlier/later", + ShowSelectedLinesEarlierLaterPerformed = "Show earlier/later performed on selected lines", + DoubleWordsViaRegEx = "Double words via regex {0}", + BeforeSortX = "Before sort: {0}", + SortedByX = "Sorted by: {0}", + BeforeAutoBalanceSelectedLines = "Before auto balance selected lines", + NumberOfLinesAutoBalancedX = "Number of lines auto balanced: {0}", + BeforeRemoveLineBreaksInSelectedLines = "Before remove line-breaks from selected lines", + NumberOfWithRemovedLineBreakX = "Number of lines with removed line-break: {0}", + BeforeMultipleReplace = "Before multiple replace", + NumberOfLinesReplacedX = "Number of lines with text replaced: {0}", + NameXAddedToNamesEtcList = "The name '{0}' was added to names/etc list", + NameXNotAddedToNamesEtcList = "The name '{0}' was NOT added to names/etc list", + XLinesSelected = "{0} lines selected", + UnicodeMusicSymbolsAnsiWarning = "Subtitle contains unicode music notes. Saving using ANSI file encoding will lose these. Continue with saving?", + NegativeTimeWarning = "Subtitle contains negative time codes. Continue with saving?", + BeforeMergeShortLines = "Before merge short lines", + MergedShortLinesX = "Number of lines merged: {0}", + BeforeSetMinimumDisplayTimeBetweenParagraphs = "Before set minimum display time between paragraphs", + XMinimumDisplayTimeBetweenParagraphsChanged = "Number of lines with minimum display time between paragraphs changed: {0}", + BeforeImportText = "Before import plain text", + TextImported = "Text imported", + BeforePointSynchronization = "Before point synchronization", + PointSynchronizationDone = "Point synchronization done", + BeforeTimeCodeImport = "Before import of time codes", + TimeCodeImportedFromXY = "Time codes imported from {0}: {1}", + BeforeInsertSubtitleAtVideoPosition = "Before insert subtitle at video position", + BeforeSetStartTimeAndOffsetTheRest = "Before set start time and offset the rest", + ContinueWithCurrentSpellCheck = "Continue with current spell check?", + + Menu = new LanguageStructure.Main.MainMenu + { + File = new LanguageStructure.Main.MainMenu.FileMenu + { + Title = "&File", + New = "&New", + Open = "&Open", + Reopen = "&Reopen", + Save = "&Save", + SaveAs = "Save &as...", + OpenContainingFolder = "Open containing folder", + Compare = "&Compare...", + ImportOcrFromDvd = "Import/OCR subtitle from vob/ifo (dvd) ...", + ImportOcrVobSubSubtitle = "Import/OCR VobSub (sub/idx) subtitle...", + ImportSubtitleFromMatroskaFile = "Import subtitle from Matroska file...", + ImportSubtitleWithManualChosenEncoding = "Import subtitle with manual chosen encoding...", + ImportText = "Import plain text...", + ImportTimecodes = "Import time codes...", + Exit = "E&xit" + }, + + Edit = new LanguageStructure.Main.MainMenu.EditMenu + { + Title = "Edit", + ShowUndoHistory = "Show history (for undo)", + ShowOriginalText = "Show original text (translator mode)", + HideOriginalText = "Hide original text", + InsertUnicodeSymbol = "Insert unicode symbol", + Find = "&Find", + FindNext = "Find &next", + Replace = "&Replace", + MultipleReplace = "&Multiple replace...", + GoToSubtitleNumber = "&Go to subtitle number...", + }, + + Tools = new LanguageStructure.Main.MainMenu.ToolsMenu + { + Title = "Tools", + AdjustDisplayDuration = "&Adjust durations...", + FixCommonErrors = "&Fix common errors...", + StartNumberingFrom = "Start numbering from...", + RemoveTextForHearingImpaired = "Remove text for hearing impaired...", + ChangeCasing = "Change casing...", + ChangeFrameRate = "Change frame rate...", + MergeShortLines = "Merge short lines...", + MinimumDisplayTimeBetweenParagraphs = "Minimum display time between paragraphs...", + SortBy = "Sort by", + TextAlphabetically = "Text - alphabetically", + TextSingleLineMaximumLength = "Text - single line max. length", + TextTotalLength = "Text - total length", + TextNumberOfLines = "Text - number of lines", + SplitSubtitle = "Split subtitle...", + AppendSubtitle = "Append subtitle...", + }, + + Video = new LanguageStructure.Main.MainMenu.VideoMenu + { + Title = "Video", + OpenVideo = "Open video file...", + ShowHideVideo = "Show/hide video", + ShowHideWaveForm = "Show/hide wave form", + }, + + SpellCheck = new LanguageStructure.Main.MainMenu.SpellCheckMenu + { + Title = "Spell check", + FindDoubleWords = "Find double words", + SpellCheck = "&Spell check...", + GetDictionaries = "Get dictionaries...", + AddToNamesEtcList = "Add word to names/ect list", + }, + + Synchronization = new LanguageStructure.Main.MainMenu.SynchronizationkMenu + { + Title = "Synchronization", + AdjustAllTimes = "Adjust all times (show earlier/later)...", + VisualSync = "&Visual sync...", + PointSync = "Point sync...", + }, + + AutoTranslate = new LanguageStructure.Main.MainMenu.AutoTranslateMenu + { + Title = "Auto-translate", + TranslatePoweredByGoogle = "Translate (powered by Google)...", + TranslatePoweredByMicrosoft = "Translate (powered by Microsoft)...", + TranslateFromSwedishToDanish = "Translate from Swedish to Danish (powered by nikse.dk)...", + }, + + Options = new LanguageStructure.Main.MainMenu.OptionsMenu + { + Title = "Options", + Settings = "&Settings...", + ChooseLanguage = "&Choose language...", + }, + + Help = new LanguageStructure.Main.MainMenu.HelpMenu + { + Title = "Help", + Help = "&Help", + About = "&About" + }, + + ToolBar = new LanguageStructure.Main.MainMenu.ToolBarMenu + { + New = "New", + Open = "Open", + Save = "Save", + SaveAs = "Save as", + Find = "Find", + Replace = "Replace", + VisualSync = "Visual sync", + SpellCheck = "Spell check", + Settings = "Settings", + Help = "Help", + ShowHideWaveForm = "Show/hide wave form", + ShowHideVideo = "Show/hide video", + }, + + ContextMenu = new LanguageStructure.Main.MainMenu.ListViewContextMenu + { + Delete = "Delete", + InsertBefore = "Insert before", + InsertAfter = "Insert after", + Split = "Split", + MergeSelectedLines = "Merge selected lines", + MergeWithLineBefore = "Merge with line before", + MergeWithLineAfter = "Merge with line after", + Normal = "Normal", + Underline = "Underline", + Color = "Color...", + FontName = "Font name...", + AutoBalanceSelectedLines = "Auto balance selected lines...", + RemoveLineBreaksFromSelectedLines = "Remove line-breaks from selected lines...", + TypewriterEffect = "Typewriter effect...", + KaraokeEffect = "Karaoke effect...", + ShowSelectedLinesEarlierLater = "Show selected lines earlier/later...", + VisualSyncSelectedLines = "Visual sync selected lines...", + GoogleTranslateSelectedLines = "Google translate selected lines...", + AdjustDisplayDurationForSelectedLines = "Adjust durations for selected lines...", + FixCommonErrorsInSelectedLines = "Fix common errors in selected lines...", + ChangeCasingForSelectedLines = "Change casing for selected lines...", + } + }, + + Controls = new LanguageStructure.Main.MainControls + { + SubtitleFormat = "Format", + FileEncoding = "Encoding", + ListView = "List view", + SourceView = "Source view", + UndoChangesInEditPanel = "Undo changes in edit panel", + Previous = "< Prev", + Next = "Next >", + AutoBreak = "Auto br", + Unbreak = "Unbreak" + }, + + VideoControls = new LanguageStructure.Main.MainVideoControls + { + Translate = "Translate", + Create = "Create", + Adjust = "Adjust", + SelectCurrentElementWhilePlaying = "Select current subtitle while playing", + + AutoRepeat = "Auto repeat", + AutoRepeatOn = "Auto repeat on", + AutoRepeatCount = "Repeat count (times)", + AutoContinue = "Auto continue", + AutoContinueOn = "Auto continue on", + DelayInSeconds = "Delay (seconds)", + Previous = "< Pre&vious", + Next = "&Next >", + PlayCurrent = "&Play current", + Stop = "&Stop", + Playing = "Playing...", + RepeatingLastTime = "Repeating... last time", + RepeatingXTimesLeft = "Repeating... {0} times left", + AutoContinueInOneSecond = "Auto continue in one second", + AutoContinueInXSeconds = "Auto continue in {0} seconds", + StillTypingAutoContinueStopped = "Still typing... auto continue stopped", + + InsertNewSubtitleAtVideoPosition = "&Insert new subtitle at video pos", + Auto = "Auto", + PlayFromJustBeforeText = "Play from just before &text", + Pause = "Pause", + GoToSubtitlePositionAndPause = "Go to subposition and pause", + SetStartTime = "Set &start time", + SetEndTimeAndGoToNext = "Set &end && goto next", + SetEndTime = "Set e&nd time", + SetstartTimeAndOffsetOfRest = "Set sta&rt and offset the rest", + + GoogleIt = "Google it", + GoogleTranslate = "Google translate", + OriginalText = "Original text", + SearchTextOnline = "Search text online", + SecondsBackShort = "<< secs", + SecondsForwardShort = "secs >>", + VideoPosition = "Video position:", + TranslateTip = "Tip: Use to go to previous/next subtitle", + CreateTip = "Tip: Use keys", + AdjustTip = "Tip: Use to go to previous/next subtitle", + + BeforeChangingTimeInWaveFormX = "Before changing time in wave form: {0}", + NewTextInsertAtX = "New text inserted at {0}", + }, + }; + + MatroskaSubtitleChooser = new LanguageStructure.MatroskaSubtitleChooser + { + Title = "Choose subtitle from Matroska file", + PleaseChoose = "More than one subtitle found - please choose", + TrackXLanguageYTypeZ = "Track {0} - {1} - language: {2} - type: {3}", + }; + + MergedShortLines = new LanguageStructure.MergeShortLines + { + Title = "Merge short lines", + MaximumCharacters = "Maximum characters in one paragraph", + MaximumMillisecondsBetween = "Maximum milliseconds between lines", + NumberOfMergesX = "Number of merges: {0}", + LineNumber = "Line#", + MergedText = "Merged text", + }; + + MultipleReplace = new LanguageStructure.MultipleReplace + { + Title = "Multiple replace", + FindWhat = "Find what", + ReplaceWith = "Replace with", + Normal = "Normal", + CaseSensitive = "Case sensitive", + RegularExpression = "Regular expression", + LineNumber = "Line#", + Before = "Before", + After = "After", + LinesFoundX = "Lines found: {0}", + Delete = "Delete", + Add = "Add", + Update = "&Update", + Enabled = "Enabled", + SearchType = "Search type", + }; + + RemoveTextFromHearImpaired = new LanguageStructure.RemoveTextFromHearImpaired + { + Title = "Remove text for hearing impaired", + RemoveTextConditions = "Remove text conditions", + RemoveTextBetween = "Remove text conditions", + SquareBrackets = "'[' and ']'", + Brackets = "'{' and '}'", + QuestionMarks = "'?' and '?'", + Parentheses = "'(' and ')'", + And = "and", + RemoveTextBeforeColon = "Remove text before a colon (':')", + OnlyIfTextIsUppercase = "Only if text is UPPERCASE", + OnlyIfInSeparateLine = "Only if in separate line", + LineNumber = "Line#", + Before = "Before", + After = "After", + LinesFoundX = "Lines found: {0}", + RemoveTextIfContains = "Remove text if it contains:", + }; + + ReplaceDialog = new LanguageStructure.ReplaceDialog + { + Title = "Replace", + FindWhat = "Find what:", + Normal = "Normal", + CaseSensitive = "Case sensitive", + RegularExpression = "Regular expression", + ReplaceWith = "Replace with", + Find = "&Find", + Replace = "&Replace", + ReplaceAll = "Replace &all", + }; + + SetMinimumDisplayTimeBetweenParagraphs = new LanguageStructure.SetMinimumDisplayTimeBetweenParagraphs + { + Title = "Set minimum display time between paragraphs", + PreviewLinesModifiedX = "Preview - paragraphs modified: {0}", + MinimumMillisecondsBetweenParagraphs = "Minimum milliseconds between lines", + ShowOnlyModifiedLines = "Show only modified lines", + }; + + SetSyncPoint = new LanguageStructure.SetSyncPoint + { + Title = "Set Sync point for line {0}", + SyncPointTimeCode = "Sync point time code", + ThreeSecondsBack = "<< 3 secs", + HalfASecondBack = "<< ½ sec", + HalfASecondForward = "½ sec >>", + ThreeSecondsForward = "3 secs >>", + }; + + Settings = new LanguageStructure.Settings + { + Title = "Settings", + General = "General", + VideoPlayer = "Video player", + WaveForm = "Wave form", + Tools = "Tools", + WordLists = "Word lists", + SsaStyle = "SSA Style", + Proxy = "Proxy", + ShowToolBarButtons = "Show tool bar buttons", + New = "New", + Open = "Open", + Save = "Save", + SaveAs = "Save as", + Find = "Find", + Replace = "Replace", + VisualSync = "Visual sync", + SpellCheck = "Spell check", + SettingsName = "Settings", + Help = "Help", + Miscellaneous = "Miscellaneous", + ShowFrameRate = "Show frame rate in toolbar", + DefaultFrameRate = "Default frame rate", + DefaultFileEncoding = "Default file encoding", + AutoDetectAnsiEncoding = "Auto detect ANSI encoding", + SubtitleLineMaximumLength = "Subtitle max. length", + SubtitleFont = "Subtitle font", + SubtitleFontSize = "Subtitle font size", + RememberRecentFiles = "Remember recent files (for reopen)", + StartWithLastFileLoaded = "Start with last file loaded", + RememberPositionAndSize = "Remember main window position and size", + StartInSourceView = "Start in source view", + RemoveBlankLinesWhenOpening = "Remove blank lines when opening a subtitle", + ShowLineBreaksAs = "Show line breaks in list view as", + MainListViewDoubleClickAction = "Double-click on line in main window listview will", + MainListViewNothing = "Nothing", + MainListViewVideoGoToPositionAndPause= "Go to video pos and pause", + MainListViewVideoGoToPositionAndPlay = "Go to video pos and play", + MainListViewEditText = "Go to edit text box", + VideoEngine = "Video engine", + DirectShow = "DirectShow", + DirectShowDescription = "quartz.dll in system32 folder", + ManagedDirectX = "Managed DirectX", + ManagedDirectXDescription = "Microsoft.DirectX.AudioVideoPlayback - .NET Managed code from DirectX", + WindowsMediaPlayer = "Windows Media Player", + WindowsMediaPlayerDescription = "WMP ActiveX control", + VlcMediaPlayer = "VLC Media Player", + VlcMediaPlayerDescription = "libvlc.dll from VLC Media Player 1.1.0 or newer", + ShowStopButton = "Show stop button", + DefaultVolume = "Default volume", + VolumeNotes = "0 is no sound, 100 is higest volume", + MainWindowVideoControls = "Main window video controls", + CustomSearchTextAndUrl = "Custom search text and url", + WaveFormAppearance = "Wave form appearance", + WaveFormGridColor = "Grid color", + WaveFormShowGridLines = "Show grid lines", + WaveFormColor = "Color", + WaveFormSelectedColor = "Selected color", + WaveFormBackgroundColor = "Back color", + WaveFormTextColor = "Text color", + WaveFormsFolderEmpty = "Empty 'WaveForms' folder", + WaveFormsFolderInfo = "'WaveForms' folder contains {0} files ({1:0.00} MB)", + SubStationAlphaStyle = "Sub Station Alpha style", + ChooseFont = "Choose font", + ChooseColor = "Choose color", + Example = "Example", + Testing123 = "Testing 123...", + Language = "Language", + NamesIgnoreLists = "Names/ignore list (case sensitive)", + AddNameEtc = "Add name", + AddWord = "Add word", + Remove = "Remove", + AddPair = "Add pair", + UserWordList = "User word list", + OcrFixList = "OCR fix list", + Location = "Location", + UseOnlineNamesEtc = "Use online names etc xml file", + WordAddedX = "Word added: {0}", + WordAlreadyExists = "Word already exists!", + RemoveX = "Remove {0}?", + WordNotFound = "Word not found", + CannotUpdateNamesEtcOnline = "Cannot update NamesEtc.xml online!", + ProxyServerSettings = "Proxy server settings", + ProxyAddress = "Proxy address", + ProxyAuthentication = "Authentication", + ProxyUserName = "User name", + ProxyPassword = "Password", + ProxyDomain = "Domain", + PlayXSecondsAndBack = "Play X seconds and back, X is", + StartSceneIndex = "Start scene paragraph is", + EndSceneIndex = "End scene paragraph is", + FirstPlusX = "First + {0}", + LastMinusX = "Last - {0}", + FixCommonerrors = "Fix common errors", + MergeLinesShorterThan = "Merge lines shorter than", + MusicSymbol = "Music symbol", + MusicSymbolsToReplace = "Music symbols to replace (separate by space)", + }; + + ShowEarlierLater = new LanguageStructure.ShowEarlierLater + { + Title = "Show selected lines earlier/later", + ShowEarlier = "Show earlier", + ShowLater = "Show later", + TotalAdjustmentX = "Total adjustment: {0}", + }; + + ShowHistory = new LanguageStructure.ShowHistory + { + Title = "History (for undo)", + SelectRollbackPoint = "Select time/description for rollback", + Time = "Time", + Description = "Description", + CompareHistoryItems = "Compare history items", + CompareWithCurrent = "Compare with current", + Rollback = "Rollback", + }; + + SpellCheck = new LanguageStructure.SpellCheck + { + Title = "Spell check", + FullText = "Full text", + WordNotFound = "Word not found", + Language = "Language", + Change = "Change", + ChangeAll = "Change all", + SkipOnce = "Skip &one", + SkipAll = "&Skip all", + AddToUserDictionary = "Add to user dictionary", + AddToNamesAndIgnoreList = "Add to names/noise list (case sensitive)", + Abort = "Abort", + Use = "Use", + UseAlways = "&Use always", + Suggestions = "Suggestions", + SpellCheckProgress = "Spell check [{0}] - {1}", + EditWholeText = "Edit whole text", + EditWordOnly = "Edit word only", + AddXToNamesEtc = "Add '{0}' to names/etc list", + AutoFixNames = "Auto fix names where only casing differ", + ImageText = "Image text", + SpellCheckCompleted ="Spell check completed.", + SpellCheckAborted = "Spell check aborted", + }; + + SplitSubtitle = new LanguageStructure.SplitSubtitle + { + Title = "Split subtitle", + Description1 = "Enter length of first part of video or browse", + Description2 = "and get length from video file:", + Part1 = "Part1", + Part2 = "Part2", + Done = "&Done", + Split = "&Split", + SavePartOneAs = "Save part 1 as...", + SavePartTwoAs = "Save part 2 as...", + NothingToSplit = "Nothing to split!", + UnableToSaveFileX = "Unable to save {0}", + }; + + StartNumberingFrom = new LanguageStructure.StartNumberingFrom + { + Title = "Start numbering from...", + StartFromNumber = "Start from number:", + PleaseEnterAValidNumber = "Ups, please enter a number", + }; + + PointSync = new LanguageStructure.PointSync + { + Title = "Point synchronization", + SyncHelp = "Set at least two sync points to make rough synchronization", + SetSyncPoint = "Set sync point", + RemoveSyncPoint = "Remove sync point", + SyncPointsX = "Sync points: {0}", + Description = "Point synchronization requires at least 2 synchronization points", + }; + + UnknownSubtitle = new LanguageStructure.UnknownSubtitle + { + Title = "Unknown subtitle type", + Message = "If you want this fixed please send an email to mailto:niksedk@gmail.com and include a copy of the subtitle.", + }; + + VisualSync = new LanguageStructure.VisualSync + { + Title = "Visual sync", + StartScene = "Start scene", + EndScene = "End scene", + Synchronize = "Sync", + HalfASecondBack = "< ½ sec", + ThreeSecondsBack = "< 3 secs", + PlayXSecondsAndBack = "Play {0} secs and back", + FindText = "Find text", + GoToSubPosition = "Go to sub pos", + KeepChangesTitle = "Keep changes?", + KeepChangesMessage = "Changes have been made to subtitle in 'Visual sync'.", + SynchronizationDone = "Sync done!", + StartSceneMustComeBeforeEndScene = "Start scene must come before end scene!", + Tip = "Tip: Use keys to move 100 ms back/forward", + }; + + VobSubEditCharacters = new LanguageStructure.VobSubEditCharacters + { + Title = "Edit image compare database", + ChooseCharacter = "Choose character(s)", + ImageCompareFiles = "Image compare files", + CurrentCompareImage = "Current compare image", + TextAssociatedWithImage = "Text associated with image", + IsItalic = "Is &italic", + Update = "&Update", + Delete = "&Delete", + ImageDoubleSize = "Image double size", + ImageFileNotFound = "Image file not found", + Image = "Image", + }; + + VobSubOcr = new LanguageStructure.VobSubOcr + { + Title = "Import/OCR VobSub (sub/idx) subtitle", + OcrMethod = "OCR method", + OcrViaModi = "OCR via Microsoft Office Document Imaging (MODI). Requires MS Office", + Language = "Language", + OcrViaImageCompare = "OCR via image compare", + ImageDatabase = "Image database", + NoOfPixelsIsSpace = "No of pixels is space", + New = "New", + Edit = "Edit", + StartOcr = "Start OCR", + Stop = "Stop", + StartOcrFrom = "Start OCR from subtitle no:", + LoadingVobSubImages = "Loading VobSub images...", + SubtitleImage = "Subtitle image", + SubtitleText = "Subtitle text", + UnableToCreateCharacterDatabaseFolder = "Unable to create 'Character database folder': {0}", + SubtitleImageXofY = "Subtitle image {0} of {1}", + ImagePalette = "Image palette", + UseCustomColors = "Use custom colors", + Transparent = "Transparent", + PromptForUnknownWords = "Prompt for unknown words", + TryToGuessUnkownWords = "Try to guess unknown words", + AutoBreakSubtitleIfMoreThanTwoLines = "Auto break paragraph if more than two lines", + AllFixes = "All fixes", + GuessesUsed = "Guesses used", + UnknownWords = "Unknown words", + OcrAutoCorrectionSpellchecking = "OCR auto correction / spellchecking", + OcrViaTesseract = "OCR via Tesseract", + FixOcrErrors = "Fix OCR errors", + SaveSubtitleImageAs = "Save subtitle image as...", + TryModiForUnknownWords = "Try MS MODI OCR for unknown words", + DictionaryX = "Dictionary: {0}", + RightToLeft = "Right to left", + ShowOnlyForcedSubtitles = "Show only forced subtitles", + UseTimeCodesFromIdx = "Use time codes from .idx file", + }; + + VobSubOcrCharacter = new LanguageStructure.VobSubOcrCharacter + { + Title = "VobSub - Manual image to text", + Abort = "&Abort", + SubtitleImage = "Subtitle image", + ShrinkSelection = "Shrink selection", + ExpandSelection = "Expand selection", + Characters = "Character(s)", + CharactersAsText = "Character(s) as text", + Italic = "&Italic", + }; + + VobSubOcrNewFolder = new LanguageStructure.VobSubOcrNewFolder + { + Title = "New folder", + Message = "Name of new character database folder", + }; + + WaveForm = new LanguageStructure.WaveForm + { + ClickToAddWaveForm = "Click to add waveform", + Seconds = "seconds", + ZoomIn = "Zoom in", + ZoomOut = "Zoom out", + AddParagraphHere = "Add text here", + DeleteParagraph = "Delete text", + Split = "Split", + SplitAtCursor = "Split at cursor", + MergeWithPrevious = "Merge with previous", + MergeWithNext = "Merge with next", + PlaySelection = "Play selection", + }; + + } + + public static Language LoadAndDecompress(StreamReader sr) + { + using (var zip = new GZipStream(sr.BaseStream, CompressionMode.Decompress)) + { + var s = new XmlSerializer(typeof(Language)); + return (Language)s.Deserialize(zip); + } + } + + public void SaveAndCompress() + { + var s = new XmlSerializer(typeof(Language)); + var ms = new MemoryStream(); + s.Serialize(ms, this); + var b = new byte[ms.Length]; + ms.Position = 0; + ms.Read(b, 0, (int)ms.Length); + + using (var f2 = new FileStream(Configuration.BaseDirectory + "Language.xml.zip", FileMode.Create)) + using (var gz = new GZipStream(f2, CompressionMode.Compress, false)) + { + gz.Write(b, 0, b.Length); + } + } + + public static Language Load(StreamReader sr) + { + var s = new XmlSerializer(typeof(Language)); + var language = (Language)s.Deserialize(sr); + return language; + } + + public void Save() + { + var s = new XmlSerializer(typeof(Language)); + TextWriter w = new StreamWriter(Configuration.BaseDirectory + "Language.xml"); + s.Serialize(w, this); + w.Close(); + } + + public static void TranslateViaGoogle(string languagePair) + { + var doc = new XmlDocument(); + doc.Load(Configuration.BaseDirectory + "Language.xml"); + if (doc.DocumentElement != null) + foreach (XmlNode node in doc.DocumentElement.ChildNodes) + TranslateNode(node, languagePair); + + doc.Save(Configuration.BaseDirectory + "Language.xml"); + } + + private static void TranslateNode(XmlNode node, string languagePair) + { + if (node.ChildNodes.Count == 0) + { + string oldText = node.InnerText; + string newText = Forms.GoogleTranslate.TranslateTextViaApi(node.InnerText, languagePair); + if (!string.IsNullOrEmpty(oldText) && !string.IsNullOrEmpty(newText)) + { + if (oldText.Contains("{0:")) + { + newText = oldText; + } + else + { + if (!oldText.Contains(" / ")) + newText = newText.Replace(" / ", "/"); + + if (!oldText.Contains(" ...")) + newText = newText.Replace(" ...", "..."); + + if (!oldText.Contains("& ")) + newText = newText.Replace("& ", "&"); + + if (!oldText.Contains("# ")) + newText = newText.Replace("# ", "#"); + + if (!oldText.Contains("@ ")) + newText = newText.Replace("@ ", "@"); + + if (oldText.Contains("{0}")) + { + newText = newText.Replace("(0)", "{0}"); + newText = newText.Replace("(1)", "{1}"); + newText = newText.Replace("(2)", "{2}"); + newText = newText.Replace("(3)", "{3}"); + newText = newText.Replace("(4)", "{4}"); + newText = newText.Replace("(5)", "{5}"); + newText = newText.Replace("(6)", "{6}"); + newText = newText.Replace("(7)", "{7}"); + } + } + } + node.InnerText = newText; + } + else + { + foreach (XmlNode childNode in node.ChildNodes) + TranslateNode(childNode, languagePair); + } + } + + internal void CompareWithEnglish() + { + var s = new XmlSerializer(typeof(Language)); + TextWriter w = new StreamWriter(Configuration.BaseDirectory + "English.xml"); + s.Serialize(w, new Language()); + w.Close(); + var english = new XmlDocument(); + english.Load(Configuration.BaseDirectory + "English.xml"); + + Save(); + var doc = new XmlDocument(); + doc.Load(Configuration.BaseDirectory + "Language.xml"); + + var sb = new StringBuilder(); + sb.AppendLine("The following tags are missing:"); + sb.AppendLine(); + if (english.DocumentElement != null) + foreach (XmlNode node in english.DocumentElement.ChildNodes) + CompareNode(node, english.DocumentElement.Name + "/" + node.Name, doc, sb); + + System.Windows.Forms.MessageBox.Show(sb.ToString()); + } + + private static void CompareNode(XmlNode node, string name, XmlDocument localLanguage, StringBuilder sb) + { + if (name.EndsWith("/#text")) + name = name.Substring(0, name.Length - 6); + if (localLanguage.SelectSingleNode(name) == null) + { + sb.AppendLine(name + " not found!"); + } + else if (node.ChildNodes.Count > 0) + { + foreach (XmlNode childNode in node.ChildNodes) + CompareNode(childNode, name + "/" + childNode.Name, localLanguage, sb); + } + } + } +} + \ No newline at end of file diff --git a/src/Logic/LanguageStructure.cs b/src/Logic/LanguageStructure.cs new file mode 100644 index 000000000..85e025b26 --- /dev/null +++ b/src/Logic/LanguageStructure.cs @@ -0,0 +1,1160 @@ +namespace Nikse.SubtitleEdit.Logic +{ + // The language classes are build for easy xml-serilization (makes save/load code simple) + public class LanguageStructure + { + public class General + { + public string Title { get; set; } + public string Version { get; set; } + public string TranslatedBy { get; set; } + public string CultureName { get; set; } + public string HelpFile { get; set; } + public string OK { get; set; } + public string Cancel { get; set; } + public string Apply { get; set; } + public string None { get; set; } + public string Preview { get; set; } + public string SubtitleFiles { get; set; } + public string AllFiles { get; set; } + public string VideoFiles { get; set; } + public string OpenSubtitle { get; set; } + public string OpenVideoFile { get; set; } + public string NoVideoLoaded { get; set; } + public string VideoInformation { get; set; } + public string PositionX { get; set; } + public string StartTime { get; set; } + public string EndTime { get; set; } + public string Duration { get; set; } + public string Number { get; set; } + public string Text { get; set; } + public string HourMinutesSecondsMilliseconds { get; set; } + public string Bold { get; set; } + public string Italic { get; set; } + public string Visible { get; set; } + public string FrameRate { get; set; } + public string Name { get; set; } + public string FileNameXAndSize { get; set; } + public string ResolutionX { get; set; } + public string FrameRateX { get; set; } + public string TotalFramesX { get; set; } + public string VideoEncodingX { get; set; } + public string SingleLineLengths { get; set; } + public string TotalLengthX { get; set; } + public string TotalLengthXSplitLine { get; set; } + public string NotAvailable { get; set; } + public string OverlapPreviousLineX { get; set; } + public string OverlapX { get; set; } + public string OverlapNextX { get; set; } + public string Negative { get; set; } + public string RegularExpressionIsNotValid { get; set; } + public string SubtitleSaved { get; set; } + public string CurrentSubtitle { get; set; } + public string OriginalText { get; set; } + public string OpenOriginalSubtitleFile { get; set; } + public string PleaseWait { get; set; } + } + + public class About + { + public string Title { get; set; } + public string AboutText1 { get; set; } + } + + public class AddToNames + { + public string Title { get; set; } + public string Description { get; set; } + } + + public class AddWareForm + { + public string Title { get; set; } + public string SourceVideoFile { get; set; } + public string GenerateWaveFormData { get; set; } + public string PleaseWait{ get; set; } + public string VlcMediaPlayerNotFoundTitle { get; set; } + public string VlcMediaPlayerNotFound { get; set; } + public string GoToVlcMediaPlayerHomePage { get; set; } + public string GeneratingPeakFile { get; set; } + public string ExtractingSeconds { get; set; } + public string ExtractingMinutes { get; set; } + } + + public class AdjustDisplayDuration + { + public string Title { get; set; } + public string AdjustVia { get; set; } + public string Seconds { get; set; } + public string Percent { get; set; } + public string AddSeconds { get; set; } + public string SetAsPercent { get; set; } + public string Note { get; set; } + public string PleaseSelectAValueFromTheDropDownList { get; set; } + public string PleaseChoose { get; set; } + } + + public class AutoBreakUnbreakLines + { + public string TitleAutoBreak { get; set; } + public string TitleUnbreak { get; set; } + public string LineNumber { get; set; } + public string Before { get; set; } + public string After { get; set; } + public string LinesFoundX { get; set; } + public string OnlyBreakLinesLongerThan { get; set; } + public string OnlyUnbreakLinesShorterThan { get; set; } + } + + public class ChangeCasing + { + public string Title { get; set; } + public string ChangeCasingTo { get; set; } + public string NormalCasing { get; set; } + public string FixNamesCasing { get; set; } + public string FixOnlyNamesCasing { get; set; } + public string OnlyChangeAllUppercaseLines { get; set; } + public string AllUppercase { get; set; } + public string AllLowercase { get; set; } + } + + public class ChangeCasingNames + { + public string Title { get; set; } + public string NamesFoundInSubtitleX { get; set; } + public string Enabled { get; set; } + public string Name { get; set; } + public string LineNumber { get; set; } + public string Before { get; set; } + public string After { get; set; } + public string LinesFoundX { get; set; } + } + + public class ChangeFrameRate + { + public string Title { get; set; } + public string ConvertFrameRateOfSubtitle { get; set; } + public string FromFrameRate { get; set; } + public string ToFrameRate { get; set; } + } + + public class ChooseEncoding + { + public string Title { get; set; } + public string CodePage { get; set; } + public string DisplayName { get; set; } + public string PleaseSelectAnEncoding { get; set; } + } + + public class ChooseLanguage + { + public string Title { get; set; } + public string Language { get; set; } + } + + public class CompareSubtitles + { + public string Title { get; set; } + public string PreviousDifference { get; set; } + public string NextDifference { get; set; } + public string SubtitlesNotAlike { get; set; } + public string XNumberOfDifference { get; set; } + public string ShowOnlyDifferences { get; set; } + public string OnlyLookForDifferencesInText { get; set; } + } + + public class DvdSubRip + { + public string Title { get; set; } + public string DvdGroupTitle { get; set; } + public string IfoFile { get; set; } + public string IfoFiles { get; set; } + public string VobFiles { get; set; } + public string Add { get; set; } + public string Remove { get; set; } + public string Clear { get; set; } + public string MoveUp { get; set; } + public string MoveDown { get; set; } + public string Languages { get; set; } + public string PalNtsc { get; set; } + public string Pal { get; set; } + public string Ntsc { get; set; } + public string StartRipping { get; set; } + public string Abort { get; set; } + public string AbortedByUser { get; set; } + public string ReadingSubtitleData { get; set; } + public string RippingVobFileXofYZ { get; set; } + } + + public class DvdSubRipChooseLanguage + { + public string Title { get; set; } + public string ChooseLanguageStreamId { get; set; } + public string UnknownLanguage { get; set; } + public string SubtitleImageXofYAndWidthXHeight { get; set; } + } + + public class EffectKaraoke + { + public string Title { get; set; } + public string ChooseColor { get; set; } + public string TotalMilliseconds { get; set; } + public string EndDelayInMilliseconds { get; set; } + } + + public class EffectTypewriter + { + public string Title { get; set; } + public string TotalMilliseconds { get; set; } + public string EndDelayInMillisecs { get; set; } + } + + public class FindDialog + { + public string Title { get; set; } + public string Find { get; set; } + public string Normal { get; set; } + public string CaseSensitive { get; set; } + public string RegularExpression { get; set; } + } + + public class FindSubtitleLine + { + public string Title { get; set; } + public string Find { get; set; } + public string FindNext { get; set; } + } + + public class FixCommonErrors + { + public string Title { get; set; } + public string Step1 { get; set; } + public string WhatToFix { get; set; } + public string Example { get; set; } + public string SelectAll { get; set; } + public string InverseSelection { get; set; } + public string Back { get; set; } + public string Next { get; set; } + public string Step2 { get; set; } + public string Fixes { get; set; } + public string Log { get; set; } + public string LineNumber { get; set; } + public string Function { get; set; } + public string Before { get; set; } + public string After { get; set; } + public string RemovedEmptyLine { get; set; } + public string RemovedEmptyLineAtTop { get; set; } + public string RemovedEmptyLineAtBottom { get; set; } + public string RemovedEmptyLinesUnsedLineBreaks { get; set; } + public string EmptyLinesRemovedX { get; set; } + public string FixOverlappingDisplayTimes { get; set; } + public string FixShortDisplayTimes { get; set; } + public string FixLongDisplayTimes { get; set; } + public string FixInvalidItalicTags { get; set; } + public string RemoveUnneededSpaces { get; set; } + public string RemoveUnneededPeriods { get; set; } + public string FixMissingSpaces { get; set; } + public string BreakLongLines { get; set; } + public string RemoveLineBreaks { get; set; } + public string FixUppercaseIInsindeLowercaseWords { get; set; } + public string FixDoubleApostrophes { get; set; } + public string AddPeriods { get; set; } + public string StartWithUppercaseLetterAfterParagraph { get; set; } + public string StartWithUppercaseLetterAfterPeriodInsideParagraph { get; set; } + public string FixLowercaseIToUppercaseI { get; set; } + public string FixCommonOcrErrors { get; set; } + public string CommonOcrErrorsFixed { get; set; } + public string FixDanishLetterI { get; set; } + public string FixSpanishInvertedQuestionAndExclamationMarks { get; set; } + public string AddMissingQuote { get; set; } + public string AddMissingQuotes { get; set; } + public string FixHyphens { get; set; } + public string FixHyphen { get; set; } + public string XHyphensFixed { get; set; } + public string AddMissingQuotesExample { get; set; } + public string XMissingQuotesAdded { get; set; } + public string Fix3PlusLines { get; set; } + public string Fix3PlusLine { get; set; } + public string X3PlusLinesFixed { get; set; } + public string Analysing { get; set; } + public string NothingToFix { get; set; } + public string FixesFoundX { get; set; } + public string XFixesApplied { get; set; } + public string NothingToFixBut { get; set; } + public string FixLowercaseIToUppercaseICheckedButCurrentLanguageIsNotEnglish { get; set; } + public string Continue { get; set; } + public string ContinueAnyway { get; set; } + public string UncheckedFixLowercaseIToUppercaseI { get; set; } + public string XIsChangedToUppercase { get; set; } + public string FixFirstLetterToUppercaseAfterParagraph { get; set; } + public string MergeShortLine { get; set; } + public string XLineBreaksAdded { get; set; } + public string BreakLongLine { get; set; } + public string FixLongDisplayTime { get; set; } + public string FixInvalidItalicTag { get; set; } + public string FixShortDisplayTime { get; set; } + public string FixOverlappingDisplayTime { get; set; } + public string FixInvalidItalicTagsExample { get; set; } + public string RemoveUnneededSpacesExample { get; set; } + public string RemoveUnneededPeriodsExample { get; set; } + public string FixMissingSpacesExample { get; set; } + public string FixUppercaseIInsindeLowercaseWordsExample { get; set; } + public string FixLowercaseIToUppercaseIExample { get; set; } + public string StartTimeLaterThanEndTime { get; set; } + public string UnableToFixStartTimeLaterThanEndTime { get; set; } + public string XFixedToYZ { get; set; } + public string UnableToFixTextXY { get; set; } + public string XOverlappingTimestampsFixed { get; set; } + public string XDisplayTimesProlonged { get; set; } + public string XInvalidHtmlTagsFixed { get; set; } + public string XDisplayTimesShortned { get; set; } + public string XLinesUnbreaked { get; set; } + public string UnneededSpace { get; set; } + public string XUnneededSpacesRemoved { get; set; } + public string UnneededPeriod { get; set; } + public string XUnneededPeriodsRemoved { get; set; } + public string FixMissingSpace { get; set; } + public string XMissingSpacesAdded { get; set; } + public string FixUppercaseIInsideLowercaseWord { get; set; } + public string XPeriodsAdded { get; set; } + public string FixMissingPeriodAtEndOfLine { get; set; } + public string XDoubleApostrophesFixed { get; set; } + public string XUppercaseIsFoundInsideLowercaseWords { get; set; } + public string RefreshFixes { get; set; } + public string ApplyFixes { get; set; } + public string AutoBreak { get; set; } + public string Unbreak { get; set; } + public string FixDoubleDash { get; set; } + public string FixDoubleGreaterThan { get; set; } + public string FixEllipsesStart { get; set; } + public string FixMissingOpenBracket { get; set; } + public string FixMusicNotation { get; set; } + public string FixDoubleDashs { get; set; } + public string FixDoubleGreaterThans { get; set; } + public string FixEllipsesStarts { get; set; } + public string FixMissingOpenBrackets { get; set; } + public string FixMusicNotations { get; set; } + public string XFixDoubleDash { get; set; } + public string XFixDoubleGreaterThan { get; set; } + public string XFixEllipsesStart { get; set; } + public string XFixMissingOpenBracket { get; set; } + public string XFixMusicNotation { get; set; } + public string FixDoubleDashExample { get; set; } + public string FixDoubleGreaterThanExample { get; set; } + public string FixEllipsesStartExample { get; set; } + public string FixMissingOpenBracketExample { get; set; } + public string FixMusicNotationExample { get; set; } + public string NumberOfImportantLogMessages { get; set; } + } + + public class GetDictionaries + { + public string Title { get; set; } + public string DescriptionLine1 { get; set; } + public string DescriptionLine2 { get; set; } + public string GetDictionariesHere { get; set; } + public string OpenOpenOfficeWiki { get; set; } + public string GetAllDictionaries { get; set; } + public string ChooseLanguageAndClickDownload { get; set; } + public string OpenDictionariesFolder { get; set; } + public string Download { get; set; } + public string XDownloaded { get; set; } + } + + public class GoogleTranslate + { + public string Title { get; set; } + public string From { get; set; } + public string To { get; set; } + public string Translate { get; set; } + public string PleaseWait { get; set; } + public string PoweredByGoogleTranslate { get; set; } + public string PoweredByMicrosoftTranslate { get; set; } + } + + public class GoToLine + { + public string Title { get; set; } + public string XIsNotAValidNumber { get; set; } + } + + public class ImportText + { + public string Title { get; set; } + public string OpenTextFile { get; set; } + public string ImportOptions { get; set; } + public string Splitting { get; set; } + public string AutoSplitText { get; set; } + public string OneLineIsOneSubtitle { get; set; } + public string MergeShortLines { get; set; } + public string RemoveEmptyLines { get; set; } + public string RemoveLinesWithoutLetters { get; set; } + public string GapBetweenSubtitles { get; set; } + public string Auto { get; set; } + public string Fixed { get; set; } + public string Refresh { get; set; } + public string Next { get; set; } + public string TextFiles { get; set; } + public string PreviewLinesModifiedX { get; set; } + } + + public class Main + { + public MainMenu Menu { get; set; } + public MainControls Controls { get; set; } + public MainVideoControls VideoControls { get; set; } + public string SaveChangesToUntitled { get; set; } + public string SaveChangesToX { get; set; } + public string SaveSubtitleAs { get; set; } + public string NoSubtitleLoaded { get; set; } + public string VisualSyncSelectedLines { get; set; } + public string VisualSyncTitle { get; set; } + public string BeforeVisualSync { get; set; } + public string VisualSyncPerformedOnSelectedLines { get; set; } + public string VisualSyncPerformed { get; set; } + public string ImportThisVobSubSubtitle { get; set; } + public string FileXIsLargerThan10Mb { get; set; } + public string ContinueAnyway { get; set; } + public string BeforeLoadOf { get; set; } + public string LoadedSubtitleX { get; set; } + public string LoadedEmptyOrShort { get; set; } + public string FileIsEmptyOrShort { get; set; } + public string FileNotFound { get; set; } + public string SavedSubtitleX { get; set; } + public string FileOnDiskModified { get; set; } + public string OverwriteModifiedFile { get; set; } + public string UnableToSaveSubtitleX { get; set; } + public string BeforeNew { get; set; } + public string New { get; set; } + public string BeforeConvertingToX { get; set; } + public string ConvertedToX { get; set; } + public string BeforeShowEarlier { get; set; } + public string BeforeShowLater { get; set; } + public string LineNumberX { get; set; } + public string OpenVideoFile { get; set; } + public string NewFrameRateUsedToCalculateTimeCodes { get; set; } + public string NewFrameRateUsedToCalculateFrameNumbers { get; set; } + public string FindContinue { get; set; } + public string FindContinueTitle { get; set; } + public string XFoundAtLineNumberY { get; set; } + public string XNotFound { get; set; } + public string BeforeReplace { get; set; } + public string MatchFoundX { get; set; } + public string NoMatchFoundX { get; set; } + public string FoundNothingToReplace { get; set; } + public string ReplaceCountX { get; set; } + public string NoXFoundAtLineY { get; set; } + public string OneReplacementMade { get; set; } + public string BeforeChangesMadeInSourceView { get; set; } + public string UnableToParseSourceView { get; set; } + public string GoToLineNumberX { get; set; } + public string CreateAdjustChangesApplied { get; set; } + public string SelectedLines { get; set; } + public string BeforeDisplayTimeAdjustment { get; set; } + public string DisplayTimeAdjustedX { get; set; } + public string BeforeCommonErrorFixes { get; set; } + public string CommonErrorsFixedInSelectedLines { get; set; } + public string CommonErrorsFixed { get; set; } + public string BeforeRenumbering { get; set; } + public string RenumberedStartingFromX { get; set; } + public string BeforeRemovalOfTextingForHearingImpaired { get; set; } + public string TextingForHearingImpairedRemovedOneLine { get; set; } + public string TextingForHearingImpairedRemovedXLines { get; set; } + public string SubtitleSplitted { get; set; } + public string SubtitleAppendPrompt { get; set; } + public string SubtitleAppendPromptTitle { get; set; } + public string OpenSubtitleToAppend { get; set; } + public string AppendViaVisualSyncTitle { get; set; } + public string AppendSynchronizedSubtitlePrompt { get; set; } + public string BeforeAppend { get; set; } + public string SubtitleAppendedX { get; set; } + public string SubtitleNotAppended { get; set; } + public string GoogleTranslate { get; set; } + public string MicrosoftTranslate { get; set; } + public string BeforeGoogleTranslation { get; set; } + public string SelectedLinesTranslated { get; set; } + public string SubtitleTranslated { get; set; } + public string TranslateSwedishToDanish { get; set; } + public string TranslateSwedishToDanishWarning { get; set; } + public string TranslatingViaNikseDkMt { get; set; } + public string BeforeSwedishToDanishTranslation { get; set; } + public string TranslationFromSwedishToDanishComplete { get; set; } + public string TranslationFromSwedishToDanishFailed { get; set; } + public string BeforeUndo { get; set; } + public string UndoPerformed { get; set; } + public string NothingToUndo { get; set; } + public string InvalidLanguageNameX { get; set; } + public string UnableToChangeLanguage { get; set; } + public string NumberOfCorrectedWords { get; set; } + public string NumberOfSkippedWords { get; set; } + public string NumberOfCorrectWords { get; set; } + public string NumberOfWordsAddedToDictionary { get; set; } + public string NumberOfNameHits { get; set; } + public string SpellCheck { get; set; } + public string BeforeSpellCheck { get; set; } + public string SpellCheckChangedXToY { get; set; } + public string BeforeAddingTagX { get; set; } + public string TagXAdded { get; set; } + public string LineXOfY { get; set; } + public string XLinesDeleted { get; set; } + public string BeforeDeletingXLines { get; set; } + public string DeleteXLinesPrompt { get; set; } + public string OneLineDeleted { get; set; } + public string BeforeDeletingOneLine { get; set; } + public string DeleteOneLinePrompt { get; set; } + public string BeforeInsertLine { get; set; } + public string LineInserted { get; set; } + public string BeforeLineUpdatedInListView { get; set; } + public string BeforeSettingFontToNormal { get; set; } + public string BeforeSplitLine { get; set; } + public string LineSplitted { get; set; } + public string BeforeMergeLines { get; set; } + public string LinesMerged { get; set; } + public string BeforeSettingColor { get; set; } + public string BeforeSettingFontName { get; set; } + public string BeforeTypeWriterEffect { get; set; } + public string BeforeKaraokeEffect { get; set; } + public string BeforeImportingDvdSubtitle { get; set; } + public string OpenMatroskaFile { get; set; } + public string MatroskaFiles { get; set; } + public string NoSubtitlesFound { get; set; } + public string NotAValidMatroskaFileX { get; set; } + public string ParsingMatroskaFile { get; set; } + public string BeforeImportFromMatroskaFile { get; set; } + public string SubtitleImportedFromMatroskaFile { get; set; } + public string DropFileXNotAccepted { get; set; } + public string DropOnlyOneFile { get; set; } + public string BeforeCreateAdjustLines { get; set; } + public string OpenAnsiSubtitle { get; set; } + public string BeforeChangeCasing { get; set; } + public string CasingCompleteMessageNoNames { get; set; } + public string CasingCompleteMessageOnlyNames { get; set; } + public string CasingCompleteMessage { get; set; } + public string BeforeChangeFrameRate { get; set; } + public string FrameRateChangedFromXToY { get; set; } + public string IdxFileNotFoundWarning { get; set; } + public string InvalidVobSubHeader { get; set; } + public string OpenVobSubFile { get; set; } + public string VobSubFiles { get; set; } + public string BeforeImportingVobSubFile { get; set; } + public string BeforeShowSelectedLinesEarlierLater { get; set; } + public string ShowSelectedLinesEarlierLaterPerformed { get; set; } + public string DoubleWordsViaRegEx { get; set; } + public string BeforeSortX { get; set; } + public string SortedByX { get; set; } + public string BeforeAutoBalanceSelectedLines { get; set; } + public string NumberOfLinesAutoBalancedX { get; set; } + public string BeforeRemoveLineBreaksInSelectedLines { get; set; } + public string NumberOfWithRemovedLineBreakX { get; set; } + public string BeforeMultipleReplace { get; set; } + public string NumberOfLinesReplacedX { get; set; } + public string NameXAddedToNamesEtcList { get; set; } + public string NameXNotAddedToNamesEtcList { get; set; } + public string XLinesSelected { get; set; } + public string UnicodeMusicSymbolsAnsiWarning { get; set; } + public string NegativeTimeWarning { get; set; } + public string BeforeMergeShortLines { get; set; } + public string MergedShortLinesX { get; set; } + public string BeforeSetMinimumDisplayTimeBetweenParagraphs { get; set; } + public string XMinimumDisplayTimeBetweenParagraphsChanged { get; set; } + public string BeforeImportText { get; set; } + public string TextImported { get; set; } + public string BeforePointSynchronization { get; set; } + public string PointSynchronizationDone { get; set; } + public string BeforeTimeCodeImport { get; set; } + public string TimeCodeImportedFromXY { get; set; } + public string BeforeInsertSubtitleAtVideoPosition { get; set; } + public string BeforeSetStartTimeAndOffsetTheRest { get; set; } + public string ContinueWithCurrentSpellCheck { get; set; } + + public class MainMenu + { + public class FileMenu + { + public string Title { get; set; } + public string New { get; set; } + public string Open { get; set; } + public string Reopen { get; set; } + public string Save { get; set; } + public string SaveAs { get; set; } + public string OpenContainingFolder { get; set; } + public string Compare { get; set; } + public string ImportOcrFromDvd { get; set; } + public string ImportOcrVobSubSubtitle { get; set; } + public string ImportSubtitleFromMatroskaFile { get; set; } + public string ImportSubtitleWithManualChosenEncoding { get; set; } + public string ImportText { get; set; } + public string ImportTimecodes { get; set; } + public string Exit { get; set; } + } + public class EditMenu + { + public string Title { get; set; } + public string ShowUndoHistory { get; set; } + public string ShowOriginalText { get; set; } + public string HideOriginalText { get; set; } + public string InsertUnicodeSymbol { get; set; } + public string Find { get; set; } + public string FindNext { get; set; } + public string Replace { get; set; } + public string MultipleReplace { get; set; } + public string GoToSubtitleNumber { get; set; } + } + public class ToolsMenu + { + public string Title { get; set; } + public string AdjustDisplayDuration { get; set; } + public string FixCommonErrors { get; set; } + public string StartNumberingFrom { get; set; } + public string RemoveTextForHearingImpaired { get; set; } + public string ChangeCasing { get; set; } + public string ChangeFrameRate { get; set; } + public string MergeShortLines { get; set; } + public string MinimumDisplayTimeBetweenParagraphs { get; set; } + public string SortBy { get; set; } + public string TextAlphabetically { get; set; } + public string TextSingleLineMaximumLength { get; set; } + public string TextTotalLength { get; set; } + public string TextNumberOfLines { get; set; } + public string SplitSubtitle { get; set; } + public string AppendSubtitle { get; set; } + } + public class VideoMenu + { + public string Title { get; set; } + public string OpenVideo { get; set; } + public string ShowHideVideo { get; set; } + public string ShowHideWaveForm { get; set; } + } + public class SpellCheckMenu + { + public string Title { get; set; } + public string SpellCheck { get; set; } + public string FindDoubleWords { get; set; } + public string GetDictionaries { get; set; } + public string AddToNamesEtcList { get; set; } + } + public class SynchronizationkMenu + { + public string Title { get; set; } + public string AdjustAllTimes { get; set; } + public string VisualSync { get; set; } + public string PointSync { get; set; } + } + public class AutoTranslateMenu + { + public string Title { get; set; } + public string TranslatePoweredByGoogle { get; set; } + public string TranslatePoweredByMicrosoft { get; set; } + public string TranslateFromSwedishToDanish { get; set; } + } + public class OptionsMenu + { + public string Title { get; set; } + public string Settings { get; set; } + public string ChooseLanguage { get; set; } + } + + public class HelpMenu + { + public string Title { get; set; } + public string Help { get; set; } + public string About { get; set; } + } + + public class ToolBarMenu + { + public string New { get; set; } + public string Open { get; set; } + public string Save { get; set; } + public string SaveAs { get; set; } + public string Find { get; set; } + public string Replace { get; set; } + public string VisualSync { get; set; } + public string SpellCheck { get; set; } + public string Settings { get; set; } + public string Help { get; set; } + public string ShowHideWaveForm { get; set; } + public string ShowHideVideo { get; set; } + } + + public class ListViewContextMenu + { + public string Delete { get; set; } + public string InsertBefore { get; set; } + public string InsertAfter { get; set; } + public string Split { get; set; } + public string MergeSelectedLines { get; set; } + public string MergeWithLineBefore { get; set; } + public string MergeWithLineAfter { get; set; } + public string Normal { get; set; } + public string Underline { get; set; } + public string Color { get; set; } + public string FontName { get; set; } + public string AutoBalanceSelectedLines { get; set; } + public string RemoveLineBreaksFromSelectedLines { get; set; } + public string TypewriterEffect { get; set; } + public string KaraokeEffect { get; set; } + public string ShowSelectedLinesEarlierLater { get; set; } + public string VisualSyncSelectedLines { get; set; } + public string GoogleTranslateSelectedLines { get; set; } + public string AdjustDisplayDurationForSelectedLines { get; set; } + public string FixCommonErrorsInSelectedLines { get; set; } + public string ChangeCasingForSelectedLines { get; set; } + } + + public FileMenu File { get; set; } + public EditMenu Edit { get; set; } + public ToolsMenu Tools { get; set; } + public VideoMenu Video { get; set; } + public SpellCheckMenu SpellCheck { get; set; } + public SynchronizationkMenu Synchronization { get; set; } + public AutoTranslateMenu AutoTranslate { get; set; } + public OptionsMenu Options { get; set; } + public HelpMenu Help { get; set; } + public ToolBarMenu ToolBar { get; set; } + public ListViewContextMenu ContextMenu { get; set; } + } + + public class MainControls + { + public string SubtitleFormat { get; set; } + public string FileEncoding { get; set; } + public string ListView { get; set; } + public string SourceView { get; set; } + public string UndoChangesInEditPanel { get; set; } + public string Previous { get; set; } + public string Next { get; set; } + public string AutoBreak { get; set; } + public string Unbreak { get; set; } + } + + public class MainVideoControls + { + public string Translate { get; set; } + public string Create { get; set; } + public string Adjust { get; set; } + public string SelectCurrentElementWhilePlaying { get; set; } + + //translation helper + public string AutoRepeat { get; set; } + public string AutoRepeatOn { get; set; } + public string AutoRepeatCount { get; set; } + public string AutoContinue { get; set; } + public string AutoContinueOn { get; set; } + public string DelayInSeconds { get; set; } + public string OriginalText { get; set; } + public string Previous { get; set; } + public string Stop { get; set; } + public string PlayCurrent { get; set; } + public string Next { get; set; } + public string Playing { get; set; } + public string RepeatingLastTime { get; set; } + public string RepeatingXTimesLeft { get; set; } + public string AutoContinueInOneSecond { get; set; } + public string AutoContinueInXSeconds { get; set; } + public string StillTypingAutoContinueStopped { get; set; } + + // create/adjust + public string InsertNewSubtitleAtVideoPosition { get; set; } + public string Auto { get; set; } + public string PlayFromJustBeforeText { get; set; } + public string Pause { get; set; } + public string GoToSubtitlePositionAndPause { get; set; } + public string SetStartTime { get; set; } + public string SetEndTimeAndGoToNext { get; set; } + public string SetEndTime { get; set; } + public string SetstartTimeAndOffsetOfRest { get; set; } + + public string SearchTextOnline { get; set; } + public string GoogleTranslate { get; set; } + public string GoogleIt { get; set; } + public string SecondsBackShort { get; set; } + public string SecondsForwardShort { get; set; } + public string VideoPosition { get; set; } + public string TranslateTip { get; set; } + public string CreateTip { get; set; } + public string AdjustTip { get; set; } + + public string BeforeChangingTimeInWaveFormX { get; set; } + public string NewTextInsertAtX { get; set; } + } + } + + public class MatroskaSubtitleChooser + { + public string Title { get; set; } + public string PleaseChoose { get; set; } + public string TrackXLanguageYTypeZ { get; set; } + } + + public class MergeShortLines + { + public string Title { get; set; } + public string MaximumCharacters { get; set; } + public string MaximumMillisecondsBetween { get; set; } + public string NumberOfMergesX { get; set; } + public string LineNumber { get; set; } + + public string MergedText { get; set; } + } + + public class MultipleReplace + { + public string Title { get; set; } + public string FindWhat { get; set; } + public string ReplaceWith { get; set; } + public string Normal { get; set; } + public string CaseSensitive { get; set; } + public string RegularExpression { get; set; } + public string LineNumber { get; set; } + public string Before { get; set; } + public string After { get; set; } + public string LinesFoundX { get; set; } + public string Delete { get; set; } + public string Add { get; set; } + public string Update { get; set; } + public string Enabled { get; set; } + public string SearchType { get; set; } + } + public class RemoveTextFromHearImpaired + { + public string Title { get; set; } + public string RemoveTextConditions { get; set; } + public string RemoveTextBetween { get; set; } + public string SquareBrackets { get; set; } + public string Brackets { get; set; } + public string Parentheses { get; set; } + public string QuestionMarks { get; set; } + public string And { get; set; } + public string RemoveTextBeforeColon { get; set; } + public string OnlyIfTextIsUppercase { get; set; } + public string OnlyIfInSeparateLine { get; set; } + public string LineNumber { get; set; } + public string Before { get; set; } + public string After { get; set; } + public string LinesFoundX { get; set; } + public string RemoveTextIfContains { get; set; } + } + + public class ReplaceDialog + { + public string Title { get; set; } + public string FindWhat { get; set; } + public string Normal { get; set; } + public string CaseSensitive { get; set; } + public string RegularExpression { get; set; } + public string ReplaceWith { get; set; } + public string Find { get; set; } + public string Replace { get; set; } + public string ReplaceAll { get; set; } + } + + public class SetMinimumDisplayTimeBetweenParagraphs + { + public string Title { get; set; } + public string PreviewLinesModifiedX { get; set; } + public string ShowOnlyModifiedLines { get; set; } + public string MinimumMillisecondsBetweenParagraphs { get; set; } + } + + public class SetSyncPoint + { + public string Title { get; set; } + public string SyncPointTimeCode { get; set; } + public string ThreeSecondsBack { get; set; } + public string HalfASecondBack { get; set; } + public string HalfASecondForward { get; set; } + public string ThreeSecondsForward { get; set; } + } + + public class Settings + { + public string Title { get; set; } + public string General { get; set; } + public string VideoPlayer { get; set; } + public string WaveForm { get; set; } + public string Tools { get; set; } + public string WordLists { get; set; } + public string SsaStyle { get; set; } + public string Proxy { get; set; } + public string ShowToolBarButtons { get; set; } + public string New { get; set; } + public string Open { get; set; } + public string Save { get; set; } + public string SaveAs { get; set; } + public string Find { get; set; } + public string Replace { get; set; } + public string VisualSync { get; set; } + public string SpellCheck { get; set; } + public string SettingsName { get; set; } + public string Help { get; set; } + public string Miscellaneous { get; set; } + public string ShowFrameRate { get; set; } + public string DefaultFrameRate { get; set; } + public string DefaultFileEncoding { get; set; } + public string AutoDetectAnsiEncoding { get; set; } + public string SubtitleLineMaximumLength { get; set; } + public string SubtitleFont { get; set; } + public string SubtitleFontSize { get; set; } + public string RememberRecentFiles { get; set; } + public string StartWithLastFileLoaded { get; set; } + public string RememberPositionAndSize { get; set; } + public string StartInSourceView { get; set; } + public string RemoveBlankLinesWhenOpening { get; set; } + public string ShowLineBreaksAs { get; set; } + public string MainListViewDoubleClickAction { get; set; } + public string MainListViewNothing { get; set; } + public string MainListViewVideoGoToPositionAndPause { get; set; } + public string MainListViewVideoGoToPositionAndPlay { get; set; } + public string MainListViewEditText { get; set; } + public string VideoEngine { get; set; } + public string DirectShow { get; set; } + public string DirectShowDescription { get; set; } + public string ManagedDirectX { get; set; } + public string ManagedDirectXDescription { get; set; } + public string WindowsMediaPlayer { get; set; } + public string WindowsMediaPlayerDescription { get; set; } + public string VlcMediaPlayer { get; set; } + public string VlcMediaPlayerDescription { get; set; } + public string ShowStopButton { get; set; } + public string DefaultVolume { get; set; } + public string VolumeNotes { get; set; } + public string MainWindowVideoControls { get; set; } + public string CustomSearchTextAndUrl { get; set; } + public string WaveFormAppearance { get; set; } + public string WaveFormGridColor { get; set; } + public string WaveFormShowGridLines { get; set; } + public string WaveFormColor { get; set; } + public string WaveFormSelectedColor { get; set; } + public string WaveFormBackgroundColor { get; set; } + public string WaveFormTextColor { get; set; } + public string WaveFormsFolderEmpty { get; set; } + public string WaveFormsFolderInfo { get; set; } + public string SubStationAlphaStyle { get; set; } + public string ChooseFont { get; set; } + public string ChooseColor { get; set; } + public string Example { get; set; } + public string Testing123 { get; set; } + public string Language { get; set; } + public string NamesIgnoreLists { get; set; } + public string AddNameEtc { get; set; } + public string AddWord { get; set; } + public string Remove { get; set; } + public string AddPair { get; set; } + public string UserWordList { get; set; } + public string OcrFixList { get; set; } + public string Location { get; set; } + public string UseOnlineNamesEtc { get; set; } + public string WordAddedX { get; set; } + public string WordAlreadyExists { get; set; } + public string WordNotFound { get; set; } + public string RemoveX { get; set; } + public string CannotUpdateNamesEtcOnline { get; set; } + public string ProxyServerSettings { get; set; } + public string ProxyAddress { get; set; } + public string ProxyAuthentication { get; set; } + public string ProxyUserName { get; set; } + public string ProxyPassword { get; set; } + public string ProxyDomain { get; set; } + public string PlayXSecondsAndBack { get; set; } + public string StartSceneIndex { get; set; } + public string EndSceneIndex { get; set; } + public string FirstPlusX { get; set; } + public string LastMinusX { get; set; } + public string FixCommonerrors { get; set; } + public string MergeLinesShorterThan { get; set; } + public string MusicSymbol { get; set; } + public string MusicSymbolsToReplace { get; set; } + } + + public class ShowEarlierLater + { + public string Title { get; set; } + public string ShowEarlier { get; set; } + public string ShowLater { get; set; } + public string TotalAdjustmentX { get; set; } + } + + public class ShowHistory + { + public string Title { get; set; } + public string SelectRollbackPoint { get; set; } + public string Time { get; set; } + public string Description { get; set; } + public string CompareHistoryItems { get; set; } + public string CompareWithCurrent { get; set; } + public string Rollback { get; set; } + } + + public class SpellCheck + { + public string Title { get; set; } + public string FullText { get; set; } + public string WordNotFound { get; set; } + public string Language { get; set; } + public string Change { get; set; } + public string ChangeAll { get; set; } + public string SkipOnce { get; set; } + public string SkipAll { get; set; } + public string AddToUserDictionary { get; set; } + public string AddToNamesAndIgnoreList { get; set; } + public string Abort { get; set; } + public string Use { get; set; } + public string UseAlways { get; set; } + public string Suggestions { get; set; } + public string SpellCheckProgress { get; set; } + public string EditWholeText { get; set; } + public string EditWordOnly { get; set; } + public string AddXToNamesEtc { get; set; } + public string AutoFixNames { get; set; } + public string ImageText { get; set; } + public string SpellCheckCompleted { get; set; } + public string SpellCheckAborted { get; set; } + } + + public class SplitSubtitle + { + public string Title { get; set; } + public string Description1 { get; set; } + public string Description2 { get; set; } + public string Split { get; set; } + public string Done { get; set; } + public string NothingToSplit { get; set; } + public string SavePartOneAs { get; set; } + public string SavePartTwoAs{ get; set; } + public string Part1 { get; set; } + public string Part2 { get; set; } + public string UnableToSaveFileX { get; set; } + } + + public class StartNumberingFrom + { + public string Title { get; set; } + public string StartFromNumber { get; set; } + public string PleaseEnterAValidNumber { get; set; } + } + + public class PointSync + { + public string Title { get; set; } + public string SyncHelp { get; set; } + public string SetSyncPoint { get; set; } + public string RemoveSyncPoint { get; set; } + public string SyncPointsX { get; set; } + public string Description { get; set; } + } + + public class UnknownSubtitle + { + public string Title { get; set; } + public string Message { get; set; } + } + + public class VisualSync + { + public string Title { get; set; } + public string StartScene { get; set; } + public string EndScene { get; set; } + public string Synchronize { get; set; } + public string HalfASecondBack { get; set; } + public string ThreeSecondsBack { get; set; } + public string PlayXSecondsAndBack { get; set; } + public string FindText { get; set; } + public string GoToSubPosition { get; set; } + public string KeepChangesTitle { get; set; } + public string KeepChangesMessage { get; set; } + public string SynchronizationDone { get; set; } + public string StartSceneMustComeBeforeEndScene { get; set; } + public string Tip { get; set; } + } + + public class VobSubEditCharacters + { + public string Title { get; set; } + public string ChooseCharacter { get; set; } + public string ImageCompareFiles { get; set; } + public string CurrentCompareImage { get; set; } + public string TextAssociatedWithImage { get; set; } + public string IsItalic { get; set; } + public string Update { get; set; } + public string Delete { get; set; } + public string ImageDoubleSize { get; set; } + public string ImageFileNotFound { get; set; } + public string Image { get; set; } + } + + public class VobSubOcr + { + public string Title { get; set; } + public string OcrMethod { get; set; } + public string OcrViaModi { get; set; } + public string OcrViaTesseract { get; set; } + public string Language { get; set; } + public string OcrViaImageCompare { get; set; } + public string ImageDatabase { get; set; } + public string NoOfPixelsIsSpace { get; set; } + public string New { get; set; } + public string Edit { get; set; } + public string StartOcr { get; set; } + public string Stop { get; set; } + public string StartOcrFrom { get; set; } + public string LoadingVobSubImages { get; set; } + public string SubtitleImage { get; set; } + public string SubtitleText { get; set; } + public string UnableToCreateCharacterDatabaseFolder { get; set; } + public string SubtitleImageXofY { get; set; } + public string ImagePalette { get; set; } + public string UseCustomColors { get; set; } + public string Transparent { get; set; } + public string PromptForUnknownWords { get; set; } + public string TryToGuessUnkownWords { get; set; } + public string AutoBreakSubtitleIfMoreThanTwoLines { get; set; } + public string AllFixes { get; set; } + public string GuessesUsed { get; set; } + public string UnknownWords { get; set; } + public string OcrAutoCorrectionSpellchecking { get; set; } + public string FixOcrErrors { get; set; } + public string SaveSubtitleImageAs { get; set; } + public string TryModiForUnknownWords { get; set; } + public string DictionaryX { get; set; } + public string RightToLeft { get; set; } + public string ShowOnlyForcedSubtitles { get; set; } + public string UseTimeCodesFromIdx { get; set; } + } + + public class VobSubOcrCharacter + { + public string Title { get; set; } + public string ShrinkSelection { get; set; } + public string ExpandSelection { get; set; } + public string SubtitleImage { get; set; } + public string Characters { get; set; } + public string CharactersAsText { get; set; } + public string Italic { get; set; } + public string Abort { get; set; } + } + + public class VobSubOcrNewFolder + { + public string Title { get; set; } + public string Message { get; set; } + } + + public class WaveForm + { + public string ClickToAddWaveForm { get; set; } + public string Seconds { get; set; } + public string ZoomIn { get; set; } + public string ZoomOut { get; set; } + public string AddParagraphHere { get; set; } + public string DeleteParagraph { get; set; } + public string Split { get; set; } + public string SplitAtCursor { get; set; } + public string MergeWithPrevious { get; set; } + public string MergeWithNext { get; set; } + public string PlaySelection { get; set; } + } + + } +} diff --git a/src/Logic/Paragraph.cs b/src/Logic/Paragraph.cs new file mode 100644 index 000000000..31f10d1e5 --- /dev/null +++ b/src/Logic/Paragraph.cs @@ -0,0 +1,105 @@ +using System; + +namespace Nikse.SubtitleEdit.Logic +{ + public class Paragraph + { + public int Number { get; set; } + + public string Text { get; set; } + + public TimeCode StartTime { get; set; } + + public TimeCode EndTime { get; set; } + + public TimeCode Duration + { + get + { + var timeCode = new TimeCode(EndTime.TimeSpan); + timeCode.AddTime(- StartTime.TotalMilliseconds); + return timeCode; + } + } + + public int StartFrame { get; set; } + + public int EndFrame { get; set; } + + public Paragraph() + { + StartTime = new TimeCode(TimeSpan.FromSeconds(0)); + EndTime = new TimeCode(TimeSpan.FromSeconds(0)); + Text = string.Empty; + } + + public Paragraph(TimeCode startTime, TimeCode endTime, string text) + { + StartTime = startTime; + EndTime = endTime; + Text = text; + } + + public Paragraph(Paragraph paragraph) + { + Number = paragraph.Number; + Text = paragraph.Text; + StartTime = new TimeCode(paragraph.StartTime.TimeSpan); + EndTime = new TimeCode(paragraph.EndTime.TimeSpan); + StartFrame = paragraph.StartFrame; + EndFrame = paragraph.EndFrame; + } + + public Paragraph(int startFrame, int endFrame, string text) + { + StartTime = new TimeCode(0, 0, 0, 0); + EndTime = new TimeCode(0, 0, 0, 0); + StartFrame = startFrame; + EndFrame = endFrame; + Text = text; + } + + public Paragraph(string text, double startTotalMilliseconds, double endTotalMilliseconds) + { + StartTime = new TimeCode(TimeSpan.FromMilliseconds(startTotalMilliseconds)); + EndTime = new TimeCode(TimeSpan.FromMilliseconds(endTotalMilliseconds)); + Text = text; + } + + internal void Adjust(double factor, double adjust) + { + double seconds = StartTime.TimeSpan.TotalSeconds * factor + adjust; + StartTime.TimeSpan = TimeSpan.FromSeconds(seconds); + + seconds = EndTime.TimeSpan.TotalSeconds * factor + adjust; + EndTime.TimeSpan = TimeSpan.FromSeconds(seconds); + } + + public void CalculateFrameNumbersFromTimeCodes(double frameRate) + { + StartFrame = (int)(StartTime.TotalMilliseconds / 1000.0 * frameRate); + EndFrame = (int)(EndTime.TotalMilliseconds / 1000.0 * frameRate); + } + + public void CalculateTimeCodesFromFrameNumbers(double frameRate) + { + StartTime.TotalMilliseconds = StartFrame * (1000.0 / frameRate); + EndTime.TotalMilliseconds = EndFrame * (1000.0 / frameRate); + } + + public override string ToString() + { + return StartTime + " --> " + EndTime + " " + Text; + } + + public int NumberOfLines + { + get + { + if (string.IsNullOrEmpty(Text)) + return 0; + return Text.Length - Text.Replace(Environment.NewLine, string.Empty).Length; + } + } + } +} diff --git a/src/Logic/PositionAndSize.cs b/src/Logic/PositionAndSize.cs new file mode 100644 index 000000000..e5c6376e6 --- /dev/null +++ b/src/Logic/PositionAndSize.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.Drawing; + +namespace Nikse.SubtitleEdit.Logic +{ + class PositionAndSize + { + public string Name { get; set; } + public int Left { get; set; } + public int Top { get; set; } + public Size Size { get; set; } + } +} diff --git a/src/Logic/PositionsAndSizes.cs b/src/Logic/PositionsAndSizes.cs new file mode 100644 index 000000000..77730c9f5 --- /dev/null +++ b/src/Logic/PositionsAndSizes.cs @@ -0,0 +1,56 @@ +using System.Collections.Generic; +using System.Windows.Forms; + +namespace Nikse.SubtitleEdit.Logic +{ + class PositionsAndSizes + { + List _positionsAndSizes = new List(); + + public void SetPositionAndSize(Form form) + { + if (form == null) + return; + + foreach (PositionAndSize ps in _positionsAndSizes) + { + if (ps.Name == form.Name) + { + form.StartPosition = FormStartPosition.Manual; + form.Left = ps.Left; + form.Top = ps.Top; + form.Size = ps.Size; + break; + } + } + } + + public void SavePositionAndSize(Form form) + { + if (form == null) + return; + + bool found = false; + PositionAndSize pAndS = new PositionAndSize(); + foreach (PositionAndSize ps in _positionsAndSizes) + { + if (ps.Name == form.Name) + { + found = true; + pAndS = ps; + break; + } + } + + pAndS.Left = form.Left; + pAndS.Top = form.Top; + pAndS.Size = form.Size; + + if (!found) + { + pAndS.Name = form.Name; + _positionsAndSizes.Add(pAndS); + } + } + } +} diff --git a/src/Logic/Settings.cs b/src/Logic/Settings.cs new file mode 100644 index 000000000..508c8c986 --- /dev/null +++ b/src/Logic/Settings.cs @@ -0,0 +1,902 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Text; +using System.Xml; +using System.Xml.Serialization; +using System.Drawing; + +namespace Nikse.SubtitleEdit.Logic +{ + // The settings classes are build for easy xml-serilization (makes save/load code simple) + // ...but the built-in serialization is too slow - so a custom (de-)serialization has been used! + + public class RecentFilesSettings + { + private const int MaxRecentFiles = 25; + + [XmlArrayItem("FileName")] + public List FileNames { get; set; } + + public RecentFilesSettings() + { + FileNames = new List(); + } + + public void Add(string fileName) + { + var newList = new List {fileName}; + int index = 0; + foreach (string oldFileName in FileNames) + { + if (string.Compare(fileName, oldFileName, true) != 0 && index < MaxRecentFiles) + newList.Add(oldFileName); + index++; + } + FileNames = newList; + } + } + + public class ToolsSettings + { + public int StartSceneIndex { get; set; } + public int EndSceneIndex { get; set; } + public int VerifyPlaySeconds { get; set; } + public int MergeLinesShorterThan { get; set; } + public string MusicSymbol { get; set; } + public string MusicSymbolToReplace { get; set; } + public bool SpellCheckAutoChangeNames { get; set; } + + public ToolsSettings() + { + StartSceneIndex = 1; + EndSceneIndex = 1; + VerifyPlaySeconds = 2; + MergeLinesShorterThan = 33; + MusicSymbol = "♪"; + MusicSymbolToReplace = "♪ ⶠ♪ âTª ã¢â™âª ?t×3 ?t¤3"; + SpellCheckAutoChangeNames = true; + } + } + + public class WordListSettings + { + public string LastLanguage { get; set; } + public string NamesEtcUrl { get; set; } + public bool UseOnlineNamesEtc { get; set; } + + public WordListSettings() + { + LastLanguage = "en"; + NamesEtcUrl = "http://www.nikse.dk/se/Names_Etc.xml"; + } + } + + public class SsaStyleSettings + { + public string FontName { get; set; } + public double FontSize { get; set; } + public int FontColorArgb { get; set; } + + public SsaStyleSettings() + { + FontName = "Microsoft Sans Serif"; + FontSize = 18; + FontColorArgb = System.Drawing.Color.FromArgb(255, 255, 255).ToArgb(); + } + } + + public class ProxySettings + { + public string ProxyAddress { get; set; } + public string UserName { get; set; } + public string Password { get; set; } + public string Domain { get; set; } + + public string DecodePassword() + { + return Encoding.UTF8.GetString(Convert.FromBase64String(Password)); + } + public void EncodePassword(string unencryptedPassword) + { + Password = Convert.ToBase64String(Encoding.UTF8.GetBytes(unencryptedPassword)); + } + } + + public class FixCommonErrorsSettings + { + public bool EmptyLinesTicked { get; set; } + public bool OverlappingDisplayTimeTicked { get; set; } + public bool TooShortDisplayTimeTicked { get; set; } + public bool TooLongDisplayTimeTicked { get; set; } + public bool InvalidItalicTagsTicked { get; set; } + public bool BreakLongLinesTicked { get; set; } + public bool MergeShortLinesTicked { get; set; } + public bool UnneededSpacesTicked { get; set; } + public bool UnneededPeriodsTicked { get; set; } + public bool MissingSpacesTicked { get; set; } + public bool AddMissingQuotesTicked { get; set; } + public bool Fix3PlusLinesTicked { get; set; } + public bool FixHyphensTicked { get; set; } + public bool UppercaseIInsideLowercaseWordTicked { get; set; } + public bool DoubleApostropheToQuoteTicked { get; set; } + public bool AddPeriodAfterParagraphTicked { get; set; } + public bool StartWithUppercaseLetterAfterParagraphTicked { get; set; } + public bool StartWithUppercaseLetterAfterPeriodInsideParagraphTicked { get; set; } + public bool AloneLowercaseIToUppercaseIEnglishTicked { get; set; } + public bool FixOcrErrorsViaReplaceListTicked { get; set; } + public bool DanishLetterITicked { get; set; } + public bool SpanishInvertedQuestionAndExclamationMarksTicked { get; set; } + public bool FixDoubleDashTicked { get; set; } + public bool FixDoubleGreaterThanTicked { get; set; } + public bool FixEllipsesStartTicked { get; set; } + public bool FixMissingOpenBracketTicked { get; set; } + public bool FixMusicNotationTicked { get; set; } + + public FixCommonErrorsSettings() + { + EmptyLinesTicked = true; + OverlappingDisplayTimeTicked = true; + TooShortDisplayTimeTicked = true; + TooLongDisplayTimeTicked = true; + InvalidItalicTagsTicked = true; + BreakLongLinesTicked = true; + MergeShortLinesTicked = true; + UnneededPeriodsTicked = true; + UnneededSpacesTicked = true; + MissingSpacesTicked = true; + UppercaseIInsideLowercaseWordTicked = true; + DoubleApostropheToQuoteTicked = true; + AddPeriodAfterParagraphTicked = false; + StartWithUppercaseLetterAfterParagraphTicked = true; + StartWithUppercaseLetterAfterPeriodInsideParagraphTicked = false; + AloneLowercaseIToUppercaseIEnglishTicked = false; + DanishLetterITicked = false; + FixDoubleDashTicked = true; + FixDoubleGreaterThanTicked = true; + FixEllipsesStartTicked = true; + FixMissingOpenBracketTicked = true; + FixMusicNotationTicked = true; + } + } + + public class GeneralSettings + { + public bool ShowToolbarNew { get; set; } + public bool ShowToolbarOpen { get; set; } + public bool ShowToolbarSave { get; set; } + public bool ShowToolbarSaveAs { get; set; } + public bool ShowToolbarFind { get; set; } + public bool ShowToolbarReplace { get; set; } + public bool ShowToolbarVisualSync { get; set; } + public bool ShowToolbarSpellCheck { get; set; } + public bool ShowToolbarSettings { get; set; } + public bool ShowToolbarHelp { get; set; } + + public bool ShowVideoPlayer { get; set; } + public bool ShowWaveForm { get; set; } + public bool ShowFrameRate { get; set; } + public double DefaultFrameRate { get; set; } + public string DefaultEncoding { get; set; } + public bool AutoGuessAnsiEncoding { get; set; } + public string SubtitleFontName { get; set; } + public int SubtitleFontSize { get; set; } + public bool SubtitleFontBold { get; set; } + public bool ShowRecentFiles { get; set; } + public bool StartLoadLastFile { get; set; } + public bool StartRememberPositionAndSize { get; set; } + public string StartPosition { get; set; } + public string StartSize { get; set; } + public bool StartInSourceView { get; set; } + public bool RemoveBlankLinesWhenOpening { get; set; } + public int SubtitleLineMaximumLength { get; set; } + public string SpellCheckLanguage { get; set; } + public string VideoPlayer { get; set; } + public int VideoPlayerDefaultVolume { get; set; } + public bool VideoPlayerShowStopButton { get; set; } + public string Language { get; set; } + public string ListViewLineSeparatorString { get; set; } + public int ListViewDoubleClickAction { get; set; } + public string UppercaseLetters { get; set; } + public int DefaultAdjustMilliseconds { get; set; } + + public GeneralSettings() + { + ShowToolbarNew = true; + ShowToolbarOpen = true; + ShowToolbarSave = true; + ShowToolbarSaveAs = false; + ShowToolbarFind = true; + ShowToolbarReplace = true; + ShowToolbarVisualSync = true; + ShowToolbarSpellCheck = true; + ShowToolbarSettings = false; + ShowToolbarHelp = true; + + ShowVideoPlayer = false; + ShowWaveForm = false; + ShowFrameRate = false; + DefaultFrameRate = 23.976; + SubtitleFontName = "Microsoft Sans Serif"; + if (Environment.OSVersion.Version.Major < 6) // 6 == Vista/Win2008Server/Win7 + SubtitleFontName = "Lucida Sans Unicode"; + + SubtitleFontSize = 8; + SubtitleFontBold = false; + DefaultEncoding = "UTF-8"; + AutoGuessAnsiEncoding = false; + ShowRecentFiles = true; + StartLoadLastFile = true; + StartRememberPositionAndSize = true; + SubtitleLineMaximumLength = 65; + SpellCheckLanguage = null; + VideoPlayer = string.Empty; + VideoPlayerDefaultVolume = 50; + VideoPlayerShowStopButton = true; + ListViewLineSeparatorString = "
"; + ListViewDoubleClickAction = 1; + UppercaseLetters = "ABCDEFGHIJKLMNOPQRSTUVWZYXÆØÃÅÄÖÉÈÁÂÀÇÉÊÍÓÔÕÚŁ"; + DefaultAdjustMilliseconds = 1000; + } + } + + + public class VideoControlsSettings + { + public string CustomSearchText { get; set; } + public string CustomSearchUrl { get; set; } + public string LastActiveTab { get; set; } + public bool WaveFormDrawGrid { get; set; } + public Color WaveFormGridColor { get; set; } + public Color WaveFormColor { get; set; } + public Color WaveFormSelectedColor { get; set; } + public Color WaveFormBackgroundColor { get; set; } + public Color WaveFormTextColor { get; set; } + + public VideoControlsSettings() + { + CustomSearchText = "MS Encarta Thesaurus"; + CustomSearchUrl = "http://encarta.msn.com/encnet/features/dictionary/DictionaryResults.aspx?lextype=2&search={0}"; + LastActiveTab = "Translate"; + WaveFormDrawGrid = true; + WaveFormGridColor = Color.FromArgb(255, 20, 20, 18); + WaveFormColor = Color.GreenYellow; + WaveFormSelectedColor = Color.Red; + WaveFormBackgroundColor = Color.Black; + WaveFormTextColor = Color.Gray; + } + } + + public class VobSubOcrSettings + { + public int XOrMorePixelsMakesSpace { get; set; } + public double AllowDifferenceInPercent { get; set; } + public string LastImageCompareFolder { get; set; } + public int LastModiLanguageId { get; set; } + public string LastOcrMethod { get; set; } + public string TesseractLastLanguage { get; set; } + + public VobSubOcrSettings() + { + XOrMorePixelsMakesSpace = 5; + AllowDifferenceInPercent = 1.0; + LastImageCompareFolder = "English"; + LastModiLanguageId = 9; + LastOcrMethod = "Tesseract"; + } + } + + public class MultipleSearchAndReplaceSetting + { + public bool Enabled { get; set; } + public string FindWhat { get; set; } + public string ReplaceWith { get; set; } + public string SearchType { get; set; } + } + + public class Settings + { + public RecentFilesSettings RecentFiles { get; set; } + public GeneralSettings General { get; set; } + public ToolsSettings Tools { get; set; } + public SsaStyleSettings SsaStyle { get; set; } + public ProxySettings Proxy { get; set; } + public WordListSettings WordLists { get; set; } + public FixCommonErrorsSettings CommonErrors { get; set; } + public VobSubOcrSettings VobSubOcr { get; set; } + public VideoControlsSettings VideoControls { get; set; } + + [XmlArrayItem("MultipleSearchAndReplaceItem")] + public List MultipleSearchAndReplaceList { get; set; } + + [XmlIgnore] + public Language Language { get; set; } + + private Settings() + { + RecentFiles = new RecentFilesSettings(); + General = new GeneralSettings(); + Tools = new ToolsSettings(); + WordLists = new WordListSettings(); + SsaStyle = new SsaStyleSettings(); + Proxy = new ProxySettings(); + CommonErrors = new FixCommonErrorsSettings(); + VobSubOcr = new VobSubOcrSettings(); + VideoControls = new VideoControlsSettings(); + MultipleSearchAndReplaceList = new List(); + Language = new Language(); + } + + public void Save() + { + //slow + //Serialize(Configuration.BaseDirectory + "Settings.xml", this); + + //Fast - TODO: Fix in release + CustomSerialize(Configuration.BaseDirectory + "Settings.xml", this); + } + + private static void Serialize(string fileName, Settings settings) + { + var s = new XmlSerializer(typeof(Settings)); + TextWriter w = new StreamWriter(fileName); + s.Serialize(w, settings); + w.Close(); + } + + public static Settings GetSettings() + { + Settings settings = new Settings(); + if (File.Exists(Configuration.BaseDirectory + "Settings.xml")) + { + try + { + //TODO: Fix in release + settings = CustomDeserialize(Configuration.BaseDirectory + "Settings.xml"); // 15 msecs + + //too slow... :( + //settings = Deserialize(Configuration.BaseDirectory + "Settings.xml"); // 688 msecs + + } + catch + { + settings = new Settings(); + } + + if (string.IsNullOrEmpty(settings.General.ListViewLineSeparatorString)) + settings.General.ListViewLineSeparatorString = Environment.NewLine; + } + + return settings; + } + + private static Settings Deserialize(string fileName) + { + var r = new StreamReader(fileName); + var s = new XmlSerializer(typeof(Settings)); + var settings = (Settings)s.Deserialize(r); + r.Close(); + + if (settings.RecentFiles == null) + settings.RecentFiles = new RecentFilesSettings(); + if (settings.General == null) + settings.General = new GeneralSettings(); + if (settings.SsaStyle == null) + settings.SsaStyle = new SsaStyleSettings(); + if (settings.CommonErrors == null) + settings.CommonErrors = new FixCommonErrorsSettings(); + if (settings.VideoControls == null) + settings.VideoControls = new VideoControlsSettings(); + if (settings.VobSubOcr == null) + settings.VobSubOcr = new VobSubOcrSettings(); + if (settings.MultipleSearchAndReplaceList == null) + settings.MultipleSearchAndReplaceList = new List(); + + return settings; + } + + /// + /// A faster serializer than xml serializer... which is insanely slow (first time)!!!! + /// This method is auto-generated with XmlSerializerGenerator + /// + /// File name of xml settings file to load + /// Newly loaded settings + private static Settings CustomDeserialize(string fileName) + { + var doc = new XmlDocument(); + doc.Load(fileName); + + Settings settings = new Settings(); + + settings.RecentFiles = new Nikse.SubtitleEdit.Logic.RecentFilesSettings(); + XmlNode node = doc.DocumentElement.SelectSingleNode("RecentFiles"); + foreach (XmlNode listNode in node.SelectNodes("FileNames/FileName")) + settings.RecentFiles.FileNames.Add(listNode.InnerText); + + settings.General = new Nikse.SubtitleEdit.Logic.GeneralSettings(); + node = doc.DocumentElement.SelectSingleNode("General"); + XmlNode subNode = node.SelectSingleNode("ShowToolbarNew"); + if (subNode != null) + settings.General.ShowToolbarNew = Convert.ToBoolean(subNode.InnerText); + subNode = node.SelectSingleNode("ShowToolbarOpen"); + if (subNode != null) + settings.General.ShowToolbarOpen = Convert.ToBoolean(subNode.InnerText); + subNode = node.SelectSingleNode("ShowToolbarSave"); + if (subNode != null) + settings.General.ShowToolbarSave = Convert.ToBoolean(subNode.InnerText); + subNode = node.SelectSingleNode("ShowToolbarSaveAs"); + if (subNode != null) + settings.General.ShowToolbarSaveAs = Convert.ToBoolean(subNode.InnerText); + subNode = node.SelectSingleNode("ShowToolbarFind"); + if (subNode != null) + settings.General.ShowToolbarFind = Convert.ToBoolean(subNode.InnerText); + subNode = node.SelectSingleNode("ShowToolbarReplace"); + if (subNode != null) + settings.General.ShowToolbarReplace = Convert.ToBoolean(subNode.InnerText); + subNode = node.SelectSingleNode("ShowToolbarVisualSync"); + if (subNode != null) + settings.General.ShowToolbarVisualSync = Convert.ToBoolean(subNode.InnerText); + subNode = node.SelectSingleNode("ShowToolbarSpellCheck"); + if (subNode != null) + settings.General.ShowToolbarSpellCheck = Convert.ToBoolean(subNode.InnerText); + subNode = node.SelectSingleNode("ShowToolbarSettings"); + if (subNode != null) + settings.General.ShowToolbarSettings = Convert.ToBoolean(subNode.InnerText); + subNode = node.SelectSingleNode("ShowToolbarHelp"); + if (subNode != null) + settings.General.ShowToolbarHelp = Convert.ToBoolean(subNode.InnerText); + subNode = node.SelectSingleNode("ShowFrameRate"); + if (subNode != null) + settings.General.ShowFrameRate = Convert.ToBoolean(subNode.InnerText); + subNode = node.SelectSingleNode("ShowVideoPlayer"); + if (subNode != null) + settings.General.ShowVideoPlayer = Convert.ToBoolean(subNode.InnerText); + subNode = node.SelectSingleNode("ShowWaveForm"); + if (subNode != null) + settings.General.ShowWaveForm = Convert.ToBoolean(subNode.InnerText); + subNode = node.SelectSingleNode("DefaultFrameRate"); + if (subNode != null) + settings.General.DefaultFrameRate = Convert.ToDouble(subNode.InnerText); + subNode = node.SelectSingleNode("DefaultEncoding"); + if (subNode != null) + settings.General.DefaultEncoding = subNode.InnerText; + subNode = node.SelectSingleNode("AutoGuessAnsiEncoding"); + if (subNode != null) + settings.General.AutoGuessAnsiEncoding = Convert.ToBoolean(subNode.InnerText); + subNode = node.SelectSingleNode("SubtitleFontName"); + if (subNode != null) + settings.General.SubtitleFontName = subNode.InnerText; + subNode = node.SelectSingleNode("SubtitleFontSize"); + if (subNode != null) + settings.General.SubtitleFontSize = Convert.ToInt32(subNode.InnerText); + subNode = node.SelectSingleNode("SubtitleFontBold"); + if (subNode != null) + settings.General.SubtitleFontBold = Convert.ToBoolean(subNode.InnerText); + subNode = node.SelectSingleNode("ShowRecentFiles"); + if (subNode != null) + settings.General.ShowRecentFiles = Convert.ToBoolean(subNode.InnerText); + subNode = node.SelectSingleNode("StartLoadLastFile"); + if (subNode != null) + settings.General.StartLoadLastFile = Convert.ToBoolean(subNode.InnerText); + subNode = node.SelectSingleNode("StartRememberPositionAndSize"); + if (subNode != null) + settings.General.StartRememberPositionAndSize = Convert.ToBoolean(subNode.InnerText); + subNode = node.SelectSingleNode("StartPosition"); + if (subNode != null) + settings.General.StartPosition = subNode.InnerText; + subNode = node.SelectSingleNode("StartSize"); + if (subNode != null) + settings.General.StartSize = subNode.InnerText; + subNode = node.SelectSingleNode("StartInSourceView"); + if (subNode != null) + settings.General.StartInSourceView = Convert.ToBoolean(subNode.InnerText); + subNode = node.SelectSingleNode("RemoveBlankLinesWhenOpening"); + if (subNode != null) + settings.General.RemoveBlankLinesWhenOpening = Convert.ToBoolean(subNode.InnerText); + subNode = node.SelectSingleNode("SubtitleLineMaximumLength"); + if (subNode != null) + settings.General.SubtitleLineMaximumLength = Convert.ToInt32(subNode.InnerText); + subNode = node.SelectSingleNode("SpellCheckLanguage"); + if (subNode != null) + settings.General.SpellCheckLanguage = subNode.InnerText; + subNode = node.SelectSingleNode("VideoPlayer"); + if (subNode != null) + settings.General.VideoPlayer = subNode.InnerText; + subNode = node.SelectSingleNode("VideoPlayerDefaultVolume"); + if (subNode != null) + settings.General.VideoPlayerDefaultVolume = Convert.ToInt32(subNode.InnerText); + subNode = node.SelectSingleNode("VideoPlayerShowStopButton"); + if (subNode != null) + settings.General.VideoPlayerShowStopButton = Convert.ToBoolean(subNode.InnerText); + subNode = node.SelectSingleNode("Language"); + if (subNode != null) + settings.General.Language = subNode.InnerText; + subNode = node.SelectSingleNode("ListViewLineSeparatorString"); + if (subNode != null) + settings.General.ListViewLineSeparatorString = subNode.InnerText; + subNode = node.SelectSingleNode("ListViewDoubleClickAction"); + if (subNode != null) + settings.General.ListViewDoubleClickAction = Convert.ToInt32(subNode.InnerText); + subNode = node.SelectSingleNode("UppercaseLetters"); + if (subNode != null) + settings.General.UppercaseLetters = subNode.InnerText; + subNode = node.SelectSingleNode("DefaultAdjustMilliseconds"); + if (subNode != null) + settings.General.DefaultAdjustMilliseconds = Convert.ToInt32(subNode.InnerText); + + settings.Tools = new Nikse.SubtitleEdit.Logic.ToolsSettings(); + node = doc.DocumentElement.SelectSingleNode("Tools"); + subNode = node.SelectSingleNode("StartSceneIndex"); + if (subNode != null) + settings.Tools.StartSceneIndex = Convert.ToInt32(subNode.InnerText); + subNode = node.SelectSingleNode("EndSceneIndex"); + if (subNode != null) + settings.Tools.EndSceneIndex = Convert.ToInt32(subNode.InnerText); + subNode = node.SelectSingleNode("VerifyPlaySeconds"); + if (subNode != null) + settings.Tools.VerifyPlaySeconds = Convert.ToInt32(subNode.InnerText); + subNode = node.SelectSingleNode("MergeLinesShorterThan"); + if (subNode != null) + settings.Tools.MergeLinesShorterThan = Convert.ToInt32(subNode.InnerText); + subNode = node.SelectSingleNode("MusicSymbol"); + if (subNode != null) + settings.Tools.MusicSymbol = subNode.InnerText; + subNode = node.SelectSingleNode("MusicSymbolToReplace"); + if (subNode != null) + settings.Tools.MusicSymbolToReplace = subNode.InnerText; + subNode = node.SelectSingleNode("SpellCheckAutoChangeNames"); + if (subNode != null) + settings.Tools.SpellCheckAutoChangeNames = Convert.ToBoolean(subNode.InnerText); + + settings.SsaStyle = new Nikse.SubtitleEdit.Logic.SsaStyleSettings(); + node = doc.DocumentElement.SelectSingleNode("SsaStyle"); + subNode = node.SelectSingleNode("FontName"); + if (subNode != null) + settings.SsaStyle.FontName = subNode.InnerText; + subNode = node.SelectSingleNode("FontSize"); + if (subNode != null) + settings.SsaStyle.FontSize = Convert.ToDouble(subNode.InnerText); + subNode = node.SelectSingleNode("FontColorArgb"); + if (subNode != null) + settings.SsaStyle.FontColorArgb = Convert.ToInt32(subNode.InnerText); + + settings.Proxy = new Nikse.SubtitleEdit.Logic.ProxySettings(); + node = doc.DocumentElement.SelectSingleNode("Proxy"); + subNode = node.SelectSingleNode("ProxyAddress"); + if (subNode != null) + settings.Proxy.ProxyAddress = subNode.InnerText; + subNode = node.SelectSingleNode("UserName"); + if (subNode != null) + settings.Proxy.UserName = subNode.InnerText; + subNode = node.SelectSingleNode("Password"); + if (subNode != null) + settings.Proxy.Password = subNode.InnerText; + subNode = node.SelectSingleNode("Domain"); + if (subNode != null) + settings.Proxy.Domain = subNode.InnerText; + + settings.WordLists = new Nikse.SubtitleEdit.Logic.WordListSettings(); + node = doc.DocumentElement.SelectSingleNode("WordLists"); + subNode = node.SelectSingleNode("LastLanguage"); + if (subNode != null) + settings.WordLists.LastLanguage = subNode.InnerText; + subNode = node.SelectSingleNode("NamesEtcUrl"); + if (subNode != null) + settings.WordLists.NamesEtcUrl = subNode.InnerText; + subNode = node.SelectSingleNode("UseOnlineNamesEtc"); + if (subNode != null) + settings.WordLists.UseOnlineNamesEtc = Convert.ToBoolean(subNode.InnerText); + + settings.CommonErrors = new Nikse.SubtitleEdit.Logic.FixCommonErrorsSettings(); + node = doc.DocumentElement.SelectSingleNode("CommonErrors"); + subNode = node.SelectSingleNode("EmptyLinesTicked"); + if (subNode != null) + settings.CommonErrors.EmptyLinesTicked = Convert.ToBoolean(subNode.InnerText); + subNode = node.SelectSingleNode("OverlappingDisplayTimeTicked"); + if (subNode != null) + settings.CommonErrors.OverlappingDisplayTimeTicked = Convert.ToBoolean(subNode.InnerText); + subNode = node.SelectSingleNode("TooShortDisplayTimeTicked"); + if (subNode != null) + settings.CommonErrors.TooShortDisplayTimeTicked = Convert.ToBoolean(subNode.InnerText); + subNode = node.SelectSingleNode("TooLongDisplayTimeTicked"); + if (subNode != null) + settings.CommonErrors.TooLongDisplayTimeTicked = Convert.ToBoolean(subNode.InnerText); + subNode = node.SelectSingleNode("InvalidItalicTagsTicked"); + if (subNode != null) + settings.CommonErrors.InvalidItalicTagsTicked = Convert.ToBoolean(subNode.InnerText); + subNode = node.SelectSingleNode("BreakLongLinesTicked"); + if (subNode != null) + settings.CommonErrors.BreakLongLinesTicked = Convert.ToBoolean(subNode.InnerText); + subNode = node.SelectSingleNode("MergeShortLinesTicked"); + if (subNode != null) + settings.CommonErrors.MergeShortLinesTicked = Convert.ToBoolean(subNode.InnerText); + subNode = node.SelectSingleNode("UnneededSpacesTicked"); + if (subNode != null) + settings.CommonErrors.UnneededSpacesTicked = Convert.ToBoolean(subNode.InnerText); + subNode = node.SelectSingleNode("UnneededPeriodsTicked"); + if (subNode != null) + settings.CommonErrors.UnneededPeriodsTicked = Convert.ToBoolean(subNode.InnerText); + subNode = node.SelectSingleNode("MissingSpacesTicked"); + if (subNode != null) + settings.CommonErrors.MissingSpacesTicked = Convert.ToBoolean(subNode.InnerText); + subNode = node.SelectSingleNode("AddMissingQuotesTicked"); + if (subNode != null) + settings.CommonErrors.AddMissingQuotesTicked = Convert.ToBoolean(subNode.InnerText); + subNode = node.SelectSingleNode("Fix3PlusLinesTicked"); + if (subNode != null) + settings.CommonErrors.Fix3PlusLinesTicked = Convert.ToBoolean(subNode.InnerText); + subNode = node.SelectSingleNode("FixHyphensTicked"); + if (subNode != null) + settings.CommonErrors.FixHyphensTicked = Convert.ToBoolean(subNode.InnerText); + subNode = node.SelectSingleNode("UppercaseIInsideLowercaseWordTicked"); + if (subNode != null) + settings.CommonErrors.UppercaseIInsideLowercaseWordTicked = Convert.ToBoolean(subNode.InnerText); + subNode = node.SelectSingleNode("DoubleApostropheToQuoteTicked"); + if (subNode != null) + settings.CommonErrors.DoubleApostropheToQuoteTicked = Convert.ToBoolean(subNode.InnerText); + subNode = node.SelectSingleNode("AddPeriodAfterParagraphTicked"); + if (subNode != null) + settings.CommonErrors.AddPeriodAfterParagraphTicked = Convert.ToBoolean(subNode.InnerText); + subNode = node.SelectSingleNode("StartWithUppercaseLetterAfterParagraphTicked"); + if (subNode != null) + settings.CommonErrors.StartWithUppercaseLetterAfterParagraphTicked = Convert.ToBoolean(subNode.InnerText); + subNode = node.SelectSingleNode("StartWithUppercaseLetterAfterPeriodInsideParagraphTicked"); + if (subNode != null) + settings.CommonErrors.StartWithUppercaseLetterAfterPeriodInsideParagraphTicked = Convert.ToBoolean(subNode.InnerText); + subNode = node.SelectSingleNode("AloneLowercaseIToUppercaseIEnglishTicked"); + if (subNode != null) + settings.CommonErrors.AloneLowercaseIToUppercaseIEnglishTicked = Convert.ToBoolean(subNode.InnerText); + subNode = node.SelectSingleNode("FixOcrErrorsViaReplaceListTicked"); + if (subNode != null) + settings.CommonErrors.FixOcrErrorsViaReplaceListTicked = Convert.ToBoolean(subNode.InnerText); + subNode = node.SelectSingleNode("DanishLetterITicked"); + if (subNode != null) + settings.CommonErrors.DanishLetterITicked = Convert.ToBoolean(subNode.InnerText); + subNode = node.SelectSingleNode("SpanishInvertedQuestionAndExclamationMarksTicked"); + if (subNode != null) + settings.CommonErrors.SpanishInvertedQuestionAndExclamationMarksTicked = Convert.ToBoolean(subNode.InnerText); + subNode = node.SelectSingleNode("FixDoubleDashTicked"); + if (subNode != null) + settings.CommonErrors.FixDoubleDashTicked = Convert.ToBoolean(subNode.InnerText); + subNode = node.SelectSingleNode("FixDoubleGreaterThanTicked"); + if (subNode != null) + settings.CommonErrors.FixDoubleGreaterThanTicked = Convert.ToBoolean(subNode.InnerText); + subNode = node.SelectSingleNode("FixEllipsesStartTicked"); + if (subNode != null) + settings.CommonErrors.FixEllipsesStartTicked = Convert.ToBoolean(subNode.InnerText); + subNode = node.SelectSingleNode("FixMissingOpenBracketTicked"); + if (subNode != null) + settings.CommonErrors.FixMissingOpenBracketTicked = Convert.ToBoolean(subNode.InnerText); + subNode = node.SelectSingleNode("FixMusicNotationTicked"); + if (subNode != null) + settings.CommonErrors.FixMusicNotationTicked = Convert.ToBoolean(subNode.InnerText); + + settings.VideoControls = new VideoControlsSettings(); + node = doc.DocumentElement.SelectSingleNode("VideoControls"); + subNode = node.SelectSingleNode("CustomSearchText"); + if (subNode != null) + settings.VideoControls.CustomSearchText = subNode.InnerText; + subNode = node.SelectSingleNode("CustomSearchUrl"); + if (subNode != null) + settings.VideoControls.CustomSearchUrl = subNode.InnerText; + subNode = node.SelectSingleNode("LastActiveTab"); + if (subNode != null) + settings.VideoControls.LastActiveTab = subNode.InnerText; + subNode = node.SelectSingleNode("WaveFormDrawGrid"); + if (subNode != null) + settings.VideoControls.WaveFormDrawGrid = Convert.ToBoolean(subNode.InnerText); + subNode = node.SelectSingleNode("WaveFormGridColor"); + if (subNode != null) + settings.VideoControls.WaveFormGridColor = Color.FromArgb(int.Parse(subNode.InnerText)); + subNode = node.SelectSingleNode("WaveFormColor"); + if (subNode != null) + settings.VideoControls.WaveFormColor = Color.FromArgb(int.Parse(subNode.InnerText)); + subNode = node.SelectSingleNode("WaveFormSelectedColor"); + if (subNode != null) + settings.VideoControls.WaveFormSelectedColor = Color.FromArgb(int.Parse(subNode.InnerText)); + subNode = node.SelectSingleNode("WaveFormBackgroundColor"); + if (subNode != null) + settings.VideoControls.WaveFormBackgroundColor = Color.FromArgb(int.Parse(subNode.InnerText)); + subNode = node.SelectSingleNode("WaveFormTextColor"); + if (subNode != null) + settings.VideoControls.WaveFormTextColor = Color.FromArgb(int.Parse(subNode.InnerText)); + + + settings.VobSubOcr = new Nikse.SubtitleEdit.Logic.VobSubOcrSettings(); + node = doc.DocumentElement.SelectSingleNode("VobSubOcr"); + subNode = node.SelectSingleNode("XOrMorePixelsMakesSpace"); + if (subNode != null) + settings.VobSubOcr.XOrMorePixelsMakesSpace = Convert.ToInt32(subNode.InnerText); + subNode = node.SelectSingleNode("AllowDifferenceInPercent"); + if (subNode != null) + settings.VobSubOcr.AllowDifferenceInPercent = Convert.ToDouble(subNode.InnerText); + subNode = node.SelectSingleNode("LastImageCompareFolder"); + if (subNode != null) + settings.VobSubOcr.LastImageCompareFolder = subNode.InnerText; + subNode = node.SelectSingleNode("LastModiLanguageId"); + if (subNode != null) + settings.VobSubOcr.LastModiLanguageId = Convert.ToInt32(subNode.InnerText); + subNode = node.SelectSingleNode("LastOcrMethod"); + if (subNode != null) + settings.VobSubOcr.LastOcrMethod = subNode.InnerText; + subNode = node.SelectSingleNode("TesseractLastLanguage"); + if (subNode != null) + settings.VobSubOcr.TesseractLastLanguage = subNode.InnerText; + + foreach (XmlNode listNode in doc.DocumentElement.SelectNodes("MultipleSearchAndReplaceList/MultipleSearchAndReplaceItem")) + { + MultipleSearchAndReplaceSetting item = new MultipleSearchAndReplaceSetting(); + subNode = listNode.SelectSingleNode("Enabled"); + if (subNode != null) + item.Enabled = Convert.ToBoolean(subNode.InnerText); + subNode = listNode.SelectSingleNode("FindWhat"); + if (subNode != null) + item.FindWhat = subNode.InnerText; + subNode = listNode.SelectSingleNode("ReplaceWith"); + if (subNode != null) + item.ReplaceWith = subNode.InnerText; + subNode = listNode.SelectSingleNode("SearchType"); + if (subNode != null) + item.SearchType = subNode.InnerText; + settings.MultipleSearchAndReplaceList.Add(item); + } + + return settings; + } + + private static void CustomSerialize(string fileName, Settings settings) + { + var textWriter = new XmlTextWriter(fileName, null) {Formatting = Formatting.Indented}; + textWriter.WriteStartDocument(); + + textWriter.WriteStartElement("Settings", ""); + + textWriter.WriteStartElement("RecentFiles", ""); + textWriter.WriteStartElement("FileNames", ""); + foreach (var item in settings.RecentFiles.FileNames) + { + textWriter.WriteElementString("FileName", item); + } + textWriter.WriteEndElement(); + textWriter.WriteEndElement(); + + textWriter.WriteStartElement("General", ""); + textWriter.WriteElementString("ShowToolbarNew", settings.General.ShowToolbarNew.ToString()); + textWriter.WriteElementString("ShowToolbarOpen", settings.General.ShowToolbarOpen.ToString()); + textWriter.WriteElementString("ShowToolbarSave", settings.General.ShowToolbarSave.ToString()); + textWriter.WriteElementString("ShowToolbarSaveAs", settings.General.ShowToolbarSaveAs.ToString()); + textWriter.WriteElementString("ShowToolbarFind", settings.General.ShowToolbarFind.ToString()); + textWriter.WriteElementString("ShowToolbarReplace", settings.General.ShowToolbarReplace.ToString()); + textWriter.WriteElementString("ShowToolbarVisualSync", settings.General.ShowToolbarVisualSync.ToString()); + textWriter.WriteElementString("ShowToolbarSpellCheck", settings.General.ShowToolbarSpellCheck.ToString()); + textWriter.WriteElementString("ShowToolbarSettings", settings.General.ShowToolbarSettings.ToString()); + textWriter.WriteElementString("ShowToolbarHelp", settings.General.ShowToolbarHelp.ToString()); + textWriter.WriteElementString("ShowFrameRate", settings.General.ShowFrameRate.ToString()); + textWriter.WriteElementString("ShowVideoPlayer", settings.General.ShowVideoPlayer.ToString()); + textWriter.WriteElementString("ShowWaveForm", settings.General.ShowWaveForm.ToString()); + textWriter.WriteElementString("DefaultFrameRate", settings.General.DefaultFrameRate.ToString()); + textWriter.WriteElementString("DefaultEncoding", settings.General.DefaultEncoding); + textWriter.WriteElementString("AutoGuessAnsiEncoding", settings.General.AutoGuessAnsiEncoding.ToString()); + textWriter.WriteElementString("SubtitleFontName", settings.General.SubtitleFontName); + textWriter.WriteElementString("SubtitleFontSize", settings.General.SubtitleFontSize.ToString()); + textWriter.WriteElementString("SubtitleFontBold", settings.General.SubtitleFontBold.ToString()); + textWriter.WriteElementString("ShowRecentFiles", settings.General.ShowRecentFiles.ToString()); + textWriter.WriteElementString("StartLoadLastFile", settings.General.StartLoadLastFile.ToString()); + textWriter.WriteElementString("StartRememberPositionAndSize", settings.General.StartRememberPositionAndSize.ToString()); + textWriter.WriteElementString("StartPosition", settings.General.StartPosition); + textWriter.WriteElementString("StartSize", settings.General.StartSize); + textWriter.WriteElementString("StartInSourceView", settings.General.StartInSourceView.ToString()); + textWriter.WriteElementString("RemoveBlankLinesWhenOpening", settings.General.RemoveBlankLinesWhenOpening.ToString()); + textWriter.WriteElementString("SubtitleLineMaximumLength", settings.General.SubtitleLineMaximumLength.ToString()); + textWriter.WriteElementString("SpellCheckLanguage", settings.General.SpellCheckLanguage); + textWriter.WriteElementString("VideoPlayer", settings.General.VideoPlayer); + textWriter.WriteElementString("VideoPlayerDefaultVolume", settings.General.VideoPlayerDefaultVolume.ToString()); + textWriter.WriteElementString("VideoPlayerShowStopButton", settings.General.VideoPlayerShowStopButton.ToString()); + textWriter.WriteElementString("Language", settings.General.Language); + textWriter.WriteElementString("ListViewLineSeparatorString", settings.General.ListViewLineSeparatorString); + textWriter.WriteElementString("ListViewDoubleClickAction", settings.General.ListViewDoubleClickAction.ToString()); + textWriter.WriteElementString("UppercaseLetters", settings.General.UppercaseLetters); + textWriter.WriteElementString("DefaultAdjustMilliseconds", settings.General.DefaultAdjustMilliseconds.ToString()); + textWriter.WriteEndElement(); + + textWriter.WriteStartElement("Tools", ""); + textWriter.WriteElementString("StartSceneIndex", settings.Tools.StartSceneIndex.ToString()); + textWriter.WriteElementString("EndSceneIndex", settings.Tools.EndSceneIndex.ToString()); + textWriter.WriteElementString("VerifyPlaySeconds", settings.Tools.VerifyPlaySeconds.ToString()); + textWriter.WriteElementString("MergeLinesShorterThan", settings.Tools.MergeLinesShorterThan.ToString()); + textWriter.WriteElementString("MusicSymbol", settings.Tools.MusicSymbol); + textWriter.WriteElementString("MusicSymbolToReplace", settings.Tools.MusicSymbolToReplace); + textWriter.WriteElementString("SpellCheckAutoChangeNames", settings.Tools.SpellCheckAutoChangeNames.ToString()); + textWriter.WriteEndElement(); + + textWriter.WriteStartElement("SsaStyle", ""); + textWriter.WriteElementString("FontName", settings.SsaStyle.FontName); + textWriter.WriteElementString("FontSize", settings.SsaStyle.FontSize.ToString()); + textWriter.WriteElementString("FontColorArgb", settings.SsaStyle.FontColorArgb.ToString()); + textWriter.WriteEndElement(); + + textWriter.WriteStartElement("Proxy", ""); + textWriter.WriteElementString("ProxyAddress", settings.Proxy.ProxyAddress); + textWriter.WriteElementString("UserName", settings.Proxy.UserName); + textWriter.WriteElementString("Password", settings.Proxy.Password); + textWriter.WriteElementString("Domain", settings.Proxy.Domain); + textWriter.WriteEndElement(); + + textWriter.WriteStartElement("WordLists", ""); + textWriter.WriteElementString("LastLanguage", settings.WordLists.LastLanguage); + textWriter.WriteElementString("NamesEtcUrl", settings.WordLists.NamesEtcUrl); + textWriter.WriteElementString("UseOnlineNamesEtc", settings.WordLists.UseOnlineNamesEtc.ToString()); + textWriter.WriteEndElement(); + + textWriter.WriteStartElement("CommonErrors", ""); + textWriter.WriteElementString("EmptyLinesTicked", settings.CommonErrors.EmptyLinesTicked.ToString()); + textWriter.WriteElementString("OverlappingDisplayTimeTicked", settings.CommonErrors.OverlappingDisplayTimeTicked.ToString()); + textWriter.WriteElementString("TooShortDisplayTimeTicked", settings.CommonErrors.TooShortDisplayTimeTicked.ToString()); + textWriter.WriteElementString("TooLongDisplayTimeTicked", settings.CommonErrors.TooLongDisplayTimeTicked.ToString()); + textWriter.WriteElementString("InvalidItalicTagsTicked", settings.CommonErrors.InvalidItalicTagsTicked.ToString()); + textWriter.WriteElementString("BreakLongLinesTicked", settings.CommonErrors.BreakLongLinesTicked.ToString()); + textWriter.WriteElementString("MergeShortLinesTicked", settings.CommonErrors.MergeShortLinesTicked.ToString()); + textWriter.WriteElementString("UnneededSpacesTicked", settings.CommonErrors.UnneededSpacesTicked.ToString()); + textWriter.WriteElementString("UnneededPeriodsTicked", settings.CommonErrors.UnneededPeriodsTicked.ToString()); + textWriter.WriteElementString("MissingSpacesTicked", settings.CommonErrors.MissingSpacesTicked.ToString()); + textWriter.WriteElementString("AddMissingQuotesTicked", settings.CommonErrors.AddMissingQuotesTicked.ToString()); + textWriter.WriteElementString("Fix3PlusLinesTicked", settings.CommonErrors.Fix3PlusLinesTicked.ToString()); + textWriter.WriteElementString("FixHyphensTicked", settings.CommonErrors.FixHyphensTicked.ToString()); + textWriter.WriteElementString("UppercaseIInsideLowercaseWordTicked", settings.CommonErrors.UppercaseIInsideLowercaseWordTicked.ToString()); + textWriter.WriteElementString("DoubleApostropheToQuoteTicked", settings.CommonErrors.DoubleApostropheToQuoteTicked.ToString()); + textWriter.WriteElementString("AddPeriodAfterParagraphTicked", settings.CommonErrors.AddPeriodAfterParagraphTicked.ToString()); + textWriter.WriteElementString("StartWithUppercaseLetterAfterParagraphTicked", settings.CommonErrors.StartWithUppercaseLetterAfterParagraphTicked.ToString()); + textWriter.WriteElementString("StartWithUppercaseLetterAfterPeriodInsideParagraphTicked", settings.CommonErrors.StartWithUppercaseLetterAfterPeriodInsideParagraphTicked.ToString()); + textWriter.WriteElementString("AloneLowercaseIToUppercaseIEnglishTicked", settings.CommonErrors.AloneLowercaseIToUppercaseIEnglishTicked.ToString()); + textWriter.WriteElementString("FixOcrErrorsViaReplaceListTicked", settings.CommonErrors.FixOcrErrorsViaReplaceListTicked.ToString()); + textWriter.WriteElementString("DanishLetterITicked", settings.CommonErrors.DanishLetterITicked.ToString()); + textWriter.WriteElementString("SpanishInvertedQuestionAndExclamationMarksTicked", settings.CommonErrors.SpanishInvertedQuestionAndExclamationMarksTicked.ToString()); + textWriter.WriteElementString("FixDoubleDashTicked", settings.CommonErrors.FixDoubleDashTicked.ToString()); + textWriter.WriteElementString("FixDoubleGreaterThanTicked", settings.CommonErrors.FixDoubleGreaterThanTicked.ToString()); + textWriter.WriteElementString("FixEllipsesStartTicked", settings.CommonErrors.FixEllipsesStartTicked.ToString()); + textWriter.WriteElementString("FixMissingOpenBracketTicked", settings.CommonErrors.FixMissingOpenBracketTicked.ToString()); + textWriter.WriteElementString("FixMusicNotationTicked", settings.CommonErrors.FixMusicNotationTicked.ToString()); + textWriter.WriteEndElement(); + + textWriter.WriteStartElement("VideoControls", ""); + textWriter.WriteElementString("CustomSearchText", settings.VideoControls.CustomSearchText); + textWriter.WriteElementString("CustomSearchUrl", settings.VideoControls.CustomSearchUrl); + textWriter.WriteElementString("LastActiveTab", settings.VideoControls.LastActiveTab); + + textWriter.WriteElementString("WaveFormDrawGrid", settings.VideoControls.WaveFormDrawGrid.ToString()); + textWriter.WriteElementString("WaveFormGridColor", settings.VideoControls.WaveFormGridColor.ToArgb().ToString()); + textWriter.WriteElementString("WaveFormColor", settings.VideoControls.WaveFormColor.ToArgb().ToString()); + textWriter.WriteElementString("WaveFormSelectedColor", settings.VideoControls.WaveFormSelectedColor.ToArgb().ToString()); + textWriter.WriteElementString("WaveFormBackgroundColor", settings.VideoControls.WaveFormBackgroundColor.ToArgb().ToString()); + textWriter.WriteElementString("WaveFormTextColor", settings.VideoControls.WaveFormTextColor.ToArgb().ToString()); + textWriter.WriteEndElement(); + + textWriter.WriteStartElement("VobSubOcr", ""); + textWriter.WriteElementString("XOrMorePixelsMakesSpace", settings.VobSubOcr.XOrMorePixelsMakesSpace.ToString()); + textWriter.WriteElementString("AllowDifferenceInPercent", settings.VobSubOcr.AllowDifferenceInPercent.ToString()); + textWriter.WriteElementString("LastImageCompareFolder", settings.VobSubOcr.LastImageCompareFolder); + textWriter.WriteElementString("LastModiLanguageId", settings.VobSubOcr.LastModiLanguageId.ToString()); + textWriter.WriteElementString("LastOcrMethod", settings.VobSubOcr.LastOcrMethod); + textWriter.WriteElementString("TesseractLastLanguage", settings.VobSubOcr.TesseractLastLanguage); + textWriter.WriteEndElement(); + + textWriter.WriteStartElement("MultipleSearchAndReplaceList", ""); + foreach (var item in settings.MultipleSearchAndReplaceList) + { + textWriter.WriteStartElement("MultipleSearchAndReplaceItem", ""); + textWriter.WriteElementString("Enabled", item.Enabled.ToString()); + textWriter.WriteElementString("FindWhat", item.FindWhat); + textWriter.WriteElementString("ReplaceWith", item.ReplaceWith); + textWriter.WriteElementString("SearchType", item.SearchType); + textWriter.WriteEndElement(); + } + textWriter.WriteEndElement(); + + textWriter.WriteEndElement(); + + textWriter.WriteEndDocument(); + textWriter.Close(); + } + + } +} diff --git a/src/Logic/StripableText.cs b/src/Logic/StripableText.cs new file mode 100644 index 000000000..e25afa665 --- /dev/null +++ b/src/Logic/StripableText.cs @@ -0,0 +1,241 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Nikse.SubtitleEdit.Logic +{ + + public class StripableText + { + public string Pre { get; set; } + public string Post { get; set; } + public string StrippedText { get; set; } + public string OriginalText { get; private set; } + private string _stripStartCharacters; + private string _stripEndCharacters; + + public string MergedString + { + get { return Pre + StrippedText + Post; } + } + + public StripableText(string text) + : this(text, " >-\"['‘`´¶(♪¿¡.", " -\"]'`´¶)♪.!?:") + { + } + + public StripableText(string text, string stripStartCharacters, string stripEndCharacters) + { + _stripStartCharacters = stripStartCharacters; + _stripEndCharacters = stripEndCharacters; + OriginalText = text; + + Pre = string.Empty; + if (text.Length > 0 && !Utilities.GetLetters(true, true, true).Contains(text[0].ToString())) + { + for (int i = 0; i < 5; i++) + { + while (text.Length > 1 && _stripStartCharacters.Contains(text.Substring(0, 1))) + { + Pre += text.Substring(0, 1); + text = text.Substring(1); + } + + // tags like or + if (text.StartsWith("<") && text.IndexOf(">") <= 21) + { + int index = text.IndexOf(">") + 1; + Pre += text.Substring(0, index); + text = text.Substring(index); + } + } + } + + Post = string.Empty; + if (text.Length > 0 && !Utilities.GetLetters(true, true, true).Contains(text[text.Length - 1].ToString())) + { + for (int i = 0; i < 5; i++) + { + while (text.Length > 1 && _stripEndCharacters.Contains(text.Substring(text.Length - 1, 1))) + { + Post = text.Substring(text.Length - 1, 1) + Post; + text = text.Substring(0, text.Length - 1); + } + + // tags + if (text.ToLower().EndsWith("
") || + text.ToLower().EndsWith("") || + text.ToLower().EndsWith("")) + { + Post = text.Substring(text.Length - 4, 4) + Post; + text = text.Substring(0, text.Length - 4); + } + + // tag + if (text.ToLower().EndsWith("")) + { + Post = text.Substring(text.Length - 7, 7) + Post; + text = text.Substring(0, text.Length - 7); + } + } + } + + StrippedText = text; + } + + private static string GetAndInsertNextId(List replaceIds, List replaceNames, string name) + { + int i = 0; + string id = string.Format("_@{0}_", i); + while (replaceIds.Contains(id)) + { + i++; + id = string.Format("_@{0}_", i); + } + replaceIds.Add(id); + replaceNames.Add(name); + return id; + } + + private void ReplaceNames1Remove(List namesEtc, List replaceIds, List replaceNames, List originalNames) + { + if (Post.StartsWith(".")) + { + StrippedText += "."; + Post = Post.Remove(0, 1); + } + + string lower = StrippedText.ToLower(); + + foreach (string name in namesEtc) + { + int start = lower.IndexOf(name.ToLower()); + while (start >= 0 && start < lower.Length) + { + bool startOk = (start == 0) || (lower[start - 1] == ' ') || (lower[start - 1] == '-') || + (lower[start - 1] == '"') || (lower[start - 1] == '\'') || (lower[start - 1] == '>') || + (Environment.NewLine.EndsWith(lower[start - 1].ToString())); + + if (startOk) + { + int end = start + name.Length; + bool endOk = end <= lower.Length; + if (endOk) + endOk = (end == lower.Length) || ((" ,.!?:;')- <\"" + Environment.NewLine).Contains(lower[end].ToString())); + + if (endOk && StrippedText.Length >= start + name.Length) + { + string orginalName = StrippedText.Substring(start, name.Length); + originalNames.Add(orginalName); + StrippedText = StrippedText.Remove(start, name.Length); + StrippedText = StrippedText.Insert(start, GetAndInsertNextId(replaceIds, replaceNames, name)); + lower = StrippedText.ToLower(); + } + } + start = lower.IndexOf(name.ToLower(), start +3); + } + } + + if (StrippedText.EndsWith(".")) + { + Post = "." + Post; + StrippedText = StrippedText.TrimEnd('.'); + } + } + + private void ReplaceNames2Fix(List replaceIds, List replaceNames) + { + for (int i=0; i namesEtc, bool changeNameCases, bool makeUppercaseAfterBreak, bool checkLastLine, string lastLine) + { + var replaceIds = new List(); + var replaceNames = new List(); + var originalNames = new List(); + ReplaceNames1Remove(namesEtc, replaceIds, replaceNames, originalNames); + + if (checkLastLine) + { + string s = Utilities.RemoveHtmlTags(lastLine).TrimEnd().TrimEnd('\"').TrimEnd(); + + + bool startWithUppercase = string.IsNullOrEmpty(s) || + s.EndsWith(".") || + s.EndsWith("!") || + s.EndsWith("?") || + s.EndsWith("]") || + s.EndsWith(")") || + s.EndsWith(":"); + + if (startWithUppercase && StrippedText.Length > 0) + { + StrippedText = StrippedText.Remove(0, 1).Insert(0, StrippedText[0].ToString().ToUpper()); + } + } + + if (makeUppercaseAfterBreak && + (StrippedText.Contains(".") || + StrippedText.Contains("!") || + StrippedText.Contains("?") || + StrippedText.Contains(":") || + StrippedText.Contains(";") || + StrippedText.Contains(")") || + StrippedText.Contains("]") || + StrippedText.Contains("}") || + StrippedText.Contains("(") || + StrippedText.Contains("[") || + StrippedText.Contains("{"))) + { + var sb = new StringBuilder(); + bool lastWasBreak = false; + for (int i=0; i!?.- " + Environment.NewLine).Contains(s)) + { + sb.Append(s); + } + else if ((sb.ToString().EndsWith("<") || sb.ToString().EndsWith("') + { // tags + sb.Append(s); + } + else if (sb.ToString().EndsWith("<") && s == "/" && i + 2 < StrippedText.Length && StrippedText[i + 2] == '>') + { // tags + sb.Append(s); + } + else if (sb.ToString().EndsWith("... ")) + { + sb.Append(s); + lastWasBreak = false; + } + else + { + lastWasBreak = false; + sb.Append(s.ToUpper()); + } + } + else + { + + sb.Append(s); + if (".!?:;)]}([{".Contains(s)) + lastWasBreak = true; + } + } + StrippedText = sb.ToString(); + } + + if (changeNameCases) + ReplaceNames2Fix(replaceIds, replaceNames); + else + ReplaceNames2Fix(replaceIds, originalNames); + } + + } +} \ No newline at end of file diff --git a/src/Logic/Subtitle.cs b/src/Logic/Subtitle.cs new file mode 100644 index 000000000..f83d5764f --- /dev/null +++ b/src/Logic/Subtitle.cs @@ -0,0 +1,397 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Text; +using Nikse.SubtitleEdit.Logic.SubtitleFormats; +using Nikse.SubtitleEdit.Logic.Enums; + +namespace Nikse.SubtitleEdit.Logic +{ + public class Subtitle + { + List _paragraphs; + List _history; + SubtitleFormat _format; + bool _wasLoadedWithFrameNumbers; + public string Header { get; set; } + + public string FileName { get; set; } + + public SubtitleFormat OriginalFormat + { + get + { + return _format; + } + } + + public List HistoryItems + { + get { return _history; } + } + + public Subtitle() + { + _paragraphs = new List(); + _history = new List(); + FileName = "Untitled"; + } + + public Subtitle(List historyItems) : this() + { + _history = historyItems; + } + + /// + /// Copy constructor (only paragraphs) + /// + /// Subtitle to copy + public Subtitle(Subtitle subtitle) : this() + { + foreach (Paragraph p in subtitle.Paragraphs) + { + _paragraphs.Add(new Paragraph(p)); + } + _wasLoadedWithFrameNumbers = subtitle.WasLoadedWithFrameNumbers; + } + + public List Paragraphs + { + get + { + return _paragraphs; + } + } + + public Paragraph GetParagraphOrDefault(int index) + { + if (_paragraphs == null || _paragraphs.Count <= index || index < 0) + return null; + + return _paragraphs[index]; + } + + public SubtitleFormat ReloadLoadSubtitle(List lines, string fileName) + { + foreach (SubtitleFormat subtitleFormat in SubtitleFormat.AllSubtitleFormats) + { + if (subtitleFormat.IsMine(lines, fileName)) + { + subtitleFormat.LoadSubtitle(this, lines, fileName); + _format = subtitleFormat; + return subtitleFormat; + } + } + return null; + } + + public SubtitleFormat LoadSubtitle(string fileName, out Encoding encoding, Encoding useThisEncoding) + { + FileName = fileName; + + _paragraphs = new List(); + + var lines = new List(); + StreamReader sr; + if (useThisEncoding != null) + sr = new StreamReader(fileName, useThisEncoding); + else + sr = new StreamReader(fileName, Utilities.GetEncodingFromFile(fileName), true); + + encoding = sr.CurrentEncoding; + while (!sr.EndOfStream) + lines.Add(sr.ReadLine()); + sr.Close(); + + foreach (SubtitleFormat subtitleFormat in SubtitleFormat.AllSubtitleFormats) + { + if (subtitleFormat.IsMine(lines, fileName)) + { + subtitleFormat.LoadSubtitle(this, lines, fileName); + _format = subtitleFormat; + _wasLoadedWithFrameNumbers = _format.IsFrameBased; + return subtitleFormat; + } + } + return null; + } + + public void MakeHistoryForUndo(string description, SubtitleFormat subtitleFormat, DateTime fileModified) + { + // don't fill memory with history - use a max rollback points + if (_history.Count > 50) + _history.RemoveAt(0); + + _history.Add(new HistoryItem(_history.Count, this, description, FileName, fileModified, subtitleFormat.FriendlyName)); + } + + public bool CanUndo + { + get + { + return _history.Count > 0; + } + } + + public void UndoLast() + { + string subtitleFormatFriendlyName; + DateTime fileModified; + UndoHistory(_history.Count - 1, out subtitleFormatFriendlyName, out fileModified); + } + + public string UndoHistory(int index, out string subtitleFormatFriendlyName, out DateTime fileModified) + { + _paragraphs.Clear(); + foreach (Paragraph p in _history[index].Subtitle.Paragraphs) + _paragraphs.Add(new Paragraph(p)); + + subtitleFormatFriendlyName = _history[index].SubtitleFormatFriendlyName; + FileName = _history[index].FileName; + fileModified = _history[index].FileModified; + return FileName; + } + + internal string ToText(SubtitleFormat format) + { + return format.ToText(this, Path.GetFileNameWithoutExtension(FileName)); + } + + public void AddTimeToAllParagraphs(TimeSpan time) + { + foreach (Paragraph p in Paragraphs) + { + p.StartTime.AddTime(time); + p.EndTime.AddTime(time); + } + } + + /// + /// Calculate the time codes from framenumber/framerate + /// + /// Number of frames per second + /// True if times could be calculated + public bool CalculateTimeCodesFromFrameNumbers(double frameRate) + { + if (_format == null) + return false; + + if (_format.IsTimeBased) + return false; + + foreach (Paragraph p in Paragraphs) + { + p.CalculateTimeCodesFromFrameNumbers(frameRate); + } + return true; + } + + /// + /// Calculate the frame numbers from time codes/framerate + /// + /// + /// + public bool CalculateFrameNumbersFromTimeCodes(double frameRate) + { + if (_format == null) + return false; + + if (_format.IsFrameBased) + return false; + + foreach (Paragraph p in Paragraphs) + { + p.CalculateFrameNumbersFromTimeCodes(frameRate); + } + + FixEqualOrJustOverlappingFrameNumbers(); + + return true; + } + + public void CalculateFrameNumbersFromTimeCodesNoCheck(double frameRate) + { + foreach (Paragraph p in Paragraphs) + p.CalculateFrameNumbersFromTimeCodes(frameRate); + + FixEqualOrJustOverlappingFrameNumbers(); + } + + private void FixEqualOrJustOverlappingFrameNumbers() + { + for (int i = 0; i < Paragraphs.Count - 1; i++) + { + Paragraph p = Paragraphs[i]; + Paragraph next = Paragraphs[i + 1]; + if (next != null && p.EndFrame == next.StartFrame || p.EndFrame == next.StartFrame + 1) + p.EndFrame = next.StartFrame - 1; + } + } + + internal void ChangeFramerate(double oldFramerate, double newFramerate) + { + foreach (Paragraph p in Paragraphs) + { + p.CalculateFrameNumbersFromTimeCodes(oldFramerate); + p.CalculateTimeCodesFromFrameNumbers(newFramerate); + } + } + + public bool WasLoadedWithFrameNumbers + { + get + { + return _wasLoadedWithFrameNumbers; + } + set + { + _wasLoadedWithFrameNumbers = value; + } + } + + internal void AdjustDisplayTimeUsingPercent(double percent, System.Windows.Forms.ListView.SelectedIndexCollection selectedIndexes) + { + for (int i = 0; i < _paragraphs.Count; i++) + { + if (selectedIndexes == null || selectedIndexes.Contains(i)) + { + double nextStartMilliseconds = _paragraphs[_paragraphs.Count - 1].EndTime.TotalMilliseconds + 100000; + if (i + 1 < _paragraphs.Count) + nextStartMilliseconds = _paragraphs[i + 1].StartTime.TotalMilliseconds; + + double newEndMilliseconds = _paragraphs[i].EndTime.TotalMilliseconds; + newEndMilliseconds = _paragraphs[i].StartTime.TotalMilliseconds + (((newEndMilliseconds - _paragraphs[i].StartTime.TotalMilliseconds) * percent) / 100); + if (newEndMilliseconds > nextStartMilliseconds) + newEndMilliseconds = nextStartMilliseconds - 1; + _paragraphs[i].EndTime.TotalMilliseconds = newEndMilliseconds; + } + } + } + + internal void AdjustDisplayTimeUsingSeconds(double seconds, System.Windows.Forms.ListView.SelectedIndexCollection selectedIndexes) + { + for (int i = 0; i < _paragraphs.Count; i++) + { + if (selectedIndexes == null || selectedIndexes.Contains(i)) + { + double nextStartMilliseconds = _paragraphs[_paragraphs.Count - 1].EndTime.TotalMilliseconds + 100000; + if (i + 1 < _paragraphs.Count) + nextStartMilliseconds = _paragraphs[i + 1].StartTime.TotalMilliseconds; + + double newEndMilliseconds = _paragraphs[i].EndTime.TotalMilliseconds + (seconds * 1000.0); + if (newEndMilliseconds > nextStartMilliseconds) + newEndMilliseconds = nextStartMilliseconds - 1; + _paragraphs[i].EndTime.TotalMilliseconds = newEndMilliseconds; + } + } + } + + internal void Renumber(int startNumber) + { + int i = startNumber; + foreach (Paragraph p in _paragraphs) + { + p.Number = i; + i++; + } + } + + internal int GetIndex(Paragraph p) + { + return _paragraphs.IndexOf(p); + } + + internal Paragraph GetFirstParagraphByLineNumber(int number) + { + foreach (Paragraph p in _paragraphs) + { + if (p.Number == number) + return p; + } + return null; + } + + internal int RemoveEmptyLines() + { + int count = 0; + if (_paragraphs.Count > 0) + { + int firstNumber = _paragraphs[0].Number; + for (int i = _paragraphs.Count - 1; i >= 0; i--) + { + Paragraph p = _paragraphs[i]; + string s = p.Text.Trim(); + + if (s.Length == 0) + { + _paragraphs.RemoveAt(i); + count++; + } + } + Renumber(firstNumber); + } + return count; + } + + /// + /// Sort subtitle paragraphs + /// + /// Paragraph sort criteria + public void Sort(SubtitleSortCriteria sortCriteria) + { + switch (sortCriteria) + { + case SubtitleSortCriteria.Number: + _paragraphs.Sort(delegate(Paragraph p1, Paragraph p2) + { + return p1.Number.CompareTo(p2.Number); + }); + break; + case SubtitleSortCriteria.StartTime: + _paragraphs.Sort(delegate(Paragraph p1, Paragraph p2) + { + return p1.StartTime.TotalMilliseconds.CompareTo(p2.StartTime.TotalMilliseconds); + }); + break; + case SubtitleSortCriteria.EndTime: + _paragraphs.Sort(delegate(Paragraph p1, Paragraph p2) + { + return p1.EndTime.TotalMilliseconds.CompareTo(p2.EndTime.TotalMilliseconds); + }); + break; + case SubtitleSortCriteria.Duration: + _paragraphs.Sort(delegate(Paragraph p1, Paragraph p2) + { + return p1.Duration.TotalMilliseconds.CompareTo(p2.Duration.TotalMilliseconds); + }); + break; + case SubtitleSortCriteria.Text: + _paragraphs.Sort(delegate(Paragraph p1, Paragraph p2) + { + return p1.Text.CompareTo(p2.Text); + }); + break; + case SubtitleSortCriteria.TextMaxLineLength: + _paragraphs.Sort(delegate(Paragraph p1, Paragraph p2) + { + return Utilities.GetMaxLineLength(p1.Text).CompareTo(Utilities.GetMaxLineLength(p2.Text)); + }); + break; + case SubtitleSortCriteria.TextTotalLength: + _paragraphs.Sort(delegate(Paragraph p1, Paragraph p2) + { + return p1.Text.Length.CompareTo(p2.Text.Length); + }); + break; + case SubtitleSortCriteria.TextNumberOfLines: + _paragraphs.Sort(delegate(Paragraph p1, Paragraph p2) + { + return p1.NumberOfLines.CompareTo(p2.NumberOfLines); + }); + break; + default: + break; + } + } + } +} diff --git a/src/Logic/TimeCode.cs b/src/Logic/TimeCode.cs new file mode 100644 index 000000000..4c3c05d87 --- /dev/null +++ b/src/Logic/TimeCode.cs @@ -0,0 +1,125 @@ +using System; + +namespace Nikse.SubtitleEdit.Logic +{ + public class TimeCode + { + TimeSpan _time; + + public static double ParseToMilliseconds(string text) + { + string[] parts = text.Split(":,.".ToCharArray(), StringSplitOptions.RemoveEmptyEntries); + if (parts.Length == 4) + { + int hours; + int minutes; + int seconds; + int milliseconds; + if (int.TryParse(parts[0], out hours) && int.TryParse(parts[1], out minutes) && int.TryParse(parts[2], out seconds) && int.TryParse(parts[3], out milliseconds)) + { + TimeSpan ts = new TimeSpan(0, hours, minutes, seconds, milliseconds); + return ts.TotalMilliseconds; + } + } + return 0; + } + + public TimeCode(TimeSpan timeSpan) + { + TimeSpan = timeSpan; + } + + public TimeCode(int hour, int minute, int seconds, int milliseconds) + { + _time = new TimeSpan(0, hour, minute, seconds, milliseconds); + } + + public int Hours + { + get { return _time.Hours; } + set { _time = new TimeSpan(0, value, _time.Minutes, _time.Seconds, _time.Milliseconds); } + } + + public int Minutes + { + get { return _time.Minutes; } + set { _time = new TimeSpan(0, _time.Hours, value, _time.Seconds, _time.Milliseconds); } + } + + public int Seconds + { + get { return _time.Seconds; } + set { _time = new TimeSpan(0, _time.Hours, _time.Minutes, value, _time.Milliseconds); } + } + + public int Milliseconds + { + get { return _time.Milliseconds; } + set { _time = new TimeSpan(0, _time.Hours, _time.Minutes, _time.Seconds, value); } + } + + public double TotalMilliseconds + { + get { return _time.TotalMilliseconds; } + set { _time = TimeSpan.FromMilliseconds(value); } + } + + public double TotalSeconds + { + get { return _time.TotalSeconds; } + set { _time = TimeSpan.FromSeconds(value); } + } + + public TimeSpan TimeSpan + { + get + { + return _time; + } + set + { + _time = value; + } + } + + public void AddTime(int hour, int minutes, int seconds, int milliseconds) + { + Hours += hour; + Minutes += minutes; + Seconds += seconds; + Milliseconds += milliseconds; + } + + + public void AddTime(long milliseconds) + { + _time = TimeSpan.FromMilliseconds(_time.TotalMilliseconds + milliseconds); + } + + public void AddTime(TimeSpan timeSpan) + { + _time = TimeSpan.FromMilliseconds(_time.TotalMilliseconds + timeSpan.TotalMilliseconds); + } + + public void AddTime(double milliseconds) + { + _time = TimeSpan.FromMilliseconds(_time.TotalMilliseconds + milliseconds); + } + + public override string ToString() + { + return string.Format("{0:00}:{1:00}:{2:00},{3:000}", _time.Hours, _time.Minutes, _time.Seconds, _time.Milliseconds); + } + + public string ToShortString() + { + if (_time.Minutes == 0 && _time.Hours == 0) + return string.Format("{0:00},{1:000}", _time.Seconds, _time.Milliseconds); + else if (_time.Hours == 0) + return string.Format("{0:00}:{1:00},{2:000}", _time.Minutes, _time.Seconds, _time.Milliseconds); + else + return string.Format("{0:00}:{1:00}:{2:00},{3:000}", _time.Hours, _time.Minutes, _time.Seconds, _time.Milliseconds); + } + + } +} diff --git a/src/Logic/Utilities.cs b/src/Logic/Utilities.cs new file mode 100644 index 000000000..0f614bfb4 --- /dev/null +++ b/src/Logic/Utilities.cs @@ -0,0 +1,1335 @@ +using System; +using System.Collections.Generic; +using System.Globalization; +using System.IO; +using System.Net; +using System.Reflection; +using System.Text; +using System.Text.RegularExpressions; +using System.Windows.Forms; +using System.Xml; +using Nikse.SubtitleEdit.Controls; +using Nikse.SubtitleEdit.Forms; +using Nikse.SubtitleEdit.Logic.SubtitleFormats; +using Nikse.SubtitleEdit.Logic.VideoPlayers; + +namespace Nikse.SubtitleEdit.Logic +{ + public static class Utilities + { + public static VideoInfo GetVideoInfo(string fileName, EventHandler event1) + { + VideoInfo info = TryReadVideoInfoViaAviHeader(fileName); + if (info.Success) + return info; + + info = TryReadVideoInfoViaMatroskaHeader(fileName); + if (info.Success) + return info; + + info = TryReadVideoInfoViaDirectShow(fileName); + if (info.Success) + return info; + + if (IsWmpAvailable) + return TryReadVideoInfoViaMediaPlayer(fileName, event1); + + return new VideoInfo { VideoCodec = "Unknown" }; + } + + private static VideoInfo TryReadVideoInfoViaDirectShow(string fileName) + { + return QuartsPlayer.GetVideoInfo(fileName); + } + + private static VideoInfo TryReadVideoInfoViaMatroskaHeader(string fileName) + { + var info = new VideoInfo { Success = false }; + + try + { + bool hasConstantFrameRate = false; + bool success = false; + double frameRate = 0; + int width = 0; + int height = 0; + double milliseconds = 0; + string videoCodec = string.Empty; + + var matroskaParser = new Matroska(); + matroskaParser.GetMatroskaInfo(fileName, ref success, ref hasConstantFrameRate, ref frameRate, ref width, ref height, ref milliseconds, ref videoCodec); + if (success) + { + info.Width = width; + info.Height = height; + info.FramesPerSecond = frameRate; + info.Success = true; + info.TotalMilliseconds = milliseconds; + info.TotalSeconds = milliseconds / 1000.0; + info.TotalFrames = info.TotalSeconds * frameRate; + info.VideoCodec = videoCodec; + } + } + catch (Exception exception) + { + MessageBox.Show(exception.Message); + } + return info; + } + + private static VideoInfo TryReadVideoInfoViaMediaPlayer(string fileName, EventHandler doEvents) + { + var info = new VideoInfo { Success = false }; + + try + { + var player = new WMPLib.WindowsMediaPlayer { URL = fileName }; + + player.controls.play(); + + int i = 0; + while (i < 100 && player.openState != WMPLib.WMPOpenState.wmposMediaOpen) + { + i++; + System.Threading.Thread.Sleep(100); + if (doEvents != null) + doEvents.Invoke(null, null); + } + + info.TotalSeconds = player.currentMedia.duration; + info.TotalMilliseconds = player.currentMedia.duration * 1000; + + info.Width = player.currentMedia.imageSourceWidth; + info.Height = player.currentMedia.imageSourceHeight; + info.FramesPerSecond = player.network.encodedFrameRate; + + player.controls.stop(); + player.close(); + info.Success = true; + } + catch + { + } + return info; + } + + private static VideoInfo TryReadVideoInfoViaAviHeader(string fileName) + { + var info = new VideoInfo { Success = false }; + + try + { + var rp = new RiffParser(); + var dh = new RiffDecodeHeader(rp); + rp.OpenFile(fileName); + info.FileType = RiffParser.FromFourCC(rp.FileType); + if (RiffParser.ckidAVI == rp.FileType) + { + dh.ProcessMainAVI(); + info.Width = dh.Width; + info.Height = dh.Height; + info.FramesPerSecond = dh.FrameRate; + info.TotalFrames = dh.TotalFrames; + info.TotalMilliseconds = dh.TotalMilliseconds; + info.VideoCodec = dh.VideoHandler; + info.Success = true; + } + } + catch + { + } + return info; + } + + public static IEnumerable GetMovieFileExtensions() + { + return new List { ".avi", ".mkv", ".wmv", ".mpg", ".mpeg", ".divx", ".mp4", ".asf", ".flv" }; + } + + public static string GetVideoFileFilter() + { + var sb = new StringBuilder(); + sb.Append(Configuration.Settings.Language.General.VideoFiles + "|"); + int i = 0; + foreach (string extension in GetMovieFileExtensions()) + { + if (i > 0) + sb.Append(";"); + sb.Append("*" + extension); + i++; + } + sb.Append("|" + Configuration.Settings.Language.General.AllFiles + "|*.*"); + return sb.ToString(); + } + + public static bool IsInteger(string s) + { + int i; + if (int.TryParse(s, out i)) + return true; + return false; + } + + internal static SubtitleFormat GetSubtitleFormatByFriendlyName(string friendlyName) + { + foreach (SubtitleFormat format in SubtitleFormat.AllSubtitleFormats) + { + if (format.FriendlyName == friendlyName) + return format; + } + return null; + } + + public static string FormatBytesToDisplayFileSize(long fileSize) + { + { + if (fileSize <= 1024) + return string.Format("{0} bytes", fileSize); + if (fileSize <= 1024 * 1024) + return string.Format("{0} kb", fileSize / 1024); + if (fileSize <= 1024 * 1024 * 1024) + return string.Format("{0:0.0} mb", (float)fileSize / (1024 * 1024)); + return string.Format("{0:0.0} gb", (float)fileSize / (1024 * 1024 * 1024)); + } + } + + public static int ShowSubtitle(List paragraphs, Label labelSubtitle, VideoPlayer mediaPlayer) + { + int index = 0; + if (mediaPlayer != null) + { + double positionInMilliseconds = mediaPlayer.CurrentPosition * 1000.0; + string text = string.Empty; + foreach (Paragraph p in paragraphs) + { + if (p.StartTime.TotalMilliseconds <= positionInMilliseconds && + p.EndTime.TotalMilliseconds > positionInMilliseconds) + { + text = p.Text.Replace("|", Environment.NewLine); + break; + } + index++; + } + if (index == paragraphs.Count) + index = -1; + + if (labelSubtitle.Text != text) + { + labelSubtitle.Text = text; + return index; + } + } + return -1; + } + + public static string ReadTextFileViaUrlAndProxyIfAvailable(string url) + { + var wc = new WebClient {Proxy = GetProxy()}; + var ms = new MemoryStream(wc.DownloadData(url)); + var reader = new StreamReader(ms); + return reader.ReadToEnd().Trim(); + } + + public static WebProxy GetProxy() + { + if (!string.IsNullOrEmpty(Configuration.Settings.Proxy.ProxyAddress)) + { + var proxy = new WebProxy(Configuration.Settings.Proxy.ProxyAddress); + + if (!string.IsNullOrEmpty(Configuration.Settings.Proxy.UserName)) + { + if (string.IsNullOrEmpty(Configuration.Settings.Proxy.Domain)) + proxy.Credentials = new NetworkCredential(Configuration.Settings.Proxy.UserName, Configuration.Settings.Proxy.DecodePassword()); + else + proxy.Credentials = new NetworkCredential(Configuration.Settings.Proxy.UserName, Configuration.Settings.Proxy.DecodePassword(), Configuration.Settings.Proxy.Domain); + } + else + proxy.UseDefaultCredentials = true; + + return proxy; + } + return null; + } + + private static bool IsPartOfNumber(string s, int position) + { + if (",.".Contains(s[position].ToString())) + { + if (position > 0 && position < s.Length-1) + { + return "1234567890".Contains(s[position-1].ToString()) && "1234567890".Contains(s[position+1].ToString()); + } + } + return false; + } + + public static string AutoBreakLine(string text) + { + return AutoBreakLine(text, 5); + } + + public static string AutoBreakLine(string text, int mininumLength) + { + if (text.Length < 5) + return text; + + string temp = RemoveHtmlTags(text); + temp = temp.TrimEnd("!?.:;".ToCharArray()); + if (text.Length < 40 && !temp.Contains(".") && !temp.Contains("!") && !temp.Contains("?")) + { + text = text.Replace(Environment.NewLine, " "); + text = text.Replace(" ", " "); + text = text.Replace(" ", " "); + return text; + } + + string s = text.Replace(Environment.NewLine, " "); + s = s.Replace(" ", " "); + s = s.Replace(" ", " "); + int splitPos = -1; + int mid = s.Length / 2; + + if (splitPos == -1) + { + for (int j = 0; j < 15; j++) + { + if (mid + j + 1 < s.Length && mid + j > 0) + { + if (".!?".Contains(s[mid + j].ToString()) && !IsPartOfNumber(s, mid + j)) + { + splitPos = mid + j + 1; + if (".!?0123456789".Contains(s[splitPos].ToString())) + { // do not break double/tripple end lines like "!!!" or "..." + splitPos++; + if (".!?0123456789".Contains(s[mid + j + 1].ToString())) + splitPos++; + } + break; + } + if (".!?".Contains(s[mid - j].ToString()) && !IsPartOfNumber(s, mid - j)) + { + splitPos = mid - j; + splitPos++; + break; + } + } + } + } + + if (splitPos == -1) + { + for (int j = 0; j < 25; j++) + { + if (mid + j + 1 < s.Length && mid + j > 0) + { + if (".!?, ".Contains(s[mid + j].ToString()) && !IsPartOfNumber(s, mid + j)) + { + splitPos = mid + j; + if (" .!?".Contains(s[mid + j + 1].ToString())) + { + splitPos++; + if (" .!?".Contains(s[mid + j + 2].ToString())) + splitPos++; + } + break; + } + if (".!?, ".Contains(s[mid - j].ToString()) && !IsPartOfNumber(s, mid - j)) + { + splitPos = mid - j; + if (".!?".Contains(s[mid - (j + 1)].ToString())) + { + splitPos--; + if (".!?".Contains(s[mid + (j + 2)].ToString())) + splitPos--; + } + break; + } + } + } + } + + if (splitPos == -1) + { + splitPos = mid; + s = s.Insert(mid - 1, "-"); + } + if (splitPos < s.Length-2) + s = s.Substring(0, splitPos).TrimEnd() + Environment.NewLine + s.Substring(splitPos).Trim(); + return s.TrimEnd(); + } + + public static string UnbreakLine(string text) + { + if (text.Contains(Environment.NewLine)) + { + string newText = text.Replace(Environment.NewLine, " "); + while (newText.Contains(" ")) + newText = newText.Replace(" ", " "); + return newText; + } + return text; + } + + public static void InitializeSubtitleFont(Control control) + { + var gs = Configuration.Settings.General; + + if (string.IsNullOrEmpty(gs.SubtitleFontName)) + gs.SubtitleFontName = "Microsoft Sans Serif"; + + if (gs.SubtitleFontBold) + control.Font = new System.Drawing.Font(gs.SubtitleFontName, gs.SubtitleFontSize, System.Drawing.FontStyle.Bold); + else + control.Font = new System.Drawing.Font(gs.SubtitleFontName, gs.SubtitleFontSize); + } + + public static string RemoveHtmlTags(string s) + { + s = s.Replace("", string.Empty); + s = s.Replace("", string.Empty); + s = s.Replace("", string.Empty); + s = s.Replace("", string.Empty); + s = s.Replace("", string.Empty); + s = s.Replace("", string.Empty); + s = s.Replace("", string.Empty); + s = s.Replace("", string.Empty); + s = s.Replace("", string.Empty); + s = s.Replace("", string.Empty); + s = s.Replace("", string.Empty); + s = s.Replace("", string.Empty); + return RemoveHtmlFontTag(s); + } + + internal static string RemoveHtmlFontTag(string s) + { + s = s.Replace("", string.Empty); + s = s.Replace("", string.Empty); + s = s.Replace("", string.Empty); + s = s.Replace("", string.Empty); + s = s.Replace("", string.Empty); + s = s.Replace("", string.Empty); + while (s.ToLower().Contains(""), startIndex + 4); + s = s.Remove(startIndex, (endIndex - startIndex) + 1); + } + return s; + } + + public static Encoding GetEncodingFromFile(string fileName) + { + Encoding encoding = Encoding.Default; + try + { + var file = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.Read); + + var bom = new byte[12]; // Get the byte-order mark, if there is one + file.Position = 0; + file.Read(bom, 0, 12); + if (bom[0] == 0xef && bom[1] == 0xbb && bom[2] == 0xbf) + encoding = Encoding.UTF8; + else if (bom[0] == 0xff && bom[1] == 0xfe) + encoding = Encoding.Unicode; + else if (bom[0] == 0xfe && bom[1] == 0xff) // utf-16 and ucs-2 + encoding = Encoding.BigEndianUnicode; + else if (bom[0] == 0 && bom[1] == 0 && bom[2] == 0xfe && bom[3] == 0xff) // ucs-4 + encoding = Encoding.UTF32; + else if (encoding == Encoding.Default && file.Length > 12) + { + int length = (int)file.Length; + if (length > 100000) + length = 100000; + + file.Position = 0; + var buffer = new byte[length]; + file.Read(buffer, 0, length); + + if (IsUtf8(buffer)) + { + encoding = Encoding.UTF8; + } + else if (Configuration.Settings.General.AutoGuessAnsiEncoding) + { + encoding = DetectAnsiEncoding(buffer); + + Encoding greekEncoding = Encoding.GetEncoding(1253); // Greek + if (GetCount(greekEncoding.GetString(buffer), "μου", "είναι", "Είναι", "αυτό", "Τόμπυ", "καλά") > 5) + return greekEncoding; + + Encoding russianEncoding = Encoding.GetEncoding(1251); // Russian + if (GetCount(russianEncoding.GetString(buffer), "что", "быть", "весь", "этот", "один", "такой") > 5) + return russianEncoding; + russianEncoding = Encoding.GetEncoding(28595); // Russian + if (GetCount(russianEncoding.GetString(buffer), "что", "быть", "весь", "этот", "один", "такой") > 5) + return russianEncoding; + + Encoding arabicEncoding = Encoding.GetEncoding(28596); // Arabic + Encoding hewbrewEncoding = Encoding.GetEncoding(28598); // Hebrew + if (GetCount(arabicEncoding.GetString(buffer), "من", "هل", "لا", "فى", "لقد", "ما") > 5) + { + if (GetCount(hewbrewEncoding.GetString(buffer), "אולי", "אולי", "אולי", "אולי", "טוב", "טוב") > 10) + return hewbrewEncoding; + else + return arabicEncoding; + } + else if (GetCount(hewbrewEncoding.GetString(buffer), "אתה", "אולי", "הוא", "בסדר", "יודע", "טוב") > 5) + return hewbrewEncoding; + + } + } + file.Close(); + file.Dispose(); + } + catch + { + + } + return encoding; + } + + /// + /// Will try to determine if buffer is utf-8 encoded or not. + /// If any non-utf8 sequences are found then false is returned, if no utf8 multibytes sequences are found then false is returned. + /// + private static bool IsUtf8(byte[] buffer) + { + int utf8Count = 0; + int i = 0; + while (i < buffer.Length - 3) + { + byte b = buffer[i]; + if (b > 127) + { + if (b >= 194 && b <=223 && buffer[i+1] >= 128 && buffer[i+1] <= 191) + { // 2-byte sequence + utf8Count++; + i++; + } + else if (b >= 224 && b <= 239 && buffer[i + 1] >= 128 && buffer[i + 1] <= 191 && + buffer[i + 2] >= 128 && buffer[i + 2] <= 191) + { // 3-byte sequence + utf8Count++; + i += 2; + } + else if (b >= 240 && b <= 244 && buffer[i + 1] >= 128 && buffer[i + 1] <= 191 && + buffer[i + 2] >= 128 && buffer[i + 2] <= 191 && + buffer[i + 3] >= 128 && buffer[i + 3] <= 191) + { // 4-byte sequence + utf8Count++; + i += 3; + } + else + { + return false; + } + } + i++; + } + if (utf8Count == 0) + return false; // not utf-8 + + return true; + } + + public static Encoding DetectAnsiEncoding(byte[] buffer) + { + if (IsRunningOnMono()) + return Encoding.Default; + + try + { + Encoding encoding = DetectEncoding.EncodingTools.DetectInputCodepage(buffer); + + Encoding greekEncoding = Encoding.GetEncoding(1253); // Greek + if (GetCount(greekEncoding.GetString(buffer), "μου", "είναι", "Είναι", "αυτό", "Τόμπυ", "καλά") > 5) + return greekEncoding; + + Encoding russianEncoding = Encoding.GetEncoding(1251); // Russian + if (GetCount(russianEncoding.GetString(buffer), "что", "быть", "весь", "этот", "один", "такой") > 5) + return russianEncoding; + russianEncoding = Encoding.GetEncoding(28595); // Russian + if (GetCount(russianEncoding.GetString(buffer), "что", "быть", "весь", "этот", "один", "такой") > 5) + return russianEncoding; + + Encoding arabicEncoding = Encoding.GetEncoding(28596); // Arabic + Encoding hewbrewEncoding = Encoding.GetEncoding(28598); // Hebrew + if (GetCount(arabicEncoding.GetString(buffer), "من", "هل", "لا", "فى", "لقد", "ما") > 5) + { + if (GetCount(hewbrewEncoding.GetString(buffer), "אולי", "אולי", "אולי", "אולי", "טוב", "טוב") > 10) + return hewbrewEncoding; + else + return arabicEncoding; + } + else if (GetCount(hewbrewEncoding.GetString(buffer), "אתה", "אולי", "הוא", "בסדר", "יודע", "טוב") > 5) + return hewbrewEncoding; + + return encoding; + } + catch + { + return Encoding.Default; + } + } + + public static string DictionaryFolder + { + get + { + return Path.GetDirectoryName(Application.ExecutablePath).TrimEnd(Path.DirectorySeparatorChar) + Path.DirectorySeparatorChar + "Dictionaries" + Path.DirectorySeparatorChar; + } + } + + public static List GetDictionaryLanguages() + { + var list = new List(); + string dictionaryFolder = DictionaryFolder; + if (Directory.Exists(dictionaryFolder)) + { + foreach (string dic in Directory.GetFiles(dictionaryFolder, "*.dic")) + { + string name = Path.GetFileNameWithoutExtension(dic); + if (!name.StartsWith("hyph")) + { + try + { + var ci = new CultureInfo(name.Replace("_", "-")); + name = ci.DisplayName + " [" + name + "]"; + } + catch (Exception exception) + { + System.Diagnostics.Debug.WriteLine(exception.Message); + name = "[" + name + "]"; + } + list.Add(name); + } + } + } + return list; + } + + /// + /// Get suggested display time in milliseconds (a tiny bit low). + /// + /// Subtitle text paragraph + /// Suggested display time in milliseconds (a tiny bit low). + public static double GetDisplayMillisecondsFromText(string text) + { + int l = text.Length; + + if (l < 8) + return 800; + if (l < 15) + return 1000; + if (l < 25) + return 1300; + if (l < 35) + return 1500; + if (l < 50) + return 2000; + if (l < 75) + return 2500; + if (l < 90) + return 3000; + return 3500; + } + + private static int GetCount(string text, + string word1, + string word2, + string word3, + string word4, + string word5, + string word6) + { + var regEx1 = new Regex("\\b" + word1 + "\\b"); + var regEx2 = new Regex("\\b" + word2 + "\\b"); + var regEx3 = new Regex("\\b" + word3 + "\\b"); + var regEx4 = new Regex("\\b" + word4 + "\\b"); + var regEx5 = new Regex("\\b" + word5 + "\\b"); + var regEx6 = new Regex("\\b" + word6 + "\\b"); + int count = regEx1.Matches(text).Count; + count += regEx2.Matches(text).Count; + count += regEx3.Matches(text).Count; + count += regEx4.Matches(text).Count; + count += regEx5.Matches(text).Count; + count += regEx6.Matches(text).Count; + return count; + } + + public static string AutoDetectGoogleLanguage(string text, int bestCount) + { + int count = GetCount(text, "we", "are", "and", "you", "your", "what"); + if (count > bestCount) + return "en"; + + count = GetCount(text, "vi", "er", "og", "jeg", "var", "men"); + if (count > bestCount) + { + int norwegianCount = GetCount(text, "ut", "deg", "meg", "merkelig", "mye", "spørre"); + if (norwegianCount < 2) + return "da"; + } + + count = GetCount(text, "vi", "er", "og", "jeg", "var", "men"); + if (count > bestCount) + { + int danishCount = GetCount(text, "siger", "dig", "mig", "mærkelig", "meget", "spørge"); + if (danishCount < 2) + return "no"; + } + + count = GetCount(text, "vi", "är", "och", "Jag", "inte", "för"); + if (count > bestCount) + return "sv"; + + count = GetCount(text, "el", "bien", "Vamos", "Hola", "casa", "con"); + if (count > bestCount) + { + int frenchWords = GetCount(text, "Cest", "cest", "pas", "vous", "pour", "suis"); // not spanish words + if (frenchWords < 2) + return "es"; + } + + count = GetCount(text, "un", "vous", "avec", "pas", "ce", "une"); + if (count > bestCount) + { + int spanishWords = GetCount(text, "Hola", "nada", "Vamos", "pasa", "los", "como"); // not french words + int italianWords = GetCount(text, "Cosa", "sono", "Grazie", "Buongiorno", "bene", "questo"); + + if (spanishWords < 2 && italianWords < 2) + return "fr"; + } + + count = GetCount(text, "und", "auch", "sich", "bin", "hast", "möchte"); + if (count > bestCount) + return "de"; + + count = GetCount(text, "van", "het", "een", "Het", "mij", "zijn"); + if (count > bestCount) + return "nl"; + + count = GetCount(text, "Czy", "ale", "ty", "siê", "jest", "mnie"); + if (count > bestCount) + return "pl"; + + count = GetCount(text, "Cosa", "sono", "Grazie", "Buongiorno", "bene", "questo"); + if (count > bestCount) + { + int frenchWords = GetCount(text, "Cest", "cest", "pas", "vous", "pour", "suis"); // not spanish words + int spanishWords = GetCount(text, "Hola", "nada", "Vamos", "pasa", "los", "como"); // not french words + if (frenchWords < 2 && spanishWords < 2) + return "it"; + } + + count = GetCount(text, "não", "Não", "Estás", "Então", "isso", "com"); + if (count > bestCount) + return "pt-PT"; // PORTUGUESE + + count = GetCount(text, "μου", "είναι", "Είναι", "αυτό", "Τόμπυ", "καλά"); + if (count > bestCount) + return "el"; // Greek + + count = GetCount(text, "все", "это", "как", "Воробей", "сюда", "Давай"); + if (count > bestCount) + return "ru"; // Russian + + count = GetCount(text, "sam", "öto", "äto", "ovo", "vas", "što"); + if (count > bestCount && GetCount(text, "htjeti ", "htjeti ", "htjeti ", "htjeti ", "htjeti ", "htjeti ") > 0) + return "hr"; // Croatia + + count = GetCount(text, "من", "هل", "لا", "فى", "لقد", "ما"); + if (count > bestCount) + { + if (GetCount(text, "אולי", "אולי", "אולי", "אולי", "טוב", "טוב") > 10) + return "he"; + return "ar"; // Arabic + } + + count = GetCount(text, "אתה", "אולי", "הוא", "בסדר", "יודע", "טוב"); + if (count > bestCount) + return "he"; // Hebrew + + count = GetCount(text, "sam", "što", "nije", "Šta", "ovde", "za"); + if (count > bestCount) + return "sr"; // Serbian + + count = GetCount(text, "không", "tôi", "anh", "đó", "Tôi", "ông"); + if (count > bestCount) + return "vi"; // Vietnamese + + return string.Empty; + } + + public static string AutoDetectGoogleLanguage(Subtitle subtitle) + { + int bestCount = subtitle.Paragraphs.Count / 14; + + StringBuilder sb = new StringBuilder(); + foreach (Paragraph p in subtitle.Paragraphs) + sb.AppendLine(p.Text); + string text = sb.ToString(); + + string languageId = AutoDetectGoogleLanguage(text, bestCount); + + if (string.IsNullOrEmpty(languageId)) + return "en"; + + return languageId; + } + + public static string AutoDetectLanguageName(string languageName, Subtitle subtitle) + { + int bestCount = subtitle.Paragraphs.Count / 14; + + StringBuilder sb = new StringBuilder(); + foreach (Paragraph p in subtitle.Paragraphs) + sb.AppendLine(p.Text); + string text = sb.ToString(); + + foreach (string name in GetDictionaryLanguages()) + { + string shortName = string.Empty; + int start = name.IndexOf("["); + int end = name.IndexOf("]"); + if (start > 0 && end > start) + { + start++; + shortName = name.Substring(start, end - start); + } + + int count; + switch (shortName) + { + case "da_DK": + count = GetCount(text, "vi", "er", "og", "jeg", "var", "men"); + if (count > bestCount) + { + int norweigianCount = GetCount(text, "ut", "deg", "meg", "merkelig", "mye", "spørre"); + if (norweigianCount < 2) + languageName = shortName; + } + break; + case "nb_NO": + count = GetCount(text, "vi", "er", "og", "jeg", "var", "men"); + if (count > bestCount) + { + int danishCount = GetCount(text, "siger", "dig", "mig", "mærkelig", "meget", "spørge"); + if (danishCount < 2) + languageName = shortName; + } + break; + case "en_US": + count = GetCount(text, "we", "are", "and", "you", "your", "what"); + if (count > bestCount) + languageName = shortName; + break; + case "sv_SE": + count = GetCount(text, "vi", "är", "och", "Jag", "inte", "för"); + if (count > bestCount) + languageName = shortName; + break; + case "es_ES": + count = GetCount(text, "el", "bien", "Vamos", "Hola", "casa", "con"); + if (count > bestCount) + { + int frenchWords = GetCount(text, "Cest", "cest", "pas", "vous", "pour", "suis"); // not spanish words + if (frenchWords < 2) + languageName = shortName; + } + break; + case "fr_FR": + count = GetCount(text, "un", "vous", "avec", "pas", "ce", "une"); + if (count > bestCount) + { + int spanishWords = GetCount(text, "Hola", "nada", "Vamos", "pasa", "los", "como"); // not french words + int italianWords = GetCount(text, "Cosa", "sono", "Grazie", "Buongiorno", "bene", "questo"); // not italian words + if (spanishWords < 2 && italianWords < 2) + languageName = shortName; + } + break; + case "it_IT": + count = GetCount(text, "Cosa", "sono", "Grazie", "Buongiorno", "bene", "questo"); + if (count > bestCount) + { + int frenchWords = GetCount(text, "Cest", "cest", "pas", "vous", "pour", "suis"); // not spanish words + int spanishWords = GetCount(text, "Hola", "nada", "Vamos", "pasa", "los", "como"); // not french words + if (frenchWords < 2 && spanishWords < 2) + languageName = shortName; + } + break; + case "de_DE": + count = GetCount(text, "und", "auch", "sich", "bin", "hast", "möchte"); + if (count > bestCount) + languageName = shortName; + break; + case "nl_NL": + count = GetCount(text, "van", "het", "een", "Het", "mij", "zijn"); + if (count > bestCount) + languageName = shortName; + break; + case "pl_PL": + count = GetCount(text, "Czy", "ale", "ty", "siê", "jest", "mnie"); + if (count > bestCount) + languageName = shortName; + break; + case "el_GR": + count = GetCount(text, "μου", "είναι", "Είναι", "αυτό", "Τόμπυ", "καλά"); + if (count > bestCount) + languageName = shortName; + break; + case "ru_RU": + count = GetCount(text, "все", "это", "как", "Воробей", "сюда", "Давай"); + if (count > bestCount) + languageName = shortName; + break; + case "ro_RO": + count = GetCount(text, "sunt", "fost", "Bine", "Haide", "Trebuie", "trebuie"); + if (count > bestCount) + languageName = shortName; + break; + case "hr_HR": // Croatia + count = GetCount(text, "sam", "öto", "äto", "ovo", "vas", "što"); + if (count > bestCount) + languageName = shortName; + break; + case "pt_PT": // Portuguese + count = GetCount(text, "não", "Não", "Estás", "Então", "isso", "com"); + if (count > bestCount) + languageName = shortName; + break; + case "pt_BR": // Portuguese (Brasil) + count = GetCount(text, "não", "Não", "Estás", "Então", "isso", "com"); + if (count > bestCount) + languageName = shortName; + break; + default: + break; + } + } + return languageName; + } + + public static string ColorToHex(System.Drawing.Color c) + { + string result = string.Format("#{0:x2}{1:x2}{2:x2}", c.R, c.G, c.B); + return result; + } + + public static int GetMaxLineLength(string text) + { + int maxLength = 0; + foreach (string line in text.Split(Environment.NewLine.ToCharArray(), StringSplitOptions.RemoveEmptyEntries)) + { + string s = RemoveHtmlTags(line); + if (s.Length > maxLength) + maxLength = s.Length; + } + return maxLength; + } + + public static bool IsRunningOnMono() + { + return Type.GetType("Mono.Runtime") != null; + } + + public static void ShowHelp(string parameter) + { + string helpFile = Configuration.Settings.Language.General.HelpFile; + if (string.IsNullOrEmpty(helpFile)) + helpFile = "http://www.nikse.dk/se/Help.aspx"; + System.Diagnostics.Process.Start(helpFile + parameter); + } + + public static string AssemblyVersion + { + get + { + return Assembly.GetExecutingAssembly().GetName().Version.ToString(); + } + } + + public static string GetOpenDialogFiler() + { + StringBuilder sb = new StringBuilder(); + sb.Append(Configuration.Settings.Language.General.SubtitleFiles + "|"); + foreach (SubtitleFormat s in SubtitleFormat.AllSubtitleFormats) + { + sb.Append("*" + s.Extension + ";"); + foreach (string ext in s.AlternateExtensions) + { + sb.Append("*" + ext + ";"); + } + } + sb.Append("|" + Configuration.Settings.Language.General.AllFiles + "|*.*"); + return sb.ToString(); + } + + public static void SetSaveDialogFilter(SaveFileDialog saveFileDialog, SubtitleFormat currentFormat) + { + var sb = new StringBuilder(); + int index = 0; + foreach (SubtitleFormat format in SubtitleFormat.AllSubtitleFormats) + { + sb.Append(format.FriendlyName + "|*" + format.Extension + "|"); + if (currentFormat.FriendlyName == format.FriendlyName) + saveFileDialog.FilterIndex = index + 1; + index++; + } + saveFileDialog.Filter = sb.ToString().TrimEnd('|'); + } + + public static bool IsQuartsDllInstalled + { + get + { + if (IsRunningOnMono()) + return false; + + string quartsInteropFileName = Path.GetDirectoryName(Application.ExecutablePath).TrimEnd('\\') + @"\Interop.QuartzTypeLib.dll"; + if (!File.Exists(quartsInteropFileName)) + return false; + + string quartzFileName = Environment.GetFolderPath(Environment.SpecialFolder.System).TrimEnd('\\') + @"\quartz.dll"; + return File.Exists(quartzFileName); + } + } + + public static bool IsManagedDirectXInstalled + { + get + { + if (IsRunningOnMono()) + return false; + + try + { + //Check if this folder exists: C:\WINDOWS\Microsoft.NET\DirectX for Managed Code + string folderName = Environment.SystemDirectory.TrimEnd('\\'); + folderName = folderName.Substring(0, folderName.LastIndexOf('\\')); + folderName = folderName + @"\\Microsoft.NET\DirectX for Managed Code"; + return Directory.Exists(folderName); + } + catch (FileNotFoundException) + { + return false; + } + } + } + + public static bool IsWmpAvailable + { + get + { + if (IsRunningOnMono()) + return false; + + string wmpInteropFileName = Path.GetDirectoryName(Application.ExecutablePath).TrimEnd('\\') + @"\AxInterop.WMPLib.dll"; + if (!File.Exists(wmpInteropFileName)) + return false; + + string wmpLibFileName = Path.GetDirectoryName(Application.ExecutablePath).TrimEnd('\\') + @"\Interop.WMPLib.dll"; + return File.Exists(wmpLibFileName); + } + } + + public static VideoPlayer GetVideoPlayer() + { + GeneralSettings gs = Configuration.Settings.General; + + if (gs.VideoPlayer == "VLC" && LibVlc11xDynamic.IsInstalled) + return new LibVlc11xDynamic(); + if (gs.VideoPlayer == "WindowsMediaPlayer" && IsWmpAvailable) + return new WmpPlayer(); + //if (gs.VideoPlayer == "ManagedDirectX" && IsManagedDirectXInstalled) + // return new ManagedDirectXPlayer(); + if (IsQuartsDllInstalled) + return new QuartsPlayer(); + if (IsWmpAvailable) + return new WmpPlayer(); + + throw new NotSupportedException("You need DirectX or VLC media player 1.1.x installed as well as Subtitle Edit dll files!"); + } + + public static void InitializeVideoPlayerAndContainer(string fileName, VideoInfo videoInfo, VideoPlayerContainer videoPlayerContainer, EventHandler onVideoLoaded, EventHandler onVideoEnded) + { + try + { + videoPlayerContainer.VideoPlayer = GetVideoPlayer(); + videoPlayerContainer.VideoPlayer.Initialize(videoPlayerContainer.PanelPlayer, fileName, onVideoLoaded, onVideoEnded); + videoPlayerContainer.ShowStopButton = Configuration.Settings.General.VideoPlayerShowStopButton; + videoPlayerContainer.Volume = Configuration.Settings.General.VideoPlayerDefaultVolume; + } + catch (Exception exception) + { + videoPlayerContainer.VideoPlayer = null; + var videoError = new VideoError(); + videoError.Initialize(fileName, videoInfo, exception); + videoError.ShowDialog(); + } + } + + + internal static void DisplayLineLengths(Panel panelSingleLine, string text) + { + string cleanText = RemoveHtmlTags(text).Replace(Environment.NewLine, "|"); + string[] lines = cleanText.Split('|'); + + int position = 0; + + // we must dispose before clearing controls (or this will occur: "Error creating window handle") + foreach (Control ctrl in panelSingleLine.Controls) + ctrl.Dispose(); + panelSingleLine.Controls.Clear(); + + for (int i = 0; i < lines.Length; i++) + { + string line = lines[i]; + if (i > 0) + { + var labelSlash = new Label {AutoSize = true, Margin = new Padding(0)}; + panelSingleLine.Controls.Add(labelSlash); + labelSlash.Text = "/"; + labelSlash.Top = 0; + labelSlash.Left = position; + position += labelSlash.Width - 4; + + } + var labelLength = new Label(); + labelLength.AutoSize = true; + labelLength.Margin = new Padding(0); + panelSingleLine.Controls.Add(labelLength); + labelLength.Text = line.Length.ToString(); + labelLength.Top = 0; + labelLength.Left = position; + position += labelLength.Width - 4; + if (line.Length > Configuration.Settings.General.SubtitleLineMaximumLength) + labelLength.ForeColor = System.Drawing.Color.Red; + else if (line.Length > Configuration.Settings.General.SubtitleLineMaximumLength - 5) + labelLength.ForeColor = System.Drawing.Color.Orange; + } + } + + public static bool IsValidRegex(string testPattern) + { + if (!string.IsNullOrEmpty(testPattern)) + { + try + { + Regex.Match("", testPattern); + return true; + } + catch (ArgumentException) + { // BAD PATTERN: Syntax error + } + } + return false; + } + + public static Regex MakeWordSearchRegex(string word) + { + string s = word.Replace("\\", "\\\\"); + s = s.Replace("*", "\\*"); + s = s.Replace(".", "\\."); + s = s.Replace("?", "\\?"); + return new Regex(@"\b" + s + @"\b", RegexOptions.Compiled); + } + + public static Regex MakeWordSearchRegexWithNumbers(string word) + { + string s = word.Replace("\\", "\\\\"); + s = s.Replace("*", "\\*"); + s = s.Replace(".", "\\."); + s = s.Replace("?", "\\?"); + return new Regex(@"[\b ,\.\?\!]" + s + @"[\b !\.,\r\n\?]", RegexOptions.Compiled); + } + + public static void AddToUserDictionary(string word, string languageName) + { + word = word.Trim(); + if (word.Length > 1) + { + string userWordsXmlFileName = DictionaryFolder + languageName + "_user.xml"; + var userWords = new XmlDocument(); + if (File.Exists(userWordsXmlFileName)) + userWords.Load(userWordsXmlFileName); + else + userWords.LoadXml(""); + + XmlNode node = userWords.CreateElement("word"); + node.InnerText = word; + userWords.DocumentElement.AppendChild(node); + userWords.Save(userWordsXmlFileName); + } + } + + public static bool AddWordToLocalNamesEtcList(string word, string languageName) + { + word = word.Trim(); + if (word.Length > 1) + { + var localNamesEtc = new List(); + string userNamesEtcXmlFileName = LoadLocalNamesEtc(localNamesEtc, localNamesEtc, languageName); + + if (localNamesEtc.Contains(word)) + return false; + localNamesEtc.Add(word); + localNamesEtc.Sort(); + + var namesEtcDoc = new XmlDocument(); + if (File.Exists(userNamesEtcXmlFileName)) + namesEtcDoc.Load(userNamesEtcXmlFileName); + else + namesEtcDoc.LoadXml(""); + + XmlNode de = namesEtcDoc.DocumentElement; + if (de != null) + { + de.RemoveAll(); + foreach (var name in localNamesEtc) + { + XmlNode node = namesEtcDoc.CreateElement("name"); + node.InnerText = name; + de.AppendChild(node); + } + namesEtcDoc.Save(userNamesEtcXmlFileName); + } + return true; + } + return false; + } + + public static string LoadNamesEtcWordLists(List namesEtcList, List namesEtcMultiWordList, string languageName) + { + namesEtcList.Clear(); + namesEtcMultiWordList.Clear(); + + LoadGlobalNamesEtc(namesEtcList, namesEtcMultiWordList); + + string userNamesEtcXmlFileName = LoadLocalNamesEtc(namesEtcList, namesEtcMultiWordList, languageName); + return userNamesEtcXmlFileName; + } + + internal static void LoadGlobalNamesEtc(List namesEtcList, List namesEtcMultiWordList) + { + // Load names etc list (names/noise words) + var namesEtcDoc = new XmlDocument(); + bool loaded = false; + if (Configuration.Settings.WordLists.UseOnlineNamesEtc && !string.IsNullOrEmpty(Configuration.Settings.WordLists.NamesEtcUrl)) + { + try + { + string xml = ReadTextFileViaUrlAndProxyIfAvailable(Configuration.Settings.WordLists.NamesEtcUrl); + namesEtcDoc.LoadXml(xml); + loaded = true; + } + catch (Exception exception) + { + MessageBox.Show(exception.Message + Environment.NewLine + exception.StackTrace); + } + } + if (!loaded && File.Exists(DictionaryFolder + "names_etc.xml")) + { + namesEtcDoc.Load(DictionaryFolder + "names_etc.xml"); + } + if (namesEtcDoc.DocumentElement != null) + foreach (XmlNode node in namesEtcDoc.DocumentElement.SelectNodes("name")) + { + string s = node.InnerText.Trim(); + if (s.Contains(" ")) + { + if (!namesEtcMultiWordList.Contains(s)) + namesEtcMultiWordList.Add(s); + } + else + { + if (!namesEtcList.Contains(s)) + namesEtcList.Add(s); + } + } + } + + internal static string LoadLocalNamesEtc(List namesEtcList, List namesEtcMultiWordList, string languageName) + { + string userNamesEtcXmlFileName = DictionaryFolder + languageName + "_names_etc.xml"; + if (!File.Exists(userNamesEtcXmlFileName) && languageName.Length == 2) + { + string[] files = Directory.GetFiles(DictionaryFolder, languageName + "_??_names_etc.xml"); + if (files.Length > 0) + userNamesEtcXmlFileName = files[0]; + } + + if (File.Exists(userNamesEtcXmlFileName)) + { + var namesEtcDoc = new XmlDocument(); + namesEtcDoc.Load(userNamesEtcXmlFileName); + foreach (XmlNode node in namesEtcDoc.DocumentElement.SelectNodes("name")) + { + string s = node.InnerText.Trim(); + if (s.Contains(" ")) + { + if (!namesEtcMultiWordList.Contains(s)) + namesEtcMultiWordList.Add(s); + } + else + { + if (!namesEtcList.Contains(s)) + namesEtcList.Add(s); + } + } + } + return userNamesEtcXmlFileName; + } + + internal static bool IsInNamesEtcMultiWordList(List namesEtcMultiWordList, string line, string word) + { + string text = line.Replace(Environment.NewLine, " "); + text = text.Replace(" ", " "); + + foreach (string s in namesEtcMultiWordList) + { + if (s.Contains(word) && text.Contains(s)) + { + if (s.StartsWith(word + " ") || s.EndsWith(" " + word) || s.Contains(" " + word + " ")) + return true; + } + } + return false; + } + + public static string LoadUserWordList(List userWordList, string languageName) + { + userWordList.Clear(); + var userWordDictionary = new XmlDocument(); + string userWordListXmlFileName = DictionaryFolder + languageName + "_user.xml"; + if (File.Exists(userWordListXmlFileName)) + { + userWordDictionary.Load(userWordListXmlFileName); + foreach (XmlNode node in userWordDictionary.DocumentElement.SelectNodes("word")) + { + string s = node.InnerText.ToLower(); + if (!userWordList.Contains(s)) + userWordList.Add(s); + } + } + return userWordListXmlFileName; + } + + public static string GetLetters(bool uppercase, bool lowercase, bool numbers) + { + string s = string.Empty; + + if (uppercase) + s += Configuration.Settings.General.UppercaseLetters; + + if (lowercase) + s += Configuration.Settings.General.UppercaseLetters.ToLower(); + + if (numbers) + s += "0123456789"; + + return s; + } + + } +} \ No newline at end of file diff --git a/src/Logic/Wave.cs b/src/Logic/Wave.cs new file mode 100644 index 000000000..618d7e797 --- /dev/null +++ b/src/Logic/Wave.cs @@ -0,0 +1,22 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Nikse.SubtitleEdit.Logic +{ + class Wave + { + public Wave(string fileName) + { + RiffParser parser = new RiffParser(); + RiffDecodeHeader decoder = new RiffDecodeHeader(parser); + parser.OpenFile(fileName); + if (RiffParser.ckidAVI == parser.FileType) + { + decoder.ProcessMainAVI(); + decoder.ProcessMainWAVE(); + parser.CloseFile(); + } + } + } +} diff --git a/src/Logic/WavePeak.cs b/src/Logic/WavePeak.cs new file mode 100644 index 000000000..50f4d7404 --- /dev/null +++ b/src/Logic/WavePeak.cs @@ -0,0 +1,353 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.IO; + +namespace Nikse.SubtitleEdit.Logic +{ + public class WaveHeader + { + const int ConstantHeaderSize = 20; + private byte[] _headerData; + + public string ChunkId { get; private set; } + public int ChunkSize { get; private set; } + public string Format { get; private set; } + public string FmtId { get; private set; } + public int FmtChunkSize { get; private set; } + + /// + /// 1 = PCM (uncompressed) + /// + public int AudioFormat { get; private set; } + + public int NumberOfChannels { get; private set; } + + /// + /// Number of samples per second + /// + public int SampleRate { get; private set; } + + /// + /// Should be SampleRate * BlockAlign + /// + public int ByteRate { get; private set; } + + /// + /// 8 bytes per block (32 bit); 6 bytes per block (24 bit); 4 bytes per block (16 bit) + /// + public int BlockAlign { get; private set; } + + public int BitsPerSample { get; private set; } + + public string DataId { get; private set; } + + /// + /// Size of sound data + /// + public int DataChunkSize { get; private set; } + public int DataStartPosition { get; private set; } + + public WaveHeader(Stream stream) + { + stream.Position = 0; + byte[] buffer = new byte[ConstantHeaderSize]; + int bytesRead = stream.Read(buffer, 0, buffer.Length); + if (bytesRead < buffer.Length) + throw new ArgumentException("Stream is too small"); + + // constant header + ChunkId = Encoding.UTF8.GetString(buffer, 0, 4); + ChunkSize = BitConverter.ToInt32(buffer, 4); + Format = Encoding.UTF8.GetString(buffer, 8, 4); + FmtId = Encoding.UTF8.GetString(buffer, 12, 4); + FmtChunkSize = BitConverter.ToInt32(buffer, 16); + + // fmt data + buffer = new byte[FmtChunkSize]; + stream.Read(buffer, 0, buffer.Length); + AudioFormat = BitConverter.ToInt16(buffer, 0); + NumberOfChannels = BitConverter.ToInt16(buffer, 2); + SampleRate = BitConverter.ToInt32(buffer, 4); + ByteRate = BitConverter.ToInt32(buffer, 8); + BlockAlign = BitConverter.ToInt16(buffer, 12); + BitsPerSample = BitConverter.ToInt16(buffer, 14); + + // data + buffer = new byte[8]; + stream.Position = ConstantHeaderSize + FmtChunkSize; + stream.Read(buffer, 0, buffer.Length); + DataId = Encoding.UTF8.GetString(buffer, 0, 4); + DataChunkSize = BitConverter.ToInt32(buffer, 4); + DataStartPosition = (int)(ConstantHeaderSize + FmtChunkSize + 8); + + _headerData = new byte[DataStartPosition]; + stream.Position = 0; + stream.Read(_headerData, 0, _headerData.Length); + } + + public long BytesPerSecond + { + get + { + return SampleRate * (BitsPerSample / 8) * NumberOfChannels; + } + } + + public double LengthInSeconds + { + get + { + return DataChunkSize / BytesPerSecond; + } + } + + internal void WriteHeader(Stream fromStream, Stream toStream, int sampleRate, int numberOfChannels, int bitsPerSample, int dataSize) + { + int byteRate = sampleRate * (bitsPerSample / 8) * numberOfChannels; + + WriteInt32ToByteArray(_headerData, 4, dataSize + DataStartPosition - 8); + WriteInt16ToByteArray(_headerData, ConstantHeaderSize + 2, numberOfChannels); + WriteInt32ToByteArray(_headerData, ConstantHeaderSize + 4, sampleRate); + WriteInt32ToByteArray(_headerData, ConstantHeaderSize + 8, byteRate); + WriteInt16ToByteArray(_headerData, ConstantHeaderSize + 14, bitsPerSample); + WriteInt32ToByteArray(_headerData, ConstantHeaderSize + FmtChunkSize + 4, dataSize); + toStream.Write(_headerData, 0, _headerData.Length); + } + + private void WriteInt16ToByteArray(byte[] _headerData, int index, int value) + { + byte[] buffer = BitConverter.GetBytes((short)value); + for (int i = 0; i < buffer.Length; i++) + _headerData[index + i] = buffer[i]; + } + private void WriteInt32ToByteArray(byte[] _headerData, int index, int value) + { + byte[] buffer = BitConverter.GetBytes(value); + for (int i = 0; i < buffer.Length; i++) + _headerData[index + i] = buffer[i]; + } + } + + public class WavePeakGenerator + { + private Stream _stream = null; + private byte[] _data = null; + + private delegate int ReadSampleDataValueDelegate(ref int index); + + public WaveHeader Header { get; private set; } + + /// + /// Lowest data value + /// + public int DataMinValue { get; private set; } + + /// + /// Highest data value + /// + public int DataMaxValue { get; private set; } + + /// + /// Number of peaks per second (should be divideable by SampleRate) + /// + public int PeaksPerSecond { get; private set; } + + /// + /// List of all peak samples (channels are merged) + /// + public List PeakSamples { get; private set; } + + /// + /// List of all samples (channels are merged) + /// + public List AllSamples { get; private set; } + + /// + /// Constructor + /// + /// Wave file name + public WavePeakGenerator(string fileName) + { + Initialize(new FileStream(fileName, FileMode.Open, FileAccess.Read)); + } + + /// + /// Constructor + /// + /// Stream of a wave file + public WavePeakGenerator(Stream stream) + { + Initialize(stream); + } + + /// + /// Generate peaks (samples with some interval) for an uncompressed wave file + /// + /// Sampeles per second / sample rate + public void GeneratePeakSamples(int peaksPerSecond) + { + PeaksPerSecond = peaksPerSecond; + + ReadSampleDataValueDelegate readSampleDataValue = GetSampleDataRerader(); + DataMinValue = int.MaxValue; + DataMaxValue = int.MinValue; + PeakSamples = new List(); + int bytesInterval = (int)Header.BytesPerSecond / PeaksPerSecond; + _data = new byte[Header.BytesPerSecond]; + _stream.Position = Header.DataStartPosition; + int bytesRead = _stream.Read(_data, 0, _data.Length); + while (bytesRead == Header.BytesPerSecond) + { + for (int i = 0; i < Header.BytesPerSecond; i += bytesInterval) + { + int index = i; + int value = 0; + for (int channelNumber = 0; channelNumber < Header.NumberOfChannels; channelNumber++) + { + value += readSampleDataValue.Invoke(ref index); + } + value = value / Header.NumberOfChannels; + if (value < DataMinValue) + DataMinValue = value; + if (value > DataMaxValue) + DataMaxValue = value; + PeakSamples.Add(value); + } + bytesRead = _stream.Read(_data, 0, _data.Length); + } + } + + public void GenerateAllSamples() + { + // determine how to read sample values + ReadSampleDataValueDelegate readSampleDataValue = GetSampleDataRerader(); + + // load data + _data = new byte[Header.DataChunkSize]; + _stream.Position = Header.DataStartPosition; + int bytesRead = _stream.Read(_data, 0, _data.Length); + + // read sample values + DataMinValue = int.MaxValue; + DataMaxValue = int.MinValue; + AllSamples = new List(); + int index = 0; + while (index + Header.NumberOfChannels < Header.DataChunkSize) + { + int value = 0; + for (int channelNumber = 0; channelNumber < Header.NumberOfChannels; channelNumber++) + { + value += readSampleDataValue.Invoke(ref index); + } + value = value / Header.NumberOfChannels; + if (value < DataMinValue) + DataMinValue = value; + if (value > DataMaxValue) + DataMaxValue = value; + AllSamples.Add(value); + } + } + + public void WritePeakSamples(string fileName) + { + FileStream fs = new FileStream(fileName, FileMode.Create, FileAccess.Write); + WritePeakSamples(fs); + fs.Close(); + } + + public void WritePeakSamples(Stream stream) + { + Header.WriteHeader(_stream, stream, PeaksPerSecond, 1, 16, PeakSamples.Count * 2); + WritePeakData(stream); + stream.Flush(); + } + + private void WritePeakData(Stream stream) + { + foreach (var value in PeakSamples) + { + byte[] buffer = BitConverter.GetBytes((short)(value)); + stream.Write(buffer, 0, buffer.Length); + } + } + + private void Initialize(Stream stream) + { + _stream = stream; + Header = new WaveHeader(_stream); + } + + private int ReadValue8Bit(ref int index) + { + int result = _data[index]; + index += 2; + return result; + } + + private int ReadValue16Bit(ref int index) + { + int result = BitConverter.ToInt16(_data, index); + index += 2; + return result; + } + + private int ReadValue24Bit(ref int index) + { + byte[] buffer = new byte[4]; + buffer[0] = 0; + buffer[1] = _data[index]; + buffer[2] = _data[index + 1]; + buffer[3] = _data[index + 2]; + int result = BitConverter.ToInt32(buffer, 0); + index += 3; + return result; + } + + private int ReadValue32Bit(ref int index) + { + int result = BitConverter.ToInt32(_data, index); + index += 4; + return result; + } + + /// + /// Determine how to read sample values + /// + /// Sample data reader that matches bits per sample + private ReadSampleDataValueDelegate GetSampleDataRerader() + { + ReadSampleDataValueDelegate readSampleDataValue = null; + switch (Header.BitsPerSample) + { + case 8: + readSampleDataValue = ReadValue8Bit; + break; + case 16: + readSampleDataValue = ReadValue16Bit; + break; + case 24: + readSampleDataValue = ReadValue24Bit; + break; + case 32: + readSampleDataValue = ReadValue32Bit; + break; + default: + throw new InvalidDataException("Cannot read bits per sample of " + Header.BitsPerSample); + } + return readSampleDataValue; + } + + public void Dispose() + { + if (_stream != null) + _stream.Close(); + } + + public void Close() + { + if (_stream != null) + _stream.Close(); + } + } +} diff --git a/src/Logic/ZipExtractor.cs b/src/Logic/ZipExtractor.cs new file mode 100644 index 000000000..f21e3c7d6 --- /dev/null +++ b/src/Logic/ZipExtractor.cs @@ -0,0 +1,433 @@ +// ZipStorer, by Jaime Olivares +// Website: zipstorer.codeplex.com +// Version: 2.35 (March 14, 2010) + +// Simplified to extract-only by Nikse - August 18, 2010 + +using System.Collections.Generic; +using System.Text; + +namespace System.IO.Compression +{ + /// + /// Zip archive decompression. Represents a Zip file. + /// + public class ZipExtractor : IDisposable + { + /// + /// Compression method enumeration + /// + public enum Compression : ushort + { + /// Uncompressed storage + Store = 0, + /// Deflate compression method + Deflate = 8 + } + + /// + /// Represents an entry in Zip file directory + /// + public struct ZipFileEntry + { + /// Compression method + public Compression Method; + /// Full path and filename as stored in Zip + public string FilenameInZip; + /// Original file size + public uint FileSize; + /// Compressed file size + public uint CompressedSize; + /// Offset of header information inside Zip storage + public uint HeaderOffset; + /// Offset of file inside Zip storage + public uint FileOffset; + /// Size of header information + public uint HeaderSize; + /// 32-bit checksum of entire file + public uint Crc32; + /// Last modification time of file + public DateTime ModifyTime; + /// User comment for file + public string Comment; + /// True if UTF8 encoding for filename and comments, false if default (CP 437) + public bool EncodeUTF8; + + /// Overriden method + /// Filename in Zip + public override string ToString() + { + return this.FilenameInZip; + } + } + + #region Public fields + /// True if UTF8 encoding for filename and comments, false if default (CP 437) + public bool EncodeUTF8 = false; + /// Force deflate algotithm even if it inflates the stored file. Off by default. + public bool ForceDeflating = false; + #endregion + + #region Private fields + // List of files to store + private List Files = new List(); + // Filename of storage file + private string FileName; + // Stream object of storage file + private Stream ZipFileStream; + // Central dir image + private byte[] CentralDirImage = null; + // Existing files in zip + private ushort ExistingFiles = 0; + // Static CRC32 Table + private static UInt32[] CrcTable = null; + // Default filename encoder + private static Encoding DefaultEncoding = Encoding.GetEncoding(437); + #endregion + + #region Public methods + // Static constructor. Just invoked once in order to create the CRC32 lookup table. + static ZipExtractor() + { + // Generate CRC32 table + CrcTable = new UInt32[256]; + for (int i = 0; i < CrcTable.Length; i++) + { + UInt32 c = (UInt32)i; + for (int j = 0; j < 8; j++) + { + if ((c & 1) != 0) + c = 3988292384 ^ (c >> 1); + else + c >>= 1; + } + CrcTable[i] = c; + } + } + + /// + /// Method to open an existing storage file + /// + /// Full path of Zip file to open + /// A valid ZipStorer object + public static ZipExtractor Open(string _filename) + { + Stream stream = (Stream)new FileStream(_filename, FileMode.Open, FileAccess.Read); + + ZipExtractor zip = Open(stream); + zip.FileName = _filename; + + return zip; + } + + /// + /// Method to open an existing storage from stream + /// + /// Already opened stream with zip contents + /// A valid ZipStorer object + public static ZipExtractor Open(Stream _stream) + { + ZipExtractor zip = new ZipExtractor(); + zip.ZipFileStream = _stream; + + if (zip.ReadFileInfo()) + return zip; + + throw new System.IO.InvalidDataException(); + } + + /// + /// Close the Zip storage + /// + /// This is a required step, unless automatic dispose is used + public void Close() + { + if (this.ZipFileStream != null) + { + this.ZipFileStream.Flush(); + this.ZipFileStream.Dispose(); + this.ZipFileStream = null; + } + } + + /// + /// Read all the file records in the central directory + /// + /// List of all entries in directory + public List ReadCentralDir() + { + if (this.CentralDirImage == null) + throw new InvalidOperationException("Central directory currently does not exist"); + + List result = new List(); + + for (int pointer = 0; pointer < this.CentralDirImage.Length; ) + { + uint signature = BitConverter.ToUInt32(CentralDirImage, pointer); + if (signature != 0x02014b50) + break; + + bool encodeUTF8 = (BitConverter.ToUInt16(CentralDirImage, pointer + 8) & 0x0800) != 0; + ushort method = BitConverter.ToUInt16(CentralDirImage, pointer + 10); + uint modifyTime = BitConverter.ToUInt32(CentralDirImage, pointer + 12); + uint crc32 = BitConverter.ToUInt32(CentralDirImage, pointer + 16); + uint comprSize = BitConverter.ToUInt32(CentralDirImage, pointer + 20); + uint fileSize = BitConverter.ToUInt32(CentralDirImage, pointer + 24); + ushort filenameSize = BitConverter.ToUInt16(CentralDirImage, pointer + 28); + ushort extraSize = BitConverter.ToUInt16(CentralDirImage, pointer + 30); + ushort commentSize = BitConverter.ToUInt16(CentralDirImage, pointer + 32); + uint headerOffset = BitConverter.ToUInt32(CentralDirImage, pointer + 42); + uint headerSize = (uint)(46 + filenameSize + extraSize + commentSize); + + Encoding encoder = encodeUTF8 ? Encoding.UTF8 : DefaultEncoding; + + ZipFileEntry zfe = new ZipFileEntry(); + zfe.Method = (Compression)method; + zfe.FilenameInZip = encoder.GetString(CentralDirImage, pointer + 46, filenameSize); + zfe.FileOffset = GetFileOffset(headerOffset); + zfe.FileSize = fileSize; + zfe.CompressedSize = comprSize; + zfe.HeaderOffset = headerOffset; + zfe.HeaderSize = headerSize; + zfe.Crc32 = crc32; + zfe.ModifyTime = DosTimeToDateTime(modifyTime); + if (commentSize > 0) + zfe.Comment = encoder.GetString(CentralDirImage, pointer + 46 + filenameSize + extraSize, commentSize); + + result.Add(zfe); + pointer += (46 + filenameSize + extraSize + commentSize); + } + + return result; + } + + /// + /// Copy the contents of a stored file into a physical file + /// + /// Entry information of file to extract + /// Name of file to store uncompressed data + /// True if success, false if not. + /// Unique compression methods are Store and Deflate + public bool ExtractFile(ZipFileEntry _zfe, string _filename) + { + // Make sure the parent directory exist + string path = System.IO.Path.GetDirectoryName(_filename); + + if (!Directory.Exists(path)) + Directory.CreateDirectory(path); + // Check it is directory. If so, do nothing + if (Directory.Exists(_filename)) + return true; + + Stream output = new FileStream(_filename, FileMode.Create, FileAccess.Write); + bool result = ExtractFile(_zfe, output); + if (result) + output.Close(); + + File.SetCreationTime(_filename, _zfe.ModifyTime); + File.SetLastWriteTime(_filename, _zfe.ModifyTime); + + return result; + } + + /// + /// Copy the contents of a stored file into an opened stream + /// + /// Entry information of file to extract + /// Stream to store the uncompressed data + /// True if success, false if not. + /// Unique compression methods are Store and Deflate + public bool ExtractFile(ZipFileEntry _zfe, Stream _stream) + { + if (!_stream.CanWrite) + throw new InvalidOperationException("Stream cannot be written"); + + // check signature + byte[] signature = new byte[4]; + this.ZipFileStream.Seek(_zfe.HeaderOffset, SeekOrigin.Begin); + this.ZipFileStream.Read(signature, 0, 4); + if (BitConverter.ToUInt32(signature, 0) != 0x04034b50) + return false; + + // Select input stream for inflating or just reading + Stream inStream; + if (_zfe.Method == Compression.Store) + inStream = this.ZipFileStream; + else if (_zfe.Method == Compression.Deflate) + inStream = new DeflateStream(this.ZipFileStream, CompressionMode.Decompress, true); + else + return false; + + // Buffered copy + byte[] buffer = new byte[16384]; + this.ZipFileStream.Seek(_zfe.FileOffset, SeekOrigin.Begin); + uint bytesPending = _zfe.FileSize; + while (bytesPending > 0) + { + int bytesRead = inStream.Read(buffer, 0, (int)Math.Min(bytesPending, buffer.Length)); + _stream.Write(buffer, 0, bytesRead); + bytesPending -= (uint)bytesRead; + } + _stream.Flush(); + + if (_zfe.Method == Compression.Deflate) + inStream.Dispose(); + return true; + } + + #endregion + + #region Private methods + + /// + /// Calculate the file offset by reading the corresponding local header + /// + private uint GetFileOffset(uint _headerOffset) + { + byte[] buffer = new byte[2]; + + this.ZipFileStream.Seek(_headerOffset + 26, SeekOrigin.Begin); + this.ZipFileStream.Read(buffer, 0, 2); + ushort filenameSize = BitConverter.ToUInt16(buffer, 0); + this.ZipFileStream.Read(buffer, 0, 2); + ushort extraSize = BitConverter.ToUInt16(buffer, 0); + + return (uint)(30 + filenameSize + extraSize + _headerOffset); + } + /* Local file header: + local file header signature 4 bytes (0x04034b50) + version needed to extract 2 bytes + general purpose bit flag 2 bytes + compression method 2 bytes + last mod file time 2 bytes + last mod file date 2 bytes + crc-32 4 bytes + compressed size 4 bytes + uncompressed size 4 bytes + filename length 2 bytes + extra field length 2 bytes + + filename (variable size) + extra field (variable size) + */ + + /* Central directory's File header: + central file header signature 4 bytes (0x02014b50) + version made by 2 bytes + version needed to extract 2 bytes + general purpose bit flag 2 bytes + compression method 2 bytes + last mod file time 2 bytes + last mod file date 2 bytes + crc-32 4 bytes + compressed size 4 bytes + uncompressed size 4 bytes + filename length 2 bytes + extra field length 2 bytes + file comment length 2 bytes + disk number start 2 bytes + internal file attributes 2 bytes + external file attributes 4 bytes + relative offset of local header 4 bytes + + filename (variable size) + extra field (variable size) + file comment (variable size) + + * + /* End of central dir record: + end of central dir signature 4 bytes (0x06054b50) + number of this disk 2 bytes + number of the disk with the + start of the central directory 2 bytes + total number of entries in + the central dir on this disk 2 bytes + total number of entries in + the central dir 2 bytes + size of the central directory 4 bytes + offset of start of central + directory with respect to + the starting disk number 4 bytes + zipfile comment length 2 bytes + zipfile comment (variable size) + */ + + + /* DOS Date and time: + MS-DOS date. The date is a packed value with the following format. Bits Description + 0-4 Day of the month (1–31) + 5-8 Month (1 = January, 2 = February, and so on) + 9-15 Year offset from 1980 (add 1980 to get actual year) + MS-DOS time. The time is a packed value with the following format. Bits Description + 0-4 Second divided by 2 + 5-10 Minute (0–59) + 11-15 Hour (0–23 on a 24-hour clock) + */ + + private DateTime DosTimeToDateTime(uint _dt) + { + return new DateTime( + (int)(_dt >> 25) + 1980, + (int)(_dt >> 21) & 15, + (int)(_dt >> 16) & 31, + (int)(_dt >> 11) & 31, + (int)(_dt >> 5) & 63, + (int)(_dt & 31) * 2); + } + + // Reads the end-of-central-directory record + private bool ReadFileInfo() + { + if (this.ZipFileStream.Length < 22) + return false; + + try + { + this.ZipFileStream.Seek(-17, SeekOrigin.End); + BinaryReader br = new BinaryReader(this.ZipFileStream); + do + { + this.ZipFileStream.Seek(-5, SeekOrigin.Current); + UInt32 sig = br.ReadUInt32(); + if (sig == 0x06054b50) + { + this.ZipFileStream.Seek(6, SeekOrigin.Current); + + UInt16 entries = br.ReadUInt16(); + Int32 centralSize = br.ReadInt32(); + UInt32 centralDirOffset = br.ReadUInt32(); + UInt16 commentSize = br.ReadUInt16(); + + // check if comment field is the very last data in file + if (this.ZipFileStream.Position + commentSize != this.ZipFileStream.Length) + return false; + + // Copy entire central directory to a memory buffer + this.ExistingFiles = entries; + this.CentralDirImage = new byte[centralSize]; + this.ZipFileStream.Seek(centralDirOffset, SeekOrigin.Begin); + this.ZipFileStream.Read(this.CentralDirImage, 0, centralSize); + + // Leave the pointer at the begining of central dir, to append new files + this.ZipFileStream.Seek(centralDirOffset, SeekOrigin.Begin); + return true; + } + } while (this.ZipFileStream.Position > 0); + } + catch { } + + return false; + } + #endregion + + #region IDisposable Members + /// + /// Closes the Zip file stream + /// + public void Dispose() + { + this.Close(); + } + #endregion + } +}