1
2 /**
3 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
4
5 DO NOT CHANGE THIS FILE!
6
7 this file is deprecated and will be replaced with
8
9 lsl/battle/tdfcontainer.cpp
10
11 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
12 **/
13
14
15
16 #include "tdfcontainer.h"
17
18 #include "utils/conversion.h"
19 #include "utils/debug.h"
20 #include <wx/intl.h>
21 #include <wx/tokenzr.h>
22 #include <wx/log.h>
23 #include <cmath>
24
TDFWriter(wxString & s)25 TDFWriter::TDFWriter( wxString &s ):
26 m_stream( s ),
27 m_depth( 0 )
28 {
29
30 }
31
~TDFWriter()32 TDFWriter::~TDFWriter() {
33 Close();
34 }
EnterSection(const wxString & name)35 void TDFWriter::EnterSection( const wxString &name ) {
36 Indent();
37 m_stream << _T( "[" ) << name << _T( "]\n" );
38 Indent();
39 m_stream << _T( "{\n" );
40 m_depth++;
41 }
LeaveSection()42 void TDFWriter::LeaveSection() {
43 m_depth--;
44 Indent();
45 m_stream << _T( "}\n" );
46 }
Indent()47 void TDFWriter::Indent() {
48 for ( int i = 0;i < m_depth;++i )m_stream << _T( "\t" );
49 }
50 //wxString GetCurrentPath();
Append(const wxString & name,wxString value)51 void TDFWriter::Append( const wxString &name, wxString value ) {
52 Indent();
53 m_stream << name << _T( "=" ) << value << _T( ";\n" );
54 }
55
Close()56 void TDFWriter::Close() {
57 while ( m_depth > 0 )
58 LeaveSection();
59 if ( m_depth < 0 ) {
60 wxLogWarning( _T( "error in TDFWriter usage: more LeaveSection() calls than EnterSection(). Please contact springlobby developers" ) );
61 }
62 }
63
AppendLineBreak()64 void TDFWriter::AppendLineBreak() {
65 m_stream << _T( "\n" );
66 }
67
68 #include "sstream"
69 #include "fstream"
70 #include <iomanip>
71 #include <algorithm>
72
73
ReportError(const Token & t,const wxString & err)74 void Tokenizer::ReportError( const Token &t, const wxString &err ) {
75 wxLogMessage( _T( "TDF parsing error at (%s), on token \"%s\" : %s" ), t.pos_string.c_str(), t.value_s.c_str(), err.c_str() );
76 errors++;
77 }
78
79 //#define ReportError(a) {std::cerr<<"error "<<(a);}
80 //#define ReportError(a) {wxLogMessage(_T("error %s"),TowxString(a).c_str());}
81
EnterStream(std::istream & stream_,const wxString & name)82 void Tokenizer::EnterStream( std::istream &stream_, const wxString &name ) {
83 skip_eol = false;
84 include_stack.push_back( IncludeCacheEntry( &stream_, false ) );
85 include_stack.back().name = name;
86 }
87
UnwindStack()88 void Tokenizer::UnwindStack() {
89 while ( ( !include_stack.empty() ) && include_stack.back().stream && ( !include_stack.back().stream->good() ) ) {
90 include_stack.pop_back();
91 }
92 }
93
PeekNextChar()94 char Tokenizer::PeekNextChar() {
95 UnwindStack();
96 //std::string tmp;
97 char tmp = 0;
98 if ( !include_stack.empty() )tmp = ( *include_stack.back().stream ).peek();
99 return tmp;
100 }
101
GetNextChar()102 char Tokenizer::GetNextChar() {
103 UnwindStack();
104 //std::string tmp;
105 if ( include_stack.empty() )return 0;
106
107 char c = ( *include_stack.back().stream ).get();
108
109 if ( ( !skip_eol ) && ( c == 10 || c == 13 ) ) {// end of line
110 include_stack.back().line += 1;
111 include_stack.back().column = 1;
112
113 // if next is different we'll skip it.
114 //std::istream &stream=(*include_stack.back().stream);
115 char nc = ( *include_stack.back().stream ).peek();
116 if ( ( nc == 10 || nc == 13 ) && ( nc != c ) )skip_eol = true;
117 } else {
118 if ( !skip_eol )include_stack.back().column += 1;
119 skip_eol = false;
120 }
121
122 return c;
123 }
124
Good()125 bool Tokenizer::Good() {
126 UnwindStack();
127 return !include_stack.empty();
128 }
129
ReadToken(Token & token)130 void Tokenizer::ReadToken( Token &token ) {
131 start:
132
133 SkipSpaces();
134
135
136 token.value_s.clear();
137
138 if ( !Good() ) {
139 token.type = Token::type_eof;
140 token.pos_string = _T( "EOF" );
141 return;
142 }
143
144 token.pos_string = wxString();
145 if ( !include_stack.empty() && !include_stack.back().name.empty() )token.pos_string << include_stack.back().name << _T( " , " );
146 token.pos_string << _( "line " ) << include_stack.back().line << _( " , column " ) << include_stack.back().column;
147
148 char c = GetNextChar();
149 token.value_s += c;
150 // first find what token is it, and handle all except numbers
151 switch ( c ) {
152 case '[': {
153 token.type = Token::type_section_name;
154 token.value_s.clear();
155 bool skip_next_eol_char = false;
156 while ( Good() ) {
157 c = GetNextChar();
158 // wxString has problem with zero characters, replace by space.
159 if ( c == 0 ) {
160 c = ' ';
161 }
162 if ( c == '\\' ) {
163 if ( Good() ) {
164 token.value_s += GetNextChar();
165 } else {
166 ReportError( token, wxT( "Quotes not closed before end of file" ) );
167 return;
168 }
169 } else if ( c == ']' ) {
170 return;
171 } else
172 {
173 token.value_s += c;
174 }
175 // handle end of line
176 if ( skip_next_eol_char ) {
177 skip_next_eol_char = false;
178 } else if ( c == 10 || c == 13 ) {
179 //++line;
180 //column=1;
181 if ( ( PeekNextChar() == 10 || PeekNextChar() == 13 ) && ( PeekNextChar() != c ) )skip_next_eol_char = true;
182 }
183 }
184 ReportError( token, wxT( "Quotes not closed before end of file" ) );
185 }
186 case '{':
187 token.type = Token::type_enter_section;
188 return;
189 case '}':
190 token.type = Token::type_leave_section;
191 return;
192 case ';':
193 token.type = Token::type_semicolon;
194 return;
195 case '=':
196 token.type = Token::type_entry_value;
197 token.value_s = wxEmptyString;
198 while ( Good() && PeekNextChar() != ';' ) {
199 unsigned char c_ = GetNextChar();
200 token.value_s += c_;
201 }
202 return;
203 case '/':// handle comments
204 if ( PeekNextChar() == '/' ) {
205 //SkipToEOL();
206 if ( !include_stack.empty() ) {
207 std::string tmp;
208 std::getline( ( *include_stack.back().stream ), tmp );
209 include_stack.back().line += 1;
210 include_stack.back().column = 1;
211 }
212
213 goto start;
214 }
215 else if ( PeekNextChar() == '*' ) {// multi-line comment
216 while ( Good() ) {
217 char c1 = GetNextChar();
218 if ( ( c1 == '*' ) && ( PeekNextChar() == '/' ) ) {
219 GetNextChar();
220 break;
221 }
222 }
223 goto start;
224 }
225 default:
226 while ( Good() && PeekNextChar() != '=' ) {
227 unsigned char c_ = GetNextChar();
228 token.value_s += c_;
229 }
230 token.type = Token::type_entry_name;
231 return;
232 }
233 }
234
SkipSpaces()235 void Tokenizer::SkipSpaces() {
236 while ( Good() && IsWhitespace( PeekNextChar() ) ) {
237 GetNextChar();
238 }
239 }
240
GetToken(int i)241 Token Tokenizer::GetToken( int i ) {
242 int p = buffer_pos + i;
243 if ( p < 0 )return Token();
244 while ( int( token_buffer.size() ) < p + 1 ) {
245 Token t;
246 ReadToken( t );
247 if ( t.IsEOF() )return t;
248 token_buffer.push_back( t );
249 }
250
251 return token_buffer[p];
252 }
253
Step(int i)254 void Tokenizer::Step( int i ) {
255 buffer_pos += i;
256 }
257 namespace SL {
~Node()258 Node::~Node() {
259 //if(parent)parent->Remove(name);
260 }
261
Parent() const262 DataList* Node::Parent() const { // parent list
263 return parent;
264 }
265
IsChildOf(DataList * what) const266 bool Node::IsChildOf( DataList *what ) const {
267 DataList *current = Parent();
268 while ( current ) {
269 if ( current == what )return true;
270 current = current->Parent();
271 }
272 return false;
273 }
274
ListRemove()275 void Node::ListRemove() {
276 //if(parent->list_first==this)parent->list_first=next;
277 //if(parent->list_last==this)parent->list_last=prev;
278 if ( list_prev ) {
279 list_prev->list_next = this->list_next;
280 }
281 if ( list_next ) {
282 list_next->list_prev = this->list_prev;
283 }
284 list_prev = NULL;
285 list_next = NULL;
286 }
287
ListInsertAfter(Node * what)288 void Node::ListInsertAfter( Node *what ) {
289 ListRemove();
290 if ( !what )return;
291 this->list_next = what->list_next;
292 if ( what->list_next )what->list_next->list_prev = this;
293 what->list_next = this;
294 this->list_prev = what;
295 }
296
Name()297 wxString Node::Name() {
298 return name;
299 }
SetName(const wxString & name_)300 bool Node::SetName( const wxString &name_ ) {
301 if ( parent ) {
302 return parent->Rename( name, name_ );
303 }
304 name = name_;
305 return true;
306 }
307
Save(TDFWriter &)308 void Node::Save( TDFWriter &/*unused*/ ) {
309 /// nothing to save there.
310 }
Load(Tokenizer &)311 void Node::Load( Tokenizer &/*unused*/ ) {
312 /// nothing to load there.
313 //ASSERT_LOGIC(0,_T("this function should not be called."));
314 }
315
316 /// ***********************************************************
317 /// class DataList
318 /// ***********************************************************
319
DataList()320 DataList::DataList() {
321 //parent = NULL;
322 list_loop.list_prev = &list_loop;
323 list_loop.list_next = &list_loop;
324 list_loop.parent = this;
325 list_loop.Reference();
326 }
327
~DataList()328 DataList::~DataList() {// disconnect from childs
329 PNode node = First();
330 while ( node.Ok() && node != End() ) {
331 //std::cout<<"printing"<<std::endl;
332 PNode nextnode = Next( node );
333 node->parent = NULL;
334 node->ListRemove();
335 node = nextnode;
336 }
337 }
338
Insert(PNode node)339 bool DataList::Insert( PNode node )/// return false if such entry already exists.
340 {
341 if ( !node.Ok() )return false;
342 bool inserted = nodes.insert( std::pair<wxString, PNode>( ( *node ).name.Lower(), node ) ).second;
343 if ( !inserted )return false;
344
345 node->parent = this;
346 node->ListInsertAfter( list_loop.list_prev );
347 return true;
348 }
349
InsertAt(PNode node,PNode where)350 bool DataList::InsertAt( PNode node, PNode where )/// return false if such entry already exists.
351 {
352 if ( !node.Ok() )return false;
353 if ( !( where->list_prev ) )return false;
354 bool inserted = nodes.insert( std::pair<wxString, PNode>( ( *node ).name, node ) ).second;
355 if ( !inserted )return false;
356
357 node->parent = this;
358 node->ListInsertAfter( where->list_prev );
359 return true;
360 }
361
362 #ifdef use_std_string
363 static const char* rename_prefix = "!";
364 #else
365 static const wxChar* rename_prefix = _T( "!" );
366 #endif
367
InsertRename(PNode node)368 void DataList::InsertRename( PNode node ) {/// rename if such entry already exists. str contains new name.
369 if ( !node.Ok() )return;
370
371 if ( !Insert( node ) ) {
372 wxString original_name = node->Name();
373 for ( int n = 0;n < 10000;++n ) {
374 //wxString tmp=str+wxString(rename_prefix);
375 #ifdef use_std_string
376 std::ostringstream os;
377 os << original_name << rename_prefix << n;
378 node->name = os.str();
379 #else
380 wxString tmp;
381 tmp << original_name;
382 tmp << rename_prefix;
383 tmp << n;
384 node->name = tmp;
385 #endif
386 if ( Insert( node ) ) {
387 return;
388 }
389 }
390 wxLogError( _T( "insertRename: iterated over 10 000 names, way too many" ) );
391 }
392 }
393
InsertRenameAt(PNode node,PNode where)394 void DataList::InsertRenameAt( PNode node, PNode where ) {// rename if such entry already exists. str contains new name.
395 if ( !node.Ok() )return;
396 if ( !where->list_prev )return;
397
398 if ( !InsertAt( node, where ) ) {
399 for ( int n = 0;n < 10000;++n ) {
400
401 #ifdef use_std_string
402 std::ostringstream os;
403 os << node->Name() << rename_prefix << n;
404 node->name = os.str();
405 #else
406 wxString tmp;
407 tmp << ( node->Name() );
408 tmp << rename_prefix;
409 tmp << n;
410 node->name = tmp;
411 #endif
412 if ( InsertAt( node, where ) ) {
413 return;
414 }
415 }
416 wxLogError( _T( "insertRename: iterated over 10 000 names, way too many" ) );
417 }
418 }
419
Remove(const wxString & str)420 bool DataList::Remove( const wxString &str ) {
421 //PNode node=nodes.find(str.Lower())->last;
422 PNode node = Find( str );
423 if ( !node.Ok() )return false;
424 if ( nodes.erase( str.Lower() ) <= 0 ) return false;
425
426 node->parent = NULL;
427 node->ListRemove();
428 return true;
429 }
430
Remove(PNode node)431 bool DataList::Remove( PNode node ) {
432 if ( !node.Ok() )return false;
433 if ( nodes.erase( node->Name().Lower() ) <= 0 ) return false;
434
435 node->parent = NULL;
436 node->ListRemove();
437 return true;
438 }
439
Rename(const wxString & old_name,const wxString & new_name)440 bool DataList::Rename( const wxString &old_name, const wxString &new_name ) {
441 // check that new name is not used up.
442 if ( nodes.find( new_name.Lower() ) != nodes.end() )return false;
443 nodes_iterator i = nodes.find( old_name.Lower() );
444 if ( i == nodes.end() )return false;
445 PNode node = i->second;
446
447 ASSERT_LOGIC( node.Ok(), _T( "Internal TDF tree consistency (1)" ) );
448 ASSERT_LOGIC( node->Name().Lower() == old_name.Lower(), _T( "Internal TDF tree consistency (2)" ) );
449
450 node->name = new_name.Lower();
451 nodes.erase( i );
452 bool inserted = nodes.insert( std::pair<wxString, PNode>( ( *node ).name.Lower(), node ) ).second;
453 ASSERT_LOGIC( inserted, _T( "DataList::Rename failed" ) );
454 return inserted;
455 }
456
457 /// find by name. unused.
Find(const wxString & str)458 PNode DataList::Find( const wxString &str ) {
459 if ( str == _T( ".." ) )return Parent();
460 if ( str == _T( "." ) )return this;
461 nodes_iterator i = nodes.find( str.Lower() );
462 if ( i != nodes.end() ) {
463 ASSERT_LOGIC( i->second->Name().Lower() == str.Lower(), _T( "Internal TDF tree consistency (3)" ) );
464 return i->second;
465 }
466 return NULL;
467 }
468
Path()469 wxString DataList::Path() {
470 wxString result;
471 PDataList tmp( this );
472 while ( tmp.Ok() ) {
473 result = wxString( _T( "/" ) ) + tmp->Name();
474 tmp = tmp->Parent();
475 }
476 return name;
477 }
478
FindByPath(const wxString & str)479 PNode DataList::FindByPath( const wxString &str ) {
480 if ( str.empty() )return this;
481 int i = 0;
482 wxString buff;
483 PDataList current_dir( this );
484 if ( str[i] == '/' ) {// go to root
485 PDataList tmp = Parent();
486 while ( tmp.Ok() ) {
487 current_dir = tmp;
488 tmp = tmp->Parent();
489 }
490 }
491 else {
492 buff += str[0];
493
494 }
495 i = 1;
496 while ( ( unsigned int )( i ) < str.size() ) {
497 if ( str[i] == '/' ) {
498 if ( buff == _T( ".." ) ) {
499 current_dir = current_dir->Parent();
500 if ( !current_dir.Ok() )
501 return NULL;
502 }
503 else if ( buff != _T( "." ) && !buff.empty() ) {//
504 PNode node = current_dir->Find( buff );
505 if ( !node.Ok() )
506 return NULL;
507 PDataList datalist( node );
508 if ( datalist.Ok() ) {
509 current_dir = datalist;
510 }
511 else
512 return NULL;
513 }
514 buff = wxEmptyString;
515 }
516 else {
517 buff += str[i];
518 }
519 ++i;
520 }
521 if ( current_dir.Ok() ) {
522 if ( !buff.empty() ) {
523 return current_dir->Find( buff );
524 }
525 else
526 return PNode( current_dir );
527 }
528 else {
529 return NULL;
530 }
531 }
532
Next(PNode what)533 PNode DataList::Next( PNode what ) {
534 if ( what.Ok() )return what->list_next;
535 return NULL;
536 }
Prev(PNode what)537 PNode DataList::Prev( PNode what ) {
538 if ( what.Ok() )return what->list_prev;
539 return NULL;
540 }
End()541 PNode DataList::End() {
542 return PNode( &list_loop );
543 }
First()544 PNode DataList::First() {
545 return PNode( list_loop.list_next );
546 }
Last()547 PNode DataList::Last() {
548 return PNode( list_loop.list_prev );
549 }
550
551 /*
552 void DataList::PrintContent(std::ostream &s) {
553 PNode node=First();
554
555 while(node.Ok() && node!=End()){
556 //std::cout<<"printing"<<std::endl;
557 #ifdef use_std_string
558 s<<std::endl<<"'"<<node->Name()<<"'={";
559 node->PrintContent(s);
560 s<<"}"<<std::endl;
561 #else
562 s<<std::endl<<"'"<<node->Name().mb_str()<<"'={";
563 node->PrintContent(s);
564 s<<"}"<<std::endl;
565 #endif
566 node=Next(node);
567 }
568 }*/
Save(TDFWriter & f)569 void DataList::Save( TDFWriter &f ) {
570 PNode node = First();
571 if ( node == End() )return;
572
573 while ( node.Ok() && node != End() ) {
574 // if class name is not set properly, continue
575 //if(node->ClassName().empty())continue;
576 PDataList list( node );
577 if ( list.Ok() ) {
578 f.EnterSection( list->Name() );
579 list->Save( f );
580 f.LeaveSection();
581 } else {
582 PDataLeaf leaf( node );
583 if ( leaf.Ok() ) {
584 leaf->Save( f );
585 }
586 }
587 node = Next( node );
588 }
589
590 }
591
Load(Tokenizer & f)592 void DataList::Load( Tokenizer &f ) {
593 while ( f.Good() ) {
594 Token t = f.TakeToken();
595 switch ( t.type ) {
596 case Token::type_leave_section:
597 case Token::type_eof:
598 return;
599 case Token::type_entry_name:
600 {
601 PDataLeaf new_leaf( new DataLeaf );
602 new_leaf->SetName( t.value_s );
603 new_leaf->Load( f );
604 Insert( PNode( new_leaf ) );
605 }
606 break;
607
608 case Token::type_section_name:
609 {
610 Token t2 = f.TakeToken();
611 if ( t2.type != Token::type_enter_section ) {
612 f.ReportError( t, _T( "'{' expected" ) );
613 } else {
614 PDataList new_list( new DataList );
615 new_list->SetName( t.value_s );
616 new_list->Load( f );// will eat the '}'
617 Insert( PNode( new_list ) );
618 }
619 }
620 break;
621 default:
622 f.ReportError( t, _T( "[sectionname] or entryname= expected." ) );
623 }
624
625 }
626 }
627
628
GetInt(const wxString & f_name,int default_value,bool * it_worked)629 int DataList::GetInt( const wxString &f_name, int default_value, bool *it_worked ) {
630 PDataLeaf leaf( Find( f_name ) );
631 if ( !leaf.ok() ) {
632 if ( it_worked ) {
633 *it_worked = false;
634 }
635 return default_value;
636 }
637 wxString s = leaf->GetValue();
638 long result = default_value;
639 if ( !s.ToLong( &result ) ) {
640 if ( it_worked ) {
641 *it_worked = false;
642 }
643 return result;
644 }
645 if ( it_worked ) {
646 *it_worked = true;
647 }
648 return result;
649 }
GetDouble(const wxString & f_name,double default_value,bool * it_worked)650 double DataList::GetDouble( const wxString &f_name, double default_value, bool *it_worked ) {
651 PDataLeaf leaf( Find( f_name ) );
652 if ( !leaf.ok() ) {
653 if ( it_worked ) {
654 *it_worked = false;
655 }
656 return default_value;
657 }
658 wxString s = leaf->GetValue();
659 double result = default_value;
660 if ( !s.ToDouble( &result ) ) {
661 if ( it_worked ) {
662 *it_worked = false;
663 }
664 return result;
665 }
666 if ( it_worked ) {
667 *it_worked = true;
668 }
669 return result;
670
671 }
GetString(const wxString & f_name,const wxString & default_value,bool * it_worked)672 wxString DataList::GetString( const wxString &f_name, const wxString &default_value, bool *it_worked ) {
673 PDataLeaf leaf( Find( f_name ) );
674 if ( !leaf.ok() ) {
675 if ( it_worked ) {
676 *it_worked = false;
677 }
678 return default_value;
679 }
680 if ( it_worked ) {
681 *it_worked = true;
682 }
683 return leaf->GetValue();
684 }
GetDoubleArray(const wxString & f_name,int n_values,double * values)685 int DataList::GetDoubleArray( const wxString &f_name, int n_values, double *values ) {
686 PDataLeaf leaf( Find( f_name ) );
687 if ( !leaf.ok() ) {
688 return 0;
689 }
690 wxStringTokenizer tok( leaf->GetValue() );
691 int i = 0;
692 int values_read = 0;
693 for ( i = 0;i < n_values && tok.HasMoreTokens();++i ) {
694 wxString s = tok.GetNextToken();
695 if ( s.ToDouble( values + i ) )values_read++;
696 }
697 return values_read;
698 }
699
GetColour(const wxString & f_name,const wxColour & default_value,bool * it_worked)700 wxColour DataList::GetColour( const wxString &f_name, const wxColour &default_value, bool *it_worked ) {
701 double values[3];
702 if ( GetDoubleArray( f_name, 3, values ) != 3 ) {
703 if ( it_worked ) {
704 *it_worked = false;
705 }
706 return default_value;
707 }
708 if ( it_worked ) {
709 *it_worked = true;
710 }
711 return wxColour( values[0]*255.99, values[1]*255.99, values[2]*255.99 );
712 }
713
714
GetValue()715 wxString DataLeaf::GetValue() {
716 return value;
717 }
SetValue(const wxString & value_)718 void DataLeaf::SetValue( const wxString &value_ ) {
719 value = value_;
720 }
721
Save(TDFWriter & f)722 void DataLeaf::Save( TDFWriter &f ) {
723 f.Append( Name(), GetValue() );
724 }
Load(Tokenizer & f)725 void DataLeaf::Load( Tokenizer &f ) {
726 Token t = f.TakeToken();
727 value = t.value_s;
728 t = f.TakeToken();
729 if ( t.value_s != _T( ";" ) ) {
730 f.ReportError( t, _T( "; expected" ) );
731 }
732 }
733 } // end namespace SL
734
ParseTDF(std::istream & s,int * error_count)735 SL::PDataList ParseTDF( std::istream &s, int *error_count ) {
736 Tokenizer t;
737 t.EnterStream( s );
738 SL::PDataList result( new SL::DataList );
739 result->Load( t );
740 if ( error_count ) {
741 *error_count = t.NumErrors();
742 }
743 return result;
744 }
745