Refactor AssParser so that AddLine is less of a monolithic monstrosity
This commit is contained in:
parent
7e1bb8348a
commit
d3e2585faf
3 changed files with 119 additions and 92 deletions
|
@ -25,46 +25,109 @@ AssParser::AssParser(AssFile *target, int version)
|
||||||
: target(target)
|
: target(target)
|
||||||
, version(version)
|
, version(version)
|
||||||
, attach(0)
|
, attach(0)
|
||||||
|
, state(&AssParser::ParseScriptInfoLine)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
AssParser::~AssParser() {
|
AssParser::~AssParser() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void AssParser::AddLine(wxString const& data) {
|
void AssParser::ParseAttachmentLine(wxString const& data) {
|
||||||
// Is this line an attachment filename?
|
bool is_filename = data.StartsWith("fontname: ") || data.StartsWith("filename: ");
|
||||||
bool isFilename = data.StartsWith("fontname: ") || data.StartsWith("filename: ");
|
|
||||||
|
|
||||||
// If there's an attachment in progress, deal with it first as an
|
bool valid_data = data.size() > 0 && data.size() <= 80;
|
||||||
// attachment data line can appear to be other things
|
for (size_t i = 0; i < data.size(); ++i) {
|
||||||
if (attach.get()) {
|
if (data[i] < 33 || data[i] >= 97) {
|
||||||
// Check if it's valid data
|
valid_data = false;
|
||||||
bool validData = data.size() > 0 && data.size() <= 80;
|
break;
|
||||||
for (size_t i = 0; i < data.size(); ++i) {
|
|
||||||
if (data[i] < 33 || data[i] >= 97) {
|
|
||||||
validData = false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Data is over, add attachment to the file
|
// Data is over, add attachment to the file
|
||||||
if (!validData || isFilename) {
|
if (!valid_data || is_filename) {
|
||||||
|
attach->Finish();
|
||||||
|
target->Line.push_back(attach.release());
|
||||||
|
AddLine(data);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
attach->AddData(data);
|
||||||
|
|
||||||
|
// Done building
|
||||||
|
if (data.Length() < 80) {
|
||||||
attach->Finish();
|
attach->Finish();
|
||||||
target->Line.push_back(attach.release());
|
target->Line.push_back(attach.release());
|
||||||
}
|
}
|
||||||
else {
|
}
|
||||||
// Insert data
|
}
|
||||||
attach->AddData(data);
|
|
||||||
|
|
||||||
// Done building
|
void AssParser::ParseScriptInfoLine(wxString const& data) {
|
||||||
if (data.Length() < 80) {
|
// If the first nonblank line isn't a header pretend it starts with [Script Info]
|
||||||
attach->Finish();
|
if (target->Line.empty())
|
||||||
target->Line.push_back(attach.release());
|
target->Line.push_back(new AssEntry("[Script Info]", "[Script Info]"));
|
||||||
return;
|
|
||||||
}
|
if (data.StartsWith(";")) {
|
||||||
|
// Skip stupid comments added by other programs
|
||||||
|
// Of course, we'll add our own in place later... ;)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data.StartsWith("ScriptType:")) {
|
||||||
|
wxString versionString = data.Mid(11).Trim(true).Trim(false).Lower();
|
||||||
|
int trueVersion;
|
||||||
|
if (versionString == "v4.00")
|
||||||
|
trueVersion = 0;
|
||||||
|
else if (versionString == "v4.00+")
|
||||||
|
trueVersion = 1;
|
||||||
|
else
|
||||||
|
throw "Unknown SSA file format version";
|
||||||
|
if (trueVersion != version) {
|
||||||
|
wxLogMessage("Warning: File has the wrong extension.");
|
||||||
|
version = trueVersion;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
target->Line.push_back(new AssEntry(data, "[Script Info]"));
|
||||||
|
}
|
||||||
|
|
||||||
|
void AssParser::ParseEventLine(wxString const& data) {
|
||||||
|
if (data.StartsWith("Dialogue:") || data.StartsWith("Comment:"))
|
||||||
|
target->Line.push_back(new AssDialogue(data));
|
||||||
|
else if (data.StartsWith("Format:"))
|
||||||
|
target->Line.push_back(new AssEntry("Format: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text", "[Events]"));
|
||||||
|
}
|
||||||
|
|
||||||
|
void AssParser::ParseStyleLine(wxString const& data) {
|
||||||
|
if (data.StartsWith("Style:"))
|
||||||
|
target->Line.push_back(new AssStyle(data, version));
|
||||||
|
else if (data.StartsWith("Format:"))
|
||||||
|
target->Line.push_back(new AssEntry("Format: Name, Fontname, Fontsize, PrimaryColour, SecondaryColour, OutlineColour, BackColour, Bold, Italic, Underline, StrikeOut, ScaleX, ScaleY, Spacing, Angle, BorderStyle, Outline, Shadow, Alignment, MarginL, MarginR, MarginV, Encoding", "[V4+ Styles]"));
|
||||||
|
}
|
||||||
|
|
||||||
|
void AssParser::ParseFontLine(wxString const& data) {
|
||||||
|
if (data.StartsWith("fontname: ")) {
|
||||||
|
attach.reset(new AssAttachment(data.Mid(10), "[Fonts]"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void AssParser::ParseGraphicsLine(wxString const& data) {
|
||||||
|
if (data.StartsWith("filename: ")) {
|
||||||
|
attach.reset(new AssAttachment(data.Mid(10), "[Graphics]"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void AssParser::AppendUnknownLine(wxString const& data) {
|
||||||
|
target->Line.push_back(new AssEntry(data, target->Line.back()->group));
|
||||||
|
}
|
||||||
|
|
||||||
|
void AssParser::AddLine(wxString const& data) {
|
||||||
|
// Special-case for attachments since a line could theoretically be both a
|
||||||
|
// valid attachment data line and a valid section header, and if an
|
||||||
|
// attachment is in progress it needs to be treated as that
|
||||||
|
if (attach.get()) {
|
||||||
|
ParseAttachmentLine(data);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (data.empty()) return;
|
if (data.empty()) return;
|
||||||
|
|
||||||
// Section header
|
// Section header
|
||||||
|
@ -75,77 +138,32 @@ void AssParser::AddLine(wxString const& data) {
|
||||||
if (low == "[v4 styles]") {
|
if (low == "[v4 styles]") {
|
||||||
header = "[V4+ Styles]";
|
header = "[V4+ Styles]";
|
||||||
version = 0;
|
version = 0;
|
||||||
|
state = &AssParser::ParseStyleLine;
|
||||||
}
|
}
|
||||||
else if (low == "[v4+ styles]") {
|
else if (low == "[v4+ styles]") {
|
||||||
header = "[V4+ Styles]";
|
header = "[V4+ Styles]";
|
||||||
version = 1;
|
version = 1;
|
||||||
|
state = &AssParser::ParseStyleLine;
|
||||||
|
}
|
||||||
|
else if (low == "[events]") {
|
||||||
|
state = &AssParser::ParseEventLine;
|
||||||
|
}
|
||||||
|
else if (low == "[script info]") {
|
||||||
|
state = &AssParser::ParseScriptInfoLine;
|
||||||
|
}
|
||||||
|
else if (low == "[graphics]") {
|
||||||
|
state = &AssParser::ParseGraphicsLine;
|
||||||
|
}
|
||||||
|
else if (low == "[fonts]") {
|
||||||
|
state = &AssParser::ParseFontLine;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
state = &AssParser::AppendUnknownLine;
|
||||||
}
|
}
|
||||||
|
|
||||||
target->Line.push_back(new AssEntry(header, header));
|
target->Line.push_back(new AssEntry(header, header));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the first nonblank line isn't a header pretend it starts with [Script Info]
|
(this->*state)(data);
|
||||||
if (target->Line.empty())
|
|
||||||
target->Line.push_back(new AssEntry("[Script Info]", "[Script Info]"));
|
|
||||||
|
|
||||||
wxString group = target->Line.back()->group;
|
|
||||||
wxString lowGroup = group.Lower();
|
|
||||||
|
|
||||||
// Attachment
|
|
||||||
if (lowGroup == "[fonts]" || lowGroup == "[graphics]") {
|
|
||||||
if (isFilename) {
|
|
||||||
attach.reset(new AssAttachment(data.Mid(10), group));
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Dialogue
|
|
||||||
if (lowGroup == "[events]") {
|
|
||||||
if (data.StartsWith("Dialogue:") || data.StartsWith("Comment:"))
|
|
||||||
target->Line.push_back(new AssDialogue(data));
|
|
||||||
else if (data.StartsWith("Format:"))
|
|
||||||
target->Line.push_back(new AssEntry("Format: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text", group));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Style
|
|
||||||
if (lowGroup == "[v4+ styles]") {
|
|
||||||
if (data.StartsWith("Style:"))
|
|
||||||
target->Line.push_back(new AssStyle(data, version));
|
|
||||||
else if (data.StartsWith("Format:"))
|
|
||||||
target->Line.push_back(new AssEntry("Format: Name, Fontname, Fontsize, PrimaryColour, SecondaryColour, OutlineColour, BackColour, Bold, Italic, Underline, StrikeOut, ScaleX, ScaleY, Spacing, Angle, BorderStyle, Outline, Shadow, Alignment, MarginL, MarginR, MarginV, Encoding", group));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Script info
|
|
||||||
if (lowGroup == "[script info]") {
|
|
||||||
// Comment
|
|
||||||
if (data.StartsWith(";")) {
|
|
||||||
// Skip stupid comments added by other programs
|
|
||||||
// Of course, we'll add our own in place later... ;)
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (data.StartsWith("ScriptType:")) {
|
|
||||||
wxString versionString = data.Mid(11).Trim(true).Trim(false).Lower();
|
|
||||||
int trueVersion;
|
|
||||||
if (versionString == "v4.00")
|
|
||||||
trueVersion = 0;
|
|
||||||
else if (versionString == "v4.00+")
|
|
||||||
trueVersion = 1;
|
|
||||||
else
|
|
||||||
throw "Unknown SSA file format version";
|
|
||||||
if (trueVersion != version) {
|
|
||||||
wxLogMessage("Warning: File has the wrong extension.");
|
|
||||||
version = trueVersion;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
target->Line.push_back(new AssEntry(data, group));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Unrecognized group
|
|
||||||
target->Line.push_back(new AssEntry(data, group));
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,6 +25,15 @@ class AssParser {
|
||||||
AssFile *target;
|
AssFile *target;
|
||||||
int version;
|
int version;
|
||||||
std::auto_ptr<AssAttachment> attach;
|
std::auto_ptr<AssAttachment> attach;
|
||||||
|
void (AssParser::*state)(wxString const&);
|
||||||
|
|
||||||
|
void ParseAttachmentLine(wxString const& data);
|
||||||
|
void ParseEventLine(wxString const& data);
|
||||||
|
void ParseStyleLine(wxString const& data);
|
||||||
|
void ParseScriptInfoLine(wxString const& data);
|
||||||
|
void ParseFontLine(wxString const& data);
|
||||||
|
void ParseGraphicsLine(wxString const& data);
|
||||||
|
void AppendUnknownLine(wxString const& data);
|
||||||
public:
|
public:
|
||||||
AssParser(AssFile *target, int version);
|
AssParser(AssFile *target, int version);
|
||||||
~AssParser();
|
~AssParser();
|
||||||
|
|
|
@ -77,7 +77,7 @@ public:
|
||||||
#define std_ftell ftello
|
#define std_ftell ftello
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static void read_subtitles(agi::ProgressSink *ps, MatroskaFile *file, MkvStdIO *input, bool srt, bool ssa, double totalTime, AssFile *target) {
|
static void read_subtitles(agi::ProgressSink *ps, MatroskaFile *file, MkvStdIO *input, bool srt, double totalTime, AssParser *parser) {
|
||||||
std::map<int, wxString> subList;
|
std::map<int, wxString> subList;
|
||||||
char *readBuf = 0;
|
char *readBuf = 0;
|
||||||
size_t readBufSize = 0;
|
size_t readBufSize = 0;
|
||||||
|
@ -135,9 +135,8 @@ static void read_subtitles(agi::ProgressSink *ps, MatroskaFile *file, MkvStdIO *
|
||||||
delete[] readBuf;
|
delete[] readBuf;
|
||||||
|
|
||||||
// Insert into file
|
// Insert into file
|
||||||
AssParser parser(target, ssa);
|
|
||||||
for (std::map<int, wxString>::iterator it = subList.begin(); it != subList.end(); ++it) {
|
for (std::map<int, wxString>::iterator it = subList.begin(); it != subList.end(); ++it) {
|
||||||
parser.AddLine(it->second);
|
parser->AddLine(it->second);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -197,6 +196,8 @@ void MatroskaWrapper::GetSubtitles(wxString const& filename, AssFile *target) {
|
||||||
bool srt = CodecID == "S_TEXT/UTF8";
|
bool srt = CodecID == "S_TEXT/UTF8";
|
||||||
bool ssa = CodecID == "S_TEXT/SSA";
|
bool ssa = CodecID == "S_TEXT/SSA";
|
||||||
|
|
||||||
|
AssParser parser(target, !ssa);
|
||||||
|
|
||||||
// Read private data if it's ASS/SSA
|
// Read private data if it's ASS/SSA
|
||||||
if (!srt) {
|
if (!srt) {
|
||||||
// Read raw data
|
// Read raw data
|
||||||
|
@ -204,7 +205,6 @@ void MatroskaWrapper::GetSubtitles(wxString const& filename, AssFile *target) {
|
||||||
wxString privString((const char *)trackInfo->CodecPrivate, wxConvUTF8, trackInfo->CodecPrivateSize);
|
wxString privString((const char *)trackInfo->CodecPrivate, wxConvUTF8, trackInfo->CodecPrivateSize);
|
||||||
|
|
||||||
// Load into file
|
// Load into file
|
||||||
AssParser parser(target, !ssa);
|
|
||||||
wxStringTokenizer token(privString, "\r\n", wxTOKEN_STRTOK);
|
wxStringTokenizer token(privString, "\r\n", wxTOKEN_STRTOK);
|
||||||
while (token.HasMoreTokens())
|
while (token.HasMoreTokens())
|
||||||
parser.AddLine(token.GetNextToken());
|
parser.AddLine(token.GetNextToken());
|
||||||
|
@ -221,7 +221,7 @@ void MatroskaWrapper::GetSubtitles(wxString const& filename, AssFile *target) {
|
||||||
// Progress bar
|
// Progress bar
|
||||||
double totalTime = double(segInfo->Duration) / timecodeScale;
|
double totalTime = double(segInfo->Duration) / timecodeScale;
|
||||||
DialogProgress progress(NULL, _("Parsing Matroska"), _("Reading subtitles from Matroska file."));
|
DialogProgress progress(NULL, _("Parsing Matroska"), _("Reading subtitles from Matroska file."));
|
||||||
progress.Run(bind(read_subtitles, std::tr1::placeholders::_1, file, &input, srt, ssa, totalTime, target));
|
progress.Run(bind(read_subtitles, std::tr1::placeholders::_1, file, &input, srt, totalTime, &parser));
|
||||||
}
|
}
|
||||||
catch (...) {
|
catch (...) {
|
||||||
mkv_Close(file);
|
mkv_Close(file);
|
||||||
|
|
Loading…
Reference in a new issue