2
* This file is part of SubLib.
3
* Copyright (C) 2005-2007 Pedro Castro
5
* SubLib is free software; you can redistribute it and/or modify
6
* it under the terms of the GNU General Public License as published by
7
* the Free Software Foundation; either version 2 of the License, or
8
* (at your option) any later version.
10
* SubLib is distributed in the hope that it will be useful,
11
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
* GNU General Public License for more details.
15
* You should have received a copy of the GNU General Public License
16
* along with this program; if not, write to the Free Software
17
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
21
using System.Collections;
23
using System.Text.RegularExpressions;
27
internal class SubtitleOutput {
28
private SubtitleFormat format = null;
29
private SubtitleTextType textType = SubtitleTextType.Text;
31
private Subtitle subtitle = null;
32
private Subtitle previousSubtitle = null;
33
private int subtitleNumber = 1;
35
internal SubtitleOutput (SubtitleFormat format, SubtitleTextType textType) {
37
this.textType = textType;
40
internal string Build (SubtitleCollection collection, SubtitleProperties subtitleProperties, FileProperties fileProperties) {
41
StringBuilder output = new StringBuilder();
42
if (format.HasHeaders)
43
output.Append(format.HeadersToString(subtitleProperties, fileProperties));
45
if (format.HasBodyBegin)
46
output.Append(format.BodyBeginOut);
48
string subtitleExpression = GetSubtitleExpression(format, subtitleProperties, fileProperties);
49
Regex fieldExpression = new Regex(@"<<(?<Field>\w+)(,(?<Width>\d+))?>>");
50
MatchEvaluator matchEvaluator = new MatchEvaluator(this.FieldEvaluator);
52
foreach (Subtitle currentSubtitle in collection) {
53
subtitle = currentSubtitle;
54
string outputSubtitle = fieldExpression.Replace(subtitleExpression, matchEvaluator);
55
output.Append(outputSubtitle);
58
previousSubtitle = subtitle;
61
if (format.HasBodyEnd)
62
output.Append(format.BodyEndOut);
65
previousSubtitle = null;
68
ConvertNewlines(output, fileProperties);
69
return output.ToString();
75
private string FieldEvaluator (Match match) {
76
Group fieldGroup = match.Groups["Field"];
77
string field = fieldGroup.Value;
81
int startFrame = subtitle.Frames.Start;
82
return FormatedField(startFrame, match);
83
case "StartElapsedFrames":
84
int previousFrames = (previousSubtitle == null ? 0 : previousSubtitle.Frames.End);
85
int startElapsedFrames = subtitle.Frames.Start - previousFrames;
86
return FormatedField(startElapsedFrames, match);
88
int endFrame = subtitle.Frames.End;
89
return FormatedField(endFrame, match);
90
case "EndElapsedFrames":
91
int endElapsedFrames = subtitle.Frames.Duration;
92
return FormatedField(endElapsedFrames, match);
94
int startHours = subtitle.Times.Start.Hours;
95
return FormatedField(startHours, 2, match);
97
int startMinutes = subtitle.Times.Start.Minutes;
98
return FormatedField(startMinutes, 2, match);
100
int startSeconds = subtitle.Times.Start.Seconds;
101
return FormatedField(startSeconds, 2, match);
102
case "StartDeciseconds":
103
int startDeciseconds = DivideAndRound(subtitle.Times.Start.Milliseconds, 100);
104
return FormatedField(startDeciseconds, 2, match);
105
case "StartTotalDeciseconds":
106
int startTotalDeciseconds = DivideAndRound((int)subtitle.Times.Start.TotalMilliseconds, 100);
107
return startTotalDeciseconds.ToString();
108
case "StartCentiseconds":
109
int startCentiseconds = DivideAndRound(subtitle.Times.Start.Milliseconds, 10);
110
return FormatedField(startCentiseconds, 2, match);
111
case "StartMilliseconds":
112
int startMilliseconds = subtitle.Times.Start.Milliseconds;
113
return FormatedField(startMilliseconds, 3, match);
114
case "StartMillisecondsAsFramesPAL":
115
int startMillisecondsAsFramesPAL = (int)Synchronization.TimeMillisecondsToFrames(subtitle.Times.Start.Milliseconds, 25);
116
return FormatedField(startMillisecondsAsFramesPAL, match);
117
case "StartMillisecondsAsFramesNTSC":
118
int startMillisecondsAsFramesNTSC = (int)Synchronization.TimeMillisecondsToFrames(subtitle.Times.Start.Milliseconds, 29.97F);
119
return FormatedField(startMillisecondsAsFramesNTSC, match);
120
case "EndMillisecondsAsFramesPAL":
121
int endMillisecondsAsFramesPAL = (int)Synchronization.TimeMillisecondsToFrames(subtitle.Times.End.Milliseconds, 25);
122
return FormatedField(endMillisecondsAsFramesPAL, match);
123
case "EndMillisecondsAsFramesNTSC":
124
int endMillisecondsAsFramesNTSC = (int)Synchronization.TimeMillisecondsToFrames(subtitle.Times.End.Milliseconds, 29.97F);
125
return FormatedField(endMillisecondsAsFramesNTSC, match);
126
case "StartElapsedTime":
127
TimeSpan previousTime = (previousSubtitle == null ? TimeSpan.Zero : previousSubtitle.Times.End);
128
TimeSpan startElapsedTime = subtitle.Times.Start - previousTime;
129
return FormatedField(startElapsedTime.TotalSeconds);
131
int endHours = subtitle.Times.End.Hours;
132
return FormatedField(endHours, 2, match);
134
int endMinutes = subtitle.Times.End.Minutes;
135
return FormatedField(endMinutes, 2, match);
137
int endSeconds = subtitle.Times.End.Seconds;
138
return FormatedField(endSeconds, 2, match);
139
case "EndDeciseconds":
140
int endDeciseconds = DivideAndRound(subtitle.Times.End.Milliseconds, 100);
141
return FormatedField(endDeciseconds, 2, match);
142
case "EndTotalDeciseconds":
143
int endTotalDeciseconds = DivideAndRound((int)subtitle.Times.End.TotalMilliseconds, 100);
144
return endTotalDeciseconds.ToString();
145
case "EndCentiseconds":
146
int endCentiseconds = DivideAndRound(subtitle.Times.End.Milliseconds, 10);
147
return FormatedField(endCentiseconds, 2, match);
148
case "EndMilliseconds":
149
int endMilliseconds = subtitle.Times.End.Milliseconds;
150
return FormatedField(endMilliseconds, 3, match);
151
case "EndElapsedTime":
152
TimeSpan endElapsedTime = subtitle.Times.Duration;
153
return FormatedField(endElapsedTime.TotalSeconds);
155
SubtitleText subtitleText = (textType == SubtitleTextType.Text ? subtitle.Text : subtitle.Translation);
156
string text = subtitleText.GetTrimLines(format.LineBreak);
157
return text.ToString();
159
string style = format.StyleToString(subtitle.Style);
160
return style.ToString();
162
string endOfStyle = format.EndOfStyleToString(subtitle.Style);
163
return endOfStyle.ToString();
164
case "SubtitleNumber":
165
return FormatedField(subtitleNumber, match);
171
private string FormatedField (int field, int defaultWidth, Match match) {
172
Group group = match.Groups["Width"];
173
int width = (group.Success ? Convert.ToInt32(group.Value) : defaultWidth);
174
return DimensionField(field, width);
177
private string FormatedField (int field, Match match) {
178
Group group = match.Groups["Width"];
180
int width = Convert.ToInt32(group.Value);
181
return DimensionField(field, width);
184
return field.ToString();
187
private string FormatedField (double field) {
188
return field.ToString("0.###");
191
private string DimensionField (int field, int width) {
192
return field.ToString("D" + width).Substring(0, width);
195
private int DivideAndRound (int number, int denominator) {
196
return (int)Math.Round((double)number / denominator);
199
private void ConvertNewlines (StringBuilder builder, FileProperties properties) {
200
NewlineType type = properties.NewlineType;
201
if ((type == NewlineType.Unknown) || (type == NewlineType.Unix))
204
string newline = (type == NewlineType.Windows ? "\r\n" : "\r"); //Windows : Macintosh
205
builder.Replace("\n", newline);
208
private string GetSubtitleExpression (SubtitleFormat format, SubtitleProperties subtitleProperties, FileProperties fileProperties) {
209
if (format.Mode == SubtitleMode.Both) {
210
if (fileProperties.TimingMode == TimingMode.Times)
211
return format.SubtitleOutTimesMode;
213
return format.SubtitleOutFramesMode;
216
if (format.SubtitleOut != null)
217
return format.SubtitleOut;
219
return format.GetDynamicSubtitleOut(subtitleProperties);