mirror of
https://github.com/SubtitleEdit/subtitleedit.git
synced 2024-11-21 18:52:36 +01:00
Initial version
git-svn-id: https://subtitleedit.googlecode.com/svn/trunk@13 99eadd0c-20b8-1223-b5c4-2a2b2df33de2
This commit is contained in:
parent
f73c7479e4
commit
976be2c6e6
36
src/Logic/Configuration.cs
Normal file
36
src/Logic/Configuration.cs
Normal file
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
86
src/Logic/FastBitmap.cs
Normal file
86
src/Logic/FastBitmap.cs
Normal file
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
164
src/Logic/FindReplaceDialogHelper.cs
Normal file
164
src/Logic/FindReplaceDialogHelper.cs
Normal file
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
26
src/Logic/HistoryItem.cs
Normal file
26
src/Logic/HistoryItem.cs
Normal file
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
408
src/Logic/IfoParser.cs
Normal file
408
src/Logic/IfoParser.cs
Normal file
@ -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<AudioStream> AudioStreams;
|
||||
public List<string> Subtitles;
|
||||
|
||||
public VtsVobs()
|
||||
{
|
||||
VideoStream = new VideoStream();
|
||||
AudioStreams = new List<AudioStream>();
|
||||
Subtitles = new List<string>();
|
||||
}
|
||||
};
|
||||
|
||||
public class ProgramChain
|
||||
{
|
||||
public int NumberOfPGC;
|
||||
public int NumberOfCells;
|
||||
public string PlaybackTime;
|
||||
public List<byte> PGCEntryCells;
|
||||
public List<string> PGCPlaybackTimes;
|
||||
public List<string> PGCStartTimes;
|
||||
public List<char> AudioStreamsAvailable;
|
||||
public List<char> SubtitlesAvailable;
|
||||
public List<Color> ColorLookupTable;
|
||||
|
||||
public ProgramChain()
|
||||
{
|
||||
PGCEntryCells = new List<byte>();
|
||||
PGCPlaybackTimes = new List<string>();
|
||||
PGCStartTimes = new List<string>();
|
||||
AudioStreamsAvailable = new List<char>();
|
||||
SubtitlesAvailable = new List<char>();
|
||||
ColorLookupTable = new List<Color>();
|
||||
}
|
||||
};
|
||||
|
||||
public class VtsPgci
|
||||
{
|
||||
public int NumberOfProgramChains;
|
||||
public List<ProgramChain> ProgramChains;
|
||||
|
||||
public VtsPgci()
|
||||
{
|
||||
ProgramChains = new List<ProgramChain>();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
readonly List<string> ArrayOfAudioMode = new List<string> { "AC3", "...", "MPEG1", "MPEG2", "LPCM", "...", "DTS" };
|
||||
readonly List<string> ArrayOfAudioExtension = new List<string> { "unspecified", "normal", "for visually impaired", "director's comments", "alternate director's comments" };
|
||||
readonly List<string> ArrayOfAspect = new List<string> { "4:3", "...", "...", "16:9" };
|
||||
readonly List<string> ArrayOfStandard = new List<string> { "NTSC", "PAL", "...", "..." };
|
||||
readonly List<string> ArrayOfCodingMode = new List<string> { "MPEG1", "MPEG2" };
|
||||
readonly List<string> ArrayOfNTSCResolution = new List<string> { "720x480", "704x480", "352x480", "352x240" };
|
||||
readonly List<string> ArrayOfPALResolution = new List<string> { "720x576", "704x576", "352x576", "352x288" };
|
||||
readonly List<string> ArrayOfLangageCode = new List<string> { " ", "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<string> ArrayOfLangage = new List<string> { "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<AudioStream>();
|
||||
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<ProgramChain>();
|
||||
|
||||
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<int> timeArray = new List<int>();
|
||||
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);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
361
src/Logic/ImageSplitter.cs
Normal file
361
src/Logic/ImageSplitter.cs
Normal file
@ -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<ImageSplitterItem> SplitVertical(Bitmap bmp)
|
||||
{ // split into lines
|
||||
int startY = 0;
|
||||
int size = 0;
|
||||
var parts = new List<ImageSplitterItem>();
|
||||
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<ImageSplitterItem> SplitHorizontal(ImageSplitterItem verticalItem, int xOrMorePixelsMakesSpace)
|
||||
{ // split line into letters
|
||||
Bitmap bmp = verticalItem.Bitmap;
|
||||
var parts = new List<ImageSplitterItem>();
|
||||
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<Point>();
|
||||
|
||||
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<Point> 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<ImageSplitterItem> SplitBitmapToLetters(Bitmap bmp, int xOrMorePixelsMakesSpace)
|
||||
{
|
||||
var list = new List<ImageSplitterItem>();
|
||||
|
||||
// split into seperate lines
|
||||
List<ImageSplitterItem> 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;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
28
src/Logic/ImageSplitterItem.cs
Normal file
28
src/Logic/ImageSplitterItem.cs
Normal file
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
1362
src/Logic/Language.cs
Normal file
1362
src/Logic/Language.cs
Normal file
File diff suppressed because it is too large
Load Diff
1160
src/Logic/LanguageStructure.cs
Normal file
1160
src/Logic/LanguageStructure.cs
Normal file
File diff suppressed because it is too large
Load Diff
105
src/Logic/Paragraph.cs
Normal file
105
src/Logic/Paragraph.cs
Normal file
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
15
src/Logic/PositionAndSize.cs
Normal file
15
src/Logic/PositionAndSize.cs
Normal file
@ -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; }
|
||||
}
|
||||
}
|
56
src/Logic/PositionsAndSizes.cs
Normal file
56
src/Logic/PositionsAndSizes.cs
Normal file
@ -0,0 +1,56 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace Nikse.SubtitleEdit.Logic
|
||||
{
|
||||
class PositionsAndSizes
|
||||
{
|
||||
List<PositionAndSize> _positionsAndSizes = new List<PositionAndSize>();
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
902
src/Logic/Settings.cs
Normal file
902
src/Logic/Settings.cs
Normal file
@ -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<string> FileNames { get; set; }
|
||||
|
||||
public RecentFilesSettings()
|
||||
{
|
||||
FileNames = new List<string>();
|
||||
}
|
||||
|
||||
public void Add(string fileName)
|
||||
{
|
||||
var newList = new List<string> {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 = "<br />";
|
||||
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<MultipleSearchAndReplaceSetting> 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<MultipleSearchAndReplaceSetting>();
|
||||
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<MultipleSearchAndReplaceSetting>();
|
||||
|
||||
return settings;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A faster serializer than xml serializer... which is insanely slow (first time)!!!!
|
||||
/// This method is auto-generated with XmlSerializerGenerator
|
||||
/// </summary>
|
||||
/// <param name="fileName">File name of xml settings file to load</param>
|
||||
/// <returns>Newly loaded settings</returns>
|
||||
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();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
241
src/Logic/StripableText.cs
Normal file
241
src/Logic/StripableText.cs
Normal file
@ -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 <i> or <font color="#ff0000">
|
||||
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 </i> </b> </u>
|
||||
if (text.ToLower().EndsWith("</i>") ||
|
||||
text.ToLower().EndsWith("</b>") ||
|
||||
text.ToLower().EndsWith("</u>"))
|
||||
{
|
||||
Post = text.Substring(text.Length - 4, 4) + Post;
|
||||
text = text.Substring(0, text.Length - 4);
|
||||
}
|
||||
|
||||
// tag </font>
|
||||
if (text.ToLower().EndsWith("</font>"))
|
||||
{
|
||||
Post = text.Substring(text.Length - 7, 7) + Post;
|
||||
text = text.Substring(0, text.Length - 7);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
StrippedText = text;
|
||||
}
|
||||
|
||||
private static string GetAndInsertNextId(List<string> replaceIds, List<string> 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<string> namesEtc, List<string> replaceIds, List<string> replaceNames, List<string> 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<string> replaceIds, List<string> replaceNames)
|
||||
{
|
||||
for (int i=0; i<replaceIds.Count; i++)
|
||||
{
|
||||
StrippedText = StrippedText.Replace(replaceIds[i], replaceNames[i]);
|
||||
}
|
||||
}
|
||||
|
||||
public void FixCasing(List<string> namesEtc, bool changeNameCases, bool makeUppercaseAfterBreak, bool checkLastLine, string lastLine)
|
||||
{
|
||||
var replaceIds = new List<string>();
|
||||
var replaceNames = new List<string>();
|
||||
var originalNames = new List<string>();
|
||||
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<StrippedText.Length; i++)
|
||||
{
|
||||
string s = StrippedText[i].ToString();
|
||||
if (lastWasBreak)
|
||||
{
|
||||
if (("\"`´'()<>!?.- " + Environment.NewLine).Contains(s))
|
||||
{
|
||||
sb.Append(s);
|
||||
}
|
||||
else if ((sb.ToString().EndsWith("<") || sb.ToString().EndsWith("</")) && i + 1 < StrippedText.Length && StrippedText[i + 1] == '>')
|
||||
{ // 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);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
397
src/Logic/Subtitle.cs
Normal file
397
src/Logic/Subtitle.cs
Normal file
@ -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<Paragraph> _paragraphs;
|
||||
List<HistoryItem> _history;
|
||||
SubtitleFormat _format;
|
||||
bool _wasLoadedWithFrameNumbers;
|
||||
public string Header { get; set; }
|
||||
|
||||
public string FileName { get; set; }
|
||||
|
||||
public SubtitleFormat OriginalFormat
|
||||
{
|
||||
get
|
||||
{
|
||||
return _format;
|
||||
}
|
||||
}
|
||||
|
||||
public List<HistoryItem> HistoryItems
|
||||
{
|
||||
get { return _history; }
|
||||
}
|
||||
|
||||
public Subtitle()
|
||||
{
|
||||
_paragraphs = new List<Paragraph>();
|
||||
_history = new List<HistoryItem>();
|
||||
FileName = "Untitled";
|
||||
}
|
||||
|
||||
public Subtitle(List<HistoryItem> historyItems) : this()
|
||||
{
|
||||
_history = historyItems;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Copy constructor (only paragraphs)
|
||||
/// </summary>
|
||||
/// <param name="subtitle">Subtitle to copy</param>
|
||||
public Subtitle(Subtitle subtitle) : this()
|
||||
{
|
||||
foreach (Paragraph p in subtitle.Paragraphs)
|
||||
{
|
||||
_paragraphs.Add(new Paragraph(p));
|
||||
}
|
||||
_wasLoadedWithFrameNumbers = subtitle.WasLoadedWithFrameNumbers;
|
||||
}
|
||||
|
||||
public List<Paragraph> 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<string> 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<Paragraph>();
|
||||
|
||||
var lines = new List<string>();
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Calculate the time codes from framenumber/framerate
|
||||
/// </summary>
|
||||
/// <param name="frameRate">Number of frames per second</param>
|
||||
/// <returns>True if times could be calculated</returns>
|
||||
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;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Calculate the frame numbers from time codes/framerate
|
||||
/// </summary>
|
||||
/// <param name="frameRate"></param>
|
||||
/// <returns></returns>
|
||||
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;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sort subtitle paragraphs
|
||||
/// </summary>
|
||||
/// <param name="sortCriteria">Paragraph sort criteria</param>
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
125
src/Logic/TimeCode.cs
Normal file
125
src/Logic/TimeCode.cs
Normal file
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
1335
src/Logic/Utilities.cs
Normal file
1335
src/Logic/Utilities.cs
Normal file
File diff suppressed because it is too large
Load Diff
22
src/Logic/Wave.cs
Normal file
22
src/Logic/Wave.cs
Normal file
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
353
src/Logic/WavePeak.cs
Normal file
353
src/Logic/WavePeak.cs
Normal file
@ -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; }
|
||||
|
||||
/// <summary>
|
||||
/// 1 = PCM (uncompressed)
|
||||
/// </summary>
|
||||
public int AudioFormat { get; private set; }
|
||||
|
||||
public int NumberOfChannels { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Number of samples per second
|
||||
/// </summary>
|
||||
public int SampleRate { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Should be SampleRate * BlockAlign
|
||||
/// </summary>
|
||||
public int ByteRate { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// 8 bytes per block (32 bit); 6 bytes per block (24 bit); 4 bytes per block (16 bit)
|
||||
/// </summary>
|
||||
public int BlockAlign { get; private set; }
|
||||
|
||||
public int BitsPerSample { get; private set; }
|
||||
|
||||
public string DataId { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Size of sound data
|
||||
/// </summary>
|
||||
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; }
|
||||
|
||||
/// <summary>
|
||||
/// Lowest data value
|
||||
/// </summary>
|
||||
public int DataMinValue { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Highest data value
|
||||
/// </summary>
|
||||
public int DataMaxValue { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Number of peaks per second (should be divideable by SampleRate)
|
||||
/// </summary>
|
||||
public int PeaksPerSecond { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// List of all peak samples (channels are merged)
|
||||
/// </summary>
|
||||
public List<int> PeakSamples { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// List of all samples (channels are merged)
|
||||
/// </summary>
|
||||
public List<int> AllSamples { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Constructor
|
||||
/// </summary>
|
||||
/// <param name="fileName">Wave file name</param>
|
||||
public WavePeakGenerator(string fileName)
|
||||
{
|
||||
Initialize(new FileStream(fileName, FileMode.Open, FileAccess.Read));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructor
|
||||
/// </summary>
|
||||
/// <param name="stream">Stream of a wave file</param>
|
||||
public WavePeakGenerator(Stream stream)
|
||||
{
|
||||
Initialize(stream);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Generate peaks (samples with some interval) for an uncompressed wave file
|
||||
/// </summary>
|
||||
/// <param name="peaksPerSecond">Sampeles per second / sample rate</param>
|
||||
public void GeneratePeakSamples(int peaksPerSecond)
|
||||
{
|
||||
PeaksPerSecond = peaksPerSecond;
|
||||
|
||||
ReadSampleDataValueDelegate readSampleDataValue = GetSampleDataRerader();
|
||||
DataMinValue = int.MaxValue;
|
||||
DataMaxValue = int.MinValue;
|
||||
PeakSamples = new List<int>();
|
||||
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>();
|
||||
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;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determine how to read sample values
|
||||
/// </summary>
|
||||
/// <returns>Sample data reader that matches bits per sample</returns>
|
||||
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();
|
||||
}
|
||||
}
|
||||
}
|
433
src/Logic/ZipExtractor.cs
Normal file
433
src/Logic/ZipExtractor.cs
Normal file
@ -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
|
||||
{
|
||||
/// <summary>
|
||||
/// Zip archive decompression. Represents a Zip file.
|
||||
/// </summary>
|
||||
public class ZipExtractor : IDisposable
|
||||
{
|
||||
/// <summary>
|
||||
/// Compression method enumeration
|
||||
/// </summary>
|
||||
public enum Compression : ushort
|
||||
{
|
||||
/// <summary>Uncompressed storage</summary>
|
||||
Store = 0,
|
||||
/// <summary>Deflate compression method</summary>
|
||||
Deflate = 8
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Represents an entry in Zip file directory
|
||||
/// </summary>
|
||||
public struct ZipFileEntry
|
||||
{
|
||||
/// <summary>Compression method</summary>
|
||||
public Compression Method;
|
||||
/// <summary>Full path and filename as stored in Zip</summary>
|
||||
public string FilenameInZip;
|
||||
/// <summary>Original file size</summary>
|
||||
public uint FileSize;
|
||||
/// <summary>Compressed file size</summary>
|
||||
public uint CompressedSize;
|
||||
/// <summary>Offset of header information inside Zip storage</summary>
|
||||
public uint HeaderOffset;
|
||||
/// <summary>Offset of file inside Zip storage</summary>
|
||||
public uint FileOffset;
|
||||
/// <summary>Size of header information</summary>
|
||||
public uint HeaderSize;
|
||||
/// <summary>32-bit checksum of entire file</summary>
|
||||
public uint Crc32;
|
||||
/// <summary>Last modification time of file</summary>
|
||||
public DateTime ModifyTime;
|
||||
/// <summary>User comment for file</summary>
|
||||
public string Comment;
|
||||
/// <summary>True if UTF8 encoding for filename and comments, false if default (CP 437)</summary>
|
||||
public bool EncodeUTF8;
|
||||
|
||||
/// <summary>Overriden method</summary>
|
||||
/// <returns>Filename in Zip</returns>
|
||||
public override string ToString()
|
||||
{
|
||||
return this.FilenameInZip;
|
||||
}
|
||||
}
|
||||
|
||||
#region Public fields
|
||||
/// <summary>True if UTF8 encoding for filename and comments, false if default (CP 437)</summary>
|
||||
public bool EncodeUTF8 = false;
|
||||
/// <summary>Force deflate algotithm even if it inflates the stored file. Off by default.</summary>
|
||||
public bool ForceDeflating = false;
|
||||
#endregion
|
||||
|
||||
#region Private fields
|
||||
// List of files to store
|
||||
private List<ZipFileEntry> Files = new List<ZipFileEntry>();
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Method to open an existing storage file
|
||||
/// </summary>
|
||||
/// <param name="_filename">Full path of Zip file to open</param>
|
||||
/// <returns>A valid ZipStorer object</returns>
|
||||
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;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Method to open an existing storage from stream
|
||||
/// </summary>
|
||||
/// <param name="_stream">Already opened stream with zip contents</param>
|
||||
/// <returns>A valid ZipStorer object</returns>
|
||||
public static ZipExtractor Open(Stream _stream)
|
||||
{
|
||||
ZipExtractor zip = new ZipExtractor();
|
||||
zip.ZipFileStream = _stream;
|
||||
|
||||
if (zip.ReadFileInfo())
|
||||
return zip;
|
||||
|
||||
throw new System.IO.InvalidDataException();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Close the Zip storage
|
||||
/// </summary>
|
||||
/// <remarks>This is a required step, unless automatic dispose is used</remarks>
|
||||
public void Close()
|
||||
{
|
||||
if (this.ZipFileStream != null)
|
||||
{
|
||||
this.ZipFileStream.Flush();
|
||||
this.ZipFileStream.Dispose();
|
||||
this.ZipFileStream = null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read all the file records in the central directory
|
||||
/// </summary>
|
||||
/// <returns>List of all entries in directory</returns>
|
||||
public List<ZipFileEntry> ReadCentralDir()
|
||||
{
|
||||
if (this.CentralDirImage == null)
|
||||
throw new InvalidOperationException("Central directory currently does not exist");
|
||||
|
||||
List<ZipFileEntry> result = new List<ZipFileEntry>();
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Copy the contents of a stored file into a physical file
|
||||
/// </summary>
|
||||
/// <param name="_zfe">Entry information of file to extract</param>
|
||||
/// <param name="_filename">Name of file to store uncompressed data</param>
|
||||
/// <returns>True if success, false if not.</returns>
|
||||
/// <remarks>Unique compression methods are Store and Deflate</remarks>
|
||||
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;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Copy the contents of a stored file into an opened stream
|
||||
/// </summary>
|
||||
/// <param name="_zfe">Entry information of file to extract</param>
|
||||
/// <param name="_stream">Stream to store the uncompressed data</param>
|
||||
/// <returns>True if success, false if not.</returns>
|
||||
/// <remarks>Unique compression methods are Store and Deflate</remarks>
|
||||
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
|
||||
|
||||
/// <summary>
|
||||
/// Calculate the file offset by reading the corresponding local header
|
||||
/// </summary>
|
||||
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
|
||||
/// <summary>
|
||||
/// Closes the Zip file stream
|
||||
/// </summary>
|
||||
public void Dispose()
|
||||
{
|
||||
this.Close();
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user