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"
31 #include "xy_buffered_reader.h"
32 #include "text_reader.h"
35 #include "xy_logger.h"
37 // gathered from http://www.netwave.or.jp/~shikai/shikai/shcolor.htm
39 struct htmlcolor
{TCHAR
* name
; DWORD color
;} hmtlcolors
[] =
41 {_T("white"), 0xffffff},
42 {_T("whitesmoke"), 0xf5f5f5},
43 {_T("ghostwhite"), 0xf8f8ff},
44 {_T("snow"), 0xfffafa},
45 {_T("gainsboro"), 0xdcdcdc},
46 {_T("lightgrey"), 0xd3d3d3},
47 {_T("silver"), 0xc0c0c0},
48 {_T("darkgray"), 0xa9a9a9},
49 {_T("gray"), 0x808080},
50 {_T("dimgray"), 0x696969},
51 {_T("lightslategray"), 0x778899},
52 {_T("slategray"), 0x708090},
53 {_T("darkslategray"), 0x2f4f4f},
54 {_T("black"), 0x000000},
56 {_T("azure"), 0xf0ffff},
57 {_T("aliceblue"), 0xf0f8ff},
58 {_T("mintcream"), 0xf5fffa},
59 {_T("honeydew"), 0xf0fff0},
60 {_T("lightcyan"), 0xe0ffff},
61 {_T("paleturqoise"), 0xafeeee},
62 {_T("powderblue"), 0xb0e0e6},
63 {_T("lightblue"), 0xadd8ed},
64 {_T("lightsteelblue"), 0xb0c4de},
65 {_T("skyblue"), 0x87ceeb},
66 {_T("lightskyblue"), 0x87cefa},
67 {_T("cyan"), 0x00ffff},
68 {_T("aqua"), 0x00ff80},
69 {_T("deepskyblue"), 0x00bfff},
70 {_T("aquamarine"), 0x7fffd4},
71 {_T("turquoise"), 0x40e0d0},
72 {_T("darkturquoise"), 0x00ced1},
73 {_T("lightseagreen"), 0x20b2aa},
74 {_T("mediumturquoise"), 0x40e0dd},
75 {_T("mediumaquamarine"), 0x66cdaa},
76 {_T("cadetblue"), 0x5f9ea0},
77 {_T("teal"), 0x008080},
78 {_T("darkcyan"), 0x008b8b},
79 {_T("comflowerblue"), 0x6495ed},
80 {_T("dodgerblue"), 0x1e90ff},
81 {_T("steelblue"), 0x4682b4},
82 {_T("royalblue"), 0x4169e1},
83 {_T("blue"), 0x0000ff},
84 {_T("mediumblue"), 0x0000cd},
85 {_T("mediumslateblue"), 0x7b68ee},
86 {_T("slateblue"), 0x6a5acd},
87 {_T("darkslateblue"), 0x483d8b},
88 {_T("darkblue"), 0x00008b},
89 {_T("midnightblue"), 0x191970},
90 {_T("navy"), 0x000080},
92 {_T("palegreen"), 0x98fb98},
93 {_T("lightgreen"), 0x90ee90},
94 {_T("mediumspringgreen"), 0x00fa9a},
95 {_T("springgreen"), 0x00ff7f},
96 {_T("chartreuse"), 0x7fff00},
97 {_T("lawngreen"), 0x7cfc00},
98 {_T("lime"), 0x00ff00},
99 {_T("limegreen"), 0x32cd32},
100 {_T("greenyellow"), 0xadff2f},
101 {_T("yellowgreen"), 0x9acd32},
102 {_T("darkseagreen"), 0x8fbc8f},
103 {_T("mediumseagreen"), 0x3cb371},
104 {_T("seagreen"), 0x2e8b57},
105 {_T("olivedrab"), 0x6b8e23},
106 {_T("forestgreen"), 0x228b22},
107 {_T("green"), 0x008000},
108 {_T("darkkhaki"), 0xbdb76b},
109 {_T("olive"), 0x808000},
110 {_T("darkolivegreen"), 0x556b2f},
111 {_T("darkgreen"), 0x006400},
113 {_T("floralwhite"), 0xfffaf0},
114 {_T("seashell"), 0xfff5ee},
115 {_T("ivory"), 0xfffff0},
116 {_T("beige"), 0xf5f5dc},
117 {_T("cornsilk"), 0xfff8dc},
118 {_T("lemonchiffon"), 0xfffacd},
119 {_T("lightyellow"), 0xffffe0},
120 {_T("lightgoldenrodyellow"), 0xfafad2},
121 {_T("papayawhip"), 0xffefd5},
122 {_T("blanchedalmond"), 0xffedcd},
123 {_T("palegoldenrod"), 0xeee8aa},
124 {_T("khaki"), 0xf0eb8c},
125 {_T("bisque"), 0xffe4c4},
126 {_T("moccasin"), 0xffe4b5},
127 {_T("navajowhite"), 0xffdead},
128 {_T("peachpuff"), 0xffdab9},
129 {_T("yellow"), 0xffff00},
130 {_T("gold"), 0xffd700},
131 {_T("wheat"), 0xf5deb3},
132 {_T("orange"), 0xffa500},
133 {_T("darkorange"), 0xff8c00},
135 {_T("oldlace"), 0xfdf5e6},
136 {_T("linen"), 0xfaf0e6},
137 {_T("antiquewhite"), 0xfaebd7},
138 {_T("lightsalmon"), 0xffa07a},
139 {_T("darksalmon"), 0xe9967a},
140 {_T("salmon"), 0xfa8072},
141 {_T("lightcoral"), 0xf08080},
142 {_T("indianred"), 0xcd5c5c},
143 {_T("coral"), 0xff7f50},
144 {_T("tomato"), 0xff6347},
145 {_T("orangered"), 0xff4500},
146 {_T("red"), 0xff0000},
147 {_T("crimson"), 0xdc143c},
148 {_T("firebrick"), 0xb22222},
149 {_T("maroon"), 0x800000},
150 {_T("darkred"), 0x8b0000},
152 {_T("lavender"), 0xe6e6fe},
153 {_T("lavenderblush"), 0xfff0f5},
154 {_T("mistyrose"), 0xffe4e1},
155 {_T("thistle"), 0xd8bfd8},
156 {_T("pink"), 0xffc0cb},
157 {_T("lightpink"), 0xffb6c1},
158 {_T("palevioletred"), 0xdb7093},
159 {_T("hotpink"), 0xff69b4},
160 {_T("fuchsia"), 0xff00ee},
161 {_T("magenta"), 0xff00ff},
162 {_T("mediumvioletred"), 0xc71585},
163 {_T("deeppink"), 0xff1493},
164 {_T("plum"), 0xdda0dd},
165 {_T("violet"), 0xee82ee},
166 {_T("orchid"), 0xda70d6},
167 {_T("mediumorchid"), 0xba55d3},
168 {_T("mediumpurple"), 0x9370db},
169 {_T("purple"), 0x9370db},
170 {_T("blueviolet"), 0x8a2be2},
171 {_T("darkviolet"), 0x9400d3},
172 {_T("darkorchid"), 0x9932cc},
174 {_T("tan"), 0xd2b48c},
175 {_T("burlywood"), 0xdeb887},
176 {_T("sandybrown"), 0xf4a460},
177 {_T("peru"), 0xcd853f},
178 {_T("goldenrod"), 0xdaa520},
179 {_T("darkgoldenrod"), 0xb8860b},
180 {_T("chocolate"), 0xd2691e},
181 {_T("rosybrown"), 0xbc8f8f},
182 {_T("sienna"), 0xa0522d},
183 {_T("saddlebrown"), 0x8b4513},
184 {_T("brown"), 0xa52a2a},
187 CHtmlColorMap::CHtmlColorMap()
189 for(int i
= 0; i
< countof(hmtlcolors
); i
++)
190 SetAt(hmtlcolors
[i
].name
, hmtlcolors
[i
].color
);
193 CHtmlColorMap g_colors
;
195 CString
g_default_style(_T("Default"));
223 TCHAR
* CharSetNames
[] =
247 int CharSetLen
= countof(CharSetList
);
249 static void LogSegments(const CAtlArray
<STSSegment
>& segments
)
252 for (int i
=0;i
<segments
.GetCount();i
++)
254 const STSSegment
& s
= segments
[i
];
255 XY_LOG_INFO(_T("\tsegments ")<<i
<<_T(":")<<s
.start
<<_T(" ")
256 <<s
.end
<<_T(" ")<<s
.subs
.GetCount());
257 XY_LOG_INFO(_T("\tsubs: "));
258 for (int j
=0;j
<s
.subs
.GetCount();j
++)
260 XY_LOG_INFO(_T("\t\t ")<<s
.subs
[j
]);
268 static DWORD
CharSetToCodePage(DWORD dwCharSet
)
271 ::TranslateCharsetInfo((DWORD
*)dwCharSet
, &cs
, TCI_SRCCHARSET
);
275 int FindChar(CStringW str
, WCHAR c
, int pos
, bool fUnicode
, int CharSet
)
277 if(fUnicode
) return(str
.Find(c
, pos
));
281 DWORD cp
= CharSetToCodePage(CharSet
);
282 int OrgCharSet
= CharSet
;
284 for(int i
= 0, j
= str
.GetLength(), k
; i
< j
; i
++)
288 if(IsDBCSLeadByteEx(cp
, (BYTE
)c2
)) i
++;
291 if(c2
== c
) return(i
);
294 if(c2
== '{') fStyleMod
++;
295 else if(fStyleMod
> 0)
297 if(c2
== '}') fStyleMod
--;
298 else if(c2
== 'e' && i
>= 3 && i
< j
-1 && str
.Mid(i
-2, 3) == L
"\\fe")
301 for(k
= i
+1; _istdigit(str
[k
]); k
++) CharSet
= CharSet
*10 + (str
[k
] - '0');
302 if(k
== i
+1) CharSet
= OrgCharSet
;
304 cp
= CharSetToCodePage(CharSet
);
312 int FindChar(CStringA str, char c, int pos, bool fUnicode, int CharSet)
316 return(FindChar(AToW(str), c, pos, false, CharSet));
319 static CStringW
ToMBCS(CStringW str
, DWORD CharSet
)
323 DWORD cp
= CharSetToCodePage(CharSet
);
325 for(int i
= 0, j
= str
.GetLength(); i
< j
; i
++)
327 WCHAR wc
= str
.GetAt(i
);
331 if((len
= WideCharToMultiByte(cp
, 0, &wc
, 1, c
, 8, NULL
, NULL
)) > 0)
333 for(int k
= 0; k
< len
; k
++)
334 ret
+= (WCHAR
)(BYTE
)c
[k
];
345 static CStringW
UnicodeSSAToMBCS(CStringW str
, DWORD CharSet
)
349 int OrgCharSet
= CharSet
;
351 for(int j
= 0; j
< str
.GetLength(); )
353 j
= str
.Find('{', j
);
356 ret
+= ToMBCS(str
.Left(j
), CharSet
);
362 ret
+= ToMBCS(str
, CharSet
);
367 int k
= str
.Find(L
"\\fe");
372 for(; _istdigit(str
[l
]); l
++) CharSet
= CharSet
*10 + (str
[l
] - '0');
373 if(l
== k
+3) CharSet
= OrgCharSet
;
378 ret
+= ToMBCS(str
.Left(j
), OrgCharSet
);
385 ret
+= ToMBCS(str
, CharSet
);
393 static CStringW
ToUnicode(CStringW str
, DWORD CharSet
)
397 DWORD cp
= CharSetToCodePage(CharSet
);
399 for(int i
= 0, j
= str
.GetLength(); i
< j
; i
++)
401 WCHAR wc
= str
.GetAt(i
);
404 if(IsDBCSLeadByteEx(cp
, (BYTE
)wc
))
412 cc
[1] = (char)str
.GetAt(i
);
414 MultiByteToWideChar(cp
, 0, cc
, 2, &wc
, 1);
419 MultiByteToWideChar(cp
, 0, &c
, 1, &wc
, 1);
428 static CStringW
MBCSSSAToUnicode(CStringW str
, int CharSet
)
432 int OrgCharSet
= CharSet
;
434 for(int j
= 0; j
< str
.GetLength(); )
436 j
= FindChar(str
, '{', 0, false, CharSet
);
440 ret
+= ToUnicode(str
.Left(j
), CharSet
);
443 j
= FindChar(str
, '}', 0, false, CharSet
);
447 ret
+= ToUnicode(str
, CharSet
);
452 int k
= str
.Find(L
"\\fe");
457 for(; _istdigit(str
[l
]); l
++) CharSet
= CharSet
*10 + (str
[l
] - '0');
458 if(l
== k
+3) CharSet
= OrgCharSet
;
463 ret
+= ToUnicode(str
.Left(j
), OrgCharSet
);
470 ret
+= ToUnicode(str
, CharSet
);
478 CStringW
RemoveSSATags(CStringW str
, bool fUnicode
, int CharSet
)
480 str
.Replace (L
"{\\i1}", L
"<i>");
481 str
.Replace (L
"{\\i}", L
"</i>");
483 for(int i
= 0, j
; i
< str
.GetLength(); )
485 if((i
= FindChar(str
, '{', i
, fUnicode
, CharSet
)) < 0) break;
486 if((j
= FindChar(str
, '}', i
, fUnicode
, CharSet
)) < 0) break;
487 str
.Delete(i
, j
-i
+1);
490 str
.Replace(L
"\\N", L
"\n");
491 str
.Replace(L
"\\n", L
"\n");
492 str
.Replace(L
"\\h", L
" ");
499 static CStringW
SubRipper2SSA(CStringW str
, int CharSet
)
501 str
.Replace(L
"<i>", L
"{\\i1}");
502 str
.Replace(L
"</i>", L
"{\\i}");
503 str
.Replace(L
"<b>", L
"{\\b1}");
504 str
.Replace(L
"</b>", L
"{\\b}");
505 str
.Replace(L
"<u>", L
"{\\u1}");
506 str
.Replace(L
"</u>", L
"{\\u}");
511 static bool OpenSubRipper(CTextFile
* file
, CSimpleTextSubtitle
& ret
, int CharSet
)
516 while(file
->ReadString(buff
))
519 if(buff
.IsEmpty()) continue;
522 int hh1
, mm1
, ss1
, ms1
, hh2
, mm2
, ss2
, ms2
;
523 int c
= swscanf(buff
, L
"%d%c%d%c%d%c%d --> %d%c%d%c%d%c%d\n",
524 &hh1
, &sep
, &mm1
, &sep
, &ss1
, &sep
, &ms1
,
525 &hh2
, &sep
, &mm2
, &sep
, &ss2
, &sep
, &ms2
);
527 if(c
== 1) // numbering
531 else if(c
== 14) // time info
535 bool fFoundEmpty
= false;
537 while(file
->ReadString(tmp
))
540 if(tmp
.IsEmpty()) fFoundEmpty
= true;
544 if(swscanf(tmp
, L
"%d%c", &num2
, &c
) == 1 && fFoundEmpty
)
554 SubRipper2SSA(str
, CharSet
),
556 (((hh1
*60 + mm1
)*60) + ss1
)*1000 + ms1
,
557 (((hh2
*60 + mm2
)*60) + ss2
)*1000 + ms2
);
559 else if(c
!= EOF
) // might be another format
565 return(!ret
.IsEmpty());
568 static bool OpenOldSubRipper(CTextFile
* file
, CSimpleTextSubtitle
& ret
, int CharSet
)
571 while(file
->ReadString(buff
))
574 if(buff
.IsEmpty()) continue;
576 for(int i
= 0; i
< buff
.GetLength(); i
++)
578 if((i
= FindChar(buff
, '|', i
, file
->IsUnicode(), CharSet
)) < 0) break;
582 int hh1
, mm1
, ss1
, hh2
, mm2
, ss2
;
583 int c
= swscanf(buff
, L
"{%d:%d:%d}{%d:%d:%d}", &hh1
, &mm1
, &ss1
, &hh2
, &mm2
, &ss2
);
588 buff
.Mid(buff
.Find('}', buff
.Find('}')+1)+1),
590 (((hh1
*60 + mm1
)*60) + ss1
)*1000,
591 (((hh2
*60 + mm2
)*60) + ss2
)*1000);
593 else if(c
!= EOF
) // might be another format
599 return(!ret
.IsEmpty());
602 static bool OpenSubViewer(CTextFile
* file
, CSimpleTextSubtitle
& ret
, int CharSet
)
605 CStringW font
, color
, size
;
606 bool fBold
, fItalic
, fStriked
, fUnderline
;
609 while(file
->ReadString(buff
))
612 if(buff
.IsEmpty()) continue;
616 for(int i
= 0; i
< buff
.GetLength() && buff
[i
]== '['; )
618 int j
= buff
.Find(']', ++i
);
621 CStringW tag
= buff
.Mid(i
,j
-i
);
627 j
= buff
.Find('[', ++i
);
628 if(j
< 0) j
= buff
.GetLength();
630 CStringW param
= buff
.Mid(i
,j
-i
);
631 param
.Trim(L
" \\t,");
636 font
= def
.fontName
.CompareNoCase(WToT(param
)) ? param
: L
"";
637 else if(tag
== L
"colf")
638 color
= def
.colors
[0] != wcstol(((LPCWSTR
)param
)+2, 0, 16) ? param
: L
"";
639 else if(tag
== L
"size")
640 size
= def
.fontSize
!= wcstol(param
, 0, 10) ? param
: L
"";
641 else if(tag
== L
"style")
643 if(param
.Find(L
"no") >= 0)
645 fBold
= fItalic
= fStriked
= fUnderline
= false;
649 fBold
= def
.fontWeight
< FW_BOLD
&& param
.Find(L
"bd") >= 0;
650 fItalic
= def
.fItalic
&& param
.Find(L
"it") >= 0;
651 fStriked
= def
.fStrikeOut
&& param
.Find(L
"st") >= 0;
652 fUnderline
= def
.fUnderline
&& param
.Find(L
"ud") >= 0;
661 int hh1
, mm1
, ss1
, hs1
, hh2
, mm2
, ss2
, hs2
;
662 int c
= swscanf(buff
, L
"%d:%d:%d%c%d,%d:%d:%d%c%d\n",
663 &hh1
, &mm1
, &ss1
, &sep
, &hs1
, &hh2
, &mm2
, &ss2
, &sep
, &hs2
);
668 file
->ReadString(str
);
670 str
.Replace(L
"[br]", L
"\\N");
673 if(!font
.IsEmpty()) prefix
+= L
"\\fn" + font
;
674 if(!color
.IsEmpty()) prefix
+= L
"\\c" + color
;
675 if(!size
.IsEmpty()) prefix
+= L
"\\fs" + size
;
676 if(fBold
) prefix
+= L
"\\b1";
677 if(fItalic
) prefix
+= L
"\\i1";
678 if(fStriked
) prefix
+= L
"\\s1";
679 if(fUnderline
) prefix
+= L
"\\u1";
680 if(!prefix
.IsEmpty()) str
= L
"{" + prefix
+ L
"}" + str
;
684 (((hh1
*60 + mm1
)*60) + ss1
)*1000 + hs1
*10,
685 (((hh2
*60 + mm2
)*60) + ss2
)*1000 + hs2
*10);
687 else if(c
!= EOF
) // might be another format
693 return(!ret
.IsEmpty());
696 static STSStyle
* GetMicroDVDStyle(CString str
, int CharSet
)
698 STSStyle
* ret
= new STSStyle();
699 if(!ret
) return(NULL
);
701 for(int i
= 0, len
= str
.GetLength(); i
< len
; i
++)
703 int j
= str
.Find('{', i
);
708 int k
= str
.Find('}', j
);
711 CString code
= str
.Mid(j
, k
-j
);
712 if(code
.GetLength() > 2) code
.SetAt(1, (TCHAR
)towlower(code
[1]));
714 if(!_tcsnicmp(code
, _T("{c:$"), 4))
716 _stscanf(code
, _T("{c:$%x"), &ret
->colors
[0]);
718 else if(!_tcsnicmp(code
, _T("{f:"), 3))
720 ret
->fontName
= code
.Mid(3);
722 else if(!_tcsnicmp(code
, _T("{s:"), 3))
725 if(1 == _stscanf(code
, _T("{s:%f"), &f
))
728 else if(!_tcsnicmp(code
, _T("{h:"), 3))
730 _stscanf(code
, _T("{h:%d"), &ret
->charSet
);
732 else if(!_tcsnicmp(code
, _T("{y:"), 3))
735 if(code
.Find('b') >= 0) ret
->fontWeight
= FW_BOLD
;
736 if(code
.Find('i') >= 0) ret
->fItalic
= true;
737 if(code
.Find('u') >= 0) ret
->fUnderline
= true;
738 if(code
.Find('s') >= 0) ret
->fStrikeOut
= true;
740 else if(!_tcsnicmp(code
, _T("{p:"), 3))
743 _stscanf(code
, _T("{p:%d"), &p
);
744 ret
->scrAlignment
= (p
== 0) ? 8 : 2;
753 static CStringW
MicroDVD2SSA(CStringW str
, bool fUnicode
, int CharSet
)
757 enum {COLOR
=0, FONTNAME
, FONTSIZE
, FONTCHARSET
, BOLD
, ITALIC
, UNDERLINE
, STRIKEOUT
};
760 memset(fRestore
, 0, sizeof(bool)*fRestoreLen
);
762 for(int pos
= 0, eol
; pos
< str
.GetLength(); pos
++)
764 if((eol
= FindChar(str
, '|', pos
, fUnicode
, CharSet
)) < 0) eol
= str
.GetLength();
766 CStringW line
= str
.Mid(pos
, eol
-pos
);
770 for(int i
= 0, j
, k
, len
= line
.GetLength(); i
< len
; i
++)
772 if((j
= FindChar(line
, '{', i
, fUnicode
, CharSet
)) < 0) j
= str
.GetLength();
774 ret
+= line
.Mid(i
, j
-i
);
778 if((k
= FindChar(line
, '}', j
, fUnicode
, CharSet
)) < 0) k
= len
;
781 CStringW code
= line
.Mid(j
, k
-j
);
783 if(!wcsnicmp(code
, L
"{c:$", 4))
785 fRestore
[COLOR
] = (iswupper(code
[1]) == 0);
789 swscanf(code
, L
"{c:$%x", &color
);
790 code
.Format(L
"{\\c&H%x&}", color
);
793 else if(!wcsnicmp(code
, L
"{f:", 3))
795 fRestore
[FONTNAME
] = (iswupper(code
[1]) == 0);
797 code
.Format(L
"{\\fn%s}", code
.Mid(3));
800 else if(!wcsnicmp(code
, L
"{s:", 3))
802 fRestore
[FONTSIZE
] = (iswupper(code
[1]) == 0);
806 swscanf(code
, L
"{s:%f", &size
);
807 code
.Format(L
"{\\fs%f}", size
);
810 else if(!wcsnicmp(code
, L
"{h:", 3))
812 fRestore
[COLOR
] = (_istupper(code
[1]) == 0);
816 swscanf(code
, L
"{h:%d", &CharSet
);
817 code
.Format(L
"{\\fe%d}", CharSet
);
820 else if(!wcsnicmp(code
, L
"{y:", 3))
822 bool f
= (_istupper(code
[1]) == 0);
827 if(code
.Find('b') >= 0) {ret
+= L
"\\b1"; fRestore
[BOLD
] = f
;}
828 if(code
.Find('i') >= 0) {ret
+= L
"\\i1"; fRestore
[ITALIC
] = f
;}
829 if(code
.Find('u') >= 0) {ret
+= L
"\\u1"; fRestore
[UNDERLINE
] = f
;}
830 if(code
.Find('s') >= 0) {ret
+= L
"\\s1"; fRestore
[STRIKEOUT
] = f
;}
833 else if(!wcsnicmp(code
, L
"{o:", 3))
839 swscanf(code
, L
"{o:%d%c%d", &x
, &c
, &y
);
840 code
.Format(L
"{\\move(%d,%d,0,0,0,0)}", x
, y
);
849 if(pos
>= str
.GetLength()) break;
851 for(int i
= 0; i
< fRestoreLen
; i
++)
857 case COLOR
: ret
+= L
"{\\c}"; break;
858 case FONTNAME
: ret
+= L
"{\\fn}"; break;
859 case FONTSIZE
: ret
+= L
"{\\fs}"; break;
860 case FONTCHARSET
: ret
+= L
"{\\fe}"; break;
861 case BOLD
: ret
+= L
"{\\b}"; break;
862 case ITALIC
: ret
+= L
"{\\i}"; break;
863 case UNDERLINE
: ret
+= L
"{\\u}"; break;
864 case STRIKEOUT
: ret
+= L
"{\\s}"; break;
870 memset(fRestore
, 0, sizeof(bool)*fRestoreLen
);
878 static bool OpenMicroDVD(CTextFile
* file
, CSimpleTextSubtitle
& ret
, int CharSet
)
880 bool fCheck
= false, fCheck2
= false;
882 CString
style(_T("Default"));
885 while(file
->ReadString(buff
))
888 if(buff
.IsEmpty()) continue;
891 int c
= swscanf(buff
, L
"{%d}{%d}", &start
, &end
);
893 if(c
!= 2) {c
= swscanf(buff
, L
"{%d}{}", &start
)+1; end
= start
+ 60; fCheck
= true;}
898 if(buff
.Find('{') == 0 && (i
= buff
.Find('}')) > 1 && i
< buff
.GetLength())
900 if(STSStyle
* s
= GetMicroDVDStyle(WToT(buff
.Mid(i
+1)), CharSet
))
902 style
= buff
.Mid(1, i
-1);
904 if(style
.GetLength()) {CString str
= style
.Mid(1); str
.MakeLower(); style
= style
.Left(1) + str
;}
905 ret
.AddStyle(style
, s
);
906 CharSet
= s
->charSet
;
914 if(fCheck2
&& !ret
.IsEmpty())
916 STSEntry
& stse
= ret
.m_entries
[ret
.m_entries
.GetCount()-1];
917 stse
.end
= min(stse
.end
, start
);
922 MicroDVD2SSA(buff
.Mid(buff
.Find('}', buff
.Find('}')+1)+1), file
->IsUnicode(), CharSet
),
933 else if(c
!= EOF
) // might be another format
939 return(!ret
.IsEmpty());
942 static void ReplaceNoCase(CStringW
& str
, CStringW from
, CStringW to
)
949 for(i
= 0, j
= str
.GetLength(); i
< j
; )
951 if((k
= lstr
.Find(from
, i
)) >= 0)
953 str
.Delete(k
, from
.GetLength()); lstr
.Delete(k
, from
.GetLength());
954 str
.Insert(k
, to
); lstr
.Insert(k
, to
);
955 i
= k
+ to
.GetLength();
962 static CStringW
SMI2SSA(CStringW str
, int CharSet
)
964 ReplaceNoCase(str
, L
" ", L
" ");
965 ReplaceNoCase(str
, L
""", L
"\"");
966 ReplaceNoCase(str
, L
"<br>", L
"\\N");
967 ReplaceNoCase(str
, L
"<i>", L
"{\\i1}");
968 ReplaceNoCase(str
, L
"</i>", L
"{\\i}");
969 ReplaceNoCase(str
, L
"<b>", L
"{\\b1}");
970 ReplaceNoCase(str
, L
"</b>", L
"{\\b}");
977 for(int i
= 0, j
= str
.GetLength(); i
< j
; )
980 if((k
= lstr
.Find('<', i
)) < 0) break;
982 int chars_inserted
= 0;
985 for(; k
+l
< j
&& lstr
[k
+l
] != '>'; l
++);
988 // Modified by Cookie Monster
989 if (lstr
.Find(L
"<font ", k
) == k
)
991 CStringW args
= lstr
.Mid(k
+6, l
-6); // delete "<font "
994 args
.Remove('\"'); args
.Remove('#'); // may include 2 * " + #
995 arg
.TrimLeft(); arg
.TrimRight(L
" >");
1000 arg
= args
.SpanExcluding(L
" \t>");
1001 args
= args
.Mid(arg
.GetLength());
1005 if (arg
.Find(L
"color=") == 0 )
1009 arg
= arg
.Mid(6); // delete "color="
1014 if(g_colors
.Lookup(CString(arg
), val
))
1016 else if((color
= wcstol(arg
, NULL
, 16) ) == 0)
1017 color
= 0x00ffffff; // default is white
1019 arg
.Format(L
"%02x%02x%02x", color
&0xff, (color
>>8)&0xff, (color
>>16)&0xff);
1020 lstr
.Insert(k
+ l
+ chars_inserted
, CStringW(L
"{\\c&H") + arg
+ L
"&}");
1021 str
.Insert(k
+ l
+ chars_inserted
, CStringW(L
"{\\c&H") + arg
+ L
"&}");
1022 chars_inserted
+= 5 + arg
.GetLength() + 2;
1025 else if (arg.Find(_T("size=" )) == 0 )
1029 arg = arg.Mid(5); // delete "size="
1030 if ( arg.GetLength() == 0)
1033 if ( fsize = _tcstol(arg, &tmp, 10) == 0 )
1036 lstr.Insert(k + l + chars_inserted, CString(_T("{\\fs")) + arg + _T("&}"));
1037 str.Insert(k + l + chars_inserted, CString(_T("{\\fs")) + arg + _T("&}"));
1038 chars_inserted += 4 + arg.GetLength() + 2;
1046 if (lstr.Find(L"<font color=", k) == k)
1048 CStringW arg = lstr.Mid(k+12, l-12); // may include 2 * " + #
1052 arg.TrimLeft(); arg.TrimRight(L" >");
1054 if(arg.GetLength() > 0)
1058 CString key = WToT(arg);
1060 if(g_colors.Lookup(key, val)) color = (DWORD)val;
1061 else color = wcstol(arg, NULL, 16);
1063 arg.Format(L"%02x%02x%02x", color&0xff, (color>>8)&0xff, (color>>16)&0xff);
1066 lstr.Insert(k + l + chars_inserted, L"{\\c&H" + arg + L"&}");
1067 str.Insert(k + l + chars_inserted, L"{\\c&H" + arg + L"&}");
1068 chars_inserted += 5 + arg.GetLength() + 2;
1071 else if (lstr
.Find(L
"</font>", k
) == k
)
1073 lstr
.Insert(k
+ l
+ chars_inserted
, L
"{\\c}");
1074 str
.Insert(k
+ l
+ chars_inserted
, L
"{\\c}");
1075 chars_inserted
+= 4;
1078 str
.Delete(k
, l
); lstr
.Delete(k
, l
);
1079 i
= k
+ chars_inserted
;
1080 j
= str
.GetLength();
1086 static bool OpenSami(CTextFile
* file
, CSimpleTextSubtitle
& ret
, int CharSet
)
1088 CStringW buff
, caption
;
1090 ULONGLONG pos
= file
->GetPosition();
1094 while(file
->ReadString(buff
) && !fSAMI
)
1096 if(buff
.MakeUpper().Find(L
"<SAMI>") >= 0) fSAMI
= true;
1099 if(!fSAMI
) return(false);
1103 bool fComment
= false;
1107 while(file
->ReadString(buff
))
1110 if(buff
.IsEmpty()) continue;
1112 CStringW ubuff
= buff
;
1115 if(ubuff
.Find(L
"<!--") >= 0 || ubuff
.Find(L
"<TITLE>") >= 0)
1122 if((i
= ubuff
.Find(L
"<SYNC START=")) >= 0)
1126 for(i
= 12; i
< ubuff
.GetLength(); i
++)
1128 if(ubuff
[i
] != '>' && ubuff
[i
] != 'M')
1130 if(iswdigit(ubuff
[i
]))
1133 time
+= ubuff
[i
] - 0x30;
1140 SMI2SSA(caption
, CharSet
),
1151 if(ubuff
.Find(L
"-->") >= 0 || ubuff
.Find(L
"</TITLE>") >= 0)
1156 SMI2SSA(caption
, CharSet
),
1158 start_time
, MAXLONG
);
1163 static bool OpenVPlayer(CTextFile
* file
, CSimpleTextSubtitle
& ret
, int CharSet
)
1166 while(file
->ReadString(buff
))
1169 if(buff
.IsEmpty()) continue;
1171 for(int i
= 0; i
< buff
.GetLength(); i
++)
1173 if((i
= FindChar(buff
, '|', i
, file
->IsUnicode(), CharSet
)) < 0) break;
1174 buff
.SetAt(i
, '\n');
1178 int c
= swscanf(buff
, L
"%d:%d:%d:", &hh
, &mm
, &ss
);
1182 CStringW str
= buff
.Mid(buff
.Find(':', buff
.Find(':', buff
.Find(':')+1)+1)+1);
1185 (((hh
*60 + mm
)*60) + ss
)*1000,
1186 (((hh
*60 + mm
)*60) + ss
)*1000 + 1000 + 50*str
.GetLength());
1188 else if(c
!= EOF
) // might be another format
1194 return(!ret
.IsEmpty());
1197 inline CStringW
GetStr(CStringW
& buff
, char sep
= ',') //throw(...)
1201 int pos
= buff
.Find(sep
);
1204 pos
= buff
.GetLength();
1205 if(pos
< 1) throw 1;
1208 CStringW ret
= buff
.Left(pos
);
1209 if(pos
< buff
.GetLength()) buff
= buff
.Mid(pos
+1);
1214 inline int GetInt(CStringW
& buff
, char sep
= ',') //throw(...)
1218 str
= GetStr(buff
, sep
);
1221 CStringW fmtstr
= str
.GetLength() > 2 && (str
.Left(2) == L
"&h" || str
.Left(2) == L
"0x")
1222 ? str
= str
.Mid(2), L
"%x"
1226 if(swscanf(str
, fmtstr
, &ret
) != 1) throw 1;
1231 inline double GetFloat(CStringW
& buff
, char sep
= ',') //throw(...)
1235 str
= GetStr(buff
, sep
);
1239 if(swscanf(str
, L
"%f", &ret
) != 1) throw 1;
1241 return((double)ret
);
1244 inline CStringW::PCXSTR
TryNextStr(CStringW::PXSTR
* buff
, WCHAR sep
= WCHAR(','))
1246 CStringW::PXSTR start
= NULL
;
1247 CStringW::PXSTR ret
= NULL
;
1248 for(start
=*buff
; *start
!=0 && *start
==WCHAR(' '); start
++) ;
1253 for( ;*start
!=0 && *start
!=sep
; start
++) ;
1263 inline int NextInt(CStringW::PXSTR
* buff
, WCHAR sep
= WCHAR(',')) //throw(...)
1267 str
= TryNextStr(buff
, sep
);
1270 CStringW fmtstr
= str
.GetLength() > 2 && (str
.Left(2) == L
"&h" || str
.Left(2) == L
"0x")
1271 ? str
= str
.Mid(2), L
"%x"
1275 if(swscanf(str
, fmtstr
, &ret
) != 1) throw 1;
1280 inline double NextFloat(CStringW::PXSTR
* buff
, WCHAR sep
= WCHAR(',')) //throw(...)
1284 str
= TryNextStr(buff
, sep
);
1288 if(swscanf(str
, L
"%f", &ret
) != 1) throw 1;
1290 return((double)ret
);
1293 static bool LoadFont(CString
& font
)
1295 int len
= font
.GetLength();
1297 CAutoVectorPtr
<BYTE
> pData
;
1298 if(len
== 0 || (len
&3) == 1 || !pData
.Allocate(len
))
1301 const TCHAR
* s
= font
;
1302 const TCHAR
* e
= s
+ len
;
1303 for(BYTE
* p
= pData
; s
< e
; s
++, p
++) *p
= *s
- 33;
1305 for(int i
= 0, j
= 0, k
= len
&~3; i
< k
; i
+=4, j
+=3)
1307 pData
[j
+0] = ((pData
[i
+0]&63)<<2)|((pData
[i
+1]>>4)& 3);
1308 pData
[j
+1] = ((pData
[i
+1]&15)<<4)|((pData
[i
+2]>>2)&15);
1309 pData
[j
+2] = ((pData
[i
+2]& 3)<<6)|((pData
[i
+3]>>0)&63);
1312 int datalen
= (len
&~3)*3/4;
1316 pData
[datalen
++] = ((pData
[(len
&~3)+0]&63)<<2)|((pData
[(len
&~3)+1]>>4)&3);
1318 else if((len
&3) == 3)
1320 pData
[datalen
++] = ((pData
[(len
&~3)+0]&63)<<2)|((pData
[(len
&~3)+1]>>4)& 3);
1321 pData
[datalen
++] = ((pData
[(len
&~3)+1]&15)<<4)|((pData
[(len
&~3)+2]>>2)&15);
1324 HANDLE hFont
= INVALID_HANDLE_VALUE
;
1326 if(HMODULE hModule
= LoadLibrary(_T("GDI32.DLL")))
1328 typedef HANDLE (WINAPI
*PAddFontMemResourceEx
)( IN PVOID
, IN DWORD
, IN PVOID
, IN DWORD
*);
1329 if(PAddFontMemResourceEx f
= (PAddFontMemResourceEx
)GetProcAddress(hModule
, "AddFontMemResourceEx"))
1332 hFont
= f(pData
, datalen
, NULL
, &cFonts
);
1335 FreeLibrary(hModule
);
1338 if(hFont
== INVALID_HANDLE_VALUE
)
1340 TCHAR path
[MAX_PATH
];
1341 GetTempPath(MAX_PATH
, path
);
1344 for(int i
= 0, j
= datalen
>>2; i
< j
; i
++)
1345 chksum
+= ((DWORD
*)(BYTE
*)pData
)[i
];
1348 fn
.Format(_T("%sfont%08x.ttf"), path
, chksum
);
1351 if(!CFileGetStatus(fn
, fs
))
1354 if(f
.Open(fn
, CFile::modeCreate
|CFile::modeWrite
|CFile::typeBinary
|CFile::shareDenyWrite
))
1356 f
.Write(pData
, datalen
);
1361 AddFontResource(fn
);
1367 static bool LoadUUEFont(CTextFile
* file
)
1370 while(file
->ReadString(s
))
1373 if(s
.IsEmpty() || s
[0] == '[') break;
1374 if(s
.Find(_T("fontname:")) == 0) {LoadFont(font
); font
.Empty(); continue;}
1385 static bool OpenSubStationAlpha(CTextFile
* file
, CSimpleTextSubtitle
& ret
, int CharSet
)
1387 using namespace xy_utils
;
1390 int version
= 3, sver
= 3;
1393 BufferedReader
<CTextFile
> buffered_reader
;
1394 if(!buffered_reader
.Init(file
, file
->GetLength()))
1396 DbgLog(( LOG_ERROR
, 1, "init buffered_reader failed. buffsize:%d", file
->GetLength() ));
1399 TextReader
<BufferedReader
<CTextFile
>> text_reader(buffered_reader
, (TextReader
<BufferedReader
<CTextFile
>>::Encoding
)file
->GetEncoding());
1401 while(text_reader
.ReadLine(&buff
))
1404 if(buff
.IsEmpty() || buff
.GetAt(0) == ';') continue;
1409 entry
= GetStr(buff
, ':');
1411 // catch(...) {continue;}
1415 if(entry
== _T("dialogue"))
1419 CStringW::PXSTR __buff
= buff
.GetBuffer();
1420 int hh1
, mm1
, ss1
, ms1_div10
, hh2
, mm2
, ss2
, ms2_div10
, layer
= 0;
1421 CString Style
, Actor
, Effect
;
1424 if(version
<= 4){TryNextStr(&__buff
, '='); NextInt(&__buff
);} /* Marked = */
1425 if(version
>= 5)layer
= NextInt(&__buff
);
1426 hh1
= NextInt(&__buff
, ':');
1427 mm1
= NextInt(&__buff
, ':');
1428 ss1
= NextInt(&__buff
, '.');
1429 ms1_div10
= NextInt(&__buff
);
1430 hh2
= NextInt(&__buff
, ':');
1431 mm2
= NextInt(&__buff
, ':');
1432 ss2
= NextInt(&__buff
, '.');
1433 ms2_div10
= NextInt(&__buff
);
1434 Style
= WToT(TryNextStr(&__buff
));
1435 Actor
= WToT(TryNextStr(&__buff
));
1436 marginRect
.left
= NextInt(&__buff
);
1437 marginRect
.right
= NextInt(&__buff
);
1438 marginRect
.top
= marginRect
.bottom
= NextInt(&__buff
);
1439 if(version
>= 6)marginRect
.bottom
= NextInt(&__buff
);
1440 Effect
= WToT(TryNextStr(&__buff
));
1442 CStringW buff2
= __buff
;
1443 int len
= min(Effect
.GetLength(), buff2
.GetLength());
1444 if(Effect
.Left(len
) == WToT(buff2
.Left(len
))) Effect
.Empty();
1446 Style
.TrimLeft('*');
1447 if(!Style
.CompareNoCase(_T("Default"))) Style
= _T("Default");
1449 ret
.AddSTSEntryOnly(buff2
,
1451 (((hh1
*60 + mm1
)*60) + ss1
)*1000 + ms1_div10
*10,
1452 (((hh2
*60 + mm2
)*60) + ss2
)*1000 + ms2_div10
*10,
1453 Style
, Actor
, Effect
,
1464 else if(entry
== L
"[script info]")
1468 else if(entry
== L
"playresx")
1470 try {ret
.m_dstScreenSize
.cx
= GetInt(buff
);}
1471 catch(...) {ret
.m_dstScreenSize
= CSize(0, 0); return(false);}
1473 if(ret
.m_dstScreenSize
.cy
<= 0)
1475 ret
.m_dstScreenSize
.cy
= (ret
.m_dstScreenSize
.cx
== 1280)
1477 : ret
.m_dstScreenSize
.cx
* 3 / 4;
1480 else if(entry
== L
"playresy")
1482 try {ret
.m_dstScreenSize
.cy
= GetInt(buff
);}
1483 catch(...) {ret
.m_dstScreenSize
= CSize(0, 0); return(false);}
1485 if(ret
.m_dstScreenSize
.cx
<= 0)
1487 ret
.m_dstScreenSize
.cx
= (ret
.m_dstScreenSize
.cy
== 1024)
1489 : ret
.m_dstScreenSize
.cy
* 4 / 3;
1492 else if(entry
== L
"wrapstyle")
1494 try {ret
.m_defaultWrapStyle
= GetInt(buff
);}
1495 catch(...) {ret
.m_defaultWrapStyle
= 1; return(false);}
1497 else if(entry
== L
"scripttype")
1499 if(buff
.GetLength() >= 4 && !buff
.Right(4).CompareNoCase(L
"4.00")) version
= sver
= 4;
1500 else if(buff
.GetLength() >= 5 && !buff
.Right(5).CompareNoCase(L
"4.00+")) version
= sver
= 5;
1501 else if(buff
.GetLength() >= 6 && !buff
.Right(6).CompareNoCase(L
"4.00++")) version
= sver
= 6;
1503 else if(entry
== L
"collisions")
1505 buff
= GetStr(buff
);
1507 ret
.m_collisions
= buff
.Find(L
"reverse") >= 0 ? 1 : 0;
1509 else if(entry
== L
"scaledborderandshadow")
1511 buff
= GetStr(buff
);
1513 ret
.m_fScaledBAS
= buff
.Find(L
"yes") >= 0;
1515 else if(entry
== L
"[v4 styles]")
1520 else if(entry
== L
"[v4+ styles]")
1525 else if(entry
== L
"[v4++ styles]")
1530 else if(entry
== L
"style")
1532 STSStyle
* style
= new STSStyle
;
1533 if(!style
) return(false);
1541 StyleName
= WToT(GetStr(buff
));
1542 style
->fontName
= WToT(GetStr(buff
));
1543 style
->fontSize
= GetFloat(buff
);
1544 for(int i
= 0; i
< 4; i
++) style
->colors
[i
] = (COLORREF
)GetInt(buff
);
1545 style
->fontWeight
= !!GetInt(buff
) ? FW_BOLD
: FW_NORMAL
;
1546 style
->fItalic
= !!GetInt(buff
);
1547 if(sver
>= 5) style
->fUnderline
= !!GetInt(buff
);
1548 if(sver
>= 5) style
->fStrikeOut
= !!GetInt(buff
);
1549 if(sver
>= 5) style
->fontScaleX
= GetFloat(buff
);
1550 if(sver
>= 5) style
->fontScaleY
= GetFloat(buff
);
1551 if(sver
>= 5) style
->fontSpacing
= GetFloat(buff
);
1552 if(sver
>= 5) style
->fontAngleZ
= GetFloat(buff
);
1553 if(sver
>= 4) style
->borderStyle
= GetInt(buff
);
1554 style
->outlineWidthX
= style
->outlineWidthY
= GetFloat(buff
);
1555 style
->shadowDepthX
= style
->shadowDepthY
= GetFloat(buff
);
1556 style
->scrAlignment
= GetInt(buff
);
1557 tmp_rect
.left
= GetInt(buff
);
1558 tmp_rect
.right
= GetInt(buff
);
1559 tmp_rect
.top
= tmp_rect
.bottom
= GetInt(buff
);
1560 if(sver
>= 6) tmp_rect
.bottom
= GetInt(buff
);
1561 style
->marginRect
= tmp_rect
;
1562 if(sver
<= 4) alpha
= GetInt(buff
);
1563 style
->charSet
= GetInt(buff
);
1564 if(sver
>= 6) style
->relativeTo
= GetInt(buff
);
1566 if(sver
<= 4) style
->colors
[2] = style
->colors
[3]; // style->colors[2] is used for drawing the outline
1567 if(sver
<= 4) alpha
= max(min(alpha
, 0xff), 0);
1568 if(sver
<= 4) {for(int i
= 0; i
< 3; i
++) style
->alpha
[i
] = alpha
; style
->alpha
[3] = 0x80;}
1569 if(sver
>= 5) for(int i
= 0; i
< 4; i
++) {style
->alpha
[i
] = (BYTE
)(style
->colors
[i
]>>24); style
->colors
[i
] &= 0xffffff;}
1570 if(sver
>= 5) style
->fontScaleX
= max(style
->fontScaleX
, 0);
1571 if(sver
>= 5) style
->fontScaleY
= max(style
->fontScaleY
, 0);
1572 if(sver
>= 5) style
->fontSpacing
= max(style
->fontSpacing
, 0);
1573 style
->fontAngleX
= style
->fontAngleY
= 0;
1574 style
->borderStyle
= style
->borderStyle
== 1 ? 0 : style
->borderStyle
== 3 ? 1 : 0;
1575 style
->outlineWidthX
= max(style
->outlineWidthX
, 0);
1576 style
->outlineWidthY
= max(style
->outlineWidthY
, 0);
1577 style
->shadowDepthX
= max(style
->shadowDepthX
, 0);
1578 style
->shadowDepthY
= max(style
->shadowDepthY
, 0);
1579 if(sver
<= 4) style
->scrAlignment
= (style
->scrAlignment
&4) ? ((style
->scrAlignment
&3)+6) // top
1580 : (style
->scrAlignment
&8) ? ((style
->scrAlignment
&3)+3) // mid
1581 : (style
->scrAlignment
&3); // bottom
1583 StyleName
.TrimLeft('*');
1585 ret
.AddStyle(StyleName
, style
);
1593 else if(entry
== L
"[events]")
1597 // else if(entry == _T("dialogue"))
1601 // CStringW::PXSTR __buff = buff.GetBuffer();
1602 // int hh1, mm1, ss1, ms1_div10, hh2, mm2, ss2, ms2_div10, layer = 0;
1603 // CString Style, Actor, Effect;
1604 // CRect marginRect;
1606 //if(version <= 4){NextStr(&__buff, '='); NextInt(&__buff);} /* Marked = */
1607 //if(version >= 5)layer = NextInt(&__buff);
1608 // hh1 = NextInt(&__buff, ':');
1609 // mm1 = NextInt(&__buff, ':');
1610 // ss1 = NextInt(&__buff, '.');
1611 // ms1_div10 = NextInt(&__buff);
1612 // hh2 = NextInt(&__buff, ':');
1613 // mm2 = NextInt(&__buff, ':');
1614 // ss2 = NextInt(&__buff, '.');
1615 // ms2_div10 = NextInt(&__buff);
1616 // Style = WToT(NextStr(&__buff));
1617 // Actor = WToT(NextStr(&__buff));
1618 // marginRect.left = NextInt(&__buff);
1619 // marginRect.right = NextInt(&__buff);
1620 // marginRect.top = marginRect.bottom = NextInt(&__buff);
1621 //if(version >= 6)marginRect.bottom = NextInt(&__buff);
1622 // Effect = WToT(NextStr(&__buff));
1624 // int len = min(Effect.GetLength(), buff.GetLength());
1625 // if(Effect.Left(len) == WToT(buff.Left(len))) Effect.Empty();
1627 // Style.TrimLeft('*');
1628 // if(!Style.CompareNoCase(_T("Default"))) Style = _T("Default");
1630 // ret.AddSTSEntryOnly(__buff,
1631 // file->IsUnicode(),
1632 // (((hh1*60 + mm1)*60) + ss1)*1000 + ms1_div10*10,
1633 // (((hh2*60 + mm2)*60) + ss2)*1000 + ms2_div10*10,
1634 // Style, Actor, Effect,
1645 else if(entry
== L
"fontname")
1654 static bool OpenXombieSub(CTextFile
* file
, CSimpleTextSubtitle
& ret
, int CharSet
)
1658 // CMapStringToPtr stylemap;
1661 while(file
->ReadString(buff
))
1664 if(buff
.IsEmpty() || buff
.GetAt(0) == ';') continue;
1669 entry
= GetStr(buff
, '=');
1671 // catch(...) {continue;}
1675 if(entry
== L
"version")
1677 version
= (float)GetFloat(buff
);
1679 else if(entry
== L
"screenhorizontal")
1681 try {ret
.m_dstScreenSize
.cx
= GetInt(buff
);}
1682 catch(...) {ret
.m_dstScreenSize
= CSize(0, 0); return(false);}
1684 if(ret
.m_dstScreenSize
.cy
<= 0)
1686 ret
.m_dstScreenSize
.cy
= (ret
.m_dstScreenSize
.cx
== 1280)
1688 : ret
.m_dstScreenSize
.cx
* 3 / 4;
1691 else if(entry
== L
"screenvertical")
1693 try {ret
.m_dstScreenSize
.cy
= GetInt(buff
);}
1694 catch(...) {ret
.m_dstScreenSize
= CSize(0, 0); return(false);}
1696 if(ret
.m_dstScreenSize
.cx
<= 0)
1698 ret
.m_dstScreenSize
.cx
= (ret
.m_dstScreenSize
.cy
== 1024)
1700 : ret
.m_dstScreenSize
.cy
* 4 / 3;
1703 else if(entry
== L
"style")
1705 STSStyle
* style
= new STSStyle
;
1706 if(!style
) return(false);
1713 StyleName
= WToT(GetStr(buff
)) + _T("_") + WToT(GetStr(buff
));
1714 style
->fontName
= WToT(GetStr(buff
));
1715 style
->fontSize
= GetFloat(buff
);
1716 for(int i
= 0; i
< 4; i
++) style
->colors
[i
] = (COLORREF
)GetInt(buff
);
1717 for(int i
= 0; i
< 4; i
++) style
->alpha
[i
] = GetInt(buff
);
1718 style
->fontWeight
= !!GetInt(buff
) ? FW_BOLD
: FW_NORMAL
;
1719 style
->fItalic
= !!GetInt(buff
);
1720 style
->fUnderline
= !!GetInt(buff
);
1721 style
->fStrikeOut
= !!GetInt(buff
);
1722 style
->fBlur
= !!GetInt(buff
);
1723 style
->fontScaleX
= GetFloat(buff
);
1724 style
->fontScaleY
= GetFloat(buff
);
1725 style
->fontSpacing
= GetFloat(buff
);
1726 style
->fontAngleX
= GetFloat(buff
);
1727 style
->fontAngleY
= GetFloat(buff
);
1728 style
->fontAngleZ
= GetFloat(buff
);
1729 style
->borderStyle
= GetInt(buff
);
1730 style
->outlineWidthX
= style
->outlineWidthY
= GetFloat(buff
);
1731 style
->shadowDepthX
= style
->shadowDepthY
= GetFloat(buff
);
1732 style
->scrAlignment
= GetInt(buff
);
1734 tmp_rect
.left
= GetInt(buff
);
1735 tmp_rect
.right
= GetInt(buff
);
1736 tmp_rect
.top
= tmp_rect
.bottom
= GetInt(buff
);
1737 style
->marginRect
= tmp_rect
;
1739 style
->charSet
= GetInt(buff
);
1741 style
->fontScaleX
= max(style
->fontScaleX
, 0);
1742 style
->fontScaleY
= max(style
->fontScaleY
, 0);
1743 style
->fontSpacing
= max(style
->fontSpacing
, 0);
1744 style
->borderStyle
= style
->borderStyle
== 1 ? 0 : style
->borderStyle
== 3 ? 1 : 0;
1745 style
->outlineWidthX
= max(style
->outlineWidthX
, 0);
1746 style
->outlineWidthY
= max(style
->outlineWidthY
, 0);
1747 style
->shadowDepthX
= max(style
->shadowDepthX
, 0);
1748 style
->shadowDepthY
= max(style
->shadowDepthY
, 0);
1750 ret
.AddStyle(StyleName
, style
);
1758 else if(entry
== L
"line")
1763 int hh1
, mm1
, ss1
, ms1
, hh2
, mm2
, ss2
, ms2
, layer
= 0;
1764 CString Style
, Actor
;
1767 if(GetStr(buff
) != L
"D") continue;
1769 layer
= GetInt(buff
);
1770 hh1
= GetInt(buff
, ':');
1771 mm1
= GetInt(buff
, ':');
1772 ss1
= GetInt(buff
, '.');
1774 hh2
= GetInt(buff
, ':');
1775 mm2
= GetInt(buff
, ':');
1776 ss2
= GetInt(buff
, '.');
1778 Style
= WToT(GetStr(buff
)) + _T("_") + WToT(GetStr(buff
));
1779 Actor
= WToT(GetStr(buff
));
1780 marginRect
.left
= GetInt(buff
);
1781 marginRect
.right
= GetInt(buff
);
1782 marginRect
.top
= marginRect
.bottom
= GetInt(buff
);
1784 Style
.TrimLeft('*');
1785 if(!Style
.CompareNoCase(_T("Default"))) Style
= _T("Default");
1789 (((hh1
*60 + mm1
)*60) + ss1
)*1000 + ms1
,
1790 (((hh2
*60 + mm2
)*60) + ss2
)*1000 + ms2
,
1791 Style
, Actor
, _T(""),
1800 else if(entry
== L
"fontname")
1806 return(!ret
.IsEmpty());
1809 #include "USFSubtitles.h"
1811 static bool OpenUSF(CTextFile
* file
, CSimpleTextSubtitle
& ret
, int CharSet
)
1814 while(file
->ReadString(str
))
1816 if(str
.Find(_T("USFSubtitles")) >= 0)
1819 if(usf
.Read(file
->GetFilePath()) && usf
.ConvertToSTS(ret
))
1829 static CStringW
MPL22SSA(CStringW str
)
1831 CAtlList
<CStringW
> sl
;
1832 Explode(str
, sl
, '|');
1833 POSITION pos
= sl
.GetHeadPosition();
1836 CStringW
& s
= sl
.GetNext(pos
);
1837 if(s
[0] == '/') {s
= L
"{\\i1}" + s
.Mid(1) + L
"{\\i0}";}
1839 str
= Implode(sl
, '\n');
1840 str
.Replace(L
"\n", L
"\\N");
1844 static bool OpenMPL2(CTextFile
* file
, CSimpleTextSubtitle
& ret
, int CharSet
)
1847 while(file
->ReadString(buff
))
1850 if(buff
.IsEmpty()) continue;
1853 int c
= swscanf(buff
, L
"[%d][%d]", &start
, &end
);
1858 MPL22SSA(buff
.Mid(buff
.Find(']', buff
.Find(']')+1)+1)),
1860 start
*100, end
*100);
1862 else if(c
!= EOF
) // might be another format
1868 return(!ret
.IsEmpty());
1871 typedef bool (*STSOpenFunct
)(CTextFile
* file
, CSimpleTextSubtitle
& ret
, int CharSet
);
1873 static bool OpenRealText(CTextFile
* file
, CSimpleTextSubtitle
& ret
, int CharSet
);
1875 typedef struct {STSOpenFunct open
; tmode mode
;} OpenFunctStruct
;
1877 static OpenFunctStruct OpenFuncts
[] =
1879 OpenSubStationAlpha
, TIME
,
1880 OpenSubRipper
, TIME
,
1881 OpenOldSubRipper
, TIME
,
1882 OpenSubViewer
, TIME
,
1883 OpenMicroDVD
, FRAME
,
1886 OpenXombieSub
, TIME
,
1892 static int nOpenFuncts
= countof(OpenFuncts
);
1896 CSimpleTextSubtitle::CSimpleTextSubtitle()
1899 m_dstScreenSize
= CSize(0, 0);
1900 m_defaultWrapStyle
= 0;
1902 m_fScaledBAS
= false;
1903 m_encoding
= CTextFile::ASCII
;
1904 m_ePARCompensationType
= EPCTDisabled
;
1905 m_dPARCompensation
= 1.0;
1908 CSimpleTextSubtitle::~CSimpleTextSubtitle()
1913 CSimpleTextSubtitle::CSimpleTextSubtitle(CSimpleTextSubtitle& sts)
1918 CSimpleTextSubtitle& CSimpleTextSubtitle::operator = (CSimpleTextSubtitle& sts)
1922 m_name = sts.m_name;
1923 m_mode = sts.m_mode;
1924 m_dstScreenSize = sts.m_dstScreenSize;
1925 m_defaultWrapStyle = sts.m_defaultWrapStyle;
1926 m_collisions = sts.m_collisions;
1927 m_fScaledBAS = sts.m_fScaledBAS;
1928 m_fSSA = sts.m_fSSA;
1929 m_fUsingAutoGeneratedDefaultStyle = sts.m_fUsingAutoGeneratedDefaultStyle;
1930 CopyStyles(sts.m_styles);
1931 m_segments.Copy(sts.m_segments);
1938 void CSimpleTextSubtitle::Copy(CSimpleTextSubtitle
& sts
)
1942 m_name
= sts
.m_name
;
1943 m_mode
= sts
.m_mode
;
1944 m_dstScreenSize
= sts
.m_dstScreenSize
;
1945 m_defaultWrapStyle
= sts
.m_defaultWrapStyle
;
1946 m_collisions
= sts
.m_collisions
;
1947 m_fScaledBAS
= sts
.m_fScaledBAS
;
1948 m_encoding
= sts
.m_encoding
;
1949 m_fUsingAutoGeneratedDefaultStyle
= sts
.m_fUsingAutoGeneratedDefaultStyle
;
1950 CopyStyles(sts
.m_styles
);
1951 m_segments
.Copy(sts
.m_segments
);
1952 m_entries
.Copy(sts
.m_entries
);
1955 void CSimpleTextSubtitle::Append(CSimpleTextSubtitle
& sts
, int timeoff
)
1959 timeoff
= m_entries
.GetCount() > 0 ? m_entries
.GetAt(m_entries
.GetCount()-1).end
: 0;
1962 for(int i
= 0, j
= m_entries
.GetCount(); i
< j
; i
++)
1964 if(m_entries
.GetAt(i
).start
> timeoff
)
1966 m_entries
.RemoveAt(i
, j
- i
);
1971 CopyStyles(sts
.m_styles
, true);
1973 for(int i
= 0, j
= sts
.m_entries
.GetCount(); i
< j
; i
++)
1975 STSEntry stse
= sts
.m_entries
.GetAt(i
);
1976 stse
.start
+= timeoff
;
1977 stse
.end
+= timeoff
;
1978 stse
.readorder
+= m_entries
.GetCount();
1979 m_entries
.Add(stse
);
1985 void CSTSStyleMap::Free()
1987 POSITION pos
= GetStartPosition();
1992 GetNextAssoc(pos
, key
, val
);
1999 bool CSimpleTextSubtitle::CopyStyles(const CSTSStyleMap
& styles
, bool fAppend
)
2001 if(!fAppend
) m_styles
.Free();
2003 POSITION pos
= styles
.GetStartPosition();
2008 styles
.GetNextAssoc(pos
, key
, val
);
2010 STSStyle
* s
= new STSStyle
;
2011 if(!s
) return(false);
2021 void CSimpleTextSubtitle::Empty()
2023 m_dstScreenSize
= CSize(0, 0);
2025 m_segments
.RemoveAll();
2026 m_entries
.RemoveAll();
2029 void CSimpleTextSubtitle::Add(CStringW str
, bool fUnicode
, int start
, int end
,
2030 CString style
, const CString
& actor
, const CString
& effect
, const CRect
& marginRect
, int layer
, int readorder
)
2032 XY_LOG_INFO(start
<<_T(" ")<<end
<<_T(" ")<<str
.GetString()<<_T(" style:")<<style
.GetString()
2033 <<_T(" Unicode:")<<fUnicode
2034 <<_T(" actor:")<<actor
.GetString()<<_T(" effect:")<<effect
.GetString()
2035 <<_T(" (l:")<<marginRect
.left
<<_T(",t:")<<marginRect
.top
<<_T(",r:")<<marginRect
.right
<<_T(",b:")<<marginRect
.bottom
2036 <<_T(" layer:")<<layer
<<_T(" readorder:")<<readorder
2037 <<_T(" entries:")<<m_entries
.GetCount()<<_T(" seg:")<<m_segments
.GetCount());
2039 if(start
> end
|| str
.Trim().IsEmpty() ) return;
2042 str
.Replace(L
"\n", L
"\\N");
2043 if(style
.IsEmpty()) style
= g_default_style
;
2044 else if(style
!=g_default_style
)
2046 style
.TrimLeft('*');
2051 sub
.fUnicode
= fUnicode
;
2054 sub
.effect
= effect
;
2055 sub
.marginRect
= marginRect
;
2059 sub
.readorder
= readorder
< 0 ? m_entries
.GetCount() : readorder
;
2060 int n
= m_entries
.Add(sub
);
2062 int len
= m_segments
.GetCount();
2066 STSSegment
stss(start
, end
);
2068 m_segments
.Add(stss
);
2070 else if(end
<= m_segments
[0].start
)
2072 STSSegment
stss(start
, end
);
2074 m_segments
.InsertAt(0, stss
);
2076 else if(start
>= m_segments
[len
-1].end
)
2078 STSSegment
stss(start
, end
);
2080 m_segments
.Add(stss
);
2084 if(start
< m_segments
[0].start
)
2086 STSSegment
stss(start
, m_segments
[0].start
);
2088 start
= m_segments
[0].start
;
2089 m_segments
.InsertAt(0, stss
);
2092 for(size_t i
= 0; i
< m_segments
.GetCount(); i
++)
2094 STSSegment
& s
= m_segments
[i
];
2100 else if(end
<= s
.start
)
2104 else if(s
.start
< start
&& start
< s
.end
)
2106 STSSegment
stss(s
.start
, start
);
2107 stss
.subs
.Copy(s
.subs
);
2109 m_segments
.InsertAt(i
, stss
);
2112 if(start
<= s
.start
&& s
.end
<= end
)
2114 for(int j
= 0, k
= s
.subs
.GetCount(); j
<= k
; j
++)
2116 if(j
== k
|| sub
.readorder
< m_entries
.GetAt(s
.subs
[j
]).readorder
)
2118 s
.subs
.InsertAt(j
, n
);
2123 else if(s
.start
< end
&& end
< s
.end
)
2125 STSSegment
stss(s
.start
, end
);
2126 stss
.subs
.Copy(s
.subs
);
2127 for(int j
= 0, k
= s
.subs
.GetCount(); j
<= k
; j
++)
2129 if(j
== k
|| sub
.readorder
< m_entries
.GetAt(stss
.subs
[j
]).readorder
)
2131 stss
.subs
.InsertAt(j
, n
);
2136 m_segments
.InsertAt(i
, stss
);
2140 if(end
> m_segments
[m_segments
.GetCount()-1].end
)
2142 STSSegment
stss(m_segments
[m_segments
.GetCount()-1].end
, end
);
2144 m_segments
.Add(stss
);
2149 str.Replace(L"\n", L"\\N");
2150 if(style.IsEmpty()) style = _T("Default");
2152 int j = m_segments.GetCount();
2153 for(int i = j-1; i >= 0; i--)
2155 if(m_segments[i].end <= start)
2159 else if(m_segments[i].start >= start)
2161 m_segments.SetCount(m_segments.GetCount()-1);
2164 else if(m_segments[i].end > start)
2166 if(i < j-1) m_segments.RemoveAt(i+1, j-i-1);
2167 m_segments[i].end = start;
2172 if(m_segments.GetCount() == 0 && j > 0)
2173 CSTSArray::RemoveAll();
2175 STSSegment stss(start, end);
2176 int len = m_entries.GetCount();
2178 m_segments.Add(stss);
2182 sub.fUnicode = fUnicode;
2185 sub.effect = effect;
2186 sub.marginRect = marginRect;
2190 sub.readorder = m_entries.GetCount();
2191 CSTSArray::Add(sub);
2195 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*/ )
2197 if(str
.Trim().IsEmpty() || start
> end
) return;
2200 str
.Replace(L
"\n", L
"\\N");
2201 if(style
.IsEmpty()) style
= _T("Default");
2202 style
.TrimLeft('*');
2206 sub
.fUnicode
= fUnicode
;
2209 sub
.effect
= effect
;
2210 sub
.marginRect
= marginRect
;
2214 sub
.readorder
= readorder
< 0 ? m_entries
.GetCount() : readorder
;
2219 STSStyle
* CSimpleTextSubtitle::CreateDefaultStyle(int CharSet
)
2221 STSStyle
* ret
= NULL
;
2223 if(!m_styles
.Lookup(g_default_style
, ret
))
2225 STSStyle
* style
= new STSStyle();
2226 style
->charSet
= CharSet
;
2227 AddStyle(g_default_style
, style
);
2228 m_styles
.Lookup(g_default_style
, ret
);
2230 m_fUsingAutoGeneratedDefaultStyle
= true;
2234 m_fUsingAutoGeneratedDefaultStyle
= false;
2240 void CSimpleTextSubtitle::ChangeUnknownStylesToDefault()
2242 CAtlMap
<CString
, STSStyle
*, CStringElementTraits
<CString
> > unknown
;
2243 bool fReport
= true;
2245 for(size_t i
= 0; i
< m_entries
.GetCount(); i
++)
2247 STSEntry
& stse
= m_entries
.GetAt(i
);
2250 if(!m_styles
.Lookup(stse
.style
, val
))
2252 if(!unknown
.Lookup(stse
.style
, val
))
2257 msg
.Format(_T("Unknown style found: \"%s\", changed to \"Default\"!\n\nPress Cancel to ignore further warnings."), stse
.style
);
2258 if(MessageBox(NULL
, msg
, _T("Warning"), MB_OKCANCEL
|MB_ICONWARNING
) != IDOK
) fReport
= false;
2261 unknown
[stse
.style
] = NULL
;
2264 stse
.style
= g_default_style
;
2269 void CSimpleTextSubtitle::AddStyle(CString name
, STSStyle
* style
)
2273 if(name
.IsEmpty()) name
= g_default_style
;
2276 if(m_styles
.Lookup(name
, val
))
2283 const CString
& name_str
= name
;
2285 int len
= name_str
.GetLength();
2287 for(i
= len
; i
> 0 && _istdigit(name_str
[i
-1]); i
--);
2291 CString name2
= name_str
;
2293 if(i
< len
&& _stscanf(name_str
.Right(len
-i
), _T("%d"), &idx
) == 1)
2295 name2
= name_str
.Left(i
);
2304 name3_str
.Format(_T("%s%d"), name2
, idx
);
2308 while(m_styles
.Lookup(name3
));
2310 m_styles
.RemoveKey(name
);
2311 m_styles
[name3
] = val
;
2313 for(i
= 0, j
= m_entries
.GetCount(); i
< j
; i
++)
2315 STSEntry
& stse
= m_entries
.GetAt(i
);
2316 if(stse
.style
== name
) stse
.style
= name3
;
2320 m_styles
[name
] = style
;
2323 bool CSimpleTextSubtitle::SetDefaultStyle(STSStyle
& s
)
2325 DbgLog((LOG_TRACE
, 3, "%s(%d): %s", __FILE__
, __LINE__
, __FUNCTION__
));
2326 DbgLog((LOG_TRACE
, 3, "\tm_styles count:%d", m_styles
.GetCount()));
2328 if(!m_styles
.Lookup(g_default_style
, val
)) return false;
2329 DbgLog((LOG_TRACE
, 3, "\tm_styles Lookup Default succeed"));
2332 for(POSITION pos
=m_styles
.GetStartPosition(); pos
!=NULL
;)
2334 DbgLog((LOG_TRACE
, 3, _T("\tm_styles[%s]"), (LPCTSTR
)m_styles
.GetNextKey(pos
)));
2339 m_fUsingAutoGeneratedDefaultStyle
= false;
2343 bool CSimpleTextSubtitle::GetDefaultStyle(STSStyle
& s
)
2346 if(!m_styles
.Lookup(g_default_style
, val
)) return false;
2351 void CSimpleTextSubtitle::ConvertToTimeBased(double fps
)
2353 if(m_mode
== TIME
) return;
2355 for(int i
= 0, j
= m_entries
.GetCount(); i
< j
; i
++)
2357 STSEntry
& stse
= m_entries
[i
];
2358 stse
.start
= int(1.0 * stse
.start
* 1000 / fps
+ 0.5);
2359 stse
.end
= int(1.0 * stse
.end
* 1000 / fps
+ 0.5);
2367 void CSimpleTextSubtitle::ConvertToFrameBased(double fps
)
2369 if(m_mode
== FRAME
) return;
2371 for(int i
= 0, j
= m_entries
.GetCount(); i
< j
; i
++)
2373 STSEntry
& stse
= m_entries
[i
];
2374 stse
.start
= int(1.0 * stse
.start
* fps
/ 1000 + 0.5);
2375 stse
.end
= int(1.0 * stse
.end
* fps
/ 1000 + 0.5);
2383 int CSimpleTextSubtitle::SearchSub(int t
, double fps
)
2385 int i
= 0, j
= m_entries
.GetCount() - 1, ret
= -1;
2387 if(j
>= 0 && t
>= TranslateStart(j
, fps
))
2394 int mid
= (i
+ j
) >> 1;
2396 int midt
= TranslateStart(mid
, fps
);
2400 while(mid
> 0 && t
== TranslateStart(mid
-1, fps
)) mid
--;
2421 const STSSegment
* CSimpleTextSubtitle::SearchSubs(int t
, double fps
, /*[out]*/ int* iSegment
, int* nSegments
)
2423 int segmentsCount
= m_segments
.GetCount();
2424 int i
= 0, j
= segmentsCount
- 1;
2426 if(nSegments
) *nSegments
= segmentsCount
;
2427 if(segmentsCount
<=0)
2434 if(t
>= TranslateSegmentEnd(j
, fps
))
2439 if(t
< TranslateSegmentEnd(i
, fps
))
2447 int mid
= (i
+ j
) >> 1;
2449 int midt
= TranslateSegmentEnd(mid
, fps
);
2460 return &m_segments
[j
];
2465 STSSegment
* CSimpleTextSubtitle::SearchSubs2(int t
, double fps
, /*[out]*/ int* iSegment
, int* nSegments
)
2467 int segmentsCount
= m_segments
.GetCount();
2468 int i
= 0, j
= segmentsCount
- 1;
2470 if(iSegment
) *iSegment
= -1;
2471 if(nSegments
) *nSegments
= segmentsCount
;
2473 if(segmentsCount
<=0)
2475 if(iSegment
) *iSegment
= 0;
2479 if(t
>= TranslateSegmentEnd(j
, fps
))
2484 if(t
< TranslateSegmentEnd(i
, fps
))
2492 int mid
= (i
+ j
) >> 1;
2494 int midt
= TranslateSegmentEnd(mid
, fps
);
2501 if(j
<segmentsCount
&& t
>=TranslateSegmentStart(j
, fps
))
2503 if(iSegment
) *iSegment
= j
;
2504 return &m_segments
[j
];
2511 int CSimpleTextSubtitle::TranslateStart(int i
, double fps
)
2513 return(i
< 0 || m_entries
.GetCount() <= i
? -1 :
2514 m_mode
== TIME
? m_entries
.GetAt(i
).start
:
2515 m_mode
== FRAME
? (int)(m_entries
.GetAt(i
).start
*1000/fps
) :
2519 int CSimpleTextSubtitle::TranslateEnd(int i
, double fps
)
2521 return(i
< 0 || m_entries
.GetCount() <= i
? -1 :
2522 m_mode
== TIME
? m_entries
.GetAt(i
).end
:
2523 m_mode
== FRAME
? (int)(m_entries
.GetAt(i
).end
*1000/fps
) :
2527 int CSimpleTextSubtitle::TranslateSegmentStart(int i
, double fps
)
2529 return(i
< 0 || m_segments
.GetCount() <= i
? -1 :
2530 m_mode
== TIME
? m_segments
[i
].start
:
2531 m_mode
== FRAME
? (int)(m_segments
[i
].start
*1000/fps
) :
2535 int CSimpleTextSubtitle::TranslateSegmentEnd(int i
, double fps
)
2537 return(i
< 0 || m_segments
.GetCount() <= i
? -1 :
2538 m_mode
== TIME
? m_segments
[i
].end
:
2539 m_mode
== FRAME
? (int)(m_segments
[i
].end
*1000/fps
) :
2543 void CSimpleTextSubtitle::TranslateSegmentStartEnd(int i
, double fps
, /*out*/int& start
, /*out*/int& end
)
2545 if(i
< 0 || m_segments
.GetCount() <= i
)
2554 start
= m_segments
[i
].start
;
2555 end
= m_segments
[i
].end
;
2557 else //m_mode == FRAME
2559 start
= (int)(m_segments
[i
].start
*1000/fps
);
2560 end
= (int)(m_segments
[i
].end
*1000/fps
);
2565 STSStyle
* CSimpleTextSubtitle::GetStyle(int i
)
2567 STSStyle
* style
= NULL
;
2568 m_styles
.Lookup(m_entries
.GetAt(i
).style
, style
);
2570 STSStyle
* defstyle
= NULL
;
2571 m_styles
.Lookup(g_default_style
, defstyle
);
2583 bool CSimpleTextSubtitle::GetStyle(int i
, STSStyle
* const stss
)
2585 STSStyle
* style
= NULL
;
2586 m_styles
.Lookup(m_entries
.GetAt(i
).style
, style
);
2588 STSStyle
* defstyle
= NULL
;
2589 m_styles
.Lookup(g_default_style
, defstyle
);
2595 defstyle
= CreateDefaultStyle(DEFAULT_CHARSET
);
2601 if(!style
) {ASSERT(0); return false;}
2604 if(stss
->relativeTo
== 2 && defstyle
)
2605 stss
->relativeTo
= defstyle
->relativeTo
;
2610 int CSimpleTextSubtitle::GetCharSet(int i
)
2612 STSStyle
* style
= GetStyle(i
);
2613 return style
!=NULL
? style
->charSet
: -1;
2616 bool CSimpleTextSubtitle::IsEntryUnicode(int i
)
2618 return(m_entries
.GetAt(i
).fUnicode
);
2621 void CSimpleTextSubtitle::ConvertUnicode(int i
, bool fUnicode
)
2623 STSEntry
& stse
= m_entries
.GetAt(i
);
2625 if(stse
.fUnicode
^ fUnicode
)
2627 int CharSet
= GetCharSet(i
);
2630 ? MBCSSSAToUnicode(stse
.str
, CharSet
)
2631 : UnicodeSSAToMBCS(stse
.str
, CharSet
);
2633 stse
.fUnicode
= fUnicode
;
2637 CStringA
CSimpleTextSubtitle::GetStrA(int i
, bool fSSA
)
2639 return(WToA(GetStrWA(i
, fSSA
)));
2642 CStringW
CSimpleTextSubtitle::GetStrW(int i
, bool fSSA
)
2644 bool fUnicode
= IsEntryUnicode(i
);
2645 int CharSet
= GetCharSet(i
);
2647 CStringW str
= m_entries
.GetAt(i
).str
;
2650 str
= MBCSSSAToUnicode(str
, CharSet
);
2653 str
= RemoveSSATags(str
, fUnicode
, CharSet
);
2658 CStringW
CSimpleTextSubtitle::GetStrWA(int i
, bool fSSA
)
2660 bool fUnicode
= IsEntryUnicode(i
);
2661 int CharSet
= GetCharSet(i
);
2663 CStringW str
= m_entries
.GetAt(i
).str
;
2666 str
= UnicodeSSAToMBCS(str
, CharSet
);
2669 str
= RemoveSSATags(str
, fUnicode
, CharSet
);
2674 void CSimpleTextSubtitle::SetStr(int i
, CStringA str
, bool fUnicode
)
2676 SetStr(i
, AToW(str
), false);
2679 void CSimpleTextSubtitle::SetStr(int i
, CStringW str
, bool fUnicode
)
2681 STSEntry
& stse
= m_entries
.GetAt(i
);
2683 str
.Replace(L
"\n", L
"\\N");
2685 if(stse
.fUnicode
&& !fUnicode
) stse
.str
= MBCSSSAToUnicode(str
, GetCharSet(i
));
2686 else if(!stse
.fUnicode
&& fUnicode
) stse
.str
= UnicodeSSAToMBCS(str
, GetCharSet(i
));
2687 else stse
.str
= str
;
2690 static int comp1(const void* a
, const void* b
)
2692 int ret
= ((STSEntry
*)a
)->start
- ((STSEntry
*)b
)->start
;
2693 if(ret
== 0) ret
= ((STSEntry
*)a
)->layer
- ((STSEntry
*)b
)->layer
;
2694 if(ret
== 0) ret
= ((STSEntry
*)a
)->readorder
- ((STSEntry
*)b
)->readorder
;
2698 static int comp2(const void* a
, const void* b
)
2700 return(((STSEntry
*)a
)->readorder
- ((STSEntry
*)b
)->readorder
);
2703 void CSimpleTextSubtitle::Sort(bool fRestoreReadorder
)
2705 qsort(m_entries
.GetData(), m_entries
.GetCount(), sizeof(STSEntry
), !fRestoreReadorder
? comp1
: comp2
);
2709 static int intcomp(const void* i1
, const void* i2
)
2711 return(*((int*)i1
) - *((int*)i2
));
2714 void CSimpleTextSubtitle::CreateSegments()
2716 m_segments
.RemoveAll();
2718 if(m_entries
.GetCount()>0)
2720 size_t start
, mid
, end
;
2721 CAtlArray
<STSSegment
> tempSegments
;//if add to m_segments directly, then remove empty entities can be a
2722 //complex operation when having large segmentCount and lots of empty entities
2723 std::vector
<int> breakpoints(2*m_entries
.GetCount());
2724 for(size_t i
= 0; i
< m_entries
.GetCount(); i
++)
2726 STSEntry
& stse
= m_entries
.GetAt(i
);
2727 breakpoints
[2*i
]=stse
.start
;
2728 breakpoints
[2*i
+1]=stse
.end
;
2731 std::sort(breakpoints
.begin(), breakpoints
.end());
2733 int ptr
= 1, prev
= breakpoints
[0];
2734 for(size_t i
= breakpoints
.size()-1; i
> 0; i
--, ptr
++)
2736 if(breakpoints
[ptr
] != prev
)
2738 tempSegments
.Add(STSSegment(prev
, breakpoints
[ptr
]));
2739 prev
= breakpoints
[ptr
];
2743 size_t segmentCount
= tempSegments
.GetCount();
2745 for(size_t i
= 0; i
< m_entries
.GetCount(); i
++)
2747 STSEntry
& stse
= m_entries
.GetAt(i
);
2752 mid
= (start
+end
)>>1;
2753 if(tempSegments
[mid
].start
< stse
.start
)
2762 for(; start
< tempSegments
.GetCount() && tempSegments
[start
].end
<= stse
.end
; start
++)
2763 tempSegments
[start
].subs
.Add(i
);
2765 for(size_t i
= 0; i
< segmentCount
; i
++)
2766 if(tempSegments
[i
].subs
.GetCount()>0)
2767 m_segments
.Add(tempSegments
[i
]);
2771 for(i = 0, j = m_segments.GetCount(); i < j; i++)
2773 STSSegment& stss = m_segments[i];
2775 TRACE(_T("%d - %d"), stss.start, stss.end);
2777 for(int k = 0, l = stss.subs.GetCount(); k < l; k++)
2779 TRACE(_T(", %d"), stss.subs[k]);
2787 bool CSimpleTextSubtitle::Open(CString fn
, int CharSet
, CString name
)
2792 if(!f
.Open(fn
)) return(false);
2794 fn
.Replace('\\', '/');
2797 name
= fn
.Left(fn
.ReverseFind('.'));
2798 name
= name
.Mid(name
.ReverseFind('/')+1);
2799 name
= name
.Mid(name
.ReverseFind('.')+1);
2802 return(Open(&f
, CharSet
, name
));
2805 static int CountLines(CTextFile
* f
, ULONGLONG from
, ULONGLONG to
)
2810 while(f
->ReadString(s
) && f
->GetPosition() < to
) n
++;
2814 bool CSimpleTextSubtitle::Open(CTextFile
* f
, int CharSet
, CString name
)
2818 ULONGLONG pos
= f
->GetPosition();
2820 for(int i
= 0; i
< nOpenFuncts
; i
++)
2822 const TCHAR
* func_name
[]={
2823 TEXT("OpenSubStationAlpha"),
2824 TEXT("OpenSubRipper"),
2825 TEXT("OpenOldSubRipper"),
2826 TEXT("OpenSubViewer"),
2827 TEXT("OpenMicroDVD"),
2829 TEXT("OpenVPlayer"),
2830 TEXT("OpenXombieSub"),
2833 TEXT("OpenRealText")};
2834 CAutoTiming
t(func_name
[i
],0);
2836 if(!OpenFuncts
[i
].open(f
, *this, CharSet
) /*|| !GetCount()*/)
2838 if(m_entries
.GetCount() > 0)
2840 int n
= CountLines(f
, pos
, f
->GetPosition());
2842 s
.Format(_T("Syntax error at line %d!\t"), n
+1);
2843 AfxMessageBox(s
, MB_OK
|MB_ICONERROR
);
2854 m_mode
= OpenFuncts
[i
].mode
;
2855 m_encoding
= f
->GetEncoding();
2856 m_path
= f
->GetFilePath();
2859 if(f2
.Open(f
->GetFilePath() + _T(".style")))
2860 OpenSubStationAlpha(&f2
, *this, CharSet
);
2865 CreateDefaultStyle(CharSet
);
2867 ChangeUnknownStylesToDefault();
2869 if(m_dstScreenSize
== CSize(0, 0)) m_dstScreenSize
= CSize(384, 288);
2877 bool CSimpleTextSubtitle::Open(BYTE
* data
, int len
, int CharSet
, CString name
)
2879 TCHAR path
[MAX_PATH
];
2880 if(!GetTempPath(MAX_PATH
, path
)) return(false);
2883 if(!GetTempFileName(path
, _T("vs"), 0, fn
)) return(false);
2885 FILE* tmp
= _tfopen(fn
, _T("wb"));
2886 if(!tmp
) return(false);
2889 for(; i
<= (len
-1024); i
+= 1024) fwrite(&data
[i
], 1024, 1, tmp
);
2890 if(len
> i
) fwrite(&data
[i
], len
- i
, 1, tmp
);
2894 bool fRet
= Open(fn
, CharSet
, name
);
2901 bool CSimpleTextSubtitle::SaveAs(CString fn
, exttype et
, double fps
, CTextFile::enc e
)
2903 if(fn
.Mid(fn
.ReverseFind('.')+1).CompareNoCase(exttypestr
[et
]))
2905 if(fn
[fn
.GetLength()-1] != '.') fn
+= _T(".");
2906 fn
+= exttypestr
[et
];
2917 str
+= _T("<SAMI>\n<HEAD>\n");
2918 str
+= _T("<STYLE TYPE=\"text/css\">\n");
2919 str
+= _T("<!--\n");
2920 str
+= _T("P {margin-left: 16pt; margin-right: 16pt; margin-bottom: 16pt; margin-top: 16pt;\n");
2921 str
+= _T(" text-align: center; font-size: 18pt; font-family: arial; font-weight: bold; color: #f0f0f0;}\n");
2922 str
+= _T(".UNKNOWNCC {Name:Unknown; lang:en-US; SAMIType:CC;}\n");
2924 str
+= _T("</STYLE>\n");
2925 str
+= _T("</HEAD>\n");
2927 str
+= _T("<BODY>\n");
2931 else if(et
== EXTSSA
|| et
== EXTASS
)
2935 str
= _T("[Script Info]\n");
2936 str
+= (et
== EXTSSA
) ? _T("; This is a Sub Station Alpha v4 script.\n") : _T("; This is an Advanced Sub Station Alpha v4+ script.\n");
2937 str
+= _T("; For Sub Station Alpha info and downloads,\n");
2938 str
+= _T("; go to http://www.eswat.demon.co.uk/\n");
2939 str
+= _T("; or email kotus@eswat.demon.co.uk\n");
2943 str
+= _T("; Advanced Sub Station Alpha script format developed by #Anime-Fansubs@EfNET\n");
2944 str
+= _T("; http://www.anime-fansubs.org\n");
2946 str
+= _T("; For additional info and downloads go to http://gabest.org/\n");
2947 str
+= _T("; or email gabest@freemail.hu\n");
2950 str
+= _T("; Note: This file was saved by Subresync.\n");
2952 str
+= (et
== EXTSSA
) ? _T("ScriptType: v4.00\n") : _T("ScriptType: v4.00+\n");
2953 str
+= (m_collisions
== 0) ? _T("Collisions: Normal\n") : _T("Collisions: Reverse\n");
2954 if(et
== EXTASS
&& m_fScaledBAS
) str
+= _T("ScaledBorderAndShadow: Yes\n");
2955 str
+= _T("PlayResX: %d\n");
2956 str
+= _T("PlayResY: %d\n");
2957 str
+= _T("Timer: 100.0000\n");
2959 str
+= (et
== EXTSSA
)
2960 ? _T("[V4 Styles]\nFormat: Name, Fontname, Fontsize, PrimaryColour, SecondaryColour, TertiaryColour, BackColour, Bold, Italic, BorderStyle, Outline, Shadow, Alignment, MarginL, MarginR, MarginV, AlphaLevel, Encoding\n")
2961 : _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");
2964 str2
.Format(str
, m_dstScreenSize
.cx
, m_dstScreenSize
.cy
);
2965 f
.WriteString(str2
);
2967 str
= (et
== EXTSSA
)
2968 ? _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")
2969 : _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");
2971 POSITION pos
= m_styles
.GetStartPosition();
2976 m_styles
.GetNextAssoc(pos
, key
, s
);
2981 str2
.Format(str
, key
,
2982 s
->fontName
, (int)s
->fontSize
,
2983 s
->colors
[0]&0xffffff,
2984 s
->colors
[1]&0xffffff,
2985 s
->colors
[2]&0xffffff,
2986 s
->colors
[3]&0xffffff,
2987 s
->fontWeight
> FW_NORMAL
? -1 : 0, s
->fItalic
? -1 : 0,
2988 s
->borderStyle
== 0 ? 1 : s
->borderStyle
== 1 ? 3 : 0,
2989 (int)s
->outlineWidthY
, (int)s
->shadowDepthY
,
2990 s
->scrAlignment
<= 3 ? s
->scrAlignment
: s
->scrAlignment
<= 6 ? ((s
->scrAlignment
-3)|8) : s
->scrAlignment
<= 9 ? ((s
->scrAlignment
-6)|4) : 2,
2991 s
->marginRect
.get().left
, s
->marginRect
.get().right
, (s
->marginRect
.get().top
+ s
->marginRect
.get().bottom
) / 2,
2994 f
.WriteString(str2
);
2999 str2
.Format(str
, key
,
3000 s
->fontName
, (int)s
->fontSize
,
3001 (s
->colors
[0]&0xffffff) | (s
->alpha
[0]<<24),
3002 (s
->colors
[1]&0xffffff) | (s
->alpha
[1]<<24),
3003 (s
->colors
[2]&0xffffff) | (s
->alpha
[2]<<24),
3004 (s
->colors
[3]&0xffffff) | (s
->alpha
[3]<<24),
3005 s
->fontWeight
> FW_NORMAL
? -1 : 0,
3006 s
->fItalic
? -1 : 0, s
->fUnderline
? -1 : 0, s
->fStrikeOut
? -1 : 0,
3007 (int)s
->fontScaleX
, (int)s
->fontScaleY
,
3008 (int)s
->fontSpacing
, (float)s
->fontAngleZ
,
3009 s
->borderStyle
== 0 ? 1 : s
->borderStyle
== 1 ? 3 : 0,
3010 (int)s
->outlineWidthY
, (int)s
->shadowDepthY
,
3012 s
->marginRect
.get().left
, s
->marginRect
.get().right
, (s
->marginRect
.get().top
+ s
->marginRect
.get().bottom
) / 2,
3014 f
.WriteString(str2
);
3018 if(m_entries
.GetCount() > 0)
3021 str
+= _T("[Events]\n");
3022 str
+= (et
== EXTSSA
)
3023 ? _T("Format: Marked, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text\n")
3024 : _T("Format: Layer, Start, End, Style, Actor, MarginL, MarginR, MarginV, Effect, Text\n");
3030 et
== EXTSRT
? L
"%d\n%02d:%02d:%02d,%03d --> %02d:%02d:%02d,%03d\n%s\n\n" :
3031 et
== EXTSUB
? L
"{%d}{%d}%s\n" :
3032 et
== EXTSMI
? L
"<SYNC Start=%d><P Class=UNKNOWNCC>\n%s\n<SYNC Start=%d><P Class=UNKNOWNCC> \n" :
3033 et
== EXTPSB
? L
"{%d:%02d:%02d}{%d:%02d:%02d}%s\n" :
3034 et
== EXTSSA
? L
"Dialogue: Marked=0,%d:%02d:%02d.%02d,%d:%02d:%02d.%02d,%s,%s,%04d,%04d,%04d,%s,%s\n" :
3035 et
== EXTASS
? L
"Dialogue: %d,%d:%02d:%02d.%02d,%d:%02d:%02d.%02d,%s,%s,%04d,%04d,%04d,%s,%s\n" :
3039 for(int i
= 0, j
= m_entries
.GetCount(), k
= 0; i
< j
; i
++)
3041 STSEntry
& stse
= m_entries
.GetAt(i
);
3043 int t1
= TranslateStart(i
, fps
);
3044 if(t1
< 0) {k
++; continue;}
3046 int t2
= TranslateEnd(i
, fps
);
3048 int hh1
= (t1
/60/60/1000);
3049 int mm1
= (t1
/60/1000)%60;
3050 int ss1
= (t1
/1000)%60;
3051 int ms1
= (t1
)%1000;
3052 int hh2
= (t2
/60/60/1000);
3053 int mm2
= (t2
/60/1000)%60;
3054 int ss2
= (t2
/1000)%60;
3055 int ms2
= (t2
)%1000;
3057 CStringW str
= f
.IsUnicode()
3058 ? GetStrW(i
, et
== EXTSSA
|| et
== EXTASS
)
3059 : GetStrWA(i
, et
== EXTSSA
|| et
== EXTASS
);
3065 str2
.Format(fmt
, i
-k
+1, hh1
, mm1
, ss1
, ms1
, hh2
, mm2
, ss2
, ms2
, str
);
3067 else if(et
== EXTSUB
)
3069 str
.Replace('\n', '|');
3070 str2
.Format(fmt
, int(t1
*fps
/1000), int(t2
*fps
/1000), str
);
3072 else if(et
== EXTSMI
)
3074 str
.Replace(L
"\n", L
"<br>");
3075 str2
.Format(fmt
, t1
, str
, t2
);
3077 else if(et
== EXTPSB
)
3079 str
.Replace('\n', '|');
3080 str2
.Format(fmt
, hh1
, mm1
, ss1
, hh2
, mm2
, ss2
, str
);
3082 else if(et
== EXTSSA
)
3084 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
);
3092 else if(et
== EXTASS
)
3094 str
.Replace(L
"\n", L
"\\N");
3097 hh1
, mm1
, ss1
, ms1
/10,
3098 hh2
, mm2
, ss2
, ms2
/10,
3099 TToW(stse
.style
), TToW(stse
.actor
),
3100 stse
.marginRect
.left
, stse
.marginRect
.right
, (stse
.marginRect
.top
+ stse
.marginRect
.bottom
) / 2,
3101 TToW(stse
.effect
), str
);
3104 f
.WriteString(str2
);
3111 f
.WriteString(_T("</BODY>\n</SAMI>\n"));
3115 if(!m_fUsingAutoGeneratedDefaultStyle
&& m_styles
.Lookup(g_default_style
, s
) && et
!= EXTSSA
&& et
!= EXTASS
)
3118 if(!f
.Save(fn
+ _T(".style"), e
))
3123 str
+= _T("ScriptType: v4.00+\n");
3124 str
+= _T("PlayResX: %d\n");
3125 str
+= _T("PlayResY: %d\n");
3127 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");
3128 str2
.Format(str
, m_dstScreenSize
.cx
, m_dstScreenSize
.cy
);
3129 f
.WriteString(str2
);
3131 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");
3133 s
->fontName
, (int)s
->fontSize
,
3134 (s
->colors
[0]&0xffffff) | (s
->alpha
[0]<<24),
3135 (s
->colors
[1]&0xffffff) | (s
->alpha
[1]<<24),
3136 (s
->colors
[2]&0xffffff) | (s
->alpha
[2]<<24),
3137 (s
->colors
[3]&0xffffff) | (s
->alpha
[3]<<24),
3138 s
->fontWeight
> FW_NORMAL
? -1 : 0,
3139 s
->fItalic
? -1 : 0, s
->fUnderline
? -1 : 0, s
->fStrikeOut
? -1 : 0,
3140 (int)s
->fontScaleX
, (int)s
->fontScaleY
,
3141 (int)s
->fontSpacing
, (float)s
->fontAngleZ
,
3142 s
->borderStyle
== 0 ? 1 : s
->borderStyle
== 1 ? 3 : 0,
3143 (int)s
->outlineWidthY
, (int)s
->shadowDepthY
,
3145 s
->marginRect
.get().left
, s
->marginRect
.get().right
, (s
->marginRect
.get().top
+ s
->marginRect
.get().bottom
) / 2,
3147 f
.WriteString(str2
);
3153 bool CSimpleTextSubtitle::IsEmpty()
3155 return m_entries
.IsEmpty();
3158 void CSimpleTextSubtitle::RemoveAllEntries()
3160 m_entries
.RemoveAll();
3163 ////////////////////////////////////////////////////////////////////
3165 bool STSStyleBase::operator==( const STSStyleBase
& s
) const
3167 return charSet
== s
.charSet
3168 && fontName
== s
.fontName
3169 && fontSize
== s
.fontSize
3170 && fontWeight
== s
.fontWeight
3171 && fItalic
== s
.fItalic
3172 && fUnderline
== s
.fUnderline
3173 && fStrikeOut
== s
.fStrikeOut
;
3176 STSStyle::STSStyle()
3181 void STSStyle::SetDefault()
3183 marginRect
= CRect(20, 20, 20, 20);
3186 outlineWidthX
= outlineWidthY
= 2;
3187 shadowDepthX
= shadowDepthY
= 3;
3188 colors
[0] = 0x00ffffff;
3189 colors
[1] = 0x0000ffff;
3190 colors
[2] = 0x00000000;
3191 colors
[3] = 0x00000000;
3196 charSet
= DEFAULT_CHARSET
;
3197 fontName
= _T("Arial");
3199 fontScaleX
= fontScaleY
= 100;
3201 fontWeight
= FW_BOLD
;
3207 fontShiftX
= fontShiftY
= fontAngleZ
= fontAngleX
= fontAngleY
= 0;
3211 bool STSStyle::operator == (const STSStyle
& s
)const
3213 return(marginRect
== s
.marginRect
3214 && scrAlignment
== s
.scrAlignment
3215 && borderStyle
== s
.borderStyle
3216 && outlineWidthX
== s
.outlineWidthX
3217 && outlineWidthY
== s
.outlineWidthY
3218 && shadowDepthX
== s
.shadowDepthX
3219 && shadowDepthY
== s
.shadowDepthY
3220 && *((int*)&colors
[0]) == *((int*)&s
.colors
[0])
3221 && *((int*)&colors
[1]) == *((int*)&s
.colors
[1])
3222 && *((int*)&colors
[2]) == *((int*)&s
.colors
[2])
3223 && *((int*)&colors
[3]) == *((int*)&s
.colors
[3])
3224 && alpha
[0] == s
.alpha
[0]
3225 && alpha
[1] == s
.alpha
[1]
3226 && alpha
[2] == s
.alpha
[2]
3227 && alpha
[3] == s
.alpha
[3]
3229 && fGaussianBlur
== s
.fGaussianBlur
3230 && relativeTo
== s
.relativeTo
3231 && IsFontStyleEqual(s
));
3234 bool STSStyle::IsFontStyleEqual(const STSStyle
& s
) const
3237 charSet
== s
.charSet
3238 && fontName
== s
.fontName
3239 && fontSize
== s
.fontSize
3240 && fontScaleX
== s
.fontScaleX
3241 && fontScaleY
== s
.fontScaleY
3242 && fontSpacing
== s
.fontSpacing
3243 && fontWeight
== s
.fontWeight
3244 && fItalic
== s
.fItalic
3245 && fUnderline
== s
.fUnderline
3246 && fStrikeOut
== s
.fStrikeOut
3247 && fontAngleZ
== s
.fontAngleZ
3248 && fontAngleX
== s
.fontAngleX
3249 && fontAngleY
== s
.fontAngleY
3250 && fontShiftX
== s
.fontShiftX
3251 && fontShiftY
== s
.fontShiftY
);
3254 void STSStyle::operator = (const LOGFONT
& lf
)
3256 charSet
= lf
.lfCharSet
;
3257 fontName
= lf
.lfFaceName
;
3259 fontSize
= -MulDiv(lf
.lfHeight
, 72, GetDeviceCaps(hDC
, LOGPIXELSY
));
3261 // fontAngleZ = (float)(1.0*lf.lfEscapement/10);
3262 fontWeight
= lf
.lfWeight
;
3263 fItalic
= !!lf
.lfItalic
;
3264 fUnderline
= !!lf
.lfUnderline
;
3265 fStrikeOut
= !!lf
.lfStrikeOut
;
3268 LOGFONTA
& operator <<= (LOGFONTA
& lfa
, const STSStyleBase
& s
)
3270 lfa
.lfCharSet
= s
.charSet
;
3271 strncpy_s(lfa
.lfFaceName
, LF_FACESIZE
, CStringA(s
.fontName
), _TRUNCATE
);
3273 lfa
.lfHeight
= -MulDiv((int)(s
.fontSize
+0.5), GetDeviceCaps(hDC
, LOGPIXELSY
), 72);
3275 lfa
.lfWeight
= s
.fontWeight
;
3276 lfa
.lfItalic
= s
.fItalic
?-1:0;
3277 lfa
.lfUnderline
= s
.fUnderline
?-1:0;
3278 lfa
.lfStrikeOut
= s
.fStrikeOut
?-1:0;
3282 LOGFONTW
& operator <<= (LOGFONTW
& lfw
, const STSStyleBase
& s
)
3284 lfw
.lfCharSet
= s
.charSet
;
3285 wcsncpy_s(lfw
.lfFaceName
, LF_FACESIZE
, CStringW(s
.fontName
), _TRUNCATE
);
3287 lfw
.lfHeight
= -MulDiv((int)(s
.fontSize
+0.5), GetDeviceCaps(hDC
, LOGPIXELSY
), 72);
3289 lfw
.lfWeight
= s
.fontWeight
;
3290 lfw
.lfItalic
= s
.fItalic
?-1:0;
3291 lfw
.lfUnderline
= s
.fUnderline
?-1:0;
3292 lfw
.lfStrikeOut
= s
.fStrikeOut
?-1:0;
3296 CString
& operator <<= (CString
& style
, const STSStyle
& s
)
3298 style
.Format(_T("%d;%d;%d;%d;")
3299 _T("%d;%d;%f;%f;%f;%f;")
3300 _T("0x%06x;0x%06x;0x%06x;0x%06x;")
3301 _T("0x%02x;0x%02x;0x%02x;0x%02x;")
3303 _T("%s;%f;%f;%f;%f;%d;")
3304 _T("%d;%d;%d;%d;%f;")
3307 s
.marginRect
.get().left
, s
.marginRect
.get().right
, s
.marginRect
.get().top
, s
.marginRect
.get().bottom
,
3308 s
.scrAlignment
, s
.borderStyle
,s
.outlineWidthX
, s
.outlineWidthY
, s
.shadowDepthX
, s
.shadowDepthY
,
3309 s
.colors
[0], s
.colors
[1], s
.colors
[2], s
.colors
[3],
3310 s
.alpha
[0], s
.alpha
[1], s
.alpha
[2], s
.alpha
[3],
3312 s
.fontName
,s
.fontSize
,s
.fontScaleX
, s
.fontScaleY
,s
.fontSpacing
,s
.fontWeight
,
3313 (int)s
.fItalic
, (int)s
.fUnderline
, (int)s
.fStrikeOut
, s
.fBlur
, s
.fGaussianBlur
,
3314 s
.fontAngleZ
, s
.fontAngleX
, s
.fontAngleY
,
3320 STSStyle
& operator <<= (STSStyle
& s
, const CString
& style
)
3326 CStringW str
= TToW(style
);
3327 if(str
.Find(';')>=0)
3330 tmp_rect
.left
= GetInt(str
,';'); tmp_rect
.right
= GetInt(str
,';'); tmp_rect
.top
= GetInt(str
,';'); tmp_rect
.bottom
= GetInt(str
,';');
3331 s
.marginRect
= tmp_rect
;
3332 s
.scrAlignment
= GetInt(str
,';'); s
.borderStyle
= GetInt(str
,';');
3333 s
.outlineWidthX
= GetFloat(str
,';'); s
.outlineWidthY
= GetFloat(str
,';'); s
.shadowDepthX
= GetFloat(str
,';'); s
.shadowDepthY
= GetFloat(str
,';');
3334 for(int i
= 0; i
< 4; i
++) s
.colors
[i
] = (COLORREF
)GetInt(str
,';');
3335 for(int i
= 0; i
< 4; i
++) s
.alpha
[i
] = GetInt(str
,';');
3336 s
.charSet
= GetInt(str
,';');
3337 s
.fontName
= WToT(GetStr(str
,';')); s
.fontSize
= GetFloat(str
,';');
3338 s
.fontScaleX
= GetFloat(str
,';'); s
.fontScaleY
= GetFloat(str
,';');
3339 s
.fontSpacing
= GetFloat(str
,';'); s
.fontWeight
= GetInt(str
,';');
3340 s
.fItalic
= !!GetInt(str
,';'); s
.fUnderline
= !!GetInt(str
,';'); s
.fStrikeOut
= !!GetInt(str
,';'); s
.fBlur
= GetInt(str
,';'); s
.fGaussianBlur
= GetFloat(str
,';');
3341 s
.fontAngleZ
= GetFloat(str
,';'); s
.fontAngleX
= GetFloat(str
,';'); s
.fontAngleY
= GetFloat(str
,';');
3342 s
.relativeTo
= GetInt(str
,';');
3353 static bool OpenRealText(CTextFile
* file
, CSimpleTextSubtitle
& ret
, int CharSet
)
3358 while(file
->ReadString(buff
))
3361 if(buff
.IsEmpty()) continue;
3363 szFile
+= CStringW(_T("\n")) + buff
.GetBuffer();
3366 CRealTextParser RealTextParser
;
3367 if (!RealTextParser
.ParseRealText(szFile
))
3370 CRealTextParser::Subtitles crRealText
= RealTextParser
.GetParsedSubtitles();
3372 for (map
<pair
<int, int>, wstring
>::const_iterator i
= crRealText
.m_mapLines
.begin();
3373 i
!= crRealText
.m_mapLines
.end();
3377 SubRipper2SSA(i
->second
.c_str(), CharSet
),
3383 // std::wofstream wofsOut(L"c:/zzz.srt");
3384 // RealTextParser.OutputSRT(wofsOut);
3386 return(!ret
.IsEmpty());