STS.cpp
上传用户:xjjlds
上传日期:2015-12-05
资源大小:22823k
文件大小:71k
源码类别:

多媒体编程

开发平台:

Visual C++

  1. /* 
  2.  * Copyright (C) 2003-2005 Gabest
  3.  * http://www.gabest.org
  4.  *
  5.  *  This Program is free software; you can redistribute it and/or modify
  6.  *  it under the terms of the GNU General Public License as published by
  7.  *  the Free Software Foundation; either version 2, or (at your option)
  8.  *  any later version.
  9.  *   
  10.  *  This Program is distributed in the hope that it will be useful,
  11.  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  12.  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13.  *  GNU General Public License for more details.
  14.  *   
  15.  *  You should have received a copy of the GNU General Public License
  16.  *  along with GNU Make; see the file COPYING.  If not, write to
  17.  *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. 
  18.  *  http://www.gnu.org/copyleft/gpl.html
  19.  *
  20.  */
  21. #include "stdafx.h"
  22. #include "STS.h"
  23. #include <atlbase.h>
  24. // gathered from http://www.netwave.or.jp/~shikai/shikai/shcolor.htm
  25. struct htmlcolor {TCHAR* name; DWORD color;} hmtlcolors[] = 
  26. {
  27. {_T("white"), 0xffffff}, 
  28. {_T("whitesmoke"), 0xf5f5f5}, 
  29. {_T("ghostwhite"), 0xf8f8ff}, 
  30. {_T("snow"), 0xfffafa}, 
  31. {_T("gainsboro"), 0xdcdcdc}, 
  32. {_T("lightgrey"), 0xd3d3d3}, 
  33. {_T("silver"), 0xc0c0c0}, 
  34. {_T("darkgray"), 0xa9a9a9}, 
  35. {_T("gray"), 0x808080}, 
  36. {_T("dimgray"), 0x696969}, 
  37. {_T("lightslategray"), 0x778899}, 
  38. {_T("slategray"), 0x708090}, 
  39. {_T("darkslategray"), 0x2f4f4f}, 
  40. {_T("black"), 0x000000}, 
  41. {_T("azure"), 0xf0ffff}, 
  42. {_T("aliceblue"), 0xf0f8ff}, 
  43. {_T("mintcream"), 0xf5fffa}, 
  44. {_T("honeydew"), 0xf0fff0}, 
  45. {_T("lightcyan"), 0xe0ffff}, 
  46. {_T("paleturqoise"), 0xafeeee}, 
  47. {_T("powderblue"), 0xb0e0e6}, 
  48. {_T("lightblue"), 0xadd8ed}, 
  49. {_T("lightsteelblue"), 0xb0c4de}, 
  50. {_T("skyblue"), 0x87ceeb}, 
  51. {_T("lightskyblue"), 0x87cefa}, 
  52. {_T("cyan"), 0x00ffff}, 
  53. {_T("aqua"), 0x00ff80}, 
  54. {_T("deepskyblue"), 0x00bfff}, 
  55. {_T("aquamarine"), 0x7fffd4}, 
  56. {_T("turquoise"), 0x40e0d0}, 
  57. {_T("darkturquoise"), 0x00ced1}, 
  58. {_T("lightseagreen"), 0x20b2aa}, 
  59. {_T("mediumturquoise"), 0x40e0dd}, 
  60. {_T("mediumaquamarine"), 0x66cdaa}, 
  61. {_T("cadetblue"), 0x5f9ea0}, 
  62. {_T("teal"), 0x008080}, 
  63. {_T("darkcyan"), 0x008b8b}, 
  64. {_T("comflowerblue"), 0x6495ed}, 
  65. {_T("dodgerblue"), 0x1e90ff}, 
  66. {_T("steelblue"), 0x4682b4}, 
  67. {_T("royalblue"), 0x4169e1}, 
  68. {_T("blue"), 0x0000ff}, 
  69. {_T("mediumblue"), 0x0000cd}, 
  70. {_T("mediumslateblue"), 0x7b68ee}, 
  71. {_T("slateblue"), 0x6a5acd}, 
  72. {_T("darkslateblue"), 0x483d8b}, 
  73. {_T("darkblue"), 0x00008b}, 
  74. {_T("midnightblue"), 0x191970}, 
  75. {_T("navy"), 0x000080}, 
  76. {_T("palegreen"), 0x98fb98}, 
  77. {_T("lightgreen"), 0x90ee90}, 
  78. {_T("mediumspringgreen"), 0x00fa9a}, 
  79. {_T("springgreen"), 0x00ff7f}, 
  80. {_T("chartreuse"), 0x7fff00}, 
  81. {_T("lawngreen"), 0x7cfc00}, 
  82. {_T("lime"), 0x00ff00}, 
  83. {_T("limegreen"), 0x32cd32}, 
  84. {_T("greenyellow"), 0xadff2f}, 
  85. {_T("yellowgreen"), 0x9acd32}, 
  86. {_T("darkseagreen"), 0x8fbc8f}, 
  87. {_T("mediumseagreen"), 0x3cb371}, 
  88. {_T("seagreen"), 0x2e8b57}, 
  89. {_T("olivedrab"), 0x6b8e23}, 
  90. {_T("forestgreen"), 0x228b22}, 
  91. {_T("green"), 0x008000}, 
  92. {_T("darkkhaki"), 0xbdb76b}, 
  93. {_T("olive"), 0x808000}, 
  94. {_T("darkolivegreen"), 0x556b2f}, 
  95. {_T("darkgreen"), 0x006400}, 
  96.  
  97. {_T("floralwhite"), 0xfffaf0}, 
  98. {_T("seashell"), 0xfff5ee}, 
  99. {_T("ivory"), 0xfffff0}, 
  100. {_T("beige"), 0xf5f5dc}, 
  101. {_T("cornsilk"), 0xfff8dc}, 
  102. {_T("lemonchiffon"), 0xfffacd}, 
  103. {_T("lightyellow"), 0xffffe0}, 
  104. {_T("lightgoldenrodyellow"), 0xfafad2}, 
  105. {_T("papayawhip"), 0xffefd5}, 
  106. {_T("blanchedalmond"), 0xffedcd}, 
  107. {_T("palegoldenrod"), 0xeee8aa}, 
  108. {_T("khaki"), 0xf0eb8c}, 
  109. {_T("bisque"), 0xffe4c4}, 
  110. {_T("moccasin"), 0xffe4b5}, 
  111. {_T("navajowhite"), 0xffdead}, 
  112. {_T("peachpuff"), 0xffdab9}, 
  113. {_T("yellow"), 0xffff00}, 
  114. {_T("gold"), 0xffd700}, 
  115. {_T("wheat"), 0xf5deb3}, 
  116. {_T("orange"), 0xffa500}, 
  117. {_T("darkorange"), 0xff8c00}, 
  118.  
  119. {_T("oldlace"), 0xfdf5e6}, 
  120. {_T("linen"), 0xfaf0e6}, 
  121. {_T("antiquewhite"), 0xfaebd7}, 
  122. {_T("lightsalmon"), 0xffa07a}, 
  123. {_T("darksalmon"), 0xe9967a}, 
  124. {_T("salmon"), 0xfa8072}, 
  125. {_T("lightcoral"), 0xf08080}, 
  126. {_T("indianred"), 0xcd5c5c}, 
  127. {_T("coral"), 0xff7f50}, 
  128. {_T("tomato"), 0xff6347}, 
  129. {_T("orangered"), 0xff4500}, 
  130. {_T("red"), 0xff0000}, 
  131. {_T("crimson"), 0xdc143c}, 
  132. {_T("firebrick"), 0xb22222}, 
  133. {_T("maroon"), 0x800000}, 
  134. {_T("darkred"), 0x8b0000},
  135. {_T("lavender"), 0xe6e6fe}, 
  136. {_T("lavenderblush"), 0xfff0f5}, 
  137. {_T("mistyrose"), 0xffe4e1}, 
  138. {_T("thistle"), 0xd8bfd8}, 
  139. {_T("pink"), 0xffc0cb}, 
  140. {_T("lightpink"), 0xffb6c1}, 
  141. {_T("palevioletred"), 0xdb7093}, 
  142. {_T("hotpink"), 0xff69b4}, 
  143. {_T("fuchsia"), 0xff00ee}, 
  144. {_T("magenta"), 0xff00ff}, 
  145. {_T("mediumvioletred"), 0xc71585}, 
  146. {_T("deeppink"), 0xff1493}, 
  147. {_T("plum"), 0xdda0dd}, 
  148. {_T("violet"), 0xee82ee}, 
  149. {_T("orchid"), 0xda70d6}, 
  150. {_T("mediumorchid"), 0xba55d3}, 
  151. {_T("mediumpurple"), 0x9370db}, 
  152. {_T("purple"), 0x9370db}, 
  153. {_T("blueviolet"), 0x8a2be2}, 
  154. {_T("darkviolet"), 0x9400d3}, 
  155. {_T("darkorchid"), 0x9932cc}, 
  156.  
  157. {_T("tan"), 0xd2b48c}, 
  158. {_T("burlywood"), 0xdeb887}, 
  159. {_T("sandybrown"), 0xf4a460}, 
  160. {_T("peru"), 0xcd853f}, 
  161. {_T("goldenrod"), 0xdaa520}, 
  162. {_T("darkgoldenrod"), 0xb8860b}, 
  163. {_T("chocolate"), 0xd2691e}, 
  164. {_T("rosybrown"), 0xbc8f8f}, 
  165. {_T("sienna"), 0xa0522d}, 
  166. {_T("saddlebrown"), 0x8b4513}, 
  167. {_T("brown"), 0xa52a2a}, 
  168. };
  169. CHtmlColorMap::CHtmlColorMap()
  170. {
  171. for(int i = 0; i < countof(hmtlcolors); i++)
  172. SetAt(hmtlcolors[i].name, (void*)hmtlcolors[i].color);
  173. }
  174. CHtmlColorMap g_colors;
  175. //
  176. BYTE CharSetList[] =
  177. {
  178. ANSI_CHARSET,
  179. DEFAULT_CHARSET,
  180. SYMBOL_CHARSET,
  181. SHIFTJIS_CHARSET,
  182. HANGEUL_CHARSET,
  183. HANGUL_CHARSET,
  184. GB2312_CHARSET,
  185. CHINESEBIG5_CHARSET,
  186. OEM_CHARSET,
  187. JOHAB_CHARSET,
  188. HEBREW_CHARSET,
  189. ARABIC_CHARSET,
  190. GREEK_CHARSET,
  191. TURKISH_CHARSET,
  192. VIETNAMESE_CHARSET,
  193. THAI_CHARSET,
  194. EASTEUROPE_CHARSET,
  195. RUSSIAN_CHARSET,
  196. MAC_CHARSET,
  197. BALTIC_CHARSET
  198. };
  199. TCHAR* CharSetNames[] = 
  200. {
  201. _T("ANSI"),
  202. _T("DEFAULT"),
  203. _T("SYMBOL"),
  204. _T("SHIFTJIS"),
  205. _T("HANGEUL"),
  206. _T("HANGUL"),
  207. _T("GB2312"),
  208. _T("CHINESEBIG5"),
  209. _T("OEM"),
  210. _T("JOHAB"),
  211. _T("HEBREW"),
  212. _T("ARABIC"),
  213. _T("GREEK"),
  214. _T("TURKISH"),
  215. _T("VIETNAMESE"),
  216. _T("THAI"),
  217. _T("EASTEUROPE"),
  218. _T("RUSSIAN"),
  219. _T("MAC"),
  220. _T("BALTIC"),
  221. };
  222. int CharSetLen = countof(CharSetList);
  223. //
  224. static DWORD CharSetToCodePage(DWORD dwCharSet)
  225. {
  226. CHARSETINFO cs={0};
  227. ::TranslateCharsetInfo((DWORD *)dwCharSet, &cs, TCI_SRCCHARSET);
  228. return cs.ciACP;
  229. }
  230. int FindChar(CStringW str, WCHAR c, int pos, bool fUnicode, int CharSet)
  231. {
  232. if(fUnicode) return(str.Find(c, pos));
  233. int fStyleMod = 0;
  234. DWORD cp = CharSetToCodePage(CharSet);
  235. int OrgCharSet = CharSet;
  236. for(int i = 0, j = str.GetLength(), k; i < j; i++)
  237. {
  238. WCHAR c2 = str[i];
  239. if(IsDBCSLeadByteEx(cp, (BYTE)c2)) i++;
  240. else if(i >= pos)
  241. {
  242. if(c2 == c) return(i);
  243. }
  244. if(c2 == '{') fStyleMod++;
  245. else if(fStyleMod > 0)
  246. {
  247. if(c2 == '}') fStyleMod--;
  248. else if(c2 == 'e' && i >= 3 && i < j-1 && str.Mid(i-2, 3) == L"\fe")
  249. {
  250. CharSet = 0;
  251. for(k = i+1; _istdigit(str[k]); k++) CharSet = CharSet*10 + (str[k] - '0');
  252. if(k == i+1) CharSet = OrgCharSet;
  253. cp = CharSetToCodePage(CharSet);
  254. }
  255. }
  256. }
  257. return(-1);
  258. }
  259. /*
  260. int FindChar(CStringA str, char c, int pos, bool fUnicode, int CharSet)
  261. {
  262. ASSERT(!fUnicode);
  263. return(FindChar(AToW(str), c, pos, false, CharSet));
  264. }
  265. */
  266. static CStringW ToMBCS(CStringW str, DWORD CharSet)
  267. {
  268. CStringW ret;
  269. DWORD cp = CharSetToCodePage(CharSet);
  270. for(int i = 0, j = str.GetLength(); i < j; i++)
  271. {
  272. WCHAR wc = str.GetAt(i);
  273. char c[8];
  274. int len;
  275. if((len = WideCharToMultiByte(cp, 0, &wc, 1, c, 8, NULL, NULL)) > 0)
  276. {
  277. for(int k = 0; k < len; k++)
  278. ret += (WCHAR)(BYTE)c[k];
  279. }
  280. else
  281. {
  282. ret += '?';
  283. }
  284. }
  285. return(ret);
  286. }
  287. static CStringW UnicodeSSAToMBCS(CStringW str, DWORD CharSet)
  288. {
  289. CStringW ret;
  290. int OrgCharSet = CharSet;
  291. for(int j = 0; j < str.GetLength(); )
  292. {
  293. j = str.Find('{', j);
  294. if(j >= 0)
  295. {
  296. ret += ToMBCS(str.Left(j), CharSet);
  297. str = str.Mid(j);
  298. j = str.Find('}');
  299. if(j < 0)
  300. {
  301. ret += ToMBCS(str, CharSet);
  302. break;
  303. }
  304. else
  305. {
  306. int k = str.Find(L"\fe");
  307. if(k >= 0 && k < j)
  308. {
  309. CharSet = 0;
  310. int l = k+3;
  311. for(; _istdigit(str[l]); l++) CharSet = CharSet*10 + (str[l] - '0');
  312. if(l == k+3) CharSet = OrgCharSet;
  313. }
  314. j++;
  315. ret += ToMBCS(str.Left(j), OrgCharSet);
  316. str = str.Mid(j);
  317. j = 0;
  318. }
  319. }
  320. else
  321. {
  322. ret += ToMBCS(str, CharSet);
  323. break;
  324. }
  325. }
  326. return(ret);
  327. }
  328. static CStringW ToUnicode(CStringW str, DWORD CharSet)
  329. {
  330. CStringW ret;
  331. DWORD cp = CharSetToCodePage(CharSet);
  332. for(int i = 0, j = str.GetLength(); i < j; i++)
  333. {
  334. WCHAR wc = str.GetAt(i);
  335. char c = wc&0xff;
  336. if(IsDBCSLeadByteEx(cp, (BYTE)wc))
  337. {
  338. i++;
  339. if(i < j)
  340. {
  341. char cc[2];
  342. cc[0] = c;
  343. cc[1] = (char)str.GetAt(i);
  344. MultiByteToWideChar(cp, 0, cc, 2, &wc, 1);
  345. }
  346. }
  347. else
  348. {
  349. MultiByteToWideChar(cp, 0, &c, 1, &wc, 1);
  350. }
  351. ret += wc;
  352. }
  353. return(ret);
  354. }
  355. static CStringW MBCSSSAToUnicode(CStringW str, int CharSet)
  356. {
  357. CStringW ret;
  358. int OrgCharSet = CharSet;
  359. for(int j = 0; j < str.GetLength(); )
  360. {
  361. j = FindChar(str, '{', 0, false, CharSet);
  362. if(j >= 0)
  363. {
  364. ret += ToUnicode(str.Left(j), CharSet);
  365. str = str.Mid(j);
  366. j = FindChar(str, '}', 0, false, CharSet);
  367. if(j < 0)
  368. {
  369. ret += ToUnicode(str, CharSet);
  370. break;
  371. }
  372. else
  373. {
  374. int k = str.Find(L"\fe");
  375. if(k >= 0 && k < j)
  376. {
  377. CharSet = 0;
  378. int l = k+3;
  379. for(; _istdigit(str[l]); l++) CharSet = CharSet*10 + (str[l] - '0');
  380. if(l == k+3) CharSet = OrgCharSet;
  381. }
  382. j++;
  383. ret += ToUnicode(str.Left(j), OrgCharSet);
  384. str = str.Mid(j);
  385. j = 0;
  386. }
  387. }
  388. else
  389. {
  390. ret += ToUnicode(str, CharSet);
  391. break;
  392. }
  393. }
  394. return(ret);
  395. }
  396. CStringW RemoveSSATags(CStringW str, bool fUnicode, int CharSet)
  397. {
  398. for(int i = 0, j; i < str.GetLength(); )
  399. {
  400. if((i = FindChar(str, '{', i, fUnicode, CharSet)) < 0) break;
  401. if((j = FindChar(str, '}', i, fUnicode, CharSet)) < 0) break;
  402. str.Delete(i, j-i+1);
  403. }
  404. str.Replace(L"\N", L"n");
  405. str.Replace(L"\n", L"n");
  406. str.Replace(L"\h", L" ");
  407. return(str);
  408. }
  409. //
  410. static CStringW SubRipper2SSA(CStringW str, int CharSet)
  411. {
  412. str.Replace(L"<i>", L"{\i1}");
  413. str.Replace(L"</i>", L"{\i}");
  414. str.Replace(L"<b>", L"{\b1}");
  415. str.Replace(L"</b>", L"{\b}");
  416. str.Replace(L"<u>", L"{\u1}");
  417. str.Replace(L"</u>", L"{\u}");
  418. return(str);
  419. }
  420. static bool OpenSubRipper(CTextFile* file, CSimpleTextSubtitle& ret, int CharSet)
  421. {
  422. int num = 0;
  423. CStringW buff;
  424. while(file->ReadString(buff))
  425. {
  426. buff.Trim();
  427. if(buff.IsEmpty()) continue;
  428. WCHAR sep;
  429. int hh1, mm1, ss1, ms1, hh2, mm2, ss2, ms2;
  430. int c = swscanf(buff, L"%d%c%d%c%d%c%d --> %d%c%d%c%d%c%dn", 
  431. &hh1, &sep, &mm1, &sep, &ss1, &sep, &ms1,
  432. &hh2, &sep, &mm2, &sep, &ss2, &sep, &ms2);
  433. if(c == 1) // numbering
  434. {
  435. num = hh1;
  436. }
  437. else if(c == 14) // time info
  438. {
  439. CStringW str, tmp;
  440. bool fFoundEmpty = false;
  441. while(file->ReadString(tmp))
  442. {
  443. tmp.Trim();
  444. if(tmp.IsEmpty()) fFoundEmpty = true;
  445. int num2;
  446. WCHAR c;
  447. if(swscanf(tmp, L"%d%c", &num2, &c) == 1 && fFoundEmpty)
  448. {
  449. num = num2;
  450. break;
  451. }
  452. str += tmp + 'n';
  453. }
  454. ret.Add(
  455. SubRipper2SSA(str, CharSet), 
  456. file->IsUnicode(),
  457. (((hh1*60 + mm1)*60) + ss1)*1000 + ms1, 
  458. (((hh2*60 + mm2)*60) + ss2)*1000 + ms2);
  459. }
  460. else if(c != EOF) // might be another format
  461. {
  462. return(false);
  463. }
  464. }
  465. return(ret.GetCount() > 0);
  466. }
  467. static bool OpenOldSubRipper(CTextFile* file, CSimpleTextSubtitle& ret, int CharSet)
  468. {
  469. CStringW buff;
  470. while(file->ReadString(buff))
  471. {
  472. buff.Trim();
  473. if(buff.IsEmpty()) continue;
  474. for(int i = 0; i < buff.GetLength(); i++)
  475. {
  476. if((i = FindChar(buff, '|', i, file->IsUnicode(), CharSet)) < 0) break;
  477. buff.SetAt(i, 'n');
  478. }
  479. int hh1, mm1, ss1, hh2, mm2, ss2;
  480. int c = swscanf(buff, L"{%d:%d:%d}{%d:%d:%d}", &hh1, &mm1, &ss1, &hh2, &mm2, &ss2);
  481. if(c == 6)
  482. {
  483. ret.Add(
  484. buff.Mid(buff.Find('}', buff.Find('}')+1)+1), 
  485. file->IsUnicode(),
  486. (((hh1*60 + mm1)*60) + ss1)*1000, 
  487. (((hh2*60 + mm2)*60) + ss2)*1000);
  488. }
  489. else if(c != EOF) // might be another format
  490. {
  491. return(false);
  492. }
  493. }
  494. return(ret.GetCount() > 0);
  495. }
  496. static bool OpenSubViewer(CTextFile* file, CSimpleTextSubtitle& ret, int CharSet)
  497. {
  498. STSStyle def;
  499. CStringW font, color, size;
  500. bool fBold, fItalic, fStriked, fUnderline;
  501. CStringW buff;
  502. while(file->ReadString(buff))
  503. {
  504. buff.Trim();
  505. if(buff.IsEmpty()) continue;
  506. if(buff[0] == '[')
  507. {
  508. for(int i = 0; i < buff.GetLength() && buff[i]== '['; )
  509. {
  510. int j = buff.Find(']', ++i);
  511. if(j < i) break;
  512. CStringW tag = buff.Mid(i,j-i);
  513. tag.Trim();
  514. tag.MakeLower();
  515. i += j-i;
  516. j = buff.Find('[', ++i);
  517. if(j < 0) j = buff.GetLength();
  518. CStringW param = buff.Mid(i,j-i);
  519. param.Trim(L" \t,");
  520. i = j;
  521. if(tag == L"font")
  522. font = def.fontName.CompareNoCase(WToT(param)) ? param : L"";
  523. else if(tag == L"colf")
  524. color = def.colors[0] != wcstol(((LPCWSTR)param)+2, 0, 16) ? param : L"";
  525. else if(tag == L"size")
  526. size = def.fontSize != wcstol(param, 0, 10) ? param : L"";
  527. else if(tag == L"style")
  528. {
  529. if(param.Find(L"no") >= 0)
  530. {
  531. fBold = fItalic = fStriked = fUnderline = false;
  532. }
  533. else
  534. {
  535. fBold = def.fontWeight < FW_BOLD && param.Find(L"bd") >= 0;
  536. fItalic = def.fItalic && param.Find(L"it") >= 0;
  537. fStriked = def.fStrikeOut && param.Find(L"st") >= 0;
  538. fUnderline = def.fUnderline && param.Find(L"ud") >= 0;
  539. }
  540. }
  541. }
  542. continue;
  543. }
  544. WCHAR sep;
  545. int hh1, mm1, ss1, hs1, hh2, mm2, ss2, hs2;
  546. int c = swscanf(buff, L"%d:%d:%d%c%d,%d:%d:%d%c%dn", 
  547. &hh1, &mm1, &ss1, &sep, &hs1, &hh2, &mm2, &ss2, &sep, &hs2);
  548. if(c == 10)
  549. {
  550. CStringW str;
  551. file->ReadString(str);
  552. str.Replace(L"[br]", L"\N");
  553. CStringW prefix;
  554. if(!font.IsEmpty()) prefix += L"\fn" + font;
  555. if(!color.IsEmpty()) prefix += L"\c" + color;
  556. if(!size.IsEmpty()) prefix += L"\fs" + size;
  557. if(fBold) prefix += L"\b1";
  558. if(fItalic) prefix += L"\i1";
  559. if(fStriked) prefix += L"\s1";
  560. if(fUnderline) prefix += L"\u1";
  561. if(!prefix.IsEmpty()) str = L"{" + prefix + L"}" + str;
  562. ret.Add(str,
  563. file->IsUnicode(),
  564. (((hh1*60 + mm1)*60) + ss1)*1000 + hs1*10,
  565. (((hh2*60 + mm2)*60) + ss2)*1000 + hs2*10);
  566. }
  567. else if(c != EOF) // might be another format
  568. {
  569. return(false);
  570. }
  571. }
  572. return(ret.GetCount() > 0);
  573. }
  574. static STSStyle* GetMicroDVDStyle(CString str, int CharSet)
  575. {
  576. STSStyle* ret = new STSStyle();
  577. if(!ret) return(NULL);
  578. for(int i = 0, len = str.GetLength(); i < len; i++)
  579. {
  580. int j = str.Find('{', i);
  581. if(j < 0) j = len;
  582. if(j >= len) break;
  583. int k = str.Find('}', j);
  584. if(k < 0) k = len;
  585. CString code = str.Mid(j, k-j);
  586. if(code.GetLength() > 2) code.SetAt(1, (TCHAR)towlower(code[1]));
  587. if(!_tcsnicmp(code, _T("{c:$"), 4))
  588. {
  589. _stscanf(code, _T("{c:$%x"), &ret->colors[0]);
  590. }
  591. else if(!_tcsnicmp(code, _T("{f:"), 3))
  592. {
  593. ret->fontName = code.Mid(3);
  594. }
  595. else if(!_tcsnicmp(code, _T("{s:"), 3))
  596. {
  597. float f;
  598. if(1 == _stscanf(code, _T("{s:%f"), &f))
  599. ret->fontSize = f;
  600. }
  601. else if(!_tcsnicmp(code, _T("{h:"), 3))
  602. {
  603. _stscanf(code, _T("{h:%d"), &ret->charSet);
  604. }
  605. else if(!_tcsnicmp(code, _T("{y:"), 3))
  606. {
  607. code.MakeLower();
  608. if(code.Find('b') >= 0) ret->fontWeight = FW_BOLD;
  609. if(code.Find('i') >= 0) ret->fItalic = true;
  610. if(code.Find('u') >= 0) ret->fUnderline = true;
  611. if(code.Find('s') >= 0) ret->fStrikeOut = true;
  612. }
  613. else if(!_tcsnicmp(code, _T("{p:"), 3))
  614. {
  615. int p;
  616. _stscanf(code, _T("{p:%d"), &p);
  617. ret->scrAlignment = (p == 0) ? 8 : 2;
  618. }
  619. i = k;
  620. }
  621. return(ret);
  622. }
  623. static CStringW MicroDVD2SSA(CStringW str, bool fUnicode, int CharSet)
  624. {
  625. CStringW ret;
  626. enum {COLOR=0, FONTNAME, FONTSIZE, FONTCHARSET, BOLD, ITALIC, UNDERLINE, STRIKEOUT};
  627. bool fRestore[8];
  628. int fRestoreLen = 8;
  629. memset(fRestore, 0, sizeof(bool)*fRestoreLen);
  630. for(int pos = 0, eol; pos < str.GetLength(); pos++)
  631. {
  632. if((eol = FindChar(str, '|', pos, fUnicode, CharSet)) < 0) eol = str.GetLength();
  633. CStringW line = str.Mid(pos, eol-pos);
  634. pos = eol;
  635. for(int i = 0, j, k, len = line.GetLength(); i < len; i++)
  636. {
  637. if((j = FindChar(line, '{', i, fUnicode, CharSet)) < 0) j = str.GetLength();
  638. ret += line.Mid(i, j-i);
  639. if(j >= len) break;
  640. if((k = FindChar(line, '}', j, fUnicode, CharSet)) < 0) k = len;
  641. {
  642. CStringW code = line.Mid(j, k-j);
  643. if(!wcsnicmp(code, L"{c:$", 4))
  644. {
  645. fRestore[COLOR] = (iswupper(code[1]) == 0);
  646. code.MakeLower();
  647. int color;
  648. swscanf(code, L"{c:$%x", &color);
  649. code.Format(L"{\c&H%x&}", color);
  650. ret += code;
  651. }
  652. else if(!wcsnicmp(code, L"{f:", 3))
  653. {
  654. fRestore[FONTNAME] = (iswupper(code[1]) == 0);
  655. code.Format(L"{\fn%s}", code.Mid(3));
  656. ret += code;
  657. }
  658. else if(!wcsnicmp(code, L"{s:", 3))
  659. {
  660. fRestore[FONTSIZE] = (iswupper(code[1]) == 0);
  661. code.MakeLower();
  662. float size;
  663. swscanf(code, L"{s:%f", &size);
  664. code.Format(L"{\fs%f}", size);
  665. ret += code;
  666. }
  667. else if(!wcsnicmp(code, L"{h:", 3))
  668. {
  669. fRestore[COLOR] = (_istupper(code[1]) == 0);
  670. code.MakeLower();
  671. int CharSet;
  672. swscanf(code, L"{h:%d", &CharSet);
  673. code.Format(L"{\fe%d}", CharSet);
  674. ret += code;
  675. }
  676. else if(!wcsnicmp(code, L"{y:", 3))
  677. {
  678. bool f = (_istupper(code[1]) == 0);
  679. code.MakeLower();
  680. ret += '{';
  681. if(code.Find('b') >= 0) {ret += L"\b1"; fRestore[BOLD] = f;}
  682. if(code.Find('i') >= 0) {ret += L"\i1"; fRestore[ITALIC] = f;}
  683. if(code.Find('u') >= 0) {ret += L"\u1"; fRestore[UNDERLINE] = f;}
  684. if(code.Find('s') >= 0) {ret += L"\s1"; fRestore[STRIKEOUT] = f;}
  685. ret += '}';
  686. }
  687. else if(!wcsnicmp(code, L"{o:", 3))
  688. {
  689. code.MakeLower();
  690. int x, y;
  691. TCHAR c;
  692. swscanf(code, L"{o:%d%c%d", &x, &c, &y);
  693. code.Format(L"{\move(%d,%d,0,0,0,0)}", x, y);
  694. ret += code;
  695. }
  696. else ret += code;
  697. }
  698. i = k;
  699. }
  700. if(pos >= str.GetLength()) break;
  701. for(int i = 0; i < fRestoreLen; i++)
  702. {
  703. if(fRestore[i]) 
  704. {
  705. switch(i)
  706. {
  707. case COLOR: ret += L"{\c}"; break;
  708. case FONTNAME: ret += L"{\fn}"; break;
  709. case FONTSIZE: ret += L"{\fs}"; break;
  710. case FONTCHARSET: ret += L"{\fe}"; break;
  711. case BOLD: ret += L"{\b}"; break;
  712. case ITALIC: ret += L"{\i}"; break;
  713. case UNDERLINE: ret += L"{\u}"; break;
  714. case STRIKEOUT: ret += L"{\s}"; break;
  715. default: break;
  716. }
  717. }
  718. }
  719. memset(fRestore, 0, sizeof(bool)*fRestoreLen);
  720. ret += L"\N";
  721. }
  722. return(ret);
  723. }
  724. static bool OpenMicroDVD(CTextFile* file, CSimpleTextSubtitle& ret, int CharSet)
  725. {
  726. bool fCheck = false, fCheck2 = false;
  727. CString style(_T("Default"));
  728. CStringW buff;;
  729. while(file->ReadString(buff))
  730. {
  731. buff.Trim();
  732. if(buff.IsEmpty()) continue;
  733. int start, end;
  734. int c = swscanf(buff, L"{%d}{%d}", &start, &end);
  735. if(c != 2) {c = swscanf(buff, L"{%d}{}", &start)+1; end = start + 60; fCheck = true;}
  736. if(c != 2)
  737. {
  738. int i;
  739. if(buff.Find('{') == 0 && (i = buff.Find('}')) > 1 && i < buff.GetLength())
  740. {
  741. if(STSStyle* s = GetMicroDVDStyle(WToT(buff.Mid(i+1)), CharSet))
  742. {
  743. style = buff.Mid(1, i-1);
  744. style.MakeUpper();
  745. if(style.GetLength()) {CString str = style.Mid(1); str.MakeLower(); style = style.Left(1) + str;}
  746. ret.AddStyle(style, s);
  747. CharSet = s->charSet;
  748. continue;
  749. }
  750. }
  751. }
  752. if(c == 2)
  753. {
  754. if(fCheck2 && ret.GetSize())
  755. {
  756. STSEntry& stse = ret[ret.GetSize()-1];
  757. stse.end = min(stse.end, start);
  758. fCheck2 = false;
  759. }
  760. ret.Add(
  761. MicroDVD2SSA(buff.Mid(buff.Find('}', buff.Find('}')+1)+1), file->IsUnicode(), CharSet), 
  762. file->IsUnicode(),
  763. start, end, 
  764. style);
  765. if(fCheck) 
  766. {
  767. fCheck = false;
  768. fCheck2 = true;
  769. }
  770. }
  771. else if(c != EOF) // might be another format
  772. {
  773. return(false);
  774. }
  775. }
  776. return(ret.GetCount() > 0);
  777. }
  778. static void ReplaceNoCase(CStringW& str, CStringW from, CStringW to)
  779. {
  780. CStringW lstr = str;
  781. lstr.MakeLower();
  782. int i, j, k;
  783. for(i = 0, j = str.GetLength(); i < j; )
  784. {
  785. if((k = lstr.Find(from, i)) >= 0) 
  786. {
  787. str.Delete(k, from.GetLength()); lstr.Delete(k, from.GetLength());
  788. str.Insert(k, to); lstr.Insert(k, to);
  789. i = k + to.GetLength();
  790. j = str.GetLength();
  791. }
  792. else break;
  793. }
  794. }
  795. static CStringW SMI2SSA(CStringW str, int CharSet)
  796. {
  797. ReplaceNoCase(str, L"&nbsp;", L" ");
  798. ReplaceNoCase(str, L"&quot;", L""");
  799. ReplaceNoCase(str, L"<br>", L"\N");
  800. ReplaceNoCase(str, L"<i>", L"{\i1}");
  801. ReplaceNoCase(str, L"</i>", L"{\i}");
  802. ReplaceNoCase(str, L"<b>", L"{\b1}");
  803. ReplaceNoCase(str, L"</b>", L"{\b}");
  804. CStringW lstr = str;
  805. lstr.MakeLower();
  806. // maven@maven.de
  807. // now parse line
  808. for(int i = 0, j = str.GetLength(); i < j; )
  809. {
  810. int k;
  811. if((k = lstr.Find('<', i)) < 0) break;
  812. int chars_inserted = 0;
  813. int l = 1;
  814. for(; k+l < j && lstr[k+l] != '>'; l++);
  815. l++;
  816. // Modified by Cookie Monster 
  817. if (lstr.Find(L"<font ", k) == k)
  818. {
  819. CStringW args = lstr.Mid(k+6, l-6); // delete "<font "
  820. CStringW arg ;
  821. args.Remove('"'); args.Remove('#'); // may include 2 * " + #
  822. arg.TrimLeft(); arg.TrimRight(L" >");
  823. for (;;)
  824. {
  825. args.TrimLeft();
  826. arg = args.SpanExcluding(L" t>");
  827. args = args.Mid(arg.GetLength());
  828. if(arg.IsEmpty())
  829. break;
  830. if (arg.Find(L"color=") == 0 )
  831. {
  832. DWORD color;
  833. arg = arg.Mid(6); // delete "color="
  834. if ( arg.IsEmpty())
  835. continue;
  836. CString key = WToT(arg);
  837. void* val;
  838. if(g_colors.Lookup(key, val))
  839. color = (DWORD)val;
  840. else if ( (color = wcstol(arg, NULL, 16) ) == 0 )
  841. color = 0x00ffffff;  // default is white
  842. arg.Format(L"%02x%02x%02x", color&0xff, (color>>8)&0xff, (color>>16)&0xff);
  843. lstr.Insert(k + l + chars_inserted, CStringW(L"{\c&H") + arg + L"&}");
  844. str.Insert(k + l + chars_inserted, CStringW(L"{\c&H") + arg + L"&}");
  845. chars_inserted += 5 + arg.GetLength() + 2;
  846. }
  847. /*
  848. else if (arg.Find(_T("size=" )) == 0 )
  849. {
  850. uint fsize;
  851. arg = arg.Mid(5); // delete "size="
  852. if ( arg.GetLength() == 0)
  853. continue;
  854. if ( fsize = _tcstol(arg, &tmp, 10) == 0 )
  855. continue;
  856. lstr.Insert(k + l + chars_inserted, CString(_T("{\fs")) + arg + _T("&}"));
  857. str.Insert(k + l + chars_inserted, CString(_T("{\fs")) + arg + _T("&}"));
  858. chars_inserted += 4 + arg.GetLength() + 2;
  859. }
  860. */
  861. }
  862. }
  863. // Original Code
  864. /*
  865. if (lstr.Find(L"<font color=", k) == k)
  866. {
  867. CStringW arg = lstr.Mid(k+12, l-12); // may include 2 * " + #
  868. arg.Remove('"');
  869. arg.Remove('#');
  870. arg.TrimLeft(); arg.TrimRight(L" >");
  871. if(arg.GetLength() > 0)
  872. {
  873. DWORD color;
  874. CString key = WToT(arg);
  875. void* val;
  876. if(g_colors.Lookup(key, val)) color = (DWORD)val;
  877. else color = wcstol(arg, NULL, 16);
  878. arg.Format(L"%02x%02x%02x", color&0xff, (color>>8)&0xff, (color>>16)&0xff);
  879. }
  880. lstr.Insert(k + l + chars_inserted, L"{\c&H" + arg + L"&}");
  881. str.Insert(k + l + chars_inserted, L"{\c&H" + arg + L"&}");
  882. chars_inserted += 5 + arg.GetLength() + 2;
  883. }
  884. */
  885. else if (lstr.Find(L"</font>", k) == k)
  886. {
  887. lstr.Insert(k + l + chars_inserted, L"{\c}");
  888. str.Insert(k + l + chars_inserted, L"{\c}");
  889. chars_inserted += 4;
  890. }
  891. str.Delete(k, l); lstr.Delete(k, l);
  892. i = k + chars_inserted;
  893. j = str.GetLength();
  894. }
  895. return(str);
  896. }
  897. static bool OpenSami(CTextFile* file, CSimpleTextSubtitle& ret, int CharSet)
  898. {
  899. CStringW buff, caption;
  900. ULONGLONG pos = file->GetPosition();
  901. bool fSAMI = false;
  902. while(file->ReadString(buff) && !fSAMI)
  903. {
  904. if(buff.MakeUpper().Find(L"<SAMI>") >= 0) fSAMI = true;
  905. }
  906. if(!fSAMI) return(false);
  907. file->Seek(pos, 0);
  908. bool fComment = false;
  909. int start_time = 0;
  910. while(file->ReadString(buff))
  911. {
  912. buff.Trim();
  913. if(buff.IsEmpty()) continue;
  914. CStringW ubuff = buff;
  915. ubuff.MakeUpper();
  916. if(ubuff.Find(L"<!--") >= 0 || ubuff.Find(L"<TITLE>") >= 0)
  917. fComment = true;
  918. if(!fComment)
  919. {
  920. int i;
  921. if((i = ubuff.Find(L"<SYNC START=")) >= 0)
  922. {
  923. int time = 0;
  924. for(i = 12; i < ubuff.GetLength(); i++)
  925. {
  926. if(ubuff[i] != '>' && ubuff[i] != 'M')
  927. {
  928. if(iswdigit(ubuff[i]))
  929. {
  930. time *= 10;
  931. time += ubuff[i] - 0x30;
  932. }
  933. }
  934. else break;
  935. }
  936. ret.Add(
  937. SMI2SSA(caption, CharSet), 
  938. file->IsUnicode(),
  939. start_time, time);
  940. start_time = time;
  941. caption.Empty();
  942. }
  943. caption += buff;
  944. }
  945. if(ubuff.Find(L"-->") >= 0 || ubuff.Find(L"</TITLE>") >= 0)
  946. fComment = false;
  947. }
  948. ret.Add(
  949. SMI2SSA(caption, CharSet), 
  950. file->IsUnicode(),
  951. start_time, MAXLONG);
  952. return(true);
  953. }
  954. static bool OpenVPlayer(CTextFile* file, CSimpleTextSubtitle& ret, int CharSet)
  955. {
  956. CStringW buff;
  957. while(file->ReadString(buff))
  958. {
  959. buff.Trim();
  960. if(buff.IsEmpty()) continue;
  961. for(int i = 0; i < buff.GetLength(); i++)
  962. {
  963. if((i = FindChar(buff, '|', i, file->IsUnicode(), CharSet)) < 0) break;
  964. buff.SetAt(i, 'n');
  965. }
  966. int hh, mm, ss;
  967. int c = swscanf(buff, L"%d:%d:%d:", &hh, &mm, &ss);
  968. if(c == 3)
  969. {
  970. CStringW str = buff.Mid(buff.Find(':', buff.Find(':', buff.Find(':')+1)+1)+1);
  971. ret.Add(str, 
  972. file->IsUnicode(),
  973. (((hh*60 + mm)*60) + ss)*1000, 
  974. (((hh*60 + mm)*60) + ss)*1000 + 1000 + 50*str.GetLength());
  975. }
  976. else if(c != EOF) // might be another format
  977. {
  978. return(false);
  979. }
  980. }
  981. return(ret.GetCount() > 0);
  982. }
  983. CStringW GetStr(CStringW& buff, char sep = ',') //throw(...)
  984. {
  985. buff.TrimLeft();
  986. int pos = buff.Find(sep);
  987. if(pos < 0) 
  988. {
  989. pos = buff.GetLength();
  990. if(pos < 1) throw 1;
  991. }
  992. CStringW ret = buff.Left(pos);
  993. if(pos < buff.GetLength()) buff = buff.Mid(pos+1);
  994. return(ret);
  995. }
  996. int GetInt(CStringW& buff, char sep = ',') //throw(...) 
  997. {
  998. CStringW str;
  999. str = GetStr(buff, sep);
  1000. str.MakeLower();
  1001. CStringW fmtstr = str.GetLength() > 2 && (str.Left(2) == L"&h" || str.Left(2) == L"0x")
  1002. ? str = str.Mid(2), L"%x"
  1003. : L"%d";
  1004. int ret;
  1005. if(swscanf(str, fmtstr, &ret) != 1) throw 1;
  1006. return(ret);
  1007. }
  1008. double GetFloat(CStringW& buff, char sep = ',') //throw(...) 
  1009. {
  1010. CStringW str;
  1011. str = GetStr(buff, sep);
  1012. str.MakeLower();
  1013. float ret;
  1014. if(swscanf(str, L"%f", &ret) != 1) throw 1;
  1015. return((double)ret);
  1016. }
  1017. static bool LoadFont(CString& font)
  1018. {
  1019. int len = font.GetLength();
  1020. CAutoVectorPtr<BYTE> pData;
  1021. if(len == 0 || (len&3) == 1 || !pData.Allocate(len))
  1022. return(false);
  1023. const TCHAR* s = font;
  1024. const TCHAR* e = s + len;
  1025. for(BYTE* p = pData; s < e; s++, p++) *p = *s - 33;
  1026. for(int i = 0, j = 0, k = len&~3; i < k; i+=4, j+=3)
  1027. {
  1028. pData[j+0] = ((pData[i+0]&63)<<2)|((pData[i+1]>>4)& 3);
  1029. pData[j+1] = ((pData[i+1]&15)<<4)|((pData[i+2]>>2)&15);
  1030. pData[j+2] = ((pData[i+2]& 3)<<6)|((pData[i+3]>>0)&63);
  1031. }
  1032. int datalen = (len&~3)*3/4;
  1033. if((len&3) == 2)
  1034. {
  1035. pData[datalen++] = ((pData[(len&~3)+0]&63)<<2)|((pData[(len&~3)+1]>>4)&3);
  1036. }
  1037. else if((len&3) == 3)
  1038. {
  1039. pData[datalen++] = ((pData[(len&~3)+0]&63)<<2)|((pData[(len&~3)+1]>>4)& 3);
  1040. pData[datalen++] = ((pData[(len&~3)+1]&15)<<4)|((pData[(len&~3)+2]>>2)&15);
  1041. }
  1042. HANDLE hFont = INVALID_HANDLE_VALUE;
  1043. if(HMODULE hModule = LoadLibrary(_T("GDI32.DLL")))
  1044. {
  1045. typedef HANDLE (WINAPI *PAddFontMemResourceEx)( IN PVOID, IN DWORD, IN PVOID , IN DWORD*);
  1046. if(PAddFontMemResourceEx f = (PAddFontMemResourceEx)GetProcAddress(hModule, "AddFontMemResourceEx"))
  1047. {
  1048. DWORD cFonts;
  1049. hFont = f(pData, datalen, NULL, &cFonts);
  1050. }
  1051. FreeLibrary(hModule);
  1052. }
  1053. if(hFont == INVALID_HANDLE_VALUE)
  1054. {
  1055. TCHAR path[MAX_PATH];
  1056. GetTempPath(MAX_PATH, path);
  1057. DWORD chksum = 0;
  1058. for(int i = 0, j = datalen>>2; i < j; i++)
  1059. chksum += ((DWORD*)(BYTE*)pData)[i];
  1060. CString fn;
  1061. fn.Format(_T("%sfont%08x.ttf"), path, chksum);
  1062. CFileStatus fs;
  1063. if(!CFileGetStatus(fn, fs))
  1064. {
  1065. CFile f;
  1066. if(f.Open(fn, CFile::modeCreate|CFile::modeWrite|CFile::typeBinary|CFile::shareDenyWrite))
  1067. {
  1068. f.Write(pData, datalen);
  1069. f.Close();
  1070. }
  1071. }
  1072. AddFontResource(fn);
  1073. }
  1074. return(true);
  1075. }
  1076. static bool LoadUUEFont(CTextFile* file)
  1077. {
  1078. CString s, font;
  1079. while(file->ReadString(s))
  1080. {
  1081. s.Trim();
  1082. if(s.IsEmpty() || s[0] == '[') break;
  1083. if(s.Find(_T("fontname:")) == 0) {LoadFont(font); font.Empty(); continue;}
  1084. font += s;
  1085. }
  1086. if(!font.IsEmpty())
  1087. LoadFont(font);
  1088. return(true);
  1089. }
  1090. static bool OpenSubStationAlpha(CTextFile* file, CSimpleTextSubtitle& ret, int CharSet)
  1091. {
  1092. bool fRet = false;
  1093. int version = 3, sver = 3;
  1094. CStringW buff;
  1095. while(file->ReadString(buff))
  1096. {
  1097. buff.Trim();
  1098. if(buff.IsEmpty() || buff.GetAt(0) == ';') continue;
  1099. CStringW entry;
  1100. // try {
  1101. entry = GetStr(buff, ':');
  1102. // }
  1103. // catch(...) {continue;}
  1104. entry.MakeLower();
  1105. if(entry == L"[script info]")
  1106. {
  1107. fRet = true;
  1108. }
  1109. else if(entry == L"playresx")
  1110. {
  1111. try {ret.m_dstScreenSize.cx = GetInt(buff);}
  1112. catch(...) {ret.m_dstScreenSize = CSize(0, 0); return(false);}
  1113. if(ret.m_dstScreenSize.cy <= 0)
  1114. {
  1115. ret.m_dstScreenSize.cy = (ret.m_dstScreenSize.cx == 1280)
  1116. ? 1024 
  1117. : ret.m_dstScreenSize.cx * 3 / 4;
  1118. }
  1119. }
  1120. else if(entry == L"playresy")
  1121. {
  1122. try {ret.m_dstScreenSize.cy = GetInt(buff);}
  1123. catch(...) {ret.m_dstScreenSize = CSize(0, 0); return(false);}
  1124. if(ret.m_dstScreenSize.cx <= 0)
  1125. {
  1126. ret.m_dstScreenSize.cx = (ret.m_dstScreenSize.cy == 1024)
  1127. ? 1280 
  1128. : ret.m_dstScreenSize.cy * 4 / 3;
  1129. }
  1130. }
  1131. else if(entry == L"wrapstyle")
  1132. {
  1133. try {ret.m_defaultWrapStyle = GetInt(buff);}
  1134. catch(...) {ret.m_defaultWrapStyle = 1; return(false);}
  1135. }
  1136. else if(entry == L"scripttype")
  1137. {
  1138. if(buff.GetLength() >= 4 && !buff.Right(4).CompareNoCase(L"4.00")) version = sver = 4;
  1139. else if(buff.GetLength() >= 5 && !buff.Right(5).CompareNoCase(L"4.00+")) version = sver = 5;
  1140. }
  1141. else if(entry == L"collisions")
  1142. {
  1143. buff = GetStr(buff);
  1144. buff.MakeLower();
  1145. ret.m_collisions = buff.Find(L"reverse") >= 0 ? 1 : 0;
  1146. }
  1147. else if(entry == L"scaledborderandshadow")
  1148. {
  1149. buff = GetStr(buff);
  1150. buff.MakeLower();
  1151. ret.m_fScaledBAS = buff.Find(L"yes") >= 0;
  1152. }
  1153. else if(entry == L"[v4 styles]")
  1154. {
  1155. fRet = true;
  1156.             sver = 4;
  1157. }
  1158. else if(entry == L"[v4+ styles]")
  1159. {
  1160. fRet = true;
  1161.             sver = 5;
  1162. }
  1163. else if(entry == L"style")
  1164. {
  1165. STSStyle* style = new STSStyle;
  1166. if(!style) return(false);
  1167. try 
  1168. {
  1169. CString StyleName;
  1170. int alpha;
  1171. StyleName = WToT(GetStr(buff));
  1172. style->fontName = WToT(GetStr(buff));
  1173. style->fontSize = GetFloat(buff);
  1174. for(int i = 0; i < 4; i++) style->colors[i] = (COLORREF)GetInt(buff);
  1175. style->fontWeight = !!GetInt(buff) ? FW_BOLD : FW_NORMAL;
  1176. style->fItalic = !!GetInt(buff);
  1177. if(sver >= 5) style->fUnderline = !!GetInt(buff);
  1178. if(sver >= 5) style->fStrikeOut = !!GetInt(buff);
  1179. if(sver >= 5) style->fontScaleX = GetFloat(buff);
  1180. if(sver >= 5) style->fontScaleY = GetFloat(buff);
  1181. if(sver >= 5) style->fontSpacing = GetFloat(buff);
  1182. if(sver >= 5) style->fontAngleZ = GetFloat(buff);
  1183. if(sver >= 4) style->borderStyle = GetInt(buff);
  1184. style->outlineWidth = GetFloat(buff);
  1185. style->shadowDepth = GetFloat(buff);
  1186. style->scrAlignment = GetInt(buff);
  1187. style->marginRect.left = GetInt(buff);
  1188. style->marginRect.right = GetInt(buff);
  1189. style->marginRect.top = style->marginRect.bottom = GetInt(buff);
  1190. if(sver <= 4) alpha = GetInt(buff);
  1191. style->charSet = GetInt(buff);
  1192. if(sver <= 4) style->colors[2] = style->colors[3]; // style->colors[2] is used for drawing the outline
  1193. if(sver <= 4) alpha = max(min(alpha, 0xff), 0);
  1194. if(sver <= 4) {for(int i = 0; i < 3; i++) style->alpha[i] = alpha; style->alpha[3] = 0x80;}
  1195. if(sver >= 5) for(int i = 0; i < 4; i++) {style->alpha[i] = (BYTE)(style->colors[i]>>24); style->colors[i] &= 0xffffff;}
  1196. if(sver >= 5) style->fontScaleX = max(style->fontScaleX, 0);
  1197. if(sver >= 5) style->fontScaleY = max(style->fontScaleY, 0);
  1198. if(sver >= 5) style->fontSpacing = max(style->fontSpacing, 0);
  1199. style->fontAngleX = style->fontAngleY = 0;
  1200. style->borderStyle = style->borderStyle == 1 ? 0 : style->borderStyle == 3 ? 1 : 0;
  1201. style->outlineWidth = max(style->outlineWidth, 0);
  1202. style->shadowDepth = max(style->shadowDepth, 0);
  1203. if(sver <= 4) style->scrAlignment = (style->scrAlignment&4) ? ((style->scrAlignment&3)+6) // top
  1204. : (style->scrAlignment&8) ? ((style->scrAlignment&3)+3) // mid
  1205. : (style->scrAlignment&3); // bottom
  1206. StyleName.TrimLeft('*');
  1207. ret.AddStyle(StyleName, style);
  1208. }
  1209. catch(...)
  1210. {
  1211. delete style;
  1212. return(false);
  1213. }
  1214. }
  1215. else if(entry == L"[events]")
  1216. {
  1217. fRet = true;
  1218. }
  1219. else if(entry == _T("dialogue"))
  1220. {
  1221. try
  1222. {
  1223. int hh1, mm1, ss1, ms1_div10, hh2, mm2, ss2, ms2_div10, layer = 0;
  1224. CString Style, Actor, Effect;
  1225. CRect marginRect;
  1226. if(version <= 4){GetStr(buff, '='); GetInt(buff);} /* Marked = */
  1227. if(version >= 5)layer = GetInt(buff);
  1228. hh1 = GetInt(buff, ':');
  1229. mm1 = GetInt(buff, ':');
  1230. ss1 = GetInt(buff, '.');
  1231. ms1_div10 = GetInt(buff);
  1232. hh2 = GetInt(buff, ':');
  1233. mm2 = GetInt(buff, ':');
  1234. ss2 = GetInt(buff, '.');
  1235. ms2_div10 = GetInt(buff);
  1236. Style = WToT(GetStr(buff));
  1237. Actor = WToT(GetStr(buff));
  1238. marginRect.left = GetInt(buff);
  1239. marginRect.right = GetInt(buff);
  1240. marginRect.top = marginRect.bottom = GetInt(buff);
  1241. Effect = WToT(GetStr(buff));
  1242. int len = min(Effect.GetLength(), buff.GetLength());
  1243. if(Effect.Left(len) == WToT(buff.Left(len))) Effect.Empty();
  1244. Style.TrimLeft('*');
  1245. if(!Style.CompareNoCase(_T("Default"))) Style = _T("Default");
  1246. ret.Add(buff,
  1247. file->IsUnicode(),
  1248. (((hh1*60 + mm1)*60) + ss1)*1000 + ms1_div10*10, 
  1249. (((hh2*60 + mm2)*60) + ss2)*1000 + ms2_div10*10, 
  1250. Style, Actor, Effect,
  1251. marginRect,
  1252. layer);
  1253. }
  1254. catch(...)
  1255. {
  1256. return(false);
  1257. }
  1258. }
  1259. else if(entry == L"fontname")
  1260. {
  1261. LoadUUEFont(file);
  1262. }
  1263. }
  1264. return(fRet);
  1265. }
  1266. static bool OpenXombieSub(CTextFile* file, CSimpleTextSubtitle& ret, int CharSet)
  1267. {
  1268. float version = 0;
  1269. // CMapStringToPtr stylemap;
  1270. CStringW buff;
  1271. while(file->ReadString(buff))
  1272. {
  1273. buff.Trim();
  1274. if(buff.IsEmpty() || buff.GetAt(0) == ';') continue;
  1275. CStringW entry;
  1276. // try {
  1277. entry = GetStr(buff, '=');
  1278. // }
  1279. // catch(...) {continue;}
  1280. entry.MakeLower();
  1281. if(entry == L"version")
  1282. {
  1283.             version = (float)GetFloat(buff);
  1284. }
  1285. else if(entry == L"screenhorizontal")
  1286. {
  1287. try {ret.m_dstScreenSize.cx = GetInt(buff);}
  1288. catch(...) {ret.m_dstScreenSize = CSize(0, 0); return(false);}
  1289. if(ret.m_dstScreenSize.cy <= 0)
  1290. {
  1291. ret.m_dstScreenSize.cy = (ret.m_dstScreenSize.cx == 1280)
  1292. ? 1024 
  1293. : ret.m_dstScreenSize.cx * 3 / 4;
  1294. }
  1295. }
  1296. else if(entry == L"screenvertical")
  1297. {
  1298. try {ret.m_dstScreenSize.cy = GetInt(buff);}
  1299. catch(...) {ret.m_dstScreenSize = CSize(0, 0); return(false);}
  1300. if(ret.m_dstScreenSize.cx <= 0)
  1301. {
  1302. ret.m_dstScreenSize.cx = (ret.m_dstScreenSize.cy == 1024)
  1303. ? 1280 
  1304. : ret.m_dstScreenSize.cy * 4 / 3;
  1305. }
  1306. }
  1307. else if(entry == L"style")
  1308. {
  1309. STSStyle* style = new STSStyle;
  1310. if(!style) return(false);
  1311. try 
  1312. {
  1313. CString StyleName;
  1314. StyleName = WToT(GetStr(buff)) + _T("_") + WToT(GetStr(buff));
  1315. style->fontName = WToT(GetStr(buff));
  1316. style->fontSize = GetFloat(buff);
  1317. for(int i = 0; i < 4; i++) style->colors[i] = (COLORREF)GetInt(buff);
  1318. for(int i = 0; i < 4; i++) style->alpha[i] = GetInt(buff);
  1319. style->fontWeight = !!GetInt(buff) ? FW_BOLD : FW_NORMAL;
  1320. style->fItalic = !!GetInt(buff);
  1321. style->fUnderline = !!GetInt(buff);
  1322. style->fStrikeOut = !!GetInt(buff);
  1323. style->fBlur = !!GetInt(buff);
  1324. style->fontScaleX = GetFloat(buff);
  1325. style->fontScaleY = GetFloat(buff);
  1326. style->fontSpacing = GetFloat(buff);
  1327. style->fontAngleX = GetFloat(buff);
  1328. style->fontAngleY = GetFloat(buff);
  1329. style->fontAngleZ = GetFloat(buff);
  1330. style->borderStyle = GetInt(buff);
  1331. style->outlineWidth = GetFloat(buff);
  1332. style->shadowDepth = GetFloat(buff);
  1333. style->scrAlignment = GetInt(buff);
  1334. style->marginRect.left = GetInt(buff);
  1335. style->marginRect.right = GetInt(buff);
  1336. style->marginRect.top = style->marginRect.bottom = GetInt(buff);
  1337. style->charSet = GetInt(buff);
  1338. style->fontScaleX = max(style->fontScaleX, 0);
  1339. style->fontScaleY = max(style->fontScaleY, 0);
  1340. style->fontSpacing = max(style->fontSpacing, 0);
  1341. style->borderStyle = style->borderStyle == 1 ? 0 : style->borderStyle == 3 ? 1 : 0;
  1342. style->outlineWidth = max(style->outlineWidth, 0);
  1343. style->shadowDepth = max(style->shadowDepth, 0);
  1344. ret.AddStyle(StyleName, style);
  1345. }
  1346. catch(...)
  1347. {
  1348. delete style;
  1349. return(false);
  1350. }
  1351. }
  1352. else if(entry == L"line")
  1353. {
  1354. try
  1355. {
  1356. CString id;
  1357. int hh1, mm1, ss1, ms1, hh2, mm2, ss2, ms2, layer = 0;
  1358. CString Style, Actor;
  1359. CRect marginRect;
  1360. if(GetStr(buff) != L"D") continue;
  1361. id = GetStr(buff);
  1362. layer = GetInt(buff);
  1363. hh1 = GetInt(buff, ':');
  1364. mm1 = GetInt(buff, ':');
  1365. ss1 = GetInt(buff, '.');
  1366. ms1 = GetInt(buff);
  1367. hh2 = GetInt(buff, ':');
  1368. mm2 = GetInt(buff, ':');
  1369. ss2 = GetInt(buff, '.');
  1370. ms2 = GetInt(buff);
  1371. Style = WToT(GetStr(buff)) + _T("_") + WToT(GetStr(buff));
  1372. Actor = WToT(GetStr(buff));
  1373. marginRect.left = GetInt(buff);
  1374. marginRect.right = GetInt(buff);
  1375. marginRect.top = marginRect.bottom = GetInt(buff);
  1376. Style.TrimLeft('*');
  1377. if(!Style.CompareNoCase(_T("Default"))) Style = _T("Default");
  1378. ret.Add(buff,
  1379. file->IsUnicode(),
  1380. (((hh1*60 + mm1)*60) + ss1)*1000 + ms1, 
  1381. (((hh2*60 + mm2)*60) + ss2)*1000 + ms2, 
  1382. Style, Actor, _T(""),
  1383. marginRect,
  1384. layer);
  1385. }
  1386. catch(...)
  1387. {
  1388. return(false);
  1389. }
  1390. }
  1391. else if(entry == L"fontname")
  1392. {
  1393. LoadUUEFont(file);
  1394. }
  1395. }
  1396. return(ret.GetCount() > 0);
  1397. }
  1398. #include "USFSubtitles.h"
  1399. static bool OpenUSF(CTextFile* file, CSimpleTextSubtitle& ret, int CharSet)
  1400. {
  1401. CString str;
  1402. while(file->ReadString(str))
  1403. {
  1404. if(str.Find(_T("USFSubtitles")) >= 0)
  1405. {
  1406. CUSFSubtitles usf;
  1407. if(usf.Read(file->GetFilePath()) && usf.ConvertToSTS(ret))
  1408. return(true);
  1409. break;
  1410. }
  1411. }
  1412. return(false);
  1413. }
  1414. static CStringW MPL22SSA(CStringW str)
  1415. {
  1416. CList<CStringW> sl;
  1417. Explode(str, sl, '|');
  1418. POSITION pos = sl.GetHeadPosition();
  1419. while(pos)
  1420. {
  1421. CStringW& s = sl.GetNext(pos);
  1422. if(s[0] == '/') {s = L"{\i1}" + s.Mid(1) + L"{\i0}";}
  1423. }
  1424. str = Implode(sl, 'n');
  1425. str.Replace(L"n", L"\N");
  1426. return str;
  1427. }
  1428. static bool OpenMPL2(CTextFile* file, CSimpleTextSubtitle& ret, int CharSet)
  1429. {
  1430. CStringW buff;;
  1431. while(file->ReadString(buff))
  1432. {
  1433. buff.Trim();
  1434. if(buff.IsEmpty()) continue;
  1435. int start, end;
  1436. int c = swscanf(buff, L"[%d][%d]", &start, &end);
  1437. if(c == 2)
  1438. {
  1439. ret.Add(
  1440. MPL22SSA(buff.Mid(buff.Find(']', buff.Find(']')+1)+1)), 
  1441. file->IsUnicode(),
  1442. start*100, end*100);
  1443. }
  1444. else if(c != EOF) // might be another format
  1445. {
  1446. return(false);
  1447. }
  1448. }
  1449. return(ret.GetCount() > 0);
  1450. }
  1451. typedef bool (*STSOpenFunct)(CTextFile* file, CSimpleTextSubtitle& ret, int CharSet);
  1452. typedef struct {STSOpenFunct open; tmode mode;} OpenFunctStruct;
  1453. static OpenFunctStruct OpenFuncts[] = 
  1454. {
  1455. OpenSubRipper, TIME,
  1456. OpenOldSubRipper, TIME,
  1457. OpenSubViewer, TIME,
  1458. OpenMicroDVD, FRAME,
  1459. OpenSami, TIME,
  1460. OpenVPlayer, TIME,
  1461. OpenSubStationAlpha, TIME,
  1462. OpenXombieSub, TIME,
  1463. OpenUSF, TIME,
  1464. OpenMPL2, TIME,
  1465. };
  1466. static int nOpenFuncts = countof(OpenFuncts);
  1467. //
  1468. CSimpleTextSubtitle::CSimpleTextSubtitle()
  1469. {
  1470. m_mode = TIME;
  1471. m_dstScreenSize = CSize(0, 0);
  1472. m_defaultWrapStyle = 0;
  1473. m_collisions = 0;
  1474. m_fScaledBAS = false;
  1475. m_encoding = CTextFile::ASCII;
  1476. }
  1477. CSimpleTextSubtitle::~CSimpleTextSubtitle()
  1478. {
  1479. Empty();
  1480. }
  1481. /*
  1482. CSimpleTextSubtitle::CSimpleTextSubtitle(CSimpleTextSubtitle& sts)
  1483. {
  1484. *this = sts;
  1485. }
  1486. CSimpleTextSubtitle& CSimpleTextSubtitle::operator = (CSimpleTextSubtitle& sts)
  1487. {
  1488. Empty();
  1489. m_name = sts.m_name;
  1490. m_mode = sts.m_mode;
  1491. m_dstScreenSize = sts.m_dstScreenSize;
  1492. m_defaultWrapStyle = sts.m_defaultWrapStyle;
  1493. m_collisions = sts.m_collisions;
  1494. m_fScaledBAS = sts.m_fScaledBAS;
  1495. m_fSSA = sts.m_fSSA;
  1496. m_fUsingAutoGeneratedDefaultStyle = sts.m_fUsingAutoGeneratedDefaultStyle;
  1497. CopyStyles(sts.m_styles);
  1498. m_segments.Copy(sts.m_segments);
  1499. Copy(sts);
  1500. return(*this);
  1501. }
  1502. */
  1503. void CSimpleTextSubtitle::Copy(CSimpleTextSubtitle& sts)
  1504. {
  1505. Empty();
  1506. m_name = sts.m_name;
  1507. m_mode = sts.m_mode;
  1508. m_dstScreenSize = sts.m_dstScreenSize;
  1509. m_defaultWrapStyle = sts.m_defaultWrapStyle;
  1510. m_collisions = sts.m_collisions;
  1511. m_fScaledBAS = sts.m_fScaledBAS;
  1512. m_encoding = sts.m_encoding;
  1513. m_fUsingAutoGeneratedDefaultStyle = sts.m_fUsingAutoGeneratedDefaultStyle;
  1514. CopyStyles(sts.m_styles);
  1515. m_segments.Copy(sts.m_segments);
  1516. CSTSArray::Copy(sts);
  1517. }
  1518. void CSimpleTextSubtitle::Append(CSimpleTextSubtitle& sts, int timeoff)
  1519. {
  1520. if(timeoff < 0) 
  1521. {
  1522. timeoff = GetSize() > 0 ? GetAt(GetSize()-1).end : 0;
  1523. }
  1524. for(int i = 0, j = GetSize(); i < j; i++)
  1525. {
  1526. if(GetAt(i).start > timeoff) 
  1527. {
  1528. RemoveAt(i, j - i);
  1529. break;
  1530. }
  1531. }
  1532. CopyStyles(sts.m_styles, true);
  1533. for(int i = 0, j = sts.GetSize(); i < j; i++)
  1534. {
  1535. STSEntry stse = sts.GetAt(i);
  1536. stse.start += timeoff;
  1537. stse.end += timeoff;
  1538. stse.readorder += GetSize();
  1539. CSTSArray::Add(stse);
  1540. }
  1541. CreateSegments();
  1542. }
  1543. void CSTSStyleMap::Free()
  1544. {
  1545. POSITION pos = GetStartPosition();
  1546. while(pos) 
  1547. {
  1548. CString key;
  1549. void* ptr;
  1550. GetNextAssoc(pos, key, ptr);
  1551. delete (STSStyle*)ptr;
  1552. }
  1553. RemoveAll();
  1554. }
  1555. bool CSimpleTextSubtitle::CopyStyles(const CSTSStyleMap& styles, bool fAppend)
  1556. {
  1557. if(!fAppend) m_styles.Free();
  1558. POSITION pos = styles.GetStartPosition();
  1559. while(pos) 
  1560. {
  1561. CString key;
  1562. void* ptr;
  1563. styles.GetNextAssoc(pos, key, ptr);
  1564. STSStyle* s = new STSStyle;
  1565. if(!s) return(false);
  1566. *s = *((STSStyle*)ptr);
  1567. AddStyle(key, s);
  1568. }
  1569. return(true);
  1570. }
  1571. void CSimpleTextSubtitle::Empty()
  1572. {
  1573. m_dstScreenSize = CSize(0, 0);
  1574. m_styles.Free();
  1575. m_segments.RemoveAll();
  1576. RemoveAll();
  1577. }
  1578. void CSimpleTextSubtitle::Add(CStringW str, bool fUnicode, int start, int end, CString style, CString actor, CString effect, CRect marginRect, int layer, int readorder)
  1579. {
  1580. if(str.Trim().IsEmpty() || start > end) return;
  1581. str.Remove('r');
  1582. str.Replace(L"n", L"\N");
  1583. if(style.IsEmpty()) style = _T("Default");
  1584. style.TrimLeft('*');
  1585. STSEntry sub;
  1586. sub.str = str;
  1587. sub.fUnicode = fUnicode;
  1588. sub.style = style;
  1589. sub.actor = actor;
  1590. sub.effect = effect;
  1591. sub.marginRect = marginRect;
  1592. sub.layer = layer;
  1593. sub.start = start;
  1594. sub.end = end;
  1595. sub.readorder = readorder < 0 ? GetSize() : readorder;
  1596. int n = CSTSArray::Add(sub);
  1597. int len = m_segments.GetSize();
  1598.     if(len == 0)
  1599. {
  1600. STSSegment stss(start, end);
  1601. stss.subs.Add(n);
  1602. m_segments.Add(stss);
  1603. }
  1604. else if(end <= m_segments[0].start)
  1605. {
  1606. STSSegment stss(start, end);
  1607. stss.subs.Add(n);
  1608. m_segments.InsertAt(0, stss);
  1609. }
  1610. else if(start >= m_segments[len-1].end)
  1611. {
  1612. STSSegment stss(start, end);
  1613. stss.subs.Add(n);
  1614. m_segments.Add(stss);
  1615. }
  1616. else
  1617. {
  1618. if(start < m_segments[0].start)
  1619. {
  1620. STSSegment stss(start, m_segments[0].start);
  1621. stss.subs.Add(n);
  1622. start = m_segments[0].start;
  1623. m_segments.InsertAt(0, stss);
  1624. }
  1625. for(int i = 0; i < m_segments.GetCount(); i++)
  1626. {
  1627. STSSegment& s = m_segments[i];
  1628. if(start >= s.end)
  1629. continue;
  1630. if(end <= s.start)
  1631. break;
  1632. if(s.start < start && start < s.end)
  1633. {
  1634. STSSegment stss(s.start, start);
  1635. stss.subs.Copy(s.subs);
  1636. s.start = start;
  1637. m_segments.InsertAt(i, stss);
  1638. continue;
  1639. }
  1640. if(start <= s.start && s.end <= end)
  1641. {
  1642. for(int j = 0, k = s.subs.GetCount(); j <= k; j++)
  1643. {
  1644. if(j == k || sub.readorder < GetAt(s.subs[j]).readorder)
  1645. s.subs.InsertAt(j, n);
  1646. }
  1647. // s.subs.Add(n);
  1648. }
  1649. if(s.start < end && end < s.end)
  1650. {
  1651. STSSegment stss(s.start, end);
  1652. stss.subs.Copy(s.subs);
  1653. for(int j = 0, k = s.subs.GetCount(); j <= k; j++)
  1654. {
  1655. if(j == k || sub.readorder < GetAt(stss.subs[j]).readorder)
  1656. stss.subs.InsertAt(j, n);
  1657. }
  1658. // stss.subs.Add(n);
  1659. s.start = end;
  1660. m_segments.InsertAt(i, stss);
  1661. }
  1662. }
  1663. if(end > m_segments[m_segments.GetCount()-1].end)
  1664. {
  1665. STSSegment stss(m_segments[m_segments.GetCount()-1].end, end);
  1666. stss.subs.Add(n);
  1667. m_segments.Add(stss);
  1668. }
  1669. }
  1670. /*
  1671. str.Remove('r');
  1672. str.Replace(L"n", L"\N");
  1673. if(style.IsEmpty()) style = _T("Default");
  1674. int j = m_segments.GetSize();
  1675. for(int i = j-1; i >= 0; i--)
  1676. {
  1677. if(m_segments[i].end <= start)
  1678. {
  1679. break;
  1680. }
  1681. else if(m_segments[i].start >= start)
  1682. {
  1683. m_segments.SetSize(m_segments.GetSize()-1);
  1684. j--;
  1685. }
  1686. else if(m_segments[i].end > start)
  1687. {
  1688. if(i < j-1) m_segments.RemoveAt(i+1, j-i-1);
  1689. m_segments[i].end = start;
  1690. break;
  1691. }
  1692. }
  1693. if(m_segments.GetSize() == 0 && j > 0) 
  1694. CSTSArray::RemoveAll();
  1695. STSSegment stss(start, end);
  1696. int len = GetSize();
  1697. stss.subs.Add(len);
  1698. m_segments.Add(stss);
  1699. STSEntry sub;
  1700. sub.str = str;
  1701. sub.fUnicode = fUnicode;
  1702. sub.style = style;
  1703. sub.actor = actor;
  1704. sub.effect = effect;
  1705. sub.marginRect = marginRect;
  1706. sub.layer = layer;
  1707. sub.start = start;
  1708. sub.end = end;
  1709. sub.readorder = GetSize();
  1710. CSTSArray::Add(sub);
  1711. */
  1712. }
  1713. void CSimpleTextSubtitle::CreateDefaultStyle(int CharSet)
  1714. {
  1715. CString def(_T("Default"));
  1716. void* value;
  1717. // if(m_styles.IsEmpty())
  1718. if(!m_styles.Lookup(def, value))
  1719. {
  1720. STSStyle* style = new STSStyle;
  1721. if(!style) return;
  1722. style->charSet = CharSet;
  1723. AddStyle(def, style);
  1724. /*
  1725. for(int i = 0; i < GetSize(); i++)
  1726. {
  1727. (*this)[i].style = def;
  1728. }
  1729. */
  1730. m_fUsingAutoGeneratedDefaultStyle = true;
  1731. }
  1732. else
  1733. {
  1734. m_fUsingAutoGeneratedDefaultStyle = false;
  1735. }
  1736. }
  1737. void CSimpleTextSubtitle::ChangeUnknownStylesToDefault()
  1738. {
  1739. CMapStringToPtr unknown;
  1740. bool fReport = true;
  1741. for(int i = 0; i < GetSize(); i++)
  1742. {
  1743. STSEntry& stse = GetAt(i);
  1744. void* val;
  1745. if(!m_styles.Lookup(stse.style, val))
  1746. {
  1747. if(!unknown.Lookup(stse.style, val))
  1748. {
  1749. if(fReport)
  1750. {
  1751. CString msg;
  1752. msg.Format(_T("Unknown style found: "%s", changed to "Default"!nnPress Cancel to ignore further warnings."), stse.style);
  1753. if(MessageBox(NULL, msg, _T("Warning"), MB_OKCANCEL|MB_ICONWARNING) != IDOK) fReport = false;
  1754. }
  1755. unknown[stse.style] = NULL;
  1756. }
  1757. stse.style = _T("Default");
  1758. }
  1759. }
  1760. }
  1761. void CSimpleTextSubtitle::AddStyle(CString name, STSStyle* style)
  1762. {
  1763. int i, j;
  1764. if(name.IsEmpty()) name = _T("Default");
  1765. void* value;
  1766. if(m_styles.Lookup(name, value)) 
  1767. {
  1768. if(*((STSStyle*)value) == *style)
  1769. {
  1770. delete style;
  1771. return;
  1772. }
  1773. int len = name.GetLength();
  1774. for(i = len; i > 0 && _istdigit(name[i-1]); i--);
  1775. int idx = 1;
  1776. CString name2 = name;
  1777. if(i < len && _stscanf(name.Right(len-i), _T("%d"), &idx) == 1)
  1778. {
  1779. name2 = name.Left(i);
  1780. }
  1781. idx++;
  1782. CString name3;
  1783. do
  1784. {
  1785. name3.Format(_T("%s%d"), name2, idx);
  1786. idx++;
  1787. }
  1788. while(m_styles[name3]);
  1789. m_styles.RemoveKey(name);
  1790. m_styles[name3] = (STSStyle*)value;
  1791. for(i = 0, j = GetSize(); i < j; i++)
  1792. {
  1793. STSEntry& stse = GetAt(i);
  1794. if(stse.style == name) stse.style = name3;
  1795. }
  1796. }
  1797. m_styles[name] = style;
  1798. }
  1799. bool CSimpleTextSubtitle::SetDefaultStyle(STSStyle& s)
  1800. {
  1801. void* val;
  1802. if(m_styles.Lookup(_T("Default"), val))
  1803. {
  1804. *((STSStyle*)val) = s;
  1805. m_fUsingAutoGeneratedDefaultStyle = false;
  1806. return(true);
  1807. }
  1808. return(false);
  1809. }
  1810. bool CSimpleTextSubtitle::GetDefaultStyle(STSStyle& s)
  1811. {
  1812. void* val;
  1813. if(m_styles.Lookup(_T("Default"), val))
  1814. {
  1815. s = *((STSStyle*)val);
  1816. return(true);
  1817. }
  1818. return(false);
  1819. }
  1820. void CSimpleTextSubtitle::ConvertToTimeBased(double fps)
  1821. {
  1822. if(m_mode == TIME) return;
  1823. for(int i = 0, j = GetSize(); i < j; i++)
  1824. {
  1825. STSEntry& stse = (*this)[i];
  1826. stse.start = int(1.0 * stse.start * 1000 / fps + 0.5);
  1827. stse.end = int(1.0 * stse.end * 1000 / fps + 0.5);
  1828. }
  1829. m_mode = TIME;
  1830. CreateSegments();
  1831. }
  1832. void CSimpleTextSubtitle::ConvertToFrameBased(double fps)
  1833. {
  1834. if(m_mode == FRAME) return;
  1835. for(int i = 0, j = GetSize(); i < j; i++)
  1836. {
  1837. STSEntry& stse = (*this)[i];
  1838. stse.start = int(1.0 * stse.start * fps / 1000 + 0.5);
  1839. stse.end = int(1.0 * stse.end * fps / 1000 + 0.5);
  1840. }
  1841. m_mode = FRAME;
  1842. CreateSegments();
  1843. }
  1844. int CSimpleTextSubtitle::SearchSub(int t, double fps)
  1845. {
  1846. int i = 0, j = GetSize() - 1, ret = -1;
  1847. if(j >= 0 && t >= TranslateStart(j, fps))
  1848. {
  1849. return(j);
  1850. }
  1851. while(i < j)
  1852. {
  1853. int mid = (i + j) >> 1;
  1854. int midt = TranslateStart(mid, fps);
  1855. if(t == midt)
  1856. {
  1857. while(mid > 0 && t == TranslateStart(mid-1, fps)) mid--;
  1858. ret = mid;
  1859. break;
  1860. }
  1861. else if(t < midt)
  1862. {
  1863. ret = -1;
  1864. if(j == mid) mid--;
  1865. j = mid;
  1866. }
  1867. else if(t > midt)
  1868. {
  1869. ret = mid;
  1870. if(i == mid) mid++;
  1871. i = mid;
  1872. }
  1873. }
  1874. return(ret);
  1875. }
  1876. const STSSegment* CSimpleTextSubtitle::SearchSubs(int t, double fps, /*[out]*/ int* iSegment, int* nSegments)
  1877. {
  1878. int i = 0, j = m_segments.GetSize() - 1, ret = -1;
  1879. if(nSegments) *nSegments = j+1;
  1880. if(j >= 0 && t >= TranslateSegmentStart(j, fps) && t < TranslateSegmentEnd(j, fps))
  1881. {
  1882. if(iSegment) *iSegment = j;
  1883. return(&m_segments[j]);
  1884. }
  1885. if(j >= 0 && t >= TranslateSegmentEnd(j, fps))
  1886. {
  1887. if(iSegment) *iSegment = j+1;
  1888. return(NULL);
  1889. }
  1890. if(j > 0 && t < TranslateSegmentStart(i, fps))
  1891. {
  1892. if(iSegment) *iSegment = -1;
  1893. return(NULL);
  1894. }
  1895. while(i < j)
  1896. {
  1897. int mid = (i + j) >> 1;
  1898. int midt = TranslateSegmentStart(mid, fps);
  1899. if(t == midt)
  1900. {
  1901. ret = mid;
  1902. break;
  1903. }
  1904. else if(t < midt)
  1905. {
  1906. ret = -1;
  1907. if(j == mid) mid--;
  1908. j = mid;
  1909. }
  1910. else if(t > midt)
  1911. {
  1912. ret = mid;
  1913. if(i == mid) mid++;
  1914. i = mid;
  1915. }
  1916. }
  1917. if(0 <= ret && ret < m_segments.GetSize())
  1918. {
  1919. if(iSegment) *iSegment = ret;
  1920. }
  1921. if(0 <= ret && ret < m_segments.GetSize() 
  1922. && m_segments[ret].subs.GetSize() > 0
  1923. && TranslateSegmentStart(ret, fps) <= t && t < TranslateSegmentEnd(ret, fps))
  1924. {
  1925. return(&m_segments[ret]);
  1926. }
  1927. return(NULL);
  1928. }
  1929. int CSimpleTextSubtitle::TranslateStart(int i, double fps)
  1930. {
  1931. return(i < 0 || GetSize() <= i ? -1 :
  1932. m_mode == TIME ? GetAt(i).start :
  1933. m_mode == FRAME ? (int)(GetAt(i).start*1000/fps) :
  1934. 0);
  1935. }
  1936. int CSimpleTextSubtitle::TranslateEnd(int i, double fps)
  1937. {
  1938. return(i < 0 || GetSize() <= i ? -1 :
  1939. m_mode == TIME ? GetAt(i).end :
  1940. m_mode == FRAME ? (int)(GetAt(i).end*1000/fps) :
  1941. 0);
  1942. }
  1943. int CSimpleTextSubtitle::TranslateSegmentStart(int i, double fps)
  1944. {
  1945. return(i < 0 || m_segments.GetSize() <= i ? -1 :
  1946. m_mode == TIME ? m_segments[i].start :
  1947. m_mode == FRAME ? (int)(m_segments[i].start*1000/fps) :
  1948. 0);
  1949. }
  1950. int CSimpleTextSubtitle::TranslateSegmentEnd(int i, double fps)
  1951. {
  1952. return(i < 0 || m_segments.GetSize() <= i ? -1 :
  1953. m_mode == TIME ? m_segments[i].end :
  1954. m_mode == FRAME ? (int)(m_segments[i].end*1000/fps) :
  1955. 0);
  1956. }
  1957. STSStyle* CSimpleTextSubtitle::GetStyle(int i)
  1958. {
  1959. STSStyle* style = (STSStyle*)m_styles[GetAt(i).style];
  1960. if(!style) style = (STSStyle*)m_styles[_T("Default")];
  1961. ASSERT(style);
  1962. return(style);
  1963. }
  1964. bool CSimpleTextSubtitle::GetStyle(int i, STSStyle& stss)
  1965. {
  1966. CString def = _T("Default");
  1967. STSStyle* style = (STSStyle*)m_styles[GetAt(i).style];
  1968. STSStyle* defstyle = (STSStyle*)m_styles[def];
  1969. if(!style) {if(defstyle) {ASSERT(0); CreateDefaultStyle(DEFAULT_CHARSET); defstyle = (STSStyle*)m_styles[def];} style = defstyle;}
  1970. if(!style) {ASSERT(0); return(false);}
  1971. stss = *style;
  1972. if(stss.relativeTo == 2 && defstyle)
  1973. stss.relativeTo = defstyle->relativeTo;
  1974. return(true);
  1975. }
  1976. int CSimpleTextSubtitle::GetCharSet(int i)
  1977. {
  1978. STSStyle stss;
  1979. GetStyle(i, stss);
  1980. return(stss.charSet);
  1981. }
  1982. bool CSimpleTextSubtitle::IsEntryUnicode(int i)
  1983. {
  1984. return(GetAt(i).fUnicode);
  1985. }
  1986. void CSimpleTextSubtitle::ConvertUnicode(int i, bool fUnicode)
  1987. {
  1988. STSEntry& stse = GetAt(i);
  1989. if(stse.fUnicode ^ fUnicode)
  1990. {
  1991. int CharSet = GetCharSet(i);
  1992. stse.str = fUnicode 
  1993. ? MBCSSSAToUnicode(stse.str, CharSet)
  1994. : UnicodeSSAToMBCS(stse.str, CharSet);
  1995. stse.fUnicode = fUnicode;
  1996. }
  1997. }
  1998. CStringA CSimpleTextSubtitle::GetStrA(int i, bool fSSA)
  1999. {
  2000. return(WToA(GetStrWA(i, fSSA)));
  2001. }
  2002. CStringW CSimpleTextSubtitle::GetStrW(int i, bool fSSA)
  2003. {
  2004. bool fUnicode = IsEntryUnicode(i);
  2005. int CharSet = GetCharSet(i);
  2006. CStringW str = GetAt(i).str;
  2007. if(!fUnicode)
  2008. str = MBCSSSAToUnicode(str, CharSet);
  2009. if(!fSSA)
  2010. str = RemoveSSATags(str, fUnicode, CharSet);
  2011. return(str);
  2012. }
  2013. CStringW CSimpleTextSubtitle::GetStrWA(int i, bool fSSA)
  2014. {
  2015. bool fUnicode = IsEntryUnicode(i);
  2016. int CharSet = GetCharSet(i);
  2017. CStringW str = GetAt(i).str;
  2018. if(fUnicode)
  2019. str = UnicodeSSAToMBCS(str, CharSet);
  2020. if(!fSSA)
  2021. str = RemoveSSATags(str, fUnicode, CharSet);
  2022. return(str);
  2023. }
  2024. void CSimpleTextSubtitle::SetStr(int i, CStringA str, bool fUnicode)
  2025. {
  2026. SetStr(i, AToW(str), false);
  2027. }
  2028. void CSimpleTextSubtitle::SetStr(int i, CStringW str, bool fUnicode)
  2029. {
  2030. STSEntry& stse = GetAt(i);
  2031. str.Replace(L"n", L"\N"); 
  2032. if(stse.fUnicode && !fUnicode) stse.str = MBCSSSAToUnicode(str, GetCharSet(i));
  2033. else if(!stse.fUnicode && fUnicode) stse.str = UnicodeSSAToMBCS(str, GetCharSet(i));
  2034. else stse.str = str;
  2035. }
  2036. static int comp1(const void* a, const void* b)
  2037. {
  2038. int ret = ((STSEntry*)a)->start - ((STSEntry*)b)->start;
  2039. if(ret == 0) ret = ((STSEntry*)a)->layer - ((STSEntry*)b)->layer;
  2040. if(ret == 0) ret = ((STSEntry*)a)->readorder - ((STSEntry*)b)->readorder;
  2041. return(ret);
  2042. }
  2043. static int comp2(const void* a, const void* b)
  2044. {
  2045. return(((STSEntry*)a)->readorder - ((STSEntry*)b)->readorder);
  2046. }
  2047. void CSimpleTextSubtitle::Sort(bool fRestoreReadorder)
  2048. {
  2049. qsort(GetData(), GetSize(), sizeof(STSEntry), !fRestoreReadorder ? comp1 : comp2);
  2050. CreateSegments();
  2051. }
  2052. static int intcomp(const void* i1, const void* i2)
  2053. {
  2054. return(*((int*)i1) - *((int*)i2));
  2055. }
  2056. void CSimpleTextSubtitle::CreateSegments()
  2057. {
  2058. m_segments.RemoveAll();
  2059. int i, j;
  2060. CArray<int> breakpoints;
  2061. for(i = 0; i < GetSize(); i++)
  2062. {
  2063. STSEntry& stse = GetAt(i);
  2064. breakpoints.Add(stse.start);
  2065. breakpoints.Add(stse.end);
  2066. }
  2067. qsort(breakpoints.GetData(), breakpoints.GetSize(), sizeof(int), intcomp);
  2068. int* ptr = breakpoints.GetData(), prev = ptr ? *ptr : NULL;
  2069. for(i = breakpoints.GetSize(); i > 0; i--, ptr++)
  2070. {
  2071. if(*ptr != prev) 
  2072. {
  2073. m_segments.Add(STSSegment(prev, *ptr));
  2074. prev = *ptr;
  2075. }
  2076. }
  2077. for(i = 0; i < GetSize(); i++)
  2078. {
  2079. STSEntry& stse = GetAt(i);
  2080. for(j = 0; j < m_segments.GetSize() && m_segments[j].start < stse.start; j++);
  2081. for(; j < m_segments.GetSize() && m_segments[j].end <= stse.end; j++) 
  2082. m_segments[j].subs.Add(i);
  2083. }
  2084. OnChanged();
  2085. /*
  2086. for(i = 0, j = m_segments.GetSize(); i < j; i++)
  2087. {
  2088. STSSegment& stss = m_segments[i];
  2089. TRACE(_T("%d - %d"), stss.start, stss.end);
  2090. for(int k = 0, l = stss.subs.GetSize(); k < l; k++)
  2091. {
  2092. TRACE(_T(", %d"), stss.subs[k]);
  2093. }
  2094. TRACE(_T("n"));
  2095. }
  2096. */
  2097. }
  2098. bool CSimpleTextSubtitle::Open(CString fn, int CharSet, CString name)
  2099. {
  2100. Empty();
  2101. CWebTextFile f;
  2102. if(!f.Open(fn)) return(false);
  2103. fn.Replace('\', '/');
  2104. if(name.IsEmpty())
  2105. {
  2106. name = fn.Left(fn.ReverseFind('.'));
  2107. name = name.Mid(name.ReverseFind('/')+1);
  2108. name = name.Mid(name.ReverseFind('.')+1);
  2109. }
  2110. return(Open(&f, CharSet, name));
  2111. }
  2112. static int CountLines(CTextFile* f, ULONGLONG from, ULONGLONG to)
  2113. {
  2114. int n = 0;
  2115. CString s;
  2116. f->Seek(from, 0);
  2117. while(f->ReadString(s) && f->GetPosition() < to) n++;
  2118. return(n);
  2119. }
  2120. bool CSimpleTextSubtitle::Open(CTextFile* f, int CharSet, CString name)
  2121. {
  2122. Empty();
  2123. ULONGLONG pos = f->GetPosition();
  2124. for(int i = 0; i < nOpenFuncts; i++)
  2125. {
  2126. if(!OpenFuncts[i].open(f, *this, CharSet) /*|| !GetSize()*/) 
  2127. {
  2128. if(GetSize() > 0)
  2129. {
  2130. int n = CountLines(f, pos, f->GetPosition());
  2131. CString s;
  2132. s.Format(_T("Syntax error at line %d!t"), n+1);
  2133. AfxMessageBox(s, MB_OK|MB_ICONERROR);
  2134. Empty();
  2135. break;
  2136. }
  2137. f->Seek(pos, 0);
  2138. Empty();
  2139. continue;
  2140. }
  2141. m_name = name;
  2142. m_mode = OpenFuncts[i].mode;
  2143. m_encoding = f->GetEncoding();
  2144. m_path = f->GetFilePath();
  2145. // Sort();
  2146. CreateSegments();
  2147. CWebTextFile f2;
  2148. if(f2.Open(f->GetFilePath() + _T(".style"))) 
  2149. OpenSubStationAlpha(&f2, *this, CharSet);
  2150. CreateDefaultStyle(CharSet);
  2151. ChangeUnknownStylesToDefault();
  2152. if(m_dstScreenSize == CSize(0, 0)) m_dstScreenSize = CSize(384, 288);
  2153. return(true);
  2154. }
  2155. return(false);
  2156. }
  2157. bool CSimpleTextSubtitle::Open(BYTE* data, int len, int CharSet, CString name)
  2158. {
  2159. TCHAR path[MAX_PATH];
  2160. if(!GetTempPath(MAX_PATH, path)) return(false);
  2161. TCHAR fn[MAX_PATH];
  2162. if(!GetTempFileName(path, _T("vs"), 0, fn)) return(false);
  2163. FILE* tmp = _tfopen(fn, _T("wb"));
  2164. if(!tmp) return(false);
  2165. int i = 0;
  2166. for(; i <= (len-1024); i += 1024) fwrite(&data[i], 1024, 1, tmp);
  2167. if(len > i) fwrite(&data[i], len - i, 1, tmp);
  2168. fclose(tmp);
  2169. bool fRet = Open(fn, CharSet, name);
  2170. _tremove(fn);
  2171. return(fRet);
  2172. }
  2173. bool CSimpleTextSubtitle::SaveAs(CString fn, exttype et, double fps, CTextFile::enc e)
  2174. {
  2175. if(fn.Mid(fn.ReverseFind('.')+1).CompareNoCase(exttypestr[et])) 
  2176. {
  2177. if(fn[fn.GetLength()-1] != '.') fn += _T("."); 
  2178. fn += exttypestr[et];
  2179. }
  2180. CTextFile f;
  2181. if(!f.Save(fn, e))
  2182. return(false);
  2183. if(et == EXTSMI)
  2184. {
  2185. CString str;
  2186. str += _T("<SAMI>n<HEAD>n");
  2187. str += _T("<STYLE TYPE="text/css">n");
  2188. str += _T("<!--n");
  2189. str += _T("P {margin-left: 16pt; margin-right: 16pt; margin-bottom: 16pt; margin-top: 16pt;n");
  2190. str += _T("   text-align: center; font-size: 18pt; font-family: arial; font-weight: bold; color: #f0f0f0;}n");
  2191. str += _T(".UNKNOWNCC {Name:Unknown; lang:en-US; SAMIType:CC;}n");
  2192. str += _T("-->n");
  2193. str += _T("</STYLE>n");
  2194. str += _T("</HEAD>n");
  2195. str += _T("n");
  2196. str += _T("<BODY>n");
  2197. f.WriteString(str);
  2198. }
  2199. else if(et == EXTSSA || et == EXTASS)
  2200. {
  2201. CString str;
  2202. str  = _T("[Script Info]n");
  2203. str += (et == EXTSSA) ? _T("; This is a Sub Station Alpha v4 script.n") : _T("; This is an Advanced Sub Station Alpha v4+ script.n");
  2204. str += _T("; For Sub Station Alpha info and downloads,n");
  2205. str += _T("; go to http://www.eswat.demon.co.uk/n");
  2206. str += _T("; or email kotus@eswat.demon.co.ukn");
  2207. str += _T("; n");
  2208. if(et == EXTASS) 
  2209. {
  2210. str += _T("; Advanced Sub Station Alpha script format developed by #Anime-Fansubs@EfNETn");
  2211. str += _T("; http://www.anime-fansubs.orgn");
  2212. str += _T("; n");
  2213. str += _T("; For additional info and downloads go to http://gabest.org/n");
  2214. str += _T("; or email gabest@freemail.hun");
  2215. str += _T("; n");
  2216. }
  2217. str += _T("; Note: This file was saved by Subresync.n");
  2218. str += _T("; n");
  2219. str += (et == EXTSSA) ? _T("ScriptType: v4.00n") : _T("ScriptType: v4.00+n");
  2220. str += (m_collisions == 0) ? _T("Collisions: Normaln") : _T("Collisions: Reversen");
  2221. if(et == EXTASS && m_fScaledBAS) str += _T("ScaledBorderAndShadow: Yesn");
  2222. str += _T("PlayResX: %dn");
  2223. str += _T("PlayResY: %dn");
  2224. str += _T("Timer: 100.0000n");
  2225. str += _T("n");
  2226. str += (et == EXTSSA) 
  2227. ? _T("[V4 Styles]nFormat: Name, Fontname, Fontsize, PrimaryColour, SecondaryColour, TertiaryColour, BackColour, Bold, Italic, BorderStyle, Outline, Shadow, Alignment, MarginL, MarginR, MarginV, AlphaLevel, Encodingn")
  2228. : _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, Encodingn");
  2229. CString str2;
  2230. str2.Format(str, m_dstScreenSize.cx, m_dstScreenSize.cy);
  2231. f.WriteString(str2);
  2232. str  = (et == EXTSSA)
  2233. ? _T("Style: %s,%s,%d,&H%06x,&H%06x,&H%06x,&H%06x,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%dn")
  2234. : _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,%dn");
  2235. POSITION pos = m_styles.GetStartPosition();
  2236. while(pos) 
  2237. {
  2238. CString key;
  2239. void* ptr;
  2240. m_styles.GetNextAssoc(pos, key, ptr);
  2241. STSStyle* s = (STSStyle*)ptr;
  2242. if(et == EXTSSA)
  2243. {
  2244. CString str2;
  2245. str2.Format(str, key,
  2246. s->fontName, (int)s->fontSize,
  2247. s->colors[0]&0xffffff, 
  2248. s->colors[1]&0xffffff, 
  2249. s->colors[2]&0xffffff, 
  2250. s->colors[3]&0xffffff, 
  2251. s->fontWeight > FW_NORMAL ? -1 : 0, s->fItalic ? -1 : 0,
  2252. s->borderStyle == 0 ? 1 : s->borderStyle == 1 ? 3 : 0, 
  2253. (int)s->outlineWidth, (int)s->shadowDepth, 
  2254. s->scrAlignment <= 3 ? s->scrAlignment : s->scrAlignment <= 6 ? ((s->scrAlignment-3)|8) : s->scrAlignment <= 9 ? ((s->scrAlignment-6)|4) : 2,
  2255. s->marginRect.left, s->marginRect.right, (s->marginRect.top + s->marginRect.bottom) / 2,
  2256. s->alpha[0],
  2257. s->charSet);
  2258. f.WriteString(str2);
  2259. }
  2260. else
  2261. {
  2262. CString str2;
  2263. str2.Format(str, key,
  2264. s->fontName, (int)s->fontSize,
  2265. (s->colors[0]&0xffffff) | (s->alpha[0]<<24),
  2266. (s->colors[1]&0xffffff) | (s->alpha[1]<<24),
  2267. (s->colors[2]&0xffffff) | (s->alpha[2]<<24),
  2268. (s->colors[3]&0xffffff) | (s->alpha[3]<<24),
  2269. s->fontWeight > FW_NORMAL ? -1 : 0, 
  2270. s->fItalic ? -1 : 0, s->fUnderline ? -1 : 0, s->fStrikeOut ? -1 : 0, 
  2271. (int)s->fontScaleX, (int)s->fontScaleY,
  2272. (int)s->fontSpacing, (float)s->fontAngleZ,
  2273. s->borderStyle == 0 ? 1 : s->borderStyle == 1 ? 3 : 0, 
  2274. (int)s->outlineWidth, (int)s->shadowDepth, 
  2275. s->scrAlignment,
  2276. s->marginRect.left, s->marginRect.right, (s->marginRect.top + s->marginRect.bottom) / 2,
  2277. s->charSet);
  2278. f.WriteString(str2);
  2279. }
  2280. }
  2281. if(GetSize() > 0)
  2282. {
  2283. str  = _T("n");
  2284. str += _T("[Events]n");
  2285. str += (et == EXTSSA) 
  2286. ? _T("Format: Marked, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Textn")
  2287. : _T("Format: Layer, Start, End, Style, Actor, MarginL, MarginR, MarginV, Effect, Textn");
  2288. f.WriteString(str);
  2289. }
  2290. }
  2291. CStringW fmt = 
  2292. et == EXTSRT ? L"%dn%02d:%02d:%02d,%03d --> %02d:%02d:%02d,%03dn%snn" :
  2293. et == EXTSUB ? L"{%d}{%d}%sn" :
  2294. et == EXTSMI ? L"<SYNC Start=%d><P Class=UNKNOWNCC>n%sn<SYNC Start=%d><P Class=UNKNOWNCC>&nbsp;n" :
  2295. et == EXTPSB ? L"{%d:%02d:%02d}{%d:%02d:%02d}%sn" :
  2296. et == EXTSSA ? L"Dialogue: Marked=0,%d:%02d:%02d.%02d,%d:%02d:%02d.%02d,%s,%s,%04d,%04d,%04d,%s,%sn" :
  2297. et == EXTASS ? L"Dialogue: %d,%d:%02d:%02d.%02d,%d:%02d:%02d.%02d,%s,%s,%04d,%04d,%04d,%s,%sn" :
  2298.    L"";
  2299. // Sort(true);
  2300. for(int i = 0, j = GetSize(), k = 0; i < j; i++)
  2301. {
  2302. STSEntry& stse = GetAt(i);
  2303. int t1 = TranslateStart(i, fps);
  2304. if(t1 < 0) {k++; continue;}
  2305. int t2 = TranslateEnd(i, fps);
  2306. int hh1 = (t1/60/60/1000);
  2307. int mm1 = (t1/60/1000)%60;
  2308. int ss1 = (t1/1000)%60;
  2309. int ms1 = (t1)%1000;
  2310. int hh2 = (t2/60/60/1000);
  2311. int mm2 = (t2/60/1000)%60;
  2312. int ss2 = (t2/1000)%60;
  2313. int ms2 = (t2)%1000;
  2314. CStringW str = f.IsUnicode()
  2315. ? GetStrW(i, et == EXTSSA || et == EXTASS)
  2316. : GetStrWA(i, et == EXTSSA || et == EXTASS);
  2317. CStringW str2;
  2318. if(et == EXTSRT)
  2319. {
  2320. str2.Format(fmt, i-k+1, hh1, mm1, ss1, ms1, hh2, mm2, ss2, ms2, str);
  2321. }
  2322. else if(et == EXTSUB)
  2323. {
  2324. str.Replace('n', '|');
  2325. str2.Format(fmt, int(t1*fps/1000), int(t2*fps/1000), str);
  2326. }
  2327. else if(et == EXTSMI)
  2328. {
  2329. str.Replace(L"n", L"<br>");
  2330. str2.Format(fmt, t1, str, t2);
  2331. }
  2332. else if(et == EXTPSB)
  2333. {
  2334. str.Replace('n', '|');
  2335. str2.Format(fmt, hh1, mm1, ss1, hh2, mm2, ss2, str);
  2336. }
  2337. else if(et == EXTSSA)
  2338. {
  2339. str.Replace(L"n", L"\N");
  2340. str2.Format(fmt, 
  2341. hh1, mm1, ss1, ms1/10,
  2342. hh2, mm2, ss2, ms2/10,
  2343. TToW(stse.style), TToW(stse.actor), 
  2344. stse.marginRect.left, stse.marginRect.right, (stse.marginRect.top + stse.marginRect.bottom) / 2,
  2345. TToW(stse.effect), str);
  2346. }
  2347. else if(et == EXTASS)
  2348. {
  2349. str.Replace(L"n", L"\N");
  2350. str2.Format(fmt, 
  2351. stse.layer, 
  2352. hh1, mm1, ss1, ms1/10,
  2353. hh2, mm2, ss2, ms2/10,
  2354. TToW(stse.style), TToW(stse.actor), 
  2355. stse.marginRect.left, stse.marginRect.right, (stse.marginRect.top + stse.marginRect.bottom) / 2,
  2356. TToW(stse.effect), str);
  2357. }
  2358. f.WriteString(str2);
  2359. }
  2360. // Sort();
  2361. if(et == EXTSMI)
  2362. {
  2363. f.WriteString(_T("</BODY>n</SAMI>n"));
  2364. }
  2365. void* val;
  2366. if(!m_fUsingAutoGeneratedDefaultStyle && m_styles.Lookup(_T("Default"), val) && et != EXTSSA && et != EXTASS)
  2367. {
  2368. STSStyle* s = (STSStyle*)val;
  2369. CTextFile f;
  2370. if(!f.Save(fn + _T(".style"), e))
  2371. return(false);
  2372. CString str, str2;
  2373. str += _T("ScriptType: v4.00+n");
  2374. str += _T("PlayResX: %dn");
  2375. str += _T("PlayResY: %dn");
  2376. str += _T("n");
  2377. 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, Encodingn");
  2378. str2.Format(str, m_dstScreenSize.cx, m_dstScreenSize.cy);
  2379. f.WriteString(str2);
  2380. 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,%dn");
  2381. str2.Format(str,
  2382. s->fontName, (int)s->fontSize,
  2383. (s->colors[0]&0xffffff) | (s->alpha[0]<<24),
  2384. (s->colors[1]&0xffffff) | (s->alpha[1]<<24),
  2385. (s->colors[2]&0xffffff) | (s->alpha[2]<<24),
  2386. (s->colors[3]&0xffffff) | (s->alpha[3]<<24),
  2387. s->fontWeight > FW_NORMAL ? -1 : 0, 
  2388. s->fItalic ? -1 : 0, s->fUnderline ? -1 : 0, s->fStrikeOut ? -1 : 0, 
  2389. (int)s->fontScaleX, (int)s->fontScaleY,
  2390. (int)s->fontSpacing, (float)s->fontAngleZ,
  2391. s->borderStyle == 0 ? 1 : s->borderStyle == 1 ? 3 : 0, 
  2392. (int)s->outlineWidth, (int)s->shadowDepth, 
  2393. s->scrAlignment,
  2394. s->marginRect.left, s->marginRect.right, (s->marginRect.top + s->marginRect.bottom) / 2,
  2395. s->charSet);
  2396. f.WriteString(str2);
  2397. }
  2398. return(true);
  2399. }
  2400. ////////////////////////////////////////////////////////////////////
  2401. STSStyle::STSStyle()
  2402. {
  2403. SetDefault();
  2404. }
  2405. void STSStyle::SetDefault()
  2406. {
  2407. marginRect = CRect(20, 20, 20, 20);
  2408. scrAlignment = 2;
  2409. borderStyle = 0;
  2410. outlineWidth = 2;
  2411. shadowDepth = 3;
  2412. colors[0] = 0x00ffffff;
  2413. colors[1] = 0x0000ffff;
  2414. colors[2] = 0x00000000;
  2415. colors[3] = 0x00000000;
  2416. alpha[0] = 0x00;
  2417. alpha[1] = 0x00;
  2418. alpha[2] = 0x00;
  2419. alpha[3] = 0x80;
  2420.     charSet = DEFAULT_CHARSET;
  2421. fontName = _T("Arial");
  2422. fontSize = 18;
  2423. fontScaleX = fontScaleY = 100;
  2424. fontSpacing = 0;
  2425. fontWeight = FW_BOLD;
  2426. fItalic = false;
  2427. fUnderline = false;
  2428. fStrikeOut = false;
  2429. fBlur = false;
  2430. fontAngleZ = fontAngleX = fontAngleY = 0;
  2431. relativeTo = 2;
  2432. }
  2433. bool STSStyle::operator == (STSStyle& s)
  2434. {
  2435. return(marginRect == s.marginRect 
  2436. && scrAlignment == s.scrAlignment
  2437. && borderStyle == s.borderStyle
  2438. && outlineWidth == s.outlineWidth
  2439. && shadowDepth == s.shadowDepth 
  2440. && *((int*)&colors[0]) == *((int*)&s.colors[0])
  2441. && *((int*)&colors[1]) == *((int*)&s.colors[1])
  2442. && *((int*)&colors[2]) == *((int*)&s.colors[2])
  2443. && *((int*)&colors[3]) == *((int*)&s.colors[3])
  2444. && alpha[0] == s.alpha[0]
  2445. && alpha[1] == s.alpha[1]
  2446. && alpha[2] == s.alpha[2]
  2447. && alpha[3] == s.alpha[3]
  2448. && fBlur == s.fBlur
  2449. && relativeTo == s.relativeTo
  2450. && IsFontStyleEqual(s));
  2451. }
  2452. bool STSStyle::IsFontStyleEqual(STSStyle& s)
  2453. {
  2454. return(
  2455. charSet == s.charSet
  2456. && fontName == s.fontName
  2457. && fontSize == s.fontSize
  2458. && fontScaleX == s.fontScaleX
  2459. && fontScaleY == s.fontScaleY
  2460. && fontSpacing == s.fontSpacing
  2461. && fontWeight == s.fontWeight
  2462. && fItalic == s.fItalic
  2463. && fUnderline == s.fUnderline
  2464. && fStrikeOut == s.fStrikeOut
  2465. && fontAngleZ == s.fontAngleZ
  2466. && fontAngleX == s.fontAngleX
  2467. && fontAngleY == s.fontAngleY);
  2468. }
  2469. void STSStyle::operator = (LOGFONT& lf)
  2470. {
  2471. charSet = lf.lfCharSet;
  2472. fontName = lf.lfFaceName;
  2473. HDC hDC = GetDC(0);
  2474. fontSize = -MulDiv(lf.lfHeight, 72, GetDeviceCaps(hDC, LOGPIXELSY));
  2475. ReleaseDC(0, hDC);
  2476. // fontAngleZ = (float)(1.0*lf.lfEscapement/10);
  2477. fontWeight = lf.lfWeight;
  2478. fItalic = !!lf.lfItalic;
  2479. fUnderline = !!lf.lfUnderline;
  2480. fStrikeOut = !!lf.lfStrikeOut;
  2481. }
  2482. LOGFONTA& operator <<= (LOGFONTA& lfa, STSStyle& s)
  2483. {
  2484. lfa.lfCharSet = s.charSet;
  2485. #ifdef UNICODE
  2486. wcstombs(lfa.lfFaceName, s.fontName, 32);
  2487. #else
  2488. strncpy(lfa.lfFaceName, s.fontName, 32);
  2489. #endif
  2490. HDC hDC = GetDC(0);
  2491. lfa.lfHeight = -MulDiv((int)(s.fontSize+0.5), GetDeviceCaps(hDC, LOGPIXELSY), 72);
  2492. ReleaseDC(0, hDC);
  2493. lfa.lfWeight = s.fontWeight;
  2494. lfa.lfItalic = s.fItalic?-1:0;
  2495. lfa.lfUnderline = s.fUnderline?-1:0;
  2496. lfa.lfStrikeOut = s.fStrikeOut?-1:0;
  2497. return(lfa);
  2498. }
  2499. LOGFONTW& operator <<= (LOGFONTW& lfw, STSStyle& s)
  2500. {
  2501. lfw.lfCharSet = s.charSet;
  2502. #ifdef UNICODE
  2503. wcsncpy(lfw.lfFaceName, s.fontName, 32);
  2504. #else
  2505. mbstowcs(lfw.lfFaceName, s.fontName, 32);
  2506. #endif
  2507. HDC hDC = GetDC(0);
  2508. lfw.lfHeight = -MulDiv((int)(s.fontSize+0.5), GetDeviceCaps(hDC, LOGPIXELSY), 72);
  2509. ReleaseDC(0, hDC);
  2510. lfw.lfWeight = s.fontWeight;
  2511. lfw.lfItalic = s.fItalic?-1:0;
  2512. lfw.lfUnderline = s.fUnderline?-1:0;
  2513. lfw.lfStrikeOut = s.fStrikeOut?-1:0;
  2514. return(lfw);
  2515. }
  2516. CString& operator <<= (CString& style, STSStyle& s)
  2517. {
  2518. 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"),
  2519. s.marginRect.left,s.marginRect.right,s.marginRect.top,s.marginRect.bottom,
  2520. s.scrAlignment, s.borderStyle, s.outlineWidth, s.shadowDepth,
  2521. s.colors[0], s.colors[1], s.colors[2], s.colors[3], s.alpha[0], s.alpha[1], s.alpha[2], s.alpha[3],
  2522. s.charSet,
  2523. s.fontName, s.fontSize, s.fontScaleX, s.fontScaleY, s.fontSpacing, s.fontWeight,
  2524. (int)s.fItalic, (int)s.fUnderline, (int)s.fStrikeOut, (int)s.fBlur,
  2525. s.fontAngleZ, s.fontAngleX, s.fontAngleY,
  2526. s.relativeTo);
  2527. return(style);
  2528. }
  2529. STSStyle& operator <<= (STSStyle& s, CString& style)
  2530. {
  2531. s.SetDefault();
  2532. try 
  2533. {
  2534. CStringW str = TToW(style);
  2535. s.marginRect.left = GetInt(str); s.marginRect.right = GetInt(str); s.marginRect.top = GetInt(str); s.marginRect.bottom = GetInt(str);
  2536. s.scrAlignment = GetInt(str); s.borderStyle = GetInt(str); s.outlineWidth = GetFloat(str); s.shadowDepth = GetFloat(str);
  2537. for(int i = 0; i < 4; i++) s.colors[i] = (COLORREF)GetInt(str);
  2538. for(int i = 0; i < 4; i++) s.alpha[i] = GetInt(str);
  2539. s.charSet = GetInt(str);
  2540. s.fontName = WToT(GetStr(str)); s.fontSize = GetFloat(str); 
  2541. s.fontScaleX = GetFloat(str); s.fontScaleY = GetFloat(str);
  2542. s.fontSpacing = GetFloat(str); s.fontWeight = GetInt(str);
  2543. s.fItalic = !!GetInt(str); s.fUnderline = !!GetInt(str); s.fStrikeOut = !!GetInt(str); s.fBlur = !!GetInt(str);
  2544. s.fontAngleZ = GetFloat(str); s.fontAngleX = GetFloat(str); s.fontAngleY = GetFloat(str);
  2545. s.relativeTo = GetInt(str);
  2546. }
  2547. catch(...)
  2548. {
  2549. s.SetDefault();
  2550. }
  2551. return(s);
  2552. }