- Main Page
- Namespaces
- Classes
- Files
- Directories

- File List
- File Members

# 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 }