2016-09-24 22:56:49 +02:00
|
|
|
|
using System;
|
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
using System.Text;
|
|
|
|
|
|
|
|
|
|
namespace Nikse.SubtitleEdit.Core.SubtitleFormats
|
|
|
|
|
{
|
|
|
|
|
/// <summary>
|
2016-10-24 22:35:39 +02:00
|
|
|
|
/// MacSub (reading/writing).
|
2016-09-24 22:56:49 +02:00
|
|
|
|
/// http://devel.aegisub.org/wiki/SubtitleFormats/Macsub
|
|
|
|
|
/// </summary>
|
|
|
|
|
public class MacSub : SubtitleFormat
|
|
|
|
|
{
|
|
|
|
|
private enum Expecting
|
|
|
|
|
{
|
|
|
|
|
StartFrame,
|
|
|
|
|
Text,
|
|
|
|
|
EndFrame
|
|
|
|
|
}
|
|
|
|
|
|
2017-08-03 12:43:52 +02:00
|
|
|
|
public override string Extension => ".txt";
|
2016-09-24 22:56:49 +02:00
|
|
|
|
|
2017-08-03 12:43:52 +02:00
|
|
|
|
public override bool IsTimeBased => false;
|
2016-09-24 22:56:49 +02:00
|
|
|
|
|
2017-08-03 12:43:52 +02:00
|
|
|
|
public override string Name => "MacSub";
|
2016-09-24 22:56:49 +02:00
|
|
|
|
|
|
|
|
|
public override void LoadSubtitle(Subtitle subtitle, List<string> lines, string fileName)
|
|
|
|
|
{
|
|
|
|
|
var expecting = Expecting.StartFrame;
|
|
|
|
|
subtitle.Paragraphs.Clear();
|
|
|
|
|
_errorCount = 0;
|
2016-10-24 21:36:17 +02:00
|
|
|
|
char[] trimChar = { '/' };
|
2016-09-24 22:56:49 +02:00
|
|
|
|
var p = new Paragraph();
|
2016-10-20 03:02:26 +02:00
|
|
|
|
for (int i = 0, lineNumber = 1; i < lines.Count; i++)
|
2016-09-24 22:56:49 +02:00
|
|
|
|
{
|
|
|
|
|
string line = lines[i].Trim();
|
|
|
|
|
string nextLine = null;
|
|
|
|
|
if (i + 1 < lines.Count)
|
|
|
|
|
{
|
|
|
|
|
nextLine = lines[i + 1].Trim();
|
|
|
|
|
}
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
switch (expecting)
|
|
|
|
|
{
|
|
|
|
|
case Expecting.StartFrame:
|
2016-10-25 20:00:53 +02:00
|
|
|
|
if (ContainsOnlyNumber(line))
|
2016-10-24 21:36:17 +02:00
|
|
|
|
{
|
|
|
|
|
p.StartFrame = int.Parse(line.TrimStart(trimChar));
|
|
|
|
|
expecting = Expecting.Text;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
_errorCount++;
|
|
|
|
|
}
|
2016-09-24 22:56:49 +02:00
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case Expecting.Text:
|
|
|
|
|
line = HtmlUtil.RemoveHtmlTags(line, true);
|
|
|
|
|
p.Text += string.IsNullOrEmpty(p.Text) ? line : Environment.NewLine + line;
|
|
|
|
|
// Next reading is going to be endframe if next line starts with (/) delimeter which indicates frame start.
|
|
|
|
|
if ((nextLine == null) || (nextLine.Length > 0 && nextLine[0] == '/'))
|
|
|
|
|
{
|
|
|
|
|
expecting = Expecting.EndFrame;
|
2016-10-20 03:02:26 +02:00
|
|
|
|
p.Number = lineNumber++;
|
2016-09-24 22:56:49 +02:00
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case Expecting.EndFrame:
|
2016-10-25 20:00:53 +02:00
|
|
|
|
if (ContainsOnlyNumber(line))
|
|
|
|
|
{
|
|
|
|
|
p.EndFrame = int.Parse(line.TrimStart(trimChar));
|
|
|
|
|
subtitle.Paragraphs.Add(p);
|
|
|
|
|
// Prepare for next reading.
|
|
|
|
|
p = new Paragraph();
|
|
|
|
|
expecting = Expecting.StartFrame;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
_errorCount++;
|
|
|
|
|
}
|
2016-09-24 22:56:49 +02:00
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
catch
|
|
|
|
|
{
|
|
|
|
|
_errorCount++;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public override string ToText(Subtitle subtitle, string title)
|
|
|
|
|
{
|
|
|
|
|
// Startframe
|
|
|
|
|
// Text
|
|
|
|
|
// Endframe.
|
|
|
|
|
const string writeFormat = "/{0}{3}{1}{3}/{2}{3}";
|
|
|
|
|
var sb = new StringBuilder();
|
|
|
|
|
foreach (var p in subtitle.Paragraphs)
|
|
|
|
|
{
|
|
|
|
|
sb.AppendFormat(writeFormat, MillisecondsToFrames(p.StartTime.TotalMilliseconds), HtmlUtil.RemoveHtmlTags(p.Text, true),
|
|
|
|
|
MillisecondsToFrames(p.EndTime.TotalMilliseconds), Environment.NewLine);
|
|
|
|
|
}
|
|
|
|
|
return sb.ToString();
|
|
|
|
|
}
|
2016-10-25 20:00:53 +02:00
|
|
|
|
|
2016-11-20 18:18:09 +01:00
|
|
|
|
public static bool ContainsOnlyNumber(string input)
|
2016-10-25 20:00:53 +02:00
|
|
|
|
{
|
2016-11-20 18:18:09 +01:00
|
|
|
|
int len = input.Length;
|
2016-10-25 20:00:53 +02:00
|
|
|
|
// 10 = length of int.MaxValue (2147483647); +1 if starts with '/'
|
2016-11-20 18:18:09 +01:00
|
|
|
|
if (len == 0 || len > 11 || input[0] != '/')
|
2016-10-25 20:00:53 +02:00
|
|
|
|
return false;
|
|
|
|
|
int halfLen = len / 2;
|
|
|
|
|
for (int i = 1; i <= halfLen; i++) // /10.0 (Do not parse double)
|
|
|
|
|
{
|
2016-11-20 18:18:09 +01:00
|
|
|
|
if (!(CharUtils.IsDigit(input[i]) && CharUtils.IsDigit(input[len - i])))
|
2016-10-25 20:00:53 +02:00
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
2016-09-24 22:56:49 +02:00
|
|
|
|
}
|
|
|
|
|
}
|