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 contains the declaration of the KmlFile class.
27 
28 #ifndef KML_ENGINE_KML_FILE_H__
29 #define KML_ENGINE_KML_FILE_H__
30 
31 #include <ostream>
32 #include <vector>
33 #include "boost/scoped_ptr.hpp"
34 #include "kml/base/attributes.h"
35 #include "kml/base/referent.h"
36 #include "kml/base/xml_namespaces.h"
37 #include "kml/base/util.h"
38 #include "kml/base/xml_file.h"
39 #include "kml/dom.h"
40 #include "kml/engine/engine_types.h"
41 #include "kml/engine/get_link_parents.h"
42 #include "kml/engine/object_id_parser_observer.h"
43 #include "kml/engine/shared_style_parser_observer.h"
44 
45 namespace kmlengine {
46 
47 class KmlCache;
48 
49 // The KmlFile class represents the instance of a KML file from a given URL.
50 // A KmlFile manages an XML id domain and includes an internal map of all
51 // id'ed Objects, shared styles, and name'ed Schemas and a list of all links.
52 // KmlFile is a fundamental component of the KML Engine and is central in the
53 // use of shared style resolution.
54 class KmlFile : public kmlbase::XmlFile {
55  public:
56   // This creates a KmlFile from a memory buffer of either KML or KMZ data.
57   // In the case of KMZ the KmzFile module's ReadKml() is used to read the
58   // KML data from the KMZ archive.  On any parse errors NULL is returned
59   // and a human readable error message is saved in the supplied string.
60   // The caller is responsible for deleting the KmlFile this creates.
61   static KmlFile* CreateFromParse(const string& kml_or_kmz_data,
62                                   string *errors);
63 
64   // This method is for use with NetCache CacheItem.
CreateFromString(const string & kml_or_kmz_data)65   static KmlFile* CreateFromString(const string& kml_or_kmz_data) {
66     // Internal KML fetch/parse (styleUrl, etc) errors are quietly ignored.
67     return CreateFromParse(kml_or_kmz_data, NULL);
68   }
69 
70   // This method is for use with KmlCache.  The purpose is to keep set_url()
71   // and set_kml_cache() private and at creation-time.
72   static KmlFile* CreateFromStringWithUrl(const string& kml_data,
73                                           const string& url,
74                                           KmlCache* kml_cache);
75 
76   // This creates a KmlFile from the given element hierarchy.  This variant of
77   // CreateFromImport fails on id duplicates.
78   static KmlFile* CreateFromImport(const kmldom::ElementPtr& element);
79 
80   // This creates a KmlFile from the given element hierarchy.  This variant of
81   // CreateFromImport employs a "last one wins" strategy for id duplicates.
82   static KmlFile* CreateFromImportLax(const kmldom::ElementPtr& element);
83 
84   // This returns the root element of this KML file.
get_root()85   const kmldom::ElementPtr get_root() const {
86     return kmldom::AsElement(XmlFile::get_root());
87   }
88 
89   // Deprecated.  Use get_root().
root()90   const kmldom::ElementPtr root() const {
91     return get_root();
92   }
93 
94   // This serializes the KML from the root.  The xmlns() value is added to
95   // the root element, the set of namespace prefixes to namespaces is added,
96   // and the encoding is set in a prepended XML header:
97   //    <?xml version="1.0" encoding="ENCODING">
98   //    <kml xmlns="XMLNS" xmlns:PREFIX1="XMLNS1" xmlns:PREFIX2="XMLNS2"...>
99   //    ...
100   //    </kml>
101   bool SerializeToString(string* xml_output) const;
102 
103   // This does as SerializeToString() except to an ostream.
104   bool SerializeToOstream(std::ostream* xml_output) const;
105 
106   // This returns the XML header including the encoding:
107   // The default is this: "<?version="1.0" encoding="utf-8"?>
108   const string CreateXmlHeader() const;
109 
110   // These methods access the XML encoding of the XML file.
111   // TODO: set should be create time only.
set_encoding(const string & encoding)112   void set_encoding(const string& encoding) {
113     encoding_ = encoding;
114   }
get_encoding()115   const string& get_encoding() const {
116     return encoding_;
117   }
118 
119   // This returns the Object Element with the given id.  A NULL Object is
120   // returned if no Object with this id exists in the KML file.
121   kmldom::ObjectPtr GetObjectById(const string& id) const;
122 
123   // This returns the shared StyleSelector Element with the given id.  NULL is
124   // returned if no StyleSelector with this id exists as a shared style
125   // selector in the KML file.
126   kmldom::StyleSelectorPtr GetSharedStyleById(const string& id) const;
127 
get_shared_style_map()128   const SharedStyleMap& get_shared_style_map() const {
129     return shared_style_map_;
130   }
131 
132   // This returns the all Elements that may have link children.  See
133   // GetLinkParents() for more information.
get_link_parent_vector()134   const ElementVector& get_link_parent_vector() const {
135     return link_parent_vector_;
136   }
137 
138   // This is the KmlCache which created this KmlFile.  This may be NULL if this
139   // KmlFile was not created using CreateFromStringWithUrl().
get_kml_cache()140   KmlCache* get_kml_cache() const {
141     return kml_cache_;
142   }
143 
144   // Duplicate id attributes are illegal and should cause the parse to fail.
145   // However, Google Earth never enforced this in its KML ingest and thus the
146   // web has a lot of invalid KML. We attempt to parse this by default. A
147   // client may use set_strict_parse(true) to override this, which will
148   // instruct the ObjectIdParserObserver to fail on duplicate ids.
set_strict_parse(bool val)149   void set_strict_parse(bool val) {
150     strict_parse_ = val;
151   }
152 
153  private:
154   // Constructor is private.  Use static Create methods.
155   KmlFile();
156 
157   // This is an internal helper function for the public CreateFromImport*()
158   // methods.
159   static KmlFile* CreateFromImportInternal(const kmldom::ElementPtr& element,
160                                            bool disallow_duplicate_ids);
161 
162   // This is an internal method used in the static Create methods.
163   bool ParseFromString(const string& kml, string* errors);
164 
165   // Only static Create methods can set the KmlCache.
set_kml_cache(KmlCache * kml_cache)166   void set_kml_cache(KmlCache* kml_cache) {
167     kml_cache_ = kml_cache;
168   }
169   // These are helper functions for CreateFromParse().
170   bool _CreateFromParse(const string& kml_or_kmz_data,
171                         string* errors);
172   bool OpenAndParseKmz(const string& kmz_data, string* errors);
173   string encoding_;
174   // TODO: use XmlElement's id map.
175   ObjectIdMap object_id_map_;
176   SharedStyleMap shared_style_map_;
177   ElementVector link_parent_vector_;
178   KmlCache* kml_cache_;
179   bool strict_parse_;
180   LIBKML_DISALLOW_EVIL_CONSTRUCTORS(KmlFile);
181 };
182 
183 typedef boost::intrusive_ptr<KmlFile> KmlFilePtr;
184 
185 }  // end namespace kmlengine
186 
187 #endif  // KML_ENGINE_KML_FILE_H__
188