2 * Copyright (C) 2003-2006 Gabest
3 * http://www.gabest.org
5 * This Program 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, or (at your option)
10 * This Program 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 GNU Make; see the file COPYING. If not, write to
17 * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
18 * http://www.gnu.org/copyleft/gpl.html
26 #include "RealTextParser.h"
29 #include "CAutoTiming.h"
33 #include "xy_logger.h"
35 // gathered from http://www.netwave.or.jp/~shikai/shikai/shcolor.htm
37 struct htmlcolor
{TCHAR
* name
; DWORD color
;} hmtlcolors
[] =
39 {_T("white"), 0xffffff},
40 {_T("whitesmoke"), 0xf5f5f5},
41 {_T("ghostwhite"), 0xf8f8ff},
42 {_T("snow"), 0xfffafa},
43 {_T("gainsboro"), 0xdcdcdc},
44 {_T("lightgrey"), 0xd3d3d3},
45 {_T("silver"), 0xc0c0c0},
46 {_T("darkgray"), 0xa9a9a9},
47 {_T("gray"), 0x808080},
48 {_T("dimgray"), 0x696969},
49 {_T("lightslategray"), 0x778899},
50 {_T("slategray"), 0x708090},
51 {_T("darkslategray"), 0x2f4f4f},
52 {_T("black"), 0x000000},
54 {_T("azure"), 0xf0ffff},
55 {_T("aliceblue"), 0xf0f8ff},
56 {_T("mintcream"), 0xf5fffa},
57 {_T("honeydew"), 0xf0fff0},
58 {_T("lightcyan"), 0xe0ffff},
59 {_T("paleturqoise"), 0xafeeee},
60 {_T("powderblue"), 0xb0e0e6},
61 {_T("lightblue"), 0xadd8ed},
62 {_T("lightsteelblue"), 0xb0c4de},
63 {_T("skyblue"), 0x87ceeb},
64 {_T("lightskyblue"), 0x87cefa},
65 {_T("cyan"), 0x00ffff},
66 {_T("aqua"), 0x00ff80},
67 {_T("deepskyblue"), 0x00bfff},
68 {_T("aquamarine"), 0x7fffd4},
69 {_T("turquoise"), 0x40e0d0},
70 {_T("darkturquoise"), 0x00ced1},
71 {_T("lightseagreen"), 0x20b2aa},
72 {_T("mediumturquoise"), 0x40e0dd},
73 {_T("mediumaquamarine"), 0x66cdaa},
74 {_T("cadetblue"), 0x5f9ea0},
75 {_T("teal"), 0x008080},
76 {_T("darkcyan"), 0x008b8b},
77 {_T("comflowerblue"), 0x6495ed},
78 {_T("dodgerblue"), 0x1e90ff},
79 {_T("steelblue"), 0x4682b4},
80 {_T("royalblue"), 0x4169e1},
81 {_T("blue"), 0x0000ff},
82 {_T("mediumblue"), 0x0000cd},
83 {_T("mediumslateblue"), 0x7b68ee},
84 {_T("slateblue"), 0x6a5acd},
85 {_T("darkslateblue"), 0x483d8b},
86 {_T("darkblue"), 0x00008b},
87 {_T("midnightblue"), 0x191970},
88 {_T("navy"), 0x000080},
90 {_T("palegreen"), 0x98fb98},
91 {_T("lightgreen"), 0x90ee90},
92 {_T("mediumspringgreen"), 0x00fa9a},
93 {_T("springgreen"), 0x00ff7f},
94 {_T("chartreuse"), 0x7fff00},
95 {_T("lawngreen"), 0x7cfc00},
96 {_T("lime"), 0x00ff00},
97 {_T("limegreen"), 0x32cd32},
98 {_T("greenyellow"), 0xadff2f},
99 {_T("yellowgreen"), 0x9acd32},
100 {_T("darkseagreen"), 0x8fbc8f},
101 {_T("mediumseagreen"), 0x3cb371},
102 {_T("seagreen"), 0x2e8b57},
103 {_T("olivedrab"), 0x6b8e23},
104 {_T("forestgreen"), 0x228b22},
105 {_T("green"), 0x008000},
106 {_T("darkkhaki"), 0xbdb76b},
107 {_T("olive"), 0x808000},
108 {_T("darkolivegreen"), 0x556b2f},
109 {_T("darkgreen"), 0x006400},
111 {_T("floralwhite"), 0xfffaf0},
112 {_T("seashell"), 0xfff5ee},
113 {_T("ivory"), 0xfffff0},
114 {_T("beige"), 0xf5f5dc},
115 {_T("cornsilk"), 0xfff8dc},
116 {_T("lemonchiffon"), 0xfffacd},
117 {_T("lightyellow"), 0xffffe0},
118 {_T("lightgoldenrodyellow"), 0xfafad2},
119 {_T("papayawhip"), 0xffefd5},
120 {_T("blanchedalmond"), 0xffedcd},
121 {_T("palegoldenrod"), 0xeee8aa},
122 {_T("khaki"), 0xf0eb8c},
123 {_T("bisque"), 0xffe4c4},
124 {_T("moccasin"), 0xffe4b5},
125 {_T("navajowhite"), 0xffdead},
126 {_T("peachpuff"), 0xffdab9},
127 {_T("yellow"), 0xffff00},
128 {_T("gold"), 0xffd700},
129 {_T("wheat"), 0xf5deb3},
130 {_T("orange"), 0xffa500},
131 {_T("darkorange"), 0xff8c00},
133 {_T("oldlace"), 0xfdf5e6},
134 {_T("linen"), 0xfaf0e6},
135 {_T("antiquewhite"), 0xfaebd7},
136 {_T("lightsalmon"), 0xffa07a},
137 {_T("darksalmon"), 0xe9967a},
138 {_T("salmon"), 0xfa8072},
139 {_T("lightcoral"), 0xf08080},
140 {_T("indianred"), 0xcd5c5c},
141 {_T("coral"), 0xff7f50},
142 {_T("tomato"), 0xff6347},
143 {_T("orangered"), 0xff4500},
144 {_T("red"), 0xff0000},
145 {_T("crimson"), 0xdc143c},
146 {_T("firebrick"), 0xb22222},
147 {_T("maroon"), 0x800000},
148 {_T("darkred"), 0x8b0000},
150 {_T("lavender"), 0xe6e6fe},
151 {_T("lavenderblush"), 0xfff0f5},
152 {_T("mistyrose"), 0xffe4e1},
153 {_T("thistle"), 0xd8bfd8},
154 {_T("pink"), 0xffc0cb},
155 {_T("lightpink"), 0xffb6c1},
156 {_T("palevioletred"), 0xdb7093},
157 {_T("hotpink"), 0xff69b4},
158 {_T("fuchsia"), 0xff00ee},
159 {_T("magenta"), 0xff00ff},
160 {_T("mediumvioletred"), 0xc71585},
161 {_T("deeppink"), 0xff1493},
162 {_T("plum"), 0xdda0dd},
163 {_T("violet"), 0xee82ee},
164 {_T("orchid"), 0xda70d6},
165 {_T("mediumorchid"), 0xba55d3},
166 {_T("mediumpurple"), 0x9370db},
167 {_T("purple"), 0x9370db},
168 {_T("blueviolet"), 0x8a2be2},
169 {_T("darkviolet"), 0x9400d3},
170 {_T("darkorchid"), 0x9932cc},
172 {_T("tan"), 0xd2b48c},
173 {_T("burlywood"), 0xdeb887},
174 {_T("sandybrown"), 0xf4a460},
175 {_T("peru"), 0xcd853f},
176 {_T("goldenrod"), 0xdaa520},
177 {_T("darkgoldenrod"), 0xb8860b},
178 {_T("chocolate"), 0xd2691e},
179 {_T("rosybrown"), 0xbc8f8f},
180 {_T("sienna"), 0xa0522d},
181 {_T("saddlebrown"), 0x8b4513},
182 {_T("brown"), 0xa52a2a},
185 CHtmlColorMap::CHtmlColorMap()
187 for(int i
= 0; i
< countof(hmtlcolors
); i
++)
188 SetAt(hmtlcolors
[i
].name
, hmtlcolors
[i
].color
);
191 CHtmlColorMap g_colors
;
193 CString
g_default_style(_T("Default"));
221 TCHAR
* CharSetNames
[] =
245 int CharSetLen
= countof(CharSetList
);
247 static void LogSegments(const CAtlArray
<STSSegment
>& segments
)
250 for (int i
=0;i
<segments
.GetCount();i
++)
252 const STSSegment
& s
= segments
[i
];
253 XY_LOG_INFO(_T("\tsegments ")<<i
<<_T(":")<<s
.start
<<_T(" ")
254 <<s
.end
<<_T(" ")<<s
.subs
.GetCount());
255 XY_LOG_INFO(_T("\tsubs: "));
256 for (int j
=0;j
<s
.subs
.GetCount();j
++)
258 XY_LOG_INFO(_T("\t\t ")<<s
.subs
[j
]);
266 static DWORD
CharSetToCodePage(DWORD dwCharSet
)
269 ::TranslateCharsetInfo((DWORD
*)dwCharSet
, &cs
, TCI_SRCCHARSET
);
273 int FindChar(CStringW str
, WCHAR c
, int pos
, bool fUnicode
, int CharSet
)
275 if(fUnicode
) return(str
.Find(c
, pos
));
279 DWORD cp
= CharSetToCodePage(CharSet
);
280 int OrgCharSet
= CharSet
;
282 for(int i
= 0, j
= str
.GetLength(), k
; i
< j
; i
++)
286 if(IsDBCSLeadByteEx(cp
, (BYTE
)c2
)) i
++;
289 if(c2
== c
) return(i
);
292 if(c2
== '{') fStyleMod
++;
293 else if(fStyleMod
> 0)
295 if(c2
== '}') fStyleMod
--;
296 else if(c2
== 'e' && i
>= 3 && i
< j
-1 && str
.Mid(i
-2, 3) == L
"\\fe")
299 for(k
= i
+1; _istdigit(str
[k
]); k
++) CharSet
= CharSet
*10 + (str
[k
] - '0');
300 if(k
== i
+1) CharSet
= OrgCharSet
;
302 cp
= CharSetToCodePage(CharSet
);
310 int FindChar(CStringA str, char c, int pos, bool fUnicode, int CharSet)
314 return(FindChar(AToW(str), c, pos, false, CharSet));
317 static CStringW
ToMBCS(CStringW str
, DWORD CharSet
)
321 DWORD cp
= CharSetToCodePage(CharSet
);
323 for(int i
= 0, j
= str
.GetLength(); i
< j
; i
++)
325 WCHAR wc
= str
.GetAt(i
);
329 if((len
= WideCharToMultiByte(cp
, 0, &wc
, 1, c
, 8, NULL
, NULL
)) > 0)
331 for(int k
= 0; k
< len
; k
++)
332 ret
+= (WCHAR
)(BYTE
)c
[k
];
343 static CStringW
UnicodeSSAToMBCS(CStringW str
, DWORD CharSet
)
347 int OrgCharSet
= CharSet
;
349 for(int j
= 0; j
< str
.GetLength(); )
351 j
= str
.Find('{', j
);
354 ret
+= ToMBCS(str
.Left(j
), CharSet
);
360 ret
+= ToMBCS(str
, CharSet
);
365 int k
= str
.Find(L
"\\fe");
370 for(; _istdigit(str
[l
]); l
++) CharSet
= CharSet
*10 + (str
[l
] - '0');
371 if(l
== k
+3) CharSet
= OrgCharSet
;
376 ret
+= ToMBCS(str
.Left(j
), OrgCharSet
);
383 ret
+= ToMBCS(str
, CharSet
);
391 static CStringW
ToUnicode(CStringW str
, DWORD CharSet
)
395 DWORD cp
= CharSetToCodePage(CharSet
);
397 for(int i
= 0, j
= str
.GetLength(); i
< j
; i
++)
399 WCHAR wc
= str
.GetAt(i
);
402 if(IsDBCSLeadByteEx(cp
, (BYTE
)wc
))
410 cc
[1] = (char)str
.GetAt(i
);
412 MultiByteToWideChar(cp
, 0, cc
, 2, &wc
, 1);
417 MultiByteToWideChar(cp
, 0, &c
, 1, &wc
, 1);
426 static CStringW
MBCSSSAToUnicode(CStringW str
, int CharSet
)
430 int OrgCharSet
= CharSet
;
432 for(int j
= 0; j
< str
.GetLength(); )
434 j
= FindChar(str
, '{', 0, false, CharSet
);
438 ret
+= ToUnicode(str
.Left(j
), CharSet
);
441 j
= FindChar(str
, '}', 0, false, CharSet
);
445 ret
+= ToUnicode(str
, CharSet
);
450 int k
= str
.Find(L
"\\fe");
455 for(; _istdigit(str
[l
]); l
++) CharSet
= CharSet
*10 + (str
[l
] - '0');
456 if(l
== k
+3) CharSet
= OrgCharSet
;
461 ret
+= ToUnicode(str
.Left(j
), OrgCharSet
);
468 ret
+= ToUnicode(str
, CharSet
);
476 CStringW
RemoveSSATags(CStringW str
, bool fUnicode
, int CharSet
)
478 str
.Replace (L
"{\\i1}", L
"<i>");
479 str
.Replace (L
"{\\i}", L
"</i>");
481 for(int i
= 0, j
; i
< str
.GetLength(); )
483 if((i
= FindChar(str
, '{', i
, fUnicode
, CharSet
)) < 0) break;
484 if((j
= FindChar(str
, '}', i
, fUnicode
, CharSet
)) < 0) break;
485 str
.Delete(i
, j
-i
+1);
488 str
.Replace(L
"\\N", L
"\n");
489 str
.Replace(L
"\\n", L
"\n");
490 str
.Replace(L
"\\h", L
" ");
497 static CStringW
SubRipper2SSA(CStringW str
, int CharSet
)
499 str
.Replace(L
"<i>", L
"{\\i1}");
500 str
.Replace(L
"</i>", L
"{\\i}");
501 str
.Replace(L
"<b>", L
"{\\b1}");
502 str
.Replace(L
"</b>", L
"{\\b}");
503 str
.Replace(L
"<u>", L
"{\\u1}");
504 str
.Replace(L
"</u>", L
"{\\u}");
509 static bool OpenSubRipper(CTextFile
* file
, CSimpleTextSubtitle
& ret
, int CharSet
)
514 while(file
->ReadString(buff
))
517 if(buff
.IsEmpty()) continue;
520 int hh1
, mm1
, ss1
, ms1
, hh2
, mm2
, ss2
, ms2
;
521 int c
= swscanf(buff
, L
"%d%c%d%c%d%c%d --> %d%c%d%c%d%c%d\n",
522 &hh1
, &sep
, &mm1
, &sep
, &ss1
, &sep
, &ms1
,
523 &hh2
, &sep
, &mm2
, &sep
, &ss2
, &sep
, &ms2
);
525 if(c
== 1) // numbering
529 else if(c
== 14) // time info
533 bool fFoundEmpty
= false;
535 while(file
->ReadString(tmp
))
538 if(tmp
.IsEmpty()) fFoundEmpty
= true;
542 if(swscanf(tmp
, L
"%d%c", &num2
, &c
) == 1 && fFoundEmpty
)
552 SubRipper2SSA(str
, CharSet
),
554 (((hh1
*60 + mm1
)*60) + ss1
)*1000 + ms1
,
555 (((hh2
*60 + mm2
)*60) + ss2
)*1000 + ms2
);
557 else if(c
!= EOF
) // might be another format
563 return(!ret
.IsEmpty());
566 static bool OpenOldSubRipper(CTextFile
* file
, CSimpleTextSubtitle
& ret
, int CharSet
)
569 while(file
->ReadString(buff
))
572 if(buff
.IsEmpty()) continue;
574 for(int i
= 0; i
< buff
.GetLength(); i
++)
576 if((i
= FindChar(buff
, '|', i
, file
->IsUnicode(), CharSet
)) < 0) break;
580 int hh1
, mm1
, ss1
, hh2
, mm2
, ss2
;
581 int c
= swscanf(buff
, L
"{%d:%d:%d}{%d:%d:%d}", &hh1
, &mm1
, &ss1
, &hh2
, &mm2
, &ss2
);
586 buff
.Mid(buff
.Find('}', buff
.Find('}')+1)+1),
588 (((hh1
*60 + mm1
)*60) + ss1
)*1000,
589 (((hh2
*60 + mm2
)*60) + ss2
)*1000);
591 else if(c
!= EOF
) // might be another format
597 return(!ret
.IsEmpty());
600 static bool OpenSubViewer(CTextFile
* file
, CSimpleTextSubtitle
& ret
, int CharSet
)
603 CStringW font
, color
, size
;
604 bool fBold
, fItalic
, fStriked
, fUnderline
;
607 while(file
->ReadString(buff
))
610 if(buff
.IsEmpty()) continue;
614 for(int i
= 0; i
< buff
.GetLength() && buff
[i
]== '['; )
616 int j
= buff
.Find(']', ++i
);
619 CStringW tag
= buff
.Mid(i
,j
-i
);
625 j
= buff
.Find('[', ++i
);
626 if(j
< 0) j
= buff
.GetLength();
628 CStringW param
= buff
.Mid(i
,j
-i
);
629 param
.Trim(L
" \\t,");
634 font
= def
.fontName
.CompareNoCase(WToT(param
)) ? param
: L
"";
635 else if(tag
== L
"colf")
636 color
= def
.colors
[0] != wcstol(((LPCWSTR
)param
)+2, 0, 16) ? param
: L
"";
637 else if(tag
== L
"size")
638 size
= def
.fontSize
!= wcstol(param
, 0, 10) ? param
: L
"";
639 else if(tag
== L
"style")
641 if(param
.Find(L
"no") >= 0)
643 fBold
= fItalic
= fStriked
= fUnderline
= false;
647 fBold
= def
.fontWeight
< FW_BOLD
&& param
.Find(L
"bd") >= 0;
648 fItalic
= def
.fItalic
&& param
.Find(L
"it") >= 0;
649 fStriked
= def
.fStrikeOut
&& param
.Find(L
"st") >= 0;
650 fUnderline
= def
.fUnderline
&& param
.Find(L
"ud") >= 0;
659 int hh1
, mm1
, ss1
, hs1
, hh2
, mm2
, ss2
, hs2
;
660 int c
= swscanf(buff
, L
"%d:%d:%d%c%d,%d:%d:%d%c%d\n",
661 &hh1
, &mm1
, &ss1
, &sep
, &hs1
, &hh2
, &mm2
, &ss2
, &sep
, &hs2
);
666 file
->ReadString(str
);
668 str
.Replace(L
"[br]", L
"\\N");
671 if(!font
.IsEmpty()) prefix
+= L
"\\fn" + font
;
672 if(!color
.IsEmpty()) prefix
+= L
"\\c" + color
;
673 if(!size
.IsEmpty()) prefix
+= L
"\\fs" + size
;
674 if(fBold
) prefix
+= L
"\\b1";
675 if(fItalic
) prefix
+= L
"\\i1";
676 if(fStriked
) prefix
+= L
"\\s1";
677 if(fUnderline
) prefix
+= L
"\\u1";
678 if(!prefix
.IsEmpty()) str
= L
"{" + prefix
+ L
"}" + str
;
682 (((hh1
*60 + mm1
)*60) + ss1
)*1000 + hs1
*10,
683 (((hh2
*60 + mm2
)*60) + ss2
)*1000 + hs2
*10);
685 else if(c
!= EOF
) // might be another format
691 return(!ret
.IsEmpty());
694 static STSStyle
* GetMicroDVDStyle(CString str
, int CharSet
)
696 STSStyle
* ret
= new STSStyle();
697 if(!ret
) return(NULL
);
699 for(int i
= 0, len
= str
.GetLength(); i
< len
; i
++)
701 int j
= str
.Find('{', i
);
706 int k
= str
.Find('}', j
);
709 CString code
= str
.Mid(j
, k
-j
);
710 if(code
.GetLength() > 2) code
.SetAt(1, (TCHAR
)towlower(code
[1]));
712 if(!_tcsnicmp(code
, _T("{c:$"), 4))
714 _stscanf(code
, _T("{c:$%x"), &ret
->colors
[0]);
716 else if(!_tcsnicmp(code
, _T("{f:"), 3))
718 ret
->fontName
= code
.Mid(3);
720 else if(!_tcsnicmp(code
, _T("{s:"), 3))
723 if(1 == _stscanf(code
, _T("{s:%f"), &f
))
726 else if(!_tcsnicmp(code
, _T("{h:"), 3))
728 _stscanf(code
, _T("{h:%d"), &ret
->charSet
);
730 else if(!_tcsnicmp(code
, _T("{y:"), 3))
733 if(code
.Find('b') >= 0) ret
->fontWeight
= FW_BOLD
;
734 if(code
.Find('i') >= 0) ret
->fItalic
= true;
735 if(code
.Find('u') >= 0) ret
->fUnderline
= true;
736 if(code
.Find('s') >= 0) ret
->fStrikeOut
= true;
738 else if(!_tcsnicmp(code
, _T("{p:"), 3))
741 _stscanf(code
, _T("{p:%d"), &p
);
742 ret
->scrAlignment
= (p
== 0) ? 8 : 2;
751 static CStringW
MicroDVD2SSA(CStringW str
, bool fUnicode
, int CharSet
)
755 enum {COLOR
=0, FONTNAME
, FONTSIZE
, FONTCHARSET
, BOLD
, ITALIC
, UNDERLINE
, STRIKEOUT
};
758 memset(fRestore
, 0, sizeof(bool)*fRestoreLen
);
760 for(int pos
= 0, eol
; pos
< str
.GetLength(); pos
++)
762 if((eol
= FindChar(str
, '|', pos
, fUnicode
, CharSet
)) < 0) eol
= str
.GetLength();
764 CStringW line
= str
.Mid(pos
, eol
-pos
);
768 for(int i
= 0, j
, k
, len
= line
.GetLength(); i
< len
; i
++)
770 if((j
= FindChar(line
, '{', i
, fUnicode
, CharSet
)) < 0) j
= str
.GetLength();
772 ret
+= line
.Mid(i
, j
-i
);
776 if((k
= FindChar(line
, '}', j
, fUnicode
, CharSet
)) < 0) k
= len
;
779 CStringW code
= line
.Mid(j
, k
-j
);
781 if(!wcsnicmp(code
, L
"{c:$", 4))
783 fRestore
[COLOR
] = (iswupper(code
[1]) == 0);
787 swscanf(code
, L
"{c:$%x", &color
);
788 code
.Format(L
"{\\c&H%x&}", color
);
791 else if(!wcsnicmp(code
, L
"{f:", 3))
793 fRestore
[FONTNAME
] = (iswupper(code
[1]) == 0);
795 code
.Format(L
"{\\fn%s}", code
.Mid(3));
798 else if(!wcsnicmp(code
, L
"{s:", 3))
800 fRestore
[FONTSIZE
] = (iswupper(code
[1]) == 0);
804 swscanf(code
, L
"{s:%f", &size
);
805 code
.Format(L
"{\\fs%f}", size
);
808 else if(!wcsnicmp(code
, L
"{h:", 3))
810 fRestore
[COLOR
] = (_istupper(code
[1]) == 0);
814 swscanf(code
, L
"{h:%d", &CharSet
);
815 code
.Format(L
"{\\fe%d}", CharSet
);
818 else if(!wcsnicmp(code
, L
"{y:", 3))
820 bool f
= (_istupper(code
[1]) == 0);
825 if(code
.Find('b') >= 0) {ret
+= L
"\\b1"; fRestore
[BOLD
] = f
;}
826 if(code
.Find('i') >= 0) {ret
+= L
"\\i1"; fRestore
[ITALIC
] = f
;}
827 if(code
.Find('u') >= 0) {ret
+= L
"\\u1"; fRestore
[UNDERLINE
] = f
;}
828 if(code
.Find('s') >= 0) {ret
+= L
"\\s1"; fRestore
[STRIKEOUT
] = f
;}
831 else if(!wcsnicmp(code
, L
"{o:", 3))
837 swscanf(code
, L
"{o:%d%c%d", &x
, &c
, &y
);
838 code
.Format(L
"{\\move(%d,%d,0,0,0,0)}", x
, y
);
847 if(pos
>= str
.GetLength()) break;
849 for(int i
= 0; i
< fRestoreLen
; i
++)
855 case COLOR
: ret
+= L
"{\\c}"; break;
856 case FONTNAME
: ret
+= L
"{\\fn}"; break;
857 case FONTSIZE
: ret
+= L
"{\\fs}"; break;
858 case FONTCHARSET
: ret
+= L
"{\\fe}"; break;
859 case BOLD
: ret
+= L
"{\\b}"; break;
860 case ITALIC
: ret
+= L
"{\\i}"; break;
861 case UNDERLINE
: ret
+= L
"{\\u}"; break;
862 case STRIKEOUT
: ret
+= L
"{\\s}"; break;
868 memset(fRestore
, 0, sizeof(bool)*fRestoreLen
);
876 static bool OpenMicroDVD(CTextFile
* file
, CSimpleTextSubtitle
& ret
, int CharSet
)
878 bool fCheck
= false, fCheck2
= false;
880 CString
style(_T("Default"));
883 while(file
->ReadString(buff
))
886 if(buff
.IsEmpty()) continue;
889 int c
= swscanf(buff
, L
"{%d}{%d}", &start
, &end
);
891 if(c
!= 2) {c
= swscanf(buff
, L
"{%d}{}", &start
)+1; end
= start
+ 60; fCheck
= true;}
896 if(buff
.Find('{') == 0 && (i
= buff
.Find('}')) > 1 && i
< buff
.GetLength())
898 if(STSStyle
* s
= GetMicroDVDStyle(WToT(buff
.Mid(i
+1)), CharSet
))
900 style
= buff
.Mid(1, i
-1);
902 if(style
.GetLength()) {CString str
= style
.Mid(1); str
.MakeLower(); style
= style
.Left(1) + str
;}
903 ret
.AddStyle(style
, s
);
904 CharSet
= s
->charSet
;
912 if(fCheck2
&& !ret
.IsEmpty())
914 STSEntry
& stse
= ret
.m_entries
[ret
.m_entries
.GetCount()-1];
915 stse
.end
= min(stse
.end
, start
);
920 MicroDVD2SSA(buff
.Mid(buff
.Find('}', buff
.Find('}')+1)+1), file
->IsUnicode(), CharSet
),
931 else if(c
!= EOF
) // might be another format
937 return(!ret
.IsEmpty());
940 static void ReplaceNoCase(CStringW
& str
, CStringW from
, CStringW to
)
947 for(i
= 0, j
= str
.GetLength(); i
< j
; )
949 if((k
= lstr
.Find(from
, i
)) >= 0)
951 str
.Delete(k
, from
.GetLength()); lstr
.Delete(k
, from
.GetLength());
952 str
.Insert(k
, to
); lstr
.Insert(k
, to
);
953 i
= k
+ to
.GetLength();
960 static CStringW
SMI2SSA(CStringW str
, int CharSet
)
962 ReplaceNoCase(str
, L
" ", L
" ");
963 ReplaceNoCase(str
, L
""", L
"\"");
964 ReplaceNoCase(str
, L
"<br>", L
"\\N");
965 ReplaceNoCase(str
, L
"<i>", L
"{\\i1}");
966 ReplaceNoCase(str
, L
"</i>", L
"{\\i}");
967 ReplaceNoCase(str
, L
"<b>", L
"{\\b1}");
968 ReplaceNoCase(str
, L
"</b>", L
"{\\b}");
975 for(int i
= 0, j
= str
.GetLength(); i
< j
; )
978 if((k
= lstr
.Find('<', i
)) < 0) break;
980 int chars_inserted
= 0;
983 for(; k
+l
< j
&& lstr
[k
+l
] != '>'; l
++);
986 // Modified by Cookie Monster
987 if (lstr
.Find(L
"<font ", k
) == k
)
989 CStringW args
= lstr
.Mid(k
+6, l
-6); // delete "<font "
992 args
.Remove('\"'); args
.Remove('#'); // may include 2 * " + #
993 arg
.TrimLeft(); arg
.TrimRight(L
" >");
998 arg
= args
.SpanExcluding(L
" \t>");
999 args
= args
.Mid(arg
.GetLength());
1003 if (arg
.Find(L
"color=") == 0 )
1007 arg
= arg
.Mid(6); // delete "color="
1012 if(g_colors
.Lookup(CString(arg
), val
))
1014 else if((color
= wcstol(arg
, NULL
, 16) ) == 0)
1015 color
= 0x00ffffff; // default is white
1017 arg
.Format(L
"%02x%02x%02x", color
&0xff, (color
>>8)&0xff, (color
>>16)&0xff);
1018 lstr
.Insert(k
+ l
+ chars_inserted
, CStringW(L
"{\\c&H") + arg
+ L
"&}");
1019 str
.Insert(k
+ l
+ chars_inserted
, CStringW(L
"{\\c&H") + arg
+ L
"&}");
1020 chars_inserted
+= 5 + arg
.GetLength() + 2;
1023 else if (arg.Find(_T("size=" )) == 0 )
1027 arg = arg.Mid(5); // delete "size="
1028 if ( arg.GetLength() == 0)
1031 if ( fsize = _tcstol(arg, &tmp, 10) == 0 )
1034 lstr.Insert(k + l + chars_inserted, CString(_T("{\\fs")) + arg + _T("&}"));
1035 str.Insert(k + l + chars_inserted, CString(_T("{\\fs")) + arg + _T("&}"));
1036 chars_inserted += 4 + arg.GetLength() + 2;
1044 if (lstr.Find(L"<font color=", k) == k)
1046 CStringW arg = lstr.Mid(k+12, l-12); // may include 2 * " + #
1050 arg.TrimLeft(); arg.TrimRight(L" >");
1052 if(arg.GetLength() > 0)
1056 CString key = WToT(arg);
1058 if(g_colors.Lookup(key, val)) color = (DWORD)val;
1059 else color = wcstol(arg, NULL, 16);
1061 arg.Format(L"%02x%02x%02x", color&0xff, (color>>8)&0xff, (color>>16)&0xff);
1064 lstr.Insert(k + l + chars_inserted, L"{\\c&H" + arg + L"&}");
1065 str.Insert(k + l + chars_inserted, L"{\\c&H" + arg + L"&}");
1066 chars_inserted += 5 + arg.GetLength() + 2;
1069 else if (lstr
.Find(L
"</font>", k
) == k
)
1071 lstr
.Insert(k
+ l
+ chars_inserted
, L
"{\\c}");
1072 str
.Insert(k
+ l
+ chars_inserted
, L
"{\\c}");
1073 chars_inserted
+= 4;
1076 str
.Delete(k
, l
); lstr
.Delete(k
, l
);
1077 i
= k
+ chars_inserted
;
1078 j
= str
.GetLength();
1084 static bool OpenSami(CTextFile
* file
, CSimpleTextSubtitle
& ret
, int CharSet
)
1086 CStringW buff
, caption
;
1088 ULONGLONG pos
= file
->GetPosition();
1092 while(file
->ReadString(buff
) && !fSAMI
)
1094 if(buff
.MakeUpper().Find(L
"<SAMI>") >= 0) fSAMI
= true;
1097 if(!fSAMI
) return(false);
1101 bool fComment
= false;
1105 while(file
->ReadString(buff
))
1108 if(buff
.IsEmpty()) continue;
1110 CStringW ubuff
= buff
;
1113 if(ubuff
.Find(L
"<!--") >= 0 || ubuff
.Find(L
"<TITLE>") >= 0)
1120 if((i
= ubuff
.Find(L
"<SYNC START=")) >= 0)
1124 for(i
= 12; i
< ubuff
.GetLength(); i
++)
1126 if(ubuff
[i
] != '>' && ubuff
[i
] != 'M')
1128 if(iswdigit(ubuff
[i
]))
1131 time
+= ubuff
[i
] - 0x30;
1138 SMI2SSA(caption
, CharSet
),
1149 if(ubuff
.Find(L
"-->") >= 0 || ubuff
.Find(L
"</TITLE>") >= 0)
1154 SMI2SSA(caption
, CharSet
),
1156 start_time
, MAXLONG
);
1161 static bool OpenVPlayer(CTextFile
* file
, CSimpleTextSubtitle
& ret
, int CharSet
)
1164 while(file
->ReadString(buff
))
1167 if(buff
.IsEmpty()) continue;
1169 for(int i
= 0; i
< buff
.GetLength(); i
++)
1171 if((i
= FindChar(buff
, '|', i
, file
->IsUnicode(), CharSet
)) < 0) break;
1172 buff
.SetAt(i
, '\n');
1176 int c
= swscanf(buff
, L
"%d:%d:%d:", &hh
, &mm
, &ss
);
1180 CStringW str
= buff
.Mid(buff
.Find(':', buff
.Find(':', buff
.Find(':')+1)+1)+1);
1183 (((hh
*60 + mm
)*60) + ss
)*1000,
1184 (((hh
*60 + mm
)*60) + ss
)*1000 + 1000 + 50*str
.GetLength());
1186 else if(c
!= EOF
) // might be another format
1192 return(!ret
.IsEmpty());
1195 inline CStringW
GetStr(CStringW
& buff
, char sep
= ',') //throw(...)
1199 int pos
= buff
.Find(sep
);
1202 pos
= buff
.GetLength();
1203 if(pos
< 1) throw 1;
1206 CStringW ret
= buff
.Left(pos
);
1207 if(pos
< buff
.GetLength()) buff
= buff
.Mid(pos
+1);
1212 inline int GetInt(CStringW
& buff
, char sep
= ',') //throw(...)
1216 str
= GetStr(buff
, sep
);
1219 CStringW fmtstr
= str
.GetLength() > 2 && (str
.Left(2) == L
"&h" || str
.Left(2) == L
"0x")
1220 ? str
= str
.Mid(2), L
"%x"
1224 if(swscanf(str
, fmtstr
, &ret
) != 1) throw 1;
1229 inline double GetFloat(CStringW
& buff
, char sep
= ',') //throw(...)
1233 str
= GetStr(buff
, sep
);
1237 if(swscanf(str
, L
"%f", &ret
) != 1) throw 1;
1239 return((double)ret
);
1242 inline CStringW::PCXSTR
TryNextStr(CStringW::PXSTR
* buff
, WCHAR sep
= WCHAR(','))
1244 CStringW::PXSTR start
= NULL
;
1245 CStringW::PXSTR ret
= NULL
;
1246 for(start
=*buff
; *start
!=0 && *start
==WCHAR(' '); start
++) ;
1251 for( ;*start
!=0 && *start
!=sep
; start
++) ;
1261 inline int NextInt(CStringW::PXSTR
* buff
, WCHAR sep
= WCHAR(',')) //throw(...)
1265 str
= TryNextStr(buff
, sep
);
1268 CStringW fmtstr
= str
.GetLength() > 2 && (str
.Left(2) == L
"&h" || str
.Left(2) == L
"0x")
1269 ? str
= str
.Mid(2), L
"%x"
1273 if(swscanf(str
, fmtstr
, &ret
) != 1) throw 1;
1278 inline double NextFloat(CStringW::PXSTR
* buff
, WCHAR sep
= WCHAR(',')) //throw(...)
1282 str
= TryNextStr(buff
, sep
);
1286 if(swscanf(str
, L
"%f", &ret
) != 1) throw 1;
1288 return((double)ret
);
1291 static bool LoadFont(CString
& font
)
1293 int len
= font
.GetLength();
1295 CAutoVectorPtr
<BYTE
> pData
;
1296 if(len
== 0 || (len
&3) == 1 || !pData
.Allocate(len
))
1299 const TCHAR
* s
= font
;
1300 const TCHAR
* e
= s
+ len
;
1301 for(BYTE
* p
= pData
; s
< e
; s
++, p
++) *p
= *s
- 33;
1303 for(int i
= 0, j
= 0, k
= len
&~3; i
< k
; i
+=4, j
+=3)
1305 pData
[j
+0] = ((pData
[i
+0]&63)<<2)|((pData
[i
+1]>>4)& 3);
1306 pData
[j
+1] = ((pData
[i
+1]&15)<<4)|((pData
[i
+2]>>2)&15);
1307 pData
[j
+2] = ((pData
[i
+2]& 3)<<6)|((pData
[i
+3]>>0)&63);
1310 int datalen
= (len
&~3)*3/4;
1314 pData
[datalen
++] = ((pData
[(len
&~3)+0]&63)<<2)|((pData
[(len
&~3)+1]>>4)&3);
1316 else if((len
&3) == 3)
1318 pData
[datalen
++] = ((pData
[(len
&~3)+0]&63)<<2)|((pData
[(len
&~3)+1]>>4)& 3);
1319 pData
[datalen
++] = ((pData
[(len
&~3)+1]&15)<<4)|((pData
[(len
&~3)+2]>>2)&15);
1322 HANDLE hFont
= INVALID_HANDLE_VALUE
;
1324 if(HMODULE hModule
= LoadLibrary(_T("GDI32.DLL")))
1326 typedef HANDLE (WINAPI
*PAddFontMemResourceEx
)( IN PVOID
, IN DWORD
, IN PVOID
, IN DWORD
*);
1327 if(PAddFontMemResourceEx f
= (PAddFontMemResourceEx
)GetProcAddress(hModule
, "AddFontMemResourceEx"))
1330 hFont
= f(pData
, datalen
, NULL
, &cFonts
);
1333 FreeLibrary(hModule
);
1336 if(hFont
== INVALID_HANDLE_VALUE
)
1338 TCHAR path
[MAX_PATH
];
1339 GetTempPath(MAX_PATH
, path
);
1342 for(int i
= 0, j
= datalen
>>2; i
< j
; i
++)
1343 chksum
+= ((DWORD
*)(BYTE
*)pData
)[i
];
1346 fn
.Format(_T("%sfont%08x.ttf"), path
, chksum
);
1349 if(!CFileGetStatus(fn
, fs
))
1352 if(f
.Open(fn
, CFile::modeCreate
|CFile::modeWrite
|CFile::typeBinary
|CFile::shareDenyWrite
))
1354 f
.Write(pData
, datalen
);
1359 AddFontResource(fn
);
1365 static bool LoadUUEFont(CTextFile
* file
)
1368 while(file
->ReadString(s
))
1371 if(s
.IsEmpty() || s
[0] == '[') break;
1372 if(s
.Find(_T("fontname:")) == 0) {LoadFont(font
); font
.Empty(); continue;}
1383 static bool OpenSubStationAlpha(CTextFile
* file
, CSimpleTextSubtitle
& ret
, int CharSet
)
1387 int version
= 3, sver
= 3;
1390 while(file
->ReadString(buff
))
1393 if(buff
.IsEmpty() || buff
.GetAt(0) == ';') continue;
1398 entry
= GetStr(buff
, ':');
1400 // catch(...) {continue;}
1404 if(entry
== _T("dialogue"))
1408 CStringW::PXSTR __buff
= buff
.GetBuffer();
1409 int hh1
, mm1
, ss1
, ms1_div10
, hh2
, mm2
, ss2
, ms2_div10
, layer
= 0;
1410 CString Style
, Actor
, Effect
;
1413 if(version
<= 4){TryNextStr(&__buff
, '='); NextInt(&__buff
);} /* Marked = */
1414 if(version
>= 5)layer
= NextInt(&__buff
);
1415 hh1
= NextInt(&__buff
, ':');
1416 mm1
= NextInt(&__buff
, ':');
1417 ss1
= NextInt(&__buff
, '.');
1418 ms1_div10
= NextInt(&__buff
);
1419 hh2
= NextInt(&__buff
, ':');
1420 mm2
= NextInt(&__buff
, ':');
1421 ss2
= NextInt(&__buff
, '.');
1422 ms2_div10
= NextInt(&__buff
);
1423 Style
= WToT(TryNextStr(&__buff
));
1424 Actor
= WToT(TryNextStr(&__buff
));
1425 marginRect
.left
= NextInt(&__buff
);
1426 marginRect
.right
= NextInt(&__buff
);
1427 marginRect
.top
= marginRect
.bottom
= NextInt(&__buff
);
1428 if(version
>= 6)marginRect
.bottom
= NextInt(&__buff
);
1429 Effect
= WToT(TryNextStr(&__buff
));
1431 CStringW buff2
= __buff
;
1432 int len
= min(Effect
.GetLength(), buff2
.GetLength());
1433 if(Effect
.Left(len
) == WToT(buff2
.Left(len
))) Effect
.Empty();
1435 Style
.TrimLeft('*');
1436 if(!Style
.CompareNoCase(_T("Default"))) Style
= _T("Default");
1438 ret
.AddSTSEntryOnly(buff2
,
1440 (((hh1
*60 + mm1
)*60) + ss1
)*1000 + ms1_div10
*10,
1441 (((hh2
*60 + mm2
)*60) + ss2
)*1000 + ms2_div10
*10,
1442 Style
, Actor
, Effect
,
1453 else if(entry
== L
"[script info]")
1457 else if(entry
== L
"playresx")
1459 try {ret
.m_dstScreenSize
.cx
= GetInt(buff
);}
1460 catch(...) {ret
.m_dstScreenSize
= CSize(0, 0); return(false);}
1462 if(ret
.m_dstScreenSize
.cy
<= 0)
1464 ret
.m_dstScreenSize
.cy
= (ret
.m_dstScreenSize
.cx
== 1280)
1466 : ret
.m_dstScreenSize
.cx
* 3 / 4;
1469 else if(entry
== L
"playresy")
1471 try {ret
.m_dstScreenSize
.cy
= GetInt(buff
);}
1472 catch(...) {ret
.m_dstScreenSize
= CSize(0, 0); return(false);}
1474 if(ret
.m_dstScreenSize
.cx
<= 0)
1476 ret
.m_dstScreenSize
.cx
= (ret
.m_dstScreenSize
.cy
== 1024)
1478 : ret
.m_dstScreenSize
.cy
* 4 / 3;
1481 else if(entry
== L
"wrapstyle")
1483 try {ret
.m_defaultWrapStyle
= GetInt(buff
);}
1484 catch(...) {ret
.m_defaultWrapStyle
= 1; return(false);}
1486 else if(entry
== L
"scripttype")
1488 if(buff
.GetLength() >= 4 && !buff
.Right(4).CompareNoCase(L
"4.00")) version
= sver
= 4;
1489 else if(buff
.GetLength() >= 5 && !buff
.Right(5).CompareNoCase(L
"4.00+")) version
= sver
= 5;
1490 else if(buff
.GetLength() >= 6 && !buff
.Right(6).CompareNoCase(L
"4.00++")) version
= sver
= 6;
1492 else if(entry
== L
"collisions")
1494 buff
= GetStr(buff
);
1496 ret
.m_collisions
= buff
.Find(L
"reverse") >= 0 ? 1 : 0;
1498 else if(entry
== L
"scaledborderandshadow")
1500 buff
= GetStr(buff
);
1502 ret
.m_fScaledBAS
= buff
.Find(L
"yes") >= 0;
1504 else if(entry
== L
"[v4 styles]")
1509 else if(entry
== L
"[v4+ styles]")
1514 else if(entry
== L
"[v4++ styles]")
1519 else if(entry
== L
"style")
1521 STSStyle
* style
= new STSStyle
;
1522 if(!style
) return(false);
1530 StyleName
= WToT(GetStr(buff
));
1531 style
->fontName
= WToT(GetStr(buff
));
1532 style
->fontSize
= GetFloat(buff
);
1533 for(int i
= 0; i
< 4; i
++) style
->colors
[i
] = (COLORREF
)GetInt(buff
);
1534 style
->fontWeight
= !!GetInt(buff
) ? FW_BOLD
: FW_NORMAL
;
1535 style
->fItalic
= !!GetInt(buff
);
1536 if(sver
>= 5) style
->fUnderline
= !!GetInt(buff
);
1537 if(sver
>= 5) style
->fStrikeOut
= !!GetInt(buff
);
1538 if(sver
>= 5) style
->fontScaleX
= GetFloat(buff
);
1539 if(sver
>= 5) style
->fontScaleY
= GetFloat(buff
);
1540 if(sver
>= 5) style
->fontSpacing
= GetFloat(buff
);
1541 if(sver
>= 5) style
->fontAngleZ
= GetFloat(buff
);
1542 if(sver
>= 4) style
->borderStyle
= GetInt(buff
);
1543 style
->outlineWidthX
= style
->outlineWidthY
= GetFloat(buff
);
1544 style
->shadowDepthX
= style
->shadowDepthY
= GetFloat(buff
);
1545 style
->scrAlignment
= GetInt(buff
);
1546 tmp_rect
.left
= GetInt(buff
);
1547 tmp_rect
.right
= GetInt(buff
);
1548 tmp_rect
.top
= tmp_rect
.bottom
= GetInt(buff
);
1549 if(sver
>= 6) tmp_rect
.bottom
= GetInt(buff
);
1550 style
->marginRect
= tmp_rect
;
1551 if(sver
<= 4) alpha
= GetInt(buff
);
1552 style
->charSet
= GetInt(buff
);
1553 if(sver
>= 6) style
->relativeTo
= GetInt(buff
);
1555 if(sver
<= 4) style
->colors
[2] = style
->colors
[3]; // style->colors[2] is used for drawing the outline
1556 if(sver
<= 4) alpha
= max(min(alpha
, 0xff), 0);
1557 if(sver
<= 4) {for(int i
= 0; i
< 3; i
++) style
->alpha
[i
] = alpha
; style
->alpha
[3] = 0x80;}
1558 if(sver
>= 5) for(int i
= 0; i
< 4; i
++) {style
->alpha
[i
] = (BYTE
)(style
->colors
[i
]>>24); style
->colors
[i
] &= 0xffffff;}
1559 if(sver
>= 5) style
->fontScaleX
= max(style
->fontScaleX
, 0);
1560 if(sver
>= 5) style
->fontScaleY
= max(style
->fontScaleY
, 0);
1561 if(sver
>= 5) style
->fontSpacing
= max(style
->fontSpacing
, 0);
1562 style
->fontAngleX
= style
->fontAngleY
= 0;
1563 style
->borderStyle
= style
->borderStyle
== 1 ? 0 : style
->borderStyle
== 3 ? 1 : 0;
1564 style
->outlineWidthX
= max(style
->outlineWidthX
, 0);
1565 style
->outlineWidthY
= max(style
->outlineWidthY
, 0);
1566 style
->shadowDepthX
= max(style
->shadowDepthX
, 0);
1567 style
->shadowDepthY
= max(style
->shadowDepthY
, 0);
1568 if(sver
<= 4) style
->scrAlignment
= (style
->scrAlignment
&4) ? ((style
->scrAlignment
&3)+6) // top
1569 : (style
->scrAlignment
&8) ? ((style
->scrAlignment
&3)+3) // mid
1570 : (style
->scrAlignment
&3); // bottom
1572 StyleName
.TrimLeft('*');
1574 ret
.AddStyle(StyleName
, style
);
1582 else if(entry
== L
"[events]")
1586 // else if(entry == _T("dialogue"))
1590 // CStringW::PXSTR __buff = buff.GetBuffer();
1591 // int hh1, mm1, ss1, ms1_div10, hh2, mm2, ss2, ms2_div10, layer = 0;
1592 // CString Style, Actor, Effect;
1593 // CRect marginRect;
1595 //if(version <= 4){NextStr(&__buff, '='); NextInt(&__buff);} /* Marked = */
1596 //if(version >= 5)layer = NextInt(&__buff);
1597 // hh1 = NextInt(&__buff, ':');
1598 // mm1 = NextInt(&__buff, ':');
1599 // ss1 = NextInt(&__buff, '.');
1600 // ms1_div10 = NextInt(&__buff);
1601 // hh2 = NextInt(&__buff, ':');
1602 // mm2 = NextInt(&__buff, ':');
1603 // ss2 = NextInt(&__buff, '.');
1604 // ms2_div10 = NextInt(&__buff);
1605 // Style = WToT(NextStr(&__buff));
1606 // Actor = WToT(NextStr(&__buff));
1607 // marginRect.left = NextInt(&__buff);
1608 // marginRect.right = NextInt(&__buff);
1609 // marginRect.top = marginRect.bottom = NextInt(&__buff);
1610 //if(version >= 6)marginRect.bottom = NextInt(&__buff);
1611 // Effect = WToT(NextStr(&__buff));
1613 // int len = min(Effect.GetLength(), buff.GetLength());
1614 // if(Effect.Left(len) == WToT(buff.Left(len))) Effect.Empty();
1616 // Style.TrimLeft('*');
1617 // if(!Style.CompareNoCase(_T("Default"))) Style = _T("Default");
1619 // ret.AddSTSEntryOnly(__buff,
1620 // file->IsUnicode(),
1621 // (((hh1*60 + mm1)*60) + ss1)*1000 + ms1_div10*10,
1622 // (((hh2*60 + mm2)*60) + ss2)*1000 + ms2_div10*10,
1623 // Style, Actor, Effect,
1634 else if(entry
== L
"fontname")
1643 static bool OpenXombieSub(CTextFile
* file
, CSimpleTextSubtitle
& ret
, int CharSet
)
1647 // CMapStringToPtr stylemap;
1650 while(file
->ReadString(buff
))
1653 if(buff
.IsEmpty() || buff
.GetAt(0) == ';') continue;
1658 entry
= GetStr(buff
, '=');
1660 // catch(...) {continue;}
1664 if(entry
== L
"version")
1666 version
= (float)GetFloat(buff
);
1668 else if(entry
== L
"screenhorizontal")
1670 try {ret
.m_dstScreenSize
.cx
= GetInt(buff
);}
1671 catch(...) {ret
.m_dstScreenSize
= CSize(0, 0); return(false);}
1673 if(ret
.m_dstScreenSize
.cy
<= 0)
1675 ret
.m_dstScreenSize
.cy
= (ret
.m_dstScreenSize
.cx
== 1280)
1677 : ret
.m_dstScreenSize
.cx
* 3 / 4;
1680 else if(entry
== L
"screenvertical")
1682 try {ret
.m_dstScreenSize
.cy
= GetInt(buff
);}
1683 catch(...) {ret
.m_dstScreenSize
= CSize(0, 0); return(false);}
1685 if(ret
.m_dstScreenSize
.cx
<= 0)
1687 ret
.m_dstScreenSize
.cx
= (ret
.m_dstScreenSize
.cy
== 1024)
1689 : ret
.m_dstScreenSize
.cy
* 4 / 3;
1692 else if(entry
== L
"style")
1694 STSStyle
* style
= new STSStyle
;
1695 if(!style
) return(false);
1702 StyleName
= WToT(GetStr(buff
)) + _T("_") + WToT(GetStr(buff
));
1703 style
->fontName
= WToT(GetStr(buff
));
1704 style
->fontSize
= GetFloat(buff
);
1705 for(int i
= 0; i
< 4; i
++) style
->colors
[i
] = (COLORREF
)GetInt(buff
);
1706 for(int i
= 0; i
< 4; i
++) style
->alpha
[i
] = GetInt(buff
);
1707 style
->fontWeight
= !!GetInt(buff
) ? FW_BOLD
: FW_NORMAL
;
1708 style
->fItalic
= !!GetInt(buff
);
1709 style
->fUnderline
= !!GetInt(buff
);
1710 style
->fStrikeOut
= !!GetInt(buff
);
1711 style
->fBlur
= !!GetInt(buff
);
1712 style
->fontScaleX
= GetFloat(buff
);
1713 style
->fontScaleY
= GetFloat(buff
);
1714 style
->fontSpacing
= GetFloat(buff
);
1715 style
->fontAngleX
= GetFloat(buff
);
1716 style
->fontAngleY
= GetFloat(buff
);
1717 style
->fontAngleZ
= GetFloat(buff
);
1718 style
->borderStyle
= GetInt(buff
);
1719 style
->outlineWidthX
= style
->outlineWidthY
= GetFloat(buff
);
1720 style
->shadowDepthX
= style
->shadowDepthY
= GetFloat(buff
);
1721 style
->scrAlignment
= GetInt(buff
);
1723 tmp_rect
.left
= GetInt(buff
);
1724 tmp_rect
.right
= GetInt(buff
);
1725 tmp_rect
.top
= tmp_rect
.bottom
= GetInt(buff
);
1726 style
->marginRect
= tmp_rect
;
1728 style
->charSet
= GetInt(buff
);
1730 style
->fontScaleX
= max(style
->fontScaleX
, 0);
1731 style
->fontScaleY
= max(style
->fontScaleY
, 0);
1732 style
->fontSpacing
= max(style
->fontSpacing
, 0);
1733 style
->borderStyle
= style
->borderStyle
== 1 ? 0 : style
->borderStyle
== 3 ? 1 : 0;
1734 style
->outlineWidthX
= max(style
->outlineWidthX
, 0);
1735 style
->outlineWidthY
= max(style
->outlineWidthY
, 0);
1736 style
->shadowDepthX
= max(style
->shadowDepthX
, 0);
1737 style
->shadowDepthY
= max(style
->shadowDepthY
, 0);
1739 ret
.AddStyle(StyleName
, style
);
1747 else if(entry
== L
"line")
1752 int hh1
, mm1
, ss1
, ms1
, hh2
, mm2
, ss2
, ms2
, layer
= 0;
1753 CString Style
, Actor
;
1756 if(GetStr(buff
) != L
"D") continue;
1758 layer
= GetInt(buff
);
1759 hh1
= GetInt(buff
, ':');
1760 mm1
= GetInt(buff
, ':');
1761 ss1
= GetInt(buff
, '.');
1763 hh2
= GetInt(buff
, ':');
1764 mm2
= GetInt(buff
, ':');
1765 ss2
= GetInt(buff
, '.');
1767 Style
= WToT(GetStr(buff
)) + _T("_") + WToT(GetStr(buff
));
1768 Actor
= WToT(GetStr(buff
));
1769 marginRect
.left
= GetInt(buff
);
1770 marginRect
.right
= GetInt(buff
);
1771 marginRect
.top
= marginRect
.bottom
= GetInt(buff
);
1773 Style
.TrimLeft('*');
1774 if(!Style
.CompareNoCase(_T("Default"))) Style
= _T("Default");
1778 (((hh1
*60 + mm1
)*60) + ss1
)*1000 + ms1
,
1779 (((hh2
*60 + mm2
)*60) + ss2
)*1000 + ms2
,
1780 Style
, Actor
, _T(""),
1789 else if(entry
== L
"fontname")
1795 return(!ret
.IsEmpty());
1798 #include "USFSubtitles.h"
1800 static bool OpenUSF(CTextFile
* file
, CSimpleTextSubtitle
& ret
, int CharSet
)
1803 while(file
->ReadString(str
))
1805 if(str
.Find(_T("USFSubtitles")) >= 0)
1808 if(usf
.Read(file
->GetFilePath()) && usf
.ConvertToSTS(ret
))
1818 static CStringW
MPL22SSA(CStringW str
)
1820 CAtlList
<CStringW
> sl
;
1821 Explode(str
, sl
, '|');
1822 POSITION pos
= sl
.GetHeadPosition();
1825 CStringW
& s
= sl
.GetNext(pos
);
1826 if(s
[0] == '/') {s
= L
"{\\i1}" + s
.Mid(1) + L
"{\\i0}";}
1828 str
= Implode(sl
, '\n');
1829 str
.Replace(L
"\n", L
"\\N");
1833 static bool OpenMPL2(CTextFile
* file
, CSimpleTextSubtitle
& ret
, int CharSet
)
1836 while(file
->ReadString(buff
))
1839 if(buff
.IsEmpty()) continue;
1842 int c
= swscanf(buff
, L
"[%d][%d]", &start
, &end
);
1847 MPL22SSA(buff
.Mid(buff
.Find(']', buff
.Find(']')+1)+1)),
1849 start
*100, end
*100);
1851 else if(c
!= EOF
) // might be another format
1857 return(!ret
.IsEmpty());
1860 typedef bool (*STSOpenFunct
)(CTextFile
* file
, CSimpleTextSubtitle
& ret
, int CharSet
);
1862 static bool OpenRealText(CTextFile
* file
, CSimpleTextSubtitle
& ret
, int CharSet
);
1864 typedef struct {STSOpenFunct open
; tmode mode
;} OpenFunctStruct
;
1866 static OpenFunctStruct OpenFuncts
[] =
1868 OpenSubStationAlpha
, TIME
,
1869 OpenSubRipper
, TIME
,
1870 OpenOldSubRipper
, TIME
,
1871 OpenSubViewer
, TIME
,
1872 OpenMicroDVD
, FRAME
,
1875 OpenXombieSub
, TIME
,
1881 static int nOpenFuncts
= countof(OpenFuncts
);
1885 CSimpleTextSubtitle::CSimpleTextSubtitle()
1888 m_dstScreenSize
= CSize(0, 0);
1889 m_defaultWrapStyle
= 0;
1891 m_fScaledBAS
= false;
1892 m_encoding
= CTextFile::ASCII
;
1893 m_ePARCompensationType
= EPCTDisabled
;
1894 m_dPARCompensation
= 1.0;
1897 CSimpleTextSubtitle::~CSimpleTextSubtitle()
1902 CSimpleTextSubtitle::CSimpleTextSubtitle(CSimpleTextSubtitle& sts)
1907 CSimpleTextSubtitle& CSimpleTextSubtitle::operator = (CSimpleTextSubtitle& sts)
1911 m_name = sts.m_name;
1912 m_mode = sts.m_mode;
1913 m_dstScreenSize = sts.m_dstScreenSize;
1914 m_defaultWrapStyle = sts.m_defaultWrapStyle;
1915 m_collisions = sts.m_collisions;
1916 m_fScaledBAS = sts.m_fScaledBAS;
1917 m_fSSA = sts.m_fSSA;
1918 m_fUsingAutoGeneratedDefaultStyle = sts.m_fUsingAutoGeneratedDefaultStyle;
1919 CopyStyles(sts.m_styles);
1920 m_segments.Copy(sts.m_segments);
1927 void CSimpleTextSubtitle::Copy(CSimpleTextSubtitle
& sts
)
1931 m_name
= sts
.m_name
;
1932 m_mode
= sts
.m_mode
;
1933 m_dstScreenSize
= sts
.m_dstScreenSize
;
1934 m_defaultWrapStyle
= sts
.m_defaultWrapStyle
;
1935 m_collisions
= sts
.m_collisions
;
1936 m_fScaledBAS
= sts
.m_fScaledBAS
;
1937 m_encoding
= sts
.m_encoding
;
1938 m_fUsingAutoGeneratedDefaultStyle
= sts
.m_fUsingAutoGeneratedDefaultStyle
;
1939 CopyStyles(sts
.m_styles
);
1940 m_segments
.Copy(sts
.m_segments
);
1941 m_entries
.Copy(sts
.m_entries
);
1944 void CSimpleTextSubtitle::Append(CSimpleTextSubtitle
& sts
, int timeoff
)
1948 timeoff
= m_entries
.GetCount() > 0 ? m_entries
.GetAt(m_entries
.GetCount()-1).end
: 0;
1951 for(int i
= 0, j
= m_entries
.GetCount(); i
< j
; i
++)
1953 if(m_entries
.GetAt(i
).start
> timeoff
)
1955 m_entries
.RemoveAt(i
, j
- i
);
1960 CopyStyles(sts
.m_styles
, true);
1962 for(int i
= 0, j
= sts
.m_entries
.GetCount(); i
< j
; i
++)
1964 STSEntry stse
= sts
.m_entries
.GetAt(i
);
1965 stse
.start
+= timeoff
;
1966 stse
.end
+= timeoff
;
1967 stse
.readorder
+= m_entries
.GetCount();
1968 m_entries
.Add(stse
);
1974 void CSTSStyleMap::Free()
1976 POSITION pos
= GetStartPosition();
1981 GetNextAssoc(pos
, key
, val
);
1988 bool CSimpleTextSubtitle::CopyStyles(const CSTSStyleMap
& styles
, bool fAppend
)
1990 if(!fAppend
) m_styles
.Free();
1992 POSITION pos
= styles
.GetStartPosition();
1997 styles
.GetNextAssoc(pos
, key
, val
);
1999 STSStyle
* s
= new STSStyle
;
2000 if(!s
) return(false);
2010 void CSimpleTextSubtitle::Empty()
2012 m_dstScreenSize
= CSize(0, 0);
2014 m_segments
.RemoveAll();
2015 m_entries
.RemoveAll();
2018 void CSimpleTextSubtitle::Add(CStringW str
, bool fUnicode
, int start
, int end
,
2019 CString style
, const CString
& actor
, const CString
& effect
, const CRect
& marginRect
, int layer
, int readorder
)
2021 XY_LOG_INFO(start
<<_T(" ")<<end
<<_T(" ")<<str
.GetString()<<_T(" style:")<<style
.GetString()
2022 <<_T(" Unicode:")<<fUnicode
2023 <<_T(" actor:")<<actor
.GetString()<<_T(" effect:")<<effect
.GetString()
2024 <<_T(" (l:")<<marginRect
.left
<<_T(",t:")<<marginRect
.top
<<_T(",r:")<<marginRect
.right
<<_T(",b:")<<marginRect
.bottom
2025 <<_T(" layer:")<<layer
<<_T(" readorder:")<<readorder
2026 <<_T(" entries:")<<m_entries
.GetCount()<<_T(" seg:")<<m_segments
.GetCount());
2028 if(start
> end
|| str
.Trim().IsEmpty() ) return;
2031 str
.Replace(L
"\n", L
"\\N");
2032 if(style
.IsEmpty()) style
= g_default_style
;
2033 else if(style
!=g_default_style
)
2035 style
.TrimLeft('*');
2040 sub
.fUnicode
= fUnicode
;
2043 sub
.effect
= effect
;
2044 sub
.marginRect
= marginRect
;
2048 sub
.readorder
= readorder
< 0 ? m_entries
.GetCount() : readorder
;
2049 int n
= m_entries
.Add(sub
);
2051 int len
= m_segments
.GetCount();
2055 STSSegment
stss(start
, end
);
2057 m_segments
.Add(stss
);
2059 else if(end
<= m_segments
[0].start
)
2061 STSSegment
stss(start
, end
);
2063 m_segments
.InsertAt(0, stss
);
2065 else if(start
>= m_segments
[len
-1].end
)
2067 STSSegment
stss(start
, end
);
2069 m_segments
.Add(stss
);
2073 if(start
< m_segments
[0].start
)
2075 STSSegment
stss(start
, m_segments
[0].start
);
2077 start
= m_segments
[0].start
;
2078 m_segments
.InsertAt(0, stss
);
2081 for(size_t i
= 0; i
< m_segments
.GetCount(); i
++)
2083 STSSegment
& s
= m_segments
[i
];
2089 else if(end
<= s
.start
)
2093 else if(s
.start
< start
&& start
< s
.end
)
2095 STSSegment
stss(s
.start
, start
);
2096 stss
.subs
.Copy(s
.subs
);
2098 m_segments
.InsertAt(i
, stss
);
2101 if(start
<= s
.start
&& s
.end
<= end
)
2103 for(int j
= 0, k
= s
.subs
.GetCount(); j
<= k
; j
++)
2105 if(j
== k
|| sub
.readorder
< m_entries
.GetAt(s
.subs
[j
]).readorder
)
2107 s
.subs
.InsertAt(j
, n
);
2112 else if(s
.start
< end
&& end
< s
.end
)
2114 STSSegment
stss(s
.start
, end
);
2115 stss
.subs
.Copy(s
.subs
);
2116 for(int j
= 0, k
= s
.subs
.GetCount(); j
<= k
; j
++)
2118 if(j
== k
|| sub
.readorder
< m_entries
.GetAt(stss
.subs
[j
]).readorder
)
2120 stss
.subs
.InsertAt(j
, n
);
2125 m_segments
.InsertAt(i
, stss
);
2129 if(end
> m_segments
[m_segments
.GetCount()-1].end
)
2131 STSSegment
stss(m_segments
[m_segments
.GetCount()-1].end
, end
);
2133 m_segments
.Add(stss
);
2138 str.Replace(L"\n", L"\\N");
2139 if(style.IsEmpty()) style = _T("Default");
2141 int j = m_segments.GetCount();
2142 for(int i = j-1; i >= 0; i--)
2144 if(m_segments[i].end <= start)
2148 else if(m_segments[i].start >= start)
2150 m_segments.SetCount(m_segments.GetCount()-1);
2153 else if(m_segments[i].end > start)
2155 if(i < j-1) m_segments.RemoveAt(i+1, j-i-1);
2156 m_segments[i].end = start;
2161 if(m_segments.GetCount() == 0 && j > 0)
2162 CSTSArray::RemoveAll();
2164 STSSegment stss(start, end);
2165 int len = m_entries.GetCount();
2167 m_segments.Add(stss);
2171 sub.fUnicode = fUnicode;
2174 sub.effect = effect;
2175 sub.marginRect = marginRect;
2179 sub.readorder = m_entries.GetCount();
2180 CSTSArray::Add(sub);
2184 void CSimpleTextSubtitle::AddSTSEntryOnly( CStringW str
, bool fUnicode
, int start
, int end
, CString style
/*= _T("Default")*/, const CString
& actor
/*= _T("")*/, const CString
& effect
/*= _T("")*/, const CRect
& marginRect
/*= CRect(0,0,0,0)*/, int layer
/*= 0*/, int readorder
/*= -1*/ )
2186 if(str
.Trim().IsEmpty() || start
> end
) return;
2189 str
.Replace(L
"\n", L
"\\N");
2190 if(style
.IsEmpty()) style
= _T("Default");
2191 style
.TrimLeft('*');
2195 sub
.fUnicode
= fUnicode
;
2198 sub
.effect
= effect
;
2199 sub
.marginRect
= marginRect
;
2203 sub
.readorder
= readorder
< 0 ? m_entries
.GetCount() : readorder
;
2208 STSStyle
* CSimpleTextSubtitle::CreateDefaultStyle(int CharSet
)
2210 STSStyle
* ret
= NULL
;
2212 if(!m_styles
.Lookup(g_default_style
, ret
))
2214 STSStyle
* style
= new STSStyle();
2215 style
->charSet
= CharSet
;
2216 AddStyle(g_default_style
, style
);
2217 m_styles
.Lookup(g_default_style
, ret
);
2219 m_fUsingAutoGeneratedDefaultStyle
= true;
2223 m_fUsingAutoGeneratedDefaultStyle
= false;
2229 void CSimpleTextSubtitle::ChangeUnknownStylesToDefault()
2231 CAtlMap
<CString
, STSStyle
*, CStringElementTraits
<CString
> > unknown
;
2232 bool fReport
= true;
2234 for(size_t i
= 0; i
< m_entries
.GetCount(); i
++)
2236 STSEntry
& stse
= m_entries
.GetAt(i
);
2239 if(!m_styles
.Lookup(stse
.style
, val
))
2241 if(!unknown
.Lookup(stse
.style
, val
))
2246 msg
.Format(_T("Unknown style found: \"%s\", changed to \"Default\"!\n\nPress Cancel to ignore further warnings."), stse
.style
);
2247 if(MessageBox(NULL
, msg
, _T("Warning"), MB_OKCANCEL
|MB_ICONWARNING
) != IDOK
) fReport
= false;
2250 unknown
[stse
.style
] = NULL
;
2253 stse
.style
= g_default_style
;
2258 void CSimpleTextSubtitle::AddStyle(CString name
, STSStyle
* style
)
2262 if(name
.IsEmpty()) name
= g_default_style
;
2265 if(m_styles
.Lookup(name
, val
))
2272 const CString
& name_str
= name
;
2274 int len
= name_str
.GetLength();
2276 for(i
= len
; i
> 0 && _istdigit(name_str
[i
-1]); i
--);
2280 CString name2
= name_str
;
2282 if(i
< len
&& _stscanf(name_str
.Right(len
-i
), _T("%d"), &idx
) == 1)
2284 name2
= name_str
.Left(i
);
2293 name3_str
.Format(_T("%s%d"), name2
, idx
);
2297 while(m_styles
.Lookup(name3
));
2299 m_styles
.RemoveKey(name
);
2300 m_styles
[name3
] = val
;
2302 for(i
= 0, j
= m_entries
.GetCount(); i
< j
; i
++)
2304 STSEntry
& stse
= m_entries
.GetAt(i
);
2305 if(stse
.style
== name
) stse
.style
= name3
;
2309 m_styles
[name
] = style
;
2312 bool CSimpleTextSubtitle::SetDefaultStyle(STSStyle
& s
)
2314 DbgLog((LOG_TRACE
, 3, "%s(%d): %s", __FILE__
, __LINE__
, __FUNCTION__
));
2315 DbgLog((LOG_TRACE
, 3, "\tm_styles count:%d", m_styles
.GetCount()));
2317 if(!m_styles
.Lookup(g_default_style
, val
)) return false;
2318 DbgLog((LOG_TRACE
, 3, "\tm_styles Lookup Default succeed"));
2321 for(POSITION pos
=m_styles
.GetStartPosition(); pos
!=NULL
;)
2323 DbgLog((LOG_TRACE
, 3, _T("\tm_styles[%s]"), (LPCTSTR
)m_styles
.GetNextKey(pos
)));
2328 m_fUsingAutoGeneratedDefaultStyle
= false;
2332 bool CSimpleTextSubtitle::GetDefaultStyle(STSStyle
& s
)
2335 if(!m_styles
.Lookup(g_default_style
, val
)) return false;
2340 void CSimpleTextSubtitle::ConvertToTimeBased(double fps
)
2342 if(m_mode
== TIME
) return;
2344 for(int i
= 0, j
= m_entries
.GetCount(); i
< j
; i
++)
2346 STSEntry
& stse
= m_entries
[i
];
2347 stse
.start
= int(1.0 * stse
.start
* 1000 / fps
+ 0.5);
2348 stse
.end
= int(1.0 * stse
.end
* 1000 / fps
+ 0.5);
2356 void CSimpleTextSubtitle::ConvertToFrameBased(double fps
)
2358 if(m_mode
== FRAME
) return;
2360 for(int i
= 0, j
= m_entries
.GetCount(); i
< j
; i
++)
2362 STSEntry
& stse
= m_entries
[i
];
2363 stse
.start
= int(1.0 * stse
.start
* fps
/ 1000 + 0.5);
2364 stse
.end
= int(1.0 * stse
.end
* fps
/ 1000 + 0.5);
2372 int CSimpleTextSubtitle::SearchSub(int t
, double fps
)
2374 int i
= 0, j
= m_entries
.GetCount() - 1, ret
= -1;
2376 if(j
>= 0 && t
>= TranslateStart(j
, fps
))
2383 int mid
= (i
+ j
) >> 1;
2385 int midt
= TranslateStart(mid
, fps
);
2389 while(mid
> 0 && t
== TranslateStart(mid
-1, fps
)) mid
--;
2410 const STSSegment
* CSimpleTextSubtitle::SearchSubs(int t
, double fps
, /*[out]*/ int* iSegment
, int* nSegments
)
2412 int segmentsCount
= m_segments
.GetCount();
2413 int i
= 0, j
= segmentsCount
- 1;
2415 if(nSegments
) *nSegments
= segmentsCount
;
2416 if(segmentsCount
<=0)
2423 if(t
>= TranslateSegmentEnd(j
, fps
))
2428 if(t
< TranslateSegmentEnd(i
, fps
))
2436 int mid
= (i
+ j
) >> 1;
2438 int midt
= TranslateSegmentEnd(mid
, fps
);
2449 return &m_segments
[j
];
2454 STSSegment
* CSimpleTextSubtitle::SearchSubs2(int t
, double fps
, /*[out]*/ int* iSegment
, int* nSegments
)
2456 int segmentsCount
= m_segments
.GetCount();
2457 int i
= 0, j
= segmentsCount
- 1;
2459 if(iSegment
) *iSegment
= -1;
2460 if(nSegments
) *nSegments
= segmentsCount
;
2462 if(segmentsCount
<=0)
2464 if(iSegment
) *iSegment
= 0;
2468 if(t
>= TranslateSegmentEnd(j
, fps
))
2473 if(t
< TranslateSegmentEnd(i
, fps
))
2481 int mid
= (i
+ j
) >> 1;
2483 int midt
= TranslateSegmentEnd(mid
, fps
);
2490 if(j
<segmentsCount
&& t
>=TranslateSegmentStart(j
, fps
))
2492 if(iSegment
) *iSegment
= j
;
2493 return &m_segments
[j
];
2500 int CSimpleTextSubtitle::TranslateStart(int i
, double fps
)
2502 return(i
< 0 || m_entries
.GetCount() <= i
? -1 :
2503 m_mode
== TIME
? m_entries
.GetAt(i
).start
:
2504 m_mode
== FRAME
? (int)(m_entries
.GetAt(i
).start
*1000/fps
) :
2508 int CSimpleTextSubtitle::TranslateEnd(int i
, double fps
)
2510 return(i
< 0 || m_entries
.GetCount() <= i
? -1 :
2511 m_mode
== TIME
? m_entries
.GetAt(i
).end
:
2512 m_mode
== FRAME
? (int)(m_entries
.GetAt(i
).end
*1000/fps
) :
2516 int CSimpleTextSubtitle::TranslateSegmentStart(int i
, double fps
)
2518 return(i
< 0 || m_segments
.GetCount() <= i
? -1 :
2519 m_mode
== TIME
? m_segments
[i
].start
:
2520 m_mode
== FRAME
? (int)(m_segments
[i
].start
*1000/fps
) :
2524 int CSimpleTextSubtitle::TranslateSegmentEnd(int i
, double fps
)
2526 return(i
< 0 || m_segments
.GetCount() <= i
? -1 :
2527 m_mode
== TIME
? m_segments
[i
].end
:
2528 m_mode
== FRAME
? (int)(m_segments
[i
].end
*1000/fps
) :
2532 void CSimpleTextSubtitle::TranslateSegmentStartEnd(int i
, double fps
, /*out*/int& start
, /*out*/int& end
)
2534 if(i
< 0 || m_segments
.GetCount() <= i
)
2543 start
= m_segments
[i
].start
;
2544 end
= m_segments
[i
].end
;
2546 else //m_mode == FRAME
2548 start
= (int)(m_segments
[i
].start
*1000/fps
);
2549 end
= (int)(m_segments
[i
].end
*1000/fps
);
2554 STSStyle
* CSimpleTextSubtitle::GetStyle(int i
)
2556 STSStyle
* style
= NULL
;
2557 m_styles
.Lookup(m_entries
.GetAt(i
).style
, style
);
2559 STSStyle
* defstyle
= NULL
;
2560 m_styles
.Lookup(g_default_style
, defstyle
);
2572 bool CSimpleTextSubtitle::GetStyle(int i
, STSStyle
* const stss
)
2574 STSStyle
* style
= NULL
;
2575 m_styles
.Lookup(m_entries
.GetAt(i
).style
, style
);
2577 STSStyle
* defstyle
= NULL
;
2578 m_styles
.Lookup(g_default_style
, defstyle
);
2584 defstyle
= CreateDefaultStyle(DEFAULT_CHARSET
);
2590 if(!style
) {ASSERT(0); return false;}
2593 if(stss
->relativeTo
== 2 && defstyle
)
2594 stss
->relativeTo
= defstyle
->relativeTo
;
2599 int CSimpleTextSubtitle::GetCharSet(int i
)
2601 STSStyle
* style
= GetStyle(i
);
2602 return style
!=NULL
? style
->charSet
: -1;
2605 bool CSimpleTextSubtitle::IsEntryUnicode(int i
)
2607 return(m_entries
.GetAt(i
).fUnicode
);
2610 void CSimpleTextSubtitle::ConvertUnicode(int i
, bool fUnicode
)
2612 STSEntry
& stse
= m_entries
.GetAt(i
);
2614 if(stse
.fUnicode
^ fUnicode
)
2616 int CharSet
= GetCharSet(i
);
2619 ? MBCSSSAToUnicode(stse
.str
, CharSet
)
2620 : UnicodeSSAToMBCS(stse
.str
, CharSet
);
2622 stse
.fUnicode
= fUnicode
;
2626 CStringA
CSimpleTextSubtitle::GetStrA(int i
, bool fSSA
)
2628 return(WToA(GetStrWA(i
, fSSA
)));
2631 CStringW
CSimpleTextSubtitle::GetStrW(int i
, bool fSSA
)
2633 bool fUnicode
= IsEntryUnicode(i
);
2634 int CharSet
= GetCharSet(i
);
2636 CStringW str
= m_entries
.GetAt(i
).str
;
2639 str
= MBCSSSAToUnicode(str
, CharSet
);
2642 str
= RemoveSSATags(str
, fUnicode
, CharSet
);
2647 CStringW
CSimpleTextSubtitle::GetStrWA(int i
, bool fSSA
)
2649 bool fUnicode
= IsEntryUnicode(i
);
2650 int CharSet
= GetCharSet(i
);
2652 CStringW str
= m_entries
.GetAt(i
).str
;
2655 str
= UnicodeSSAToMBCS(str
, CharSet
);
2658 str
= RemoveSSATags(str
, fUnicode
, CharSet
);
2663 void CSimpleTextSubtitle::SetStr(int i
, CStringA str
, bool fUnicode
)
2665 SetStr(i
, AToW(str
), false);
2668 void CSimpleTextSubtitle::SetStr(int i
, CStringW str
, bool fUnicode
)
2670 STSEntry
& stse
= m_entries
.GetAt(i
);
2672 str
.Replace(L
"\n", L
"\\N");
2674 if(stse
.fUnicode
&& !fUnicode
) stse
.str
= MBCSSSAToUnicode(str
, GetCharSet(i
));
2675 else if(!stse
.fUnicode
&& fUnicode
) stse
.str
= UnicodeSSAToMBCS(str
, GetCharSet(i
));
2676 else stse
.str
= str
;
2679 static int comp1(const void* a
, const void* b
)
2681 int ret
= ((STSEntry
*)a
)->start
- ((STSEntry
*)b
)->start
;
2682 if(ret
== 0) ret
= ((STSEntry
*)a
)->layer
- ((STSEntry
*)b
)->layer
;
2683 if(ret
== 0) ret
= ((STSEntry
*)a
)->readorder
- ((STSEntry
*)b
)->readorder
;
2687 static int comp2(const void* a
, const void* b
)
2689 return(((STSEntry
*)a
)->readorder
- ((STSEntry
*)b
)->readorder
);
2692 void CSimpleTextSubtitle::Sort(bool fRestoreReadorder
)
2694 qsort(m_entries
.GetData(), m_entries
.GetCount(), sizeof(STSEntry
), !fRestoreReadorder
? comp1
: comp2
);
2698 static int intcomp(const void* i1
, const void* i2
)
2700 return(*((int*)i1
) - *((int*)i2
));
2703 void CSimpleTextSubtitle::CreateSegments()
2705 m_segments
.RemoveAll();
2707 if(m_entries
.GetCount()>0)
2709 size_t start
, mid
, end
;
2710 CAtlArray
<STSSegment
> tempSegments
;//if add to m_segments directly, then remove empty entities can be a
2711 //complex operation when having large segmentCount and lots of empty entities
2712 std::vector
<int> breakpoints(2*m_entries
.GetCount());
2713 for(size_t i
= 0; i
< m_entries
.GetCount(); i
++)
2715 STSEntry
& stse
= m_entries
.GetAt(i
);
2716 breakpoints
[2*i
]=stse
.start
;
2717 breakpoints
[2*i
+1]=stse
.end
;
2720 std::sort(breakpoints
.begin(), breakpoints
.end());
2722 int ptr
= 1, prev
= breakpoints
[0];
2723 for(size_t i
= breakpoints
.size()-1; i
> 0; i
--, ptr
++)
2725 if(breakpoints
[ptr
] != prev
)
2727 tempSegments
.Add(STSSegment(prev
, breakpoints
[ptr
]));
2728 prev
= breakpoints
[ptr
];
2732 size_t segmentCount
= tempSegments
.GetCount();
2734 for(size_t i
= 0; i
< m_entries
.GetCount(); i
++)
2736 STSEntry
& stse
= m_entries
.GetAt(i
);
2741 mid
= (start
+end
)>>1;
2742 if(tempSegments
[mid
].start
< stse
.start
)
2751 for(; start
< tempSegments
.GetCount() && tempSegments
[start
].end
<= stse
.end
; start
++)
2752 tempSegments
[start
].subs
.Add(i
);
2754 for(size_t i
= 0; i
< segmentCount
; i
++)
2755 if(tempSegments
[i
].subs
.GetCount()>0)
2756 m_segments
.Add(tempSegments
[i
]);
2760 for(i = 0, j = m_segments.GetCount(); i < j; i++)
2762 STSSegment& stss = m_segments[i];
2764 TRACE(_T("%d - %d"), stss.start, stss.end);
2766 for(int k = 0, l = stss.subs.GetCount(); k < l; k++)
2768 TRACE(_T(", %d"), stss.subs[k]);
2776 bool CSimpleTextSubtitle::Open(CString fn
, int CharSet
, CString name
)
2781 if(!f
.Open(fn
)) return(false);
2783 fn
.Replace('\\', '/');
2786 name
= fn
.Left(fn
.ReverseFind('.'));
2787 name
= name
.Mid(name
.ReverseFind('/')+1);
2788 name
= name
.Mid(name
.ReverseFind('.')+1);
2791 return(Open(&f
, CharSet
, name
));
2794 static int CountLines(CTextFile
* f
, ULONGLONG from
, ULONGLONG to
)
2799 while(f
->ReadString(s
) && f
->GetPosition() < to
) n
++;
2803 bool CSimpleTextSubtitle::Open(CTextFile
* f
, int CharSet
, CString name
)
2807 ULONGLONG pos
= f
->GetPosition();
2809 for(int i
= 0; i
< nOpenFuncts
; i
++)
2811 const TCHAR
* func_name
[]={
2812 TEXT("OpenSubStationAlpha"),
2813 TEXT("OpenSubRipper"),
2814 TEXT("OpenOldSubRipper"),
2815 TEXT("OpenSubViewer"),
2816 TEXT("OpenMicroDVD"),
2818 TEXT("OpenVPlayer"),
2819 TEXT("OpenXombieSub"),
2822 TEXT("OpenRealText")};
2823 CAutoTiming
t(func_name
[i
],0);
2825 if(!OpenFuncts
[i
].open(f
, *this, CharSet
) /*|| !GetCount()*/)
2827 if(m_entries
.GetCount() > 0)
2829 int n
= CountLines(f
, pos
, f
->GetPosition());
2831 s
.Format(_T("Syntax error at line %d!\t"), n
+1);
2832 AfxMessageBox(s
, MB_OK
|MB_ICONERROR
);
2843 m_mode
= OpenFuncts
[i
].mode
;
2844 m_encoding
= f
->GetEncoding();
2845 m_path
= f
->GetFilePath();
2848 if(f2
.Open(f
->GetFilePath() + _T(".style")))
2849 OpenSubStationAlpha(&f2
, *this, CharSet
);
2854 CreateDefaultStyle(CharSet
);
2856 ChangeUnknownStylesToDefault();
2858 if(m_dstScreenSize
== CSize(0, 0)) m_dstScreenSize
= CSize(384, 288);
2866 bool CSimpleTextSubtitle::Open(BYTE
* data
, int len
, int CharSet
, CString name
)
2868 TCHAR path
[MAX_PATH
];
2869 if(!GetTempPath(MAX_PATH
, path
)) return(false);
2872 if(!GetTempFileName(path
, _T("vs"), 0, fn
)) return(false);
2874 FILE* tmp
= _tfopen(fn
, _T("wb"));
2875 if(!tmp
) return(false);
2878 for(; i
<= (len
-1024); i
+= 1024) fwrite(&data
[i
], 1024, 1, tmp
);
2879 if(len
> i
) fwrite(&data
[i
], len
- i
, 1, tmp
);
2883 bool fRet
= Open(fn
, CharSet
, name
);
2890 bool CSimpleTextSubtitle::SaveAs(CString fn
, exttype et
, double fps
, CTextFile::enc e
)
2892 if(fn
.Mid(fn
.ReverseFind('.')+1).CompareNoCase(exttypestr
[et
]))
2894 if(fn
[fn
.GetLength()-1] != '.') fn
+= _T(".");
2895 fn
+= exttypestr
[et
];
2906 str
+= _T("<SAMI>\n<HEAD>\n");
2907 str
+= _T("<STYLE TYPE=\"text/css\">\n");
2908 str
+= _T("<!--\n");
2909 str
+= _T("P {margin-left: 16pt; margin-right: 16pt; margin-bottom: 16pt; margin-top: 16pt;\n");
2910 str
+= _T(" text-align: center; font-size: 18pt; font-family: arial; font-weight: bold; color: #f0f0f0;}\n");
2911 str
+= _T(".UNKNOWNCC {Name:Unknown; lang:en-US; SAMIType:CC;}\n");
2913 str
+= _T("</STYLE>\n");
2914 str
+= _T("</HEAD>\n");
2916 str
+= _T("<BODY>\n");
2920 else if(et
== EXTSSA
|| et
== EXTASS
)
2924 str
= _T("[Script Info]\n");
2925 str
+= (et
== EXTSSA
) ? _T("; This is a Sub Station Alpha v4 script.\n") : _T("; This is an Advanced Sub Station Alpha v4+ script.\n");
2926 str
+= _T("; For Sub Station Alpha info and downloads,\n");
2927 str
+= _T("; go to http://www.eswat.demon.co.uk/\n");
2928 str
+= _T("; or email kotus@eswat.demon.co.uk\n");
2932 str
+= _T("; Advanced Sub Station Alpha script format developed by #Anime-Fansubs@EfNET\n");
2933 str
+= _T("; http://www.anime-fansubs.org\n");
2935 str
+= _T("; For additional info and downloads go to http://gabest.org/\n");
2936 str
+= _T("; or email gabest@freemail.hu\n");
2939 str
+= _T("; Note: This file was saved by Subresync.\n");
2941 str
+= (et
== EXTSSA
) ? _T("ScriptType: v4.00\n") : _T("ScriptType: v4.00+\n");
2942 str
+= (m_collisions
== 0) ? _T("Collisions: Normal\n") : _T("Collisions: Reverse\n");
2943 if(et
== EXTASS
&& m_fScaledBAS
) str
+= _T("ScaledBorderAndShadow: Yes\n");
2944 str
+= _T("PlayResX: %d\n");
2945 str
+= _T("PlayResY: %d\n");
2946 str
+= _T("Timer: 100.0000\n");
2948 str
+= (et
== EXTSSA
)
2949 ? _T("[V4 Styles]\nFormat: Name, Fontname, Fontsize, PrimaryColour, SecondaryColour, TertiaryColour, BackColour, Bold, Italic, BorderStyle, Outline, Shadow, Alignment, MarginL, MarginR, MarginV, AlphaLevel, Encoding\n")
2950 : _T("[V4+ Styles]\nFormat: Name, Fontname, Fontsize, PrimaryColour, SecondaryColour, OutlineColour, BackColour, Bold, Italic, Underline, StrikeOut, ScaleX, ScaleY, Spacing, Angle, BorderStyle, Outline, Shadow, Alignment, MarginL, MarginR, MarginV, Encoding\n");
2953 str2
.Format(str
, m_dstScreenSize
.cx
, m_dstScreenSize
.cy
);
2954 f
.WriteString(str2
);
2956 str
= (et
== EXTSSA
)
2957 ? _T("Style: %s,%s,%d,&H%06x,&H%06x,&H%06x,&H%06x,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d\n")
2958 : _T("Style: %s,%s,%d,&H%08x,&H%08x,&H%08x,&H%08x,%d,%d,%d,%d,%d,%d,%d,%.2f,%d,%d,%d,%d,%d,%d,%d,%d\n");
2960 POSITION pos
= m_styles
.GetStartPosition();
2965 m_styles
.GetNextAssoc(pos
, key
, s
);
2970 str2
.Format(str
, key
,
2971 s
->fontName
, (int)s
->fontSize
,
2972 s
->colors
[0]&0xffffff,
2973 s
->colors
[1]&0xffffff,
2974 s
->colors
[2]&0xffffff,
2975 s
->colors
[3]&0xffffff,
2976 s
->fontWeight
> FW_NORMAL
? -1 : 0, s
->fItalic
? -1 : 0,
2977 s
->borderStyle
== 0 ? 1 : s
->borderStyle
== 1 ? 3 : 0,
2978 (int)s
->outlineWidthY
, (int)s
->shadowDepthY
,
2979 s
->scrAlignment
<= 3 ? s
->scrAlignment
: s
->scrAlignment
<= 6 ? ((s
->scrAlignment
-3)|8) : s
->scrAlignment
<= 9 ? ((s
->scrAlignment
-6)|4) : 2,
2980 s
->marginRect
.get().left
, s
->marginRect
.get().right
, (s
->marginRect
.get().top
+ s
->marginRect
.get().bottom
) / 2,
2983 f
.WriteString(str2
);
2988 str2
.Format(str
, key
,
2989 s
->fontName
, (int)s
->fontSize
,
2990 (s
->colors
[0]&0xffffff) | (s
->alpha
[0]<<24),
2991 (s
->colors
[1]&0xffffff) | (s
->alpha
[1]<<24),
2992 (s
->colors
[2]&0xffffff) | (s
->alpha
[2]<<24),
2993 (s
->colors
[3]&0xffffff) | (s
->alpha
[3]<<24),
2994 s
->fontWeight
> FW_NORMAL
? -1 : 0,
2995 s
->fItalic
? -1 : 0, s
->fUnderline
? -1 : 0, s
->fStrikeOut
? -1 : 0,
2996 (int)s
->fontScaleX
, (int)s
->fontScaleY
,
2997 (int)s
->fontSpacing
, (float)s
->fontAngleZ
,
2998 s
->borderStyle
== 0 ? 1 : s
->borderStyle
== 1 ? 3 : 0,
2999 (int)s
->outlineWidthY
, (int)s
->shadowDepthY
,
3001 s
->marginRect
.get().left
, s
->marginRect
.get().right
, (s
->marginRect
.get().top
+ s
->marginRect
.get().bottom
) / 2,
3003 f
.WriteString(str2
);
3007 if(m_entries
.GetCount() > 0)
3010 str
+= _T("[Events]\n");
3011 str
+= (et
== EXTSSA
)
3012 ? _T("Format: Marked, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text\n")
3013 : _T("Format: Layer, Start, End, Style, Actor, MarginL, MarginR, MarginV, Effect, Text\n");
3019 et
== EXTSRT
? L
"%d\n%02d:%02d:%02d,%03d --> %02d:%02d:%02d,%03d\n%s\n\n" :
3020 et
== EXTSUB
? L
"{%d}{%d}%s\n" :
3021 et
== EXTSMI
? L
"<SYNC Start=%d><P Class=UNKNOWNCC>\n%s\n<SYNC Start=%d><P Class=UNKNOWNCC> \n" :
3022 et
== EXTPSB
? L
"{%d:%02d:%02d}{%d:%02d:%02d}%s\n" :
3023 et
== EXTSSA
? L
"Dialogue: Marked=0,%d:%02d:%02d.%02d,%d:%02d:%02d.%02d,%s,%s,%04d,%04d,%04d,%s,%s\n" :
3024 et
== EXTASS
? L
"Dialogue: %d,%d:%02d:%02d.%02d,%d:%02d:%02d.%02d,%s,%s,%04d,%04d,%04d,%s,%s\n" :
3028 for(int i
= 0, j
= m_entries
.GetCount(), k
= 0; i
< j
; i
++)
3030 STSEntry
& stse
= m_entries
.GetAt(i
);
3032 int t1
= TranslateStart(i
, fps
);
3033 if(t1
< 0) {k
++; continue;}
3035 int t2
= TranslateEnd(i
, fps
);
3037 int hh1
= (t1
/60/60/1000);
3038 int mm1
= (t1
/60/1000)%60;
3039 int ss1
= (t1
/1000)%60;
3040 int ms1
= (t1
)%1000;
3041 int hh2
= (t2
/60/60/1000);
3042 int mm2
= (t2
/60/1000)%60;
3043 int ss2
= (t2
/1000)%60;
3044 int ms2
= (t2
)%1000;
3046 CStringW str
= f
.IsUnicode()
3047 ? GetStrW(i
, et
== EXTSSA
|| et
== EXTASS
)
3048 : GetStrWA(i
, et
== EXTSSA
|| et
== EXTASS
);
3054 str2
.Format(fmt
, i
-k
+1, hh1
, mm1
, ss1
, ms1
, hh2
, mm2
, ss2
, ms2
, str
);
3056 else if(et
== EXTSUB
)
3058 str
.Replace('\n', '|');
3059 str2
.Format(fmt
, int(t1
*fps
/1000), int(t2
*fps
/1000), str
);
3061 else if(et
== EXTSMI
)
3063 str
.Replace(L
"\n", L
"<br>");
3064 str2
.Format(fmt
, t1
, str
, t2
);
3066 else if(et
== EXTPSB
)
3068 str
.Replace('\n', '|');
3069 str2
.Format(fmt
, hh1
, mm1
, ss1
, hh2
, mm2
, ss2
, str
);
3071 else if(et
== EXTSSA
)
3073 str
.Replace(L
"\n", L
"\\N");
3075 hh1
, mm1
, ss1
, ms1
/10,
3076 hh2
, mm2
, ss2
, ms2
/10,
3077 TToW(stse
.style
), TToW(stse
.actor
),
3078 stse
.marginRect
.left
, stse
.marginRect
.right
, (stse
.marginRect
.top
+ stse
.marginRect
.bottom
) / 2,
3079 TToW(stse
.effect
), str
);
3081 else if(et
== EXTASS
)
3083 str
.Replace(L
"\n", L
"\\N");
3086 hh1
, mm1
, ss1
, ms1
/10,
3087 hh2
, mm2
, ss2
, ms2
/10,
3088 TToW(stse
.style
), TToW(stse
.actor
),
3089 stse
.marginRect
.left
, stse
.marginRect
.right
, (stse
.marginRect
.top
+ stse
.marginRect
.bottom
) / 2,
3090 TToW(stse
.effect
), str
);
3093 f
.WriteString(str2
);
3100 f
.WriteString(_T("</BODY>\n</SAMI>\n"));
3104 if(!m_fUsingAutoGeneratedDefaultStyle
&& m_styles
.Lookup(g_default_style
, s
) && et
!= EXTSSA
&& et
!= EXTASS
)
3107 if(!f
.Save(fn
+ _T(".style"), e
))
3112 str
+= _T("ScriptType: v4.00+\n");
3113 str
+= _T("PlayResX: %d\n");
3114 str
+= _T("PlayResY: %d\n");
3116 str
+= _T("[V4+ Styles]\nFormat: Name, Fontname, Fontsize, PrimaryColour, SecondaryColour, OutlineColour, BackColour, Bold, Italic, Underline, StrikeOut, ScaleX, ScaleY, Spacing, Angle, BorderStyle, Outline, Shadow, Alignment, MarginL, MarginR, MarginV, Encoding\n");
3117 str2
.Format(str
, m_dstScreenSize
.cx
, m_dstScreenSize
.cy
);
3118 f
.WriteString(str2
);
3120 str
= _T("Style: Default,%s,%d,&H%08x,&H%08x,&H%08x,&H%08x,%d,%d,%d,%d,%d,%d,%d,%.2f,%d,%d,%d,%d,%d,%d,%d,%d\n");
3122 s
->fontName
, (int)s
->fontSize
,
3123 (s
->colors
[0]&0xffffff) | (s
->alpha
[0]<<24),
3124 (s
->colors
[1]&0xffffff) | (s
->alpha
[1]<<24),
3125 (s
->colors
[2]&0xffffff) | (s
->alpha
[2]<<24),
3126 (s
->colors
[3]&0xffffff) | (s
->alpha
[3]<<24),
3127 s
->fontWeight
> FW_NORMAL
? -1 : 0,
3128 s
->fItalic
? -1 : 0, s
->fUnderline
? -1 : 0, s
->fStrikeOut
? -1 : 0,
3129 (int)s
->fontScaleX
, (int)s
->fontScaleY
,
3130 (int)s
->fontSpacing
, (float)s
->fontAngleZ
,
3131 s
->borderStyle
== 0 ? 1 : s
->borderStyle
== 1 ? 3 : 0,
3132 (int)s
->outlineWidthY
, (int)s
->shadowDepthY
,
3134 s
->marginRect
.get().left
, s
->marginRect
.get().right
, (s
->marginRect
.get().top
+ s
->marginRect
.get().bottom
) / 2,
3136 f
.WriteString(str2
);
3142 bool CSimpleTextSubtitle::IsEmpty()
3144 return m_entries
.IsEmpty();
3147 void CSimpleTextSubtitle::RemoveAllEntries()
3149 m_entries
.RemoveAll();
3152 ////////////////////////////////////////////////////////////////////
3154 bool STSStyleBase::operator==( const STSStyleBase
& s
) const
3156 return charSet
== s
.charSet
3157 && fontName
== s
.fontName
3158 && fontSize
== s
.fontSize
3159 && fontWeight
== s
.fontWeight
3160 && fItalic
== s
.fItalic
3161 && fUnderline
== s
.fUnderline
3162 && fStrikeOut
== s
.fStrikeOut
;
3165 STSStyle::STSStyle()
3170 void STSStyle::SetDefault()
3172 marginRect
= CRect(20, 20, 20, 20);
3175 outlineWidthX
= outlineWidthY
= 2;
3176 shadowDepthX
= shadowDepthY
= 3;
3177 colors
[0] = 0x00ffffff;
3178 colors
[1] = 0x0000ffff;
3179 colors
[2] = 0x00000000;
3180 colors
[3] = 0x00000000;
3185 charSet
= DEFAULT_CHARSET
;
3186 fontName
= _T("Arial");
3188 fontScaleX
= fontScaleY
= 100;
3190 fontWeight
= FW_BOLD
;
3196 fontShiftX
= fontShiftY
= fontAngleZ
= fontAngleX
= fontAngleY
= 0;
3200 bool STSStyle::operator == (const STSStyle
& s
)const
3202 return(marginRect
== s
.marginRect
3203 && scrAlignment
== s
.scrAlignment
3204 && borderStyle
== s
.borderStyle
3205 && outlineWidthX
== s
.outlineWidthX
3206 && outlineWidthY
== s
.outlineWidthY
3207 && shadowDepthX
== s
.shadowDepthX
3208 && shadowDepthY
== s
.shadowDepthY
3209 && *((int*)&colors
[0]) == *((int*)&s
.colors
[0])
3210 && *((int*)&colors
[1]) == *((int*)&s
.colors
[1])
3211 && *((int*)&colors
[2]) == *((int*)&s
.colors
[2])
3212 && *((int*)&colors
[3]) == *((int*)&s
.colors
[3])
3213 && alpha
[0] == s
.alpha
[0]
3214 && alpha
[1] == s
.alpha
[1]
3215 && alpha
[2] == s
.alpha
[2]
3216 && alpha
[3] == s
.alpha
[3]
3218 && fGaussianBlur
== s
.fGaussianBlur
3219 && relativeTo
== s
.relativeTo
3220 && IsFontStyleEqual(s
));
3223 bool STSStyle::IsFontStyleEqual(const STSStyle
& s
) const
3226 charSet
== s
.charSet
3227 && fontName
== s
.fontName
3228 && fontSize
== s
.fontSize
3229 && fontScaleX
== s
.fontScaleX
3230 && fontScaleY
== s
.fontScaleY
3231 && fontSpacing
== s
.fontSpacing
3232 && fontWeight
== s
.fontWeight
3233 && fItalic
== s
.fItalic
3234 && fUnderline
== s
.fUnderline
3235 && fStrikeOut
== s
.fStrikeOut
3236 && fontAngleZ
== s
.fontAngleZ
3237 && fontAngleX
== s
.fontAngleX
3238 && fontAngleY
== s
.fontAngleY
3239 && fontShiftX
== s
.fontShiftX
3240 && fontShiftY
== s
.fontShiftY
);
3243 void STSStyle::operator = (const LOGFONT
& lf
)
3245 charSet
= lf
.lfCharSet
;
3246 fontName
= lf
.lfFaceName
;
3248 fontSize
= -MulDiv(lf
.lfHeight
, 72, GetDeviceCaps(hDC
, LOGPIXELSY
));
3250 // fontAngleZ = (float)(1.0*lf.lfEscapement/10);
3251 fontWeight
= lf
.lfWeight
;
3252 fItalic
= !!lf
.lfItalic
;
3253 fUnderline
= !!lf
.lfUnderline
;
3254 fStrikeOut
= !!lf
.lfStrikeOut
;
3257 LOGFONTA
& operator <<= (LOGFONTA
& lfa
, const STSStyleBase
& s
)
3259 lfa
.lfCharSet
= s
.charSet
;
3260 strncpy_s(lfa
.lfFaceName
, LF_FACESIZE
, CStringA(s
.fontName
), _TRUNCATE
);
3262 lfa
.lfHeight
= -MulDiv((int)(s
.fontSize
+0.5), GetDeviceCaps(hDC
, LOGPIXELSY
), 72);
3264 lfa
.lfWeight
= s
.fontWeight
;
3265 lfa
.lfItalic
= s
.fItalic
?-1:0;
3266 lfa
.lfUnderline
= s
.fUnderline
?-1:0;
3267 lfa
.lfStrikeOut
= s
.fStrikeOut
?-1:0;
3271 LOGFONTW
& operator <<= (LOGFONTW
& lfw
, const STSStyleBase
& s
)
3273 lfw
.lfCharSet
= s
.charSet
;
3274 wcsncpy_s(lfw
.lfFaceName
, LF_FACESIZE
, CStringW(s
.fontName
), _TRUNCATE
);
3276 lfw
.lfHeight
= -MulDiv((int)(s
.fontSize
+0.5), GetDeviceCaps(hDC
, LOGPIXELSY
), 72);
3278 lfw
.lfWeight
= s
.fontWeight
;
3279 lfw
.lfItalic
= s
.fItalic
?-1:0;
3280 lfw
.lfUnderline
= s
.fUnderline
?-1:0;
3281 lfw
.lfStrikeOut
= s
.fStrikeOut
?-1:0;
3285 CString
& operator <<= (CString
& style
, const STSStyle
& s
)
3287 style
.Format(_T("%d;%d;%d;%d;")
3288 _T("%d;%d;%f;%f;%f;%f;")
3289 _T("0x%06x;0x%06x;0x%06x;0x%06x;")
3290 _T("0x%02x;0x%02x;0x%02x;0x%02x;")
3292 _T("%s;%f;%f;%f;%f;%d;")
3293 _T("%d;%d;%d;%d;%f;")
3296 s
.marginRect
.get().left
, s
.marginRect
.get().right
, s
.marginRect
.get().top
, s
.marginRect
.get().bottom
,
3297 s
.scrAlignment
, s
.borderStyle
,s
.outlineWidthX
, s
.outlineWidthY
, s
.shadowDepthX
, s
.shadowDepthY
,
3298 s
.colors
[0], s
.colors
[1], s
.colors
[2], s
.colors
[3],
3299 s
.alpha
[0], s
.alpha
[1], s
.alpha
[2], s
.alpha
[3],
3301 s
.fontName
,s
.fontSize
,s
.fontScaleX
, s
.fontScaleY
,s
.fontSpacing
,s
.fontWeight
,
3302 (int)s
.fItalic
, (int)s
.fUnderline
, (int)s
.fStrikeOut
, s
.fBlur
, s
.fGaussianBlur
,
3303 s
.fontAngleZ
, s
.fontAngleX
, s
.fontAngleY
,
3309 STSStyle
& operator <<= (STSStyle
& s
, const CString
& style
)
3315 CStringW str
= TToW(style
);
3316 if(str
.Find(';')>=0)
3319 tmp_rect
.left
= GetInt(str
,';'); tmp_rect
.right
= GetInt(str
,';'); tmp_rect
.top
= GetInt(str
,';'); tmp_rect
.bottom
= GetInt(str
,';');
3320 s
.marginRect
= tmp_rect
;
3321 s
.scrAlignment
= GetInt(str
,';'); s
.borderStyle
= GetInt(str
,';');
3322 s
.outlineWidthX
= GetFloat(str
,';'); s
.outlineWidthY
= GetFloat(str
,';'); s
.shadowDepthX
= GetFloat(str
,';'); s
.shadowDepthY
= GetFloat(str
,';');
3323 for(int i
= 0; i
< 4; i
++) s
.colors
[i
] = (COLORREF
)GetInt(str
,';');
3324 for(int i
= 0; i
< 4; i
++) s
.alpha
[i
] = GetInt(str
,';');
3325 s
.charSet
= GetInt(str
,';');
3326 s
.fontName
= WToT(GetStr(str
,';')); s
.fontSize
= GetFloat(str
,';');
3327 s
.fontScaleX
= GetFloat(str
,';'); s
.fontScaleY
= GetFloat(str
,';');
3328 s
.fontSpacing
= GetFloat(str
,';'); s
.fontWeight
= GetInt(str
,';');
3329 s
.fItalic
= !!GetInt(str
,';'); s
.fUnderline
= !!GetInt(str
,';'); s
.fStrikeOut
= !!GetInt(str
,';'); s
.fBlur
= GetInt(str
,';'); s
.fGaussianBlur
= GetFloat(str
,';');
3330 s
.fontAngleZ
= GetFloat(str
,';'); s
.fontAngleX
= GetFloat(str
,';'); s
.fontAngleY
= GetFloat(str
,';');
3331 s
.relativeTo
= GetInt(str
,';');
3342 static bool OpenRealText(CTextFile
* file
, CSimpleTextSubtitle
& ret
, int CharSet
)
3347 while(file
->ReadString(buff
))
3350 if(buff
.IsEmpty()) continue;
3352 szFile
+= CStringW(_T("\n")) + buff
.GetBuffer();
3355 CRealTextParser RealTextParser
;
3356 if (!RealTextParser
.ParseRealText(szFile
))
3359 CRealTextParser::Subtitles crRealText
= RealTextParser
.GetParsedSubtitles();
3361 for (map
<pair
<int, int>, wstring
>::const_iterator i
= crRealText
.m_mapLines
.begin();
3362 i
!= crRealText
.m_mapLines
.end();
3366 SubRipper2SSA(i
->second
.c_str(), CharSet
),
3372 // std::wofstream wofsOut(L"c:/zzz.srt");
3373 // RealTextParser.OutputSRT(wofsOut);
3375 return(!ret
.IsEmpty());