diff --git a/libse/LibSE.csproj b/libse/LibSE.csproj
index 5550a9e75..0feeff93d 100644
--- a/libse/LibSE.csproj
+++ b/libse/LibSE.csproj
@@ -195,6 +195,7 @@
+
diff --git a/libse/SubtitleFormats/MacSub.cs b/libse/SubtitleFormats/MacSub.cs
new file mode 100644
index 000000000..898a3474a
--- /dev/null
+++ b/libse/SubtitleFormats/MacSub.cs
@@ -0,0 +1,120 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace Nikse.SubtitleEdit.Core.SubtitleFormats
+{
+ ///
+ /// Implements MacSub (reading/writing).
+ /// http://devel.aegisub.org/wiki/SubtitleFormats/Macsub
+ ///
+ public class MacSub : SubtitleFormat
+ {
+ ///
+ /// Enum expecting line.
+ ///
+ private enum Expecting
+ {
+ StartFrame,
+ Text,
+ EndFrame
+ }
+
+ public override string Extension
+ {
+ get
+ {
+ return ".txt";
+ }
+ }
+
+ public override bool IsTimeBased
+ {
+ get
+ {
+ return false;
+ }
+ }
+
+ public override string Name
+ {
+ get
+ {
+ return "MacSub";
+ }
+ }
+
+ public override bool IsMine(List lines, string fileName)
+ {
+ var macSub = new Subtitle();
+ LoadSubtitle(macSub, lines, fileName);
+ return macSub.Paragraphs.Count > _errorCount;
+ }
+
+ public override void LoadSubtitle(Subtitle subtitle, List lines, string fileName)
+ {
+ var expecting = Expecting.StartFrame;
+ subtitle.Paragraphs.Clear();
+ _errorCount = 0;
+ var p = new Paragraph();
+ for (int i = 0; i < lines.Count; i++)
+ {
+ string line = lines[i].Trim();
+ string nextLine = null;
+ if (i + 1 < lines.Count)
+ {
+ nextLine = lines[i + 1].Trim();
+ }
+ try
+ {
+ switch (expecting)
+ {
+ case Expecting.StartFrame:
+ p.StartFrame = int.Parse(line.TrimStart('/'));
+ expecting = Expecting.Text;
+ 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;
+ p.Number = i;
+ }
+ break;
+
+ case Expecting.EndFrame:
+ p.EndFrame = int.Parse(line.TrimStart('/'));
+ subtitle.Paragraphs.Add(p);
+ // Prepare for next reading.
+ p = new Paragraph();
+ expecting = Expecting.StartFrame;
+ 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();
+ }
+ }
+}
diff --git a/libse/SubtitleFormats/SubtitleFormat.cs b/libse/SubtitleFormats/SubtitleFormat.cs
index 84835e051..edc646a5d 100644
--- a/libse/SubtitleFormats/SubtitleFormat.cs
+++ b/libse/SubtitleFormats/SubtitleFormat.cs
@@ -87,6 +87,7 @@ namespace Nikse.SubtitleEdit.Core.SubtitleFormats
new JsonType6(),
new JsonType7(),
new Lrc(),
+ new MacSub(),
new MediaTransData(),
new MicroDvd(),
new MidwayInscriberCGX(),
diff --git a/src/Test/Logic/SubtitleFormats/SubtitleFormatsTest.cs b/src/Test/Logic/SubtitleFormats/SubtitleFormatsTest.cs
index 80662aaea..2334e8dc3 100644
--- a/src/Test/Logic/SubtitleFormats/SubtitleFormatsTest.cs
+++ b/src/Test/Logic/SubtitleFormats/SubtitleFormatsTest.cs
@@ -899,5 +899,34 @@ Dialogue: Marked=0,0:00:01.00,0:00:03.00,Default,NTP,0000,0000,0000,!Effect," +
#endregion
+ #region MacSub
+
+ [TestMethod]
+ public void MacSubTest()
+ {
+ const string input = @"/3035
+Every satellite...
+/3077
+/3082
+every constellation...
+/3133
+/3138
+""souvenirs of space walks
+and astronauts.“...""
+/3205";
+ var macSub = new MacSub();
+ var subtitle = new Subtitle();
+ macSub.LoadSubtitle(subtitle, new List(input.SplitToLines()), null);
+
+ // Test text.
+ Assert.AreEqual("Every satellite...", subtitle.Paragraphs[0].Text);
+ // Test line count.
+ Assert.AreEqual(2, subtitle.Paragraphs[2].NumberOfLines);
+ // Test frame.
+ Assert.AreEqual(3082, subtitle.Paragraphs[1].StartFrame);
+ }
+
+ #endregion
+
}
}