Line data Source code
1 : /******************************************************************************
2 : *
3 : * Project: KML Translator
4 : * Purpose: Implements OGRLIBKMLDriver
5 : * Author: Brian Case, rush at winkey dot org
6 : *
7 : ******************************************************************************
8 : * Copyright (c) 2010, Brian Case
9 : * Copyright (c) 2010-2014, Even Rouault <even dot rouault at spatialys.com>
10 : *
11 : * Permission is hereby granted, free of charge, to any person obtaining a
12 : * copy of this software and associated documentation files (the "Software"),
13 : * to deal in the Software without restriction, including without limitation
14 : * the rights to use, copy, modify, merge, publish, distribute, sublicense,
15 : * and/or sell copies of the Software, and to permit persons to whom the
16 : * Software is furnished to do so, subject to the following conditions:
17 : *
18 : * The above copyright notice and this permission notice shall be included
19 : * in all copies or substantial portions of the Software.
20 : *
21 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
22 : * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23 : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
24 : * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25 : * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
26 : * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
27 : * DEALINGS IN THE SOFTWARE.
28 : *****************************************************************************/
29 :
30 : #include "libkml_headers.h"
31 :
32 : #include "ogrsf_frmts.h"
33 : #include "ogr_featurestyle.h"
34 : #include <string>
35 : #include "ogrlibkmlfeaturestyle.h"
36 : #include "ogrlibkmlstyle.h"
37 :
38 : using kmldom::FeaturePtr;
39 : using kmldom::IconStylePtr;
40 : using kmldom::KmlFactory;
41 : using kmldom::LabelStylePtr;
42 : using kmldom::LineStylePtr;
43 : using kmldom::PolyStylePtr;
44 : using kmldom::StyleMapPtr;
45 : using kmldom::StylePtr;
46 : using kmldom::StyleSelectorPtr;
47 :
48 : /******************************************************************************
49 : function to write out a features style to kml
50 :
51 : Args:
52 : poOgrLayer the layer the feature is in
53 : poOgrFeat the feature
54 : poKmlFactory the kml dom factory
55 : poKmlFeature the placemark to add it to
56 :
57 : Returns:
58 : nothing
59 : ******************************************************************************/
60 :
61 143 : void featurestyle2kml(OGRLIBKMLDataSource *poOgrDS, OGRLayer *poOgrLayer,
62 : OGRFeature *poOgrFeat, KmlFactory *poKmlFactory,
63 : FeaturePtr poKmlFeature)
64 : {
65 : /***** get the style table *****/
66 143 : OGRStyleTable *poOgrSTBL = nullptr;
67 :
68 143 : const char *pszStyleString = poOgrFeat->GetStyleString();
69 :
70 : /***** does the feature have style? *****/
71 143 : if (pszStyleString && pszStyleString[0] != '\0')
72 : {
73 : /***** does it ref a style table? *****/
74 2 : if (*pszStyleString == '@')
75 : {
76 1 : const char *pszStyleName = pszStyleString + 1;
77 :
78 : /***** Is the name in the layer style table *****/
79 1 : OGRStyleTable *hSTBLLayer = poOgrLayer->GetStyleTable();
80 : const char *pszTest = (hSTBLLayer != nullptr)
81 1 : ? hSTBLLayer->Find(pszStyleName)
82 1 : : nullptr;
83 :
84 1 : if (pszTest)
85 : {
86 0 : string oTmp = "#";
87 0 : oTmp.append(pszStyleName);
88 0 : poKmlFeature->set_styleurl(oTmp);
89 : }
90 : /***** assume its a dataset style,
91 : maybe the user will add it later *****/
92 : else
93 : {
94 2 : string oTmp;
95 :
96 1 : if (poOgrDS->GetStylePath())
97 1 : oTmp.append(poOgrDS->GetStylePath());
98 1 : oTmp.append("#");
99 1 : oTmp.append(pszStyleName);
100 :
101 1 : poKmlFeature->set_styleurl(oTmp);
102 : }
103 : }
104 : /***** no style table ref *****/
105 : else
106 : {
107 : /***** parse the style string *****/
108 : const StylePtr poKmlStyle = addstylestring2kml(
109 3 : pszStyleString, nullptr, poKmlFactory, poKmlFeature);
110 :
111 : /***** add the style to the placemark *****/
112 1 : if (poKmlStyle)
113 1 : poKmlFeature->set_styleselector(poKmlStyle);
114 2 : }
115 : }
116 : /***** get the style table *****/
117 141 : else if ((poOgrSTBL = poOgrFeat->GetStyleTable()) != nullptr)
118 : {
119 : /***** parse the style table *****/
120 0 : poOgrSTBL->ResetStyleStringReading();
121 :
122 0 : while ((pszStyleString = poOgrSTBL->GetNextStyle()) != nullptr)
123 : {
124 0 : if (*pszStyleString == '@')
125 : {
126 0 : const char *pszStyleName = pszStyleString + 1;
127 :
128 : /***** is the name in the layer style table *****/
129 0 : OGRStyleTable *poOgrSTBLLayer = nullptr;
130 :
131 0 : if ((poOgrSTBLLayer = poOgrLayer->GetStyleTable()) != nullptr)
132 : {
133 0 : poOgrSTBLLayer->Find(pszStyleName);
134 : }
135 :
136 : /***** Assume its a dataset style, *****/
137 : /***** mayby the user will add it later. *****/
138 :
139 0 : string oTmp;
140 0 : if (poOgrDS->GetStylePath())
141 0 : oTmp.append(poOgrDS->GetStylePath());
142 0 : oTmp.append("#");
143 0 : oTmp.append(pszStyleName);
144 :
145 0 : poKmlFeature->set_styleurl(oTmp);
146 : }
147 : else
148 : {
149 : /***** parse the style string *****/
150 : const StylePtr poKmlStyle = addstylestring2kml(
151 0 : pszStyleString, nullptr, poKmlFactory, poKmlFeature);
152 0 : if (poKmlStyle)
153 : {
154 : /***** Add the style to the placemark. *****/
155 0 : poKmlFeature->set_styleselector(poKmlStyle);
156 : }
157 : }
158 : }
159 : }
160 143 : }
161 :
162 : /******************************************************************************
163 : function to read a kml style into ogr's featurestyle
164 : ******************************************************************************/
165 :
166 777 : void kml2featurestyle(FeaturePtr poKmlFeature, OGRLIBKMLDataSource *poOgrDS,
167 : OGRLayer *poOgrLayer, OGRFeature *poOgrFeat)
168 : {
169 : /***** does the placemark have a style url? *****/
170 777 : if (poKmlFeature->has_styleurl())
171 : {
172 972 : const string poKmlStyleUrl = poKmlFeature->get_styleurl();
173 :
174 : /***** is the name in the layer style table *****/
175 486 : char *pszUrl = CPLStrdup(poKmlStyleUrl.c_str());
176 :
177 486 : OGRStyleTable *poOgrSTBLLayer = nullptr;
178 486 : const char *pszTest = nullptr;
179 :
180 : /***** is it a layer style ? *****/
181 972 : if (*pszUrl == '#' &&
182 486 : (poOgrSTBLLayer = poOgrLayer->GetStyleTable()) != nullptr)
183 : {
184 41 : pszTest = poOgrSTBLLayer->Find(pszUrl + 1);
185 : }
186 :
187 486 : if (pszTest)
188 : {
189 : /***** should we resolve the style *****/
190 : const char *pszResolve =
191 41 : CPLGetConfigOption("LIBKML_RESOLVE_STYLE", "no");
192 :
193 41 : if (CPLTestBool(pszResolve))
194 : {
195 0 : poOgrFeat->SetStyleString(pszTest);
196 : }
197 : else
198 : {
199 41 : *pszUrl = '@';
200 41 : poOgrFeat->SetStyleString(pszUrl);
201 : }
202 : }
203 : /***** is it a dataset style? *****/
204 : else
205 : {
206 : const int nPathLen =
207 445 : static_cast<int>(strlen(poOgrDS->GetStylePath()));
208 :
209 445 : if (nPathLen == 0 ||
210 0 : EQUALN(pszUrl, poOgrDS->GetStylePath(), nPathLen))
211 : {
212 : /***** should we resolve the style *****/
213 : const char *pszResolve =
214 445 : CPLGetConfigOption("LIBKML_RESOLVE_STYLE", "no");
215 :
216 445 : if (CPLTestBool(pszResolve) &&
217 445 : (poOgrSTBLLayer = poOgrDS->GetStyleTable()) != nullptr &&
218 0 : (pszTest = poOgrSTBLLayer->Find(pszUrl + nPathLen + 1)) !=
219 : nullptr)
220 : {
221 0 : poOgrFeat->SetStyleString(pszTest);
222 : }
223 : else
224 : {
225 445 : pszUrl[nPathLen] = '@';
226 445 : poOgrFeat->SetStyleString(pszUrl + nPathLen);
227 : }
228 : }
229 : /**** its someplace else *****/
230 : else
231 : {
232 : const char *pszFetch =
233 0 : CPLGetConfigOption("LIBKML_EXTERNAL_STYLE", "no");
234 :
235 0 : if (CPLTestBool(pszFetch))
236 : {
237 : /***** load up the style table *****/
238 0 : char *pszUrlTmp = CPLStrdup(pszUrl);
239 0 : char *pszPound = strchr(pszUrlTmp, '#');
240 0 : if (pszPound != nullptr)
241 : {
242 0 : *pszPound = '\0';
243 : }
244 :
245 : /***** try it as a url then a file *****/
246 0 : VSILFILE *fp = nullptr;
247 0 : if ((fp = VSIFOpenL(
248 : CPLFormFilename("/vsicurl/", pszUrlTmp, nullptr),
249 0 : "r")) != nullptr ||
250 0 : (fp = VSIFOpenL(pszUrlTmp, "r")) != nullptr)
251 : {
252 0 : char szbuf[1025] = {'\0'};
253 0 : std::string oStyle = "";
254 :
255 : /***** loop, read and copy to a string *****/
256 0 : do
257 : {
258 : const size_t nRead =
259 0 : VSIFReadL(szbuf, 1, sizeof(szbuf) - 1, fp);
260 :
261 0 : if (nRead == 0)
262 0 : break;
263 :
264 : /***** copy buf to the string *****/
265 :
266 0 : szbuf[nRead] = '\0';
267 0 : oStyle.append(szbuf);
268 0 : } while (!VSIFEofL(fp));
269 :
270 0 : VSIFCloseL(fp);
271 :
272 : /***** parse the kml into the ds style table *****/
273 :
274 0 : if (poOgrDS->ParseIntoStyleTable(&oStyle, pszUrlTmp))
275 : {
276 0 : kml2featurestyle(poKmlFeature, poOgrDS, poOgrLayer,
277 : poOgrFeat);
278 : }
279 : else
280 : {
281 : /***** if failed just store the url *****/
282 0 : poOgrFeat->SetStyleString(pszUrl);
283 : }
284 : }
285 0 : CPLFree(pszUrlTmp);
286 : }
287 : else
288 : {
289 0 : poOgrFeat->SetStyleString(pszUrl);
290 : }
291 : }
292 : }
293 486 : CPLFree(pszUrl);
294 : }
295 :
296 : /***** does the placemark have a style selector *****/
297 777 : if (poKmlFeature->has_styleselector())
298 : {
299 2 : StyleSelectorPtr poKmlStyleSelector = poKmlFeature->get_styleselector();
300 :
301 : /***** is the style a style? *****/
302 1 : if (poKmlStyleSelector->IsA(kmldom::Type_Style))
303 : {
304 2 : StylePtr poKmlStyle = AsStyle(poKmlStyleSelector);
305 :
306 1 : OGRStyleMgr *poOgrSM = new OGRStyleMgr;
307 :
308 : /***** if were resolving style the feature *****/
309 : /***** might already have styling to add too *****/
310 : const char *pszResolve =
311 1 : CPLGetConfigOption("LIBKML_RESOLVE_STYLE", "no");
312 1 : if (CPLTestBool(pszResolve))
313 : {
314 0 : poOgrSM->InitFromFeature(poOgrFeat);
315 : }
316 : else
317 : {
318 : /***** if featyurestyle gets a name tool this needs
319 : changed to the above *****/
320 1 : poOgrSM->InitStyleString(nullptr);
321 : }
322 :
323 : /***** read the style *****/
324 1 : kml2stylestring(std::move(poKmlStyle), poOgrSM);
325 :
326 : /***** add the style to the feature *****/
327 1 : poOgrFeat->SetStyleString(poOgrSM->GetStyleString(nullptr));
328 :
329 1 : delete poOgrSM;
330 : }
331 : /***** is the style a stylemap? *****/
332 0 : else if (poKmlStyleSelector->IsA(kmldom::Type_StyleMap))
333 : {
334 : // TODO: Need to figure out what to do with a style map.
335 : }
336 : }
337 777 : }
|