File indexing completed on 2024-06-16 04:38:18
0001 /* 0002 SPDX-FileCopyrightText: 2007-2009 Sergio Pistone <sergio_pistone@yahoo.com.ar> 0003 SPDX-FileCopyrightText: 2010-2022 Mladen Milinkovic <max@smoothware.net> 0004 0005 SPDX-License-Identifier: GPL-2.0-or-later 0006 */ 0007 0008 #ifndef MICRODVDINPUTFORMAT_H 0009 #define MICRODVDINPUTFORMAT_H 0010 0011 #include "core/richtext/richdocument.h" 0012 #include "helpers/common.h" 0013 #include "formats/inputformat.h" 0014 0015 #include <QRegularExpression> 0016 #include <QStringBuilder> 0017 0018 namespace SubtitleComposer { 0019 class MicroDVDInputFormat : public InputFormat 0020 { 0021 friend class FormatManager; 0022 0023 protected: 0024 MicroDVDInputFormat() 0025 : InputFormat($("MicroDVD"), QStringList() << $("sub") << $("txt")) 0026 {} 0027 0028 bool parseSubtitles(Subtitle &subtitle, const QString &data) const override 0029 { 0030 staticRE$(lineRE, "\\{(\\d+)\\}\\{(\\d+)\\}([^\n]+)\n", REu | REi); 0031 staticRE$(styleRE, "\\{([yc]):([^}]*)\\}", REu | REi); 0032 0033 QRegularExpressionMatchIterator itLine = lineRE.globalMatch(data); 0034 if(!itLine.hasNext()) 0035 return false; // couldn't find first line (content or FPS) 0036 0037 QRegularExpressionMatch mLine = itLine.next(); 0038 0039 // if present, the FPS must by indicated by the first entry with both initial and final frames at 1 0040 bool ok; 0041 double fps = mLine.captured(3).toDouble(&ok); 0042 if(ok && mLine.captured(1) == QLatin1String("1") && mLine.captured(2) == QLatin1String("1")) { 0043 // first line contained the frames per second 0044 subtitle.setFramesPerSecond(fps); 0045 } else { 0046 // first line doesn't contain the FPS, use the value loaded by default 0047 fps = subtitle.framesPerSecond(); 0048 } 0049 0050 if(!itLine.hasNext()) 0051 return false; 0052 0053 do { 0054 mLine = itLine.next(); 0055 0056 Time showTime(static_cast<long>((mLine.captured(1).toLong() / fps) * 1000)); 0057 Time hideTime(static_cast<long>((mLine.captured(2).toLong() / fps) * 1000)); 0058 0059 RichString richText; 0060 0061 const QString text = mLine.captured(3); 0062 QRegularExpressionMatchIterator itText = styleRE.globalMatch(text); 0063 0064 int globalStyle = 0, currentStyle = 0; 0065 QRgb globalColor = 0, currentColor = 0; 0066 int offsetPos = 0; 0067 while(itText.hasNext()) { 0068 QRegularExpressionMatch mText = itText.next(); 0069 QString tag(mText.captured(1)), val(mText.captured(2).toLower()); 0070 0071 int newStyle = currentStyle; 0072 QRgb newColor = currentColor; 0073 0074 if(tag == QChar('Y')) { 0075 globalStyle = 0; 0076 if(val.contains('b')) 0077 globalStyle |= RichString::Bold; 0078 if(val.contains('i')) 0079 globalStyle |= RichString::Italic; 0080 if(val.contains('u')) 0081 globalStyle |= RichString::Underline; 0082 } else if(tag == QLatin1String("C")) { 0083 globalColor = val.length() != 7 ? 0 : QColor(QChar('#') % val.mid(5, 2) % val.mid(3, 2) % val.mid(1, 2)).rgb(); 0084 } else if(tag == QLatin1String("y")) { 0085 newStyle = 0; 0086 if(val.contains('b')) 0087 newStyle |= RichString::Bold; 0088 if(val.contains('i')) 0089 newStyle |= RichString::Italic; 0090 if(val.contains('u')) 0091 newStyle |= RichString::Underline; 0092 } else if(tag == QLatin1String("c")) { 0093 newColor = val.length() != 7 ? 0 : QColor(QChar('#') % val.mid(5, 2) % val.mid(3, 2) % val.mid(1, 2)).rgb(); 0094 } 0095 0096 if(newStyle != currentStyle || currentColor != newColor) { 0097 QString token(text.mid(offsetPos, mText.capturedStart() - offsetPos)); 0098 richText += RichString(token, currentStyle | (currentColor == 0 ? 0 : RichString::Color), currentColor); 0099 currentStyle = newStyle; 0100 currentColor = newColor; 0101 } 0102 0103 offsetPos = mText.capturedEnd(); 0104 } 0105 0106 QString token(text.mid(offsetPos)); 0107 richText += RichString(token, currentStyle | (currentColor == 0 ? 0 : RichString::Color), currentColor); 0108 0109 if(globalColor != 0) 0110 globalStyle |= RichString::Color; 0111 if(globalStyle != 0) { 0112 for(int i = 0, sz = richText.length(); i < sz; i++) { 0113 if(richText.styleFlagsAt(i) == 0) { 0114 richText.setStyleFlagsAt(i, globalStyle); 0115 richText.setStyleColorAt(i, globalColor); 0116 } 0117 } 0118 } 0119 0120 SubtitleLine *l = new SubtitleLine(showTime, hideTime); 0121 l->primaryDoc()->setRichText(richText.replace('|', '\n'), true); 0122 subtitle.insertLine(l); 0123 } while(itLine.hasNext()); 0124 0125 return true; 0126 } 0127 }; 0128 } 0129 0130 #endif