STS.cpp

00001 /* 
00002  *      Copyright (C) 2003-2005 Gabest
00003  *      http://www.gabest.org
00004  *
00005  *  This Program is free software; you can redistribute it and/or modify
00006  *  it under the terms of the GNU General Public License as published by
00007  *  the Free Software Foundation; either version 2, or (at your option)
00008  *  any later version.
00009  *   
00010  *  This Program is distributed in the hope that it will be useful,
00011  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00012  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
00013  *  GNU General Public License for more details.
00014  *   
00015  *  You should have received a copy of the GNU General Public License
00016  *  along with GNU Make; see the file COPYING.  If not, write to
00017  *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. 
00018  *  http://www.gnu.org/copyleft/gpl.html
00019  *
00020  */
00021 
00022 #include "stdafx.h"
00023 #include "STS.h"
00024 #include <atlbase.h>
00025 
00026 // gathered from http://www.netwave.or.jp/~shikai/shikai/shcolor.htm
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 int FindChar(CStringA str, char c, int pos, bool fUnicode, int CharSet)
00283 {
00284         ASSERT(!fUnicode);
00285 
00286         return(FindChar(AToW(str), c, pos, false, CharSet));
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) // numbering
00495                 {
00496                         num = hh1;
00497                 }
00498                 else if(c == 14) // time info
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) // might be another format
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) // might be another format
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) // might be another format
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) // might be another format
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"&nbsp;", L" ");
00932         ReplaceNoCase(str, L"&quot;", 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         // [email protected]
00943         // now parse line
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 // Modified by Cookie Monster 
00956                 if (lstr.Find(L"<font ", k) == k)
00957                 {
00958                         CStringW args = lstr.Mid(k+6, l-6);     // delete "<font "
00959                         CStringW arg ;
00960 
00961                         args.Remove('\"'); args.Remove('#');    // may include 2 * " + #
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);       // delete "color="
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;  // default is white
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                                 else if (arg.Find(_T("size=" )) == 0 )
00994                                 {
00995                                         uint fsize;
00996 
00997                                         arg = arg.Mid(5);       // delete "size="
00998                                         if ( arg.GetLength() == 0)
00999                                                 continue;
01000 
01001                                         if ( fsize = _tcstol(arg, &tmp, 10) == 0 )
01002                                                 continue;
01003                                         
01004                                         lstr.Insert(k + l + chars_inserted, CString(_T("{\\fs")) + arg + _T("&}"));
01005                                         str.Insert(k + l + chars_inserted, CString(_T("{\\fs")) + arg + _T("&}"));
01006                                         chars_inserted += 4 + arg.GetLength() + 2;
01007                                 }
01008 */
01009                         }
01010                 }
01011 
01012 // Original Code
01013 /*
01014                 if (lstr.Find(L"<font color=", k) == k)
01015                 {
01016                         CStringW arg = lstr.Mid(k+12, l-12); // may include 2 * " + #
01017 
01018                         arg.Remove('\"');
01019                         arg.Remove('#');
01020                         arg.TrimLeft(); arg.TrimRight(L" >");
01021 
01022                         if(arg.GetLength() > 0)
01023                         {
01024                                 DWORD color;
01025                                 
01026                                 CString key = WToT(arg);
01027                                 void* val;
01028                                 if(g_colors.Lookup(key, val)) color = (DWORD)val;
01029                                 else color = wcstol(arg, NULL, 16);
01030 
01031                                 arg.Format(L"%02x%02x%02x", color&0xff, (color>>8)&0xff, (color>>16)&0xff);
01032                         }
01033                         
01034                         lstr.Insert(k + l + chars_inserted, L"{\\c&H" + arg + L"&}");
01035                         str.Insert(k + l + chars_inserted, L"{\\c&H" + arg + L"&}");
01036                         chars_inserted += 5 + arg.GetLength() + 2;
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) // might be another format
01157                 {
01158                         return(false);
01159                 }
01160         }
01161 
01162         return(ret.GetCount() > 0);
01163 }
01164 
01165 CStringW GetStr(CStringW& buff, char sep = ',') //throw(...)
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 = ',') //throw(...) 
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 = ',') //throw(...) 
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 //              try {
01319                         entry = GetStr(buff, ':');
01320 //      }
01321 //              catch(...) {continue;}
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]; // style->colors[2] is used for drawing the outline
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) // top
01429                                                                                 : (style->scrAlignment&8) ? ((style->scrAlignment&3)+3) // mid
01430                                                                                 : (style->scrAlignment&3); // bottom
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);} /* Marked = */
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 //      CMapStringToPtr stylemap;
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 //              try {
01514                         entry = GetStr(buff, '=');
01515 //      }
01516 //              catch(...) {continue;}
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) // might be another format
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 CSimpleTextSubtitle::CSimpleTextSubtitle(CSimpleTextSubtitle& sts)
01748 {
01749         *this = sts;
01750 }
01751 
01752 CSimpleTextSubtitle& CSimpleTextSubtitle::operator = (CSimpleTextSubtitle& sts)
01753 {
01754         Empty();
01755 
01756         m_name = sts.m_name;
01757         m_mode = sts.m_mode;
01758         m_dstScreenSize = sts.m_dstScreenSize;
01759         m_defaultWrapStyle = sts.m_defaultWrapStyle;
01760         m_collisions = sts.m_collisions;
01761         m_fScaledBAS = sts.m_fScaledBAS;
01762         m_fSSA = sts.m_fSSA;
01763         m_fUsingAutoGeneratedDefaultStyle = sts.m_fUsingAutoGeneratedDefaultStyle;
01764         CopyStyles(sts.m_styles);
01765         m_segments.Copy(sts.m_segments);
01766         Copy(sts);
01767 
01768         return(*this);
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 //                              s.subs.Add(n);
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 //                              stss.subs.Add(n);
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         str.Remove('\r');
01969         str.Replace(L"\n", L"\\N");
01970         if(style.IsEmpty()) style = _T("Default");
01971 
01972         int j = m_segments.GetSize();
01973         for(int i = j-1; i >= 0; i--)
01974         {
01975                 if(m_segments[i].end <= start)
01976                 {
01977                         break;
01978                 }
01979                 else if(m_segments[i].start >= start)
01980                 {
01981                         m_segments.SetSize(m_segments.GetSize()-1);
01982                         j--;
01983                 }
01984                 else if(m_segments[i].end > start)
01985                 {
01986                         if(i < j-1) m_segments.RemoveAt(i+1, j-i-1);
01987                         m_segments[i].end = start;
01988                         break;
01989                 }
01990         }
01991 
01992         if(m_segments.GetSize() == 0 && j > 0) 
01993                 CSTSArray::RemoveAll();
01994 
01995         STSSegment stss(start, end);
01996         int len = GetSize();
01997         stss.subs.Add(len);
01998         m_segments.Add(stss);
01999 
02000         STSEntry sub;
02001         sub.str = str;
02002         sub.fUnicode = fUnicode;
02003         sub.style = style;
02004         sub.actor = actor;
02005         sub.effect = effect;
02006         sub.marginRect = marginRect;
02007         sub.layer = layer;
02008         sub.start = start;
02009         sub.end = end;
02010         sub.readorder = GetSize();
02011         CSTSArray::Add(sub);
02012 */
02013 }
02014 
02015 void CSimpleTextSubtitle::CreateDefaultStyle(int CharSet)
02016 {
02017         CString def(_T("Default"));
02018         void* value;
02019 
02020 //      if(m_styles.IsEmpty())
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                 for(int i = 0; i < GetSize(); i++)
02031                 {
02032                         (*this)[i].style = def;
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, /*[out]*/ 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         for(i = 0, j = m_segments.GetSize(); i < j; i++)
02480         {
02481                 STSSegment& stss = m_segments[i];
02482 
02483                 TRACE(_T("%d - %d"), stss.start, stss.end);
02484 
02485                 for(int k = 0, l = stss.subs.GetSize(); k < l; k++)
02486                 {
02487                         TRACE(_T(", %d"), stss.subs[k]);
02488                 }
02489 
02490                 TRACE(_T("\n"));
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) /*|| !GetSize()*/) 
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 //              Sort();
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>&nbsp;\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 //      Sort(true);
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 //      Sort();
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 //      fontAngleZ = (float)(1.0*lf.lfEscapement/10);
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 

Generated on Tue Dec 13 14:47:55 2005 for guliverkli by  doxygen 1.4.5