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 // Walk a KML NetworkLink hierarchy.
27 // Fetches and parses the NetworkLinks in a given file recursively.
28 // Prints a count of the number of KML files fetched and the total number
29 // of each kind of Feature in the hierachy.
30 
31 #include <iostream>
32 #include <map>
33 #include <string>
34 #include "kml/dom.h"
35 #include "kml/dom/xsd.h"  // TODO: expose Xsd::ElementName() properly
36 #include "kml/engine.h"
37 #include "curlfetch.h"
38 
39 using kmldom::ElementPtr;
40 using kmldom::FeaturePtr;
41 using kmldom::NetworkLinkPtr;
42 using kmldom::OverlayPtr;
43 using kmldom::StylePtr;
44 using kmlengine::KmlFile;
45 using kmlengine::KmlFilePtr;
46 using kmlengine::KmlCache;
47 using kmlengine::GetRootFeature;
48 using kmlengine::VisitFeatureHierarchy;
49 using std::cerr;
50 using std::cout;
51 using std::endl;
52 
53 static void CountFeature(int type_id);
54 static void PrintFeatureCounts();
55 static void PrintFileCount();
56 static void WalkKmlFile(const KmlFilePtr& kml_file);
57 
58 static int file_count;
59 static int feature_count;
60 static size_t data_size;
61 static size_t style_size;
62 static size_t balloon_size;
63 
PrintFileCount()64 static void PrintFileCount() {
65   cout << "files " << file_count << endl;
66   cout << "features " << feature_count << endl;
67   cout << "data bytes " << data_size << endl;
68   cout << "style bytes " << style_size << endl;
69   cout << "balloon bytes " << balloon_size << endl;
70 }
71 
72 typedef std::map<int,int> feature_counter_t;
73 feature_counter_t feature_counter;
74 
CountFeature(int type_id)75 static void CountFeature(int type_id) {
76   ++feature_count;
77   feature_counter_t::const_iterator entry = feature_counter.find(type_id);
78   if (entry == feature_counter.end()) {
79     feature_counter[type_id] = 1;
80   } else {
81     ++feature_counter[type_id];
82   }
83 }
84 
PrintFeatureCounts()85 static void PrintFeatureCounts() {
86   for (feature_counter_t::const_iterator iter = feature_counter.begin();
87        iter != feature_counter.end(); ++iter) {
88     std::string element_name;
89     cout << kmldom::Xsd::GetSchema()->ElementName(iter->first) << " "
90       << iter->second << endl;
91   }
92 }
93 
94 class FeatureCounter : public kmlengine::FeatureVisitor {
95  public:
FeatureCounter(const KmlFilePtr & kml_file)96   FeatureCounter(const KmlFilePtr& kml_file)
97       : kml_file_(kml_file) {}
98 
VisitFeature(const kmldom::FeaturePtr & feature)99   virtual void VisitFeature(const kmldom::FeaturePtr& feature) {
100     CountFeature(feature->Type());
101     StylePtr style = CreateResolvedStyle(feature, kml_file_,
102                                          kmldom::STYLESTATE_NORMAL);
103     std::string style_string = kmldom::SerializePretty(style);
104     style_size += style_string.size();
105     std::string balloon_text = CreateBalloonText(kml_file_, feature);
106     balloon_size += balloon_text.size();
107     if (OverlayPtr overlay = AsOverlay(feature)) {
108       std::string data;
109       if (kmlengine::FetchIcon(kml_file_, overlay, &data)) {
110         cout << " bytes " << data.size() << endl;
111         data_size += data.size();
112       } else {
113         cout << "fetch failed " << endl;
114       }
115     }
116   }
117 
118  private:
119   const KmlFilePtr kml_file_;
120 };
121 
HandleFile(const KmlFilePtr & kml_file)122 static void HandleFile(const KmlFilePtr& kml_file) {
123   cout << kml_file->get_url() << endl;
124   ++file_count;
125   FeatureCounter feature_counter(kml_file);
126   VisitFeatureHierarchy(GetRootFeature(kml_file->get_root()), feature_counter);
127 }
128 
WalkNetworkLinks(const KmlFilePtr & kml_file)129 static void WalkNetworkLinks(const KmlFilePtr& kml_file) {
130   const kmlengine::ElementVector& link_vector =
131       kml_file->get_link_parent_vector();
132   for (size_t i = 0; i < link_vector.size(); ++i) {
133     if (NetworkLinkPtr networklink = AsNetworkLink(link_vector[i])) {
134       if (KmlFilePtr child = kmlengine::FetchLink(kml_file, networklink)) {
135         WalkKmlFile(child);
136       }
137     }
138   }
139 }
140 
WalkKmlFile(const KmlFilePtr & kml_file)141 static void WalkKmlFile(const KmlFilePtr& kml_file) {
142   // First walk through this KmlFile's Features.
143   HandleFile(kml_file);
144   // Then walk recursively through all of its NetworkLinks.
145   WalkNetworkLinks(kml_file);
146 }
147 
main(int argc,char ** argv)148 int main(int argc, char** argv) {
149   if (argc != 2) {
150     cout << "usage: " << argv[0] << " url" << endl;
151     return 1;
152   }
153   const char* kml_url = argv[1];
154   CurlNetFetcher curl_net_fetcher;
155   KmlCache kml_cache(&curl_net_fetcher, 30);
156   const KmlFilePtr kml_file = kml_cache.FetchKmlAbsolute(kml_url);
157   if (!kml_file) {
158     cerr << "failed: " << kml_url << endl;
159     return 1;
160   }
161   WalkKmlFile(kml_file);
162   PrintFileCount();
163   PrintFeatureCounts();
164 }
165