1 // Copyright 2008, Google Inc. All rights reserved.
2 //
3 // Redistribution and use in source and binary forms, with or without
4 // modification, are permitted provided that the following conditions are met:
5 //
6 //  1. Redistributions of source code must retain the above copyright notice,
7 //     this list of conditions and the following disclaimer.
8 //  2. Redistributions in binary form must reproduce the above copyright notice,
9 //     this list of conditions and the following disclaimer in the documentation
10 //     and/or other materials provided with the distribution.
11 //  3. Neither the name of Google Inc. nor the names of its contributors may be
12 //     used to endorse or promote products derived from this software without
13 //     specific prior written permission.
14 //
15 // THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
16 // WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
17 // MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
18 // EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
19 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20 // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
21 // OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
22 // WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
23 // OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
24 // ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 
26 // This file maps the C-based expat to a general purpose C++ ExpatHandler class.
27 // KmlHandler is the only such handler at present, hence the static nature
28 // of the ExpatParser() function.
29 
30 #include "kml/dom/kml_funcs.h"
31 #include <cstring>
32 #include <sstream>
33 #include "kml/base/attributes.h"
34 #include "kml/base/expat_parser.h"
35 #include "kml/base/expat_handler_ns.h"
36 #include "kml/base/xmlns.h"
37 #include "kml/dom/element.h"
38 #include "kml/dom/kml_handler.h"
39 #include "kml/dom/kml_handler_ns.h"
40 #include "kml/dom/parser.h"
41 #include "kml/dom/parser_observer.h"
42 
43 namespace kmldom {
44 
45 // This is an internal API to add Element-level SAX-style handlers to
46 // a given parser instance.  TODO: determine how/if to make public and SWIG.
AddObserver(ParserObserver * parser_observer)47 void Parser::AddObserver(ParserObserver* parser_observer) {
48   observers_.push_back(parser_observer);
49 }
50 
51 // This is the internal API to the parser.  TODO: determine how/if to make
52 // public and SWIG.
Parse(const string & kml,string * errors)53 ElementPtr Parser::Parse(const string& kml, string* errors) {
54   KmlHandler kml_handler(observers_);
55   kmlbase::ExpatParser parser(&kml_handler, false);
56   if (kmlbase::ExpatParser::ParseString(kml, &kml_handler, errors, false)) {
57     return kml_handler.PopRoot();
58   }
59   return NULL;
60 }
61 
62 
63 // As Parser::Parse(), but invokes the underlying XML parser's namespace-aware
64 // mode.
ParseNS(const string & kml,string * errors)65 ElementPtr Parser::ParseNS(const string& kml, string* errors) {
66   KmlHandlerNS kml_handler(observers_);
67   if (kmlbase::ExpatParser::ParseString(kml, &kml_handler, errors, true)) {
68     return kml_handler.PopRoot();
69   }
70   return NULL;
71 }
72 
73 // This is obviously a bit of a special case.  If libkml always used full
74 // namespace-aware parsing we'd not need this.
ParseAtom(const string & atom,string * errors)75 ElementPtr Parser::ParseAtom(const string& atom, string* errors) {
76   // Create a garden variety KML parser with "short-hand" namespace prefixes
77   // for Atom.
78   KmlHandler kml_handler(observers_);
79   kmlbase::Attributes attributes;
80   // Create a namespace aware expat handler which converts the Atom namespace
81   // elements to the "short-hand" namespace prefixing used in KmlHandler.
82   // Here's the overall flow:
83   // 1) instance file has <feed xmlns="http://www.w3.org/2005/Atom">...
84   // 2) namespace-enabled expat turns this into:
85   //    <http://www.w3.org/2005/Atom|feed>
86   // 3) ExpatHandlerNns turns this to <atom:feed>
87   // 4) KmlHandler knows that <atom:feed> is kmldom::AtomFeed
88   attributes.SetValue("xmlns", "http://www.opengis.net/kml/2.2");
89   attributes.SetValue("xmlns:atom", "http://www.w3.org/2005/Atom");
90   boost::scoped_ptr<kmlbase::Xmlns> xmlns(kmlbase::Xmlns::Create(attributes));
91   kmlbase::ExpatHandlerNs expat_handler_ns(&kml_handler, xmlns.get());
92   if (kmlbase::ExpatParser::ParseString(atom, &expat_handler_ns, errors,
93                                         true)) {
94     return kml_handler.PopRoot();
95   }
96   return NULL;
97 }
98 
99 // This is the implementation of the public API to parse KML from a memory
100 // buffer.
Parse(const string & kml,string * errors)101 ElementPtr Parse(const string& kml, string* errors) {
102   Parser parser;
103   return parser.Parse(kml, errors);
104 }
105 
106 // As Parse(), but invokes the underlying XML parser's namespace-aware mode.
ParseNS(const string & kml,string * errors)107 ElementPtr ParseNS(const string& kml, string* errors) {
108   Parser parser;
109   return parser.ParseNS(kml, errors);
110 }
111 
112 // Parse the KML in the given string.  NULL is returned on any parse errors,
113 // but the error string is unavailable with this function.
ParseKml(const string & kml)114 ElementPtr ParseKml(const string& kml) {
115   return Parse(kml, NULL);
116 }
117 
ParseAtom(const string & atom,string * errors)118 ElementPtr ParseAtom(const string& atom, string* errors) {
119   Parser parser;
120   return parser.ParseAtom(atom, errors);
121 }
122 
123 } // end namespace kmldom
124