USFSubtitles.cpp

00001 /* 
00002  *      Copyright (C) 2003-2005 Gabest
00003  *      http://www.gabest.org
00004  *
00005  *  This Program is free software; you can redistribute it and/or modify
00006  *  it under the terms of the GNU General Public License as published by
00007  *  the Free Software Foundation; either version 2, or (at your option)
00008  *  any later version.
00009  *   
00010  *  This Program is distributed in the hope that it will be useful,
00011  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00012  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
00013  *  GNU General Public License for more details.
00014  *   
00015  *  You should have received a copy of the GNU General Public License
00016  *  along with GNU Make; see the file COPYING.  If not, write to
00017  *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. 
00018  *  http://www.gnu.org/copyleft/gpl.html
00019  *
00020  */
00021 
00022 #include "StdAfx.h"
00023 #include "usfsubtitles.h"
00024 
00025 #define DeclareNameAndValue(pNode, name, val) \
00026     CComBSTR name; \
00027     pNode->get_nodeName(&name); \
00028         name.ToLower(); \
00029         CComVariant val; \
00030     pNode->get_nodeValue(&val); \
00031 
00032 #define BeginEnumAttribs(pNode, pChild, name, value) \
00033         {CComPtr<IXMLDOMNamedNodeMap> pAttribs; \
00034         if(SUCCEEDED(pNode->get_attributes(&pAttribs)) && pAttribs != NULL) \
00035     { \
00036                 CComPtr<IXMLDOMNode> pChild; \
00037         for(pAttribs->nextNode(&pChild); pChild; pChild = NULL, pAttribs->nextNode(&pChild)) \
00038         { \
00039 
00040 #define EndEnumAttribs }}}
00041 
00042 #define BeginEnumChildren(pNode, pChild) \
00043         {CComPtr<IXMLDOMNode> pChild, pNext; \
00044         for(pNode->get_firstChild(&pChild); pChild; pNext = NULL, pChild->get_nextSibling(&pNext), pChild = pNext) \
00045     { \
00046 
00047 #define EndEnumChildren }}
00048 
00049 static CStringW GetText(CComPtr<IXMLDOMNode> pNode)
00050 {
00051         CComBSTR bstr;
00052         pNode->get_text(&bstr);
00053 
00054         return(CStringW(bstr));
00055 }
00056 
00057 static CStringW GetXML(CComPtr<IXMLDOMNode> pNode)
00058 {
00059         CComBSTR bstr;
00060         pNode->get_xml(&bstr);
00061         CStringW str(bstr);
00062         str.Remove('\r');
00063         str.Replace('\n', ' ');
00064         for(int i = 0; (i = str.Find(L" ", i)) >= 0; )
00065         {
00066                 for(++i; i < str.GetLength() && (str[i] == '\n' || str[i] == ' ');)
00067                         str.Delete(i);
00068         }
00069         return(str);
00070 }
00071 
00072 static CStringW GetAttrib(CStringW attrib, CComPtr<IXMLDOMNode> pNode)
00073 {
00074         CStringW ret;
00075 
00076         BeginEnumAttribs(pNode, pChild, name, val)
00077         {
00078                 DeclareNameAndValue(pChild, name, val);
00079 
00080                 if(CStringW(name) == attrib && val.vt == VT_BSTR) // TODO: prepare for other types
00081                 {
00082                         ret = val.bstrVal;
00083                         break;
00084                 }
00085         }
00086         EndEnumAttribs
00087 
00088         return(ret);
00089 }
00090 
00091 static int TimeToInt(CStringW str)
00092 {
00093         CList<CStringW> sl;
00094         int i = 0;
00095         for(CStringW token = str.Tokenize(L":.,", i); !token.IsEmpty(); token = str.Tokenize(L":.,", i))
00096                 sl.AddHead(token);
00097 
00098         if(sl.GetCount() > 4)
00099                 return(-1);
00100 
00101         int time = 0;
00102         
00103         int mul[4] = {1,1000,60*1000,60*60*1000};
00104         POSITION pos = sl.GetHeadPosition();
00105         for(i = 0; pos; i++)
00106         {
00107                 const WCHAR* s = sl.GetNext(pos);
00108                 WCHAR* tmp = NULL;
00109                 int t = wcstol(s, &tmp, 10);
00110                 if(s >= tmp) return(-1);
00111                 time += t * mul[i];
00112         }
00113 
00114         return(time);
00115 }
00116 
00117 static DWORD StringToDWORD(CStringW str)
00118 {
00119         if(str.IsEmpty()) return(0);
00120         if(str[0] == '#') return((DWORD)wcstol(str, NULL, 16));
00121         else return((DWORD)wcstol(str, NULL, 10));      
00122 }
00123 
00124 static DWORD ColorToDWORD(CStringW str)
00125 {
00126         if(str.IsEmpty()) return(0);
00127 
00128         DWORD ret = 0;
00129 
00130         if(str[0] == '#')
00131         {
00132                 ret = (DWORD)wcstol(str.TrimLeft('#'), NULL, 16);
00133         }
00134         else
00135         {
00136                 void* color = NULL;
00137                 g_colors.Lookup(CString(str), color);
00138                 ret = (DWORD)color;
00139         }
00140 
00141         ret = ((ret&0xff)<<16)|(ret&0xff00ff00)|((ret>>16)&0xff);
00142 
00143         return(ret);
00144 }
00145 
00146 static int TranslateAlignment(CStringW alignment)
00147 {
00148         return
00149                 !alignment.CompareNoCase(L"BottomLeft") ? 1 :
00150                 !alignment.CompareNoCase(L"BottomCenter") ? 2 :
00151                 !alignment.CompareNoCase(L"BottomRight") ? 3 :
00152                 !alignment.CompareNoCase(L"MiddleLeft") ? 4 :
00153                 !alignment.CompareNoCase(L"MiddleCenter") ? 5 :
00154                 !alignment.CompareNoCase(L"MiddleRight") ? 6 :
00155                 !alignment.CompareNoCase(L"TopLeft") ? 7 :
00156                 !alignment.CompareNoCase(L"TopCenter") ? 8 :
00157                 !alignment.CompareNoCase(L"TopRight") ? 9 :
00158                 2;
00159 }
00160 
00161 static int TranslateMargin(CStringW margin, int wndsize)
00162 {
00163         int ret = 0;
00164 
00165         if(!margin.IsEmpty())
00166         {
00167                 ret = wcstol(margin, NULL, 10);
00168                 if(margin.Find('%') >= 0) ret = wndsize * ret / 100;
00169         }
00170 
00171         return(ret);
00172 }
00173 
00175 
00176 CUSFSubtitles::CUSFSubtitles()
00177 {
00178 }
00179 
00180 CUSFSubtitles::~CUSFSubtitles()
00181 {
00182 }
00183 
00184 bool CUSFSubtitles::Read(LPCTSTR fn)
00185 {
00186         VARIANT_BOOL vb;
00187         CComPtr<IXMLDOMDocument> pDoc;
00188         if(FAILED(pDoc.CoCreateInstance(CLSID_DOMDocument))
00189         || FAILED(pDoc->put_async(VARIANT_FALSE))
00190         || FAILED(pDoc->load(CComVariant(fn), &vb)) || vb != VARIANT_TRUE)
00191                 return(false);
00192 
00193         styles.RemoveAll();
00194         effects.RemoveAll();
00195         texts.RemoveAll();
00196 
00197         if(!ParseUSFSubtitles(CComQIPtr<IXMLDOMNode>(pDoc)))
00198                 return(false);
00199 
00200         POSITION pos = styles.GetHeadPosition();
00201         while(pos)
00202         {
00203                 style_t* def = styles.GetNext(pos);
00204 
00205                 if(def->name.CompareNoCase(L"Default"))
00206                         continue;
00207 
00208                 POSITION pos2 = styles.GetHeadPosition();
00209                 while(pos2)
00210                 {
00211                         style_t* s = styles.GetNext(pos2);
00212 
00213                         if(!s->name.CompareNoCase(L"Default"))
00214                                 continue;
00215 
00216                         if(s->fontstyle.face.IsEmpty()) s->fontstyle.face = def->fontstyle.face;
00217                         if(s->fontstyle.size.IsEmpty()) s->fontstyle.size = def->fontstyle.size;
00218                         if(s->fontstyle.color[0].IsEmpty()) s->fontstyle.color[0] = def->fontstyle.color[0];
00219                         if(s->fontstyle.color[1].IsEmpty()) s->fontstyle.color[1] = def->fontstyle.color[1];
00220                         if(s->fontstyle.color[2].IsEmpty()) s->fontstyle.color[2] = def->fontstyle.color[2];
00221                         if(s->fontstyle.color[3].IsEmpty()) s->fontstyle.color[3] = def->fontstyle.color[3];
00222                         if(s->fontstyle.italic.IsEmpty()) s->fontstyle.italic = def->fontstyle.italic;
00223                         if(s->fontstyle.weight.IsEmpty()) s->fontstyle.weight = def->fontstyle.weight;
00224                         if(s->fontstyle.underline.IsEmpty()) s->fontstyle.underline = def->fontstyle.underline;
00225                         if(s->fontstyle.alpha.IsEmpty()) s->fontstyle.alpha = def->fontstyle.alpha;
00226                         if(s->fontstyle.outline.IsEmpty()) s->fontstyle.outline = def->fontstyle.outline;
00227                         if(s->fontstyle.shadow.IsEmpty()) s->fontstyle.shadow = def->fontstyle.shadow;
00228                         if(s->fontstyle.wrap.IsEmpty()) s->fontstyle.wrap = def->fontstyle.wrap;
00229                         if(s->pal.alignment.IsEmpty()) s->pal.alignment = def->pal.alignment;
00230                         if(s->pal.relativeto.IsEmpty()) s->pal.relativeto = def->pal.relativeto;
00231                         if(s->pal.horizontal_margin.IsEmpty()) s->pal.horizontal_margin = def->pal.horizontal_margin;
00232                         if(s->pal.vertical_margin.IsEmpty()) s->pal.vertical_margin = def->pal.vertical_margin;
00233                         if(s->pal.rotate[0].IsEmpty()) s->pal.rotate[0] = def->pal.rotate[0];
00234                         if(s->pal.rotate[1].IsEmpty()) s->pal.rotate[1] = def->pal.rotate[1];
00235                         if(s->pal.rotate[2].IsEmpty()) s->pal.rotate[2] = def->pal.rotate[2];
00236                 }
00237 
00238                 break;
00239         }
00240 
00241         pos = texts.GetHeadPosition();
00242         while(pos)
00243         {
00244                 text_t* t = texts.GetNext(pos);
00245                 if(t->style.IsEmpty()) t->style = L"Default";
00246         }
00247 
00248         return(true);
00249 }
00250 
00251 bool CUSFSubtitles::ConvertToSTS(CSimpleTextSubtitle& sts)
00252 {
00253         sts.m_name = metadata.language.text;
00254         sts.m_encoding = CTextFile::UTF8;
00255         sts.m_dstScreenSize = CSize(640, 480);
00256         sts.m_fScaledBAS = true;
00257         sts.m_defaultWrapStyle = 1;
00258 
00259         // TODO: map metadata.language.code to charset num (windows doesn't have such a function...)
00260         int charSet = DEFAULT_CHARSET; 
00261 
00262         POSITION pos = styles.GetHeadPosition();
00263         while(pos)
00264         {
00265                 style_t* s = styles.GetNext(pos);
00266 
00267                 if(!s->name.CompareNoCase(L"Default") && !s->fontstyle.wrap.IsEmpty())
00268                 {
00269                         sts.m_defaultWrapStyle = 
00270                                 !s->fontstyle.wrap.CompareNoCase(L"no") ? 2 :
00271                                 !s->fontstyle.wrap.CompareNoCase(L"auto") ? 1 :
00272                                 1;
00273                 }
00274 
00275                 STSStyle* stss = new STSStyle;
00276                 if(!stss) continue;
00277 
00278                 if(!s->pal.horizontal_margin.IsEmpty())
00279                         stss->marginRect.left = stss->marginRect.right = TranslateMargin(s->pal.horizontal_margin, sts.m_dstScreenSize.cx);
00280                 if(!s->pal.vertical_margin.IsEmpty())
00281                         stss->marginRect.top = stss->marginRect.bottom = TranslateMargin(s->pal.vertical_margin, sts.m_dstScreenSize.cy);
00282 
00283                 stss->scrAlignment = TranslateAlignment(s->pal.alignment);
00284 
00285                 if(!s->pal.relativeto.IsEmpty()) stss->relativeTo = 
00286                         !s->pal.relativeto.CompareNoCase(L"window") ? 0 :
00287                         !s->pal.relativeto.CompareNoCase(L"video") ? 1 :
00288                         0;
00289 
00290                 stss->borderStyle = 0;
00291                 if(!s->fontstyle.outline.IsEmpty()) stss->outlineWidth = wcstol(s->fontstyle.outline, NULL, 10);
00292                 if(!s->fontstyle.shadow.IsEmpty()) stss->shadowDepth = wcstol(s->fontstyle.shadow, NULL, 10);
00293 
00294                 for(int i = 0; i < 4; i++)
00295                 {
00296                         DWORD color = ColorToDWORD(s->fontstyle.color[i]);
00297                         int alpha = (BYTE)wcstol(s->fontstyle.alpha, NULL, 10);
00298 
00299                         stss->colors[i] = color & 0xffffff;
00300                         stss->alpha[i] = (BYTE)(color>>24);
00301 
00302                         stss->alpha[i] = stss->alpha[i] + (255 - stss->alpha[i]) * min(max(alpha, 0), 100) / 100;
00303                 }
00304 
00305                 if(!s->fontstyle.face.IsEmpty()) stss->fontName = s->fontstyle.face;
00306                 if(!s->fontstyle.size.IsEmpty()) stss->fontSize = wcstol(s->fontstyle.size, NULL, 10);
00307                 if(!s->fontstyle.weight.IsEmpty()) stss->fontWeight = 
00308                         !s->fontstyle.weight.CompareNoCase(L"normal") ? FW_NORMAL :
00309                         !s->fontstyle.weight.CompareNoCase(L"bold") ? FW_BOLD :
00310                         !s->fontstyle.weight.CompareNoCase(L"lighter") ? FW_LIGHT :
00311                         !s->fontstyle.weight.CompareNoCase(L"bolder") ? FW_SEMIBOLD :
00312                         wcstol(s->fontstyle.weight, NULL, 10);
00313                 if(stss->fontWeight == 0) stss->fontWeight = FW_NORMAL;
00314                 if(!s->fontstyle.italic.IsEmpty()) stss->fItalic = s->fontstyle.italic.CompareNoCase(L"yes") == 0;
00315                 if(!s->fontstyle.underline.IsEmpty()) stss->fUnderline = s->fontstyle.underline.CompareNoCase(L"yes") == 0;
00316                 if(!s->pal.rotate[0].IsEmpty()) stss->fontAngleZ = wcstol(s->pal.rotate[0], NULL, 10);
00317                 if(!s->pal.rotate[1].IsEmpty()) stss->fontAngleX = wcstol(s->pal.rotate[1], NULL, 10);
00318                 if(!s->pal.rotate[2].IsEmpty()) stss->fontAngleY = wcstol(s->pal.rotate[2], NULL, 10);
00319 
00320                 stss->charSet = charSet;
00321 
00322                 sts.AddStyle(WToT(s->name), stss);
00323         }
00324 
00325         pos = texts.GetHeadPosition();
00326         while(pos)
00327         {
00328                 text_t* t = texts.GetNext(pos);
00329 
00330                 if(!t->pal.alignment.IsEmpty())
00331                 {
00332                         CStringW s;
00333                         s.Format(L"{\\an%d}", TranslateAlignment(t->pal.alignment));
00334                         t->str = s + t->str;
00335                 }
00336 
00337                 CRect marginRect;
00338                 marginRect.SetRectEmpty();
00339 
00340                 if(!t->pal.horizontal_margin.IsEmpty())
00341                         marginRect.left = marginRect.right = TranslateMargin(t->pal.horizontal_margin, sts.m_dstScreenSize.cx);
00342                 if(!t->pal.vertical_margin.IsEmpty())
00343                         marginRect.top = marginRect.bottom = TranslateMargin(t->pal.vertical_margin, sts.m_dstScreenSize.cy);
00344 
00345                 WCHAR rtags[3][8] = {L"{\\rz%d}", L"{\\rx%d}", L"{\\ry%d}"};
00346                 for(int i = 0; i < 3; i++)
00347                 {
00348                         if(int angle = wcstol(t->pal.rotate[i], NULL, 10))
00349                         {
00350                                 CStringW str;
00351                                 str.Format(rtags[i], angle);
00352                                 t->str = str + t->str;
00353                         }
00354                 }
00355 
00356                 if(t->style.CompareNoCase(L"Default") != 0)
00357                 {
00358                         POSITION pos = styles.GetHeadPosition();
00359                         while(pos)
00360                         {
00361                                 style_t* s = styles.GetNext(pos);
00362                                 if(s->name == t->style && !s->fontstyle.wrap.IsEmpty())
00363                                 {
00364                                         int WrapStyle = 
00365                                                 !s->fontstyle.wrap.CompareNoCase(L"no") ? 2 :
00366                                                 !s->fontstyle.wrap.CompareNoCase(L"auto") ? 1 :
00367                                                 1;
00368 
00369                                         if(WrapStyle != sts.m_defaultWrapStyle)
00370                                         {
00371                                                 CStringW str;
00372                         str.Format(L"{\\q%d}", WrapStyle);
00373                                                 t->str = str + t->str;
00374                                         }
00375 
00376                                         break;
00377                                 }
00378                         }
00379                 }
00380 
00381                 // TODO: apply effects as {\t(..)} after usf's standard clearly defines them
00382 
00383                 sts.Add(t->str, true, t->start, t->stop, WToT(t->style), _T(""), _T(""), marginRect);
00384         }
00385 
00386         return(true);
00387 }
00388 
00389 bool CUSFSubtitles::ParseUSFSubtitles(CComPtr<IXMLDOMNode> pNode)
00390 {
00391         DeclareNameAndValue(pNode, name, val);
00392 
00393         if(name == L"usfsubtitles")
00394         {
00395                 // metadata
00396 
00397                 BeginEnumChildren(pNode, pChild)
00398                 {
00399                         DeclareNameAndValue(pChild, name, val);
00400 
00401                         if(name == L"metadata")
00402                         {
00403                                 ParseMetadata(pChild, metadata);
00404                         }
00405                 }
00406                 EndEnumChildren
00407 
00408                 // styles
00409 
00410                 BeginEnumChildren(pNode, pChild)
00411                 {
00412                         DeclareNameAndValue(pChild, name, val);
00413 
00414                         if(name == L"styles")
00415                         {
00416                                 BeginEnumChildren(pChild, pGrandChild) // :)
00417                                 {
00418                                         DeclareNameAndValue(pGrandChild, name, val);
00419 
00420                                         if(name == L"style")
00421                                         {
00422                                                 CAutoPtr<style_t> s(new style_t);
00423                                                 if(s)
00424                                                 {
00425                                                         ParseStyle(pGrandChild, s);
00426                                                         styles.AddTail(s);
00427                                                 }
00428                                         }
00429                                 }
00430                                 EndEnumChildren
00431                         }
00432                 }
00433                 EndEnumChildren
00434 
00435                 // effects
00436 
00437                 BeginEnumChildren(pNode, pChild)
00438                 {
00439                         DeclareNameAndValue(pChild, name, val);
00440 
00441                         if(name == L"effects")
00442                         {
00443                                 BeginEnumChildren(pChild, pGrandChild) // :)
00444                                 {
00445                                         DeclareNameAndValue(pGrandChild, name, val);
00446 
00447                                         if(name == L"effect")
00448                                         {
00449                                                 CAutoPtr<effect_t> e(new effect_t);
00450                                                 if(e)
00451                                                 {
00452                                                         ParseEffect(pGrandChild, e);
00453                                                         effects.AddTail(e);
00454                                                 }
00455                                         }
00456                                 }
00457                                 EndEnumChildren
00458                         }
00459                 }
00460                 EndEnumChildren
00461 
00462                 // subtitles
00463 
00464                 BeginEnumChildren(pNode, pChild)
00465                 {
00466                         DeclareNameAndValue(pChild, name, val);
00467 
00468                         if(name == L"subtitles")
00469                         {
00470                                 BeginEnumChildren(pChild, pGrandChild) // :)
00471                                 {
00472                                         DeclareNameAndValue(pGrandChild, name, val);
00473 
00474                                         if(name == L"subtitle")
00475                                         {
00476                                                 CStringW sstart = GetAttrib(L"start", pGrandChild);
00477                                                 CStringW sstop = GetAttrib(L"stop", pGrandChild);
00478                                                 CStringW sduration = GetAttrib(L"duration", pGrandChild);
00479                                                 if(sstart.IsEmpty() || (sstop.IsEmpty() && sduration.IsEmpty()))
00480                                                         continue;
00481 
00482                                                 int start = TimeToInt(sstart);
00483                                                 int stop = !sstop.IsEmpty() ? TimeToInt(sstop) : (start + TimeToInt(sduration));
00484 
00485                                                 ParseSubtitle(pGrandChild, start, stop);
00486                                         }
00487                                 }
00488                                 EndEnumChildren
00489                         }
00490                 }
00491                 EndEnumChildren
00492 
00493                 return(true);
00494         }
00495 
00496         BeginEnumChildren(pNode, pChild)
00497         {
00498         if(ParseUSFSubtitles(pChild))
00499                 {
00500                         return(true);
00501                 }
00502         }
00503         EndEnumChildren
00504 
00505         return(false);
00506 }
00507 
00508 void CUSFSubtitles::ParseMetadata(CComPtr<IXMLDOMNode> pNode, metadata_t& m)
00509 {
00510         DeclareNameAndValue(pNode, name, val);
00511 
00512         if(name == L"title")
00513         {
00514                 m.title = GetText(pNode);
00515         }
00516         else if(name == L"date")
00517         {
00518                 m.date = GetText(pNode);
00519         }
00520         else if(name == L"comment")
00521         {
00522                 m.comment = GetText(pNode);
00523         }
00524         else if(name == L"author")
00525         {
00526                 BeginEnumChildren(pNode, pChild)
00527                 {
00528                         DeclareNameAndValue(pChild, name, val);
00529 
00530                         if(name == L"name")
00531                                 m.author.name = GetText(pChild);
00532                         else if(name == L"email")
00533                                 m.author.email = GetText(pChild);
00534                         else if(name == L"url")
00535                                 m.author.url = GetText(pChild);
00536                 }
00537                 EndEnumChildren
00538 
00539                 return;
00540         }
00541         else if(name == L"language")
00542         {
00543                 m.language.text = GetText(pNode);
00544                 m.language.code = GetAttrib(L"code", pNode);
00545         }
00546         else if(name == L"languageext")
00547         {
00548                 m.languageext.text = GetText(pNode);
00549                 m.languageext.code = GetAttrib(L"code", pNode);
00550         }
00551 
00552         BeginEnumChildren(pNode, pChild)
00553         {
00554                 ParseMetadata(pChild, metadata);
00555         }
00556         EndEnumChildren
00557 }
00558 
00559 void CUSFSubtitles::ParseStyle(CComPtr<IXMLDOMNode> pNode, style_t* s)
00560 {
00561         DeclareNameAndValue(pNode, name, val);
00562 
00563         if(name == L"style")
00564         {
00565                 s->name = GetAttrib(L"name", pNode);
00566         }
00567         else if(name == L"fontstyle")
00568         {
00569                 ParseFontstyle(pNode, s->fontstyle);
00570                 return;
00571         }
00572         else if(name == L"position")
00573         {
00574                 ParsePal(pNode, s->pal);
00575                 return;
00576         }
00577 
00578         BeginEnumChildren(pNode, pChild)
00579         {
00580                 ParseStyle(pChild, s);
00581         }
00582         EndEnumChildren
00583 }
00584 
00585 void CUSFSubtitles::ParseFontstyle(CComPtr<IXMLDOMNode> pNode, fontstyle_t& fs)
00586 {
00587         fs.face = GetAttrib(L"face", pNode);
00588         fs.size = GetAttrib(L"size", pNode);
00589         fs.color[0] = GetAttrib(L"color", pNode);
00590         fs.color[1] = GetAttrib(L"back-color", pNode);
00591         fs.color[2] = GetAttrib(L"outline-color", pNode);
00592         fs.color[3] = GetAttrib(L"shadow-color", pNode);
00593         fs.italic = GetAttrib(L"italic", pNode);
00594         fs.weight = GetAttrib(L"weight", pNode);
00595         fs.underline = GetAttrib(L"underline", pNode);
00596         fs.alpha = GetAttrib(L"alpha", pNode);
00597         fs.outline = GetAttrib(L"outline-level", pNode);
00598         fs.shadow = GetAttrib(L"shadow-level", pNode);
00599         fs.wrap = GetAttrib(L"wrap", pNode);
00600 }
00601 
00602 void CUSFSubtitles::ParsePal(CComPtr<IXMLDOMNode> pNode, posattriblist_t& pal)
00603 {
00604         pal.alignment = GetAttrib(L"alignment", pNode);
00605         pal.relativeto = GetAttrib(L"relative-to", pNode);
00606         pal.horizontal_margin = GetAttrib(L"horizontal-margin", pNode);
00607         pal.vertical_margin = GetAttrib(L"vertical-margin", pNode);
00608         pal.rotate[0] = GetAttrib(L"rotate-z", pNode);
00609         pal.rotate[1] = GetAttrib(L"rotate-x", pNode);
00610         pal.rotate[2] = GetAttrib(L"rotate-y", pNode);
00611 }
00612 
00613 void CUSFSubtitles::ParseEffect(CComPtr<IXMLDOMNode> pNode, effect_t* e)
00614 {
00615         DeclareNameAndValue(pNode, name, val);
00616 
00617         if(name == L"effect")
00618         {
00619                 e->name = GetAttrib(L"name", pNode);
00620         }
00621         else if(name == L"keyframes")
00622         {
00623                 BeginEnumChildren(pNode, pChild)
00624                 {
00625                         DeclareNameAndValue(pChild, name, val);
00626 
00627                         if(name == L"keyframe")
00628                         {
00629                                 CAutoPtr<keyframe_t> k(new keyframe_t);
00630                                 if(k)
00631                                 {
00632                                         ParseKeyframe(pChild, k);
00633                                         e->keyframes.AddTail(k);
00634                                 }
00635                         }
00636                 }
00637                 EndEnumChildren
00638 
00639                 return;
00640         }
00641 
00642         BeginEnumChildren(pNode, pChild)
00643         {
00644                 ParseEffect(pChild, e);
00645         }
00646         EndEnumChildren
00647 }
00648 
00649 void CUSFSubtitles::ParseKeyframe(CComPtr<IXMLDOMNode> pNode, keyframe_t* k)
00650 {
00651         DeclareNameAndValue(pNode, name, val);
00652 
00653         if(name == L"keyframe")
00654         {
00655                 k->position = GetAttrib(L"position", pNode);
00656         }
00657         else if(name == L"fontstyle")
00658         {
00659                 ParseFontstyle(pNode, k->fontstyle);
00660                 return;
00661         }
00662         else if(name == L"position")
00663         {
00664                 ParsePal(pNode, k->pal);
00665                 return;
00666         }
00667 }
00668 
00669 void CUSFSubtitles::ParseSubtitle(CComPtr<IXMLDOMNode> pNode, int start, int stop)
00670 {
00671         DeclareNameAndValue(pNode, name, val);
00672 
00673         if(name == L"text" || name == L"karaoke")
00674         {
00675                 CAutoPtr<text_t> t(new text_t);
00676                 if(t)
00677                 {
00678                         t->start = start;
00679                         t->stop = stop;
00680                         t->style = GetAttrib(L"style", pNode);
00681                         t->effect = GetAttrib(L"effect", pNode);
00682                         ParsePal(pNode, t->pal);
00683                         ParseText(pNode, t->str);
00684                         texts.AddTail(t);
00685                 }
00686 
00687                 return;
00688         }
00689 //      else if
00690 
00691         BeginEnumChildren(pNode, pChild)
00692         {
00693                 ParseSubtitle(pChild, start, stop);
00694         }
00695         EndEnumChildren
00696 }
00697 
00698 void CUSFSubtitles::ParseText(CComPtr<IXMLDOMNode> pNode, CStringW& str)
00699 {
00700         DeclareNameAndValue(pNode, name, val);
00701 
00702         CStringW prefix, postfix;
00703 
00704         if(name == L"b")
00705         {
00706                 prefix = L"{\\b1}";
00707                 postfix = L"{\\b}";
00708         }
00709         else if(name == L"i")
00710         {
00711                 prefix = L"{\\i1}";
00712                 postfix = L"{\\i}";
00713         }
00714         else if(name == L"u")
00715         {
00716                 prefix = L"{\\u1}";
00717                 postfix = L"{\\u}";
00718         }
00719         else if(name == L"font")
00720         {
00721                 fontstyle_t fs;
00722                 ParseFontstyle(pNode, fs);
00723 
00724                 if(!fs.face.IsEmpty()) {prefix += L"{\\fn" + fs.face + L"}"; postfix += L"{\\fn}";}
00725                 if(!fs.size.IsEmpty()) {prefix += L"{\\fs" + fs.size + L"}"; postfix += L"{\\fs}";}
00726                 if(!fs.outline.IsEmpty()) {prefix += L"{\\bord" + fs.outline + L"}"; postfix += L"{\\bord}";}
00727                 if(!fs.shadow.IsEmpty()) {prefix += L"{\\shad" + fs.shadow + L"}"; postfix += L"{\\shad}";}
00728 
00729                 for(int i = 0; i < 4; i++)
00730                 {
00731                         if(!fs.color[i].IsEmpty())
00732                         {
00733                                 CStringW s;
00734                                 s.Format(L"{\\%dc&H%06x&}", i+1, ColorToDWORD(fs.color[i]));
00735                                 prefix += s;
00736                                 s.Format(L"{\\%dc}", i+1);
00737                                 postfix += s;
00738                         }
00739                 }
00740         }
00741         else if(name == L"k")
00742         {
00743                 int t = wcstol(GetAttrib(L"t", pNode), NULL, 10);
00744                 CStringW s;
00745                 s.Format(L"{\\kf%d}", t / 10);
00746                 str += s;
00747                 return;
00748         }
00749         else if(name == L"br")
00750         {
00751                 str += L"\\N";
00752                 return;
00753         }
00754         else if(name == L"#text")
00755         {
00756                 str += GetXML(pNode);
00757                 return;
00758         }
00759 
00760         BeginEnumChildren(pNode, pChild)
00761         {
00762                 CStringW s;
00763                 ParseText(pChild, s);
00764                 str += s;
00765         }
00766         EndEnumChildren
00767 
00768         str = prefix + str + postfix;
00769 }
00770 
00771 void CUSFSubtitles::ParseShape(CComPtr<IXMLDOMNode> pNode)
00772 {
00773         // no specs on this yet
00774 }

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