1 //---
2 //
3 // License: MIT
4 //
5 // Description: This class provides capabilities for keywordlists.
6 //
7 //---
8 // $Id$
9 
10 #include <ossim/base/ossimKeywordlist.h>
11 #include <ossim/base/ossimDirectory.h>
12 #include <ossim/base/ossimFilename.h>
13 #include <ossim/base/ossimIoStream.h>
14 
15 #include <ossim/base/ossimNotify.h>
16 #include <ossim/base/ossimRefPtr.h>
17 #include <ossim/base/ossimRegExp.h>
18 #include <ossim/base/ossimStreamFactoryRegistry.h>
19 #include <ossim/base/ossimTrace.h>
20 #include <ossim/base/ossimXmlNode.h>
21 
22 #include <algorithm>
23 #include <fstream>
24 #include <list>
25 #include <memory>
26 #include <sstream>
27 #include <utility>
28 
29 #include <ossim/base/ossimStreamFactoryRegistry.h>
30 
31 static ossimTrace traceDebug("ossimKeywordlist:debug");
32 
33 #ifdef OSSIM_ID_ENABLED
34 static const bool TRACE = false;
35 static const char OSSIM_ID[] = "$Id: ossimKeywordlist.cpp 23632 2015-11-19 20:43:06Z dburken $";
36 #endif
37 
38 const std::string ossimKeywordlist::NULL_KW = "";
39 
ossimKeywordlist(const ossimKeywordlist & src)40 ossimKeywordlist::ossimKeywordlist(const ossimKeywordlist& src)
41 :m_map(src.m_map),
42 m_delimiter(src.m_delimiter),
43 m_preserveKeyValues(src.m_preserveKeyValues),
44 m_expandEnvVars(src.m_expandEnvVars)
45 {
46 }
47 
ossimKeywordlist(const std::map<std::string,std::string> & keywordMap)48 ossimKeywordlist::ossimKeywordlist(const std::map<std::string, std::string>& keywordMap)
49 :m_map(keywordMap),
50 m_delimiter(DEFAULT_DELIMITER),
51 m_preserveKeyValues(true),
52 m_expandEnvVars(true)
53 {
54 
55 }
56 
ossimKeywordlist(char delimiter,bool expandEnvVars)57 ossimKeywordlist::ossimKeywordlist(char delimiter,
58                                    bool expandEnvVars)
59 :
60 m_map(),
61 m_delimiter(delimiter),
62 m_preserveKeyValues(true),
63 m_expandEnvVars(expandEnvVars)
64 {
65 #ifdef OSSIM_ID_ENABLED
66    if (TRACE) ossimNotify(ossimNotifyLevel_DEBUG) << OSSIM_ID << std::endl;
67 #endif
68 }
69 
ossimKeywordlist(const char * file,char delimiter,bool ignoreBinaryChars,bool expandEnvVars)70 ossimKeywordlist::ossimKeywordlist(const char* file,
71                                    char        delimiter,
72                                    bool        ignoreBinaryChars,
73                                    bool        expandEnvVars)
74 :
75 m_map(),
76 m_delimiter(delimiter),
77 m_preserveKeyValues(true),
78 //m_lineContinuationCharacter('\\'),
79 m_expandEnvVars(expandEnvVars)
80 {
81    ossimFilename in_file(file);
82 
83    if (!parseFile(in_file, ignoreBinaryChars))
84    {
85       theErrorStatus = ossimErrorCodes::OSSIM_ERROR;
86    }
87 }
88 
ossimKeywordlist(const ossimFilename & file,char delimiter,bool ignoreBinaryChars,bool expandEnvVars)89 ossimKeywordlist::ossimKeywordlist(const ossimFilename& file,
90                                    char                 delimiter,
91                                    bool                 ignoreBinaryChars,
92                                    bool                 expandEnvVars)
93 :
94 m_map(),
95 m_delimiter(delimiter),
96 m_preserveKeyValues(true),
97 m_expandEnvVars(expandEnvVars)
98 
99 {
100    if (!parseFile(file, ignoreBinaryChars))
101    {
102       theErrorStatus = ossimErrorCodes::OSSIM_ERROR;
103    }
104 }
105 
~ossimKeywordlist()106 ossimKeywordlist::~ossimKeywordlist()
107 {
108    m_map.clear();
109 }
110 
setExpandEnvVarsFlag(bool flag)111 void ossimKeywordlist::setExpandEnvVarsFlag( bool flag )
112 {
113    m_expandEnvVars = flag;
114 }
115 
getExpandEnvVarsFlag(void) const116 bool ossimKeywordlist::getExpandEnvVarsFlag( void ) const
117 {
118    return m_expandEnvVars;
119 }
120 
addFile(const char * file)121 bool ossimKeywordlist::addFile(const char* file)
122 {
123    ossimFilename in_file(file);
124 
125    return parseFile(in_file);
126 }
127 
addFile(const ossimFilename & file)128 bool ossimKeywordlist::addFile(const ossimFilename& file)
129 {
130    return parseFile(file);
131 }
132 
addList(const ossimKeywordlist & src,bool overwrite)133 void ossimKeywordlist::addList(const ossimKeywordlist &src, bool overwrite)
134 {
135    KeywordMap::const_iterator i = src.m_map.begin();
136 
137    while (i != src.m_map.end())
138    {
139       addPair( (*i).first, (*i).second, overwrite );
140       i++;
141    }
142 }
143 
add(const ossimKeywordlist & kwl,const char * prefix,bool stripPrefix)144 void ossimKeywordlist::add(const ossimKeywordlist& kwl,
145                            const char* prefix,
146                            bool stripPrefix)
147 {
148    std::map<std::string, std::string>::const_iterator iter = kwl.m_map.begin();
149 
150    ossimRegExp regExp;
151 
152    // Check for null prefix.
153    std::string tmpPrefix;
154    if (prefix) tmpPrefix = prefix;
155 
156    regExp.compile(("^("+tmpPrefix+")").c_str());
157 
158    while(iter != kwl.m_map.end())
159    {
160       ossimString newKey;
161 
162       if(regExp.find( (*iter).first.c_str()))
163       {
164          newKey = (*iter).first;
165          if(stripPrefix && prefix)
166          {
167             newKey = newKey.substitute(prefix, "");
168 
169          }
170 
171          addPair(newKey.string(), (*iter).second, true);
172       }
173       ++iter;
174    }
175 }
176 
add(const char * prefix,const ossimKeywordlist & kwl,bool overwrite)177 void ossimKeywordlist::add(const char* prefix,
178                            const ossimKeywordlist& kwl,
179                            bool overwrite)
180 {
181    std::string p = prefix ? prefix : "";
182    std::map<std::string, std::string>::const_iterator iter = kwl.m_map.begin();
183    while(iter != kwl.m_map.end())
184    {
185       std::string k( p + (*iter).first );
186       addPair( k, (*iter).second, overwrite );
187       ++iter;
188    }
189 }
190 
addPair(const std::string & key,const std::string & value,bool overwrite)191 void ossimKeywordlist::addPair(const std::string& key,
192                                const std::string& value,
193                                bool               overwrite)
194 {
195    if ( key.size() )
196    {
197       ossimString v = value;
198       if ( m_expandEnvVars == true )
199       {
200          v = v.expandEnvironmentVariable();
201       }
202 
203       KeywordMap::iterator i = getMapEntry(key);
204 
205       if (i == m_map.end())
206       {
207          m_map.insert(std::make_pair(key, v.string()));
208       }
209       else if (overwrite)
210       {
211          (*i).second = v.string();
212       }
213    }
214 }
215 
addPair(const std::string & prefix,const std::string & key,const std::string & value,bool overwrite)216 void ossimKeywordlist::addPair(const std::string& prefix,
217                                const std::string& key,
218                                const std::string& value,
219                                bool               overwrite)
220 {
221    std::string k(prefix + key);
222    addPair(k, value, overwrite);
223 }
224 
add(const char * key,const char * value,bool overwrite)225 void ossimKeywordlist::add(const char* key,
226                            const char* value,
227                            bool        overwrite)
228 {
229    if ( key )
230    {
231       std::string k(key);
232       std::string v(value?value:"");
233       addPair(k, v, overwrite);
234    }
235 }
236 
add(const char * prefix,const char * key,const char * value,bool overwrite)237 void ossimKeywordlist::add(const char* prefix,
238                            const char* key,
239                            const char* value,
240                            bool        overwrite)
241 {
242    if ( key )
243    {
244       std::string k(prefix ? (std::string(prefix)+std::string(key)) : key);
245       std::string v(value ? value : "");
246       addPair(k, v, overwrite);
247    }
248 }
249 
add(const char * key,char value,bool overwrite)250 void ossimKeywordlist::add(const char* key,
251                            char        value,
252                            bool        overwrite)
253 {
254    if ( key )
255    {
256       std::string k(key);
257       std::string v(1, value);
258       addPair(k, v, overwrite);
259    }
260 }
261 
add(const char * prefix,const char * key,char value,bool overwrite)262 void ossimKeywordlist::add(const char* prefix,
263                            const char* key,
264                            char        value,
265                            bool        overwrite)
266 {
267    if ( key )
268    {
269       std::string k(prefix ? (std::string(prefix)+std::string(key)) : key);
270       std::string v(1, value);
271       addPair(k, v, overwrite);
272    }
273 }
274 
add(const char * key,ossim_int16 value,bool overwrite)275 void ossimKeywordlist::add(const char* key,
276                            ossim_int16 value,
277                            bool overwrite)
278 {
279    if ( key )
280    {
281       std::string k(key);
282       std::string v = ossimString::toString(value).string();
283       addPair(k, v, overwrite);
284    }
285 }
286 
add(const char * prefix,const char * key,ossim_int16 value,bool overwrite)287 void ossimKeywordlist::add(const char* prefix,
288                            const char* key,
289                            ossim_int16 value,
290                            bool overwrite)
291 {
292    if ( key )
293    {
294       std::string k(prefix ? (std::string(prefix)+std::string(key)) : key);
295       std::string v = ossimString::toString(value).string();
296       addPair(k, v, overwrite);
297    }
298 }
299 
add(const char * key,ossim_uint16 value,bool overwrite)300 void ossimKeywordlist::add(const char* key,
301                            ossim_uint16 value,
302                            bool overwrite)
303 {
304    if ( key )
305    {
306       std::string k(key);
307       std::string v = ossimString::toString(value).string();
308       addPair(k, v, overwrite);
309    }
310 }
311 
add(const char * prefix,const char * key,ossim_uint16 value,bool overwrite)312 void ossimKeywordlist::add(const char* prefix,
313                            const char* key,
314                            ossim_uint16 value,
315                            bool overwrite)
316 {
317    if ( key )
318    {
319       std::string k(prefix ? (std::string(prefix)+std::string(key)) : key);
320       std::string v = ossimString::toString(value).string();
321       addPair(k, v, overwrite);
322    }
323 }
324 
add(const char * key,ossim_int32 value,bool overwrite)325 void ossimKeywordlist::add(const char* key,
326                            ossim_int32 value,
327                            bool overwrite)
328 {
329    if ( key )
330    {
331       std::string k(key);
332       std::string v = ossimString::toString(value).string();
333       addPair(k, v, overwrite);
334    }
335 }
336 
add(const char * prefix,const char * key,ossim_int32 value,bool overwrite)337 void ossimKeywordlist::add(const char*  prefix,
338                            const char*  key,
339                            ossim_int32 value,
340                            bool overwrite)
341 {
342    if ( key )
343    {
344       std::string k(prefix ? (std::string(prefix)+std::string(key)) : key);
345       std::string v = ossimString::toString(value).string();
346       addPair(k, v, overwrite);
347    }
348 }
349 
add(const char * key,ossim_uint32 value,bool overwrite)350 void ossimKeywordlist::add(const char* key,
351                            ossim_uint32 value,
352                            bool overwrite)
353 {
354    if ( key )
355    {
356       std::string k(key);
357       std::string v = ossimString::toString(value).string();
358       addPair(k, v, overwrite);
359    }
360 }
361 
add(const char * prefix,const char * key,ossim_uint32 value,bool overwrite)362 void ossimKeywordlist::add(const char*  prefix,
363                            const char*  key,
364                            ossim_uint32 value,
365                            bool overwrite)
366 {
367    if ( key )
368    {
369       std::string k(prefix ? (std::string(prefix)+std::string(key)) : key);
370       std::string v = ossimString::toString(value).string();
371       addPair(k, v, overwrite);
372    }
373 }
374 
add(const char * key,ossim_int64 value,bool overwrite)375 void ossimKeywordlist::add(const char* key,
376                            ossim_int64 value,
377                            bool overwrite)
378 {
379    if ( key )
380    {
381       std::string k(key);
382       std::string v = ossimString::toString(value).string();
383       addPair(k, v, overwrite);
384    }
385 }
386 
add(const char * prefix,const char * key,ossim_int64 value,bool overwrite)387 void ossimKeywordlist::add(const char*  prefix,
388                            const char*  key,
389                            ossim_int64 value,
390                            bool overwrite)
391 {
392    if ( key )
393    {
394       std::string k(prefix ? (std::string(prefix)+std::string(key)) : key);
395       std::string v = ossimString::toString(value).string();
396       addPair(k, v, overwrite);
397    }
398 }
399 
add(const char * key,ossim_uint64 value,bool overwrite)400 void ossimKeywordlist::add(const char* key,
401                            ossim_uint64 value,
402                            bool overwrite)
403 {
404    if ( key )
405    {
406       std::string k(key);
407       std::string v = ossimString::toString(value).string();
408       addPair(k, v, overwrite);
409    }
410 }
411 
add(const char * prefix,const char * key,ossim_uint64 value,bool overwrite)412 void ossimKeywordlist::add(const char*  prefix,
413                            const char*  key,
414                            ossim_uint64 value,
415                            bool overwrite)
416 {
417    if ( key )
418    {
419       std::string k(prefix ? (std::string(prefix)+std::string(key)) : key);
420       std::string v = ossimString::toString(value).string();
421       addPair(k, v, overwrite);
422    }
423 }
424 
add(const char * key,ossim_float32 value,bool overwrite,int precision)425 void ossimKeywordlist::add(const char* key,
426                            ossim_float32 value,
427                            bool overwrite,
428                            int precision)
429 {
430    if ( key )
431    {
432       std::string k(key);
433       std::string v = ossimString::toString(value, precision).string();
434       addPair(k, v, overwrite);
435    }
436 }
437 
add(const char * prefix,const char * key,ossim_float32 value,bool overwrite,int precision)438 void ossimKeywordlist::add(const char* prefix,
439                            const char* key,
440                            ossim_float32 value,
441                            bool overwrite,
442                            int precision)
443 {
444    if ( key )
445    {
446       std::string k(prefix ? (std::string(prefix)+std::string(key)) : key);
447       std::string v = ossimString::toString(value, precision).string();
448       addPair(k, v, overwrite);
449    }
450 }
451 
add(const char * key,ossim_float64 value,bool overwrite,int precision)452 void ossimKeywordlist::add(const char* key,
453                            ossim_float64 value,
454                            bool overwrite,
455                            int precision)
456 {
457    if ( key )
458    {
459       std::string k(key);
460       std::string v = ossimString::toString(value, precision).string();
461       addPair(k, v, overwrite);
462    }
463 }
464 
add(const char * prefix,const char * key,ossim_float64 value,bool overwrite,int precision)465 void ossimKeywordlist::add(const char* prefix,
466                            const char* key,
467                            ossim_float64 value,
468                            bool overwrite,
469                            int precision)
470 {
471    if ( key )
472    {
473       std::string k(prefix ? (std::string(prefix)+std::string(key)) : key);
474       std::string v = ossimString::toString(value, precision).string();
475       addPair(k, v, overwrite);
476    }
477 }
478 
write(const char * file,const char * comment) const479 bool ossimKeywordlist::write(const char* file,
480                              const char* comment) const
481 {
482    std::ofstream filename(file);
483    if (!filename)
484    {
485       ossimNotify(ossimNotifyLevel_WARN)
486       <<"ossimKeywordlist::write, Error opening file:  "
487       << file << std::endl;
488       return false;
489    }
490 
491    if ( comment != 0 )
492    {
493       ossimString commentStr("// ");
494       commentStr += comment;
495 
496       // Write out the input comment to the first line.
497       filename << commentStr.c_str() << std::endl;
498    }
499 
500    writeToStream(filename);
501 
502    filename.close();
503 
504    return true;
505 }
506 
toString() const507 ossimString ossimKeywordlist::toString()const
508 {
509    std::ostringstream out;
510    writeToStream(out);
511 
512 #if 0
513    KeywordMap::const_iterator i;
514    ossimString result;
515 
516    for(i = m_map.begin(); i != m_map.end(); i++)
517    {
518       result += (*i).first;
519       result += delimiter_str().c_str();
520       result += " ";
521       result += (*i).second;
522       result += '\n';
523    }
524 #endif
525    return ossimString(out.str());
526 }
527 
toString(ossimString & result) const528 void ossimKeywordlist::toString(ossimString& result)const
529 {
530    std::ostringstream out;
531    writeToStream(out);
532 
533    result = out.str();
534 #if 0
535    KeywordMap::const_iterator i;
536 
537    for(i = m_map.begin(); i != m_map.end(); i++)
538    {
539       result += (*i).first;
540       result += delimiter_str().c_str();
541       result += " ";
542       result += (*i).second;
543       result += '\n';
544    }
545 #endif
546 }
547 
writeToStream(std::ostream & out) const548 void ossimKeywordlist::writeToStream(std::ostream& out) const
549 {
550    KeywordMap::const_iterator i;
551    ossimString value;
552    ossimRegExp reg("\n|\r| $|^ ");
553    for(i = m_map.begin(); i != m_map.end(); ++i)
554    {
555       value = (*i).second;
556       if(!value.empty())
557       {
558          if(reg.find(value))
559          {
560             value = "\"\"\"" + value + "\"\"\"";
561          }
562       }
563       //      value = value.substitute('\n', "\\\n", true);
564       out << (*i).first  << delimiter_str().c_str() << "  "
565       << value << std::endl;
566    }
567 }
568 
hasKey(const std::string & key) const569 bool ossimKeywordlist::hasKey( const std::string& key ) const
570 {
571    bool result = false;
572    KeywordMap::const_iterator i = m_map.find(key);
573    if (i != m_map.end())
574    {
575       result = true;
576    }
577    return result;
578 }
579 
findKey(const std::string & key) const580 const std::string& ossimKeywordlist::findKey(const std::string& key) const
581 {
582    // std::string result;
583    KeywordMap::const_iterator i = m_map.find(key);
584    if (i != m_map.end())
585    {
586       // result = (*i).second;
587       return (*i).second;
588    }
589    return ossimKeywordlist::NULL_KW;
590 }
591 
findKey(const std::string & prefix,const std::string & key) const592 const std::string& ossimKeywordlist::findKey(const std::string& prefix,
593                                              const std::string& key) const
594 {
595    std::string k = prefix+key;
596    return findKey(k);
597 }
598 
find(const char * key) const599 const char* ossimKeywordlist::find(const char* key) const
600 {
601    const char* result = 0;
602    if (key)
603    {
604       std::string k = key;
605       KeywordMap::const_iterator i = m_map.find( k );
606       if (i != m_map.end())
607       {
608          result = (*i).second.c_str();
609       }
610    }
611    return result;
612 }
613 
find(const char * prefix,const char * key) const614 const char* ossimKeywordlist::find(const char* prefix,
615                                    const char* key) const
616 {
617    const char* result = 0;
618    if (key)
619    {
620       std::string k;
621       if (prefix) k = prefix;
622       k += key;
623       KeywordMap::const_iterator i = m_map.find( k );
624       if (i != m_map.end())
625       {
626          result = (*i).second.c_str();
627       }
628    }
629    return result;
630 }
631 
remove(const char * key)632 void ossimKeywordlist::remove(const char * key)
633 {
634    ossimString k = key?key:"";
635 
636    KeywordMap::iterator i = m_map.find(k);
637 
638    if(i != m_map.end())
639    {
640       m_map.erase(i);
641    }
642 }
643 
remove(const char * prefix,const char * key)644 void ossimKeywordlist::remove(const char* prefix, const char * key)
645 {
646    if (key)
647    {
648       ossimString k;
649       if (prefix) k = prefix;
650       k += key;
651 
652       KeywordMap::iterator i = m_map.find(k);
653 
654       if(i != m_map.end())
655       {
656          m_map.erase(i);
657       }
658    }
659 }
660 
numberOf(const char * str) const661 ossim_uint32 ossimKeywordlist::numberOf(const char* str) const
662 {
663    ossim_uint32 count = 0;
664 
665    if (str)
666    {
667       KeywordMap::const_iterator i = m_map.begin();
668 
669       while (i != m_map.end())
670       {
671          if ( ossimString((*i).first).contains(str) )
672          {
673             ++count;
674          }
675          ++i;
676       }
677    }
678 
679    return count;
680 }
681 
numberOf(const char * prefix,const char * key) const682 ossim_uint32 ossimKeywordlist::numberOf(const char* prefix,
683                                         const char* key) const
684 {
685    if ( key ) // Must have key, sometimes no prefix.
686    {
687       std::string k(prefix ? (std::string(prefix)+std::string(key)) : key);
688       return numberOf(k.c_str());
689    }
690    return 0;
691 }
692 
clear()693 void ossimKeywordlist::clear()
694 {
695    m_map.clear();
696 }
697 
698 ossimKeywordlist::KeywordMap::iterator
getMapEntry(const char * key)699 ossimKeywordlist::getMapEntry(const char* key)
700 {
701    if (key)
702    {
703       std::string k = key;
704       return m_map.find(k);
705    }
706    else
707    {
708       return m_map.end();
709    }
710 }
711 
712 ossimKeywordlist::KeywordMap::iterator
getMapEntry(const std::string & key)713 ossimKeywordlist::getMapEntry(const std::string& key)
714 {
715    return m_map.find(key);
716 }
717 
718 ossimKeywordlist::KeywordMap::iterator
getMapEntry(const ossimString & key)719 ossimKeywordlist::getMapEntry(const ossimString& key)
720 {
721    return m_map.find(key.string());
722 }
723 
724 
725 //*******************************************************************
726 // Private Method:
727 //*******************************************************************
parseFile(const ossimFilename & file,bool ignoreBinaryChars)728 bool ossimKeywordlist::parseFile(const ossimFilename& file,
729                                  bool ignoreBinaryChars)
730 {
731    bool result = false;
732 
733    std::shared_ptr<ossim::istream> is = ossim::StreamFactoryRegistry::instance()->
734       createIstream( file.string() );
735    if ( is )
736    {
737       m_currentlyParsing = file;
738       result = parseStream(*is, ignoreBinaryChars);
739       is.reset();
740    }
741 
742    return result;
743 }
744 
parseStream(ossim::istream & is,bool)745 bool ossimKeywordlist::parseStream(ossim::istream& is, bool /* ignoreBinaryChars */)
746 {
747    return parseStream(is);
748 }
749 
parseString(const std::string & inString)750 bool ossimKeywordlist::parseString(const std::string& inString)
751 {
752    ossim::istringstream in(inString);
753 
754    return parseStream(in);
755 }
756 
isValidKeywordlistCharacter(ossim_uint8 c) const757 bool ossimKeywordlist::isValidKeywordlistCharacter(ossim_uint8 c)const
758 {
759    if((c>=0x20&&c<=0x7e))
760    {
761       return true;
762    }
763    switch(c)
764    {
765       case '\n':
766       case '\r':
767       case '\t':
768          return true;
769    }
770    return false;
771 }
772 
skipWhitespace(ossim::istream & in) const773 void ossimKeywordlist::skipWhitespace(ossim::istream& in)const
774 {
775    int c = in.peek();
776    while( !in.fail() &&
777          ( (c == ' ') || (c == '\t') || (c == '\n') || (c == '\r') ) )
778    {
779       in.ignore(1);
780       c = in.peek();
781    }
782 }
783 
readComments(ossimString & sequence,ossim::istream & in) const784 ossimKeywordlist::KeywordlistParseState ossimKeywordlist::readComments(ossimString& sequence, ossim::istream& in)const
785 {
786    KeywordlistParseState result = KeywordlistParseState_FAIL;
787    char c = (char)in.peek();
788    if(c == '/')
789    {
790       sequence += (char)in.get();
791       c = in.peek();
792       if(c == '/')
793       {
794          result = KeywordlistParseState_OK;
795          sequence += c;
796          while(!in.bad()&&!in.eof())
797          {
798             c = (char)in.get();
799             if (in.bad() || in.eof())
800                break;
801 
802             if(!isValidKeywordlistCharacter(c))
803             {
804                result = KeywordlistParseState_BAD_STREAM;
805                break;
806             }
807             if((c == '\n')|| (c == '\r'))
808                break;
809 
810             sequence += c;
811          }
812       }
813    }
814    return result;
815 }
816 
817 ossimKeywordlist::KeywordlistParseState
readPreprocDirective(ossim::istream & in)818 ossimKeywordlist::readPreprocDirective(ossim::istream& in)
819 {
820    KeywordlistParseState status = KeywordlistParseState_FAIL;
821 
822    char c = (char)in.peek();
823    while (c == '#')
824    {
825       // Read the line as one big value:
826       ossimString sequence;
827       status = readValue(sequence, in);
828       if (status)
829          break;
830 
831       ossimString directive = sequence.before(" ");
832 
833       // Check for external KWL include file:
834       if (directive == "#include")
835       {
836          ossimFilename includeFile = sequence.after(" ");
837          if (includeFile.empty())
838             break; // ignore bogus preproc line
839          includeFile.trim("\"");
840          includeFile.expandEnvironmentVariable();
841 
842          // The filename can be either relative to the current file being parsed or absolute:
843          if (includeFile.string()[0] != '/')
844             includeFile = m_currentlyParsing.path() + "/" + includeFile;
845 
846          // Save the current path in case the new one contains it's own include directive!
847          ossimFilename savedCurrentPath = m_currentlyParsing;
848          addFile(includeFile); // Quietly ignore any errors loading external KWL.
849          m_currentlyParsing = savedCurrentPath;
850       }
851 
852 //      else if (directive == "#add_new_directive_here")
853 //      {
854 //         process directive
855 //      }
856 
857       status = KeywordlistParseState_OK;
858       break;
859    }
860    return status;
861 }
862 
readKey(ossimString & sequence,ossim::istream & in) const863 ossimKeywordlist::KeywordlistParseState ossimKeywordlist::readKey(ossimString& sequence, ossim::istream& in)const
864 {
865    KeywordlistParseState result = KeywordlistParseState_FAIL;
866    if(!sequence.empty())
867    {
868       if(*(sequence.begin()+(sequence.size()-1)) == m_delimiter)
869       {
870          sequence = ossimString(sequence.begin(), sequence.begin() + (sequence.size()-1));
871          return KeywordlistParseState_OK;
872       }
873    }
874    // not a comment so read til key delimeter
875    while(!in.eof() && in.good())
876    {
877       ossim_uint8 c = in.get();
878       if( isValidKeywordlistCharacter(c) )
879       {
880          if ( (c == '\n') || (c == '\r') )
881          {
882             // Hit end of line with no delimiter.
883             if ( in.peek() == EOF )
884             {
885                //---
886                // Allowing on last line only.
887                // Note the empty key will trigger parseStream to return true.
888                //---
889                sequence.clear();
890                result = KeywordlistParseState_OK;
891                break;
892             }
893             else // Line with no delimiter.
894             {
895                // mal formed input stream for keyword list specification
896                result = KeywordlistParseState_BAD_STREAM;
897                break;
898             }
899          }
900          else if(c != m_delimiter)
901          {
902             sequence += (char)c;
903          }
904          else // at m_delimiter
905          {
906             result = KeywordlistParseState_OK;
907             sequence = sequence.trim();
908             break;
909          }
910       }
911       else
912       {
913          // mal formed input stream for keyword list specification
914          result = KeywordlistParseState_BAD_STREAM;
915          break;
916       }
917    }
918    // we never found a delimeter so we are mal formed
919    if(!sequence.empty()&&(result!=KeywordlistParseState_OK))
920    {
921       result = KeywordlistParseState_BAD_STREAM;
922    }
923    return result;
924 }
925 
readValue(ossimString & sequence,ossim::istream & in) const926 ossimKeywordlist::KeywordlistParseState ossimKeywordlist::readValue(ossimString& sequence, ossim::istream& in)const
927 {
928    KeywordlistParseState result = KeywordlistParseState_OK;
929 
930    ossim_int32 quoteCount = 0; // mark as not set
931 
932    // make sure we check for a blank value
933    while(!in.eof()&&!in.bad())
934    {
935       if(in.peek() == ' '||
936          in.peek() == '\t')
937       {
938          in.ignore();
939       }
940       else if(in.peek() == '\n' ||
941               in.peek() == '\r')
942       {
943          in.ignore();
944          return result;
945       }
946       else
947       {
948          break;
949       }
950    }
951    // The ifstream object will end in '�' (character 255 or -1) if the end-of-file indicator
952    // will not be set(e.g \n). In this case, end-of-file conditions would never be detected.
953    // add EOF (which is actually the integer -1 or 255) check here.
954    // Reference link http://www.cplusplus.com/forum/general/33821/
955    while(!in.eof()&&!in.bad()&&in.peek()!=EOF)
956    {
957       ossim_uint8 c = in.get();
958       if(isValidKeywordlistCharacter(c))
959       {
960          if(((c == '\n'||c=='\r') && !quoteCount) || in.eof())
961          {
962             break;
963          }
964          sequence += (char)c;
965          if(sequence.size() >2)
966          {
967             if(quoteCount < 1)
968             {
969                //---
970                // If string has leading tripple quoted bump the "quoteCount" so
971                // we start skipping line breaks, preserving paragraph style strings.
972                //---
973                if(ossimString(sequence.begin(), sequence.begin()+3) == "\"\"\"")
974                {
975                   ++quoteCount;
976                }
977             }
978             else // check for ending quotes
979             {
980                if(ossimString(sequence.begin() + sequence.size()-3, sequence.end()) == "\"\"\"")
981                {
982                   ++quoteCount;
983                }
984             }
985          }
986          if(quoteCount > 1)
987          {
988             //---
989             // Have leading and trailing tripple quotes. Some tiff writers, e.g. Space
990             // Imaging are using four quotes.  Below code strips all quotes from each end.
991             //---
992             char quote = '"';
993             std::string::size_type startPos = sequence.string().find_first_not_of(quote);
994             std::string::size_type stopPos  = sequence.string().find_last_not_of(quote);
995             if ( ( startPos != std::string::npos ) && (stopPos != std::string::npos) )
996             {
997                sequence = sequence.string().substr( startPos, stopPos-startPos+1 );
998             }
999             break;
1000          }
1001       }
1002       else
1003       {
1004          result = KeywordlistParseState_BAD_STREAM;
1005          break;
1006       }
1007    }
1008    return result;
1009 }
1010 
readKeyAndValuePair(ossimString & key,ossimString & value,ossim::istream & in) const1011 ossimKeywordlist::KeywordlistParseState ossimKeywordlist::readKeyAndValuePair(ossimString& key, ossimString& value, ossim::istream& in)const
1012 {
1013    ossimKeywordlist::KeywordlistParseState keyState   = readKey(key, in);
1014    if(keyState & KeywordlistParseState_BAD_STREAM) return keyState;
1015    ossimKeywordlist::KeywordlistParseState valueState = readValue(value, in);
1016    return static_cast<ossimKeywordlist::KeywordlistParseState>( (static_cast<int>(keyState) |
1017                                                                  static_cast<int>(valueState)) );
1018 }
1019 
parseStream(ossim::istream & is)1020 bool ossimKeywordlist::parseStream(ossim::istream& is)
1021 {
1022    if (!is) // Check stream state.
1023    {
1024       return false;
1025    }
1026    ossimString key;
1027    ossimString value;
1028    ossimString sequence;
1029    KeywordlistParseState state = KeywordlistParseState_OK;
1030    while(!is.eof() && !is.bad())
1031    {
1032       skipWhitespace(is);
1033       if(is.eof() || is.bad())
1034          return true; // we skipped to end so valid keyword list
1035 
1036       state = readPreprocDirective(is);
1037       if(state & KeywordlistParseState_BAD_STREAM)
1038          return false;
1039 
1040       // if we failed a preprocessor directive parse then try comment parse.
1041       if(state == KeywordlistParseState_FAIL)
1042       {
1043          state = readComments(sequence, is);
1044          if(state & KeywordlistParseState_BAD_STREAM)
1045             return false;
1046       }
1047 
1048       // if we failed a comment parse then try key value parse.
1049       if(state == KeywordlistParseState_FAIL)
1050       {
1051          key = sequence; // just in case there is a 1 token look ahead residual for a single slash test.
1052          ossimKeywordlist::KeywordlistParseState testKeyValueState = readKeyAndValuePair(key, value, is);
1053          if(testKeyValueState == KeywordlistParseState_OK)
1054          {
1055             key = key.trim();
1056             if(key.empty())
1057                return true;
1058 
1059             if ( m_expandEnvVars == true )
1060                value = value.expandEnvironmentVariable();
1061             m_map.insert(std::make_pair(key.string(), value.string()));
1062          }
1063          else if(testKeyValueState & KeywordlistParseState_BAD_STREAM)
1064          {
1065             return false;
1066          }
1067 #if 0
1068          // Commented out to allow an invalid line in keyword list without
1069          // erroring out, effectively skipping bad line. drb - 01 Sep. 2001
1070          else
1071          {
1072             return false;
1073          }
1074 #endif
1075       }
1076       else if(state & KeywordlistParseState_BAD_STREAM)
1077       {
1078          return false;
1079       }
1080       sequence = key = value = "";
1081    }
1082 
1083    return true;
1084 }
1085 
getSortedList(std::vector<ossimString> & prefixValues,const ossimString & prefixKey) const1086 void ossimKeywordlist::getSortedList(std::vector<ossimString>& prefixValues,
1087                                      const ossimString &prefixKey)const
1088 {
1089    ossimString regExpression     =  ossimString("^(") + prefixKey+ "[0-9]+)";
1090    prefixValues.clear();
1091    std::vector<ossimString> keys;
1092    getSubstringKeyList(keys, regExpression);
1093    ossim_uint32 nKeys = (long)keys.size();
1094 
1095    ossim_uint32 offset = (int)ossimString(prefixKey).size();
1096    ossim_uint32 idx = 0;
1097    std::vector<ossim_uint32> numberList(nKeys);
1098    for(idx = 0; idx < (ossim_uint32)numberList.size();++idx)
1099    {
1100     ossimString numberStr(keys[idx].begin() + offset,
1101            keys[idx].end());
1102     numberList[idx] = numberStr.toInt();
1103    }
1104    std::sort(numberList.begin(), numberList.end());
1105 
1106    for(idx=0;idx < (ossim_uint32)numberList.size();++idx)
1107    {
1108       prefixValues.push_back(prefixKey+ossimString::toString(numberList[idx]));
1109    }
1110 }
1111 
findAllKeysThatContains(const ossimString & searchString) const1112 std::vector<ossimString> ossimKeywordlist::findAllKeysThatContains(const ossimString &searchString)const
1113 {
1114    KeywordMap::const_iterator i;
1115    std::vector<ossimString> result;
1116 
1117    for(i = m_map.begin(); i != m_map.end(); ++i)
1118    {
1119       if( ossimString((*i).first).contains(searchString))
1120       {
1121          result.push_back((*i).first);
1122       }
1123    }
1124 
1125    return result;
1126 }
1127 
findAllKeysThatMatch(std::vector<ossimString> & result,const ossimString & regularExpression) const1128 void ossimKeywordlist::findAllKeysThatMatch( std::vector<ossimString>& result,
1129                                              const ossimString &regularExpression ) const
1130 {
1131    KeywordMap::const_iterator i;
1132    ossimRegExp regExp;
1133    regExp.compile(regularExpression.c_str());
1134    for(i = m_map.begin(); i != m_map.end(); ++i)
1135    {
1136       if(regExp.find( (*i).first.c_str()))
1137       {
1138          result.push_back((*i).first);
1139       }
1140    }
1141 }
1142 
getNumberOfKeysThatMatch(const ossimString & regularExpression) const1143 ossim_uint32  ossimKeywordlist::getNumberOfKeysThatMatch(
1144    const ossimString &regularExpression ) const
1145 {
1146    ossim_uint32 result = 0;
1147    KeywordMap::const_iterator i;
1148    ossimRegExp regExp;
1149    regExp.compile(regularExpression.c_str());
1150    for(i = m_map.begin(); i != m_map.end(); ++i)
1151    {
1152       if(regExp.find( (*i).first.c_str()))
1153       {
1154          ++result;
1155       }
1156    }
1157    return result;
1158 }
1159 
extractKeysThatMatch(ossimKeywordlist & kwl,const ossimString & regularExpression) const1160 void ossimKeywordlist::extractKeysThatMatch(ossimKeywordlist& kwl,
1161                                             const ossimString &regularExpression)const
1162 {
1163    KeywordMap::const_iterator i;
1164    std::vector<ossimString> result;
1165    ossimRegExp regExp;
1166 
1167    regExp.compile(regularExpression.c_str());
1168 
1169    for(i = m_map.begin(); i != m_map.end(); ++i)
1170    {
1171       if(regExp.find( (*i).first.c_str()))
1172       {
1173          kwl.addPair((*i).first, (*i).second);
1174       }
1175    }
1176 }
1177 
removeKeysThatMatch(const ossimString & regularExpression)1178 void ossimKeywordlist::removeKeysThatMatch(const ossimString &regularExpression)
1179 {
1180    KeywordMap::const_iterator i;
1181    std::vector<ossimString> result;
1182    ossimRegExp regExp;
1183 
1184    regExp.compile(regularExpression.c_str());
1185 
1186    for(i = m_map.begin(); i != m_map.end(); ++i)
1187    {
1188       if(regExp.find( (*i).first.c_str()))
1189       {
1190          result.push_back((*i).first);
1191       }
1192    }
1193    for(ossim_uint32 i2 = 0; i2 < result.size(); ++i2)
1194    {
1195       remove(result[i2]);
1196    }
1197 }
1198 
getSubstringKeyList(const ossimString & regularExpression) const1199 std::vector<ossimString> ossimKeywordlist::getSubstringKeyList(const ossimString& regularExpression)const
1200 {
1201    std::vector<ossimString> result;
1202    getSubstringKeyList(result, regularExpression);
1203    return result;
1204 }
1205 
getSubstringKeyList(std::vector<ossimString> & result,const ossimString & regularExpression) const1206 void ossimKeywordlist::getSubstringKeyList(std::vector<ossimString>& result,
1207                                            const ossimString& regularExpression)const
1208 {
1209    KeywordMap::const_iterator i;
1210    ossimRegExp regExp;
1211 
1212    regExp.compile(regularExpression.c_str());
1213 
1214    for(i = m_map.begin(); i != m_map.end(); ++i)
1215    {
1216       if(regExp.find( (*i).first.c_str()))
1217       {
1218          ossimString value = ossimString((*i).first.begin()+regExp.start(),
1219                                          (*i).first.begin()+regExp.start()+regExp.end());
1220 
1221          if(std::find(result.begin(), result.end(), value) == result.end())
1222          {
1223             result.push_back(value);
1224          }
1225       }
1226    }
1227 }
1228 
getNumberOfSubstringKeys(const ossimString & regularExpression) const1229 ossim_uint32 ossimKeywordlist::getNumberOfSubstringKeys(const ossimString& regularExpression)const
1230 {
1231    KeywordMap::const_iterator i;
1232    std::vector<ossimString> currentList;
1233    getSubstringKeyList(currentList, regularExpression);
1234    return (ossim_uint32)currentList.size();
1235 }
1236 
addPrefixToAll(const ossimString & prefix)1237 void ossimKeywordlist::addPrefixToAll(const ossimString& prefix)
1238 {
1239    ossimKeywordlist tempKwl = *this;
1240 
1241    clear();
1242 
1243    KeywordMap::const_iterator values = tempKwl.m_map.begin();
1244 
1245    while(values != tempKwl.m_map.end())
1246    {
1247       std::string newKey = prefix.string() + (*values).first;
1248       addPair(newKey, (*values).second, true);
1249       ++values;
1250    }
1251 }
1252 
addPrefixToKeysThatMatch(const ossimString & prefix,const ossimString & regularExpression)1253 void ossimKeywordlist::addPrefixToKeysThatMatch(const ossimString& prefix,
1254                                                 const ossimString& regularExpression)
1255 {
1256    ossimKeywordlist tempKwl = *this;
1257 
1258    clear();
1259 
1260    KeywordMap::const_iterator values = tempKwl.m_map.begin();
1261    ossimRegExp regExp;
1262 
1263    regExp.compile(regularExpression.c_str());
1264 
1265    while(values != tempKwl.m_map.end())
1266    {
1267       std::string newKey = prefix.string()+(*values).first;
1268       if(regExp.find( (*values).first.c_str()))
1269       {
1270 
1271          addPair(newKey, (*values).second, true);
1272       }
1273       else
1274       {
1275          addPair((*values).first, (*values).second, true);
1276       }
1277       ++values;
1278    }
1279 }
1280 
stripPrefixFromAll(const ossimString & regularExpression)1281 void ossimKeywordlist::stripPrefixFromAll(const ossimString& regularExpression)
1282 {
1283    ossimKeywordlist tempKwl = *this;
1284 
1285    clear();
1286 
1287    KeywordMap::const_iterator values = tempKwl.m_map.begin();
1288    ossimRegExp regExp;
1289 
1290    regExp.compile(regularExpression.c_str());
1291 
1292    while(values != tempKwl.m_map.end())
1293    {
1294       std::string newKey = (*values).first;
1295       if(regExp.find( (*values).first.c_str()))
1296       {
1297          newKey.erase(newKey.begin()+regExp.start(),
1298                       newKey.begin()+regExp.start()+regExp.end());
1299 
1300          addPair(newKey, (*values).second, true);
1301       }
1302       else
1303       {
1304          addPair(newKey, (*values).second, true);
1305       }
1306       ++values;
1307    }
1308 }
1309 
getSize() const1310 ossim_uint32 ossimKeywordlist::getSize()const
1311 {
1312    return (ossim_uint32)m_map.size();
1313 }
1314 
getMap() const1315 const ossimKeywordlist::KeywordMap& ossimKeywordlist::getMap()const
1316 {
1317    return m_map;
1318 }
1319 
getMap()1320 ossimKeywordlist::KeywordMap& ossimKeywordlist::getMap()
1321 {
1322    return m_map;
1323 }
1324 
change_delimiter(char del)1325 void ossimKeywordlist::change_delimiter(char del)
1326 {
1327    m_delimiter = del;
1328 }
1329 
delimiter_str() const1330 ossimString ossimKeywordlist::delimiter_str() const
1331 {
1332    char tmp[2];
1333    tmp[0] = m_delimiter;
1334    tmp[1] = '\0';
1335    return ossimString(tmp);
1336 }
1337 
1338 //*******************************************************************
1339 // Public Method:
1340 //*******************************************************************
print(std::ostream & os) const1341 std::ostream& ossimKeywordlist::print(std::ostream& os) const
1342 {
1343    writeToStream(os);
1344 #if 0
1345    KeywordMap::const_iterator i;
1346 
1347    for(i = m_map.begin(); i != m_map.end(); ++i)
1348    {
1349       os << (*i).first << delimiter_str().c_str() << "  "
1350       << (*i).second << std::endl;
1351    }
1352 #endif
1353    return os;
1354 }
1355 
1356 //*******************************************************************
1357 // friend function:
1358 //*******************************************************************
operator <<(std::ostream & os,const ossimKeywordlist & kwl)1359 OSSIMDLLEXPORT std::ostream& operator<<(std::ostream& os,
1360                                         const ossimKeywordlist& kwl)
1361 {
1362    kwl.print(os);
1363 
1364    return os;
1365 }
1366 
operator ==(ossimKeywordlist & kwl) const1367 bool ossimKeywordlist::operator ==(ossimKeywordlist& kwl)const
1368 {
1369    return (m_map == kwl.m_map);
1370    /*
1371    if(this==&kwl) return true;
1372    std::map<std::string, std::string>::const_iterator iter = m_map.begin();
1373 
1374    while(iter != m_map.end())
1375    {
1376       const char* value = kwl.find((*iter).first.c_str());
1377 
1378       if(ossimString(value) != (*iter).second)
1379       {
1380          return false;
1381       }
1382       ++iter;
1383    }
1384 
1385    return true;
1386    */
1387 }
1388 
operator !=(ossimKeywordlist & kwl) const1389 bool ossimKeywordlist::operator !=(ossimKeywordlist& kwl)const
1390 {
1391    return (m_map != kwl.m_map);
1392 }
1393 
downcaseKeywords()1394 ossimKeywordlist&  ossimKeywordlist::downcaseKeywords()
1395 {
1396    KeywordMap tempMap;
1397    KeywordMap::iterator iter = m_map.begin();
1398 
1399    while(iter != m_map.end())
1400    {
1401       ossimString k(iter->first);
1402       tempMap.insert(std::make_pair(k.downcase().string(), iter->second));
1403       ++iter;
1404    }
1405    m_map = tempMap;
1406 
1407    return *this;
1408 }
1409 
upcaseKeywords()1410 ossimKeywordlist& ossimKeywordlist::upcaseKeywords()
1411 {
1412    KeywordMap tempMap;
1413    KeywordMap::iterator iter = m_map.begin();
1414 
1415    while(iter != m_map.end())
1416    {
1417       ossimString k(iter->first);
1418       tempMap.insert(std::make_pair(k.upcase().string(), iter->second));
1419       ++iter;
1420    }
1421    m_map = tempMap;
1422 
1423    return *this;
1424 }
1425 
trimAllValues(const ossimString & valueToTrim)1426 ossimKeywordlist& ossimKeywordlist::trimAllValues(const ossimString& valueToTrim)
1427 {
1428    KeywordMap::iterator iter = m_map.begin();
1429 
1430    while(iter != m_map.end())
1431    {
1432       iter->second = ossimString(iter->second).trim(valueToTrim).string();
1433       ++iter;
1434    }
1435 
1436    return *this;
1437 }
1438 
trimAllValues(const ossimString & valueToTrim) const1439 ossimKeywordlist ossimKeywordlist::trimAllValues(const ossimString& valueToTrim)const
1440 {
1441    ossimKeywordlist result(*this);
1442    result.trimAllValues(valueToTrim);
1443    return result;
1444 }
1445 
1446 
1447 //*************************************************************************************************
1448 //! [OLK, Aug/2008]
1449 //! Sets the boolean destination arg depending on value associated with keyword for values =
1450 //! (yes|no|true|false|1|0). Returns TRUE if keyword found, otherwise false. Also returns false
1451 //! if none of the above permitted values are specified (rtn_val left unchanged in this case).
1452 //*************************************************************************************************
getBoolKeywordValue(bool & rtn_val,const char * keyword,const char * prefix) const1453 bool ossimKeywordlist::getBoolKeywordValue(bool& rtn_val,
1454                                            const char* keyword,
1455                                            const char* prefix) const
1456 {
1457    bool found = true;
1458    const char* val_str = find(prefix, keyword);
1459    if (val_str)
1460    {
1461       found = true;
1462       ossimString yesno (val_str);
1463       yesno.upcase();
1464       if ((yesno == "YES") || (yesno == "TRUE") || (yesno == "1"))
1465          rtn_val = true;
1466       else if ((yesno == "NO") || (yesno == "FALSE") || (yesno == "0"))
1467          rtn_val = false;
1468       else
1469          found = false;
1470    }
1471    else
1472       found = false;
1473 
1474    return found;
1475 }
1476 
isSpecialXmlCharacters(const ossimString & value) const1477 bool ossimKeywordlist::isSpecialXmlCharacters(const ossimString& value)const
1478 {
1479    for(ossimString::const_iterator it = value.begin(); it != value.end();++it)
1480    {
1481       switch(*it)
1482       {
1483          case '&':
1484          case '<':
1485          case '>':
1486          case '"':
1487          case '\'':
1488          {
1489             return true;
1490          }
1491          default:
1492          {
1493             break;
1494          }
1495       }
1496 
1497    }
1498    return false;
1499 }
1500 
isValidTag(const std::string & value) const1501 bool ossimKeywordlist::isValidTag(const std::string& value)const
1502 {
1503    std::string::const_iterator textChars = value.begin();
1504    bool result = true;
1505    if(!isalpha(*(textChars) ))
1506    {
1507       result = false;
1508    }
1509    else if(!value.empty())
1510    {
1511       for(++textChars;textChars!=value.end();++textChars)
1512       {
1513          if(!isalnum(*(textChars) ))
1514          {
1515             result = false;
1516             break;
1517          }
1518       }
1519    }
1520    else
1521    {
1522       result = false;
1523    }
1524 
1525    return result;
1526 }
1527 
replaceSpecialCharacters(ossimString & value) const1528 void ossimKeywordlist::replaceSpecialCharacters(ossimString& value)const
1529 {
1530    ossimString::iterator iter = value.begin();
1531 
1532    while(iter!=value.end())
1533    {
1534       if(!(isdigit(*iter) ||
1535            isalpha(*iter)||
1536            (*iter=='/')))
1537       {
1538          *iter = '_';
1539       }
1540       ++iter;
1541    }
1542 }
1543 
toXML(std::ostream & out,const std::string & rootTag) const1544 void ossimKeywordlist::toXML(std::ostream& out, const std::string& rootTag)const
1545 {
1546    std::string rootTagStr = rootTag;
1547    if (!isValidTag(rootTagStr))
1548    {
1549       rootTagStr = "info";
1550    }
1551 
1552    ossimRefPtr<ossimXmlNode> metadata = new ossimXmlNode;
1553    metadata->setTag("metadata");
1554    ossimKeywordlist::KeywordMap::const_iterator iter = m_map.begin();
1555    while(iter != m_map.end())
1556    {
1557       ossimString path = iter->first;
1558       bool outputValue = true;
1559       ossimString value = iter->second;
1560       if(path.contains("unformatted_tag_data"))
1561       {
1562          ossimString temp = value.trim();
1563          if(ossimString(temp.begin(), temp.begin()+5) == "<?xml")
1564          {
1565             value = "XML not converted";
1566             outputValue = false;
1567          }
1568       }
1569 
1570       if(outputValue)
1571       {
1572          bool tagOk = true;
1573          path = path.substitute(".", "/", true);
1574          replaceSpecialCharacters(path);
1575          std::vector<ossimString> splitValues;
1576          path.split(splitValues,"/");
1577          if(splitValues.size())
1578          {
1579             splitValues[splitValues.size()-1] = splitValues[splitValues.size()-1].downcase();
1580             ossim_uint32 idx = 0;
1581             for(idx = 0; ((idx < splitValues.size()-1)&&tagOk);++idx)
1582             {
1583                if(!isValidTag(splitValues[idx]))
1584                {
1585                   tagOk = false;
1586                }
1587                splitValues[idx] = splitValues[idx].upcase();
1588             }
1589          }
1590          if(tagOk)
1591          {
1592             path.join(splitValues, "/");
1593             ossimRefPtr<ossimXmlNode> node = metadata->addNode(path.c_str(), value);
1594             if(isSpecialXmlCharacters(value))
1595             {
1596                node->setCDataFlag(true);
1597             }
1598          }
1599       }
1600       ++iter;
1601    }
1602 
1603    if( 1 ) // tmp dbr !m_includeMetadataTagName)
1604    {
1605       out << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" << std::endl
1606           << "<" << rootTagStr << ">\n";
1607 
1608       const ossimXmlNode::ChildListType& children = metadata->getChildNodes();
1609       ossimXmlNode::ChildListType::const_iterator iter = children.begin();
1610       while(iter != children.end())
1611       {
1612          out << *(iter->get());
1613          ++iter;
1614       }
1615       out << "\n</" << rootTagStr << ">" << std::endl;
1616    }
1617    else
1618    {
1619       out << *(metadata.get()) << std::endl;
1620    }
1621 }
1622 
1623 
toJSON(std::ostream & out,const std::string & rootTag) const1624 void ossimKeywordlist::toJSON(std::ostream& out, const std::string& rootTag)const
1625 {
1626    const std::string C   = ": "; // colon
1627    const std::string DQ  = "\""; // double Quote
1628    const std::string LB  = "{"; // left bracket
1629    const std::string CNL = ",\n"; // coma, new line
1630    const std::string NL  = "\n"; // new line
1631    const std::string RB  = "}"; // left bracket
1632    const std::string S   = " ";  // space
1633    ossim_uint32 nameCount = 0;
1634    ossimString lastObject;
1635    ossim_uint32 indentCount = 3;
1636    ossim_uint32 indentOffset = 3;
1637 
1638    bool stringify = true;
1639    bool closeObject = false;
1640    std::vector<ossimString> objectStack;
1641 
1642    // Opening bracket:
1643    out << LB;
1644 
1645    if( rootTag.size() )
1646    {
1647       if ( stringify )
1648       {
1649          indentOffset = indentCount;
1650          std::string indent(indentCount, ' ');
1651          out << NL << indent;
1652       }
1653       else
1654       {
1655          out << NL;
1656       }
1657       // Note: not adding rootTag to object stack
1658       out << DQ << rootTag << DQ << C << LB << NL;
1659    }
1660 
1661    ossimKeywordlist::KeywordMap::const_iterator iter = m_map.begin();
1662    while(iter != m_map.end())
1663    {
1664       bool outputValue  = true;
1665       ossimString key   = iter->first;
1666       ossimString value = iter->second;
1667       value = value.trim(); // remove spaces
1668 
1669 #if 0
1670       if(key.contains("unformatted_tag_data"))
1671       {
1672          ossimString temp = value.trim();
1673          if(ossimString(temp.begin(), temp.begin()+5) == "<?xml")
1674          {
1675             value = "data not converted";
1676             outputValue = false;
1677          }
1678       }
1679 #endif
1680 
1681       if ( outputValue && key.size() )
1682       {
1683          std::vector<ossimString> keys;
1684          key.split(keys,".");
1685 
1686          if ( keys.size() )
1687          {
1688             // The last key is the name so grab it now and pop it off the stack:
1689             ossimString name = keys[keys.size()-1];
1690             keys.pop_back();
1691 
1692             bool sameObject = isSame( keys, objectStack );
1693             if ( !sameObject && keys.size() )
1694             {
1695                for ( ossim_uint32 i = 0; i < keys.size(); ++i )
1696                {
1697                   if ( i < objectStack.size() )
1698                   {
1699                      if ( keys[i] == objectStack[i] )
1700                      {
1701                         // On stack already. Nothng to do. Go to next key.
1702                         continue;
1703                      }
1704                      else
1705                      {
1706                         // Different object:
1707                         while ( i <  objectStack.size() )
1708                         {
1709                            // Write bracket, then pop:
1710                            if ( stringify )
1711                            {
1712                               std::string indent(indentOffset+(indentCount*objectStack.size()), ' ');
1713                               out << NL << indent << RB;
1714                            }
1715                            else
1716                            {
1717                               out << NL << RB;
1718                            }
1719                            objectStack.pop_back();
1720                            nameCount = 0;
1721                            closeObject = true;
1722                            if ( objectStack.size() )
1723                            {
1724                               lastObject = objectStack[objectStack.size()-1];
1725                            }
1726                            else
1727                            {
1728                               lastObject.clear();
1729                            }
1730                         }
1731                      }
1732                   }
1733 
1734                   //---
1735                   // New object:
1736                   // If we had written a key:value for previos object, do a
1737                   // newline and zero it out.
1738                   //---
1739                   if ( nameCount )
1740                   {
1741                      out << CNL;
1742                      nameCount = 0;
1743                   }
1744 
1745                   objectStack.push_back( keys[i] );
1746 
1747                   if ( closeObject )
1748                   {
1749                      out << CNL;
1750                      closeObject = false;
1751                   }
1752 
1753                   if ( stringify )
1754                   {
1755                      std::string indent(indentOffset+(indentCount*objectStack.size()), ' ');
1756                      out << indent;
1757                   }
1758                   out << DQ << keys[i] << DQ << C << LB << NL;
1759                }
1760 
1761                // Final check if keys shrunk, pop objects off the object stack.
1762                while ( keys.size() <  objectStack.size() )
1763                {
1764                   // Write bracket then pop:
1765                   if ( stringify )
1766                   {
1767                      std::string indent(indentOffset+(indentCount*objectStack.size()), ' ');
1768                      out << NL << indent << RB;
1769                   }
1770                   else
1771                   {
1772                      out << NL << RB;
1773                   }
1774                   objectStack.pop_back();
1775                   nameCount = 0;
1776                   closeObject = true;
1777                   if ( objectStack.size() )
1778                   {
1779                      lastObject = objectStack[objectStack.size()-1];
1780                   }
1781                   else
1782                   {
1783                      lastObject.clear();
1784                   }
1785                }
1786             }
1787 
1788             if ( objectStack.size() )
1789             {
1790                if ( lastObject == objectStack[objectStack.size()-1] )
1791                {
1792                   out << CNL;
1793                   closeObject = false;
1794                }
1795             }
1796             else if ( nameCount ) // No objects loaded on the stack.
1797             {
1798                out << CNL;
1799             }
1800 
1801             // Output "key": "value"
1802             if ( stringify )
1803             {
1804                std::string indent(indentOffset+indentCount*(objectStack.size()+1), ' ');
1805                out << indent;
1806             }
1807             out << DQ << name << DQ << C << DQ << value << DQ;
1808 
1809             if ( objectStack.size() )
1810             {
1811                lastObject = objectStack[objectStack.size()-1];
1812             }
1813             else
1814             {
1815                lastObject.clear();
1816             }
1817 
1818             ++nameCount;
1819          }
1820       }
1821       ++iter;
1822 
1823    } // Matches: while(iter != m_map.end())
1824 
1825    // Close out brackets:
1826    ossim_uint32 stackSize = objectStack.size();
1827    if ( stackSize )
1828    {
1829       for ( ossim_uint32 i = stackSize; i > 0; --i )
1830       {
1831          if ( stringify )
1832          {
1833             std::string indent(indentOffset+indentCount*i, ' ');
1834             out << NL << indent << RB;
1835          }
1836          else
1837          {
1838             out << NL << RB;
1839          }
1840       }
1841    }
1842 
1843    if( rootTag.size() )
1844    {
1845       if ( stringify )
1846       {
1847          std::string indent(indentCount, ' ');
1848          out << NL << indent << RB;
1849       }
1850       else
1851       {
1852          out << NL << RB;
1853       }
1854    }
1855 
1856    // Closing bracket, newline with flush:
1857    out << NL << RB << std::endl;
1858 }
1859 
isSame(const std::vector<ossimString> & a,const std::vector<ossimString> & b) const1860 bool ossimKeywordlist::isSame( const std::vector<ossimString>& a,
1861                                const std::vector<ossimString>& b ) const
1862 {
1863    bool result = true;
1864    if ( a.size() == b.size() )
1865    {
1866       for ( ossim_uint32 i = 0; i < a.size(); ++i )
1867       {
1868          if ( a[i] != b[i] )
1869          {
1870             result = false;
1871             break;
1872          }
1873       }
1874    }
1875    else
1876    {
1877       result = false;
1878    }
1879    return result;
1880 }
1881