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

多媒体编程

开发平台:

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 "usfsubtitles.h"
  23. #define DeclareNameAndValue(pNode, name, val) 
  24.     CComBSTR name; 
  25.     pNode->get_nodeName(&name); 
  26. name.ToLower(); 
  27. CComVariant val; 
  28.     pNode->get_nodeValue(&val); 
  29. #define BeginEnumAttribs(pNode, pChild, name, value) 
  30. {CComPtr<IXMLDOMNamedNodeMap> pAttribs; 
  31. if(SUCCEEDED(pNode->get_attributes(&pAttribs)) && pAttribs != NULL) 
  32.     { 
  33. CComPtr<IXMLDOMNode> pChild; 
  34.         for(pAttribs->nextNode(&pChild); pChild; pChild = NULL, pAttribs->nextNode(&pChild)) 
  35.         { 
  36. #define EndEnumAttribs }}}
  37. #define BeginEnumChildren(pNode, pChild) 
  38. {CComPtr<IXMLDOMNode> pChild, pNext; 
  39. for(pNode->get_firstChild(&pChild); pChild; pNext = NULL, pChild->get_nextSibling(&pNext), pChild = pNext) 
  40.     { 
  41. #define EndEnumChildren }}
  42. static CStringW GetText(CComPtr<IXMLDOMNode> pNode)
  43. {
  44. CComBSTR bstr;
  45. pNode->get_text(&bstr);
  46. return(CStringW(bstr));
  47. }
  48. static CStringW GetXML(CComPtr<IXMLDOMNode> pNode)
  49. {
  50. CComBSTR bstr;
  51. pNode->get_xml(&bstr);
  52. CStringW str(bstr);
  53. str.Remove('r');
  54. str.Replace('n', ' ');
  55. for(int i = 0; (i = str.Find(L" ", i)) >= 0; )
  56. {
  57. for(++i; i < str.GetLength() && (str[i] == 'n' || str[i] == ' ');)
  58. str.Delete(i);
  59. }
  60. return(str);
  61. }
  62. static CStringW GetAttrib(CStringW attrib, CComPtr<IXMLDOMNode> pNode)
  63. {
  64. CStringW ret;
  65. BeginEnumAttribs(pNode, pChild, name, val)
  66. {
  67. DeclareNameAndValue(pChild, name, val);
  68. if(CStringW(name) == attrib && val.vt == VT_BSTR) // TODO: prepare for other types
  69. {
  70. ret = val.bstrVal;
  71. break;
  72. }
  73. }
  74. EndEnumAttribs
  75. return(ret);
  76. }
  77. static int TimeToInt(CStringW str)
  78. {
  79. CList<CStringW> sl;
  80. int i = 0;
  81. for(CStringW token = str.Tokenize(L":.,", i); !token.IsEmpty(); token = str.Tokenize(L":.,", i))
  82. sl.AddHead(token);
  83. if(sl.GetCount() > 4)
  84. return(-1);
  85. int time = 0;
  86. int mul[4] = {1,1000,60*1000,60*60*1000};
  87. POSITION pos = sl.GetHeadPosition();
  88. for(i = 0; pos; i++)
  89. {
  90. const WCHAR* s = sl.GetNext(pos);
  91. WCHAR* tmp = NULL;
  92. int t = wcstol(s, &tmp, 10);
  93. if(s >= tmp) return(-1);
  94. time += t * mul[i];
  95. }
  96. return(time);
  97. }
  98. static DWORD StringToDWORD(CStringW str)
  99. {
  100. if(str.IsEmpty()) return(0);
  101. if(str[0] == '#') return((DWORD)wcstol(str, NULL, 16));
  102. else return((DWORD)wcstol(str, NULL, 10));
  103. }
  104. static DWORD ColorToDWORD(CStringW str)
  105. {
  106. if(str.IsEmpty()) return(0);
  107. DWORD ret = 0;
  108. if(str[0] == '#')
  109. {
  110. ret = (DWORD)wcstol(str.TrimLeft('#'), NULL, 16);
  111. }
  112. else
  113. {
  114. void* color = NULL;
  115. g_colors.Lookup(CString(str), color);
  116. ret = (DWORD)color;
  117. }
  118. ret = ((ret&0xff)<<16)|(ret&0xff00ff00)|((ret>>16)&0xff);
  119. return(ret);
  120. }
  121. static int TranslateAlignment(CStringW alignment)
  122. {
  123. return
  124. !alignment.CompareNoCase(L"BottomLeft") ? 1 :
  125. !alignment.CompareNoCase(L"BottomCenter") ? 2 :
  126. !alignment.CompareNoCase(L"BottomRight") ? 3 :
  127. !alignment.CompareNoCase(L"MiddleLeft") ? 4 :
  128. !alignment.CompareNoCase(L"MiddleCenter") ? 5 :
  129. !alignment.CompareNoCase(L"MiddleRight") ? 6 :
  130. !alignment.CompareNoCase(L"TopLeft") ? 7 :
  131. !alignment.CompareNoCase(L"TopCenter") ? 8 :
  132. !alignment.CompareNoCase(L"TopRight") ? 9 :
  133. 2;
  134. }
  135. static int TranslateMargin(CStringW margin, int wndsize)
  136. {
  137. int ret = 0;
  138. if(!margin.IsEmpty())
  139. {
  140. ret = wcstol(margin, NULL, 10);
  141. if(margin.Find('%') >= 0) ret = wndsize * ret / 100;
  142. }
  143. return(ret);
  144. }
  145. ////////////////
  146. CUSFSubtitles::CUSFSubtitles()
  147. {
  148. }
  149. CUSFSubtitles::~CUSFSubtitles()
  150. {
  151. }
  152. bool CUSFSubtitles::Read(LPCTSTR fn)
  153. {
  154. VARIANT_BOOL vb;
  155. CComPtr<IXMLDOMDocument> pDoc;
  156. if(FAILED(pDoc.CoCreateInstance(CLSID_DOMDocument))
  157. || FAILED(pDoc->put_async(VARIANT_FALSE))
  158. || FAILED(pDoc->load(CComVariant(fn), &vb)) || vb != VARIANT_TRUE)
  159. return(false);
  160. styles.RemoveAll();
  161. effects.RemoveAll();
  162. texts.RemoveAll();
  163. if(!ParseUSFSubtitles(CComQIPtr<IXMLDOMNode>(pDoc)))
  164. return(false);
  165. POSITION pos = styles.GetHeadPosition();
  166. while(pos)
  167. {
  168. style_t* def = styles.GetNext(pos);
  169. if(def->name.CompareNoCase(L"Default"))
  170. continue;
  171. POSITION pos2 = styles.GetHeadPosition();
  172. while(pos2)
  173. {
  174. style_t* s = styles.GetNext(pos2);
  175. if(!s->name.CompareNoCase(L"Default"))
  176. continue;
  177. if(s->fontstyle.face.IsEmpty()) s->fontstyle.face = def->fontstyle.face;
  178. if(s->fontstyle.size.IsEmpty()) s->fontstyle.size = def->fontstyle.size;
  179. if(s->fontstyle.color[0].IsEmpty()) s->fontstyle.color[0] = def->fontstyle.color[0];
  180. if(s->fontstyle.color[1].IsEmpty()) s->fontstyle.color[1] = def->fontstyle.color[1];
  181. if(s->fontstyle.color[2].IsEmpty()) s->fontstyle.color[2] = def->fontstyle.color[2];
  182. if(s->fontstyle.color[3].IsEmpty()) s->fontstyle.color[3] = def->fontstyle.color[3];
  183. if(s->fontstyle.italic.IsEmpty()) s->fontstyle.italic = def->fontstyle.italic;
  184. if(s->fontstyle.weight.IsEmpty()) s->fontstyle.weight = def->fontstyle.weight;
  185. if(s->fontstyle.underline.IsEmpty()) s->fontstyle.underline = def->fontstyle.underline;
  186. if(s->fontstyle.alpha.IsEmpty()) s->fontstyle.alpha = def->fontstyle.alpha;
  187. if(s->fontstyle.outline.IsEmpty()) s->fontstyle.outline = def->fontstyle.outline;
  188. if(s->fontstyle.shadow.IsEmpty()) s->fontstyle.shadow = def->fontstyle.shadow;
  189. if(s->fontstyle.wrap.IsEmpty()) s->fontstyle.wrap = def->fontstyle.wrap;
  190. if(s->pal.alignment.IsEmpty()) s->pal.alignment = def->pal.alignment;
  191. if(s->pal.relativeto.IsEmpty()) s->pal.relativeto = def->pal.relativeto;
  192. if(s->pal.horizontal_margin.IsEmpty()) s->pal.horizontal_margin = def->pal.horizontal_margin;
  193. if(s->pal.vertical_margin.IsEmpty()) s->pal.vertical_margin = def->pal.vertical_margin;
  194. if(s->pal.rotate[0].IsEmpty()) s->pal.rotate[0] = def->pal.rotate[0];
  195. if(s->pal.rotate[1].IsEmpty()) s->pal.rotate[1] = def->pal.rotate[1];
  196. if(s->pal.rotate[2].IsEmpty()) s->pal.rotate[2] = def->pal.rotate[2];
  197. }
  198. break;
  199. }
  200. pos = texts.GetHeadPosition();
  201. while(pos)
  202. {
  203. text_t* t = texts.GetNext(pos);
  204. if(t->style.IsEmpty()) t->style = L"Default";
  205. }
  206. return(true);
  207. }
  208. bool CUSFSubtitles::ConvertToSTS(CSimpleTextSubtitle& sts)
  209. {
  210. sts.m_name = metadata.language.text;
  211. sts.m_encoding = CTextFile::UTF8;
  212. sts.m_dstScreenSize = CSize(640, 480);
  213. sts.m_fScaledBAS = true;
  214. sts.m_defaultWrapStyle = 1;
  215. // TODO: map metadata.language.code to charset num (windows doesn't have such a function...)
  216. int charSet = DEFAULT_CHARSET; 
  217. POSITION pos = styles.GetHeadPosition();
  218. while(pos)
  219. {
  220. style_t* s = styles.GetNext(pos);
  221. if(!s->name.CompareNoCase(L"Default") && !s->fontstyle.wrap.IsEmpty())
  222. {
  223. sts.m_defaultWrapStyle = 
  224. !s->fontstyle.wrap.CompareNoCase(L"no") ? 2 :
  225. !s->fontstyle.wrap.CompareNoCase(L"auto") ? 1 :
  226. 1;
  227. }
  228. STSStyle* stss = new STSStyle;
  229. if(!stss) continue;
  230. if(!s->pal.horizontal_margin.IsEmpty())
  231. stss->marginRect.left = stss->marginRect.right = TranslateMargin(s->pal.horizontal_margin, sts.m_dstScreenSize.cx);
  232. if(!s->pal.vertical_margin.IsEmpty())
  233. stss->marginRect.top = stss->marginRect.bottom = TranslateMargin(s->pal.vertical_margin, sts.m_dstScreenSize.cy);
  234. stss->scrAlignment = TranslateAlignment(s->pal.alignment);
  235. if(!s->pal.relativeto.IsEmpty()) stss->relativeTo = 
  236. !s->pal.relativeto.CompareNoCase(L"window") ? 0 :
  237. !s->pal.relativeto.CompareNoCase(L"video") ? 1 :
  238. 0;
  239. stss->borderStyle = 0;
  240. if(!s->fontstyle.outline.IsEmpty()) stss->outlineWidth = wcstol(s->fontstyle.outline, NULL, 10);
  241. if(!s->fontstyle.shadow.IsEmpty()) stss->shadowDepth = wcstol(s->fontstyle.shadow, NULL, 10);
  242. for(int i = 0; i < 4; i++)
  243. {
  244. DWORD color = ColorToDWORD(s->fontstyle.color[i]);
  245. int alpha = (BYTE)wcstol(s->fontstyle.alpha, NULL, 10);
  246. stss->colors[i] = color & 0xffffff;
  247. stss->alpha[i] = (BYTE)(color>>24);
  248. stss->alpha[i] = stss->alpha[i] + (255 - stss->alpha[i]) * min(max(alpha, 0), 100) / 100;
  249. }
  250. if(!s->fontstyle.face.IsEmpty()) stss->fontName = s->fontstyle.face;
  251. if(!s->fontstyle.size.IsEmpty()) stss->fontSize = wcstol(s->fontstyle.size, NULL, 10);
  252. if(!s->fontstyle.weight.IsEmpty()) stss->fontWeight = 
  253. !s->fontstyle.weight.CompareNoCase(L"normal") ? FW_NORMAL :
  254. !s->fontstyle.weight.CompareNoCase(L"bold") ? FW_BOLD :
  255. !s->fontstyle.weight.CompareNoCase(L"lighter") ? FW_LIGHT :
  256. !s->fontstyle.weight.CompareNoCase(L"bolder") ? FW_SEMIBOLD :
  257. wcstol(s->fontstyle.weight, NULL, 10);
  258. if(stss->fontWeight == 0) stss->fontWeight = FW_NORMAL;
  259. if(!s->fontstyle.italic.IsEmpty()) stss->fItalic = s->fontstyle.italic.CompareNoCase(L"yes") == 0;
  260. if(!s->fontstyle.underline.IsEmpty()) stss->fUnderline = s->fontstyle.underline.CompareNoCase(L"yes") == 0;
  261. if(!s->pal.rotate[0].IsEmpty()) stss->fontAngleZ = wcstol(s->pal.rotate[0], NULL, 10);
  262. if(!s->pal.rotate[1].IsEmpty()) stss->fontAngleX = wcstol(s->pal.rotate[1], NULL, 10);
  263. if(!s->pal.rotate[2].IsEmpty()) stss->fontAngleY = wcstol(s->pal.rotate[2], NULL, 10);
  264. stss->charSet = charSet;
  265. sts.AddStyle(WToT(s->name), stss);
  266. }
  267. pos = texts.GetHeadPosition();
  268. while(pos)
  269. {
  270. text_t* t = texts.GetNext(pos);
  271. if(!t->pal.alignment.IsEmpty())
  272. {
  273. CStringW s;
  274. s.Format(L"{\an%d}", TranslateAlignment(t->pal.alignment));
  275. t->str = s + t->str;
  276. }
  277. CRect marginRect;
  278. marginRect.SetRectEmpty();
  279. if(!t->pal.horizontal_margin.IsEmpty())
  280. marginRect.left = marginRect.right = TranslateMargin(t->pal.horizontal_margin, sts.m_dstScreenSize.cx);
  281. if(!t->pal.vertical_margin.IsEmpty())
  282. marginRect.top = marginRect.bottom = TranslateMargin(t->pal.vertical_margin, sts.m_dstScreenSize.cy);
  283. WCHAR rtags[3][8] = {L"{\rz%d}", L"{\rx%d}", L"{\ry%d}"};
  284. for(int i = 0; i < 3; i++)
  285. {
  286. if(int angle = wcstol(t->pal.rotate[i], NULL, 10))
  287. {
  288. CStringW str;
  289. str.Format(rtags[i], angle);
  290. t->str = str + t->str;
  291. }
  292. }
  293. if(t->style.CompareNoCase(L"Default") != 0)
  294. {
  295. POSITION pos = styles.GetHeadPosition();
  296. while(pos)
  297. {
  298. style_t* s = styles.GetNext(pos);
  299. if(s->name == t->style && !s->fontstyle.wrap.IsEmpty())
  300. {
  301. int WrapStyle = 
  302. !s->fontstyle.wrap.CompareNoCase(L"no") ? 2 :
  303. !s->fontstyle.wrap.CompareNoCase(L"auto") ? 1 :
  304. 1;
  305. if(WrapStyle != sts.m_defaultWrapStyle)
  306. {
  307. CStringW str;
  308.                         str.Format(L"{\q%d}", WrapStyle);
  309. t->str = str + t->str;
  310. }
  311. break;
  312. }
  313. }
  314. }
  315. // TODO: apply effects as {t(..)} after usf's standard clearly defines them
  316. sts.Add(t->str, true, t->start, t->stop, WToT(t->style), _T(""), _T(""), marginRect);
  317. }
  318. return(true);
  319. }
  320. bool CUSFSubtitles::ParseUSFSubtitles(CComPtr<IXMLDOMNode> pNode)
  321. {
  322. DeclareNameAndValue(pNode, name, val);
  323. if(name == L"usfsubtitles")
  324. {
  325. // metadata
  326. BeginEnumChildren(pNode, pChild)
  327. {
  328. DeclareNameAndValue(pChild, name, val);
  329. if(name == L"metadata")
  330. {
  331. ParseMetadata(pChild, metadata);
  332. }
  333. }
  334. EndEnumChildren
  335. // styles
  336. BeginEnumChildren(pNode, pChild)
  337. {
  338. DeclareNameAndValue(pChild, name, val);
  339. if(name == L"styles")
  340. {
  341. BeginEnumChildren(pChild, pGrandChild) // :)
  342. {
  343. DeclareNameAndValue(pGrandChild, name, val);
  344. if(name == L"style")
  345. {
  346. CAutoPtr<style_t> s(new style_t);
  347. if(s)
  348. {
  349. ParseStyle(pGrandChild, s);
  350. styles.AddTail(s);
  351. }
  352. }
  353. }
  354. EndEnumChildren
  355. }
  356. }
  357. EndEnumChildren
  358. // effects
  359. BeginEnumChildren(pNode, pChild)
  360. {
  361. DeclareNameAndValue(pChild, name, val);
  362. if(name == L"effects")
  363. {
  364. BeginEnumChildren(pChild, pGrandChild) // :)
  365. {
  366. DeclareNameAndValue(pGrandChild, name, val);
  367. if(name == L"effect")
  368. {
  369. CAutoPtr<effect_t> e(new effect_t);
  370. if(e)
  371. {
  372. ParseEffect(pGrandChild, e);
  373. effects.AddTail(e);
  374. }
  375. }
  376. }
  377. EndEnumChildren
  378. }
  379. }
  380. EndEnumChildren
  381. // subtitles
  382. BeginEnumChildren(pNode, pChild)
  383. {
  384. DeclareNameAndValue(pChild, name, val);
  385. if(name == L"subtitles")
  386. {
  387. BeginEnumChildren(pChild, pGrandChild) // :)
  388. {
  389. DeclareNameAndValue(pGrandChild, name, val);
  390. if(name == L"subtitle")
  391. {
  392. CStringW sstart = GetAttrib(L"start", pGrandChild);
  393. CStringW sstop = GetAttrib(L"stop", pGrandChild);
  394. CStringW sduration = GetAttrib(L"duration", pGrandChild);
  395. if(sstart.IsEmpty() || (sstop.IsEmpty() && sduration.IsEmpty()))
  396. continue;
  397. int start = TimeToInt(sstart);
  398. int stop = !sstop.IsEmpty() ? TimeToInt(sstop) : (start + TimeToInt(sduration));
  399. ParseSubtitle(pGrandChild, start, stop);
  400. }
  401. }
  402. EndEnumChildren
  403. }
  404. }
  405. EndEnumChildren
  406. return(true);
  407. }
  408. BeginEnumChildren(pNode, pChild)
  409. {
  410.         if(ParseUSFSubtitles(pChild))
  411. {
  412. return(true);
  413. }
  414. }
  415. EndEnumChildren
  416. return(false);
  417. }
  418. void CUSFSubtitles::ParseMetadata(CComPtr<IXMLDOMNode> pNode, metadata_t& m)
  419. {
  420. DeclareNameAndValue(pNode, name, val);
  421. if(name == L"title")
  422. {
  423. m.title = GetText(pNode);
  424. }
  425. else if(name == L"date")
  426. {
  427. m.date = GetText(pNode);
  428. }
  429. else if(name == L"comment")
  430. {
  431. m.comment = GetText(pNode);
  432. }
  433. else if(name == L"author")
  434. {
  435. BeginEnumChildren(pNode, pChild)
  436. {
  437. DeclareNameAndValue(pChild, name, val);
  438. if(name == L"name")
  439. m.author.name = GetText(pChild);
  440. else if(name == L"email")
  441. m.author.email = GetText(pChild);
  442. else if(name == L"url")
  443. m.author.url = GetText(pChild);
  444. }
  445. EndEnumChildren
  446. return;
  447. }
  448. else if(name == L"language")
  449. {
  450. m.language.text = GetText(pNode);
  451. m.language.code = GetAttrib(L"code", pNode);
  452. }
  453. else if(name == L"languageext")
  454. {
  455. m.languageext.text = GetText(pNode);
  456. m.languageext.code = GetAttrib(L"code", pNode);
  457. }
  458. BeginEnumChildren(pNode, pChild)
  459. {
  460. ParseMetadata(pChild, metadata);
  461. }
  462. EndEnumChildren
  463. }
  464. void CUSFSubtitles::ParseStyle(CComPtr<IXMLDOMNode> pNode, style_t* s)
  465. {
  466. DeclareNameAndValue(pNode, name, val);
  467. if(name == L"style")
  468. {
  469. s->name = GetAttrib(L"name", pNode);
  470. }
  471. else if(name == L"fontstyle")
  472. {
  473. ParseFontstyle(pNode, s->fontstyle);
  474. return;
  475. }
  476. else if(name == L"position")
  477. {
  478. ParsePal(pNode, s->pal);
  479. return;
  480. }
  481. BeginEnumChildren(pNode, pChild)
  482. {
  483. ParseStyle(pChild, s);
  484. }
  485. EndEnumChildren
  486. }
  487. void CUSFSubtitles::ParseFontstyle(CComPtr<IXMLDOMNode> pNode, fontstyle_t& fs)
  488. {
  489. fs.face = GetAttrib(L"face", pNode);
  490. fs.size = GetAttrib(L"size", pNode);
  491. fs.color[0] = GetAttrib(L"color", pNode);
  492. fs.color[1] = GetAttrib(L"back-color", pNode);
  493. fs.color[2] = GetAttrib(L"outline-color", pNode);
  494. fs.color[3] = GetAttrib(L"shadow-color", pNode);
  495. fs.italic = GetAttrib(L"italic", pNode);
  496. fs.weight = GetAttrib(L"weight", pNode);
  497. fs.underline = GetAttrib(L"underline", pNode);
  498. fs.alpha = GetAttrib(L"alpha", pNode);
  499. fs.outline = GetAttrib(L"outline-level", pNode);
  500. fs.shadow = GetAttrib(L"shadow-level", pNode);
  501. fs.wrap = GetAttrib(L"wrap", pNode);
  502. }
  503. void CUSFSubtitles::ParsePal(CComPtr<IXMLDOMNode> pNode, posattriblist_t& pal)
  504. {
  505. pal.alignment = GetAttrib(L"alignment", pNode);
  506. pal.relativeto = GetAttrib(L"relative-to", pNode);
  507. pal.horizontal_margin = GetAttrib(L"horizontal-margin", pNode);
  508. pal.vertical_margin = GetAttrib(L"vertical-margin", pNode);
  509. pal.rotate[0] = GetAttrib(L"rotate-z", pNode);
  510. pal.rotate[1] = GetAttrib(L"rotate-x", pNode);
  511. pal.rotate[2] = GetAttrib(L"rotate-y", pNode);
  512. }
  513. void CUSFSubtitles::ParseEffect(CComPtr<IXMLDOMNode> pNode, effect_t* e)
  514. {
  515. DeclareNameAndValue(pNode, name, val);
  516. if(name == L"effect")
  517. {
  518. e->name = GetAttrib(L"name", pNode);
  519. }
  520. else if(name == L"keyframes")
  521. {
  522. BeginEnumChildren(pNode, pChild)
  523. {
  524. DeclareNameAndValue(pChild, name, val);
  525. if(name == L"keyframe")
  526. {
  527. CAutoPtr<keyframe_t> k(new keyframe_t);
  528. if(k)
  529. {
  530. ParseKeyframe(pChild, k);
  531. e->keyframes.AddTail(k);
  532. }
  533. }
  534. }
  535. EndEnumChildren
  536. return;
  537. }
  538. BeginEnumChildren(pNode, pChild)
  539. {
  540. ParseEffect(pChild, e);
  541. }
  542. EndEnumChildren
  543. }
  544. void CUSFSubtitles::ParseKeyframe(CComPtr<IXMLDOMNode> pNode, keyframe_t* k)
  545. {
  546. DeclareNameAndValue(pNode, name, val);
  547. if(name == L"keyframe")
  548. {
  549. k->position = GetAttrib(L"position", pNode);
  550. }
  551. else if(name == L"fontstyle")
  552. {
  553. ParseFontstyle(pNode, k->fontstyle);
  554. return;
  555. }
  556. else if(name == L"position")
  557. {
  558. ParsePal(pNode, k->pal);
  559. return;
  560. }
  561. }
  562. void CUSFSubtitles::ParseSubtitle(CComPtr<IXMLDOMNode> pNode, int start, int stop)
  563. {
  564. DeclareNameAndValue(pNode, name, val);
  565. if(name == L"text" || name == L"karaoke")
  566. {
  567. CAutoPtr<text_t> t(new text_t);
  568. if(t)
  569. {
  570. t->start = start;
  571. t->stop = stop;
  572. t->style = GetAttrib(L"style", pNode);
  573. t->effect = GetAttrib(L"effect", pNode);
  574. ParsePal(pNode, t->pal);
  575. ParseText(pNode, t->str);
  576. texts.AddTail(t);
  577. }
  578. return;
  579. }
  580. // else if
  581. BeginEnumChildren(pNode, pChild)
  582. {
  583. ParseSubtitle(pChild, start, stop);
  584. }
  585. EndEnumChildren
  586. }
  587. void CUSFSubtitles::ParseText(CComPtr<IXMLDOMNode> pNode, CStringW& str)
  588. {
  589. DeclareNameAndValue(pNode, name, val);
  590. CStringW prefix, postfix;
  591. if(name == L"b")
  592. {
  593. prefix = L"{\b1}";
  594. postfix = L"{\b}";
  595. }
  596. else if(name == L"i")
  597. {
  598. prefix = L"{\i1}";
  599. postfix = L"{\i}";
  600. }
  601. else if(name == L"u")
  602. {
  603. prefix = L"{\u1}";
  604. postfix = L"{\u}";
  605. }
  606. else if(name == L"font")
  607. {
  608. fontstyle_t fs;
  609. ParseFontstyle(pNode, fs);
  610. if(!fs.face.IsEmpty()) {prefix += L"{\fn" + fs.face + L"}"; postfix += L"{\fn}";}
  611. if(!fs.size.IsEmpty()) {prefix += L"{\fs" + fs.size + L"}"; postfix += L"{\fs}";}
  612. if(!fs.outline.IsEmpty()) {prefix += L"{\bord" + fs.outline + L"}"; postfix += L"{\bord}";}
  613. if(!fs.shadow.IsEmpty()) {prefix += L"{\shad" + fs.shadow + L"}"; postfix += L"{\shad}";}
  614. for(int i = 0; i < 4; i++)
  615. {
  616. if(!fs.color[i].IsEmpty())
  617. {
  618. CStringW s;
  619. s.Format(L"{\%dc&H%06x&}", i+1, ColorToDWORD(fs.color[i]));
  620. prefix += s;
  621. s.Format(L"{\%dc}", i+1);
  622. postfix += s;
  623. }
  624. }
  625. }
  626. else if(name == L"k")
  627. {
  628. int t = wcstol(GetAttrib(L"t", pNode), NULL, 10);
  629. CStringW s;
  630. s.Format(L"{\kf%d}", t / 10);
  631. str += s;
  632. return;
  633. }
  634. else if(name == L"br")
  635. {
  636. str += L"\N";
  637. return;
  638. }
  639. else if(name == L"#text")
  640. {
  641. str += GetXML(pNode);
  642. return;
  643. }
  644. BeginEnumChildren(pNode, pChild)
  645. {
  646. CStringW s;
  647. ParseText(pChild, s);
  648. str += s;
  649. }
  650. EndEnumChildren
  651. str = prefix + str + postfix;
  652. }
  653. void CUSFSubtitles::ParseShape(CComPtr<IXMLDOMNode> pNode)
  654. {
  655. // no specs on this yet
  656. }