using System; using System.Collections.Generic; using System.Text; using System.Xml; namespace Nikse.SubtitleEdit.Core.SubtitleFormats { // // ... // // // // // // // ... public class TmpegEncXml : SubtitleFormat { public override string Extension { get { return ".xsubtitle"; } } public override string Name { get { return "TMPGEnc VME"; } } public override bool IsTimeBased { get { return true; } } public override bool IsMine(List lines, string fileName) { var sb = new StringBuilder(); lines.ForEach(line => sb.AppendLine(line)); string xmlAsString = sb.ToString().Trim(); if ((xmlAsString.Contains("") || xmlAsString.Contains(" _errorCount; } return false; } internal const string Layout = @" 23 0.069 17588159451135 0 0 0 0 1 2 0 1 0.005 0 1 0 0.005 0 1 0 1000 0 1000 0 1 0 23 0.069 17588159451135 0 0 0 0 1 0 0 1 0.005 0 1 0 0.005 0 1 0 1000 0 1000 0 1 0 23 0.069 17588159451135 0 0 0 0 0 1 1 1 0.005 0 1 0 0.005 0 1 0 1000 0 1000 0 1 1 23 0.069 17588159451135 0 0 0 0 2 1 1 1 0.005 0 1 0 0.005 0 1 0 1000 0 1000 0 1 1 23 0.069 17588159451135 0 1 0 0 1 2 0 1 0.005 0 1 0 0.005 0 1 0 1000 0 1000 0 1 0 @ "; public override string ToText(Subtitle subtitle, string title) { var xmlStructure = Layout.Replace('\'', '"'); var xml = new XmlDocument(); xml.LoadXml(xmlStructure); XmlNode div = xml.DocumentElement.SelectSingleNode("Subtitle"); div.InnerXml = string.Empty; int no = 0; foreach (Paragraph p in subtitle.Paragraphs) { XmlNode paragraph = xml.CreateElement("SubtitleItem"); var text = HtmlUtil.RemoveHtmlTags(p.Text, true); paragraph.InnerText = text; paragraph.InnerXml = ""; XmlAttribute layoutIndex = xml.CreateAttribute("layoutindex"); if (p.Text.TrimStart().StartsWith("", StringComparison.OrdinalIgnoreCase) && p.Text.TrimEnd().EndsWith("", StringComparison.OrdinalIgnoreCase)) layoutIndex.InnerText = "4"; else layoutIndex.InnerText = "0"; paragraph.Attributes.Append(layoutIndex); XmlAttribute enable = xml.CreateAttribute("enable"); enable.InnerText = "1"; paragraph.Attributes.Append(enable); XmlAttribute start = xml.CreateAttribute("starttime"); start.InnerText = p.StartTime.ToString(); paragraph.Attributes.Append(start); XmlAttribute end = xml.CreateAttribute("endtime"); end.InnerText = p.EndTime.ToString(); paragraph.Attributes.Append(end); div.AppendChild(paragraph); no++; } string s = ToUtf8XmlString(xml); var startPos = s.IndexOf("", StringComparison.Ordinal) + 10; s = s.Substring(startPos, s.IndexOf("", StringComparison.Ordinal) - startPos).Trim(); return Layout.Replace("@", s); } public override void LoadSubtitle(Subtitle subtitle, List lines, string fileName) { LoadTMpeg(subtitle, lines, false); } internal void LoadTMpeg(Subtitle subtitle, List lines, bool mustHaveLineBreakAsEnd) { _errorCount = 0; double startSeconds = 0; var sb = new StringBuilder(); lines.ForEach(line => sb.AppendLine(line)); var xml = new XmlDocument { XmlResolver = null }; xml.LoadXml(sb.ToString().Trim()); var italicStyles = new List(); foreach (XmlNode node in xml.DocumentElement.SelectNodes("Layout/LayoutItem")) { XmlNode fontItalic = node.SelectSingleNode("FontItalic"); if (fontItalic != null && fontItalic.InnerText == "1") italicStyles.Add(true); else italicStyles.Add(false); } foreach (XmlNode node in xml.DocumentElement.SelectNodes("Subtitle/SubtitleItem")) { try { var pText = new StringBuilder(); foreach (XmlNode innerNode in node.SelectSingleNode("Text").ChildNodes) { switch (innerNode.Name) { case "br": pText.AppendLine(); break; default: pText.Append(innerNode.InnerText.Trim()); break; } } var start = string.Empty; if (node.Attributes["starttime"] != null) { start = node.Attributes["starttime"].InnerText; } var end = string.Empty; if (node.Attributes["endtime"] != null) { end = node.Attributes["endtime"].InnerText; } var startCode = TimeCode.FromSeconds(startSeconds); if (start.Length > 0) { startCode = GetTimeCode(start); } TimeCode endCode; if (end.Length > 0) { endCode = GetTimeCode(end); } else { endCode = new TimeCode(startCode.TotalMilliseconds + 3000); } startSeconds = endCode.TotalSeconds; if (mustHaveLineBreakAsEnd) { if (!pText.ToString().EndsWith("\\n", StringComparison.Ordinal)) _errorCount++; } else { if (pText.ToString().EndsWith("\\n", StringComparison.Ordinal)) _errorCount++; } var p = new Paragraph(startCode, endCode, pText.ToString().Trim().Replace("", string.Empty).Replace("", string.Empty).Replace("\\n", Environment.NewLine).TrimEnd()); if (node.Attributes["layoutindex"] != null) { int idx; if (int.TryParse(node.Attributes["layoutindex"].InnerText, out idx)) { if (idx >= 0 && idx < italicStyles.Count && italicStyles[idx]) p.Text = "" + p.Text + ""; } } subtitle.Paragraphs.Add(p); } catch (Exception ex) { System.Diagnostics.Debug.WriteLine(ex.Message); _errorCount++; } } subtitle.Renumber(); } private static TimeCode GetTimeCode(string s) { if (s.EndsWith('s')) { s = s.TrimEnd('s'); return TimeCode.FromSeconds(double.Parse(s)); } string[] parts = s.Split(new[] { ':', '.', ',' }); return new TimeCode(int.Parse(parts[0]), int.Parse(parts[1]), int.Parse(parts[2]), int.Parse(parts[3])); } } }