1 /**********************************************************
2 * Version $Id$
3 *********************************************************/
4
5 ///////////////////////////////////////////////////////////
6 // //
7 // SAGA //
8 // //
9 // System for Automated Geoscientific Analyses //
10 // //
11 // Application Programming Interface //
12 // //
13 // Library: SAGA_API //
14 // //
15 //-------------------------------------------------------//
16 // //
17 // metadata.cpp //
18 // //
19 // Copyright (C) 2009 by Olaf Conrad //
20 // //
21 //-------------------------------------------------------//
22 // //
23 // This file is part of 'SAGA - System for Automated //
24 // Geoscientific Analyses'. //
25 // //
26 // This library is free software; you can redistribute //
27 // it and/or modify it under the terms of the GNU Lesser //
28 // General Public License as published by the Free //
29 // Software Foundation, either version 2.1 of the //
30 // License, or (at your option) any later version. //
31 // //
32 // This library is distributed in the hope that it will //
33 // be useful, but WITHOUT ANY WARRANTY; without even the //
34 // implied warranty of MERCHANTABILITY or FITNESS FOR A //
35 // PARTICULAR PURPOSE. See the GNU Lesser General Public //
36 // License for more details. //
37 // //
38 // You should have received a copy of the GNU Lesser //
39 // General Public License along with this program; if //
40 // not, see <http://www.gnu.org/licenses/>. //
41 // //
42 //-------------------------------------------------------//
43 // //
44 // contact: Olaf Conrad //
45 // Institute of Geography //
46 // University of Hamburg //
47 // Germany //
48 // //
49 // e-mail: oconrad@saga-gis.org //
50 // //
51 ///////////////////////////////////////////////////////////
52
53 //---------------------------------------------------------
54
55 ///////////////////////////////////////////////////////////
56 // //
57 // //
58 // //
59 ///////////////////////////////////////////////////////////
60
61 //---------------------------------------------------------
62 #include <wx/xml/xml.h>
63 #include <wx/wfstream.h>
64 #include <wx/sstream.h>
65 #include <wx/mstream.h>
66 #include <wx/protocol/http.h>
67
68 #include "metadata.h"
69 #include "table.h"
70
71
72 ///////////////////////////////////////////////////////////
73 // //
74 // //
75 // //
76 ///////////////////////////////////////////////////////////
77
78 //---------------------------------------------------------
CSG_MetaData(void)79 CSG_MetaData::CSG_MetaData(void)
80 {
81 _On_Construction();
82 }
83
Create(void)84 bool CSG_MetaData::Create(void)
85 {
86 return( true );
87 }
88
89 //---------------------------------------------------------
CSG_MetaData(const CSG_MetaData & MetaData)90 CSG_MetaData::CSG_MetaData(const CSG_MetaData &MetaData)
91 {
92 _On_Construction();
93
94 Create(MetaData);
95 }
96
Create(const CSG_MetaData & MetaData)97 bool CSG_MetaData::Create(const CSG_MetaData &MetaData)
98 {
99 return( Assign(MetaData) );
100 }
101
102 //---------------------------------------------------------
CSG_MetaData(const CSG_String & File,const SG_Char * Extension)103 CSG_MetaData::CSG_MetaData(const CSG_String &File, const SG_Char *Extension)
104 {
105 _On_Construction();
106
107 Create(File, Extension);
108 }
109
Create(const CSG_String & File,const SG_Char * Extension)110 bool CSG_MetaData::Create(const CSG_String &File, const SG_Char *Extension)
111 {
112 return( Load(File, Extension) );
113 }
114
115 //---------------------------------------------------------
CSG_MetaData(CSG_File & Stream)116 CSG_MetaData::CSG_MetaData(CSG_File &Stream)
117 {
118 _On_Construction();
119
120 Create(Stream);
121 }
122
Create(CSG_File & Stream)123 bool CSG_MetaData::Create(CSG_File &Stream)
124 {
125 return( Load(Stream) );
126 }
127
128 //---------------------------------------------------------
CSG_MetaData(CSG_MetaData * pParent)129 CSG_MetaData::CSG_MetaData(CSG_MetaData *pParent)
130 {
131 _On_Construction();
132
133 m_pParent = pParent;
134 }
135
136 //---------------------------------------------------------
_On_Construction(void)137 void CSG_MetaData::_On_Construction(void)
138 {
139 m_pParent = NULL;
140
141 m_Children.Create(sizeof(CSG_MetaData **), 0, SG_ARRAY_GROWTH_1);
142 }
143
144 //---------------------------------------------------------
~CSG_MetaData(void)145 CSG_MetaData::~CSG_MetaData(void)
146 {
147 Destroy();
148 }
149
150 //---------------------------------------------------------
Destroy(void)151 void CSG_MetaData::Destroy(void)
152 {
153 CSG_MetaData **m_pChildren = (CSG_MetaData **)m_Children.Get_Array();
154
155 for(int i=0; i<Get_Children_Count(); i++)
156 {
157 delete(m_pChildren[i]);
158 }
159
160 m_Children.Destroy();
161
162 // m_pParent = NULL;
163
164 // m_Name .Clear();
165 // m_Content .Clear();
166
167 m_Prop_Names .Clear();
168 m_Prop_Values .Clear();
169 }
170
171
172 ///////////////////////////////////////////////////////////
173 // //
174 ///////////////////////////////////////////////////////////
175
176 //---------------------------------------------------------
Add_Child(void)177 CSG_MetaData * CSG_MetaData::Add_Child(void)
178 {
179 return( Ins_Child(-1) );
180 }
181
Add_Child(const CSG_String & Name)182 CSG_MetaData * CSG_MetaData::Add_Child(const CSG_String &Name)
183 {
184 return( Ins_Child(Name, -1) );
185 }
186
Add_Child(const CSG_String & Name,const CSG_String & Content)187 CSG_MetaData * CSG_MetaData::Add_Child(const CSG_String &Name, const CSG_String &Content)
188 {
189 return( Ins_Child(Name, Content, -1) );
190 }
191
Add_Child(const CSG_String & Name,double Content)192 CSG_MetaData * CSG_MetaData::Add_Child(const CSG_String &Name, double Content)
193 {
194 return( Ins_Child(Name, SG_Get_String(Content, -16), -1) );
195 }
196
Add_Child(const CSG_String & Name,int Content)197 CSG_MetaData * CSG_MetaData::Add_Child(const CSG_String &Name, int Content)
198 {
199 return( Ins_Child(Name, CSG_String::Format(SG_T("%d"), Content), -1) );
200 }
201
Add_Child(const CSG_MetaData & MetaData,bool bAddChildren)202 CSG_MetaData * CSG_MetaData::Add_Child(const CSG_MetaData &MetaData, bool bAddChildren)
203 {
204 return( Ins_Child(MetaData, -1, bAddChildren) );
205 }
206
207
208 ///////////////////////////////////////////////////////////
209 // //
210 ///////////////////////////////////////////////////////////
211
212 //---------------------------------------------------------
Ins_Child(int Position)213 CSG_MetaData * CSG_MetaData::Ins_Child(int Position)
214 {
215 if( !m_Children.Inc_Array() )
216 {
217 return( NULL );
218 }
219
220 CSG_MetaData **pChildren = (CSG_MetaData **)m_Children.Get_Array();
221
222 if( Position < 0 || Position >= Get_Children_Count() )
223 {
224 Position = Get_Children_Count() - 1;
225 }
226
227 for(int i=Get_Children_Count()-1; i>Position; i--)
228 {
229 pChildren[i] = pChildren[i - 1];
230 }
231
232 return( pChildren[Position] = new CSG_MetaData(this) );
233 }
234
235 //---------------------------------------------------------
Ins_Child(const CSG_String & Name,const CSG_String & Content,int Position)236 CSG_MetaData * CSG_MetaData::Ins_Child(const CSG_String &Name, const CSG_String &Content, int Position)
237 {
238 CSG_MetaData *pChild = Ins_Child(Position);
239
240 if( pChild )
241 {
242 pChild->m_Name = Name;
243 pChild->m_Content = Content;
244 }
245
246 return( pChild );
247 }
248
Ins_Child(const CSG_String & Name,int Position)249 CSG_MetaData * CSG_MetaData::Ins_Child(const CSG_String &Name, int Position)
250 {
251 return( Ins_Child(Name, CSG_String(""), Position) );
252 }
253
Ins_Child(const CSG_String & Name,double Content,int Position)254 CSG_MetaData * CSG_MetaData::Ins_Child(const CSG_String &Name, double Content, int Position)
255 {
256 return( Ins_Child(Name, SG_Get_String(Content, -16), Position) );
257 }
258
Ins_Child(const CSG_String & Name,int Content,int Position)259 CSG_MetaData * CSG_MetaData::Ins_Child(const CSG_String &Name, int Content, int Position)
260 {
261 return( Ins_Child(Name, CSG_String::Format(SG_T("%d"), Content), Position) );
262 }
263
Ins_Child(const CSG_MetaData & MetaData,int Position,bool bAddChildren)264 CSG_MetaData * CSG_MetaData::Ins_Child(const CSG_MetaData &MetaData, int Position, bool bAddChildren)
265 {
266 CSG_MetaData *pChild = Ins_Child(Position);
267
268 if( pChild )
269 {
270 pChild->Assign(MetaData, bAddChildren);
271 }
272
273 return( pChild );
274 }
275
276
277 ///////////////////////////////////////////////////////////
278 // //
279 ///////////////////////////////////////////////////////////
280
281 //---------------------------------------------------------
Mov_Child(int from_Index,int to_Index)282 bool CSG_MetaData::Mov_Child(int from_Index, int to_Index)
283 {
284 if( from_Index < 0 || from_Index >= Get_Children_Count()
285 || to_Index < 0 || to_Index >= Get_Children_Count() )
286 {
287 return( false );
288 }
289
290 if( from_Index != to_Index )
291 {
292 CSG_MetaData **pChildren = (CSG_MetaData **)m_Children.Get_Array();
293 CSG_MetaData *pChild = pChildren[from_Index];
294
295 if( from_Index < to_Index )
296 {
297 for(int i=from_Index; i<to_Index; i++)
298 {
299 pChildren[i] = pChildren[i + 1];
300 }
301 }
302 else // if( from_Index > to_Index )
303 {
304 for(int i=from_Index; i>to_Index; i--)
305 {
306 pChildren[i] = pChildren[i - 1];
307 }
308 }
309
310 pChildren[to_Index] = pChild;
311 }
312
313 return( true );
314 }
315
316
317 ///////////////////////////////////////////////////////////
318 // //
319 ///////////////////////////////////////////////////////////
320
321 //---------------------------------------------------------
Del_Child(int Index)322 bool CSG_MetaData::Del_Child(int Index)
323 {
324 if( Index >= 0 && Index < Get_Children_Count() )
325 {
326 CSG_MetaData **pChildren = (CSG_MetaData **)m_Children.Get_Array();
327
328 delete(pChildren[Index]);
329
330 for(int i=Index, j=Index+1; j<Get_Children_Count(); i++, j++)
331 {
332 pChildren[i] = pChildren[j];
333 }
334
335 m_Children.Dec_Array();
336
337 return( true );
338 }
339
340 return( false );
341 }
342
343 //---------------------------------------------------------
Add_Children(const CSG_MetaData & MetaData)344 bool CSG_MetaData::Add_Children(const CSG_MetaData &MetaData)
345 {
346 if( &MetaData != this )
347 {
348 for(int i=0; i<MetaData.Get_Children_Count(); i++)
349 {
350 Add_Child(MetaData[i], true);
351 }
352 }
353
354 return( true );
355 }
356
357 //---------------------------------------------------------
358 /**
359 * Deletes children if depth level is reached, i.e. if depth level equals zero
360 * all children of the node will be deleted, if it is one only the grandchildren
361 * will be affected, and so on.
362 * If Name is a valid string, only those children are taken into account that
363 * have this name.
364 */
365 //---------------------------------------------------------
Del_Children(int Depth,const SG_Char * Name)366 bool CSG_MetaData::Del_Children(int Depth, const SG_Char *Name)
367 {
368 if( Depth < 0 )
369 {
370 // nop
371 }
372 else if( Name && *Name )
373 {
374 for(int i=Get_Children_Count()-1; i>=0; i--)
375 {
376 if( Get_Child(i)->Get_Name().CmpNoCase(Name) )
377 {
378 Get_Child(i)->Del_Children(Depth, Name);
379 }
380 else if( Depth > 0 )
381 {
382 Get_Child(i)->Del_Children(Depth - 1, Name);
383 }
384 else
385 {
386 Del_Child(i);
387 }
388 }
389 }
390 else if( Depth > 0 )
391 {
392 for(int i=0; i<Get_Children_Count(); i++)
393 {
394 Get_Child(i)->Del_Children(Depth - 1, Name);
395 }
396 }
397 else
398 {
399 for(int i=0; i<Get_Children_Count(); i++)
400 {
401 delete(Get_Child(i));
402 }
403
404 m_Children.Destroy();
405 }
406
407 return( true );
408 }
409
410 //---------------------------------------------------------
_Get_Child(const CSG_String & Name) const411 int CSG_MetaData::_Get_Child(const CSG_String &Name) const
412 {
413 for(int i=0; i<Get_Children_Count(); i++)
414 {
415 if( Name.CmpNoCase(Get_Child(i)->Get_Name()) == 0 )
416 {
417 return( i );
418 }
419 }
420
421 return( -1 );
422 }
423
424
425 ///////////////////////////////////////////////////////////
426 // //
427 ///////////////////////////////////////////////////////////
428
429 //---------------------------------------------------------
Cmp_Name(const CSG_String & String,bool bNoCase) const430 bool CSG_MetaData::Cmp_Name(const CSG_String &String, bool bNoCase) const
431 {
432 return( bNoCase ? !m_Name.CmpNoCase(String) : !m_Name.Cmp(String) );
433 }
434
435
436 ///////////////////////////////////////////////////////////
437 // //
438 ///////////////////////////////////////////////////////////
439
440 //---------------------------------------------------------
Fmt_Content(const char * Format,...)441 void CSG_MetaData::Fmt_Content(const char *Format, ...)
442 {
443 wxString s;
444
445 va_list argptr;
446
447 #ifdef _SAGA_LINUX
448 wxString _Format(Format); _Format.Replace("%s", "%ls"); // workaround as we only use wide characters since wx 2.9.4 so interpret strings as multibyte
449 va_start(argptr, _Format);
450 s.PrintfV(_Format, argptr);
451 #else
452 va_start(argptr, Format);
453 s.PrintfV(Format, argptr);
454 #endif
455
456 m_Content = CSG_String(&s);
457
458 va_end(argptr);
459 }
460
461 //---------------------------------------------------------
Fmt_Content(const wchar_t * Format,...)462 void CSG_MetaData::Fmt_Content(const wchar_t *Format, ...)
463 {
464 wxString s;
465
466 va_list argptr;
467
468 #ifdef _SAGA_LINUX
469 wxString _Format(Format); _Format.Replace("%s", "%ls"); // workaround as we only use wide characters since wx 2.9.4 so interpret strings as multibyte
470 va_start(argptr, _Format);
471 s.PrintfV(_Format, argptr);
472 #else
473 va_start(argptr, Format);
474 s.PrintfV(Format, argptr);
475 #endif
476
477 m_Content = CSG_String(&s);
478
479 va_end(argptr);
480 }
481
482 //---------------------------------------------------------
Cmp_Content(const CSG_String & String,bool bNoCase) const483 bool CSG_MetaData::Cmp_Content(const CSG_String &String, bool bNoCase) const
484 {
485 return( bNoCase ? !m_Content.CmpNoCase(String) : !m_Content.Cmp(String) );
486 }
487
488
489 ///////////////////////////////////////////////////////////
490 // //
491 ///////////////////////////////////////////////////////////
492
493 //---------------------------------------------------------
Add_Property(const CSG_String & Name,const CSG_String & Value)494 bool CSG_MetaData::Add_Property(const CSG_String &Name, const CSG_String &Value)
495 {
496 if( !Value.is_Empty() &&_Get_Property(Name) < 0 )
497 {
498 m_Prop_Names .Add(Name );
499 m_Prop_Values.Add(Value);
500
501 return( true );
502 }
503
504 return( false );
505 }
506
Add_Property(const CSG_String & Name,double Value)507 bool CSG_MetaData::Add_Property(const CSG_String &Name, double Value)
508 {
509 return( Add_Property(Name, CSG_String::Format(SG_T("%f"), Value)) );
510 }
511
Add_Property(const CSG_String & Name,int Value)512 bool CSG_MetaData::Add_Property(const CSG_String &Name, int Value)
513 {
514 return( Add_Property(Name, CSG_String::Format(SG_T("%d"), Value)) );
515 }
516
517 //---------------------------------------------------------
Del_Property(const CSG_String & Name)518 bool CSG_MetaData::Del_Property(const CSG_String &Name)
519 {
520 for(int i=0; i<Get_Property_Count(); i++)
521 {
522 if( !Get_Property_Name(i).CmpNoCase(Name) )
523 {
524 return( Del_Property(i) );
525 }
526 }
527
528 return( false );
529 }
530
Del_Property(int i)531 bool CSG_MetaData::Del_Property(int i)
532 {
533 if( i >= 0 && i < Get_Property_Count() )
534 {
535 m_Prop_Names .Del(i);
536 m_Prop_Values.Del(i);
537
538 return( true );
539 }
540
541 return( false );
542 }
543
544 //---------------------------------------------------------
Set_Property(const CSG_String & Name,const CSG_String & Value,bool bAddIfNotExists)545 bool CSG_MetaData::Set_Property(const CSG_String &Name, const CSG_String &Value, bool bAddIfNotExists)
546 {
547 int Index;
548
549 if( (Index = _Get_Property(Name)) >= 0 )
550 {
551 m_Prop_Values[Index] = Value;
552
553 return( true );
554 }
555 else if( bAddIfNotExists )
556 {
557 m_Prop_Names .Add(Name);
558 m_Prop_Values .Add(Value);
559
560 return( true );
561 }
562
563 return( false );
564 }
565
Set_Property(const CSG_String & Name,double Value,bool bAddIfNotExists)566 bool CSG_MetaData::Set_Property(const CSG_String &Name, double Value, bool bAddIfNotExists)
567 {
568 return( Set_Property(Name, CSG_String::Format(SG_T("%f"), Value, bAddIfNotExists)) );
569 }
570
Set_Property(const CSG_String & Name,int Value,bool bAddIfNotExists)571 bool CSG_MetaData::Set_Property(const CSG_String &Name, int Value, bool bAddIfNotExists)
572 {
573 return( Set_Property(Name, CSG_String::Format(SG_T("%d"), Value, bAddIfNotExists)) );
574 }
575
576 //---------------------------------------------------------
Get_Property(const CSG_String & Name,CSG_String & Value) const577 bool CSG_MetaData::Get_Property(const CSG_String &Name, CSG_String &Value) const
578 {
579 const SG_Char *cString = Get_Property(Name);
580
581 if( cString )
582 {
583 Value = cString;
584
585 return( true );
586 }
587
588 return( false );
589 }
590
Get_Property(const CSG_String & Name,double & Value) const591 bool CSG_MetaData::Get_Property(const CSG_String &Name, double &Value) const
592 {
593 CSG_String s;
594
595 return( Get_Property(Name, s) && s.asDouble(Value) );
596 }
597
Get_Property(const CSG_String & Name,int & Value) const598 bool CSG_MetaData::Get_Property(const CSG_String &Name, int &Value) const
599 {
600 CSG_String s;
601
602 return( Get_Property(Name, s) && s.asInt(Value) );
603 }
604
605 //---------------------------------------------------------
Cmp_Property(const CSG_String & Name,const CSG_String & String,bool bNoCase) const606 bool CSG_MetaData::Cmp_Property(const CSG_String &Name, const CSG_String &String, bool bNoCase) const
607 {
608 CSG_String s;
609
610 return( Get_Property(Name, s) && (bNoCase ? !s.CmpNoCase(String) : !s.Cmp(String)) );
611 }
612
613 //---------------------------------------------------------
_Get_Property(const CSG_String & Name) const614 int CSG_MetaData::_Get_Property(const CSG_String &Name) const
615 {
616 for(int i=0; i<m_Prop_Names.Get_Count(); i++)
617 {
618 if( Name.CmpNoCase(m_Prop_Names[i]) == 0 )
619 {
620 return( i );
621 }
622 }
623
624 return( -1 );
625 }
626
627
628 ///////////////////////////////////////////////////////////
629 // //
630 ///////////////////////////////////////////////////////////
631
632 //---------------------------------------------------------
asText(int Flags) const633 CSG_String CSG_MetaData::asText(int Flags) const
634 {
635 CSG_String s;
636
637 if( Flags == 0 )
638 {
639 for(int i=0; i<Get_Children_Count(); i++)
640 {
641 s += Get_Child(i)->Get_Name() + ":\t" + Get_Child(i)->Get_Content() + "\n";
642 }
643 }
644 else
645 {
646 wxXmlDocument XML;
647
648 wxXmlNode *pRoot = new wxXmlNode(NULL, wxXML_ELEMENT_NODE, Get_Name().c_str());
649
650 XML.SetRoot(pRoot);
651
652 _Save(pRoot);
653
654 wxStringOutputStream Stream;
655
656 XML.Save(Stream);
657
658 s = &Stream.GetString();
659
660 if( Flags == 2 ) // remove <xml>
661 {
662 s = s.AfterFirst('\n');
663 }
664 }
665
666 return( s );
667 }
668
669 //---------------------------------------------------------
Get_Table(int Flags) const670 CSG_Table CSG_MetaData::Get_Table(int Flags) const
671 {
672 CSG_Table t;
673
674 t.Add_Field("NAME" , SG_DATATYPE_String);
675 t.Add_Field("VALUE", SG_DATATYPE_String);
676
677 for(int i=0; i<Get_Children_Count(); i++)
678 {
679 CSG_Table_Record *r = t.Add_Record();
680
681 r->Set_Value(0, Get_Child(i)->Get_Name());
682 r->Set_Value(1, Get_Child(i)->Get_Content());
683 }
684
685 return( t );
686 }
687
688
689 ///////////////////////////////////////////////////////////
690 // //
691 ///////////////////////////////////////////////////////////
692
693 //---------------------------------------------------------
Assign(const CSG_MetaData & MetaData,bool bAddChildren)694 bool CSG_MetaData::Assign(const CSG_MetaData &MetaData, bool bAddChildren)
695 {
696 if( &MetaData != this )
697 {
698 Destroy();
699
700 Set_Name (MetaData.Get_Name ());
701 Set_Content (MetaData.Get_Content());
702
703 for(int i=0; i<MetaData.Get_Property_Count(); i++)
704 {
705 Add_Property(MetaData.Get_Property_Name(i), MetaData.Get_Property(i));
706 }
707
708 if( bAddChildren )
709 {
710 Add_Children(MetaData);
711 }
712 }
713
714 return( true );
715 }
716
717
718 ///////////////////////////////////////////////////////////
719 // //
720 ///////////////////////////////////////////////////////////
721
722 //---------------------------------------------------------
Load(const CSG_String & File,const SG_Char * Extension)723 bool CSG_MetaData::Load(const CSG_String &File, const SG_Char *Extension)
724 {
725 Destroy();
726
727 //-----------------------------------------------------
728 if( File.Find("http://") == 0 )
729 {
730 CSG_String s(File.Right(File.Length() - CSG_String("http://").Length()));
731
732 return( Load_HTTP(s.BeforeFirst('/'), s.AfterFirst('/')) );
733 }
734
735 //-----------------------------------------------------
736 CSG_String _File(SG_File_Make_Path("", File, Extension));
737
738 if( !SG_File_Exists(_File) )
739 {
740 return( false );
741 }
742
743 //-----------------------------------------------------
744 if( SG_File_Cmp_Extension(_File, "json") )
745 {
746 return( Load_JSON(_File) );
747 }
748
749 //-----------------------------------------------------
750 wxXmlDocument XML;
751
752 if( XML.Load(_File.c_str()) )
753 {
754 _Load(XML.GetRoot());
755
756 return( true );
757 }
758
759 //-----------------------------------------------------
760 return( false );
761 }
762
763 //---------------------------------------------------------
Load(CSG_File & File)764 bool CSG_MetaData::Load(CSG_File &File)
765 {
766 Destroy();
767
768 wxXmlDocument XML;
769
770 if( File.is_Reading() && XML.Load(*((wxInputStream *)File.Get_Stream())) )
771 {
772 _Load(XML.GetRoot());
773
774 return( true );
775 }
776
777 return( false );
778 }
779
780 //---------------------------------------------------------
_Load(wxXmlNode * pNode)781 void CSG_MetaData::_Load(wxXmlNode *pNode)
782 {
783 m_Name = pNode->GetName ().wc_str();
784 m_Content = pNode->GetNodeContent().wc_str();
785
786 //-----------------------------------------------------
787 wxXmlAttribute *pProperty = pNode->GetAttributes();
788
789 while( pProperty )
790 {
791 Add_Property(&pProperty->GetName(), &pProperty->GetValue());
792
793 pProperty = pProperty->GetNext();
794 }
795
796 //-----------------------------------------------------
797 wxXmlNode *pChild = pNode->GetChildren();
798
799 while( pChild )
800 {
801 if( pChild->GetType() != wxXML_TEXT_NODE )
802 {
803 Add_Child()->_Load(pChild);
804 }
805
806 pChild = pChild->GetNext();
807 }
808 }
809
810
811 ///////////////////////////////////////////////////////////
812 // //
813 ///////////////////////////////////////////////////////////
814
815 //---------------------------------------------------------
Save(const CSG_String & File,const SG_Char * Extension) const816 bool CSG_MetaData::Save(const CSG_String &File, const SG_Char *Extension) const
817 {
818 wxXmlDocument XML;
819
820 wxXmlNode *pRoot = new wxXmlNode(NULL, wxXML_ELEMENT_NODE, Get_Name().c_str());
821
822 XML.SetRoot(pRoot);
823
824 _Save(pRoot);
825
826 if( XML.Save(SG_File_Make_Path("", File, Extension).c_str()) )
827 {
828 return( true );
829 }
830
831 return( false );
832 }
833
834 //---------------------------------------------------------
Save(CSG_File & File) const835 bool CSG_MetaData::Save(CSG_File &File) const
836 {
837 wxXmlDocument XML;
838
839 wxXmlNode *pRoot = new wxXmlNode(NULL, wxXML_ELEMENT_NODE, Get_Name().c_str());
840
841 XML.SetRoot(pRoot);
842
843 _Save(pRoot);
844
845 if( File.is_Writing() && XML.Save(*((wxOutputStream *)File.Get_Stream())) )
846 {
847 return( true );
848 }
849
850 return( false );
851 }
852
853 //---------------------------------------------------------
_Save(wxXmlNode * pNode) const854 void CSG_MetaData::_Save(wxXmlNode *pNode) const
855 {
856 int i;
857
858 //-----------------------------------------------------
859 pNode->SetName (CSG_String(Get_Name().Length() ? Get_Name() : CSG_String("NODE")).c_str());
860 pNode->SetContent(Get_Content().c_str());
861
862 if( Get_Content().Length() > 0 || (Get_Property_Count() == 0 && Get_Children_Count() == 0) )
863 {
864 wxXmlNode *pChild = new wxXmlNode(pNode, wxXML_TEXT_NODE, SG_T("TEXT"));
865
866 pChild->SetContent(Get_Content().c_str());
867 }
868
869 //-----------------------------------------------------
870 for(i=0; i<Get_Property_Count(); i++)
871 {
872 pNode->AddAttribute(Get_Property_Name(i).c_str(), Get_Property(i));
873 }
874
875 //-----------------------------------------------------
876 for(i=Get_Children_Count()-1; i>=0; i--)
877 {
878 Get_Child(i)->_Save(new wxXmlNode(pNode, wxXML_ELEMENT_NODE, Get_Child(i)->Get_Name().c_str()));
879 }
880 }
881
882
883 ///////////////////////////////////////////////////////////
884 // //
885 ///////////////////////////////////////////////////////////
886
887 //---------------------------------------------------------
from_XML(const CSG_String & _XML)888 bool CSG_MetaData::from_XML(const CSG_String &_XML)
889 {
890 Destroy();
891
892 wxXmlDocument XML;
893
894 wxMemoryInputStream Stream((const void *)_XML.b_str(), (size_t)_XML.Length());
895
896 if( XML.Load(Stream) )
897 {
898 _Load(XML.GetRoot());
899
900 return( true );
901 }
902
903 return( false );
904 }
905
906 //---------------------------------------------------------
to_XML(CSG_String & _XML) const907 bool CSG_MetaData::to_XML(CSG_String &_XML) const
908 {
909 wxXmlDocument XML;
910
911 wxXmlNode *pRoot = new wxXmlNode(NULL, wxXML_ELEMENT_NODE, Get_Name().c_str());
912
913 XML.SetRoot(pRoot);
914
915 _Save(pRoot);
916
917 wxMemoryOutputStream Stream;
918
919 if( XML.Save(Stream) )
920 {
921 CSG_Array s(sizeof(char), Stream.GetSize());
922
923 Stream.CopyTo(s.Get_Array(), s.Get_Size());
924
925 _XML = (const char *)s.Get_Array();
926
927 return( true );
928 }
929
930 return( false );
931 }
932
933
934 ///////////////////////////////////////////////////////////
935 // //
936 ///////////////////////////////////////////////////////////
937
938 //---------------------------------------------------------
Load_HTTP(const CSG_String & Server,const CSG_String & Path,const SG_Char * Username,const SG_Char * Password)939 bool CSG_MetaData::Load_HTTP(const CSG_String &Server, const CSG_String &Path, const SG_Char *Username, const SG_Char *Password)
940 {
941 Destroy();
942
943 //-----------------------------------------------------
944 wxHTTP HTTP;
945
946 if( Username && *Username ) { HTTP.SetUser (Username); }
947 if( Password && *Password ) { HTTP.SetPassword(Password); }
948
949 wxString s = Server.c_str();
950
951 if( s.Find("http://") == 0 )
952 {
953 s = s.Right(s.Length() - wxString("http://").Length());
954 }
955
956 if( !HTTP.Connect(s) )
957 {
958 return( false );
959 }
960
961 //-----------------------------------------------------
962 s = Path.c_str();
963
964 if( s[0] != '/' )
965 {
966 s.Prepend("/");
967 }
968
969 wxInputStream *pStream = HTTP.GetInputStream(s);
970
971 if( !pStream )
972 {
973 return( false );
974 }
975
976 wxXmlDocument XML;
977
978 if( XML.Load(*pStream) )
979 {
980 _Load(XML.GetRoot());
981
982 delete(pStream);
983
984 return( true );
985 }
986
987 delete(pStream);
988
989 return( false );
990 }
991
992
993 ///////////////////////////////////////////////////////////
994 // //
995 ///////////////////////////////////////////////////////////
996
997 //---------------------------------------------------------
from_WKT(const CSG_String & WKT)998 bool CSG_MetaData::from_WKT(const CSG_String &WKT)
999 {
1000 return( false );
1001 }
1002
1003 //---------------------------------------------------------
to_WKT(CSG_String & WKT) const1004 bool CSG_MetaData::to_WKT(CSG_String &WKT) const
1005 {
1006 return( false );
1007 }
1008
1009
1010 ///////////////////////////////////////////////////////////
1011 // //
1012 ///////////////////////////////////////////////////////////
1013
1014 //---------------------------------------------------------
Load_JSON(const CSG_String & File)1015 bool CSG_MetaData::Load_JSON(const CSG_String &File)
1016 {
1017 CSG_File Stream; CSG_String JSON;
1018
1019 if( Stream.Open(File, SG_FILE_R, false) && Stream.Read(JSON, (size_t)Stream.Length()) > 0 )
1020 {
1021 return( from_JSON(JSON) );
1022 }
1023
1024 return( false );
1025 }
1026
1027 //---------------------------------------------------------
Save_JSON(const CSG_String & File) const1028 bool CSG_MetaData::Save_JSON(const CSG_String &File) const
1029 {
1030 return( false );
1031 }
1032
1033 //---------------------------------------------------------
from_JSON(const CSG_String & JSON)1034 bool CSG_MetaData::from_JSON(const CSG_String &JSON)
1035 {
1036 Destroy();
1037
1038 Set_Name("root");
1039
1040 CSG_MetaData *pNode = this;
1041
1042 const SG_Char *pc = JSON.c_str();
1043
1044 while( *pc )
1045 {
1046 CSG_String Element;
1047
1048 for(bool bQuota=false;;)
1049 {
1050 SG_Char c = *pc++;
1051
1052 if( !c || c == '\n' ) { break; } else
1053 {
1054 if( c == '\"' )
1055 {
1056 Element += c; bQuota = !bQuota;
1057 }
1058 else if( bQuota || (c != ' ' && c != '\t' && c != ',') )
1059 {
1060 Element += c;
1061 }
1062 }
1063 }
1064
1065 //-------------------------------------------------
1066 if( Element.is_Empty() )
1067 {
1068 // nop
1069 }
1070 else if( Element.Find('[') >= 0 ) // array begins
1071 {
1072 pNode = pNode->Add_Child(Element.AfterFirst('\"').BeforeFirst('\"'));
1073
1074 pNode->Add_Property("array", 1);
1075 }
1076 else if( Element.Find(']') >= 0 ) // array ends
1077 {
1078 if( pNode != this )
1079 {
1080 pNode = pNode->Get_Parent();
1081 }
1082 }
1083 else if( Element.Find('{') >= 0 ) // object begins
1084 {
1085 Element = Element.AfterFirst('\"').BeforeFirst('\"');
1086
1087 if( !Element.is_Empty() )
1088 {
1089 pNode = pNode->Add_Child(Element);
1090 }
1091 else if( pNode->Get_Property("array") )
1092 {
1093 pNode = pNode->Add_Child(CSG_String::Format("%d", pNode->Get_Children_Count()));
1094 }
1095 }
1096 else if( Element.Find('}') >= 0 ) // object ends
1097 {
1098 if( pNode != this )
1099 {
1100 pNode = pNode->Get_Parent();
1101 }
1102 }
1103 else
1104 {
1105 CSG_String Key (Element.AfterFirst('\"').BeforeFirst('\"'));
1106 CSG_String Value(Element.AfterFirst(':'));
1107
1108 if( Value.Find('\"') > -1 )
1109 {
1110 Value = Value.AfterFirst('\"').BeforeFirst('\"');
1111 }
1112
1113 pNode->Add_Child(Key, Value);
1114 }
1115 }
1116
1117 return( true );
1118 }
1119
1120 //---------------------------------------------------------
to_JSON(CSG_String & JSON) const1121 bool CSG_MetaData::to_JSON(CSG_String &JSON) const
1122 {
1123 return( false );
1124 }
1125
1126
1127 ///////////////////////////////////////////////////////////
1128 // //
1129 // //
1130 // //
1131 ///////////////////////////////////////////////////////////
1132
1133 //---------------------------------------------------------
CSG_HTTP(void)1134 CSG_HTTP::CSG_HTTP(void)
1135 {
1136 m_pHTTP = NULL;
1137 }
1138
1139 //---------------------------------------------------------
Create(void)1140 bool CSG_HTTP::Create(void)
1141 {
1142 return( Destroy() );
1143 }
1144
1145 //---------------------------------------------------------
CSG_HTTP(const CSG_String & Server,const SG_Char * Username,const SG_Char * Password)1146 CSG_HTTP::CSG_HTTP(const CSG_String &Server, const SG_Char *Username, const SG_Char *Password)
1147 {
1148 m_pHTTP = NULL;
1149
1150 Create(Server, Username, Password);
1151 }
1152
1153 //---------------------------------------------------------
Create(const CSG_String & Server,const SG_Char * Username,const SG_Char * Password)1154 bool CSG_HTTP::Create(const CSG_String &Server, const SG_Char *Username, const SG_Char *Password)
1155 {
1156 Destroy();
1157
1158 m_pHTTP = new wxHTTP;
1159
1160 if( Username && *Username ) { m_pHTTP->SetUser (Username); }
1161 if( Password && *Password ) { m_pHTTP->SetPassword(Password); }
1162
1163 wxString Host = Server.c_str();
1164
1165 unsigned short Port = 80;
1166
1167 #define SERVER_TRIM(s, p) { wxString sp(p); sp += "://"; if( s.Find(p) == 0 ) { s = s.Right(s.Length() - sp.Length()); } }
1168
1169 SERVER_TRIM(Host, "https");
1170 SERVER_TRIM(Host, "http");
1171
1172 if( Host.Find(":") >= 0 )
1173 {
1174 long _Port;
1175
1176 if( Host.AfterLast(':').ToLong(&_Port) )
1177 {
1178 Port = (unsigned short)_Port;
1179 }
1180
1181 Host = Host.BeforeLast(':');
1182 }
1183
1184 if( !m_pHTTP->Connect(Host, Port) )
1185 {
1186 Destroy();
1187
1188 return( false );
1189 }
1190
1191 return( true );
1192 }
1193
1194 //---------------------------------------------------------
~CSG_HTTP(void)1195 CSG_HTTP::~CSG_HTTP(void)
1196 {
1197 Destroy();
1198 }
1199
1200 //---------------------------------------------------------
Destroy(void)1201 bool CSG_HTTP::Destroy(void)
1202 {
1203 if( m_pHTTP )
1204 {
1205 delete(m_pHTTP);
1206
1207 m_pHTTP = NULL;
1208 }
1209
1210 return( true );
1211 }
1212
1213 //---------------------------------------------------------
is_Connected(void) const1214 bool CSG_HTTP::is_Connected(void) const
1215 {
1216 return( m_pHTTP != NULL );
1217 }
1218
1219 //---------------------------------------------------------
_Request(const CSG_String & Request)1220 wxInputStream * CSG_HTTP::_Request(const CSG_String &Request)
1221 {
1222 if( !is_Connected() )
1223 {
1224 return( NULL );
1225 }
1226
1227 wxString s(Request.c_str());
1228
1229 if( s[0] != '/' )
1230 {
1231 s.Prepend("/");
1232 }
1233
1234 wxInputStream *pStream = m_pHTTP->GetInputStream(s);
1235
1236 if( pStream && !pStream->CanRead() )
1237 {
1238 delete(pStream);
1239
1240 return( NULL );
1241 }
1242
1243 return( pStream );
1244 }
1245
1246 //---------------------------------------------------------
Request(const CSG_String & Request,CSG_MetaData & Answer)1247 bool CSG_HTTP::Request(const CSG_String &Request, CSG_MetaData &Answer)
1248 {
1249 wxInputStream *pStream = _Request(Request); if( !pStream ) { return( false ); }
1250
1251 wxXmlDocument XML;
1252
1253 if( !XML.Load(*pStream) )
1254 {
1255 delete(pStream);
1256
1257 return( false );
1258 }
1259
1260 Answer.Destroy(); Answer._Load(XML.GetRoot());
1261
1262 delete(pStream);
1263
1264 return( true );
1265 }
1266
1267 //---------------------------------------------------------
Request(const CSG_String & Request,CSG_Bytes & Answer)1268 bool CSG_HTTP::Request(const CSG_String &Request, CSG_Bytes &Answer)
1269 {
1270 wxInputStream *pStream = _Request(Request); if( !pStream ) { return( false ); }
1271
1272 // if( pStream->GetSize() == ((size_t)-1) )
1273 // {
1274 // delete(pStream);
1275 //
1276 // return( false );
1277 // }
1278
1279 Answer.Clear();
1280
1281 while( pStream->CanRead() )
1282 {
1283 char Byte;
1284
1285 pStream->Read(&Byte, sizeof(Byte));
1286
1287 Answer += Byte;
1288 }
1289
1290 delete(pStream);
1291
1292 return( true );
1293 }
1294
1295 //---------------------------------------------------------
Request(const CSG_String & Request,CSG_String & Answer)1296 bool CSG_HTTP::Request(const CSG_String &Request, CSG_String &Answer)
1297 {
1298 wxInputStream *pStream = _Request(Request); if( !pStream ) { return( false ); }
1299
1300 //if( pStream->GetSize() == ((size_t)-1) )
1301 //{
1302 // delete(pStream);
1303
1304 // return( false );
1305 //}
1306
1307 Answer.Clear();
1308
1309 while( pStream->CanRead() )
1310 {
1311 char Byte;
1312
1313 pStream->Read(&Byte, sizeof(Byte));
1314
1315 Answer += Byte;
1316 }
1317
1318 delete(pStream);
1319
1320 return( true );
1321 }
1322
1323 //---------------------------------------------------------
Request(const CSG_String & Request,const SG_Char * File)1324 bool CSG_HTTP::Request(const CSG_String &Request, const SG_Char *File)
1325 {
1326 wxInputStream *pStream = _Request(Request); if( !pStream ) { return( false ); }
1327
1328 wxFileOutputStream *pFile = new wxFileOutputStream(File);
1329
1330 if( !pFile )
1331 {
1332 delete(pStream);
1333
1334 return( false );
1335 }
1336
1337 pFile->Write(*pStream);
1338
1339 delete(pFile);
1340
1341 delete(pStream);
1342
1343 return( true );
1344 }
1345
1346
1347 ///////////////////////////////////////////////////////////
1348 // //
1349 // //
1350 // //
1351 ///////////////////////////////////////////////////////////
1352
1353 //---------------------------------------------------------
1354 #include <wx/protocol/ftp.h>
1355
1356 //---------------------------------------------------------
SG_FTP_Download(const CSG_String & Target_Directory,const CSG_String & Source,const SG_Char * Username,const SG_Char * Password,unsigned short Port,bool bBinary,bool bVerbose)1357 bool SG_FTP_Download(const CSG_String &Target_Directory, const CSG_String &Source, const SG_Char *Username, const SG_Char *Password, unsigned short Port, bool bBinary, bool bVerbose)
1358 {
1359 CSG_String _Source(Source); _Source.Trim();
1360
1361 if( _Source.Find("ftp://") == 0 )
1362 {
1363 _Source = _Source.Right(_Source.Length() - CSG_String("ftp://").Length());
1364 }
1365
1366 CSG_String ftpHost = _Source.BeforeFirst('/');
1367 CSG_String ftpDir = _Source.AfterFirst ('/').BeforeLast('/'); // ftpDir.Prepend("/");
1368 CSG_String ftpFile = _Source.AfterLast ('/');
1369
1370 //-----------------------------------------------------
1371 wxFTP ftp;
1372
1373 if( Username && *Username ) { ftp.SetUser (Username); }
1374 if( Password && *Password ) { ftp.SetPassword(Password); }
1375
1376 if( !ftp.Connect(ftpHost.c_str(), Port) )
1377 {
1378 if( bVerbose )
1379 {
1380 SG_UI_Msg_Add_Error(_TL("Couldn't connect"));
1381 }
1382
1383 return( false );
1384 }
1385
1386 //-----------------------------------------------------
1387 if( !ftpDir.is_Empty() && !ftp.ChDir(ftpDir.c_str()) )
1388 {
1389 if( bVerbose )
1390 {
1391 SG_UI_Msg_Add_Error(CSG_String::Format("%s [%s]", _TL("Couldn't change to directory"), ftpDir.c_str()));
1392 }
1393
1394 return( false );
1395 }
1396
1397 if( ftp.GetFileSize(ftpFile.c_str()) == -1 )
1398 {
1399 if( bVerbose )
1400 {
1401 SG_UI_Msg_Add_Error(CSG_String::Format("%s [%s]", _TL("Couldn't get the file size"), ftpFile.c_str()));
1402 }
1403 }
1404
1405 //-----------------------------------------------------
1406 wxInputStream *pStream = ftp.GetInputStream(ftpFile.c_str());
1407
1408 if( !pStream )
1409 {
1410 if( bVerbose )
1411 {
1412 SG_UI_Msg_Add_Error(CSG_String::Format("%s [%s]", _TL("Couldn't get the file"), ftpFile.c_str()));
1413 }
1414
1415 return( false );
1416 }
1417
1418 //-----------------------------------------------------
1419 wxFileOutputStream *pFile = new wxFileOutputStream(SG_File_Make_Path(Target_Directory, ftpFile).c_str());
1420
1421 if( !pFile )
1422 {
1423 if( bVerbose )
1424 {
1425 SG_UI_Msg_Add_Error(CSG_String::Format("%s [%s]", _TL("Couldn't create target file"), SG_File_Make_Path(Target_Directory, ftpFile).c_str()));
1426 }
1427
1428 delete(pStream);
1429
1430 return( false );
1431 }
1432
1433 //-----------------------------------------------------
1434 pFile->Write(*pStream);
1435
1436 delete(pFile);
1437 delete(pStream);
1438
1439 return( true );
1440 }
1441
1442
1443 ///////////////////////////////////////////////////////////
1444 // //
1445 // //
1446 // //
1447 ///////////////////////////////////////////////////////////
1448
1449 //---------------------------------------------------------
1450