00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include "stdafx.h"
00023 #include "STS.h"
00024 #include <atlbase.h>
00025
00026
00027
00028 struct htmlcolor {TCHAR* name; DWORD color;} hmtlcolors[] =
00029 {
00030 {_T("white"), 0xffffff},
00031 {_T("whitesmoke"), 0xf5f5f5},
00032 {_T("ghostwhite"), 0xf8f8ff},
00033 {_T("snow"), 0xfffafa},
00034 {_T("gainsboro"), 0xdcdcdc},
00035 {_T("lightgrey"), 0xd3d3d3},
00036 {_T("silver"), 0xc0c0c0},
00037 {_T("darkgray"), 0xa9a9a9},
00038 {_T("gray"), 0x808080},
00039 {_T("dimgray"), 0x696969},
00040 {_T("lightslategray"), 0x778899},
00041 {_T("slategray"), 0x708090},
00042 {_T("darkslategray"), 0x2f4f4f},
00043 {_T("black"), 0x000000},
00044
00045 {_T("azure"), 0xf0ffff},
00046 {_T("aliceblue"), 0xf0f8ff},
00047 {_T("mintcream"), 0xf5fffa},
00048 {_T("honeydew"), 0xf0fff0},
00049 {_T("lightcyan"), 0xe0ffff},
00050 {_T("paleturqoise"), 0xafeeee},
00051 {_T("powderblue"), 0xb0e0e6},
00052 {_T("lightblue"), 0xadd8ed},
00053 {_T("lightsteelblue"), 0xb0c4de},
00054 {_T("skyblue"), 0x87ceeb},
00055 {_T("lightskyblue"), 0x87cefa},
00056 {_T("cyan"), 0x00ffff},
00057 {_T("aqua"), 0x00ff80},
00058 {_T("deepskyblue"), 0x00bfff},
00059 {_T("aquamarine"), 0x7fffd4},
00060 {_T("turquoise"), 0x40e0d0},
00061 {_T("darkturquoise"), 0x00ced1},
00062 {_T("lightseagreen"), 0x20b2aa},
00063 {_T("mediumturquoise"), 0x40e0dd},
00064 {_T("mediumaquamarine"), 0x66cdaa},
00065 {_T("cadetblue"), 0x5f9ea0},
00066 {_T("teal"), 0x008080},
00067 {_T("darkcyan"), 0x008b8b},
00068 {_T("comflowerblue"), 0x6495ed},
00069 {_T("dodgerblue"), 0x1e90ff},
00070 {_T("steelblue"), 0x4682b4},
00071 {_T("royalblue"), 0x4169e1},
00072 {_T("blue"), 0x0000ff},
00073 {_T("mediumblue"), 0x0000cd},
00074 {_T("mediumslateblue"), 0x7b68ee},
00075 {_T("slateblue"), 0x6a5acd},
00076 {_T("darkslateblue"), 0x483d8b},
00077 {_T("darkblue"), 0x00008b},
00078 {_T("midnightblue"), 0x191970},
00079 {_T("navy"), 0x000080},
00080
00081 {_T("palegreen"), 0x98fb98},
00082 {_T("lightgreen"), 0x90ee90},
00083 {_T("mediumspringgreen"), 0x00fa9a},
00084 {_T("springgreen"), 0x00ff7f},
00085 {_T("chartreuse"), 0x7fff00},
00086 {_T("lawngreen"), 0x7cfc00},
00087 {_T("lime"), 0x00ff00},
00088 {_T("limegreen"), 0x32cd32},
00089 {_T("greenyellow"), 0xadff2f},
00090 {_T("yellowgreen"), 0x9acd32},
00091 {_T("darkseagreen"), 0x8fbc8f},
00092 {_T("mediumseagreen"), 0x3cb371},
00093 {_T("seagreen"), 0x2e8b57},
00094 {_T("olivedrab"), 0x6b8e23},
00095 {_T("forestgreen"), 0x228b22},
00096 {_T("green"), 0x008000},
00097 {_T("darkkhaki"), 0xbdb76b},
00098 {_T("olive"), 0x808000},
00099 {_T("darkolivegreen"), 0x556b2f},
00100 {_T("darkgreen"), 0x006400},
00101
00102 {_T("floralwhite"), 0xfffaf0},
00103 {_T("seashell"), 0xfff5ee},
00104 {_T("ivory"), 0xfffff0},
00105 {_T("beige"), 0xf5f5dc},
00106 {_T("cornsilk"), 0xfff8dc},
00107 {_T("lemonchiffon"), 0xfffacd},
00108 {_T("lightyellow"), 0xffffe0},
00109 {_T("lightgoldenrodyellow"), 0xfafad2},
00110 {_T("papayawhip"), 0xffefd5},
00111 {_T("blanchedalmond"), 0xffedcd},
00112 {_T("palegoldenrod"), 0xeee8aa},
00113 {_T("khaki"), 0xf0eb8c},
00114 {_T("bisque"), 0xffe4c4},
00115 {_T("moccasin"), 0xffe4b5},
00116 {_T("navajowhite"), 0xffdead},
00117 {_T("peachpuff"), 0xffdab9},
00118 {_T("yellow"), 0xffff00},
00119 {_T("gold"), 0xffd700},
00120 {_T("wheat"), 0xf5deb3},
00121 {_T("orange"), 0xffa500},
00122 {_T("darkorange"), 0xff8c00},
00123
00124 {_T("oldlace"), 0xfdf5e6},
00125 {_T("linen"), 0xfaf0e6},
00126 {_T("antiquewhite"), 0xfaebd7},
00127 {_T("lightsalmon"), 0xffa07a},
00128 {_T("darksalmon"), 0xe9967a},
00129 {_T("salmon"), 0xfa8072},
00130 {_T("lightcoral"), 0xf08080},
00131 {_T("indianred"), 0xcd5c5c},
00132 {_T("coral"), 0xff7f50},
00133 {_T("tomato"), 0xff6347},
00134 {_T("orangered"), 0xff4500},
00135 {_T("red"), 0xff0000},
00136 {_T("crimson"), 0xdc143c},
00137 {_T("firebrick"), 0xb22222},
00138 {_T("maroon"), 0x800000},
00139 {_T("darkred"), 0x8b0000},
00140
00141 {_T("lavender"), 0xe6e6fe},
00142 {_T("lavenderblush"), 0xfff0f5},
00143 {_T("mistyrose"), 0xffe4e1},
00144 {_T("thistle"), 0xd8bfd8},
00145 {_T("pink"), 0xffc0cb},
00146 {_T("lightpink"), 0xffb6c1},
00147 {_T("palevioletred"), 0xdb7093},
00148 {_T("hotpink"), 0xff69b4},
00149 {_T("fuchsia"), 0xff00ee},
00150 {_T("magenta"), 0xff00ff},
00151 {_T("mediumvioletred"), 0xc71585},
00152 {_T("deeppink"), 0xff1493},
00153 {_T("plum"), 0xdda0dd},
00154 {_T("violet"), 0xee82ee},
00155 {_T("orchid"), 0xda70d6},
00156 {_T("mediumorchid"), 0xba55d3},
00157 {_T("mediumpurple"), 0x9370db},
00158 {_T("purple"), 0x9370db},
00159 {_T("blueviolet"), 0x8a2be2},
00160 {_T("darkviolet"), 0x9400d3},
00161 {_T("darkorchid"), 0x9932cc},
00162
00163 {_T("tan"), 0xd2b48c},
00164 {_T("burlywood"), 0xdeb887},
00165 {_T("sandybrown"), 0xf4a460},
00166 {_T("peru"), 0xcd853f},
00167 {_T("goldenrod"), 0xdaa520},
00168 {_T("darkgoldenrod"), 0xb8860b},
00169 {_T("chocolate"), 0xd2691e},
00170 {_T("rosybrown"), 0xbc8f8f},
00171 {_T("sienna"), 0xa0522d},
00172 {_T("saddlebrown"), 0x8b4513},
00173 {_T("brown"), 0xa52a2a},
00174 };
00175
00176 CHtmlColorMap::CHtmlColorMap()
00177 {
00178 for(int i = 0; i < countof(hmtlcolors); i++)
00179 SetAt(hmtlcolors[i].name, (void*)hmtlcolors[i].color);
00180 }
00181
00182 CHtmlColorMap g_colors;
00183
00184
00185
00186 BYTE CharSetList[] =
00187 {
00188 ANSI_CHARSET,
00189 DEFAULT_CHARSET,
00190 SYMBOL_CHARSET,
00191 SHIFTJIS_CHARSET,
00192 HANGEUL_CHARSET,
00193 HANGUL_CHARSET,
00194 GB2312_CHARSET,
00195 CHINESEBIG5_CHARSET,
00196 OEM_CHARSET,
00197 JOHAB_CHARSET,
00198 HEBREW_CHARSET,
00199 ARABIC_CHARSET,
00200 GREEK_CHARSET,
00201 TURKISH_CHARSET,
00202 VIETNAMESE_CHARSET,
00203 THAI_CHARSET,
00204 EASTEUROPE_CHARSET,
00205 RUSSIAN_CHARSET,
00206 MAC_CHARSET,
00207 BALTIC_CHARSET
00208 };
00209
00210 TCHAR* CharSetNames[] =
00211 {
00212 _T("ANSI"),
00213 _T("DEFAULT"),
00214 _T("SYMBOL"),
00215 _T("SHIFTJIS"),
00216 _T("HANGEUL"),
00217 _T("HANGUL"),
00218 _T("GB2312"),
00219 _T("CHINESEBIG5"),
00220 _T("OEM"),
00221 _T("JOHAB"),
00222 _T("HEBREW"),
00223 _T("ARABIC"),
00224 _T("GREEK"),
00225 _T("TURKISH"),
00226 _T("VIETNAMESE"),
00227 _T("THAI"),
00228 _T("EASTEUROPE"),
00229 _T("RUSSIAN"),
00230 _T("MAC"),
00231 _T("BALTIC"),
00232 };
00233
00234 int CharSetLen = countof(CharSetList);
00235
00236
00237
00238 static DWORD CharSetToCodePage(DWORD dwCharSet)
00239 {
00240 CHARSETINFO cs={0};
00241 ::TranslateCharsetInfo((DWORD *)dwCharSet, &cs, TCI_SRCCHARSET);
00242 return cs.ciACP;
00243 }
00244
00245 int FindChar(CStringW str, WCHAR c, int pos, bool fUnicode, int CharSet)
00246 {
00247 if(fUnicode) return(str.Find(c, pos));
00248
00249 int fStyleMod = 0;
00250
00251 DWORD cp = CharSetToCodePage(CharSet);
00252 int OrgCharSet = CharSet;
00253
00254 for(int i = 0, j = str.GetLength(), k; i < j; i++)
00255 {
00256 WCHAR c2 = str[i];
00257
00258 if(IsDBCSLeadByteEx(cp, (BYTE)c2)) i++;
00259 else if(i >= pos)
00260 {
00261 if(c2 == c) return(i);
00262 }
00263
00264 if(c2 == '{') fStyleMod++;
00265 else if(fStyleMod > 0)
00266 {
00267 if(c2 == '}') fStyleMod--;
00268 else if(c2 == 'e' && i >= 3 && i < j-1 && str.Mid(i-2, 3) == L"\\fe")
00269 {
00270 CharSet = 0;
00271 for(k = i+1; _istdigit(str[k]); k++) CharSet = CharSet*10 + (str[k] - '0');
00272 if(k == i+1) CharSet = OrgCharSet;
00273
00274 cp = CharSetToCodePage(CharSet);
00275 }
00276 }
00277 }
00278
00279 return(-1);
00280 }
00281
00282
00283
00284
00285
00286
00287
00288
00289 static CStringW ToMBCS(CStringW str, DWORD CharSet)
00290 {
00291 CStringW ret;
00292
00293 DWORD cp = CharSetToCodePage(CharSet);
00294
00295 for(int i = 0, j = str.GetLength(); i < j; i++)
00296 {
00297 WCHAR wc = str.GetAt(i);
00298 char c[8];
00299
00300 int len;
00301 if((len = WideCharToMultiByte(cp, 0, &wc, 1, c, 8, NULL, NULL)) > 0)
00302 {
00303 for(int k = 0; k < len; k++)
00304 ret += (WCHAR)(BYTE)c[k];
00305 }
00306 else
00307 {
00308 ret += '?';
00309 }
00310 }
00311
00312 return(ret);
00313 }
00314
00315 static CStringW UnicodeSSAToMBCS(CStringW str, DWORD CharSet)
00316 {
00317 CStringW ret;
00318
00319 int OrgCharSet = CharSet;
00320
00321 for(int j = 0; j < str.GetLength(); )
00322 {
00323 j = str.Find('{', j);
00324 if(j >= 0)
00325 {
00326 ret += ToMBCS(str.Left(j), CharSet);
00327 str = str.Mid(j);
00328
00329 j = str.Find('}');
00330 if(j < 0)
00331 {
00332 ret += ToMBCS(str, CharSet);
00333 break;
00334 }
00335 else
00336 {
00337 int k = str.Find(L"\\fe");
00338 if(k >= 0 && k < j)
00339 {
00340 CharSet = 0;
00341 int l = k+3;
00342 for(; _istdigit(str[l]); l++) CharSet = CharSet*10 + (str[l] - '0');
00343 if(l == k+3) CharSet = OrgCharSet;
00344 }
00345
00346 j++;
00347
00348 ret += ToMBCS(str.Left(j), OrgCharSet);
00349 str = str.Mid(j);
00350 j = 0;
00351 }
00352 }
00353 else
00354 {
00355 ret += ToMBCS(str, CharSet);
00356 break;
00357 }
00358 }
00359
00360 return(ret);
00361 }
00362
00363 static CStringW ToUnicode(CStringW str, DWORD CharSet)
00364 {
00365 CStringW ret;
00366
00367 DWORD cp = CharSetToCodePage(CharSet);
00368
00369 for(int i = 0, j = str.GetLength(); i < j; i++)
00370 {
00371 WCHAR wc = str.GetAt(i);
00372 char c = wc&0xff;
00373
00374 if(IsDBCSLeadByteEx(cp, (BYTE)wc))
00375 {
00376 i++;
00377
00378 if(i < j)
00379 {
00380 char cc[2];
00381 cc[0] = c;
00382 cc[1] = (char)str.GetAt(i);
00383
00384 MultiByteToWideChar(cp, 0, cc, 2, &wc, 1);
00385 }
00386 }
00387 else
00388 {
00389 MultiByteToWideChar(cp, 0, &c, 1, &wc, 1);
00390 }
00391
00392 ret += wc;
00393 }
00394
00395 return(ret);
00396 }
00397
00398 static CStringW MBCSSSAToUnicode(CStringW str, int CharSet)
00399 {
00400 CStringW ret;
00401
00402 int OrgCharSet = CharSet;
00403
00404 for(int j = 0; j < str.GetLength(); )
00405 {
00406 j = FindChar(str, '{', 0, false, CharSet);
00407
00408 if(j >= 0)
00409 {
00410 ret += ToUnicode(str.Left(j), CharSet);
00411 str = str.Mid(j);
00412
00413 j = FindChar(str, '}', 0, false, CharSet);
00414
00415 if(j < 0)
00416 {
00417 ret += ToUnicode(str, CharSet);
00418 break;
00419 }
00420 else
00421 {
00422 int k = str.Find(L"\\fe");
00423 if(k >= 0 && k < j)
00424 {
00425 CharSet = 0;
00426 int l = k+3;
00427 for(; _istdigit(str[l]); l++) CharSet = CharSet*10 + (str[l] - '0');
00428 if(l == k+3) CharSet = OrgCharSet;
00429 }
00430
00431 j++;
00432
00433 ret += ToUnicode(str.Left(j), OrgCharSet);
00434 str = str.Mid(j);
00435 j = 0;
00436 }
00437 }
00438 else
00439 {
00440 ret += ToUnicode(str, CharSet);
00441 break;
00442 }
00443 }
00444
00445 return(ret);
00446 }
00447
00448 CStringW RemoveSSATags(CStringW str, bool fUnicode, int CharSet)
00449 {
00450 for(int i = 0, j; i < str.GetLength(); )
00451 {
00452 if((i = FindChar(str, '{', i, fUnicode, CharSet)) < 0) break;
00453 if((j = FindChar(str, '}', i, fUnicode, CharSet)) < 0) break;
00454 str.Delete(i, j-i+1);
00455 }
00456
00457 str.Replace(L"\\N", L"\n");
00458 str.Replace(L"\\n", L"\n");
00459 str.Replace(L"\\h", L" ");
00460
00461 return(str);
00462 }
00463
00464
00465
00466 static CStringW SubRipper2SSA(CStringW str, int CharSet)
00467 {
00468 str.Replace(L"<i>", L"{\\i1}");
00469 str.Replace(L"</i>", L"{\\i}");
00470 str.Replace(L"<b>", L"{\\b1}");
00471 str.Replace(L"</b>", L"{\\b}");
00472 str.Replace(L"<u>", L"{\\u1}");
00473 str.Replace(L"</u>", L"{\\u}");
00474
00475 return(str);
00476 }
00477
00478 static bool OpenSubRipper(CTextFile* file, CSimpleTextSubtitle& ret, int CharSet)
00479 {
00480 int num = 0;
00481
00482 CStringW buff;
00483 while(file->ReadString(buff))
00484 {
00485 buff.Trim();
00486 if(buff.IsEmpty()) continue;
00487
00488 WCHAR sep;
00489 int hh1, mm1, ss1, ms1, hh2, mm2, ss2, ms2;
00490 int c = swscanf(buff, L"%d%c%d%c%d%c%d --> %d%c%d%c%d%c%d\n",
00491 &hh1, &sep, &mm1, &sep, &ss1, &sep, &ms1,
00492 &hh2, &sep, &mm2, &sep, &ss2, &sep, &ms2);
00493
00494 if(c == 1)
00495 {
00496 num = hh1;
00497 }
00498 else if(c == 14)
00499 {
00500 CStringW str, tmp;
00501
00502 bool fFoundEmpty = false;
00503
00504 while(file->ReadString(tmp))
00505 {
00506 tmp.Trim();
00507 if(tmp.IsEmpty()) fFoundEmpty = true;
00508
00509 int num2;
00510 WCHAR c;
00511 if(swscanf(tmp, L"%d%c", &num2, &c) == 1 && fFoundEmpty)
00512 {
00513 num = num2;
00514 break;
00515 }
00516
00517 str += tmp + '\n';
00518 }
00519
00520 ret.Add(
00521 SubRipper2SSA(str, CharSet),
00522 file->IsUnicode(),
00523 (((hh1*60 + mm1)*60) + ss1)*1000 + ms1,
00524 (((hh2*60 + mm2)*60) + ss2)*1000 + ms2);
00525 }
00526 else if(c != EOF)
00527 {
00528 return(false);
00529 }
00530 }
00531
00532 return(ret.GetCount() > 0);
00533 }
00534
00535 static bool OpenOldSubRipper(CTextFile* file, CSimpleTextSubtitle& ret, int CharSet)
00536 {
00537 CStringW buff;
00538 while(file->ReadString(buff))
00539 {
00540 buff.Trim();
00541 if(buff.IsEmpty()) continue;
00542
00543 for(int i = 0; i < buff.GetLength(); i++)
00544 {
00545 if((i = FindChar(buff, '|', i, file->IsUnicode(), CharSet)) < 0) break;
00546 buff.SetAt(i, '\n');
00547 }
00548
00549 int hh1, mm1, ss1, hh2, mm2, ss2;
00550 int c = swscanf(buff, L"{%d:%d:%d}{%d:%d:%d}", &hh1, &mm1, &ss1, &hh2, &mm2, &ss2);
00551
00552 if(c == 6)
00553 {
00554 ret.Add(
00555 buff.Mid(buff.Find('}', buff.Find('}')+1)+1),
00556 file->IsUnicode(),
00557 (((hh1*60 + mm1)*60) + ss1)*1000,
00558 (((hh2*60 + mm2)*60) + ss2)*1000);
00559 }
00560 else if(c != EOF)
00561 {
00562 return(false);
00563 }
00564 }
00565
00566 return(ret.GetCount() > 0);
00567 }
00568
00569 static bool OpenSubViewer(CTextFile* file, CSimpleTextSubtitle& ret, int CharSet)
00570 {
00571 STSStyle def;
00572 CStringW font, color, size;
00573 bool fBold, fItalic, fStriked, fUnderline;
00574
00575 CStringW buff;
00576 while(file->ReadString(buff))
00577 {
00578 buff.Trim();
00579 if(buff.IsEmpty()) continue;
00580
00581 if(buff[0] == '[')
00582 {
00583 for(int i = 0; i < buff.GetLength() && buff[i]== '['; )
00584 {
00585 int j = buff.Find(']', ++i);
00586 if(j < i) break;
00587
00588 CStringW tag = buff.Mid(i,j-i);
00589 tag.Trim();
00590 tag.MakeLower();
00591
00592 i += j-i;
00593
00594 j = buff.Find('[', ++i);
00595 if(j < 0) j = buff.GetLength();
00596
00597 CStringW param = buff.Mid(i,j-i);
00598 param.Trim(L" \\t,");
00599
00600 i = j;
00601
00602 if(tag == L"font")
00603 font = def.fontName.CompareNoCase(WToT(param)) ? param : L"";
00604 else if(tag == L"colf")
00605 color = def.colors[0] != wcstol(((LPCWSTR)param)+2, 0, 16) ? param : L"";
00606 else if(tag == L"size")
00607 size = def.fontSize != wcstol(param, 0, 10) ? param : L"";
00608 else if(tag == L"style")
00609 {
00610 if(param.Find(L"no") >= 0)
00611 {
00612 fBold = fItalic = fStriked = fUnderline = false;
00613 }
00614 else
00615 {
00616 fBold = def.fontWeight < FW_BOLD && param.Find(L"bd") >= 0;
00617 fItalic = def.fItalic && param.Find(L"it") >= 0;
00618 fStriked = def.fStrikeOut && param.Find(L"st") >= 0;
00619 fUnderline = def.fUnderline && param.Find(L"ud") >= 0;
00620 }
00621 }
00622 }
00623
00624 continue;
00625 }
00626
00627 WCHAR sep;
00628 int hh1, mm1, ss1, hs1, hh2, mm2, ss2, hs2;
00629 int c = swscanf(buff, L"%d:%d:%d%c%d,%d:%d:%d%c%d\n",
00630 &hh1, &mm1, &ss1, &sep, &hs1, &hh2, &mm2, &ss2, &sep, &hs2);
00631
00632 if(c == 10)
00633 {
00634 CStringW str;
00635 file->ReadString(str);
00636
00637 str.Replace(L"[br]", L"\\N");
00638
00639 CStringW prefix;
00640 if(!font.IsEmpty()) prefix += L"\\fn" + font;
00641 if(!color.IsEmpty()) prefix += L"\\c" + color;
00642 if(!size.IsEmpty()) prefix += L"\\fs" + size;
00643 if(fBold) prefix += L"\\b1";
00644 if(fItalic) prefix += L"\\i1";
00645 if(fStriked) prefix += L"\\s1";
00646 if(fUnderline) prefix += L"\\u1";
00647 if(!prefix.IsEmpty()) str = L"{" + prefix + L"}" + str;
00648
00649 ret.Add(str,
00650 file->IsUnicode(),
00651 (((hh1*60 + mm1)*60) + ss1)*1000 + hs1*10,
00652 (((hh2*60 + mm2)*60) + ss2)*1000 + hs2*10);
00653 }
00654 else if(c != EOF)
00655 {
00656 return(false);
00657 }
00658 }
00659
00660 return(ret.GetCount() > 0);
00661 }
00662
00663 static STSStyle* GetMicroDVDStyle(CString str, int CharSet)
00664 {
00665 STSStyle* ret = new STSStyle();
00666 if(!ret) return(NULL);
00667
00668 for(int i = 0, len = str.GetLength(); i < len; i++)
00669 {
00670 int j = str.Find('{', i);
00671 if(j < 0) j = len;
00672
00673 if(j >= len) break;
00674
00675 int k = str.Find('}', j);
00676 if(k < 0) k = len;
00677
00678 CString code = str.Mid(j, k-j);
00679 if(code.GetLength() > 2) code.SetAt(1, (TCHAR)towlower(code[1]));
00680
00681 if(!_tcsnicmp(code, _T("{c:$"), 4))
00682 {
00683 _stscanf(code, _T("{c:$%x"), &ret->colors[0]);
00684 }
00685 else if(!_tcsnicmp(code, _T("{f:"), 3))
00686 {
00687 ret->fontName = code.Mid(3);
00688 }
00689 else if(!_tcsnicmp(code, _T("{s:"), 3))
00690 {
00691 float f;
00692 if(1 == _stscanf(code, _T("{s:%f"), &f))
00693 ret->fontSize = f;
00694 }
00695 else if(!_tcsnicmp(code, _T("{h:"), 3))
00696 {
00697 _stscanf(code, _T("{h:%d"), &ret->charSet);
00698 }
00699 else if(!_tcsnicmp(code, _T("{y:"), 3))
00700 {
00701 code.MakeLower();
00702 if(code.Find('b') >= 0) ret->fontWeight = FW_BOLD;
00703 if(code.Find('i') >= 0) ret->fItalic = true;
00704 if(code.Find('u') >= 0) ret->fUnderline = true;
00705 if(code.Find('s') >= 0) ret->fStrikeOut = true;
00706 }
00707 else if(!_tcsnicmp(code, _T("{p:"), 3))
00708 {
00709 int p;
00710 _stscanf(code, _T("{p:%d"), &p);
00711 ret->scrAlignment = (p == 0) ? 8 : 2;
00712 }
00713
00714 i = k;
00715 }
00716
00717 return(ret);
00718 }
00719
00720 static CStringW MicroDVD2SSA(CStringW str, bool fUnicode, int CharSet)
00721 {
00722 CStringW ret;
00723
00724 enum {COLOR=0, FONTNAME, FONTSIZE, FONTCHARSET, BOLD, ITALIC, UNDERLINE, STRIKEOUT};
00725 bool fRestore[8];
00726 int fRestoreLen = 8;
00727 memset(fRestore, 0, sizeof(bool)*fRestoreLen);
00728
00729 for(int pos = 0, eol; pos < str.GetLength(); pos++)
00730 {
00731 if((eol = FindChar(str, '|', pos, fUnicode, CharSet)) < 0) eol = str.GetLength();
00732
00733 CStringW line = str.Mid(pos, eol-pos);
00734
00735 pos = eol;
00736
00737 for(int i = 0, j, k, len = line.GetLength(); i < len; i++)
00738 {
00739 if((j = FindChar(line, '{', i, fUnicode, CharSet)) < 0) j = str.GetLength();
00740
00741 ret += line.Mid(i, j-i);
00742
00743 if(j >= len) break;
00744
00745 if((k = FindChar(line, '}', j, fUnicode, CharSet)) < 0) k = len;
00746
00747 {
00748 CStringW code = line.Mid(j, k-j);
00749
00750 if(!wcsnicmp(code, L"{c:$", 4))
00751 {
00752 fRestore[COLOR] = (iswupper(code[1]) == 0);
00753 code.MakeLower();
00754
00755 int color;
00756 swscanf(code, L"{c:$%x", &color);
00757 code.Format(L"{\\c&H%x&}", color);
00758 ret += code;
00759 }
00760 else if(!wcsnicmp(code, L"{f:", 3))
00761 {
00762 fRestore[FONTNAME] = (iswupper(code[1]) == 0);
00763
00764 code.Format(L"{\\fn%s}", code.Mid(3));
00765 ret += code;
00766 }
00767 else if(!wcsnicmp(code, L"{s:", 3))
00768 {
00769 fRestore[FONTSIZE] = (iswupper(code[1]) == 0);
00770 code.MakeLower();
00771
00772 float size;
00773 swscanf(code, L"{s:%f", &size);
00774 code.Format(L"{\\fs%f}", size);
00775 ret += code;
00776 }
00777 else if(!wcsnicmp(code, L"{h:", 3))
00778 {
00779 fRestore[COLOR] = (_istupper(code[1]) == 0);
00780 code.MakeLower();
00781
00782 int CharSet;
00783 swscanf(code, L"{h:%d", &CharSet);
00784 code.Format(L"{\\fe%d}", CharSet);
00785 ret += code;
00786 }
00787 else if(!wcsnicmp(code, L"{y:", 3))
00788 {
00789 bool f = (_istupper(code[1]) == 0);
00790
00791 code.MakeLower();
00792
00793 ret += '{';
00794 if(code.Find('b') >= 0) {ret += L"\\b1"; fRestore[BOLD] = f;}
00795 if(code.Find('i') >= 0) {ret += L"\\i1"; fRestore[ITALIC] = f;}
00796 if(code.Find('u') >= 0) {ret += L"\\u1"; fRestore[UNDERLINE] = f;}
00797 if(code.Find('s') >= 0) {ret += L"\\s1"; fRestore[STRIKEOUT] = f;}
00798 ret += '}';
00799 }
00800 else if(!wcsnicmp(code, L"{o:", 3))
00801 {
00802 code.MakeLower();
00803
00804 int x, y;
00805 TCHAR c;
00806 swscanf(code, L"{o:%d%c%d", &x, &c, &y);
00807 code.Format(L"{\\move(%d,%d,0,0,0,0)}", x, y);
00808 ret += code;
00809 }
00810 else ret += code;
00811 }
00812
00813 i = k;
00814 }
00815
00816 if(pos >= str.GetLength()) break;
00817
00818 for(int i = 0; i < fRestoreLen; i++)
00819 {
00820 if(fRestore[i])
00821 {
00822 switch(i)
00823 {
00824 case COLOR: ret += L"{\\c}"; break;
00825 case FONTNAME: ret += L"{\\fn}"; break;
00826 case FONTSIZE: ret += L"{\\fs}"; break;
00827 case FONTCHARSET: ret += L"{\\fe}"; break;
00828 case BOLD: ret += L"{\\b}"; break;
00829 case ITALIC: ret += L"{\\i}"; break;
00830 case UNDERLINE: ret += L"{\\u}"; break;
00831 case STRIKEOUT: ret += L"{\\s}"; break;
00832 default: break;
00833 }
00834 }
00835 }
00836
00837 memset(fRestore, 0, sizeof(bool)*fRestoreLen);
00838
00839 ret += L"\\N";
00840 }
00841
00842 return(ret);
00843 }
00844
00845 static bool OpenMicroDVD(CTextFile* file, CSimpleTextSubtitle& ret, int CharSet)
00846 {
00847 bool fCheck = false, fCheck2 = false;
00848
00849 CString style(_T("Default"));
00850
00851 CStringW buff;;
00852 while(file->ReadString(buff))
00853 {
00854 buff.Trim();
00855 if(buff.IsEmpty()) continue;
00856
00857 int start, end;
00858 int c = swscanf(buff, L"{%d}{%d}", &start, &end);
00859
00860 if(c != 2) {c = swscanf(buff, L"{%d}{}", &start)+1; end = start + 60; fCheck = true;}
00861
00862 if(c != 2)
00863 {
00864 int i;
00865 if(buff.Find('{') == 0 && (i = buff.Find('}')) > 1 && i < buff.GetLength())
00866 {
00867 if(STSStyle* s = GetMicroDVDStyle(WToT(buff.Mid(i+1)), CharSet))
00868 {
00869 style = buff.Mid(1, i-1);
00870 style.MakeUpper();
00871 if(style.GetLength()) {CString str = style.Mid(1); str.MakeLower(); style = style.Left(1) + str;}
00872 ret.AddStyle(style, s);
00873 CharSet = s->charSet;
00874 continue;
00875 }
00876 }
00877 }
00878
00879 if(c == 2)
00880 {
00881 if(fCheck2 && ret.GetSize())
00882 {
00883 STSEntry& stse = ret[ret.GetSize()-1];
00884 stse.end = min(stse.end, start);
00885 fCheck2 = false;
00886 }
00887
00888 ret.Add(
00889 MicroDVD2SSA(buff.Mid(buff.Find('}', buff.Find('}')+1)+1), file->IsUnicode(), CharSet),
00890 file->IsUnicode(),
00891 start, end,
00892 style);
00893
00894 if(fCheck)
00895 {
00896 fCheck = false;
00897 fCheck2 = true;
00898 }
00899 }
00900 else if(c != EOF)
00901 {
00902 return(false);
00903 }
00904 }
00905
00906 return(ret.GetCount() > 0);
00907 }
00908
00909 static void ReplaceNoCase(CStringW& str, CStringW from, CStringW to)
00910 {
00911 CStringW lstr = str;
00912 lstr.MakeLower();
00913
00914 int i, j, k;
00915
00916 for(i = 0, j = str.GetLength(); i < j; )
00917 {
00918 if((k = lstr.Find(from, i)) >= 0)
00919 {
00920 str.Delete(k, from.GetLength()); lstr.Delete(k, from.GetLength());
00921 str.Insert(k, to); lstr.Insert(k, to);
00922 i = k + to.GetLength();
00923 j = str.GetLength();
00924 }
00925 else break;
00926 }
00927 }
00928
00929 static CStringW SMI2SSA(CStringW str, int CharSet)
00930 {
00931 ReplaceNoCase(str, L" ", L" ");
00932 ReplaceNoCase(str, L""", L"\"");
00933 ReplaceNoCase(str, L"<br>", L"\\N");
00934 ReplaceNoCase(str, L"<i>", L"{\\i1}");
00935 ReplaceNoCase(str, L"</i>", L"{\\i}");
00936 ReplaceNoCase(str, L"<b>", L"{\\b1}");
00937 ReplaceNoCase(str, L"</b>", L"{\\b}");
00938
00939 CStringW lstr = str;
00940 lstr.MakeLower();
00941
00942
00943
00944 for(int i = 0, j = str.GetLength(); i < j; )
00945 {
00946 int k;
00947 if((k = lstr.Find('<', i)) < 0) break;
00948
00949 int chars_inserted = 0;
00950
00951 int l = 1;
00952 for(; k+l < j && lstr[k+l] != '>'; l++);
00953 l++;
00954
00955
00956 if (lstr.Find(L"<font ", k) == k)
00957 {
00958 CStringW args = lstr.Mid(k+6, l-6);
00959 CStringW arg ;
00960
00961 args.Remove('\"'); args.Remove('#');
00962 arg.TrimLeft(); arg.TrimRight(L" >");
00963
00964 for (;;)
00965 {
00966 args.TrimLeft();
00967 arg = args.SpanExcluding(L" \t>");
00968 args = args.Mid(arg.GetLength());
00969
00970 if(arg.IsEmpty())
00971 break;
00972 if (arg.Find(L"color=") == 0 )
00973 {
00974 DWORD color;
00975
00976 arg = arg.Mid(6);
00977 if ( arg.IsEmpty())
00978 continue;
00979
00980 CString key = WToT(arg);
00981 void* val;
00982 if(g_colors.Lookup(key, val))
00983 color = (DWORD)val;
00984 else if ( (color = wcstol(arg, NULL, 16) ) == 0 )
00985 color = 0x00ffffff;
00986
00987 arg.Format(L"%02x%02x%02x", color&0xff, (color>>8)&0xff, (color>>16)&0xff);
00988 lstr.Insert(k + l + chars_inserted, CStringW(L"{\\c&H") + arg + L"&}");
00989 str.Insert(k + l + chars_inserted, CStringW(L"{\\c&H") + arg + L"&}");
00990 chars_inserted += 5 + arg.GetLength() + 2;
00991 }
00992
00993
00994
00995
00996
00997
00998
00999
01000
01001
01002
01003
01004
01005
01006
01007
01008
01009 }
01010 }
01011
01012
01013
01014
01015
01016
01017
01018
01019
01020
01021
01022
01023
01024
01025
01026
01027
01028
01029
01030
01031
01032
01033
01034
01035
01036
01037
01038
01039 else if (lstr.Find(L"</font>", k) == k)
01040 {
01041 lstr.Insert(k + l + chars_inserted, L"{\\c}");
01042 str.Insert(k + l + chars_inserted, L"{\\c}");
01043 chars_inserted += 4;
01044 }
01045
01046 str.Delete(k, l); lstr.Delete(k, l);
01047 i = k + chars_inserted;
01048 j = str.GetLength();
01049 }
01050
01051 return(str);
01052 }
01053
01054 static bool OpenSami(CTextFile* file, CSimpleTextSubtitle& ret, int CharSet)
01055 {
01056 CStringW buff, caption;
01057
01058 ULONGLONG pos = file->GetPosition();
01059
01060 bool fSAMI = false;
01061
01062 while(file->ReadString(buff) && !fSAMI)
01063 {
01064 if(buff.MakeUpper().Find(L"<SAMI>") >= 0) fSAMI = true;
01065 }
01066
01067 if(!fSAMI) return(false);
01068
01069 file->Seek(pos, 0);
01070
01071 bool fComment = false;
01072
01073 int start_time = 0;
01074
01075 while(file->ReadString(buff))
01076 {
01077 buff.Trim();
01078 if(buff.IsEmpty()) continue;
01079
01080 CStringW ubuff = buff;
01081 ubuff.MakeUpper();
01082
01083 if(ubuff.Find(L"<!--") >= 0 || ubuff.Find(L"<TITLE>") >= 0)
01084 fComment = true;
01085
01086 if(!fComment)
01087 {
01088 int i;
01089
01090 if((i = ubuff.Find(L"<SYNC START=")) >= 0)
01091 {
01092 int time = 0;
01093
01094 for(i = 12; i < ubuff.GetLength(); i++)
01095 {
01096 if(ubuff[i] != '>' && ubuff[i] != 'M')
01097 {
01098 if(iswdigit(ubuff[i]))
01099 {
01100 time *= 10;
01101 time += ubuff[i] - 0x30;
01102 }
01103 }
01104 else break;
01105 }
01106
01107 ret.Add(
01108 SMI2SSA(caption, CharSet),
01109 file->IsUnicode(),
01110 start_time, time);
01111
01112 start_time = time;
01113 caption.Empty();
01114 }
01115
01116 caption += buff;
01117 }
01118
01119 if(ubuff.Find(L"-->") >= 0 || ubuff.Find(L"</TITLE>") >= 0)
01120 fComment = false;
01121 }
01122
01123 ret.Add(
01124 SMI2SSA(caption, CharSet),
01125 file->IsUnicode(),
01126 start_time, MAXLONG);
01127
01128 return(true);
01129 }
01130
01131 static bool OpenVPlayer(CTextFile* file, CSimpleTextSubtitle& ret, int CharSet)
01132 {
01133 CStringW buff;
01134 while(file->ReadString(buff))
01135 {
01136 buff.Trim();
01137 if(buff.IsEmpty()) continue;
01138
01139 for(int i = 0; i < buff.GetLength(); i++)
01140 {
01141 if((i = FindChar(buff, '|', i, file->IsUnicode(), CharSet)) < 0) break;
01142 buff.SetAt(i, '\n');
01143 }
01144
01145 int hh, mm, ss;
01146 int c = swscanf(buff, L"%d:%d:%d:", &hh, &mm, &ss);
01147
01148 if(c == 3)
01149 {
01150 CStringW str = buff.Mid(buff.Find(':', buff.Find(':', buff.Find(':')+1)+1)+1);
01151 ret.Add(str,
01152 file->IsUnicode(),
01153 (((hh*60 + mm)*60) + ss)*1000,
01154 (((hh*60 + mm)*60) + ss)*1000 + 1000 + 50*str.GetLength());
01155 }
01156 else if(c != EOF)
01157 {
01158 return(false);
01159 }
01160 }
01161
01162 return(ret.GetCount() > 0);
01163 }
01164
01165 CStringW GetStr(CStringW& buff, char sep = ',')
01166 {
01167 buff.TrimLeft();
01168
01169 int pos = buff.Find(sep);
01170 if(pos < 0)
01171 {
01172 pos = buff.GetLength();
01173 if(pos < 1) throw 1;
01174 }
01175
01176 CStringW ret = buff.Left(pos);
01177 if(pos < buff.GetLength()) buff = buff.Mid(pos+1);
01178
01179 return(ret);
01180 }
01181
01182 int GetInt(CStringW& buff, char sep = ',')
01183 {
01184 CStringW str;
01185
01186 str = GetStr(buff, sep);
01187 str.MakeLower();
01188
01189 CStringW fmtstr = str.GetLength() > 2 && (str.Left(2) == L"&h" || str.Left(2) == L"0x")
01190 ? str = str.Mid(2), L"%x"
01191 : L"%d";
01192
01193 int ret;
01194 if(swscanf(str, fmtstr, &ret) != 1) throw 1;
01195
01196 return(ret);
01197 }
01198
01199 double GetFloat(CStringW& buff, char sep = ',')
01200 {
01201 CStringW str;
01202
01203 str = GetStr(buff, sep);
01204 str.MakeLower();
01205
01206 float ret;
01207 if(swscanf(str, L"%f", &ret) != 1) throw 1;
01208
01209 return((double)ret);
01210 }
01211
01212 static bool LoadFont(CString& font)
01213 {
01214 int len = font.GetLength();
01215
01216 CAutoVectorPtr<BYTE> pData;
01217 if(len == 0 || (len&3) == 1 || !pData.Allocate(len))
01218 return(false);
01219
01220 const TCHAR* s = font;
01221 const TCHAR* e = s + len;
01222 for(BYTE* p = pData; s < e; s++, p++) *p = *s - 33;
01223
01224 for(int i = 0, j = 0, k = len&~3; i < k; i+=4, j+=3)
01225 {
01226 pData[j+0] = ((pData[i+0]&63)<<2)|((pData[i+1]>>4)& 3);
01227 pData[j+1] = ((pData[i+1]&15)<<4)|((pData[i+2]>>2)&15);
01228 pData[j+2] = ((pData[i+2]& 3)<<6)|((pData[i+3]>>0)&63);
01229 }
01230
01231 int datalen = (len&~3)*3/4;
01232
01233 if((len&3) == 2)
01234 {
01235 pData[datalen++] = ((pData[(len&~3)+0]&63)<<2)|((pData[(len&~3)+1]>>4)&3);
01236 }
01237 else if((len&3) == 3)
01238 {
01239 pData[datalen++] = ((pData[(len&~3)+0]&63)<<2)|((pData[(len&~3)+1]>>4)& 3);
01240 pData[datalen++] = ((pData[(len&~3)+1]&15)<<4)|((pData[(len&~3)+2]>>2)&15);
01241 }
01242
01243 HANDLE hFont = INVALID_HANDLE_VALUE;
01244
01245 if(HMODULE hModule = LoadLibrary(_T("GDI32.DLL")))
01246 {
01247 typedef HANDLE (WINAPI *PAddFontMemResourceEx)( IN PVOID, IN DWORD, IN PVOID , IN DWORD*);
01248 if(PAddFontMemResourceEx f = (PAddFontMemResourceEx)GetProcAddress(hModule, "AddFontMemResourceEx"))
01249 {
01250 DWORD cFonts;
01251 hFont = f(pData, datalen, NULL, &cFonts);
01252 }
01253
01254 FreeLibrary(hModule);
01255 }
01256
01257 if(hFont == INVALID_HANDLE_VALUE)
01258 {
01259 TCHAR path[MAX_PATH];
01260 GetTempPath(MAX_PATH, path);
01261
01262 DWORD chksum = 0;
01263 for(int i = 0, j = datalen>>2; i < j; i++)
01264 chksum += ((DWORD*)(BYTE*)pData)[i];
01265
01266 CString fn;
01267 fn.Format(_T("%sfont%08x.ttf"), path, chksum);
01268
01269 CFileStatus fs;
01270 if(!CFileGetStatus(fn, fs))
01271 {
01272 CFile f;
01273 if(f.Open(fn, CFile::modeCreate|CFile::modeWrite|CFile::typeBinary|CFile::shareDenyWrite))
01274 {
01275 f.Write(pData, datalen);
01276 f.Close();
01277 }
01278 }
01279
01280 AddFontResource(fn);
01281 }
01282
01283 return(true);
01284 }
01285
01286 static bool LoadUUEFont(CTextFile* file)
01287 {
01288 CString s, font;
01289 while(file->ReadString(s))
01290 {
01291 s.Trim();
01292 if(s.IsEmpty() || s[0] == '[') break;
01293 if(s.Find(_T("fontname:")) == 0) {LoadFont(font); font.Empty(); continue;}
01294
01295 font += s;
01296 }
01297
01298 if(!font.IsEmpty())
01299 LoadFont(font);
01300
01301 return(true);
01302 }
01303
01304 static bool OpenSubStationAlpha(CTextFile* file, CSimpleTextSubtitle& ret, int CharSet)
01305 {
01306 bool fRet = false;
01307
01308 int version = 3, sver = 3;
01309
01310 CStringW buff;
01311 while(file->ReadString(buff))
01312 {
01313 buff.Trim();
01314 if(buff.IsEmpty() || buff.GetAt(0) == ';') continue;
01315
01316 CStringW entry;
01317
01318
01319 entry = GetStr(buff, ':');
01320
01321
01322
01323 entry.MakeLower();
01324
01325 if(entry == L"[script info]")
01326 {
01327 fRet = true;
01328 }
01329 else if(entry == L"playresx")
01330 {
01331 try {ret.m_dstScreenSize.cx = GetInt(buff);}
01332 catch(...) {ret.m_dstScreenSize = CSize(0, 0); return(false);}
01333
01334 if(ret.m_dstScreenSize.cy <= 0)
01335 {
01336 ret.m_dstScreenSize.cy = (ret.m_dstScreenSize.cx == 1280)
01337 ? 1024
01338 : ret.m_dstScreenSize.cx * 3 / 4;
01339 }
01340 }
01341 else if(entry == L"playresy")
01342 {
01343 try {ret.m_dstScreenSize.cy = GetInt(buff);}
01344 catch(...) {ret.m_dstScreenSize = CSize(0, 0); return(false);}
01345
01346 if(ret.m_dstScreenSize.cx <= 0)
01347 {
01348 ret.m_dstScreenSize.cx = (ret.m_dstScreenSize.cy == 1024)
01349 ? 1280
01350 : ret.m_dstScreenSize.cy * 4 / 3;
01351 }
01352 }
01353 else if(entry == L"wrapstyle")
01354 {
01355 try {ret.m_defaultWrapStyle = GetInt(buff);}
01356 catch(...) {ret.m_defaultWrapStyle = 1; return(false);}
01357 }
01358 else if(entry == L"scripttype")
01359 {
01360 if(buff.GetLength() >= 4 && !buff.Right(4).CompareNoCase(L"4.00")) version = sver = 4;
01361 else if(buff.GetLength() >= 5 && !buff.Right(5).CompareNoCase(L"4.00+")) version = sver = 5;
01362 }
01363 else if(entry == L"collisions")
01364 {
01365 buff = GetStr(buff);
01366 buff.MakeLower();
01367 ret.m_collisions = buff.Find(L"reverse") >= 0 ? 1 : 0;
01368 }
01369 else if(entry == L"scaledborderandshadow")
01370 {
01371 buff = GetStr(buff);
01372 buff.MakeLower();
01373 ret.m_fScaledBAS = buff.Find(L"yes") >= 0;
01374 }
01375 else if(entry == L"[v4 styles]")
01376 {
01377 fRet = true;
01378 sver = 4;
01379 }
01380 else if(entry == L"[v4+ styles]")
01381 {
01382 fRet = true;
01383 sver = 5;
01384 }
01385 else if(entry == L"style")
01386 {
01387 STSStyle* style = new STSStyle;
01388 if(!style) return(false);
01389
01390 try
01391 {
01392 CString StyleName;
01393 int alpha;
01394
01395 StyleName = WToT(GetStr(buff));
01396 style->fontName = WToT(GetStr(buff));
01397 style->fontSize = GetFloat(buff);
01398 for(int i = 0; i < 4; i++) style->colors[i] = (COLORREF)GetInt(buff);
01399 style->fontWeight = !!GetInt(buff) ? FW_BOLD : FW_NORMAL;
01400 style->fItalic = !!GetInt(buff);
01401 if(sver >= 5) style->fUnderline = !!GetInt(buff);
01402 if(sver >= 5) style->fStrikeOut = !!GetInt(buff);
01403 if(sver >= 5) style->fontScaleX = GetFloat(buff);
01404 if(sver >= 5) style->fontScaleY = GetFloat(buff);
01405 if(sver >= 5) style->fontSpacing = GetFloat(buff);
01406 if(sver >= 5) style->fontAngleZ = GetFloat(buff);
01407 if(sver >= 4) style->borderStyle = GetInt(buff);
01408 style->outlineWidth = GetFloat(buff);
01409 style->shadowDepth = GetFloat(buff);
01410 style->scrAlignment = GetInt(buff);
01411 style->marginRect.left = GetInt(buff);
01412 style->marginRect.right = GetInt(buff);
01413 style->marginRect.top = style->marginRect.bottom = GetInt(buff);
01414 if(sver <= 4) alpha = GetInt(buff);
01415 style->charSet = GetInt(buff);
01416
01417 if(sver <= 4) style->colors[2] = style->colors[3];
01418 if(sver <= 4) alpha = max(min(alpha, 0xff), 0);
01419 if(sver <= 4) {for(int i = 0; i < 3; i++) style->alpha[i] = alpha; style->alpha[3] = 0x80;}
01420 if(sver >= 5) for(int i = 0; i < 4; i++) {style->alpha[i] = (BYTE)(style->colors[i]>>24); style->colors[i] &= 0xffffff;}
01421 if(sver >= 5) style->fontScaleX = max(style->fontScaleX, 0);
01422 if(sver >= 5) style->fontScaleY = max(style->fontScaleY, 0);
01423 if(sver >= 5) style->fontSpacing = max(style->fontSpacing, 0);
01424 style->fontAngleX = style->fontAngleY = 0;
01425 style->borderStyle = style->borderStyle == 1 ? 0 : style->borderStyle == 3 ? 1 : 0;
01426 style->outlineWidth = max(style->outlineWidth, 0);
01427 style->shadowDepth = max(style->shadowDepth, 0);
01428 if(sver <= 4) style->scrAlignment = (style->scrAlignment&4) ? ((style->scrAlignment&3)+6)
01429 : (style->scrAlignment&8) ? ((style->scrAlignment&3)+3)
01430 : (style->scrAlignment&3);
01431
01432 StyleName.TrimLeft('*');
01433
01434 ret.AddStyle(StyleName, style);
01435 }
01436 catch(...)
01437 {
01438 delete style;
01439 return(false);
01440 }
01441 }
01442 else if(entry == L"[events]")
01443 {
01444 fRet = true;
01445 }
01446 else if(entry == _T("dialogue"))
01447 {
01448 try
01449 {
01450 int hh1, mm1, ss1, ms1_div10, hh2, mm2, ss2, ms2_div10, layer = 0;
01451 CString Style, Actor, Effect;
01452 CRect marginRect;
01453
01454 if(version <= 4){GetStr(buff, '='); GetInt(buff);}
01455 if(version >= 5)layer = GetInt(buff);
01456 hh1 = GetInt(buff, ':');
01457 mm1 = GetInt(buff, ':');
01458 ss1 = GetInt(buff, '.');
01459 ms1_div10 = GetInt(buff);
01460 hh2 = GetInt(buff, ':');
01461 mm2 = GetInt(buff, ':');
01462 ss2 = GetInt(buff, '.');
01463 ms2_div10 = GetInt(buff);
01464 Style = WToT(GetStr(buff));
01465 Actor = WToT(GetStr(buff));
01466 marginRect.left = GetInt(buff);
01467 marginRect.right = GetInt(buff);
01468 marginRect.top = marginRect.bottom = GetInt(buff);
01469 Effect = WToT(GetStr(buff));
01470
01471 int len = min(Effect.GetLength(), buff.GetLength());
01472 if(Effect.Left(len) == WToT(buff.Left(len))) Effect.Empty();
01473
01474 Style.TrimLeft('*');
01475 if(!Style.CompareNoCase(_T("Default"))) Style = _T("Default");
01476
01477 ret.Add(buff,
01478 file->IsUnicode(),
01479 (((hh1*60 + mm1)*60) + ss1)*1000 + ms1_div10*10,
01480 (((hh2*60 + mm2)*60) + ss2)*1000 + ms2_div10*10,
01481 Style, Actor, Effect,
01482 marginRect,
01483 layer);
01484 }
01485 catch(...)
01486 {
01487 return(false);
01488 }
01489 }
01490 else if(entry == L"fontname")
01491 {
01492 LoadUUEFont(file);
01493 }
01494 }
01495
01496 return(fRet);
01497 }
01498
01499 static bool OpenXombieSub(CTextFile* file, CSimpleTextSubtitle& ret, int CharSet)
01500 {
01501 float version = 0;
01502
01503
01504
01505 CStringW buff;
01506 while(file->ReadString(buff))
01507 {
01508 buff.Trim();
01509 if(buff.IsEmpty() || buff.GetAt(0) == ';') continue;
01510
01511 CStringW entry;
01512
01513
01514 entry = GetStr(buff, '=');
01515
01516
01517
01518 entry.MakeLower();
01519
01520 if(entry == L"version")
01521 {
01522 version = (float)GetFloat(buff);
01523 }
01524 else if(entry == L"screenhorizontal")
01525 {
01526 try {ret.m_dstScreenSize.cx = GetInt(buff);}
01527 catch(...) {ret.m_dstScreenSize = CSize(0, 0); return(false);}
01528
01529 if(ret.m_dstScreenSize.cy <= 0)
01530 {
01531 ret.m_dstScreenSize.cy = (ret.m_dstScreenSize.cx == 1280)
01532 ? 1024
01533 : ret.m_dstScreenSize.cx * 3 / 4;
01534 }
01535 }
01536 else if(entry == L"screenvertical")
01537 {
01538 try {ret.m_dstScreenSize.cy = GetInt(buff);}
01539 catch(...) {ret.m_dstScreenSize = CSize(0, 0); return(false);}
01540
01541 if(ret.m_dstScreenSize.cx <= 0)
01542 {
01543 ret.m_dstScreenSize.cx = (ret.m_dstScreenSize.cy == 1024)
01544 ? 1280
01545 : ret.m_dstScreenSize.cy * 4 / 3;
01546 }
01547 }
01548 else if(entry == L"style")
01549 {
01550 STSStyle* style = new STSStyle;
01551 if(!style) return(false);
01552
01553 try
01554 {
01555 CString StyleName;
01556
01557 StyleName = WToT(GetStr(buff)) + _T("_") + WToT(GetStr(buff));
01558 style->fontName = WToT(GetStr(buff));
01559 style->fontSize = GetFloat(buff);
01560 for(int i = 0; i < 4; i++) style->colors[i] = (COLORREF)GetInt(buff);
01561 for(int i = 0; i < 4; i++) style->alpha[i] = GetInt(buff);
01562 style->fontWeight = !!GetInt(buff) ? FW_BOLD : FW_NORMAL;
01563 style->fItalic = !!GetInt(buff);
01564 style->fUnderline = !!GetInt(buff);
01565 style->fStrikeOut = !!GetInt(buff);
01566 style->fBlur = !!GetInt(buff);
01567 style->fontScaleX = GetFloat(buff);
01568 style->fontScaleY = GetFloat(buff);
01569 style->fontSpacing = GetFloat(buff);
01570 style->fontAngleX = GetFloat(buff);
01571 style->fontAngleY = GetFloat(buff);
01572 style->fontAngleZ = GetFloat(buff);
01573 style->borderStyle = GetInt(buff);
01574 style->outlineWidth = GetFloat(buff);
01575 style->shadowDepth = GetFloat(buff);
01576 style->scrAlignment = GetInt(buff);
01577 style->marginRect.left = GetInt(buff);
01578 style->marginRect.right = GetInt(buff);
01579 style->marginRect.top = style->marginRect.bottom = GetInt(buff);
01580 style->charSet = GetInt(buff);
01581
01582 style->fontScaleX = max(style->fontScaleX, 0);
01583 style->fontScaleY = max(style->fontScaleY, 0);
01584 style->fontSpacing = max(style->fontSpacing, 0);
01585 style->borderStyle = style->borderStyle == 1 ? 0 : style->borderStyle == 3 ? 1 : 0;
01586 style->outlineWidth = max(style->outlineWidth, 0);
01587 style->shadowDepth = max(style->shadowDepth, 0);
01588
01589 ret.AddStyle(StyleName, style);
01590 }
01591 catch(...)
01592 {
01593 delete style;
01594 return(false);
01595 }
01596 }
01597 else if(entry == L"line")
01598 {
01599 try
01600 {
01601 CString id;
01602 int hh1, mm1, ss1, ms1, hh2, mm2, ss2, ms2, layer = 0;
01603 CString Style, Actor;
01604 CRect marginRect;
01605
01606 if(GetStr(buff) != L"D") continue;
01607 id = GetStr(buff);
01608 layer = GetInt(buff);
01609 hh1 = GetInt(buff, ':');
01610 mm1 = GetInt(buff, ':');
01611 ss1 = GetInt(buff, '.');
01612 ms1 = GetInt(buff);
01613 hh2 = GetInt(buff, ':');
01614 mm2 = GetInt(buff, ':');
01615 ss2 = GetInt(buff, '.');
01616 ms2 = GetInt(buff);
01617 Style = WToT(GetStr(buff)) + _T("_") + WToT(GetStr(buff));
01618 Actor = WToT(GetStr(buff));
01619 marginRect.left = GetInt(buff);
01620 marginRect.right = GetInt(buff);
01621 marginRect.top = marginRect.bottom = GetInt(buff);
01622
01623 Style.TrimLeft('*');
01624 if(!Style.CompareNoCase(_T("Default"))) Style = _T("Default");
01625
01626 ret.Add(buff,
01627 file->IsUnicode(),
01628 (((hh1*60 + mm1)*60) + ss1)*1000 + ms1,
01629 (((hh2*60 + mm2)*60) + ss2)*1000 + ms2,
01630 Style, Actor, _T(""),
01631 marginRect,
01632 layer);
01633 }
01634 catch(...)
01635 {
01636 return(false);
01637 }
01638 }
01639 else if(entry == L"fontname")
01640 {
01641 LoadUUEFont(file);
01642 }
01643 }
01644
01645 return(ret.GetCount() > 0);
01646 }
01647
01648 #include "USFSubtitles.h"
01649
01650 static bool OpenUSF(CTextFile* file, CSimpleTextSubtitle& ret, int CharSet)
01651 {
01652 CString str;
01653 while(file->ReadString(str))
01654 {
01655 if(str.Find(_T("USFSubtitles")) >= 0)
01656 {
01657 CUSFSubtitles usf;
01658 if(usf.Read(file->GetFilePath()) && usf.ConvertToSTS(ret))
01659 return(true);
01660
01661 break;
01662 }
01663 }
01664
01665 return(false);
01666 }
01667
01668 static CStringW MPL22SSA(CStringW str)
01669 {
01670 CList<CStringW> sl;
01671 Explode(str, sl, '|');
01672 POSITION pos = sl.GetHeadPosition();
01673 while(pos)
01674 {
01675 CStringW& s = sl.GetNext(pos);
01676 if(s[0] == '/') {s = L"{\\i1}" + s.Mid(1) + L"{\\i0}";}
01677 }
01678 str = Implode(sl, '\n');
01679 str.Replace(L"\n", L"\\N");
01680 return str;
01681 }
01682
01683 static bool OpenMPL2(CTextFile* file, CSimpleTextSubtitle& ret, int CharSet)
01684 {
01685 CStringW buff;;
01686 while(file->ReadString(buff))
01687 {
01688 buff.Trim();
01689 if(buff.IsEmpty()) continue;
01690
01691 int start, end;
01692 int c = swscanf(buff, L"[%d][%d]", &start, &end);
01693
01694 if(c == 2)
01695 {
01696 ret.Add(
01697 MPL22SSA(buff.Mid(buff.Find(']', buff.Find(']')+1)+1)),
01698 file->IsUnicode(),
01699 start*100, end*100);
01700 }
01701 else if(c != EOF)
01702 {
01703 return(false);
01704 }
01705 }
01706
01707 return(ret.GetCount() > 0);
01708 }
01709
01710 typedef bool (*STSOpenFunct)(CTextFile* file, CSimpleTextSubtitle& ret, int CharSet);
01711
01712 typedef struct {STSOpenFunct open; tmode mode;} OpenFunctStruct;
01713
01714 static OpenFunctStruct OpenFuncts[] =
01715 {
01716 OpenSubRipper, TIME,
01717 OpenOldSubRipper, TIME,
01718 OpenSubViewer, TIME,
01719 OpenMicroDVD, FRAME,
01720 OpenSami, TIME,
01721 OpenVPlayer, TIME,
01722 OpenSubStationAlpha, TIME,
01723 OpenXombieSub, TIME,
01724 OpenUSF, TIME,
01725 OpenMPL2, TIME,
01726 };
01727
01728 static int nOpenFuncts = countof(OpenFuncts);
01729
01730
01731
01732 CSimpleTextSubtitle::CSimpleTextSubtitle()
01733 {
01734 m_mode = TIME;
01735 m_dstScreenSize = CSize(0, 0);
01736 m_defaultWrapStyle = 0;
01737 m_collisions = 0;
01738 m_fScaledBAS = false;
01739 m_encoding = CTextFile::ASCII;
01740 }
01741
01742 CSimpleTextSubtitle::~CSimpleTextSubtitle()
01743 {
01744 Empty();
01745 }
01746
01747
01748
01749
01750
01751
01752
01753
01754
01755
01756
01757
01758
01759
01760
01761
01762
01763
01764
01765
01766
01767
01768
01769
01770
01771
01772 void CSimpleTextSubtitle::Copy(CSimpleTextSubtitle& sts)
01773 {
01774 Empty();
01775
01776 m_name = sts.m_name;
01777 m_mode = sts.m_mode;
01778 m_dstScreenSize = sts.m_dstScreenSize;
01779 m_defaultWrapStyle = sts.m_defaultWrapStyle;
01780 m_collisions = sts.m_collisions;
01781 m_fScaledBAS = sts.m_fScaledBAS;
01782 m_encoding = sts.m_encoding;
01783 m_fUsingAutoGeneratedDefaultStyle = sts.m_fUsingAutoGeneratedDefaultStyle;
01784 CopyStyles(sts.m_styles);
01785 m_segments.Copy(sts.m_segments);
01786 CSTSArray::Copy(sts);
01787 }
01788
01789 void CSimpleTextSubtitle::Append(CSimpleTextSubtitle& sts, int timeoff)
01790 {
01791 if(timeoff < 0)
01792 {
01793 timeoff = GetSize() > 0 ? GetAt(GetSize()-1).end : 0;
01794 }
01795
01796 for(int i = 0, j = GetSize(); i < j; i++)
01797 {
01798 if(GetAt(i).start > timeoff)
01799 {
01800 RemoveAt(i, j - i);
01801 break;
01802 }
01803 }
01804
01805 CopyStyles(sts.m_styles, true);
01806
01807 for(int i = 0, j = sts.GetSize(); i < j; i++)
01808 {
01809 STSEntry stse = sts.GetAt(i);
01810 stse.start += timeoff;
01811 stse.end += timeoff;
01812 stse.readorder += GetSize();
01813 CSTSArray::Add(stse);
01814 }
01815
01816 CreateSegments();
01817 }
01818
01819 void CSTSStyleMap::Free()
01820 {
01821 POSITION pos = GetStartPosition();
01822 while(pos)
01823 {
01824 CString key;
01825 void* ptr;
01826 GetNextAssoc(pos, key, ptr);
01827 delete (STSStyle*)ptr;
01828 }
01829
01830 RemoveAll();
01831 }
01832
01833 bool CSimpleTextSubtitle::CopyStyles(const CSTSStyleMap& styles, bool fAppend)
01834 {
01835 if(!fAppend) m_styles.Free();
01836
01837 POSITION pos = styles.GetStartPosition();
01838 while(pos)
01839 {
01840 CString key;
01841 void* ptr;
01842 styles.GetNextAssoc(pos, key, ptr);
01843
01844 STSStyle* s = new STSStyle;
01845 if(!s) return(false);
01846
01847 *s = *((STSStyle*)ptr);
01848
01849 AddStyle(key, s);
01850 }
01851
01852 return(true);
01853 }
01854
01855 void CSimpleTextSubtitle::Empty()
01856 {
01857 m_dstScreenSize = CSize(0, 0);
01858 m_styles.Free();
01859 m_segments.RemoveAll();
01860 RemoveAll();
01861 }
01862
01863 void CSimpleTextSubtitle::Add(CStringW str, bool fUnicode, int start, int end, CString style, CString actor, CString effect, CRect marginRect, int layer, int readorder)
01864 {
01865 if(str.Trim().IsEmpty() || start > end) return;
01866
01867 str.Remove('\r');
01868 str.Replace(L"\n", L"\\N");
01869 if(style.IsEmpty()) style = _T("Default");
01870 style.TrimLeft('*');
01871
01872 STSEntry sub;
01873 sub.str = str;
01874 sub.fUnicode = fUnicode;
01875 sub.style = style;
01876 sub.actor = actor;
01877 sub.effect = effect;
01878 sub.marginRect = marginRect;
01879 sub.layer = layer;
01880 sub.start = start;
01881 sub.end = end;
01882 sub.readorder = readorder < 0 ? GetSize() : readorder;
01883 int n = CSTSArray::Add(sub);
01884
01885 int len = m_segments.GetSize();
01886
01887 if(len == 0)
01888 {
01889 STSSegment stss(start, end);
01890 stss.subs.Add(n);
01891 m_segments.Add(stss);
01892 }
01893 else if(end <= m_segments[0].start)
01894 {
01895 STSSegment stss(start, end);
01896 stss.subs.Add(n);
01897 m_segments.InsertAt(0, stss);
01898 }
01899 else if(start >= m_segments[len-1].end)
01900 {
01901 STSSegment stss(start, end);
01902 stss.subs.Add(n);
01903 m_segments.Add(stss);
01904 }
01905 else
01906 {
01907 if(start < m_segments[0].start)
01908 {
01909 STSSegment stss(start, m_segments[0].start);
01910 stss.subs.Add(n);
01911 start = m_segments[0].start;
01912 m_segments.InsertAt(0, stss);
01913 }
01914
01915 for(int i = 0; i < m_segments.GetCount(); i++)
01916 {
01917 STSSegment& s = m_segments[i];
01918
01919 if(start >= s.end)
01920 continue;
01921
01922 if(end <= s.start)
01923 break;
01924
01925 if(s.start < start && start < s.end)
01926 {
01927 STSSegment stss(s.start, start);
01928 stss.subs.Copy(s.subs);
01929 s.start = start;
01930 m_segments.InsertAt(i, stss);
01931 continue;
01932 }
01933
01934 if(start <= s.start && s.end <= end)
01935 {
01936 for(int j = 0, k = s.subs.GetCount(); j <= k; j++)
01937 {
01938 if(j == k || sub.readorder < GetAt(s.subs[j]).readorder)
01939 s.subs.InsertAt(j, n);
01940 }
01941
01942 }
01943
01944 if(s.start < end && end < s.end)
01945 {
01946 STSSegment stss(s.start, end);
01947 stss.subs.Copy(s.subs);
01948 for(int j = 0, k = s.subs.GetCount(); j <= k; j++)
01949 {
01950 if(j == k || sub.readorder < GetAt(stss.subs[j]).readorder)
01951 stss.subs.InsertAt(j, n);
01952 }
01953
01954 s.start = end;
01955 m_segments.InsertAt(i, stss);
01956 }
01957 }
01958
01959 if(end > m_segments[m_segments.GetCount()-1].end)
01960 {
01961 STSSegment stss(m_segments[m_segments.GetCount()-1].end, end);
01962 stss.subs.Add(n);
01963 m_segments.Add(stss);
01964 }
01965 }
01966
01967
01968
01969
01970
01971
01972
01973
01974
01975
01976
01977
01978
01979
01980
01981
01982
01983
01984
01985
01986
01987
01988
01989
01990
01991
01992
01993
01994
01995
01996
01997
01998
01999
02000
02001
02002
02003
02004
02005
02006
02007
02008
02009
02010
02011
02012
02013 }
02014
02015 void CSimpleTextSubtitle::CreateDefaultStyle(int CharSet)
02016 {
02017 CString def(_T("Default"));
02018 void* value;
02019
02020
02021 if(!m_styles.Lookup(def, value))
02022 {
02023 STSStyle* style = new STSStyle;
02024 if(!style) return;
02025
02026 style->charSet = CharSet;
02027
02028 AddStyle(def, style);
02029
02030
02031
02032
02033
02034
02035 m_fUsingAutoGeneratedDefaultStyle = true;
02036 }
02037 else
02038 {
02039 m_fUsingAutoGeneratedDefaultStyle = false;
02040 }
02041 }
02042
02043 void CSimpleTextSubtitle::ChangeUnknownStylesToDefault()
02044 {
02045 CMapStringToPtr unknown;
02046 bool fReport = true;
02047
02048 for(int i = 0; i < GetSize(); i++)
02049 {
02050 STSEntry& stse = GetAt(i);
02051
02052 void* val;
02053 if(!m_styles.Lookup(stse.style, val))
02054 {
02055 if(!unknown.Lookup(stse.style, val))
02056 {
02057 if(fReport)
02058 {
02059 CString msg;
02060 msg.Format(_T("Unknown style found: \"%s\", changed to \"Default\"!\n\nPress Cancel to ignore further warnings."), stse.style);
02061 if(MessageBox(NULL, msg, _T("Warning"), MB_OKCANCEL|MB_ICONWARNING) != IDOK) fReport = false;
02062 }
02063
02064 unknown[stse.style] = NULL;
02065 }
02066
02067 stse.style = _T("Default");
02068 }
02069 }
02070 }
02071
02072 void CSimpleTextSubtitle::AddStyle(CString name, STSStyle* style)
02073 {
02074 int i, j;
02075
02076 if(name.IsEmpty()) name = _T("Default");
02077
02078 void* value;
02079 if(m_styles.Lookup(name, value))
02080 {
02081 if(*((STSStyle*)value) == *style)
02082 {
02083 delete style;
02084 return;
02085 }
02086
02087 int len = name.GetLength();
02088
02089 for(i = len; i > 0 && _istdigit(name[i-1]); i--);
02090
02091 int idx = 1;
02092
02093 CString name2 = name;
02094
02095 if(i < len && _stscanf(name.Right(len-i), _T("%d"), &idx) == 1)
02096 {
02097 name2 = name.Left(i);
02098 }
02099
02100 idx++;
02101
02102 CString name3;
02103 do
02104 {
02105 name3.Format(_T("%s%d"), name2, idx);
02106 idx++;
02107 }
02108 while(m_styles[name3]);
02109
02110 m_styles.RemoveKey(name);
02111 m_styles[name3] = (STSStyle*)value;
02112
02113 for(i = 0, j = GetSize(); i < j; i++)
02114 {
02115 STSEntry& stse = GetAt(i);
02116 if(stse.style == name) stse.style = name3;
02117 }
02118 }
02119
02120 m_styles[name] = style;
02121 }
02122
02123 bool CSimpleTextSubtitle::SetDefaultStyle(STSStyle& s)
02124 {
02125 void* val;
02126 if(m_styles.Lookup(_T("Default"), val))
02127 {
02128 *((STSStyle*)val) = s;
02129 m_fUsingAutoGeneratedDefaultStyle = false;
02130 return(true);
02131 }
02132
02133 return(false);
02134 }
02135
02136 bool CSimpleTextSubtitle::GetDefaultStyle(STSStyle& s)
02137 {
02138 void* val;
02139 if(m_styles.Lookup(_T("Default"), val))
02140 {
02141 s = *((STSStyle*)val);
02142 return(true);
02143 }
02144
02145 return(false);
02146 }
02147
02148 void CSimpleTextSubtitle::ConvertToTimeBased(double fps)
02149 {
02150 if(m_mode == TIME) return;
02151
02152 for(int i = 0, j = GetSize(); i < j; i++)
02153 {
02154 STSEntry& stse = (*this)[i];
02155 stse.start = int(1.0 * stse.start * 1000 / fps + 0.5);
02156 stse.end = int(1.0 * stse.end * 1000 / fps + 0.5);
02157 }
02158
02159 m_mode = TIME;
02160
02161 CreateSegments();
02162 }
02163
02164 void CSimpleTextSubtitle::ConvertToFrameBased(double fps)
02165 {
02166 if(m_mode == FRAME) return;
02167
02168 for(int i = 0, j = GetSize(); i < j; i++)
02169 {
02170 STSEntry& stse = (*this)[i];
02171 stse.start = int(1.0 * stse.start * fps / 1000 + 0.5);
02172 stse.end = int(1.0 * stse.end * fps / 1000 + 0.5);
02173 }
02174
02175 m_mode = FRAME;
02176
02177 CreateSegments();
02178 }
02179
02180 int CSimpleTextSubtitle::SearchSub(int t, double fps)
02181 {
02182 int i = 0, j = GetSize() - 1, ret = -1;
02183
02184 if(j >= 0 && t >= TranslateStart(j, fps))
02185 {
02186 return(j);
02187 }
02188
02189 while(i < j)
02190 {
02191 int mid = (i + j) >> 1;
02192
02193 int midt = TranslateStart(mid, fps);
02194
02195 if(t == midt)
02196 {
02197 while(mid > 0 && t == TranslateStart(mid-1, fps)) mid--;
02198 ret = mid;
02199 break;
02200 }
02201 else if(t < midt)
02202 {
02203 ret = -1;
02204 if(j == mid) mid--;
02205 j = mid;
02206 }
02207 else if(t > midt)
02208 {
02209 ret = mid;
02210 if(i == mid) mid++;
02211 i = mid;
02212 }
02213 }
02214
02215 return(ret);
02216 }
02217
02218 const STSSegment* CSimpleTextSubtitle::SearchSubs(int t, double fps, int* iSegment, int* nSegments)
02219 {
02220 int i = 0, j = m_segments.GetSize() - 1, ret = -1;
02221
02222 if(nSegments) *nSegments = j+1;
02223
02224 if(j >= 0 && t >= TranslateSegmentStart(j, fps) && t < TranslateSegmentEnd(j, fps))
02225 {
02226 if(iSegment) *iSegment = j;
02227 return(&m_segments[j]);
02228 }
02229
02230 if(j >= 0 && t >= TranslateSegmentEnd(j, fps))
02231 {
02232 if(iSegment) *iSegment = j+1;
02233 return(NULL);
02234 }
02235
02236 if(j > 0 && t < TranslateSegmentStart(i, fps))
02237 {
02238 if(iSegment) *iSegment = -1;
02239 return(NULL);
02240 }
02241
02242 while(i < j)
02243 {
02244 int mid = (i + j) >> 1;
02245
02246 int midt = TranslateSegmentStart(mid, fps);
02247
02248 if(t == midt)
02249 {
02250 ret = mid;
02251 break;
02252 }
02253 else if(t < midt)
02254 {
02255 ret = -1;
02256 if(j == mid) mid--;
02257 j = mid;
02258 }
02259 else if(t > midt)
02260 {
02261 ret = mid;
02262 if(i == mid) mid++;
02263 i = mid;
02264 }
02265 }
02266
02267 if(0 <= ret && ret < m_segments.GetSize())
02268 {
02269 if(iSegment) *iSegment = ret;
02270 }
02271
02272 if(0 <= ret && ret < m_segments.GetSize()
02273 && m_segments[ret].subs.GetSize() > 0
02274 && TranslateSegmentStart(ret, fps) <= t && t < TranslateSegmentEnd(ret, fps))
02275 {
02276 return(&m_segments[ret]);
02277 }
02278
02279 return(NULL);
02280 }
02281
02282 int CSimpleTextSubtitle::TranslateStart(int i, double fps)
02283 {
02284 return(i < 0 || GetSize() <= i ? -1 :
02285 m_mode == TIME ? GetAt(i).start :
02286 m_mode == FRAME ? (int)(GetAt(i).start*1000/fps) :
02287 0);
02288 }
02289
02290 int CSimpleTextSubtitle::TranslateEnd(int i, double fps)
02291 {
02292 return(i < 0 || GetSize() <= i ? -1 :
02293 m_mode == TIME ? GetAt(i).end :
02294 m_mode == FRAME ? (int)(GetAt(i).end*1000/fps) :
02295 0);
02296 }
02297
02298 int CSimpleTextSubtitle::TranslateSegmentStart(int i, double fps)
02299 {
02300 return(i < 0 || m_segments.GetSize() <= i ? -1 :
02301 m_mode == TIME ? m_segments[i].start :
02302 m_mode == FRAME ? (int)(m_segments[i].start*1000/fps) :
02303 0);
02304 }
02305
02306 int CSimpleTextSubtitle::TranslateSegmentEnd(int i, double fps)
02307 {
02308 return(i < 0 || m_segments.GetSize() <= i ? -1 :
02309 m_mode == TIME ? m_segments[i].end :
02310 m_mode == FRAME ? (int)(m_segments[i].end*1000/fps) :
02311 0);
02312 }
02313
02314 STSStyle* CSimpleTextSubtitle::GetStyle(int i)
02315 {
02316 STSStyle* style = (STSStyle*)m_styles[GetAt(i).style];
02317 if(!style) style = (STSStyle*)m_styles[_T("Default")];
02318 ASSERT(style);
02319 return(style);
02320 }
02321
02322 bool CSimpleTextSubtitle::GetStyle(int i, STSStyle& stss)
02323 {
02324 CString def = _T("Default");
02325
02326 STSStyle* style = (STSStyle*)m_styles[GetAt(i).style];
02327 STSStyle* defstyle = (STSStyle*)m_styles[def];
02328 if(!style) {if(defstyle) {ASSERT(0); CreateDefaultStyle(DEFAULT_CHARSET); defstyle = (STSStyle*)m_styles[def];} style = defstyle;}
02329 if(!style) {ASSERT(0); return(false);}
02330 stss = *style;
02331 if(stss.relativeTo == 2 && defstyle)
02332 stss.relativeTo = defstyle->relativeTo;
02333 return(true);
02334 }
02335
02336 int CSimpleTextSubtitle::GetCharSet(int i)
02337 {
02338 STSStyle stss;
02339 GetStyle(i, stss);
02340 return(stss.charSet);
02341 }
02342
02343 bool CSimpleTextSubtitle::IsEntryUnicode(int i)
02344 {
02345 return(GetAt(i).fUnicode);
02346 }
02347
02348 void CSimpleTextSubtitle::ConvertUnicode(int i, bool fUnicode)
02349 {
02350 STSEntry& stse = GetAt(i);
02351
02352 if(stse.fUnicode ^ fUnicode)
02353 {
02354 int CharSet = GetCharSet(i);
02355
02356 stse.str = fUnicode
02357 ? MBCSSSAToUnicode(stse.str, CharSet)
02358 : UnicodeSSAToMBCS(stse.str, CharSet);
02359
02360 stse.fUnicode = fUnicode;
02361 }
02362 }
02363
02364 CStringA CSimpleTextSubtitle::GetStrA(int i, bool fSSA)
02365 {
02366 return(WToA(GetStrWA(i, fSSA)));
02367 }
02368
02369 CStringW CSimpleTextSubtitle::GetStrW(int i, bool fSSA)
02370 {
02371 bool fUnicode = IsEntryUnicode(i);
02372 int CharSet = GetCharSet(i);
02373
02374 CStringW str = GetAt(i).str;
02375
02376 if(!fUnicode)
02377 str = MBCSSSAToUnicode(str, CharSet);
02378
02379 if(!fSSA)
02380 str = RemoveSSATags(str, fUnicode, CharSet);
02381
02382 return(str);
02383 }
02384
02385 CStringW CSimpleTextSubtitle::GetStrWA(int i, bool fSSA)
02386 {
02387 bool fUnicode = IsEntryUnicode(i);
02388 int CharSet = GetCharSet(i);
02389
02390 CStringW str = GetAt(i).str;
02391
02392 if(fUnicode)
02393 str = UnicodeSSAToMBCS(str, CharSet);
02394
02395 if(!fSSA)
02396 str = RemoveSSATags(str, fUnicode, CharSet);
02397
02398 return(str);
02399 }
02400
02401 void CSimpleTextSubtitle::SetStr(int i, CStringA str, bool fUnicode)
02402 {
02403 SetStr(i, AToW(str), false);
02404 }
02405
02406 void CSimpleTextSubtitle::SetStr(int i, CStringW str, bool fUnicode)
02407 {
02408 STSEntry& stse = GetAt(i);
02409
02410 str.Replace(L"\n", L"\\N");
02411
02412 if(stse.fUnicode && !fUnicode) stse.str = MBCSSSAToUnicode(str, GetCharSet(i));
02413 else if(!stse.fUnicode && fUnicode) stse.str = UnicodeSSAToMBCS(str, GetCharSet(i));
02414 else stse.str = str;
02415 }
02416
02417 static int comp1(const void* a, const void* b)
02418 {
02419 int ret = ((STSEntry*)a)->start - ((STSEntry*)b)->start;
02420 if(ret == 0) ret = ((STSEntry*)a)->layer - ((STSEntry*)b)->layer;
02421 if(ret == 0) ret = ((STSEntry*)a)->readorder - ((STSEntry*)b)->readorder;
02422 return(ret);
02423 }
02424
02425 static int comp2(const void* a, const void* b)
02426 {
02427 return(((STSEntry*)a)->readorder - ((STSEntry*)b)->readorder);
02428 }
02429
02430 void CSimpleTextSubtitle::Sort(bool fRestoreReadorder)
02431 {
02432 qsort(GetData(), GetSize(), sizeof(STSEntry), !fRestoreReadorder ? comp1 : comp2);
02433 CreateSegments();
02434 }
02435
02436 static int intcomp(const void* i1, const void* i2)
02437 {
02438 return(*((int*)i1) - *((int*)i2));
02439 }
02440
02441 void CSimpleTextSubtitle::CreateSegments()
02442 {
02443 m_segments.RemoveAll();
02444
02445 int i, j;
02446
02447 CArray<int> breakpoints;
02448
02449 for(i = 0; i < GetSize(); i++)
02450 {
02451 STSEntry& stse = GetAt(i);
02452 breakpoints.Add(stse.start);
02453 breakpoints.Add(stse.end);
02454 }
02455
02456 qsort(breakpoints.GetData(), breakpoints.GetSize(), sizeof(int), intcomp);
02457
02458 int* ptr = breakpoints.GetData(), prev = ptr ? *ptr : NULL;
02459
02460 for(i = breakpoints.GetSize(); i > 0; i--, ptr++)
02461 {
02462 if(*ptr != prev)
02463 {
02464 m_segments.Add(STSSegment(prev, *ptr));
02465 prev = *ptr;
02466 }
02467 }
02468
02469 for(i = 0; i < GetSize(); i++)
02470 {
02471 STSEntry& stse = GetAt(i);
02472 for(j = 0; j < m_segments.GetSize() && m_segments[j].start < stse.start; j++);
02473 for(; j < m_segments.GetSize() && m_segments[j].end <= stse.end; j++)
02474 m_segments[j].subs.Add(i);
02475 }
02476
02477 OnChanged();
02478
02479
02480
02481
02482
02483
02484
02485
02486
02487
02488
02489
02490
02491
02492
02493 }
02494
02495 bool CSimpleTextSubtitle::Open(CString fn, int CharSet, CString name)
02496 {
02497 Empty();
02498
02499 CWebTextFile f;
02500 if(!f.Open(fn)) return(false);
02501
02502 fn.Replace('\\', '/');
02503 if(name.IsEmpty())
02504 {
02505 name = fn.Left(fn.ReverseFind('.'));
02506 name = name.Mid(name.ReverseFind('/')+1);
02507 name = name.Mid(name.ReverseFind('.')+1);
02508 }
02509
02510 return(Open(&f, CharSet, name));
02511 }
02512
02513 static int CountLines(CTextFile* f, ULONGLONG from, ULONGLONG to)
02514 {
02515 int n = 0;
02516 CString s;
02517 f->Seek(from, 0);
02518 while(f->ReadString(s) && f->GetPosition() < to) n++;
02519 return(n);
02520 }
02521
02522 bool CSimpleTextSubtitle::Open(CTextFile* f, int CharSet, CString name)
02523 {
02524 Empty();
02525
02526 ULONGLONG pos = f->GetPosition();
02527
02528 for(int i = 0; i < nOpenFuncts; i++)
02529 {
02530 if(!OpenFuncts[i].open(f, *this, CharSet) )
02531 {
02532 if(GetSize() > 0)
02533 {
02534 int n = CountLines(f, pos, f->GetPosition());
02535 CString s;
02536 s.Format(_T("Syntax error at line %d!\t"), n+1);
02537 AfxMessageBox(s, MB_OK|MB_ICONERROR);
02538 Empty();
02539 break;
02540 }
02541
02542 f->Seek(pos, 0);
02543 Empty();
02544 continue;
02545 }
02546
02547 m_name = name;
02548 m_mode = OpenFuncts[i].mode;
02549 m_encoding = f->GetEncoding();
02550 m_path = f->GetFilePath();
02551
02552
02553 CreateSegments();
02554
02555 CWebTextFile f2;
02556 if(f2.Open(f->GetFilePath() + _T(".style")))
02557 OpenSubStationAlpha(&f2, *this, CharSet);
02558
02559 CreateDefaultStyle(CharSet);
02560
02561 ChangeUnknownStylesToDefault();
02562
02563 if(m_dstScreenSize == CSize(0, 0)) m_dstScreenSize = CSize(384, 288);
02564
02565 return(true);
02566 }
02567
02568 return(false);
02569 }
02570
02571 bool CSimpleTextSubtitle::Open(BYTE* data, int len, int CharSet, CString name)
02572 {
02573 TCHAR path[MAX_PATH];
02574 if(!GetTempPath(MAX_PATH, path)) return(false);
02575
02576 TCHAR fn[MAX_PATH];
02577 if(!GetTempFileName(path, _T("vs"), 0, fn)) return(false);
02578
02579 FILE* tmp = _tfopen(fn, _T("wb"));
02580 if(!tmp) return(false);
02581
02582 int i = 0;
02583 for(; i <= (len-1024); i += 1024) fwrite(&data[i], 1024, 1, tmp);
02584 if(len > i) fwrite(&data[i], len - i, 1, tmp);
02585
02586 fclose(tmp);
02587
02588 bool fRet = Open(fn, CharSet, name);
02589
02590 _tremove(fn);
02591
02592 return(fRet);
02593 }
02594
02595 bool CSimpleTextSubtitle::SaveAs(CString fn, exttype et, double fps, CTextFile::enc e)
02596 {
02597 if(fn.Mid(fn.ReverseFind('.')+1).CompareNoCase(exttypestr[et]))
02598 {
02599 if(fn[fn.GetLength()-1] != '.') fn += _T(".");
02600 fn += exttypestr[et];
02601 }
02602
02603 CTextFile f;
02604 if(!f.Save(fn, e))
02605 return(false);
02606
02607 if(et == EXTSMI)
02608 {
02609 CString str;
02610
02611 str += _T("<SAMI>\n<HEAD>\n");
02612 str += _T("<STYLE TYPE=\"text/css\">\n");
02613 str += _T("<!--\n");
02614 str += _T("P {margin-left: 16pt; margin-right: 16pt; margin-bottom: 16pt; margin-top: 16pt;\n");
02615 str += _T(" text-align: center; font-size: 18pt; font-family: arial; font-weight: bold; color: #f0f0f0;}\n");
02616 str += _T(".UNKNOWNCC {Name:Unknown; lang:en-US; SAMIType:CC;}\n");
02617 str += _T("-->\n");
02618 str += _T("</STYLE>\n");
02619 str += _T("</HEAD>\n");
02620 str += _T("\n");
02621 str += _T("<BODY>\n");
02622
02623 f.WriteString(str);
02624 }
02625 else if(et == EXTSSA || et == EXTASS)
02626 {
02627 CString str;
02628
02629 str = _T("[Script Info]\n");
02630 str += (et == EXTSSA) ? _T("; This is a Sub Station Alpha v4 script.\n") : _T("; This is an Advanced Sub Station Alpha v4+ script.\n");
02631 str += _T("; For Sub Station Alpha info and downloads,\n");
02632 str += _T("; go to http://www.eswat.demon.co.uk/\n");
02633 str += _T("; or email [email protected]\n");
02634 str += _T("; \n");
02635 if(et == EXTASS)
02636 {
02637 str += _T("; Advanced Sub Station Alpha script format developed by #Anime-Fansubs@EfNET\n");
02638 str += _T("; http://www.anime-fansubs.org\n");
02639 str += _T("; \n");
02640 str += _T("; For additional info and downloads go to http://gabest.org/\n");
02641 str += _T("; or email [email protected]\n");
02642 str += _T("; \n");
02643 }
02644 str += _T("; Note: This file was saved by Subresync.\n");
02645 str += _T("; \n");
02646 str += (et == EXTSSA) ? _T("ScriptType: v4.00\n") : _T("ScriptType: v4.00+\n");
02647 str += (m_collisions == 0) ? _T("Collisions: Normal\n") : _T("Collisions: Reverse\n");
02648 if(et == EXTASS && m_fScaledBAS) str += _T("ScaledBorderAndShadow: Yes\n");
02649 str += _T("PlayResX: %d\n");
02650 str += _T("PlayResY: %d\n");
02651 str += _T("Timer: 100.0000\n");
02652 str += _T("\n");
02653 str += (et == EXTSSA)
02654 ? _T("[V4 Styles]\nFormat: Name, Fontname, Fontsize, PrimaryColour, SecondaryColour, TertiaryColour, BackColour, Bold, Italic, BorderStyle, Outline, Shadow, Alignment, MarginL, MarginR, MarginV, AlphaLevel, Encoding\n")
02655 : _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");
02656
02657 CString str2;
02658 str2.Format(str, m_dstScreenSize.cx, m_dstScreenSize.cy);
02659 f.WriteString(str2);
02660
02661 str = (et == EXTSSA)
02662 ? _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")
02663 : _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");
02664
02665 POSITION pos = m_styles.GetStartPosition();
02666 while(pos)
02667 {
02668 CString key;
02669 void* ptr;
02670 m_styles.GetNextAssoc(pos, key, ptr);
02671 STSStyle* s = (STSStyle*)ptr;
02672
02673 if(et == EXTSSA)
02674 {
02675 CString str2;
02676 str2.Format(str, key,
02677 s->fontName, (int)s->fontSize,
02678 s->colors[0]&0xffffff,
02679 s->colors[1]&0xffffff,
02680 s->colors[2]&0xffffff,
02681 s->colors[3]&0xffffff,
02682 s->fontWeight > FW_NORMAL ? -1 : 0, s->fItalic ? -1 : 0,
02683 s->borderStyle == 0 ? 1 : s->borderStyle == 1 ? 3 : 0,
02684 (int)s->outlineWidth, (int)s->shadowDepth,
02685 s->scrAlignment <= 3 ? s->scrAlignment : s->scrAlignment <= 6 ? ((s->scrAlignment-3)|8) : s->scrAlignment <= 9 ? ((s->scrAlignment-6)|4) : 2,
02686 s->marginRect.left, s->marginRect.right, (s->marginRect.top + s->marginRect.bottom) / 2,
02687 s->alpha[0],
02688 s->charSet);
02689 f.WriteString(str2);
02690 }
02691 else
02692 {
02693 CString str2;
02694 str2.Format(str, key,
02695 s->fontName, (int)s->fontSize,
02696 (s->colors[0]&0xffffff) | (s->alpha[0]<<24),
02697 (s->colors[1]&0xffffff) | (s->alpha[1]<<24),
02698 (s->colors[2]&0xffffff) | (s->alpha[2]<<24),
02699 (s->colors[3]&0xffffff) | (s->alpha[3]<<24),
02700 s->fontWeight > FW_NORMAL ? -1 : 0,
02701 s->fItalic ? -1 : 0, s->fUnderline ? -1 : 0, s->fStrikeOut ? -1 : 0,
02702 (int)s->fontScaleX, (int)s->fontScaleY,
02703 (int)s->fontSpacing, (float)s->fontAngleZ,
02704 s->borderStyle == 0 ? 1 : s->borderStyle == 1 ? 3 : 0,
02705 (int)s->outlineWidth, (int)s->shadowDepth,
02706 s->scrAlignment,
02707 s->marginRect.left, s->marginRect.right, (s->marginRect.top + s->marginRect.bottom) / 2,
02708 s->charSet);
02709 f.WriteString(str2);
02710 }
02711 }
02712
02713 if(GetSize() > 0)
02714 {
02715 str = _T("\n");
02716 str += _T("[Events]\n");
02717 str += (et == EXTSSA)
02718 ? _T("Format: Marked, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text\n")
02719 : _T("Format: Layer, Start, End, Style, Actor, MarginL, MarginR, MarginV, Effect, Text\n");
02720 f.WriteString(str);
02721 }
02722 }
02723
02724 CStringW fmt =
02725 et == EXTSRT ? L"%d\n%02d:%02d:%02d,%03d --> %02d:%02d:%02d,%03d\n%s\n\n" :
02726 et == EXTSUB ? L"{%d}{%d}%s\n" :
02727 et == EXTSMI ? L"<SYNC Start=%d><P Class=UNKNOWNCC>\n%s\n<SYNC Start=%d><P Class=UNKNOWNCC> \n" :
02728 et == EXTPSB ? L"{%d:%02d:%02d}{%d:%02d:%02d}%s\n" :
02729 et == EXTSSA ? L"Dialogue: Marked=0,%d:%02d:%02d.%02d,%d:%02d:%02d.%02d,%s,%s,%04d,%04d,%04d,%s,%s\n" :
02730 et == EXTASS ? L"Dialogue: %d,%d:%02d:%02d.%02d,%d:%02d:%02d.%02d,%s,%s,%04d,%04d,%04d,%s,%s\n" :
02731 L"";
02732
02733
02734 for(int i = 0, j = GetSize(), k = 0; i < j; i++)
02735 {
02736 STSEntry& stse = GetAt(i);
02737
02738 int t1 = TranslateStart(i, fps);
02739 if(t1 < 0) {k++; continue;}
02740
02741 int t2 = TranslateEnd(i, fps);
02742
02743 int hh1 = (t1/60/60/1000);
02744 int mm1 = (t1/60/1000)%60;
02745 int ss1 = (t1/1000)%60;
02746 int ms1 = (t1)%1000;
02747 int hh2 = (t2/60/60/1000);
02748 int mm2 = (t2/60/1000)%60;
02749 int ss2 = (t2/1000)%60;
02750 int ms2 = (t2)%1000;
02751
02752 CStringW str = f.IsUnicode()
02753 ? GetStrW(i, et == EXTSSA || et == EXTASS)
02754 : GetStrWA(i, et == EXTSSA || et == EXTASS);
02755
02756 CStringW str2;
02757
02758 if(et == EXTSRT)
02759 {
02760 str2.Format(fmt, i-k+1, hh1, mm1, ss1, ms1, hh2, mm2, ss2, ms2, str);
02761 }
02762 else if(et == EXTSUB)
02763 {
02764 str.Replace('\n', '|');
02765 str2.Format(fmt, int(t1*fps/1000), int(t2*fps/1000), str);
02766 }
02767 else if(et == EXTSMI)
02768 {
02769 str.Replace(L"\n", L"<br>");
02770 str2.Format(fmt, t1, str, t2);
02771 }
02772 else if(et == EXTPSB)
02773 {
02774 str.Replace('\n', '|');
02775 str2.Format(fmt, hh1, mm1, ss1, hh2, mm2, ss2, str);
02776 }
02777 else if(et == EXTSSA)
02778 {
02779 str.Replace(L"\n", L"\\N");
02780 str2.Format(fmt,
02781 hh1, mm1, ss1, ms1/10,
02782 hh2, mm2, ss2, ms2/10,
02783 TToW(stse.style), TToW(stse.actor),
02784 stse.marginRect.left, stse.marginRect.right, (stse.marginRect.top + stse.marginRect.bottom) / 2,
02785 TToW(stse.effect), str);
02786 }
02787 else if(et == EXTASS)
02788 {
02789 str.Replace(L"\n", L"\\N");
02790 str2.Format(fmt,
02791 stse.layer,
02792 hh1, mm1, ss1, ms1/10,
02793 hh2, mm2, ss2, ms2/10,
02794 TToW(stse.style), TToW(stse.actor),
02795 stse.marginRect.left, stse.marginRect.right, (stse.marginRect.top + stse.marginRect.bottom) / 2,
02796 TToW(stse.effect), str);
02797 }
02798
02799 f.WriteString(str2);
02800 }
02801
02802
02803
02804 if(et == EXTSMI)
02805 {
02806 f.WriteString(_T("</BODY>\n</SAMI>\n"));
02807 }
02808
02809 void* val;
02810 if(!m_fUsingAutoGeneratedDefaultStyle && m_styles.Lookup(_T("Default"), val) && et != EXTSSA && et != EXTASS)
02811 {
02812 STSStyle* s = (STSStyle*)val;
02813
02814 CTextFile f;
02815 if(!f.Save(fn + _T(".style"), e))
02816 return(false);
02817
02818 CString str, str2;
02819
02820 str += _T("ScriptType: v4.00+\n");
02821 str += _T("PlayResX: %d\n");
02822 str += _T("PlayResY: %d\n");
02823 str += _T("\n");
02824 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");
02825 str2.Format(str, m_dstScreenSize.cx, m_dstScreenSize.cy);
02826 f.WriteString(str2);
02827
02828 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");
02829 str2.Format(str,
02830 s->fontName, (int)s->fontSize,
02831 (s->colors[0]&0xffffff) | (s->alpha[0]<<24),
02832 (s->colors[1]&0xffffff) | (s->alpha[1]<<24),
02833 (s->colors[2]&0xffffff) | (s->alpha[2]<<24),
02834 (s->colors[3]&0xffffff) | (s->alpha[3]<<24),
02835 s->fontWeight > FW_NORMAL ? -1 : 0,
02836 s->fItalic ? -1 : 0, s->fUnderline ? -1 : 0, s->fStrikeOut ? -1 : 0,
02837 (int)s->fontScaleX, (int)s->fontScaleY,
02838 (int)s->fontSpacing, (float)s->fontAngleZ,
02839 s->borderStyle == 0 ? 1 : s->borderStyle == 1 ? 3 : 0,
02840 (int)s->outlineWidth, (int)s->shadowDepth,
02841 s->scrAlignment,
02842 s->marginRect.left, s->marginRect.right, (s->marginRect.top + s->marginRect.bottom) / 2,
02843 s->charSet);
02844 f.WriteString(str2);
02845 }
02846
02847 return(true);
02848 }
02849
02851
02852 STSStyle::STSStyle()
02853 {
02854 SetDefault();
02855 }
02856
02857 void STSStyle::SetDefault()
02858 {
02859 marginRect = CRect(20, 20, 20, 20);
02860 scrAlignment = 2;
02861 borderStyle = 0;
02862 outlineWidth = 2;
02863 shadowDepth = 3;
02864 colors[0] = 0x00ffffff;
02865 colors[1] = 0x0000ffff;
02866 colors[2] = 0x00000000;
02867 colors[3] = 0x00000000;
02868 alpha[0] = 0x00;
02869 alpha[1] = 0x00;
02870 alpha[2] = 0x00;
02871 alpha[3] = 0x80;
02872 charSet = DEFAULT_CHARSET;
02873 fontName = _T("Arial");
02874 fontSize = 18;
02875 fontScaleX = fontScaleY = 100;
02876 fontSpacing = 0;
02877 fontWeight = FW_BOLD;
02878 fItalic = false;
02879 fUnderline = false;
02880 fStrikeOut = false;
02881 fBlur = false;
02882 fontAngleZ = fontAngleX = fontAngleY = 0;
02883 relativeTo = 2;
02884 }
02885
02886 bool STSStyle::operator == (STSStyle& s)
02887 {
02888 return(marginRect == s.marginRect
02889 && scrAlignment == s.scrAlignment
02890 && borderStyle == s.borderStyle
02891 && outlineWidth == s.outlineWidth
02892 && shadowDepth == s.shadowDepth
02893 && *((int*)&colors[0]) == *((int*)&s.colors[0])
02894 && *((int*)&colors[1]) == *((int*)&s.colors[1])
02895 && *((int*)&colors[2]) == *((int*)&s.colors[2])
02896 && *((int*)&colors[3]) == *((int*)&s.colors[3])
02897 && alpha[0] == s.alpha[0]
02898 && alpha[1] == s.alpha[1]
02899 && alpha[2] == s.alpha[2]
02900 && alpha[3] == s.alpha[3]
02901 && fBlur == s.fBlur
02902 && relativeTo == s.relativeTo
02903 && IsFontStyleEqual(s));
02904 }
02905
02906 bool STSStyle::IsFontStyleEqual(STSStyle& s)
02907 {
02908 return(
02909 charSet == s.charSet
02910 && fontName == s.fontName
02911 && fontSize == s.fontSize
02912 && fontScaleX == s.fontScaleX
02913 && fontScaleY == s.fontScaleY
02914 && fontSpacing == s.fontSpacing
02915 && fontWeight == s.fontWeight
02916 && fItalic == s.fItalic
02917 && fUnderline == s.fUnderline
02918 && fStrikeOut == s.fStrikeOut
02919 && fontAngleZ == s.fontAngleZ
02920 && fontAngleX == s.fontAngleX
02921 && fontAngleY == s.fontAngleY);
02922 }
02923
02924 void STSStyle::operator = (LOGFONT& lf)
02925 {
02926 charSet = lf.lfCharSet;
02927 fontName = lf.lfFaceName;
02928 HDC hDC = GetDC(0);
02929 fontSize = -MulDiv(lf.lfHeight, 72, GetDeviceCaps(hDC, LOGPIXELSY));
02930 ReleaseDC(0, hDC);
02931
02932 fontWeight = lf.lfWeight;
02933 fItalic = !!lf.lfItalic;
02934 fUnderline = !!lf.lfUnderline;
02935 fStrikeOut = !!lf.lfStrikeOut;
02936 }
02937
02938 LOGFONTA& operator <<= (LOGFONTA& lfa, STSStyle& s)
02939 {
02940 lfa.lfCharSet = s.charSet;
02941 #ifdef UNICODE
02942 wcstombs(lfa.lfFaceName, s.fontName, 32);
02943 #else
02944 strncpy(lfa.lfFaceName, s.fontName, 32);
02945 #endif
02946 HDC hDC = GetDC(0);
02947 lfa.lfHeight = -MulDiv((int)(s.fontSize+0.5), GetDeviceCaps(hDC, LOGPIXELSY), 72);
02948 ReleaseDC(0, hDC);
02949 lfa.lfWeight = s.fontWeight;
02950 lfa.lfItalic = s.fItalic?-1:0;
02951 lfa.lfUnderline = s.fUnderline?-1:0;
02952 lfa.lfStrikeOut = s.fStrikeOut?-1:0;
02953
02954 return(lfa);
02955 }
02956
02957 LOGFONTW& operator <<= (LOGFONTW& lfw, STSStyle& s)
02958 {
02959 lfw.lfCharSet = s.charSet;
02960 #ifdef UNICODE
02961 wcsncpy(lfw.lfFaceName, s.fontName, 32);
02962 #else
02963 mbstowcs(lfw.lfFaceName, s.fontName, 32);
02964 #endif
02965 HDC hDC = GetDC(0);
02966 lfw.lfHeight = -MulDiv((int)(s.fontSize+0.5), GetDeviceCaps(hDC, LOGPIXELSY), 72);
02967 ReleaseDC(0, hDC);
02968 lfw.lfWeight = s.fontWeight;
02969 lfw.lfItalic = s.fItalic?-1:0;
02970 lfw.lfUnderline = s.fUnderline?-1:0;
02971 lfw.lfStrikeOut = s.fStrikeOut?-1:0;
02972
02973 return(lfw);
02974 }
02975
02976 CString& operator <<= (CString& style, STSStyle& s)
02977 {
02978 style.Format(_T("%d,%d,%d,%d,%d,%d,%f,%f,0x%06x,0x%06x,0x%06x,0x%06x,0x%02x,0x%02x,0x%02x,0x%02x,%d,%s,%f,%f,%f,%f,%d,%d,%d,%d,%d,%f,%f,%f,%d"),
02979 s.marginRect.left,s.marginRect.right,s.marginRect.top,s.marginRect.bottom,
02980 s.scrAlignment, s.borderStyle, s.outlineWidth, s.shadowDepth,
02981 s.colors[0], s.colors[1], s.colors[2], s.colors[3], s.alpha[0], s.alpha[1], s.alpha[2], s.alpha[3],
02982 s.charSet,
02983 s.fontName, s.fontSize, s.fontScaleX, s.fontScaleY, s.fontSpacing, s.fontWeight,
02984 (int)s.fItalic, (int)s.fUnderline, (int)s.fStrikeOut, (int)s.fBlur,
02985 s.fontAngleZ, s.fontAngleX, s.fontAngleY,
02986 s.relativeTo);
02987
02988 return(style);
02989 }
02990
02991 STSStyle& operator <<= (STSStyle& s, CString& style)
02992 {
02993 s.SetDefault();
02994
02995 try
02996 {
02997 CStringW str = TToW(style);
02998 s.marginRect.left = GetInt(str); s.marginRect.right = GetInt(str); s.marginRect.top = GetInt(str); s.marginRect.bottom = GetInt(str);
02999 s.scrAlignment = GetInt(str); s.borderStyle = GetInt(str); s.outlineWidth = GetFloat(str); s.shadowDepth = GetFloat(str);
03000 for(int i = 0; i < 4; i++) s.colors[i] = (COLORREF)GetInt(str);
03001 for(int i = 0; i < 4; i++) s.alpha[i] = GetInt(str);
03002 s.charSet = GetInt(str);
03003 s.fontName = WToT(GetStr(str)); s.fontSize = GetFloat(str);
03004 s.fontScaleX = GetFloat(str); s.fontScaleY = GetFloat(str);
03005 s.fontSpacing = GetFloat(str); s.fontWeight = GetInt(str);
03006 s.fItalic = !!GetInt(str); s.fUnderline = !!GetInt(str); s.fStrikeOut = !!GetInt(str); s.fBlur = !!GetInt(str);
03007 s.fontAngleZ = GetFloat(str); s.fontAngleX = GetFloat(str); s.fontAngleY = GetFloat(str);
03008 s.relativeTo = GetInt(str);
03009 }
03010 catch(...)
03011 {
03012 s.SetDefault();
03013 }
03014
03015 return(s);
03016 }
03017