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
== L
"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
== L
"fontname")
1590 else if(entry
== L
"ycbcr matrix")
1592 buff
= GetStr(buff
);
1596 ret
.m_eYCbCrMatrix
= CSimpleTextSubtitle::YCbCrMatrix_AUTO
;
1597 ret
.m_eYCbCrRange
= CSimpleTextSubtitle::YCbCrRange_AUTO
;
1599 else if (buff
=="tv.601")
1601 ret
.m_eYCbCrMatrix
= CSimpleTextSubtitle::YCbCrMatrix_BT601
;
1602 ret
.m_eYCbCrRange
= CSimpleTextSubtitle::YCbCrRange_TV
;
1604 else if (buff
=="tv.709")
1606 ret
.m_eYCbCrMatrix
= CSimpleTextSubtitle::YCbCrMatrix_BT709
;
1607 ret
.m_eYCbCrRange
= CSimpleTextSubtitle::YCbCrRange_TV
;
1609 else if (buff
=="pc.601")
1611 ret
.m_eYCbCrMatrix
= CSimpleTextSubtitle::YCbCrMatrix_BT601
;
1612 ret
.m_eYCbCrRange
= CSimpleTextSubtitle::YCbCrRange_PC
;
1614 else if (buff
=="pc.709")
1616 ret
.m_eYCbCrMatrix
= CSimpleTextSubtitle::YCbCrMatrix_BT709
;
1617 ret
.m_eYCbCrRange
= CSimpleTextSubtitle::YCbCrRange_PC
;
1625 static bool OpenXombieSub(CTextFile
* file
, CSimpleTextSubtitle
& ret
, int CharSet
)
1629 // CMapStringToPtr stylemap;
1632 while(file
->ReadString(buff
))
1635 if(buff
.IsEmpty() || buff
.GetAt(0) == ';') continue;
1640 entry
= GetStr(buff
, '=');
1642 // catch(...) {continue;}
1646 if(entry
== L
"version")
1648 version
= (float)GetFloat(buff
);
1650 else if(entry
== L
"screenhorizontal")
1652 try {ret
.m_dstScreenSize
.cx
= GetInt(buff
);}
1653 catch(...) {ret
.m_dstScreenSize
= CSize(0, 0); return(false);}
1655 if(ret
.m_dstScreenSize
.cy
<= 0)
1657 ret
.m_dstScreenSize
.cy
= (ret
.m_dstScreenSize
.cx
== 1280)
1659 : ret
.m_dstScreenSize
.cx
* 3 / 4;
1662 else if(entry
== L
"screenvertical")
1664 try {ret
.m_dstScreenSize
.cy
= GetInt(buff
);}
1665 catch(...) {ret
.m_dstScreenSize
= CSize(0, 0); return(false);}
1667 if(ret
.m_dstScreenSize
.cx
<= 0)
1669 ret
.m_dstScreenSize
.cx
= (ret
.m_dstScreenSize
.cy
== 1024)
1671 : ret
.m_dstScreenSize
.cy
* 4 / 3;
1674 else if(entry
== L
"style")
1676 STSStyle
* style
= new STSStyle
;
1677 if(!style
) return(false);
1684 StyleName
= WToT(GetStr(buff
)) + _T("_") + WToT(GetStr(buff
));
1685 style
->fontName
= WToT(GetStr(buff
));
1686 style
->fontSize
= GetFloat(buff
);
1687 for(int i
= 0; i
< 4; i
++) style
->colors
[i
] = (COLORREF
)GetInt(buff
);
1688 for(int i
= 0; i
< 4; i
++) style
->alpha
[i
] = GetInt(buff
);
1689 style
->fontWeight
= !!GetInt(buff
) ? FW_BOLD
: FW_NORMAL
;
1690 style
->fItalic
= !!GetInt(buff
);
1691 style
->fUnderline
= !!GetInt(buff
);
1692 style
->fStrikeOut
= !!GetInt(buff
);
1693 style
->fBlur
= !!GetInt(buff
);
1694 style
->fontScaleX
= GetFloat(buff
);
1695 style
->fontScaleY
= GetFloat(buff
);
1696 style
->fontSpacing
= GetFloat(buff
);
1697 style
->fontAngleX
= GetFloat(buff
);
1698 style
->fontAngleY
= GetFloat(buff
);
1699 style
->fontAngleZ
= GetFloat(buff
);
1700 style
->borderStyle
= GetInt(buff
);
1701 style
->outlineWidthX
= style
->outlineWidthY
= GetFloat(buff
);
1702 style
->shadowDepthX
= style
->shadowDepthY
= GetFloat(buff
);
1703 style
->scrAlignment
= GetInt(buff
);
1705 tmp_rect
.left
= GetInt(buff
);
1706 tmp_rect
.right
= GetInt(buff
);
1707 tmp_rect
.top
= tmp_rect
.bottom
= GetInt(buff
);
1708 style
->marginRect
= tmp_rect
;
1710 style
->charSet
= GetInt(buff
);
1712 style
->fontScaleX
= max(style
->fontScaleX
, 0);
1713 style
->fontScaleY
= max(style
->fontScaleY
, 0);
1714 style
->fontSpacing
= max(style
->fontSpacing
, 0);
1715 style
->borderStyle
= style
->borderStyle
== 1 ? 0 : style
->borderStyle
== 3 ? 1 : 0;
1716 style
->outlineWidthX
= max(style
->outlineWidthX
, 0);
1717 style
->outlineWidthY
= max(style
->outlineWidthY
, 0);
1718 style
->shadowDepthX
= max(style
->shadowDepthX
, 0);
1719 style
->shadowDepthY
= max(style
->shadowDepthY
, 0);
1721 ret
.AddStyle(StyleName
, style
);
1729 else if(entry
== L
"line")
1734 int hh1
, mm1
, ss1
, ms1
, hh2
, mm2
, ss2
, ms2
, layer
= 0;
1735 CString Style
, Actor
;
1738 if(GetStr(buff
) != L
"D") continue;
1740 layer
= GetInt(buff
);
1741 hh1
= GetInt(buff
, ':');
1742 mm1
= GetInt(buff
, ':');
1743 ss1
= GetInt(buff
, '.');
1745 hh2
= GetInt(buff
, ':');
1746 mm2
= GetInt(buff
, ':');
1747 ss2
= GetInt(buff
, '.');
1749 Style
= WToT(GetStr(buff
)) + _T("_") + WToT(GetStr(buff
));
1750 Actor
= WToT(GetStr(buff
));
1751 marginRect
.left
= GetInt(buff
);
1752 marginRect
.right
= GetInt(buff
);
1753 marginRect
.top
= marginRect
.bottom
= GetInt(buff
);
1755 Style
.TrimLeft('*');
1756 if(!Style
.CompareNoCase(_T("Default"))) Style
= _T("Default");
1760 (((hh1
*60 + mm1
)*60) + ss1
)*1000 + ms1
,
1761 (((hh2
*60 + mm2
)*60) + ss2
)*1000 + ms2
,
1762 Style
, Actor
, _T(""),
1771 else if(entry
== L
"fontname")
1777 return(!ret
.IsEmpty());
1780 #include "USFSubtitles.h"
1782 static bool OpenUSF(CTextFile
* file
, CSimpleTextSubtitle
& ret
, int CharSet
)
1785 while(file
->ReadString(str
))
1787 if(str
.Find(_T("USFSubtitles")) >= 0)
1790 if(usf
.Read(file
->GetFilePath()) && usf
.ConvertToSTS(ret
))
1800 static CStringW
MPL22SSA(CStringW str
)
1802 CAtlList
<CStringW
> sl
;
1803 Explode(str
, sl
, '|');
1804 POSITION pos
= sl
.GetHeadPosition();
1807 CStringW
& s
= sl
.GetNext(pos
);
1808 if(s
[0] == '/') {s
= L
"{\\i1}" + s
.Mid(1) + L
"{\\i0}";}
1810 str
= Implode(sl
, '\n');
1811 str
.Replace(L
"\n", L
"\\N");
1815 static bool OpenMPL2(CTextFile
* file
, CSimpleTextSubtitle
& ret
, int CharSet
)
1818 while(file
->ReadString(buff
))
1821 if(buff
.IsEmpty()) continue;
1824 int c
= swscanf(buff
, L
"[%d][%d]", &start
, &end
);
1829 MPL22SSA(buff
.Mid(buff
.Find(']', buff
.Find(']')+1)+1)),
1831 start
*100, end
*100);
1833 else if(c
!= EOF
) // might be another format
1839 return(!ret
.IsEmpty());
1842 typedef bool (*STSOpenFunct
)(CTextFile
* file
, CSimpleTextSubtitle
& ret
, int CharSet
);
1844 static bool OpenRealText(CTextFile
* file
, CSimpleTextSubtitle
& ret
, int CharSet
);
1846 typedef struct {STSOpenFunct open
; tmode mode
;} OpenFunctStruct
;
1848 static OpenFunctStruct OpenFuncts
[] =
1850 OpenSubStationAlpha
, TIME
,
1851 OpenSubRipper
, TIME
,
1852 OpenOldSubRipper
, TIME
,
1853 OpenSubViewer
, TIME
,
1854 OpenMicroDVD
, FRAME
,
1857 OpenXombieSub
, TIME
,
1863 static int nOpenFuncts
= countof(OpenFuncts
);
1867 CSimpleTextSubtitle::CSimpleTextSubtitle()
1870 m_dstScreenSize
= CSize(0, 0);
1871 m_defaultWrapStyle
= 0;
1873 m_fScaledBAS
= false;
1874 m_encoding
= CTextFile::ASCII
;
1875 m_ePARCompensationType
= EPCTDisabled
;
1876 m_dPARCompensation
= 1.0;
1877 m_eYCbCrMatrix
= YCbCrMatrix_BT601
;
1878 m_eYCbCrRange
= YCbCrRange_TV
;
1881 CSimpleTextSubtitle::~CSimpleTextSubtitle()
1886 CSimpleTextSubtitle::CSimpleTextSubtitle(CSimpleTextSubtitle& sts)
1891 CSimpleTextSubtitle& CSimpleTextSubtitle::operator = (CSimpleTextSubtitle& sts)
1895 m_name = sts.m_name;
1896 m_mode = sts.m_mode;
1897 m_dstScreenSize = sts.m_dstScreenSize;
1898 m_defaultWrapStyle = sts.m_defaultWrapStyle;
1899 m_collisions = sts.m_collisions;
1900 m_fScaledBAS = sts.m_fScaledBAS;
1901 m_fSSA = sts.m_fSSA;
1902 m_fUsingAutoGeneratedDefaultStyle = sts.m_fUsingAutoGeneratedDefaultStyle;
1903 CopyStyles(sts.m_styles);
1904 m_segments.Copy(sts.m_segments);
1911 void CSimpleTextSubtitle::Copy(CSimpleTextSubtitle
& sts
)
1915 m_name
= sts
.m_name
;
1916 m_mode
= sts
.m_mode
;
1917 m_dstScreenSize
= sts
.m_dstScreenSize
;
1918 m_defaultWrapStyle
= sts
.m_defaultWrapStyle
;
1919 m_collisions
= sts
.m_collisions
;
1920 m_fScaledBAS
= sts
.m_fScaledBAS
;
1921 m_encoding
= sts
.m_encoding
;
1922 m_fUsingAutoGeneratedDefaultStyle
= sts
.m_fUsingAutoGeneratedDefaultStyle
;
1923 CopyStyles(sts
.m_styles
);
1924 m_segments
.Copy(sts
.m_segments
);
1925 m_entries
.Copy(sts
.m_entries
);
1928 void CSimpleTextSubtitle::Append(CSimpleTextSubtitle
& sts
, int timeoff
)
1932 timeoff
= m_entries
.GetCount() > 0 ? m_entries
.GetAt(m_entries
.GetCount()-1).end
: 0;
1935 for(int i
= 0, j
= m_entries
.GetCount(); i
< j
; i
++)
1937 if(m_entries
.GetAt(i
).start
> timeoff
)
1939 m_entries
.RemoveAt(i
, j
- i
);
1944 CopyStyles(sts
.m_styles
, true);
1946 for(int i
= 0, j
= sts
.m_entries
.GetCount(); i
< j
; i
++)
1948 STSEntry stse
= sts
.m_entries
.GetAt(i
);
1949 stse
.start
+= timeoff
;
1950 stse
.end
+= timeoff
;
1951 stse
.readorder
+= m_entries
.GetCount();
1952 m_entries
.Add(stse
);
1958 void CSTSStyleMap::Free()
1960 POSITION pos
= GetStartPosition();
1965 GetNextAssoc(pos
, key
, val
);
1972 bool CSimpleTextSubtitle::CopyStyles(const CSTSStyleMap
& styles
, bool fAppend
)
1974 if(!fAppend
) m_styles
.Free();
1976 POSITION pos
= styles
.GetStartPosition();
1981 styles
.GetNextAssoc(pos
, key
, val
);
1983 STSStyle
* s
= new STSStyle
;
1984 if(!s
) return(false);
1994 void CSimpleTextSubtitle::Empty()
1996 m_dstScreenSize
= CSize(0, 0);
1998 m_segments
.RemoveAll();
1999 m_entries
.RemoveAll();
2002 void CSimpleTextSubtitle::Add(CStringW str
, bool fUnicode
, int start
, int end
,
2003 CString style
, const CString
& actor
, const CString
& effect
, const CRect
& marginRect
, int layer
, int readorder
)
2005 XY_LOG_INFO(start
<<_T(" ")<<end
<<_T(" ")<<str
.GetString()<<_T(" style:")<<style
.GetString()
2006 <<_T(" Unicode:")<<fUnicode
2007 <<_T(" actor:")<<actor
.GetString()<<_T(" effect:")<<effect
.GetString()
2008 <<_T(" (l:")<<marginRect
.left
<<_T(",t:")<<marginRect
.top
<<_T(",r:")<<marginRect
.right
<<_T(",b:")<<marginRect
.bottom
2009 <<_T(" layer:")<<layer
<<_T(" readorder:")<<readorder
2010 <<_T(" entries:")<<m_entries
.GetCount()<<_T(" seg:")<<m_segments
.GetCount());
2012 if(start
> end
|| str
.Trim().IsEmpty() ) return;
2015 str
.Replace(L
"\n", L
"\\N");
2016 if(style
.IsEmpty()) style
= g_default_style
;
2017 else if(style
!=g_default_style
)
2019 style
.TrimLeft('*');
2024 sub
.fUnicode
= fUnicode
;
2027 sub
.effect
= effect
;
2028 sub
.marginRect
= marginRect
;
2032 sub
.readorder
= readorder
< 0 ? m_entries
.GetCount() : readorder
;
2033 int n
= m_entries
.Add(sub
);
2035 int len
= m_segments
.GetCount();
2039 STSSegment
stss(start
, end
);
2041 m_segments
.Add(stss
);
2043 else if(end
<= m_segments
[0].start
)
2045 STSSegment
stss(start
, end
);
2047 m_segments
.InsertAt(0, stss
);
2049 else if(start
>= m_segments
[len
-1].end
)
2051 STSSegment
stss(start
, end
);
2053 m_segments
.Add(stss
);
2057 if(start
< m_segments
[0].start
)
2059 STSSegment
stss(start
, m_segments
[0].start
);
2061 start
= m_segments
[0].start
;
2062 m_segments
.InsertAt(0, stss
);
2065 for(size_t i
= 0; i
< m_segments
.GetCount(); i
++)
2067 STSSegment
& s
= m_segments
[i
];
2073 else if(end
<= s
.start
)
2077 else if(s
.start
< start
&& start
< s
.end
)
2079 STSSegment
stss(s
.start
, start
);
2080 stss
.subs
.Copy(s
.subs
);
2082 m_segments
.InsertAt(i
, stss
);
2085 if(start
<= s
.start
&& s
.end
<= end
)
2087 for(int j
= 0, k
= s
.subs
.GetCount(); j
<= k
; j
++)
2089 if(j
== k
|| sub
.readorder
< m_entries
.GetAt(s
.subs
[j
]).readorder
)
2091 s
.subs
.InsertAt(j
, n
);
2096 else if(s
.start
< end
&& end
< s
.end
)
2098 STSSegment
stss(s
.start
, end
);
2099 stss
.subs
.Copy(s
.subs
);
2100 for(int j
= 0, k
= s
.subs
.GetCount(); j
<= k
; j
++)
2102 if(j
== k
|| sub
.readorder
< m_entries
.GetAt(stss
.subs
[j
]).readorder
)
2104 stss
.subs
.InsertAt(j
, n
);
2109 m_segments
.InsertAt(i
, stss
);
2113 if(end
> m_segments
[m_segments
.GetCount()-1].end
)
2115 STSSegment
stss(m_segments
[m_segments
.GetCount()-1].end
, end
);
2117 m_segments
.Add(stss
);
2122 str.Replace(L"\n", L"\\N");
2123 if(style.IsEmpty()) style = _T("Default");
2125 int j = m_segments.GetCount();
2126 for(int i = j-1; i >= 0; i--)
2128 if(m_segments[i].end <= start)
2132 else if(m_segments[i].start >= start)
2134 m_segments.SetCount(m_segments.GetCount()-1);
2137 else if(m_segments[i].end > start)
2139 if(i < j-1) m_segments.RemoveAt(i+1, j-i-1);
2140 m_segments[i].end = start;
2145 if(m_segments.GetCount() == 0 && j > 0)
2146 CSTSArray::RemoveAll();
2148 STSSegment stss(start, end);
2149 int len = m_entries.GetCount();
2151 m_segments.Add(stss);
2155 sub.fUnicode = fUnicode;
2158 sub.effect = effect;
2159 sub.marginRect = marginRect;
2163 sub.readorder = m_entries.GetCount();
2164 CSTSArray::Add(sub);
2168 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*/ )
2170 if(str
.Trim().IsEmpty() || start
> end
) return;
2173 str
.Replace(L
"\n", L
"\\N");
2174 if(style
.IsEmpty()) style
= _T("Default");
2175 style
.TrimLeft('*');
2179 sub
.fUnicode
= fUnicode
;
2182 sub
.effect
= effect
;
2183 sub
.marginRect
= marginRect
;
2187 sub
.readorder
= readorder
< 0 ? m_entries
.GetCount() : readorder
;
2192 STSStyle
* CSimpleTextSubtitle::CreateDefaultStyle(int CharSet
)
2194 STSStyle
* ret
= NULL
;
2196 if(!m_styles
.Lookup(g_default_style
, ret
))
2198 STSStyle
* style
= new STSStyle();
2199 style
->charSet
= CharSet
;
2200 AddStyle(g_default_style
, style
);
2201 m_styles
.Lookup(g_default_style
, ret
);
2203 m_fUsingAutoGeneratedDefaultStyle
= true;
2207 m_fUsingAutoGeneratedDefaultStyle
= false;
2213 void CSimpleTextSubtitle::ChangeUnknownStylesToDefault()
2215 CAtlMap
<CString
, STSStyle
*, CStringElementTraits
<CString
> > unknown
;
2216 bool fReport
= true;
2218 for(size_t i
= 0; i
< m_entries
.GetCount(); i
++)
2220 STSEntry
& stse
= m_entries
.GetAt(i
);
2223 if(!m_styles
.Lookup(stse
.style
, val
))
2225 if(!unknown
.Lookup(stse
.style
, val
))
2230 msg
.Format(_T("Unknown style found: \"%s\", changed to \"Default\"!\n\nPress Cancel to ignore further warnings."), stse
.style
);
2231 if(MessageBox(NULL
, msg
, _T("Warning"), MB_OKCANCEL
|MB_ICONWARNING
) != IDOK
) fReport
= false;
2234 unknown
[stse
.style
] = NULL
;
2237 stse
.style
= g_default_style
;
2242 void CSimpleTextSubtitle::AddStyle(CString name
, STSStyle
* style
)
2246 if(name
.IsEmpty()) name
= g_default_style
;
2249 if(m_styles
.Lookup(name
, val
))
2256 const CString
& name_str
= name
;
2258 int len
= name_str
.GetLength();
2260 for(i
= len
; i
> 0 && _istdigit(name_str
[i
-1]); i
--);
2264 CString name2
= name_str
;
2266 if(i
< len
&& _stscanf(name_str
.Right(len
-i
), _T("%d"), &idx
) == 1)
2268 name2
= name_str
.Left(i
);
2277 name3_str
.Format(_T("%s%d"), name2
, idx
);
2281 while(m_styles
.Lookup(name3
));
2283 m_styles
.RemoveKey(name
);
2284 m_styles
[name3
] = val
;
2286 for(i
= 0, j
= m_entries
.GetCount(); i
< j
; i
++)
2288 STSEntry
& stse
= m_entries
.GetAt(i
);
2289 if(stse
.style
== name
) stse
.style
= name3
;
2293 m_styles
[name
] = style
;
2296 bool CSimpleTextSubtitle::SetDefaultStyle(STSStyle
& s
)
2298 DbgLog((LOG_TRACE
, 3, "%s(%d): %s", __FILE__
, __LINE__
, __FUNCTION__
));
2299 DbgLog((LOG_TRACE
, 3, "\tm_styles count:%d", m_styles
.GetCount()));
2301 if(!m_styles
.Lookup(g_default_style
, val
)) return false;
2302 DbgLog((LOG_TRACE
, 3, "\tm_styles Lookup Default succeed"));
2305 for(POSITION pos
=m_styles
.GetStartPosition(); pos
!=NULL
;)
2307 DbgLog((LOG_TRACE
, 3, _T("\tm_styles[%s]"), (LPCTSTR
)m_styles
.GetNextKey(pos
)));
2312 m_fUsingAutoGeneratedDefaultStyle
= false;
2316 bool CSimpleTextSubtitle::GetDefaultStyle(STSStyle
& s
)
2319 if(!m_styles
.Lookup(g_default_style
, val
)) return false;
2324 void CSimpleTextSubtitle::ConvertToTimeBased(double fps
)
2326 if(m_mode
== TIME
) return;
2328 for(int i
= 0, j
= m_entries
.GetCount(); i
< j
; i
++)
2330 STSEntry
& stse
= m_entries
[i
];
2331 stse
.start
= int(1.0 * stse
.start
* 1000 / fps
+ 0.5);
2332 stse
.end
= int(1.0 * stse
.end
* 1000 / fps
+ 0.5);
2340 void CSimpleTextSubtitle::ConvertToFrameBased(double fps
)
2342 if(m_mode
== FRAME
) 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
* fps
/ 1000 + 0.5);
2348 stse
.end
= int(1.0 * stse
.end
* fps
/ 1000 + 0.5);
2356 int CSimpleTextSubtitle::SearchSub(int t
, double fps
)
2358 int i
= 0, j
= m_entries
.GetCount() - 1, ret
= -1;
2360 if(j
>= 0 && t
>= TranslateStart(j
, fps
))
2367 int mid
= (i
+ j
) >> 1;
2369 int midt
= TranslateStart(mid
, fps
);
2373 while(mid
> 0 && t
== TranslateStart(mid
-1, fps
)) mid
--;
2394 const STSSegment
* CSimpleTextSubtitle::SearchSubs(int t
, double fps
, /*[out]*/ int* iSegment
, int* nSegments
)
2396 int segmentsCount
= m_segments
.GetCount();
2397 int i
= 0, j
= segmentsCount
- 1;
2399 if(nSegments
) *nSegments
= segmentsCount
;
2400 if(segmentsCount
<=0)
2407 if(t
>= TranslateSegmentEnd(j
, fps
))
2412 if(t
< TranslateSegmentEnd(i
, fps
))
2420 int mid
= (i
+ j
) >> 1;
2422 int midt
= TranslateSegmentEnd(mid
, fps
);
2433 return &m_segments
[j
];
2438 STSSegment
* CSimpleTextSubtitle::SearchSubs2(int t
, double fps
, /*[out]*/ int* iSegment
, int* nSegments
)
2440 int segmentsCount
= m_segments
.GetCount();
2441 int i
= 0, j
= segmentsCount
- 1;
2443 if(iSegment
) *iSegment
= -1;
2444 if(nSegments
) *nSegments
= segmentsCount
;
2446 if(segmentsCount
<=0)
2448 if(iSegment
) *iSegment
= 0;
2452 if(t
>= TranslateSegmentEnd(j
, fps
))
2457 if(t
< TranslateSegmentEnd(i
, fps
))
2465 int mid
= (i
+ j
) >> 1;
2467 int midt
= TranslateSegmentEnd(mid
, fps
);
2474 if(j
<segmentsCount
&& t
>=TranslateSegmentStart(j
, fps
))
2476 if(iSegment
) *iSegment
= j
;
2477 return &m_segments
[j
];
2484 int CSimpleTextSubtitle::TranslateStart(int i
, double fps
)
2486 return(i
< 0 || m_entries
.GetCount() <= i
? -1 :
2487 m_mode
== TIME
? m_entries
.GetAt(i
).start
:
2488 m_mode
== FRAME
? (int)(m_entries
.GetAt(i
).start
*1000/fps
) :
2492 int CSimpleTextSubtitle::TranslateEnd(int i
, double fps
)
2494 return(i
< 0 || m_entries
.GetCount() <= i
? -1 :
2495 m_mode
== TIME
? m_entries
.GetAt(i
).end
:
2496 m_mode
== FRAME
? (int)(m_entries
.GetAt(i
).end
*1000/fps
) :
2500 int CSimpleTextSubtitle::TranslateSegmentStart(int i
, double fps
)
2502 return(i
< 0 || m_segments
.GetCount() <= i
? -1 :
2503 m_mode
== TIME
? m_segments
[i
].start
:
2504 m_mode
== FRAME
? (int)(m_segments
[i
].start
*1000/fps
) :
2508 int CSimpleTextSubtitle::TranslateSegmentEnd(int i
, double fps
)
2510 return(i
< 0 || m_segments
.GetCount() <= i
? -1 :
2511 m_mode
== TIME
? m_segments
[i
].end
:
2512 m_mode
== FRAME
? (int)(m_segments
[i
].end
*1000/fps
) :
2516 void CSimpleTextSubtitle::TranslateSegmentStartEnd(int i
, double fps
, /*out*/int& start
, /*out*/int& end
)
2518 if(i
< 0 || m_segments
.GetCount() <= i
)
2527 start
= m_segments
[i
].start
;
2528 end
= m_segments
[i
].end
;
2530 else //m_mode == FRAME
2532 start
= (int)(m_segments
[i
].start
*1000/fps
);
2533 end
= (int)(m_segments
[i
].end
*1000/fps
);
2538 STSStyle
* CSimpleTextSubtitle::GetStyle(int i
)
2540 STSStyle
* style
= NULL
;
2541 m_styles
.Lookup(m_entries
.GetAt(i
).style
, style
);
2543 STSStyle
* defstyle
= NULL
;
2544 m_styles
.Lookup(g_default_style
, defstyle
);
2556 bool CSimpleTextSubtitle::GetStyle(int i
, STSStyle
* const stss
)
2558 STSStyle
* style
= NULL
;
2559 m_styles
.Lookup(m_entries
.GetAt(i
).style
, style
);
2561 STSStyle
* defstyle
= NULL
;
2562 m_styles
.Lookup(g_default_style
, defstyle
);
2568 defstyle
= CreateDefaultStyle(DEFAULT_CHARSET
);
2574 if(!style
) {ASSERT(0); return false;}
2577 if(stss
->relativeTo
== 2 && defstyle
)
2578 stss
->relativeTo
= defstyle
->relativeTo
;
2583 int CSimpleTextSubtitle::GetCharSet(int i
)
2585 STSStyle
* style
= GetStyle(i
);
2586 return style
!=NULL
? style
->charSet
: -1;
2589 bool CSimpleTextSubtitle::IsEntryUnicode(int i
)
2591 return(m_entries
.GetAt(i
).fUnicode
);
2594 void CSimpleTextSubtitle::ConvertUnicode(int i
, bool fUnicode
)
2596 STSEntry
& stse
= m_entries
.GetAt(i
);
2598 if(stse
.fUnicode
^ fUnicode
)
2600 int CharSet
= GetCharSet(i
);
2603 ? MBCSSSAToUnicode(stse
.str
, CharSet
)
2604 : UnicodeSSAToMBCS(stse
.str
, CharSet
);
2606 stse
.fUnicode
= fUnicode
;
2610 CStringA
CSimpleTextSubtitle::GetStrA(int i
, bool fSSA
)
2612 return(WToA(GetStrWA(i
, fSSA
)));
2615 CStringW
CSimpleTextSubtitle::GetStrW(int i
, bool fSSA
)
2617 bool fUnicode
= IsEntryUnicode(i
);
2618 int CharSet
= GetCharSet(i
);
2620 CStringW str
= m_entries
.GetAt(i
).str
;
2623 str
= MBCSSSAToUnicode(str
, CharSet
);
2626 str
= RemoveSSATags(str
, fUnicode
, CharSet
);
2631 CStringW
CSimpleTextSubtitle::GetStrWA(int i
, bool fSSA
)
2633 bool fUnicode
= IsEntryUnicode(i
);
2634 int CharSet
= GetCharSet(i
);
2636 CStringW str
= m_entries
.GetAt(i
).str
;
2639 str
= UnicodeSSAToMBCS(str
, CharSet
);
2642 str
= RemoveSSATags(str
, fUnicode
, CharSet
);
2647 void CSimpleTextSubtitle::SetStr(int i
, CStringA str
, bool fUnicode
)
2649 SetStr(i
, AToW(str
), false);
2652 void CSimpleTextSubtitle::SetStr(int i
, CStringW str
, bool fUnicode
)
2654 STSEntry
& stse
= m_entries
.GetAt(i
);
2656 str
.Replace(L
"\n", L
"\\N");
2658 if(stse
.fUnicode
&& !fUnicode
) stse
.str
= MBCSSSAToUnicode(str
, GetCharSet(i
));
2659 else if(!stse
.fUnicode
&& fUnicode
) stse
.str
= UnicodeSSAToMBCS(str
, GetCharSet(i
));
2660 else stse
.str
= str
;
2663 static int comp1(const void* a
, const void* b
)
2665 int ret
= ((STSEntry
*)a
)->start
- ((STSEntry
*)b
)->start
;
2666 if(ret
== 0) ret
= ((STSEntry
*)a
)->layer
- ((STSEntry
*)b
)->layer
;
2667 if(ret
== 0) ret
= ((STSEntry
*)a
)->readorder
- ((STSEntry
*)b
)->readorder
;
2671 static int comp2(const void* a
, const void* b
)
2673 return(((STSEntry
*)a
)->readorder
- ((STSEntry
*)b
)->readorder
);
2676 void CSimpleTextSubtitle::Sort(bool fRestoreReadorder
)
2678 qsort(m_entries
.GetData(), m_entries
.GetCount(), sizeof(STSEntry
), !fRestoreReadorder
? comp1
: comp2
);
2682 static int intcomp(const void* i1
, const void* i2
)
2684 return(*((int*)i1
) - *((int*)i2
));
2687 void CSimpleTextSubtitle::CreateSegments()
2689 m_segments
.RemoveAll();
2691 if(m_entries
.GetCount()>0)
2693 size_t start
, mid
, end
;
2694 CAtlArray
<STSSegment
> tempSegments
;//if add to m_segments directly, then remove empty entities can be a
2695 //complex operation when having large segmentCount and lots of empty entities
2696 std::vector
<int> breakpoints(2*m_entries
.GetCount());
2697 for(size_t i
= 0; i
< m_entries
.GetCount(); i
++)
2699 STSEntry
& stse
= m_entries
.GetAt(i
);
2700 breakpoints
[2*i
]=stse
.start
;
2701 breakpoints
[2*i
+1]=stse
.end
;
2704 std::sort(breakpoints
.begin(), breakpoints
.end());
2706 int ptr
= 1, prev
= breakpoints
[0];
2707 for(size_t i
= breakpoints
.size()-1; i
> 0; i
--, ptr
++)
2709 if(breakpoints
[ptr
] != prev
)
2711 tempSegments
.Add(STSSegment(prev
, breakpoints
[ptr
]));
2712 prev
= breakpoints
[ptr
];
2716 size_t segmentCount
= tempSegments
.GetCount();
2718 for(size_t i
= 0; i
< m_entries
.GetCount(); i
++)
2720 STSEntry
& stse
= m_entries
.GetAt(i
);
2725 mid
= (start
+end
)>>1;
2726 if(tempSegments
[mid
].start
< stse
.start
)
2735 for(; start
< tempSegments
.GetCount() && tempSegments
[start
].end
<= stse
.end
; start
++)
2736 tempSegments
[start
].subs
.Add(i
);
2738 for(size_t i
= 0; i
< segmentCount
; i
++)
2739 if(tempSegments
[i
].subs
.GetCount()>0)
2740 m_segments
.Add(tempSegments
[i
]);
2744 for(i = 0, j = m_segments.GetCount(); i < j; i++)
2746 STSSegment& stss = m_segments[i];
2748 TRACE(_T("%d - %d"), stss.start, stss.end);
2750 for(int k = 0, l = stss.subs.GetCount(); k < l; k++)
2752 TRACE(_T(", %d"), stss.subs[k]);
2760 bool CSimpleTextSubtitle::Open(CString fn
, int CharSet
, CString name
)
2764 CWebTextFile
f(CTextFile::UTF8
);
2765 if(!f
.Open(fn
)) return(false);
2767 fn
.Replace('\\', '/');
2770 name
= fn
.Left(fn
.ReverseFind('.'));
2771 name
= name
.Mid(name
.ReverseFind('/')+1);
2772 name
= name
.Mid(name
.ReverseFind('.')+1);
2775 return(Open(&f
, CharSet
, name
));
2778 static int CountLines(CTextFile
* f
, ULONGLONG from
, ULONGLONG to
)
2783 while(f
->ReadString(s
) && f
->GetPosition() < to
) n
++;
2787 bool CSimpleTextSubtitle::Open(CTextFile
* f
, int CharSet
, CString name
)
2791 ULONGLONG pos
= f
->GetPosition();
2793 for(int i
= 0; i
< nOpenFuncts
; i
++)
2795 const TCHAR
* func_name
[]={
2796 TEXT("OpenSubStationAlpha"),
2797 TEXT("OpenSubRipper"),
2798 TEXT("OpenOldSubRipper"),
2799 TEXT("OpenSubViewer"),
2800 TEXT("OpenMicroDVD"),
2802 TEXT("OpenVPlayer"),
2803 TEXT("OpenXombieSub"),
2806 TEXT("OpenRealText")};
2807 CAutoTiming
t(func_name
[i
],0);
2809 if(!OpenFuncts
[i
].open(f
, *this, CharSet
) /*|| !GetCount()*/)
2811 if(m_entries
.GetCount() > 0)
2813 int n
= CountLines(f
, pos
, f
->GetPosition());
2815 s
.Format(_T("Syntax error at line %d!\t"), n
+1);
2816 AfxMessageBox(s
, MB_OK
|MB_ICONERROR
);
2827 m_mode
= OpenFuncts
[i
].mode
;
2828 m_encoding
= f
->GetEncoding();
2829 m_path
= f
->GetFilePath();
2831 CWebTextFile
f2(CTextFile::UTF8
);
2832 if(f2
.Open(f
->GetFilePath() + _T(".style")))
2833 OpenSubStationAlpha(&f2
, *this, CharSet
);
2838 CreateDefaultStyle(CharSet
);
2840 ChangeUnknownStylesToDefault();
2842 if(m_dstScreenSize
== CSize(0, 0)) m_dstScreenSize
= CSize(384, 288);
2850 bool CSimpleTextSubtitle::Open(BYTE
* data
, int len
, int CharSet
, CString name
)
2852 TCHAR path
[MAX_PATH
];
2853 if(!GetTempPath(MAX_PATH
, path
)) return(false);
2856 if(!GetTempFileName(path
, _T("vs"), 0, fn
)) return(false);
2858 FILE* tmp
= _tfopen(fn
, _T("wb"));
2859 if(!tmp
) return(false);
2862 for(; i
<= (len
-1024); i
+= 1024) fwrite(&data
[i
], 1024, 1, tmp
);
2863 if(len
> i
) fwrite(&data
[i
], len
- i
, 1, tmp
);
2867 bool fRet
= Open(fn
, CharSet
, name
);
2874 bool CSimpleTextSubtitle::SaveAs(CString fn
, exttype et
, double fps
, CTextFile::enc e
)
2876 if(fn
.Mid(fn
.ReverseFind('.')+1).CompareNoCase(exttypestr
[et
]))
2878 if(fn
[fn
.GetLength()-1] != '.') fn
+= _T(".");
2879 fn
+= exttypestr
[et
];
2890 str
+= _T("<SAMI>\n<HEAD>\n");
2891 str
+= _T("<STYLE TYPE=\"text/css\">\n");
2892 str
+= _T("<!--\n");
2893 str
+= _T("P {margin-left: 16pt; margin-right: 16pt; margin-bottom: 16pt; margin-top: 16pt;\n");
2894 str
+= _T(" text-align: center; font-size: 18pt; font-family: arial; font-weight: bold; color: #f0f0f0;}\n");
2895 str
+= _T(".UNKNOWNCC {Name:Unknown; lang:en-US; SAMIType:CC;}\n");
2897 str
+= _T("</STYLE>\n");
2898 str
+= _T("</HEAD>\n");
2900 str
+= _T("<BODY>\n");
2904 else if(et
== EXTSSA
|| et
== EXTASS
)
2908 str
= _T("[Script Info]\n");
2909 str
+= (et
== EXTSSA
) ? _T("; This is a Sub Station Alpha v4 script.\n") : _T("; This is an Advanced Sub Station Alpha v4+ script.\n");
2910 str
+= _T("; For Sub Station Alpha info and downloads,\n");
2911 str
+= _T("; go to http://www.eswat.demon.co.uk/\n");
2912 str
+= _T("; or email kotus@eswat.demon.co.uk\n");
2916 str
+= _T("; Advanced Sub Station Alpha script format developed by #Anime-Fansubs@EfNET\n");
2917 str
+= _T("; http://www.anime-fansubs.org\n");
2919 str
+= _T("; For additional info and downloads go to http://gabest.org/\n");
2920 str
+= _T("; or email gabest@freemail.hu\n");
2923 str
+= _T("; Note: This file was saved by Subresync.\n");
2925 str
+= (et
== EXTSSA
) ? _T("ScriptType: v4.00\n") : _T("ScriptType: v4.00+\n");
2926 str
+= (m_collisions
== 0) ? _T("Collisions: Normal\n") : _T("Collisions: Reverse\n");
2927 if(et
== EXTASS
&& m_fScaledBAS
) str
+= _T("ScaledBorderAndShadow: Yes\n");
2928 str
+= _T("PlayResX: %d\n");
2929 str
+= _T("PlayResY: %d\n");
2930 str
+= _T("Timer: 100.0000\n");
2932 str
+= (et
== EXTSSA
)
2933 ? _T("[V4 Styles]\nFormat: Name, Fontname, Fontsize, PrimaryColour, SecondaryColour, TertiaryColour, BackColour, Bold, Italic, BorderStyle, Outline, Shadow, Alignment, MarginL, MarginR, MarginV, AlphaLevel, Encoding\n")
2934 : _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");
2937 str2
.Format(str
, m_dstScreenSize
.cx
, m_dstScreenSize
.cy
);
2938 f
.WriteString(str2
);
2940 str
= (et
== EXTSSA
)
2941 ? _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")
2942 : _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");
2944 POSITION pos
= m_styles
.GetStartPosition();
2949 m_styles
.GetNextAssoc(pos
, key
, s
);
2954 str2
.Format(str
, key
,
2955 s
->fontName
, (int)s
->fontSize
,
2956 s
->colors
[0]&0xffffff,
2957 s
->colors
[1]&0xffffff,
2958 s
->colors
[2]&0xffffff,
2959 s
->colors
[3]&0xffffff,
2960 s
->fontWeight
> FW_NORMAL
? -1 : 0, s
->fItalic
? -1 : 0,
2961 s
->borderStyle
== 0 ? 1 : s
->borderStyle
== 1 ? 3 : 0,
2962 (int)s
->outlineWidthY
, (int)s
->shadowDepthY
,
2963 s
->scrAlignment
<= 3 ? s
->scrAlignment
: s
->scrAlignment
<= 6 ? ((s
->scrAlignment
-3)|8) : s
->scrAlignment
<= 9 ? ((s
->scrAlignment
-6)|4) : 2,
2964 s
->marginRect
.get().left
, s
->marginRect
.get().right
, (s
->marginRect
.get().top
+ s
->marginRect
.get().bottom
) / 2,
2967 f
.WriteString(str2
);
2972 str2
.Format(str
, key
,
2973 s
->fontName
, (int)s
->fontSize
,
2974 (s
->colors
[0]&0xffffff) | (s
->alpha
[0]<<24),
2975 (s
->colors
[1]&0xffffff) | (s
->alpha
[1]<<24),
2976 (s
->colors
[2]&0xffffff) | (s
->alpha
[2]<<24),
2977 (s
->colors
[3]&0xffffff) | (s
->alpha
[3]<<24),
2978 s
->fontWeight
> FW_NORMAL
? -1 : 0,
2979 s
->fItalic
? -1 : 0, s
->fUnderline
? -1 : 0, s
->fStrikeOut
? -1 : 0,
2980 (int)s
->fontScaleX
, (int)s
->fontScaleY
,
2981 (int)s
->fontSpacing
, (float)s
->fontAngleZ
,
2982 s
->borderStyle
== 0 ? 1 : s
->borderStyle
== 1 ? 3 : 0,
2983 (int)s
->outlineWidthY
, (int)s
->shadowDepthY
,
2985 s
->marginRect
.get().left
, s
->marginRect
.get().right
, (s
->marginRect
.get().top
+ s
->marginRect
.get().bottom
) / 2,
2987 f
.WriteString(str2
);
2991 if(m_entries
.GetCount() > 0)
2994 str
+= _T("[Events]\n");
2995 str
+= (et
== EXTSSA
)
2996 ? _T("Format: Marked, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text\n")
2997 : _T("Format: Layer, Start, End, Style, Actor, MarginL, MarginR, MarginV, Effect, Text\n");
3003 et
== EXTSRT
? L
"%d\n%02d:%02d:%02d,%03d --> %02d:%02d:%02d,%03d\n%s\n\n" :
3004 et
== EXTSUB
? L
"{%d}{%d}%s\n" :
3005 et
== EXTSMI
? L
"<SYNC Start=%d><P Class=UNKNOWNCC>\n%s\n<SYNC Start=%d><P Class=UNKNOWNCC> \n" :
3006 et
== EXTPSB
? L
"{%d:%02d:%02d}{%d:%02d:%02d}%s\n" :
3007 et
== EXTSSA
? L
"Dialogue: Marked=0,%d:%02d:%02d.%02d,%d:%02d:%02d.%02d,%s,%s,%04d,%04d,%04d,%s,%s\n" :
3008 et
== EXTASS
? L
"Dialogue: %d,%d:%02d:%02d.%02d,%d:%02d:%02d.%02d,%s,%s,%04d,%04d,%04d,%s,%s\n" :
3012 for(int i
= 0, j
= m_entries
.GetCount(), k
= 0; i
< j
; i
++)
3014 STSEntry
& stse
= m_entries
.GetAt(i
);
3016 int t1
= TranslateStart(i
, fps
);
3017 if(t1
< 0) {k
++; continue;}
3019 int t2
= TranslateEnd(i
, fps
);
3021 int hh1
= (t1
/60/60/1000);
3022 int mm1
= (t1
/60/1000)%60;
3023 int ss1
= (t1
/1000)%60;
3024 int ms1
= (t1
)%1000;
3025 int hh2
= (t2
/60/60/1000);
3026 int mm2
= (t2
/60/1000)%60;
3027 int ss2
= (t2
/1000)%60;
3028 int ms2
= (t2
)%1000;
3030 CStringW str
= f
.IsUnicode()
3031 ? GetStrW(i
, et
== EXTSSA
|| et
== EXTASS
)
3032 : GetStrWA(i
, et
== EXTSSA
|| et
== EXTASS
);
3038 str2
.Format(fmt
, i
-k
+1, hh1
, mm1
, ss1
, ms1
, hh2
, mm2
, ss2
, ms2
, str
);
3040 else if(et
== EXTSUB
)
3042 str
.Replace('\n', '|');
3043 str2
.Format(fmt
, int(t1
*fps
/1000), int(t2
*fps
/1000), str
);
3045 else if(et
== EXTSMI
)
3047 str
.Replace(L
"\n", L
"<br>");
3048 str2
.Format(fmt
, t1
, str
, t2
);
3050 else if(et
== EXTPSB
)
3052 str
.Replace('\n', '|');
3053 str2
.Format(fmt
, hh1
, mm1
, ss1
, hh2
, mm2
, ss2
, str
);
3055 else if(et
== EXTSSA
)
3057 str
.Replace(L
"\n", L
"\\N");
3059 hh1
, mm1
, ss1
, ms1
/10,
3060 hh2
, mm2
, ss2
, ms2
/10,
3061 TToW(stse
.style
), TToW(stse
.actor
),
3062 stse
.marginRect
.left
, stse
.marginRect
.right
, (stse
.marginRect
.top
+ stse
.marginRect
.bottom
) / 2,
3063 TToW(stse
.effect
), str
);
3065 else if(et
== EXTASS
)
3067 str
.Replace(L
"\n", L
"\\N");
3070 hh1
, mm1
, ss1
, ms1
/10,
3071 hh2
, mm2
, ss2
, ms2
/10,
3072 TToW(stse
.style
), TToW(stse
.actor
),
3073 stse
.marginRect
.left
, stse
.marginRect
.right
, (stse
.marginRect
.top
+ stse
.marginRect
.bottom
) / 2,
3074 TToW(stse
.effect
), str
);
3077 f
.WriteString(str2
);
3084 f
.WriteString(_T("</BODY>\n</SAMI>\n"));
3088 if(!m_fUsingAutoGeneratedDefaultStyle
&& m_styles
.Lookup(g_default_style
, s
) && et
!= EXTSSA
&& et
!= EXTASS
)
3091 if(!f
.Save(fn
+ _T(".style"), e
))
3096 str
+= _T("ScriptType: v4.00+\n");
3097 str
+= _T("PlayResX: %d\n");
3098 str
+= _T("PlayResY: %d\n");
3100 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");
3101 str2
.Format(str
, m_dstScreenSize
.cx
, m_dstScreenSize
.cy
);
3102 f
.WriteString(str2
);
3104 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");
3106 s
->fontName
, (int)s
->fontSize
,
3107 (s
->colors
[0]&0xffffff) | (s
->alpha
[0]<<24),
3108 (s
->colors
[1]&0xffffff) | (s
->alpha
[1]<<24),
3109 (s
->colors
[2]&0xffffff) | (s
->alpha
[2]<<24),
3110 (s
->colors
[3]&0xffffff) | (s
->alpha
[3]<<24),
3111 s
->fontWeight
> FW_NORMAL
? -1 : 0,
3112 s
->fItalic
? -1 : 0, s
->fUnderline
? -1 : 0, s
->fStrikeOut
? -1 : 0,
3113 (int)s
->fontScaleX
, (int)s
->fontScaleY
,
3114 (int)s
->fontSpacing
, (float)s
->fontAngleZ
,
3115 s
->borderStyle
== 0 ? 1 : s
->borderStyle
== 1 ? 3 : 0,
3116 (int)s
->outlineWidthY
, (int)s
->shadowDepthY
,
3118 s
->marginRect
.get().left
, s
->marginRect
.get().right
, (s
->marginRect
.get().top
+ s
->marginRect
.get().bottom
) / 2,
3120 f
.WriteString(str2
);
3126 bool CSimpleTextSubtitle::IsEmpty()
3128 return m_entries
.IsEmpty();
3131 void CSimpleTextSubtitle::RemoveAllEntries()
3133 m_entries
.RemoveAll();
3136 ////////////////////////////////////////////////////////////////////
3138 bool STSStyleBase::operator==( const STSStyleBase
& s
) const
3140 return charSet
== s
.charSet
3141 && fontName
== s
.fontName
3142 && fontSize
== s
.fontSize
3143 && fontWeight
== s
.fontWeight
3144 && fItalic
== s
.fItalic
3145 && fUnderline
== s
.fUnderline
3146 && fStrikeOut
== s
.fStrikeOut
;
3149 STSStyle::STSStyle()
3154 void STSStyle::SetDefault()
3156 marginRect
= CRect(20, 20, 20, 20);
3159 outlineWidthX
= outlineWidthY
= 2;
3160 shadowDepthX
= shadowDepthY
= 3;
3161 colors
[0] = 0x00ffffff;
3162 colors
[1] = 0x0000ffff;
3163 colors
[2] = 0x00000000;
3164 colors
[3] = 0x00000000;
3169 charSet
= DEFAULT_CHARSET
;
3170 fontName
= _T("Arial");
3172 fontScaleX
= fontScaleY
= 100;
3174 fontWeight
= FW_BOLD
;
3180 fontShiftX
= fontShiftY
= fontAngleZ
= fontAngleX
= fontAngleY
= 0;
3184 bool STSStyle::operator == (const STSStyle
& s
)const
3186 return(marginRect
== s
.marginRect
3187 && scrAlignment
== s
.scrAlignment
3188 && borderStyle
== s
.borderStyle
3189 && outlineWidthX
== s
.outlineWidthX
3190 && outlineWidthY
== s
.outlineWidthY
3191 && shadowDepthX
== s
.shadowDepthX
3192 && shadowDepthY
== s
.shadowDepthY
3193 && *((int*)&colors
[0]) == *((int*)&s
.colors
[0])
3194 && *((int*)&colors
[1]) == *((int*)&s
.colors
[1])
3195 && *((int*)&colors
[2]) == *((int*)&s
.colors
[2])
3196 && *((int*)&colors
[3]) == *((int*)&s
.colors
[3])
3197 && alpha
[0] == s
.alpha
[0]
3198 && alpha
[1] == s
.alpha
[1]
3199 && alpha
[2] == s
.alpha
[2]
3200 && alpha
[3] == s
.alpha
[3]
3202 && fGaussianBlur
== s
.fGaussianBlur
3203 && relativeTo
== s
.relativeTo
3204 && IsFontStyleEqual(s
));
3207 bool STSStyle::IsFontStyleEqual(const STSStyle
& s
) const
3210 charSet
== s
.charSet
3211 && fontName
== s
.fontName
3212 && fontSize
== s
.fontSize
3213 && fontScaleX
== s
.fontScaleX
3214 && fontScaleY
== s
.fontScaleY
3215 && fontSpacing
== s
.fontSpacing
3216 && fontWeight
== s
.fontWeight
3217 && fItalic
== s
.fItalic
3218 && fUnderline
== s
.fUnderline
3219 && fStrikeOut
== s
.fStrikeOut
3220 && fontAngleZ
== s
.fontAngleZ
3221 && fontAngleX
== s
.fontAngleX
3222 && fontAngleY
== s
.fontAngleY
3223 && fontShiftX
== s
.fontShiftX
3224 && fontShiftY
== s
.fontShiftY
);
3227 void STSStyle::operator = (const LOGFONT
& lf
)
3229 charSet
= lf
.lfCharSet
;
3230 fontName
= lf
.lfFaceName
;
3232 fontSize
= -MulDiv(lf
.lfHeight
, 72, GetDeviceCaps(hDC
, LOGPIXELSY
));
3234 // fontAngleZ = (float)(1.0*lf.lfEscapement/10);
3235 fontWeight
= lf
.lfWeight
;
3236 fItalic
= !!lf
.lfItalic
;
3237 fUnderline
= !!lf
.lfUnderline
;
3238 fStrikeOut
= !!lf
.lfStrikeOut
;
3241 LOGFONTA
& operator <<= (LOGFONTA
& lfa
, const STSStyleBase
& s
)
3243 lfa
.lfCharSet
= s
.charSet
;
3244 strncpy_s(lfa
.lfFaceName
, LF_FACESIZE
, CStringA(s
.fontName
), _TRUNCATE
);
3246 lfa
.lfHeight
= -MulDiv((int)(s
.fontSize
+0.5), GetDeviceCaps(hDC
, LOGPIXELSY
), 72);
3248 lfa
.lfWeight
= s
.fontWeight
;
3249 lfa
.lfItalic
= s
.fItalic
?-1:0;
3250 lfa
.lfUnderline
= s
.fUnderline
?-1:0;
3251 lfa
.lfStrikeOut
= s
.fStrikeOut
?-1:0;
3255 LOGFONTW
& operator <<= (LOGFONTW
& lfw
, const STSStyleBase
& s
)
3257 lfw
.lfCharSet
= s
.charSet
;
3258 wcsncpy_s(lfw
.lfFaceName
, LF_FACESIZE
, CStringW(s
.fontName
), _TRUNCATE
);
3260 lfw
.lfHeight
= -MulDiv((int)(s
.fontSize
+0.5), GetDeviceCaps(hDC
, LOGPIXELSY
), 72);
3262 lfw
.lfWeight
= s
.fontWeight
;
3263 lfw
.lfItalic
= s
.fItalic
?-1:0;
3264 lfw
.lfUnderline
= s
.fUnderline
?-1:0;
3265 lfw
.lfStrikeOut
= s
.fStrikeOut
?-1:0;
3269 CString
& operator <<= (CString
& style
, const STSStyle
& s
)
3271 style
.Format(_T("%d;%d;%d;%d;")
3272 _T("%d;%d;%f;%f;%f;%f;")
3273 _T("0x%06x;0x%06x;0x%06x;0x%06x;")
3274 _T("0x%02x;0x%02x;0x%02x;0x%02x;")
3276 _T("%s;%f;%f;%f;%f;%d;")
3277 _T("%d;%d;%d;%f;%f;")
3280 s
.marginRect
.get().left
, s
.marginRect
.get().right
, s
.marginRect
.get().top
, s
.marginRect
.get().bottom
,
3281 s
.scrAlignment
, s
.borderStyle
,s
.outlineWidthX
, s
.outlineWidthY
, s
.shadowDepthX
, s
.shadowDepthY
,
3282 s
.colors
[0], s
.colors
[1], s
.colors
[2], s
.colors
[3],
3283 s
.alpha
[0], s
.alpha
[1], s
.alpha
[2], s
.alpha
[3],
3285 s
.fontName
,s
.fontSize
,s
.fontScaleX
, s
.fontScaleY
,s
.fontSpacing
,s
.fontWeight
,
3286 (int)s
.fItalic
, (int)s
.fUnderline
, (int)s
.fStrikeOut
, s
.fBlur
, s
.fGaussianBlur
,
3287 s
.fontAngleZ
, s
.fontAngleX
, s
.fontAngleY
,
3293 STSStyle
& operator <<= (STSStyle
& s
, const CString
& style
)
3299 CStringW str
= TToW(style
);
3300 if(str
.Find(';')>=0)
3303 tmp_rect
.left
= GetInt(str
,';'); tmp_rect
.right
= GetInt(str
,';'); tmp_rect
.top
= GetInt(str
,';'); tmp_rect
.bottom
= GetInt(str
,';');
3304 s
.marginRect
= tmp_rect
;
3305 s
.scrAlignment
= GetInt(str
,';'); s
.borderStyle
= GetInt(str
,';');
3306 s
.outlineWidthX
= GetFloat(str
,';'); s
.outlineWidthY
= GetFloat(str
,';'); s
.shadowDepthX
= GetFloat(str
,';'); s
.shadowDepthY
= GetFloat(str
,';');
3307 for(int i
= 0; i
< 4; i
++) s
.colors
[i
] = (COLORREF
)GetInt(str
,';');
3308 for(int i
= 0; i
< 4; i
++) s
.alpha
[i
] = GetInt(str
,';');
3309 s
.charSet
= GetInt(str
,';');
3310 s
.fontName
= WToT(GetStr(str
,';')); s
.fontSize
= GetFloat(str
,';');
3311 s
.fontScaleX
= GetFloat(str
,';'); s
.fontScaleY
= GetFloat(str
,';');
3312 s
.fontSpacing
= GetFloat(str
,';'); s
.fontWeight
= GetInt(str
,';');
3313 s
.fItalic
= !!GetInt(str
,';'); s
.fUnderline
= !!GetInt(str
,';'); s
.fStrikeOut
= !!GetInt(str
,';'); s
.fBlur
= GetFloat(str
,';'); s
.fGaussianBlur
= GetFloat(str
,';');
3314 s
.fontAngleZ
= GetFloat(str
,';'); s
.fontAngleX
= GetFloat(str
,';'); s
.fontAngleY
= GetFloat(str
,';');
3315 s
.relativeTo
= GetInt(str
,';');
3326 static bool OpenRealText(CTextFile
* file
, CSimpleTextSubtitle
& ret
, int CharSet
)
3331 while(file
->ReadString(buff
))
3334 if(buff
.IsEmpty()) continue;
3336 szFile
+= CStringW(_T("\n")) + buff
.GetBuffer();
3339 CRealTextParser RealTextParser
;
3340 if (!RealTextParser
.ParseRealText(szFile
))
3343 CRealTextParser::Subtitles crRealText
= RealTextParser
.GetParsedSubtitles();
3345 for (map
<pair
<int, int>, wstring
>::const_iterator i
= crRealText
.m_mapLines
.begin();
3346 i
!= crRealText
.m_mapLines
.end();
3350 SubRipper2SSA(i
->second
.c_str(), CharSet
),
3356 // std::wofstream wofsOut(L"c:/zzz.srt");
3357 // RealTextParser.OutputSRT(wofsOut);
3359 return(!ret
.IsEmpty());