Merge with MPC-HC 6d1472b2f18266d92e5bc068667de348c0cd3b3b.
[xy_vsfilter.git] / src / subtitles / libssf / Node.cpp
blob52ff46b8fdb8e900336c0dec068f7a4196183104
1 /*
2 * Copyright (C) 2003-2006 Gabest
3 * http://www.gabest.org
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.
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
22 #include "stdafx.h"
23 #include "Node.h"
24 #include "NodeFactory.h"
25 #include "Exception.h"
26 #include "Split.h"
28 #include <math.h>
30 namespace ssf
32 Node::Node(NodeFactory* pnf, CStringW name)
33 : m_pnf(pnf)
34 , m_type('?')
35 , m_name(name)
36 , m_priority(PNormal)
37 , m_predefined(false)
38 , m_parent(NULL)
40 ASSERT(m_pnf);
43 void Node::AddTail(Node* pNode)
45 if(POSITION pos = m_nodes.Find(pNode)) // TODO: slow
47 m_nodes.MoveToTail(pos);
48 return;
51 m_nodes.AddTail(pNode);
52 m_name2node[pNode->m_name] = pNode;
55 bool Node::IsNameUnknown()
57 return m_name.IsEmpty() || !!iswdigit(m_name[0]);
60 bool Node::IsTypeUnknown()
62 return m_type.IsEmpty() || m_type == '?';
65 bool Node::IsType(CStringW type)
67 return m_type == type;
70 void Node::GetChildDefs(CAtlList<Definition*>& l, LPCWSTR type, bool fFirst)
72 CAtlList<Definition*> rdl[3];
74 if(fFirst)
76 if(Definition* pDef = m_pnf->GetDefByName(m_type))
78 pDef->GetChildDefs(rdl[pDef->m_priority], type, false);
82 POSITION pos = m_nodes.GetHeadPosition();
83 while(pos)
85 if(Node* pNode = m_nodes.GetNext(pos))
87 pNode->GetChildDefs(rdl[pNode->m_priority], type, false);
91 for(int i = 0; i < sizeof(rdl)/sizeof(rdl[0]); i++)
93 l.AddTailList(&rdl[i]);
97 // Reference
99 Reference::Reference(NodeFactory* pnf, CStringW name)
100 : Node(pnf, name)
104 Reference::~Reference()
108 void Reference::GetChildDefs(CAtlList<Definition*>& l, LPCWSTR type, bool fFirst)
110 CAtlList<Definition*> rdl[3];
112 POSITION pos = m_nodes.GetHeadPosition();
113 while(pos)
115 if(Definition* pDef = dynamic_cast<Definition*>(m_nodes.GetNext(pos)))
117 if(!type || pDef->m_type == type) // TODO: faster lookup
119 rdl[pDef->m_priority].AddTail(pDef);
124 for(int i = 0; i < sizeof(rdl)/sizeof(rdl[0]); i++)
126 l.AddTailList(&rdl[i]);
130 void Reference::Dump(OutputStream& s, int level, bool fLast)
132 if(m_predefined) return;
134 CStringW tabs(' ', level*4);
136 // s.PutString(tabs + '\n' + tabs + L" {\n");
137 s.PutString(L" {\n");
139 POSITION pos = m_nodes.GetHeadPosition();
140 while(pos)
142 Node* pNode = m_nodes.GetNext(pos);
144 if(Definition* pDef = dynamic_cast<Definition*>(pNode))
146 pDef->Dump(s, level + 1, pos == NULL);
150 s.PutString(tabs + '}');
153 // Definition
155 Definition::Definition(NodeFactory* pnf, CStringW name)
156 : Node(pnf, name)
157 , m_status(node)
158 , m_autotype(false)
162 Definition::~Definition()
164 RemoveFromCache();
167 bool Definition::IsVisible(Definition* pDef)
169 Node* pNode = m_parent;
171 while(pNode)
173 if(pNode->m_name2node.Lookup(pDef->m_name))
175 return true;
178 pNode = pNode->m_parent;
181 return false;
184 void Definition::AddTail(Node* pNode)
186 // if(Reference* pRef = dynamic_cast<Reference*>(pNode))
188 ASSERT(m_status == node);
190 m_status = node;
192 if(IsTypeUnknown() && !pNode->IsTypeUnknown())
194 m_type = pNode->m_type;
195 m_autotype = true;
198 RemoveFromCache(pNode->m_type);
201 __super::AddTail(pNode);
204 Definition& Definition::operator[] (LPCWSTR type)
206 Definition* pRetDef = NULL;
207 if(m_type2def.Lookup(type, pRetDef))
208 return *pRetDef;
210 pRetDef = new Definition(m_pnf, L"");
211 pRetDef->m_priority = PLow;
212 pRetDef->m_type = type;
213 m_type2def[type] = pRetDef;
215 CAtlList<Definition*> l;
216 GetChildDefs(l, type);
218 while(!l.IsEmpty())
220 Definition* pDef = l.RemoveHead();
222 pRetDef->m_priority = pDef->m_priority;
223 pRetDef->m_parent = pDef->m_parent;
225 if(pDef->IsValue())
227 pRetDef->SetAsValue(pDef->m_status, pDef->m_value, pDef->m_unit);
229 else
231 pRetDef->m_status = node;
232 pRetDef->m_nodes.AddTailList(&pDef->m_nodes);
236 return *pRetDef;
239 void Definition::RemoveFromCache(LPCWSTR type)
241 if(!type)
243 POSITION pos = m_type2def.GetStartPosition();
244 while(pos) delete m_type2def.GetNextValue(pos);
246 else if(StringMapW<Definition*>::CPair* p = m_type2def.Lookup(type))
248 delete p->m_value;
249 m_type2def.RemoveKey(type);
253 bool Definition::IsValue(status_t s)
255 return s ? m_status == s : m_status != node;
258 void Definition::SetAsValue(status_t s, CStringW v, CStringW u)
260 ASSERT(s != node);
262 m_nodes.RemoveAll();
263 m_name2node.RemoveAll();
265 m_status = s;
267 m_value = v;
268 m_unit = u;
271 void Definition::SetAsNumber(CStringW v, CStringW u)
273 SetAsValue(number, v, u);
275 Number<float> n;
276 GetAsNumber(n); // will throw an exception if not a number
279 template<class T>
280 void Definition::GetAsNumber(Number<T>& n, StringMapW<T>* n2n)
282 CStringW str = m_value;
283 str.Replace(L" ", L"");
285 n.value = 0;
286 n.unit = m_unit;
287 n.sign = 0;
289 if(n2n)
291 if(m_status == node) throw Exception(_T("expected value type"));
293 if(StringMapW<T>::CPair* p = n2n->Lookup(str))
295 n.value = p->m_value;
296 return;
300 if(m_status != number) throw Exception(_T("expected number"));
302 n.sign = str.Find('+') == 0 ? 1 : str.Find('-') == 0 ? -1 : 0;
303 str.TrimLeft(L"+-");
305 if(str.Find(L"0x") == 0)
307 if(n.sign) throw Exception(_T("hex values must be unsigned"));
309 n.value = (T)wcstoul(str.Mid(2), NULL, 16);
311 else
313 CStringW num_string = m_value + m_unit;
315 if(m_num_string != num_string)
317 Split sa(':', str);
318 Split sa2('.', sa ? sa[sa-1] : L"");
320 if(sa == 0 || sa2 == 0 || sa2 > 2) throw Exception(_T("invalid number"));
322 float f = 0;
323 for(size_t i = 0; i < sa; i++) {f *= 60; f += wcstoul(sa[i], NULL, 10);}
324 if(sa2 > 1) f += (float)wcstoul(sa2[1], NULL, 10) / pow((float)10, sa2[1].GetLength());
326 if(n.unit == L"ms") {f /= 1000; n.unit = L"s";}
327 else if(n.unit == L"m") {f *= 60; n.unit = L"s";}
328 else if(n.unit == L"h") {f *= 3600; n.unit = L"s";}
330 m_num.value = f;
331 m_num.unit = n.unit;
332 m_num_string = num_string;
334 n.value = (T)f;
336 else
338 n.value = (T)m_num.value;
339 n.unit = m_num.unit;
342 if(n.sign) n.value *= n.sign;
346 void Definition::GetAsString(CStringW& str)
348 if(m_status == node) throw Exception(_T("expected value type"));
350 str = m_value;
353 void Definition::GetAsNumber(Number<int>& n, StringMapW<int>* n2n) {return GetAsNumber<int>(n, n2n);}
354 void Definition::GetAsNumber(Number<DWORD>& n, StringMapW<DWORD>* n2n) {return GetAsNumber<DWORD>(n, n2n);}
355 void Definition::GetAsNumber(Number<float>& n, StringMapW<float>* n2n) {return GetAsNumber<float>(n, n2n);}
357 void Definition::GetAsBoolean(bool& b)
359 static StringMapW<bool> s2b;
361 if(s2b.IsEmpty())
363 s2b[L"true"] = true;
364 s2b[L"on"] = true;
365 s2b[L"yes"] = true;
366 s2b[L"1"] = true;
367 s2b[L"false"] = false;
368 s2b[L"off"] = false;
369 s2b[L"no"] = false;
370 s2b[L"0"] = false;
373 if(!s2b.Lookup(m_value, b)) // m_status != boolean && m_status != number ||
375 throw Exception(_T("expected boolean"));
379 bool Definition::GetAsTime(Time& t, StringMapW<float>& offset, StringMapW<float>* n2n, int default_id)
381 Definition& time = (*this)[L"time"];
383 CStringW id;
384 if(time[L"id"].IsValue()) id = time[L"id"];
385 else id.Format(L"%d", default_id);
387 float scale = time[L"scale"].IsValue() ? time[L"scale"] : 1.0f;
389 if(time[L"start"].IsValue() && time[L"stop"].IsValue())
391 time[L"start"].GetAsNumber(t.start, n2n);
392 time[L"stop"].GetAsNumber(t.stop, n2n);
394 if(t.start.unit.IsEmpty()) t.start.value *= scale;
395 if(t.stop.unit.IsEmpty()) t.stop.value *= scale;
397 float o = 0;
398 offset.Lookup(id, o);
400 if(t.start.sign != 0) t.start.value = o + t.start.value;
401 if(t.stop.sign != 0) t.stop.value = t.start.value + t.stop.value;
403 offset[id] = t.stop.value;
405 return true;
408 return false;
411 Definition::operator LPCWSTR()
413 CStringW str;
414 GetAsString(str);
415 return str;
418 Definition::operator float()
420 float d;
421 GetAsNumber(d);
422 return d;
425 Definition::operator bool()
427 bool b;
428 GetAsBoolean(b);
429 return b;
432 Definition* Definition::SetChildAsValue(CStringW path, status_t s, CStringW v, CStringW u)
434 Definition* pDef = this;
436 Split split('.', path);
438 for(size_t i = 0, j = split-1; i <= j; i++)
440 CStringW type = split[i];
442 if(pDef->m_nodes.IsEmpty() || !dynamic_cast<Reference*>(pDef->m_nodes.GetTail()))
444 EXECUTE_ASSERT(m_pnf->CreateRef(pDef) != NULL);
447 if(Reference* pRef = dynamic_cast<Reference*>(pDef->m_nodes.GetTail()))
449 pDef = NULL;
451 POSITION pos = pRef->m_nodes.GetTailPosition();
452 while(pos)
454 Definition* pChildDef = dynamic_cast<Definition*>(pRef->m_nodes.GetPrev(pos));
456 if(pChildDef->IsType(type))
458 if(pChildDef->IsNameUnknown()) pDef = pChildDef;
459 break;
463 if(!pDef)
465 pDef = m_pnf->CreateDef(pRef, type);
468 if(i == j)
470 pDef->SetAsValue(s, v, u);
471 return pDef;
476 return NULL;
479 Definition* Definition::SetChildAsNumber(CStringW path, CStringW v, CStringW u)
481 Definition* pDef = SetChildAsValue(path, number, v, u);
483 Number<float> n;
484 pDef->GetAsNumber(n); // will throw an exception if not a number
486 return pDef;
489 void Definition::Dump(OutputStream& s, int level, bool fLast)
491 if(m_predefined) return;
493 CStringW tabs(' ', level*4);
495 CStringW str = tabs;
496 if(m_predefined) str += '?';
497 if(m_priority == PLow) str += '*';
498 else if(m_priority == PHigh) str += '!';
499 if(!IsTypeUnknown() && !m_autotype) str += m_type;
500 if(!IsNameUnknown()) str += '#' + m_name;
501 str += ':';
502 s.PutString(L"%s", str);
504 if(!m_nodes.IsEmpty())
506 POSITION pos = m_nodes.GetHeadPosition();
507 while(pos)
509 Node* pNode = m_nodes.GetNext(pos);
511 if(Reference* pRef = dynamic_cast<Reference*>(pNode))
513 pRef->Dump(s, level, fLast);
515 else
517 ASSERT(!pNode->IsNameUnknown());
518 s.PutString(L" %s", pNode->m_name);
522 s.PutString(L";\n");
524 if(!fLast && (!m_nodes.IsEmpty() || level == 0)) s.PutString(L"\n");
526 else if(m_status == string)
528 CStringW str = m_value;
529 str.Replace(L"\"", L"\\\"");
530 s.PutString(L" \"%s\";\n", str);
532 else if(m_status == number)
534 CStringW str = m_value;
535 if(!m_unit.IsEmpty()) str += m_unit;
536 s.PutString(L" %s;\n", str);
538 else if(m_status == boolean)
540 s.PutString(L" %s;\n", m_value);
542 else if(m_status == block)
544 s.PutString(L" {%s};\n", m_value);
546 else
548 s.PutString(L" null;\n");