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