SubtitleEdit/libse/SubtitleFormats/CaptionsInc.cs

264 lines
9.2 KiB
C#
Raw Normal View History

2016-02-08 21:11:03 +01:00
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
namespace Nikse.SubtitleEdit.Core.SubtitleFormats
{
public class CaptionsInc : SubtitleFormat
{
2017-07-23 10:53:25 +02:00
public override string Extension => ".cin";
2016-02-08 21:11:03 +01:00
2017-07-23 10:53:25 +02:00
public override string Name => "Caption Inc";
2016-02-08 21:11:03 +01:00
public static void Save(string fileName, Subtitle subtitle)
{
using (var fs = new FileStream(fileName, FileMode.Create, FileAccess.Write))
{
2019-09-29 14:33:26 +02:00
string name = Path.GetFileNameWithoutExtension(fileName);
2016-02-08 21:11:03 +01:00
byte[] buffer = Encoding.ASCII.GetBytes(name);
for (int i = 0; i < buffer.Length && i < 8; i++)
2019-01-19 14:40:37 +01:00
{
2016-02-08 21:11:03 +01:00
fs.WriteByte(buffer[i]);
2019-01-19 14:40:37 +01:00
}
2016-02-08 21:11:03 +01:00
while (fs.Length < 8)
2019-01-19 14:40:37 +01:00
{
2016-02-08 21:11:03 +01:00
fs.WriteByte(0x20);
2019-01-19 14:40:37 +01:00
}
2016-02-08 21:11:03 +01:00
WriteTime(fs, subtitle.Paragraphs[0].StartTime, false); // first start time
WriteTime(fs, subtitle.Paragraphs[subtitle.Paragraphs.Count - 1].EndTime, false); // last end time
2017-07-23 10:53:25 +02:00
buffer = Encoding.ASCII.GetBytes("Generic Unknown Unknown \"\" Unknown Unknown Unknown".PadRight(230, ' '));
2016-02-08 21:11:03 +01:00
fs.Write(buffer, 0, buffer.Length);
// paragraphs
foreach (Paragraph p in subtitle.Paragraphs)
{
buffer = new byte[] { 0x0D, 0x0A, 0xFE }; // header
fs.Write(buffer, 0, buffer.Length);
// styles
var text = new List<byte> { 0x14, 0x20, 0x14, 0x2E, 0x14, 0x54, 0x17 };
int noOfLines = Utilities.GetNumberOfLines(p.Text);
2019-09-29 14:33:26 +02:00
text.Add(noOfLines == 1 ? (byte)0x22 : (byte)0x21);
2016-02-08 21:11:03 +01:00
var lines = p.Text.Split(Utilities.NewLineChars, StringSplitOptions.None);
foreach (string line in lines)
{
foreach (char ch in line)
2019-01-19 14:40:37 +01:00
{
2016-02-08 21:11:03 +01:00
text.Add(Encoding.GetEncoding(1252).GetBytes(new[] { ch })[0]);
2019-01-19 14:40:37 +01:00
}
2016-02-08 21:11:03 +01:00
text.Add(0x14);
text.Add(0x74);
}
// codes+text length
2019-09-29 14:33:26 +02:00
buffer = Encoding.ASCII.GetBytes($"{text.Count:000}");
2016-02-08 21:11:03 +01:00
fs.Write(buffer, 0, buffer.Length);
WriteTime(fs, p.StartTime, true);
// write codes + text
foreach (byte b in text)
2019-01-19 14:40:37 +01:00
{
2016-02-08 21:11:03 +01:00
fs.WriteByte(b);
2019-01-19 14:40:37 +01:00
}
2016-02-08 21:11:03 +01:00
buffer = new byte[] { 0x14, 0x2F, 0x0D, 0x0A, 0xFE, 0x30, 0x30, 0x32, 0x30 };
fs.Write(buffer, 0, buffer.Length);
WriteTime(fs, p.EndTime, true);
}
}
}
private static void WriteTime(FileStream fs, TimeCode timeCode, bool addEndBytes)
{
var time = timeCode.ToHHMMSSFF();
var buffer = Encoding.ASCII.GetBytes(time);
fs.Write(buffer, 0, buffer.Length);
if (addEndBytes)
{
fs.WriteByte(0xd);
fs.WriteByte(0xa);
}
}
public override bool IsMine(List<string> lines, string fileName)
{
if (!string.IsNullOrEmpty(fileName) && File.Exists(fileName))
{
if (!fileName.EndsWith(".cin", StringComparison.OrdinalIgnoreCase))
2019-01-19 14:40:37 +01:00
{
2016-02-08 21:11:03 +01:00
return false;
2019-01-19 14:40:37 +01:00
}
2016-02-08 21:11:03 +01:00
return base.IsMine(lines, fileName);
2016-02-08 21:11:03 +01:00
}
return false;
}
public override string ToText(Subtitle subtitle, string title)
{
return "Not supported!";
}
private static TimeCode DecodeTimestamp(string timeCode)
{
try
{
return new TimeCode(int.Parse(timeCode.Substring(0, 2)), int.Parse(timeCode.Substring(2, 2)), int.Parse(timeCode.Substring(4, 2)), FramesToMillisecondsMax999(int.Parse(timeCode.Substring(6, 2))));
}
catch (Exception exception)
{
System.Diagnostics.Debug.WriteLine(exception.Message);
return new TimeCode();
2016-02-08 21:11:03 +01:00
}
}
public override void LoadSubtitle(Subtitle subtitle, List<string> lines, string fileName)
{
subtitle.Paragraphs.Clear();
subtitle.Header = null;
byte[] buffer = FileUtil.ReadAllBytesShared(fileName);
int i = 256;
Paragraph last = null;
while (i < buffer.Length - 20)
{
var p = new Paragraph();
while (buffer[i] != 0xfe && i < buffer.Length - 20)
{
i++;
}
if (buffer[i] == 0xfe)
{
i += 4;
string startTime = Encoding.ASCII.GetString(buffer, i, 8);
i += 8;
if (Utilities.IsInteger(startTime))
{
p.StartTime = DecodeTimestamp(startTime);
}
}
bool startFound = false;
bool textEnd = false;
while (!startFound && !textEnd && i < buffer.Length - 20)
{
bool skip = false;
if (buffer[i] == 0x0d)
2019-01-19 14:40:37 +01:00
{
2016-02-08 21:11:03 +01:00
i++;
2019-01-19 14:40:37 +01:00
}
2016-02-08 21:11:03 +01:00
else if (buffer[i] == 0x0a)
2019-01-19 14:40:37 +01:00
{
2016-02-08 21:11:03 +01:00
skip = true;
2019-01-19 14:40:37 +01:00
}
2016-02-08 21:11:03 +01:00
else if (buffer[i] == 0x14 && buffer[i + 1] == 0x2c) // text end
2019-01-19 14:40:37 +01:00
{
2016-02-08 21:11:03 +01:00
textEnd = true;
2019-01-19 14:40:37 +01:00
}
2016-02-08 21:11:03 +01:00
else if (buffer[i] <= 0x20) // text start
2019-01-19 14:40:37 +01:00
{
2016-02-08 21:11:03 +01:00
i++;
2019-01-19 14:40:37 +01:00
}
2016-02-08 21:11:03 +01:00
else
2019-01-19 14:40:37 +01:00
{
2016-02-08 21:11:03 +01:00
startFound = true;
2019-01-19 14:40:37 +01:00
}
2016-02-08 21:11:03 +01:00
if (!skip)
2019-01-19 14:40:37 +01:00
{
2016-02-08 21:11:03 +01:00
i++;
2019-01-19 14:40:37 +01:00
}
2016-02-08 21:11:03 +01:00
}
i++;
if (!textEnd)
{
i -= 2;
var sb = new StringBuilder();
while (!textEnd && i < buffer.Length - 20)
{
if (buffer[i] == 0x14 && buffer[i + 1] == 0x2c) // text end
2019-01-19 14:40:37 +01:00
{
2016-02-08 21:11:03 +01:00
textEnd = true;
2019-01-19 14:40:37 +01:00
}
2016-02-08 21:11:03 +01:00
else if (buffer[i] == 0xd && buffer[i + 1] == 0xa) // text end
2019-01-19 14:40:37 +01:00
{
2016-02-08 21:11:03 +01:00
textEnd = true;
2019-01-19 14:40:37 +01:00
}
2016-02-08 21:11:03 +01:00
else if (buffer[i] <= 0x17)
{
2017-07-23 10:53:25 +02:00
if (!sb.ToString().EndsWith(Environment.NewLine, StringComparison.Ordinal))
2019-01-19 14:40:37 +01:00
{
2016-02-08 21:11:03 +01:00
sb.Append(Environment.NewLine);
2019-01-19 14:40:37 +01:00
}
2016-02-08 21:11:03 +01:00
i++;
}
else
2019-01-19 14:40:37 +01:00
{
2016-02-08 21:11:03 +01:00
sb.Append(Encoding.GetEncoding(1252).GetString(buffer, i, 1));
2019-01-19 14:40:37 +01:00
}
2016-02-08 21:11:03 +01:00
i++;
}
i++;
if (sb.Length > 0)
{
string text = sb.ToString().Trim();
p.Text = text;
subtitle.Paragraphs.Add(p);
last = p;
}
}
if (buffer[i] == 0xFE)
{
string endTime = Encoding.ASCII.GetString(buffer, i + 4, 8);
if (Utilities.IsInteger(endTime))
{
p.EndTime = DecodeTimestamp(endTime);
}
while (i < buffer.Length && buffer[i] != 0xa)
2019-01-19 14:40:37 +01:00
{
2016-02-08 21:11:03 +01:00
i++;
2019-01-19 14:40:37 +01:00
}
2016-02-08 21:11:03 +01:00
i++;
}
else
{
while (i < buffer.Length && buffer[i] != 0xa)
2019-01-19 14:40:37 +01:00
{
2016-02-08 21:11:03 +01:00
i++;
2019-01-19 14:40:37 +01:00
}
2016-02-08 21:11:03 +01:00
i++;
if (buffer[i] == 0xfe)
{
string endTime = Encoding.ASCII.GetString(buffer, i + 4, 8);
if (Utilities.IsInteger(endTime))
{
p.EndTime = DecodeTimestamp(endTime);
}
}
}
}
if (last != null && last.Duration.TotalMilliseconds > Configuration.Settings.General.SubtitleMaximumDisplayMilliseconds)
2019-01-19 14:40:37 +01:00
{
2016-02-08 21:11:03 +01:00
last.EndTime.TotalMilliseconds = last.StartTime.TotalMilliseconds + Utilities.GetOptimalDisplayMilliseconds(last.Text);
2019-01-19 14:40:37 +01:00
}
2016-02-08 21:11:03 +01:00
subtitle.Renumber();
}
}
}