1 : /******************************************************************************
2 : * $Id: ogrgeorsslayer.cpp 18254 2009-12-10 21:56:32Z rouault $
3 : *
4 : * Project: GeoRSS Translator
5 : * Purpose: Implements OGRGeoRSSLayer class.
6 : * Author: Even Rouault, even dot rouault at mines dash paris dot org
7 : *
8 : ******************************************************************************
9 : * Copyright (c) 2008, Even Rouault
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 "ogr_georss.h"
31 : #include "cpl_conv.h"
32 : #include "cpl_minixml.h"
33 : #include "ogr_api.h"
34 : #include "ogr_p.h"
35 :
36 : CPL_CVSID("$Id: ogrgeorsslayer.cpp 18254 2009-12-10 21:56:32Z rouault $");
37 :
38 : static const char* apszAllowedATOMFieldNamesWithSubElements[] = { "author", "contributor", NULL };
39 :
40 : static
41 : const char* apszAllowedRSSFieldNames[] = { "title", "link", "description", "author",
42 : "category", "category_domain",
43 : "comments",
44 : "enclosure_url", "enclosure_length", "enclosure_type",
45 : "guid", "guid_isPermaLink",
46 : "pubDate",
47 : "source", "source_url", NULL};
48 :
49 : static
50 : const char* apszAllowedATOMFieldNames[] = { "category_term", "category_scheme", "category_label",
51 : "content", "content_type", "content_xml_lang", "content_xml_base",
52 : "summary", "summary_type", "summary_xml_lang", "summary_xml_base",
53 : "author_name", "author_uri", "author_email",
54 : "contributor_name", "contributor_uri", "contributor_email",
55 : "link_href", "link_rel", "link_type", "link_length",
56 : "id", "published", "rights", "source",
57 : "title", "updated", NULL };
58 :
59 : #define IS_LAT_ELEMENT(pszName) (strncmp(pszName, "geo:lat", strlen("geo:lat")) == 0 || \
60 : strncmp(pszName, "icbm:lat", strlen("icbm:lat")) == 0 || \
61 : strncmp(pszName, "geourl:lat", strlen("geourl:lat")) == 0)
62 :
63 : #define IS_LON_ELEMENT(pszName) (strncmp(pszName, "geo:lon", strlen("geo:lon")) == 0 || \
64 : strncmp(pszName, "icbm:lon", strlen("icbm:lon")) == 0 || \
65 : strncmp(pszName, "geourl:lon", strlen("geourl:lon")) == 0)
66 :
67 : #define IS_GEO_ELEMENT(pszName) (strcmp(pszName, "georss:point") == 0 || \
68 : strcmp(pszName, "georss:line") == 0 || \
69 : strcmp(pszName, "georss:box") == 0 || \
70 : strcmp(pszName, "georss:polygon") == 0 || \
71 : strcmp(pszName, "georss:where") == 0 || \
72 : strncmp(pszName, "gml:", strlen("gml:")) == 0 || \
73 : strncmp(pszName, "geo:", strlen("geo:")) == 0 || \
74 : strncmp(pszName, "icbm:", strlen("icbm:")) == 0 || \
75 : strncmp(pszName, "geourl:", strlen("geourl:")) == 0)
76 :
77 : /************************************************************************/
78 : /* OGRGeoRSSLayer() */
79 : /************************************************************************/
80 :
81 19 : OGRGeoRSSLayer::OGRGeoRSSLayer( const char* pszFilename,
82 : const char* pszLayerName,
83 : OGRGeoRSSDataSource* poDS,
84 : OGRSpatialReference *poSRSIn,
85 19 : int bWriteMode)
86 :
87 : {
88 19 : eof = FALSE;
89 19 : nNextFID = 0;
90 :
91 19 : this->poDS = poDS;
92 19 : this->bWriteMode = bWriteMode;
93 :
94 19 : eFormat = poDS->GetFormat();
95 :
96 19 : poFeatureDefn = new OGRFeatureDefn( pszLayerName );
97 19 : poFeatureDefn->Reference();
98 :
99 19 : poSRS = poSRSIn;
100 19 : if (poSRS)
101 1 : poSRS->Reference();
102 :
103 19 : nTotalFeatureCount = 0;
104 :
105 19 : ppoFeatureTab = NULL;
106 19 : nFeatureTabIndex = 0;
107 19 : nFeatureTabLength = 0;
108 19 : pszSubElementName = NULL;
109 19 : pszSubElementValue = NULL;
110 19 : nSubElementValueLen = 0;
111 19 : pszGMLSRSName = NULL;
112 19 : pszTagWithSubTag = NULL;
113 19 : bStopParsing = FALSE;
114 19 : bHasReadSchema = FALSE;
115 19 : setOfFoundFields = NULL;
116 19 : poGlobalGeom = NULL;
117 19 : hasFoundLat = FALSE;
118 19 : hasFoundLon = FALSE;
119 :
120 19 : poFeature = NULL;
121 :
122 : #ifdef HAVE_EXPAT
123 19 : oParser = NULL;
124 : #endif
125 :
126 19 : if (bWriteMode == FALSE)
127 : {
128 13 : fpGeoRSS = VSIFOpenL( pszFilename, "r" );
129 13 : if( fpGeoRSS == NULL )
130 : {
131 0 : CPLError(CE_Failure, CPLE_AppDefined, "Cannot open %s", pszFilename);
132 0 : return;
133 : }
134 : }
135 : else
136 6 : fpGeoRSS = NULL;
137 :
138 19 : ResetReading();
139 0 : }
140 :
141 : /************************************************************************/
142 : /* ~OGRGeoRSSLayer() */
143 : /************************************************************************/
144 :
145 38 : OGRGeoRSSLayer::~OGRGeoRSSLayer()
146 :
147 : {
148 : #ifdef HAVE_EXPAT
149 19 : if (oParser)
150 13 : XML_ParserFree(oParser);
151 : #endif
152 19 : poFeatureDefn->Release();
153 :
154 19 : if( poSRS != NULL )
155 10 : poSRS->Release();
156 :
157 19 : CPLFree(pszSubElementName);
158 19 : CPLFree(pszSubElementValue);
159 19 : CPLFree(pszGMLSRSName);
160 19 : CPLFree(pszTagWithSubTag);
161 19 : if (setOfFoundFields)
162 12 : CPLHashSetDestroy(setOfFoundFields);
163 19 : if (poGlobalGeom)
164 0 : delete poGlobalGeom;
165 :
166 : int i;
167 19 : for(i=nFeatureTabIndex;i<nFeatureTabLength;i++)
168 0 : delete ppoFeatureTab[i];
169 19 : CPLFree(ppoFeatureTab);
170 :
171 19 : if (poFeature)
172 0 : delete poFeature;
173 :
174 19 : if (fpGeoRSS)
175 13 : VSIFCloseL( fpGeoRSS );
176 38 : }
177 :
178 :
179 : /************************************************************************/
180 : /* GetLayerDefn() */
181 : /************************************************************************/
182 :
183 17 : OGRFeatureDefn * OGRGeoRSSLayer::GetLayerDefn()
184 : {
185 17 : if (!bHasReadSchema)
186 8 : LoadSchema();
187 :
188 17 : return poFeatureDefn;
189 : }
190 :
191 :
192 :
193 : #ifdef HAVE_EXPAT
194 :
195 276 : static void XMLCALL startElementCbk(void *pUserData, const char *pszName,
196 : const char **ppszAttr)
197 : {
198 276 : ((OGRGeoRSSLayer*)pUserData)->startElementCbk(pszName, ppszAttr);
199 276 : }
200 :
201 276 : static void XMLCALL endElementCbk(void *pUserData, const char *pszName)
202 : {
203 276 : ((OGRGeoRSSLayer*)pUserData)->endElementCbk(pszName);
204 276 : }
205 :
206 792 : static void XMLCALL dataHandlerCbk(void *pUserData, const char *data, int nLen)
207 : {
208 792 : ((OGRGeoRSSLayer*)pUserData)->dataHandlerCbk(data, nLen);
209 792 : }
210 :
211 : #endif
212 :
213 : /************************************************************************/
214 : /* ResetReading() */
215 : /************************************************************************/
216 :
217 19 : void OGRGeoRSSLayer::ResetReading()
218 :
219 : {
220 19 : if (bWriteMode)
221 6 : return;
222 :
223 13 : eof = FALSE;
224 13 : nNextFID = 0;
225 13 : if (fpGeoRSS)
226 : {
227 13 : VSIFSeekL( fpGeoRSS, 0, SEEK_SET );
228 : #ifdef HAVE_EXPAT
229 13 : if (oParser)
230 0 : XML_ParserFree(oParser);
231 :
232 13 : oParser = OGRCreateExpatXMLParser();
233 13 : XML_SetElementHandler(oParser, ::startElementCbk, ::endElementCbk);
234 13 : XML_SetCharacterDataHandler(oParser, ::dataHandlerCbk);
235 13 : XML_SetUserData(oParser, this);
236 : #endif
237 : }
238 13 : bInFeature = FALSE;
239 13 : hasFoundLat = FALSE;
240 13 : hasFoundLon = FALSE;
241 13 : bInSimpleGeometry = FALSE;
242 13 : bInGMLGeometry = FALSE;
243 13 : bInGeoLat = FALSE;
244 13 : bInGeoLong = FALSE;
245 13 : eGeomType = wkbUnknown;
246 13 : CPLFree(pszSubElementName);
247 13 : pszSubElementName = NULL;
248 13 : CPLFree(pszSubElementValue);
249 13 : pszSubElementValue = NULL;
250 13 : nSubElementValueLen = 0;
251 13 : CPLFree(pszGMLSRSName);
252 13 : pszGMLSRSName = NULL;
253 :
254 13 : if (setOfFoundFields)
255 0 : CPLHashSetDestroy(setOfFoundFields);
256 13 : setOfFoundFields = NULL;
257 :
258 : int i;
259 13 : for(i=nFeatureTabIndex;i<nFeatureTabLength;i++)
260 0 : delete ppoFeatureTab[i];
261 13 : CPLFree(ppoFeatureTab);
262 13 : nFeatureTabIndex = 0;
263 13 : nFeatureTabLength = 0;
264 13 : ppoFeatureTab = NULL;
265 13 : if (poFeature)
266 0 : delete poFeature;
267 13 : poFeature = NULL;
268 :
269 13 : currentDepth = 0;
270 13 : featureDepth = 0;
271 13 : geometryDepth = 0;
272 13 : bInTagWithSubTag = FALSE;
273 13 : CPLFree(pszTagWithSubTag);
274 13 : pszTagWithSubTag = NULL;
275 : }
276 :
277 : #ifdef HAVE_EXPAT
278 :
279 : /************************************************************************/
280 : /* AddStrToSubElementValue() */
281 : /************************************************************************/
282 :
283 188 : void OGRGeoRSSLayer::AddStrToSubElementValue(const char* pszStr)
284 : {
285 188 : int len = strlen(pszStr);
286 : char* pszNewSubElementValue = (char*)
287 188 : VSIRealloc(pszSubElementValue, nSubElementValueLen + len + 1);
288 188 : if (pszNewSubElementValue == NULL)
289 : {
290 0 : CPLError(CE_Failure, CPLE_OutOfMemory, "Out of memory");
291 0 : XML_StopParser(oParser, XML_FALSE);
292 0 : bStopParsing = TRUE;
293 0 : return;
294 : }
295 188 : pszSubElementValue = pszNewSubElementValue;
296 :
297 188 : memcpy(pszSubElementValue + nSubElementValueLen, pszStr, len);
298 188 : nSubElementValueLen += len;
299 : }
300 :
301 : /************************************************************************/
302 : /* OGRGeoRSS_GetOGRCompatibleTagName() */
303 : /************************************************************************/
304 :
305 : /** Replace ':' from XML NS element name by '_' more OGR friendly */
306 312 : static char* OGRGeoRSS_GetOGRCompatibleTagName(const char* pszName)
307 : {
308 312 : char* pszModName = CPLStrdup(pszName);
309 : int i;
310 2712 : for(i=0;pszModName[i] != 0;i++)
311 : {
312 2400 : if (pszModName[i] == ':')
313 24 : pszModName[i] = '_';
314 : }
315 312 : return pszModName;
316 : }
317 :
318 : /************************************************************************/
319 : /* OGRGeoRSSLayerATOMTagHasSubElement() */
320 : /************************************************************************/
321 :
322 80 : static int OGRGeoRSSLayerATOMTagHasSubElement(const char* pszName)
323 : {
324 : unsigned int i;
325 208 : for(i=0;apszAllowedATOMFieldNamesWithSubElements[i] != NULL;i++)
326 : {
327 152 : if (strcmp(pszName, apszAllowedATOMFieldNamesWithSubElements[i]) == 0)
328 24 : return TRUE;
329 : }
330 56 : return FALSE;
331 : }
332 :
333 : /************************************************************************/
334 : /* startElementCbk() */
335 : /************************************************************************/
336 :
337 276 : void OGRGeoRSSLayer::startElementCbk(const char *pszName, const char **ppszAttr)
338 : {
339 276 : int bSerializeTag = FALSE;
340 :
341 276 : if (bStopParsing) return;
342 :
343 303 : if ((eFormat == GEORSS_ATOM && currentDepth == 1 && strcmp(pszName, "entry") == 0) ||
344 : (eFormat == GEORSS_RSS && currentDepth == 2 && strcmp(pszName, "item") == 0))
345 : {
346 27 : featureDepth = currentDepth;
347 :
348 27 : if (poFeature)
349 0 : delete poFeature;
350 :
351 27 : poFeature = new OGRFeature( poFeatureDefn );
352 27 : poFeature->SetFID( nNextFID++ );
353 :
354 27 : bInFeature = TRUE;
355 27 : hasFoundLat = FALSE;
356 27 : hasFoundLon = FALSE;
357 27 : bInSimpleGeometry = FALSE;
358 27 : bInGMLGeometry = FALSE;
359 27 : bInGeoLat = FALSE;
360 27 : bInGeoLong = FALSE;
361 27 : eGeomType = wkbUnknown;
362 27 : geometryDepth = 0;
363 27 : bInTagWithSubTag = FALSE;
364 :
365 27 : if (setOfFoundFields)
366 15 : CPLHashSetDestroy(setOfFoundFields);
367 27 : setOfFoundFields = CPLHashSetNew(CPLHashSetHashStr, CPLHashSetEqualStr, CPLFree);
368 : }
369 259 : else if (bInFeature && bInTagWithSubTag && currentDepth == 3)
370 : {
371 10 : char* pszFieldName = CPLStrdup(CPLSPrintf("%s_%s", pszTagWithSubTag, pszName));
372 :
373 10 : CPLFree(pszSubElementName);
374 10 : pszSubElementName = NULL;
375 10 : CPLFree(pszSubElementValue);
376 10 : pszSubElementValue = NULL;
377 10 : nSubElementValueLen = 0;
378 :
379 10 : iCurrentField = poFeatureDefn->GetFieldIndex(pszFieldName);
380 10 : if (iCurrentField >= 0)
381 10 : pszSubElementName = CPLStrdup(pszFieldName);
382 :
383 10 : CPLFree(pszFieldName);
384 : }
385 239 : else if (bInFeature && eFormat == GEORSS_ATOM &&
386 : currentDepth == 2 && OGRGeoRSSLayerATOMTagHasSubElement(pszName))
387 : {
388 6 : CPLFree(pszTagWithSubTag);
389 6 : pszTagWithSubTag = CPLStrdup(pszName);
390 :
391 6 : int count = 1;
392 14 : while(CPLHashSetLookup(setOfFoundFields, pszTagWithSubTag) != NULL)
393 : {
394 2 : count ++;
395 2 : CPLFree(pszTagWithSubTag);
396 2 : pszTagWithSubTag = CPLStrdup(CPLSPrintf("%s%d", pszName, count));
397 : }
398 6 : CPLHashSetInsert(setOfFoundFields, CPLStrdup(pszTagWithSubTag));
399 :
400 6 : bInTagWithSubTag = TRUE;
401 : }
402 233 : else if (bInGMLGeometry)
403 : {
404 17 : bSerializeTag = TRUE;
405 : }
406 216 : else if (bInSimpleGeometry || bInGeoLat || bInGeoLong)
407 : {
408 : /* Shouldn't happen for a valid document */
409 : }
410 217 : else if (IS_LAT_ELEMENT(pszName))
411 : {
412 1 : CPLFree(pszSubElementValue);
413 1 : pszSubElementValue = NULL;
414 1 : nSubElementValueLen = 0;
415 1 : bInGeoLat = TRUE;
416 : }
417 216 : else if (IS_LON_ELEMENT(pszName))
418 : {
419 1 : CPLFree(pszSubElementValue);
420 1 : pszSubElementValue = NULL;
421 1 : nSubElementValueLen = 0;
422 1 : bInGeoLong = TRUE;
423 : }
424 224 : else if (strcmp(pszName, "georss:point") == 0 ||
425 : strcmp(pszName, "georss:line") == 0 ||
426 : strcmp(pszName, "geo:line") == 0 ||
427 : strcmp(pszName, "georss:polygon") == 0 ||
428 : strcmp(pszName, "georss:box") == 0)
429 : {
430 10 : CPLFree(pszSubElementValue);
431 10 : pszSubElementValue = NULL;
432 10 : nSubElementValueLen = 0;
433 : eGeomType = strcmp(pszName, "georss:point") == 0 ? wkbPoint :
434 : (strcmp(pszName, "georss:line") == 0 ||
435 : strcmp(pszName, "geo:line") == 0) ? wkbLineString :
436 : (strcmp(pszName, "georss:polygon") == 0 ||
437 : strcmp(pszName, "georss:box") == 0) ? wkbPolygon :
438 10 : wkbUnknown;
439 10 : bInSimpleGeometry = TRUE;
440 10 : geometryDepth = currentDepth;
441 : }
442 214 : else if (strcmp(pszName, "gml:Point") == 0 ||
443 : strcmp(pszName, "gml:LineString") == 0 ||
444 : strcmp(pszName, "gml:Polygon") == 0 ||
445 : strcmp(pszName, "gml:Envelope") == 0)
446 : {
447 10 : CPLFree(pszSubElementValue);
448 10 : pszSubElementValue = NULL;
449 10 : nSubElementValueLen = 0;
450 10 : AddStrToSubElementValue(CPLSPrintf("<%s>", pszName));
451 10 : bInGMLGeometry = TRUE;
452 10 : geometryDepth = currentDepth;
453 10 : CPLFree(pszGMLSRSName);
454 10 : pszGMLSRSName = NULL;
455 11 : for (int i = 0; ppszAttr[i]; i += 2)
456 : {
457 1 : if (strcmp(ppszAttr[i], "srsName") == 0)
458 : {
459 1 : if (pszGMLSRSName == NULL)
460 1 : pszGMLSRSName = CPLStrdup(ppszAttr[i+1]);
461 : }
462 : }
463 : }
464 324 : else if (bInFeature && currentDepth == featureDepth + 1)
465 : {
466 130 : CPLFree(pszSubElementName);
467 130 : pszSubElementName = NULL;
468 130 : CPLFree(pszSubElementValue);
469 130 : pszSubElementValue = NULL;
470 130 : nSubElementValueLen = 0;
471 130 : iCurrentField = -1;
472 :
473 130 : pszSubElementName = CPLStrdup(pszName);
474 130 : int count = 1;
475 267 : while(CPLHashSetLookup(setOfFoundFields, pszSubElementName) != NULL)
476 : {
477 7 : count ++;
478 7 : CPLFree(pszSubElementName);
479 7 : pszSubElementName = CPLStrdup(CPLSPrintf("%s%d", pszName, count));
480 : }
481 130 : CPLHashSetInsert(setOfFoundFields, CPLStrdup(pszSubElementName));
482 :
483 130 : char* pszCompatibleName = OGRGeoRSS_GetOGRCompatibleTagName(pszSubElementName);
484 130 : iCurrentField = poFeatureDefn->GetFieldIndex(pszCompatibleName);
485 130 : CPLFree(pszSubElementName);
486 :
487 161 : for(int i = 0; ppszAttr[i] != NULL && ppszAttr[i+1] != NULL; i+=2)
488 : {
489 : char* pszAttrCompatibleName =
490 31 : OGRGeoRSS_GetOGRCompatibleTagName(CPLSPrintf("%s_%s", pszCompatibleName, ppszAttr[i]));
491 31 : int iAttrField = poFeatureDefn->GetFieldIndex(pszAttrCompatibleName);
492 31 : if (iAttrField >= 0)
493 31 : poFeature->SetField( iAttrField, ppszAttr[i+1] );
494 31 : CPLFree(pszAttrCompatibleName);
495 : }
496 :
497 130 : if (iCurrentField < 0)
498 : {
499 14 : pszSubElementName = NULL;
500 : }
501 : else
502 : {
503 116 : pszSubElementName = CPLStrdup(pszCompatibleName);
504 : }
505 130 : CPLFree(pszCompatibleName);
506 : }
507 64 : else if (bInFeature && currentDepth > featureDepth + 1 && pszSubElementName != NULL)
508 : {
509 6 : bSerializeTag = TRUE;
510 : }
511 :
512 276 : if (bSerializeTag)
513 : {
514 23 : AddStrToSubElementValue("<");
515 23 : AddStrToSubElementValue(pszName);
516 25 : for(int i = 0; ppszAttr[i] != NULL && ppszAttr[i+1] != NULL; i+=2)
517 : {
518 2 : AddStrToSubElementValue(" ");
519 2 : AddStrToSubElementValue(ppszAttr[i]);
520 2 : AddStrToSubElementValue("=\"");
521 2 : AddStrToSubElementValue(ppszAttr[i+1]);
522 2 : AddStrToSubElementValue("\"");
523 : }
524 23 : AddStrToSubElementValue(">");
525 : }
526 :
527 276 : currentDepth++;
528 : }
529 :
530 : /************************************************************************/
531 : /* OGRGeoRSS_GetGMLEnvelope() */
532 : /************************************************************************/
533 :
534 1 : static OGRGeometry* OGRGeoRSS_GetGMLEnvelope(const char* pszGML)
535 : {
536 1 : OGRGeometry* poGeom = NULL;
537 1 : CPLXMLNode* poNode = CPLParseXMLString(pszGML);
538 1 : const char* pszLowerCorner = CPLGetXMLValue(poNode, "gml:lowerCorner", NULL);
539 1 : const char* pszUpperCorner = CPLGetXMLValue(poNode, "gml:upperCorner", NULL);
540 1 : if (pszLowerCorner && pszUpperCorner)
541 : {
542 : char **papszTokensLower;
543 : char **papszTokensUpper;
544 :
545 : papszTokensLower = CSLTokenizeStringComplex(
546 1 : pszLowerCorner, " ,", FALSE, FALSE );
547 : papszTokensUpper = CSLTokenizeStringComplex(
548 1 : pszUpperCorner, " ,", FALSE, FALSE );
549 1 : if (CSLCount(papszTokensLower) == 2 &&
550 : CSLCount(papszTokensUpper) == 2)
551 : {
552 1 : OGRPolygon* poPolygon = new OGRPolygon();
553 2 : OGRLinearRing* poLinearRing = new OGRLinearRing();
554 1 : poPolygon->addRingDirectly(poLinearRing);
555 1 : double x1 = atof(papszTokensLower[0]);
556 1 : double y1 = atof(papszTokensLower[1]);
557 1 : double x2 = atof(papszTokensUpper[0]);
558 1 : double y2 = atof(papszTokensUpper[1]);
559 1 : poLinearRing->addPoint( x1, y1 );
560 1 : poLinearRing->addPoint( x2, y1 );
561 1 : poLinearRing->addPoint( x2, y2 );
562 1 : poLinearRing->addPoint( x1, y2 );
563 1 : poLinearRing->addPoint( x1, y1 );
564 :
565 1 : poGeom = poPolygon;
566 : }
567 :
568 1 : CSLDestroy(papszTokensLower);
569 1 : CSLDestroy(papszTokensUpper);
570 : }
571 1 : CPLDestroyXMLNode(poNode);
572 1 : return poGeom;
573 : }
574 :
575 :
576 : /************************************************************************/
577 : /* OGRGeoRSSLayerTrimLeadingAndTrailingSpaces() */
578 : /************************************************************************/
579 :
580 10 : static void OGRGeoRSSLayerTrimLeadingAndTrailingSpaces(char* pszStr)
581 : {
582 : int i;
583 :
584 : /* Trim leading spaces, tabs and newlines */
585 10 : i = 0;
586 62 : while(pszStr[i] != '\0' &&
587 39 : (pszStr[i] == ' ' || pszStr[i] == '\t' || pszStr[i] == '\n'))
588 3 : i ++;
589 10 : memmove(pszStr, pszStr + i, strlen(pszStr + i) + 1);
590 :
591 : /* Trim trailing spaces, tabs and newlines */
592 10 : i = strlen(pszStr) - 1;
593 56 : while(i >= 0 &&
594 33 : (pszStr[i] == ' ' || pszStr[i] == '\t' || pszStr[i] == '\n'))
595 : {
596 3 : pszStr[i] = '\0';
597 3 : i --;
598 : }
599 10 : }
600 :
601 : /************************************************************************/
602 : /* endElementCbk() */
603 : /************************************************************************/
604 :
605 276 : void OGRGeoRSSLayer::endElementCbk(const char *pszName)
606 : {
607 276 : OGRGeometry* poGeom = NULL;
608 :
609 276 : if (bStopParsing) return;
610 :
611 276 : currentDepth--;
612 :
613 276 : if ((eFormat == GEORSS_ATOM && currentDepth == 1 && strcmp(pszName, "entry") == 0) ||
614 : (eFormat == GEORSS_RSS && currentDepth == 2 && strcmp(pszName, "item") == 0))
615 : {
616 27 : bInFeature = FALSE;
617 27 : bInTagWithSubTag = FALSE;
618 :
619 28 : if (hasFoundLat && hasFoundLon)
620 1 : poFeature->SetGeometryDirectly( new OGRPoint( lonVal, latVal ) );
621 26 : else if (poFeature->GetGeometryRef() == NULL && poGlobalGeom != NULL)
622 0 : poFeature->SetGeometry(poGlobalGeom);
623 :
624 27 : hasFoundLat = FALSE;
625 27 : hasFoundLon = FALSE;
626 :
627 27 : if (poSRS != NULL && poFeature->GetGeometryRef() != NULL)
628 19 : poFeature->GetGeometryRef()->assignSpatialReference(poSRS);
629 :
630 27 : if( (m_poFilterGeom == NULL
631 : || FilterGeometry( poFeature->GetGeometryRef() ) )
632 : && (m_poAttrQuery == NULL
633 : || m_poAttrQuery->Evaluate( poFeature )) )
634 : {
635 : ppoFeatureTab = (OGRFeature**)
636 : CPLRealloc(ppoFeatureTab,
637 27 : sizeof(OGRFeature*) * (nFeatureTabLength + 1));
638 27 : ppoFeatureTab[nFeatureTabLength] = poFeature;
639 27 : nFeatureTabLength++;
640 : }
641 : else
642 : {
643 0 : delete poFeature;
644 : }
645 27 : poFeature = NULL;
646 27 : return;
647 : }
648 :
649 259 : if (bInTagWithSubTag && currentDepth == 3)
650 : {
651 10 : char* pszFieldName = CPLStrdup(CPLSPrintf("%s_%s", pszTagWithSubTag, pszName));
652 :
653 10 : if (iCurrentField != -1 && pszSubElementName &&
654 : strcmp(pszFieldName, pszSubElementName) == 0 && poFeature &&
655 : pszSubElementValue && nSubElementValueLen)
656 : {
657 10 : pszSubElementValue[nSubElementValueLen] = 0;
658 10 : poFeature->SetField( iCurrentField, pszSubElementValue);
659 : }
660 :
661 10 : CPLFree(pszSubElementName);
662 10 : pszSubElementName = NULL;
663 10 : CPLFree(pszSubElementValue);
664 10 : pszSubElementValue = NULL;
665 10 : nSubElementValueLen = 0;
666 :
667 10 : CPLFree(pszFieldName);
668 : }
669 239 : else if (bInFeature && eFormat == GEORSS_ATOM &&
670 : currentDepth == 2 && OGRGeoRSSLayerATOMTagHasSubElement(pszName))
671 : {
672 6 : bInTagWithSubTag = FALSE;
673 : }
674 233 : else if (bInGMLGeometry)
675 : {
676 27 : AddStrToSubElementValue("</");
677 27 : AddStrToSubElementValue(pszName);
678 27 : AddStrToSubElementValue(">");
679 27 : if (currentDepth > geometryDepth)
680 : {
681 : }
682 : else
683 : {
684 10 : pszSubElementValue[nSubElementValueLen] = 0;
685 : CPLAssert(strncmp(pszName, "gml:", 4) == 0);
686 10 : if (strcmp(pszName, "gml:Envelope") == 0)
687 1 : poGeom = OGRGeoRSS_GetGMLEnvelope(pszSubElementValue);
688 : else
689 9 : poGeom = (OGRGeometry*) OGR_G_CreateFromGML(pszSubElementValue);
690 :
691 10 : if (poGeom != NULL && !poGeom->IsEmpty() )
692 : {
693 9 : int bSwapCoordinates = FALSE;
694 9 : if (pszGMLSRSName)
695 : {
696 1 : OGRSpatialReference* poSRSFeature = new OGRSpatialReference();
697 1 : poSRSFeature->importFromURN(pszGMLSRSName);
698 1 : poGeom->assignSpatialReference(poSRSFeature);
699 1 : poSRSFeature->Release();
700 : }
701 : else
702 8 : bSwapCoordinates = TRUE; /* lat, lon WGS 84 */
703 :
704 9 : if (bSwapCoordinates)
705 : {
706 8 : switch ( wkbFlatten(poGeom->getGeometryType()) )
707 : {
708 : case wkbPoint:
709 : {
710 2 : OGRPoint* poPoint = (OGRPoint*) poGeom;
711 2 : double x = poPoint->getX();
712 2 : double y = poPoint->getY();
713 2 : poPoint->setX(y);
714 2 : poPoint->setY(x);
715 2 : break;
716 : }
717 :
718 : case wkbLineString:
719 : {
720 2 : OGRLineString* poLineString = (OGRLineString*) poGeom;
721 2 : int n = poLineString->getNumPoints();
722 8 : for(int i=0;i<n;i++)
723 : {
724 6 : double x = poLineString->getX(i);
725 6 : double y = poLineString->getY(i);
726 6 : if (poLineString->getCoordinateDimension() == 2)
727 6 : poLineString->setPoint(i, y, x);
728 : else
729 0 : poLineString->setPoint(i, y, x, poLineString->getZ(i));
730 : }
731 2 : break;
732 : }
733 :
734 : case wkbPolygon:
735 : {
736 4 : OGRPolygon* poPolygon = (OGRPolygon*) poGeom;
737 4 : OGRLineString* poLineString = poPolygon->getExteriorRing();
738 4 : int n = poLineString->getNumPoints();
739 24 : for(int i=0;i<n;i++)
740 : {
741 20 : double x = poLineString->getX(i);
742 20 : double y = poLineString->getY(i);
743 20 : if (poLineString->getCoordinateDimension() == 2)
744 20 : poLineString->setPoint(i, y, x);
745 : else
746 0 : poLineString->setPoint(i, y, x, poLineString->getZ(i));
747 :
748 : }
749 : break;
750 : }
751 :
752 : default:
753 : break;
754 : }
755 : }
756 : }
757 10 : bInGMLGeometry = FALSE;
758 : }
759 : }
760 206 : else if (bInSimpleGeometry)
761 : {
762 10 : if (currentDepth > geometryDepth)
763 : {
764 : /* Shouldn't happen for a valid document */
765 : }
766 : else
767 : {
768 10 : if (pszSubElementValue)
769 : {
770 10 : pszSubElementValue[nSubElementValueLen] = 0;
771 :
772 : /* Trim any leading and trailing spaces, tabs, newlines, etc... */
773 10 : OGRGeoRSSLayerTrimLeadingAndTrailingSpaces(pszSubElementValue);
774 :
775 : /* Caution : Order is latitude, longitude */
776 : char** papszTokens =
777 : CSLTokenizeStringComplex( pszSubElementValue,
778 10 : " ,", TRUE, FALSE );
779 :
780 10 : int nTokens = CSLCount(papszTokens);
781 11 : if ((nTokens % 2) != 0 ||
782 : (eGeomType == wkbPoint && nTokens != 2) ||
783 : (eGeomType == wkbLineString && nTokens < 4) ||
784 : (strcmp(pszName, "georss:polygon") == 0 && nTokens < 6) ||
785 : (strcmp(pszName, "georss:box") == 0 && nTokens != 4))
786 : {
787 : CPLError(CE_Failure, CPLE_AppDefined,
788 : "Wrong number of coordinates in %s",
789 1 : pszSubElementValue);
790 : }
791 9 : else if (eGeomType == wkbPoint)
792 : {
793 3 : poGeom = new OGRPoint( CPLAtof(papszTokens[1]),
794 6 : CPLAtof(papszTokens[0]) );
795 : }
796 6 : else if (eGeomType == wkbLineString)
797 : {
798 2 : OGRLineString* poLineString = new OGRLineString ();
799 2 : poGeom = poLineString;
800 : int i;
801 8 : for(i=0;i<nTokens;i+=2)
802 : {
803 6 : poLineString->addPoint( CPLAtof(papszTokens[i+1]),
804 12 : CPLAtof(papszTokens[i]) );
805 : }
806 : }
807 4 : else if (eGeomType == wkbPolygon)
808 : {
809 4 : OGRPolygon* poPolygon = new OGRPolygon();
810 8 : OGRLinearRing* poLinearRing = new OGRLinearRing();
811 4 : poGeom = poPolygon;
812 4 : poPolygon->addRingDirectly(poLinearRing);
813 4 : if (strcmp(pszName, "georss:polygon") == 0)
814 : {
815 : int i;
816 18 : for(i=0;i<nTokens;i+=2)
817 : {
818 15 : poLinearRing->addPoint( CPLAtof(papszTokens[i+1]),
819 30 : CPLAtof(papszTokens[i]) );
820 : }
821 : }
822 : else
823 : {
824 1 : double lat1 = CPLAtof(papszTokens[0]);
825 1 : double lon1 = CPLAtof(papszTokens[1]);
826 1 : double lat2 = CPLAtof(papszTokens[2]);
827 1 : double lon2 = CPLAtof(papszTokens[3]);
828 1 : poLinearRing->addPoint( lon1, lat1 );
829 1 : poLinearRing->addPoint( lon1, lat2 );
830 1 : poLinearRing->addPoint( lon2, lat2 );
831 1 : poLinearRing->addPoint( lon2, lat1 );
832 1 : poLinearRing->addPoint( lon1, lat1 );
833 : }
834 : }
835 :
836 10 : CSLDestroy(papszTokens);
837 : }
838 10 : bInSimpleGeometry = FALSE;
839 : }
840 : }
841 197 : else if (IS_LAT_ELEMENT(pszName))
842 : {
843 1 : if (pszSubElementValue)
844 : {
845 1 : hasFoundLat = TRUE;
846 1 : pszSubElementValue[nSubElementValueLen] = 0;
847 1 : latVal = CPLAtof(pszSubElementValue);
848 : }
849 1 : bInGeoLat = FALSE;
850 : }
851 196 : else if (IS_LON_ELEMENT(pszName))
852 : {
853 1 : if (pszSubElementValue)
854 : {
855 1 : hasFoundLon = TRUE;
856 1 : pszSubElementValue[nSubElementValueLen] = 0;
857 1 : lonVal = CPLAtof(pszSubElementValue);
858 : }
859 1 : bInGeoLong = FALSE;
860 : }
861 324 : else if (bInFeature && currentDepth == featureDepth + 1)
862 : {
863 130 : if (iCurrentField != -1 && pszSubElementName &&
864 : poFeature && pszSubElementValue && nSubElementValueLen)
865 : {
866 116 : pszSubElementValue[nSubElementValueLen] = 0;
867 116 : if (poFeatureDefn->GetFieldDefn(iCurrentField)->GetType() == OFTDateTime)
868 : {
869 : int year, month, day, hour, minute, TZ;
870 : int nsecond;
871 : float fsecond;
872 25 : if (OGRParseRFC822DateTime(pszSubElementValue, &year, &month, &day,
873 : &hour, &minute, &nsecond, &TZ))
874 : {
875 : poFeature->SetField(iCurrentField, year, month, day,
876 21 : hour, minute, nsecond, TZ);
877 : }
878 4 : else if (OGRParseXMLDateTime(pszSubElementValue, &year, &month, &day,
879 : &hour, &minute, &fsecond, &TZ))
880 : {
881 : poFeature->SetField(iCurrentField, year, month, day,
882 4 : hour, minute, (int)(fsecond + .5), TZ);
883 : }
884 : else
885 : {
886 : CPLError(CE_Warning, CPLE_AppDefined,
887 0 : "Could not parse %s as a valid dateTime", pszSubElementValue);
888 : }
889 : }
890 : else
891 : {
892 91 : poFeature->SetField( iCurrentField, pszSubElementValue);
893 : }
894 : }
895 :
896 130 : CPLFree(pszSubElementName);
897 130 : pszSubElementName = NULL;
898 130 : CPLFree(pszSubElementValue);
899 130 : pszSubElementValue = NULL;
900 130 : nSubElementValueLen = 0;
901 : }
902 64 : else if (bInFeature && currentDepth > featureDepth + 1 && pszSubElementName != NULL)
903 : {
904 6 : AddStrToSubElementValue("</");
905 6 : AddStrToSubElementValue(pszName);
906 6 : AddStrToSubElementValue(">");
907 : }
908 :
909 249 : if (poGeom != NULL)
910 : {
911 18 : if (poFeature != NULL)
912 : {
913 18 : poFeature->SetGeometryDirectly(poGeom);
914 : }
915 0 : else if (!bInFeature)
916 : {
917 0 : if (poGlobalGeom != NULL)
918 0 : delete poGlobalGeom;
919 0 : poGlobalGeom = poGeom;
920 : }
921 : else
922 0 : delete poGeom;
923 : }
924 231 : else if (!bInFeature && hasFoundLat && hasFoundLon)
925 : {
926 0 : if (poGlobalGeom != NULL)
927 0 : delete poGlobalGeom;
928 0 : poGlobalGeom = new OGRPoint( lonVal, latVal );
929 0 : hasFoundLat = hasFoundLon = FALSE;
930 : }
931 : }
932 :
933 : /************************************************************************/
934 : /* dataHandlerCbk() */
935 : /************************************************************************/
936 :
937 792 : void OGRGeoRSSLayer::dataHandlerCbk(const char *data, int nLen)
938 : {
939 792 : if (bStopParsing) return;
940 :
941 792 : if (bInGMLGeometry == TRUE || bInSimpleGeometry == TRUE ||
942 : bInGeoLat == TRUE || bInGeoLong == TRUE ||
943 : pszSubElementName != NULL)
944 : {
945 : char* pszNewSubElementValue = (char*) VSIRealloc(pszSubElementValue,
946 190 : nSubElementValueLen + nLen + 1);
947 190 : if (pszNewSubElementValue == NULL)
948 : {
949 0 : CPLError(CE_Failure, CPLE_OutOfMemory, "Out of memory");
950 0 : XML_StopParser(oSchemaParser, XML_FALSE);
951 0 : bStopParsing = TRUE;
952 0 : return;
953 : }
954 190 : pszSubElementValue = pszNewSubElementValue;
955 190 : memcpy(pszSubElementValue + nSubElementValueLen, data, nLen);
956 190 : nSubElementValueLen += nLen;
957 : }
958 : }
959 : #endif
960 :
961 : /************************************************************************/
962 : /* GetNextFeature() */
963 : /************************************************************************/
964 :
965 27 : OGRFeature *OGRGeoRSSLayer::GetNextFeature()
966 : {
967 27 : if (bWriteMode)
968 : {
969 : CPLError(CE_Failure, CPLE_NotSupported,
970 0 : "Cannot read features when writing a GeoRSS file");
971 0 : return NULL;
972 : }
973 :
974 27 : if (fpGeoRSS == NULL)
975 0 : return NULL;
976 :
977 27 : if (!bHasReadSchema)
978 4 : LoadSchema();
979 :
980 27 : if (bStopParsing)
981 0 : return NULL;
982 :
983 : #ifdef HAVE_EXPAT
984 27 : if (nFeatureTabIndex < nFeatureTabLength)
985 : {
986 15 : return ppoFeatureTab[nFeatureTabIndex++];
987 : }
988 :
989 12 : if (VSIFEofL(fpGeoRSS))
990 0 : return NULL;
991 :
992 : char aBuf[BUFSIZ];
993 :
994 12 : CPLFree(ppoFeatureTab);
995 12 : ppoFeatureTab = NULL;
996 12 : nFeatureTabLength = 0;
997 12 : nFeatureTabIndex = 0;
998 :
999 : int nDone;
1000 12 : do
1001 : {
1002 : unsigned int nLen =
1003 12 : (unsigned int)VSIFReadL( aBuf, 1, sizeof(aBuf), fpGeoRSS );
1004 12 : nDone = VSIFEofL(fpGeoRSS);
1005 12 : if (XML_Parse(oParser, aBuf, nLen, nDone) == XML_STATUS_ERROR)
1006 : {
1007 : CPLError(CE_Failure, CPLE_AppDefined,
1008 : "XML parsing of GeoRSS file failed : %s "
1009 : "at line %d, column %d",
1010 : XML_ErrorString(XML_GetErrorCode(oParser)),
1011 : (int)XML_GetCurrentLineNumber(oParser),
1012 0 : (int)XML_GetCurrentColumnNumber(oParser));
1013 0 : bStopParsing = TRUE;
1014 : }
1015 : } while (!nDone && !bStopParsing && nFeatureTabLength == 0);
1016 :
1017 12 : return (nFeatureTabLength) ? ppoFeatureTab[nFeatureTabIndex++] : NULL;
1018 : #else
1019 : return NULL;
1020 : #endif
1021 : }
1022 :
1023 : /************************************************************************/
1024 : /* GetSpatialRef() */
1025 : /************************************************************************/
1026 :
1027 20 : OGRSpatialReference *OGRGeoRSSLayer::GetSpatialRef()
1028 :
1029 : {
1030 20 : if (!bWriteMode && !bHasReadSchema)
1031 6 : LoadSchema();
1032 :
1033 20 : return poSRS;
1034 : }
1035 :
1036 : /************************************************************************/
1037 : /* OGRGeoRSSLayerIsStandardFieldInternal() */
1038 : /************************************************************************/
1039 :
1040 91 : static int OGRGeoRSSLayerIsStandardFieldInternal(const char* pszName,
1041 : const char** papszNames)
1042 : {
1043 : unsigned int i;
1044 687 : for( i = 0; papszNames[i] != NULL; i++)
1045 : {
1046 681 : if (strcmp(pszName, papszNames[i]) == 0)
1047 : {
1048 74 : return TRUE;
1049 : }
1050 :
1051 607 : const char* pszUnderscore = strchr(papszNames[i], '_');
1052 607 : if (pszUnderscore == NULL)
1053 : {
1054 251 : int nLen = strlen(papszNames[i]);
1055 251 : if (strncmp(pszName, papszNames[i], nLen) == 0)
1056 : {
1057 12 : int k = nLen;
1058 30 : while(pszName[k] >= '0' && pszName[k] <= '9')
1059 6 : k++;
1060 12 : if (pszName[k] == '\0')
1061 3 : return TRUE;
1062 : }
1063 : }
1064 : else
1065 : {
1066 356 : int nLen = pszUnderscore - papszNames[i];
1067 356 : if (strncmp(pszName, papszNames[i], nLen) == 0)
1068 : {
1069 23 : int k = nLen;
1070 60 : while(pszName[k] >= '0' && pszName[k] <= '9')
1071 14 : k++;
1072 23 : if (pszName[k] == '_' && strcmp(pszName + k, pszUnderscore) == 0)
1073 8 : return TRUE;
1074 : }
1075 : }
1076 : }
1077 6 : return FALSE;
1078 : }
1079 :
1080 : /************************************************************************/
1081 : /* OGRGeoRSSLayer::IsStandardField() */
1082 : /************************************************************************/
1083 :
1084 91 : int OGRGeoRSSLayer::IsStandardField(const char* pszName)
1085 : {
1086 91 : if (eFormat == GEORSS_RSS)
1087 : {
1088 : return OGRGeoRSSLayerIsStandardFieldInternal(pszName,
1089 69 : apszAllowedRSSFieldNames);
1090 : }
1091 : else
1092 : {
1093 : return OGRGeoRSSLayerIsStandardFieldInternal(pszName,
1094 22 : apszAllowedATOMFieldNames);
1095 : }
1096 : }
1097 :
1098 : /************************************************************************/
1099 : /* OGRGeoRSSLayerSplitComposedField() */
1100 : /************************************************************************/
1101 :
1102 103 : static void OGRGeoRSSLayerSplitComposedField(const char* pszName,
1103 : char** ppszElementName,
1104 : char** ppszNumber,
1105 : char** ppszAttributeName)
1106 : {
1107 103 : *ppszElementName = CPLStrdup(pszName);
1108 :
1109 103 : int i = 0;
1110 2180 : while(pszName[i] != '\0' && pszName[i] != '_' &&
1111 1326 : !(pszName[i] >= '0' && pszName[i] <= '9'))
1112 : {
1113 648 : i++;
1114 : }
1115 :
1116 103 : (*ppszElementName)[i] = '\0';
1117 :
1118 118 : if (pszName[i] >= '0' && pszName[i] <= '9')
1119 : {
1120 15 : *ppszNumber = CPLStrdup(pszName + i);
1121 15 : char* pszUnderscore = strchr(*ppszNumber, '_');
1122 15 : if (pszUnderscore)
1123 : {
1124 11 : *pszUnderscore = '\0';
1125 11 : *ppszAttributeName = CPLStrdup(pszUnderscore + 1);
1126 : }
1127 : else
1128 : {
1129 4 : *ppszAttributeName = NULL;
1130 : }
1131 : }
1132 : else
1133 : {
1134 88 : *ppszNumber = CPLStrdup("");
1135 88 : if (pszName[i] == '_')
1136 : {
1137 29 : *ppszAttributeName = CPLStrdup(pszName + i + 1);
1138 : }
1139 : else
1140 : {
1141 59 : *ppszAttributeName = NULL;
1142 : }
1143 : }
1144 103 : }
1145 :
1146 : /************************************************************************/
1147 : /* OGRGeoRSSLayerWriteSimpleElement() */
1148 : /************************************************************************/
1149 :
1150 8 : static void OGRGeoRSSLayerWriteSimpleElement(FILE* fp,
1151 : const char* pszElementName,
1152 : const char* pszNumber,
1153 : const char** papszNames,
1154 : OGRFeatureDefn* poFeatureDefn,
1155 : OGRFeature* poFeature)
1156 : {
1157 8 : VSIFPrintf(fp, " <%s", pszElementName);
1158 :
1159 : unsigned k;
1160 152 : for( k = 0; papszNames[k] != NULL ; k++)
1161 : {
1162 184 : if (strncmp(papszNames[k], pszElementName, strlen(pszElementName)) == 0 &&
1163 40 : papszNames[k][strlen(pszElementName)] == '_')
1164 : {
1165 14 : const char* pszAttributeName = papszNames[k] + strlen(pszElementName) + 1;
1166 14 : char* pszFieldName = CPLStrdup(CPLSPrintf("%s%s_%s", pszElementName, pszNumber, pszAttributeName));
1167 14 : int iIndex = poFeatureDefn->GetFieldIndex(pszFieldName);
1168 14 : if (iIndex != -1 && poFeature->IsFieldSet( iIndex ))
1169 : {
1170 : char* pszValue =
1171 13 : OGRGetXML_UTF8_EscapedString(poFeature->GetFieldAsString( iIndex ));
1172 13 : VSIFPrintf(fp, " %s=\"%s\"", pszAttributeName, pszValue);
1173 13 : CPLFree(pszValue);
1174 : }
1175 14 : CPLFree(pszFieldName);
1176 : }
1177 : }
1178 :
1179 8 : char* pszFieldName = CPLStrdup(CPLSPrintf("%s%s", pszElementName, pszNumber));
1180 8 : int iIndex = poFeatureDefn->GetFieldIndex(pszFieldName);
1181 8 : if (iIndex != -1 && poFeature->IsFieldSet( iIndex ))
1182 : {
1183 6 : VSIFPrintf(fp, ">");
1184 :
1185 : char* pszValue =
1186 6 : OGRGetXML_UTF8_EscapedString(poFeature->GetFieldAsString( iIndex ));
1187 6 : VSIFPrintf(fp, "%s", pszValue);
1188 6 : CPLFree(pszValue);
1189 :
1190 6 : VSIFPrintf(fp, "</%s>\n", pszElementName);
1191 : }
1192 : else
1193 : {
1194 2 : VSIFPrintf(fp, "/>\n");
1195 : }
1196 8 : CPLFree(pszFieldName);
1197 8 : }
1198 :
1199 : /************************************************************************/
1200 : /* CreateFeature() */
1201 : /************************************************************************/
1202 :
1203 15 : OGRErr OGRGeoRSSLayer::CreateFeature( OGRFeature *poFeature )
1204 :
1205 : {
1206 15 : FILE* fp = poDS->GetOutputFP();
1207 15 : if (fp == NULL)
1208 0 : return CE_Failure;
1209 :
1210 15 : nNextFID ++;
1211 :
1212 : /* Verify that compulsory feeds are set. Otherwise put some default value in them */
1213 15 : if (eFormat == GEORSS_RSS)
1214 : {
1215 14 : int iFieldTitle = poFeatureDefn->GetFieldIndex( "title" );
1216 14 : int iFieldDescription = poFeatureDefn->GetFieldIndex( "description" );
1217 :
1218 14 : VSIFPrintf(fp, " <item>\n");
1219 :
1220 14 : if ((iFieldTitle == -1 || poFeature->IsFieldSet( iFieldTitle ) == FALSE) &&
1221 : (iFieldDescription == -1 || poFeature->IsFieldSet( iFieldDescription ) == FALSE))
1222 : {
1223 2 : VSIFPrintf(fp, " <title>Feature %d</title>\n", nNextFID);
1224 : }
1225 : }
1226 : else
1227 : {
1228 1 : VSIFPrintf(fp, " <entry>\n");
1229 :
1230 1 : int iFieldId = poFeatureDefn->GetFieldIndex( "id" );
1231 1 : int iFieldTitle = poFeatureDefn->GetFieldIndex( "title" );
1232 1 : int iFieldUpdated = poFeatureDefn->GetFieldIndex( "updated" );
1233 :
1234 1 : if (iFieldId == -1 || poFeature->IsFieldSet( iFieldId ) == FALSE)
1235 : {
1236 0 : VSIFPrintf(fp, " <id>Feature %d</id>\n", nNextFID);
1237 : }
1238 :
1239 1 : if (iFieldTitle == -1 || poFeature->IsFieldSet( iFieldTitle ) == FALSE)
1240 : {
1241 0 : VSIFPrintf(fp, " <title>Title for feature %d</title>\n", nNextFID);
1242 : }
1243 :
1244 1 : if (iFieldUpdated == -1 || poFeature->IsFieldSet(iFieldUpdated ) == FALSE)
1245 : {
1246 0 : VSIFPrintf(fp, " <updated>2009-01-01T00:00:00Z</updated>\n");
1247 : }
1248 : }
1249 :
1250 15 : int nFieldCount = poFeatureDefn->GetFieldCount();
1251 15 : int* pbUsed = (int*)CPLCalloc(sizeof(int), nFieldCount);
1252 :
1253 146 : for(int i = 0; i < nFieldCount; i ++)
1254 : {
1255 131 : OGRFieldDefn *poFieldDefn = poFeatureDefn->GetFieldDefn( i );
1256 131 : const char* pszName = poFieldDefn->GetNameRef();
1257 :
1258 131 : if ( ! poFeature->IsFieldSet( i ) )
1259 48 : continue;
1260 :
1261 : char* pszElementName;
1262 : char* pszNumber;
1263 : char* pszAttributeName;
1264 83 : OGRGeoRSSLayerSplitComposedField(pszName, &pszElementName, &pszNumber, &pszAttributeName);
1265 :
1266 83 : int bWillSkip = FALSE;
1267 : /* Handle Atom entries with elements with sub-elements like */
1268 : /* <author><name>...</name><uri>...</uri></author */
1269 83 : if (eFormat == GEORSS_ATOM)
1270 : {
1271 : unsigned int k;
1272 52 : for (k=0;apszAllowedATOMFieldNamesWithSubElements[k] != NULL;k++)
1273 : {
1274 37 : if (strcmp(pszElementName, apszAllowedATOMFieldNamesWithSubElements[k]) == 0 &&
1275 : pszAttributeName != NULL)
1276 : {
1277 5 : bWillSkip = TRUE;
1278 5 : if (pbUsed[i])
1279 2 : break;
1280 :
1281 3 : VSIFPrintf(fp, " <%s>\n", pszElementName);
1282 :
1283 : int j;
1284 23 : for(j = i; j < nFieldCount; j ++)
1285 : {
1286 20 : poFieldDefn = poFeatureDefn->GetFieldDefn( j );
1287 20 : if ( ! poFeature->IsFieldSet( j ) )
1288 0 : continue;
1289 :
1290 : char* pszElementName2;
1291 : char* pszNumber2;
1292 : char* pszAttributeName2;
1293 : OGRGeoRSSLayerSplitComposedField(poFieldDefn->GetNameRef(),
1294 20 : &pszElementName2, &pszNumber2, &pszAttributeName2);
1295 :
1296 20 : if (strcmp(pszElementName2, pszElementName) == 0 &&
1297 : strcmp(pszNumber, pszNumber2) == 0 && pszAttributeName2 != NULL)
1298 : {
1299 5 : pbUsed[j] = TRUE;
1300 :
1301 : char* pszValue =
1302 5 : OGRGetXML_UTF8_EscapedString(poFeature->GetFieldAsString( j ));
1303 5 : VSIFPrintf(fp, " <%s>%s</%s>\n", pszAttributeName2, pszValue, pszAttributeName2);
1304 5 : CPLFree(pszValue);
1305 : }
1306 20 : CPLFree(pszElementName2);
1307 20 : CPLFree(pszNumber2);
1308 20 : CPLFree(pszAttributeName2);
1309 : }
1310 :
1311 3 : VSIFPrintf(fp, " </%s>\n", pszElementName);
1312 :
1313 3 : break;
1314 : }
1315 : }
1316 : }
1317 :
1318 83 : if (bWillSkip)
1319 : {
1320 : /* Do nothing */
1321 : }
1322 90 : else if (eFormat == GEORSS_RSS &&
1323 : strcmp(pszName, "pubDate") == 0)
1324 : {
1325 : int year, month, day, hour, minute, second, TZFlag;
1326 12 : if (poFeature->GetFieldAsDateTime(i, &year, &month, &day,
1327 : &hour, &minute, &second, &TZFlag))
1328 : {
1329 12 : char* pszDate = OGRGetRFC822DateTime(year, month, day, hour, minute, second, TZFlag);
1330 : VSIFPrintf(fp, " <%s>%s</%s>\n",
1331 12 : pszName, pszDate, pszName);
1332 12 : CPLFree(pszDate);
1333 : }
1334 : }
1335 68 : else if (eFormat == GEORSS_ATOM &&
1336 : (strcmp(pszName, "updated") == 0 || strcmp(pszName, "published") == 0))
1337 : {
1338 : int year, month, day, hour, minute, second, TZFlag;
1339 2 : if (poFeature->GetFieldAsDateTime(i, &year, &month, &day,
1340 : &hour, &minute, &second, &TZFlag))
1341 : {
1342 2 : char* pszDate = OGRGetXMLDateTime(year, month, day, hour, minute, second, TZFlag);
1343 : VSIFPrintf(fp, " <%s>%s</%s>\n",
1344 2 : pszName, pszDate, pszName);
1345 2 : CPLFree(pszDate);
1346 : }
1347 : }
1348 64 : else if (strcmp(pszName, "dc_date") == 0)
1349 : {
1350 : int year, month, day, hour, minute, second, TZFlag;
1351 0 : if (poFeature->GetFieldAsDateTime(i, &year, &month, &day,
1352 : &hour, &minute, &second, &TZFlag))
1353 : {
1354 0 : char* pszDate = OGRGetXMLDateTime(year, month, day, hour, minute, second, TZFlag);
1355 : VSIFPrintf(fp, " <%s>%s</%s>\n",
1356 0 : "dc:date", pszDate, "dc:date");
1357 0 : CPLFree(pszDate);
1358 : }
1359 : }
1360 : /* RSS fields with content and attributes */
1361 76 : else if (eFormat == GEORSS_RSS &&
1362 : (strcmp(pszElementName, "category") == 0 ||
1363 : strcmp(pszElementName, "guid") == 0 ||
1364 : strcmp(pszElementName, "source") == 0 ))
1365 : {
1366 12 : if (pszAttributeName == NULL)
1367 : {
1368 : OGRGeoRSSLayerWriteSimpleElement(fp, pszElementName, pszNumber,
1369 6 : apszAllowedRSSFieldNames, poFeatureDefn, poFeature);
1370 : }
1371 : }
1372 : /* RSS field with attribute only */
1373 52 : else if (eFormat == GEORSS_RSS &&
1374 : strcmp(pszElementName, "enclosure") == 0)
1375 : {
1376 0 : if (pszAttributeName != NULL && strcmp(pszAttributeName, "url") == 0)
1377 : {
1378 : OGRGeoRSSLayerWriteSimpleElement(fp, pszElementName, pszNumber,
1379 0 : apszAllowedRSSFieldNames, poFeatureDefn, poFeature);
1380 : }
1381 : }
1382 : /* ATOM fields with attribute only */
1383 59 : else if (eFormat == GEORSS_ATOM &&
1384 : (strcmp(pszElementName, "category") == 0 || strcmp(pszElementName, "link") == 0))
1385 : {
1386 7 : if (pszAttributeName != NULL &&
1387 : ((strcmp(pszElementName, "category") == 0 && strcmp(pszAttributeName, "term") == 0) ||
1388 : (strcmp(pszElementName, "link") == 0 && strcmp(pszAttributeName, "href") == 0)))
1389 : {
1390 : OGRGeoRSSLayerWriteSimpleElement(fp, pszElementName, pszNumber,
1391 2 : apszAllowedATOMFieldNames, poFeatureDefn, poFeature);
1392 : }
1393 : }
1394 49 : else if (eFormat == GEORSS_ATOM &&
1395 : (strncmp(pszName, "content", strlen("content")) == 0 ||
1396 : strncmp(pszName, "summary", strlen("summary")) == 0))
1397 : {
1398 : char* pszFieldName;
1399 : int iIndex;
1400 4 : if (strchr(pszName, '_') == NULL)
1401 : {
1402 1 : VSIFPrintf(fp, " <%s", pszName);
1403 :
1404 1 : int bIsXHTML = FALSE;
1405 1 : pszFieldName = CPLStrdup(CPLSPrintf("%s_%s", pszName, "type"));
1406 1 : iIndex = poFeatureDefn->GetFieldIndex(pszFieldName);
1407 1 : if (iIndex != -1 && poFeature->IsFieldSet( iIndex ))
1408 : {
1409 1 : bIsXHTML = strcmp(poFeature->GetFieldAsString( iIndex ), "xhtml") == 0;
1410 : char* pszValue =
1411 1 : OGRGetXML_UTF8_EscapedString(poFeature->GetFieldAsString( iIndex ));
1412 1 : VSIFPrintf(fp, " %s=\"%s\"", "type", pszValue);
1413 1 : CPLFree(pszValue);
1414 : }
1415 1 : CPLFree(pszFieldName);
1416 :
1417 1 : pszFieldName = CPLStrdup(CPLSPrintf("%s_%s", pszName, "xml_lang"));
1418 1 : iIndex = poFeatureDefn->GetFieldIndex(pszFieldName);
1419 1 : if (iIndex != -1 && poFeature->IsFieldSet( iIndex ))
1420 : {
1421 : char* pszValue =
1422 1 : OGRGetXML_UTF8_EscapedString(poFeature->GetFieldAsString( iIndex ));
1423 1 : VSIFPrintf(fp, " %s=\"%s\"", "xml:lang", pszValue);
1424 1 : CPLFree(pszValue);
1425 : }
1426 1 : CPLFree(pszFieldName);
1427 :
1428 1 : pszFieldName = CPLStrdup(CPLSPrintf("%s_%s", pszName, "xml_base"));
1429 1 : iIndex = poFeatureDefn->GetFieldIndex(pszFieldName);
1430 1 : if (iIndex != -1 && poFeature->IsFieldSet( iIndex ))
1431 : {
1432 : char* pszValue =
1433 1 : OGRGetXML_UTF8_EscapedString(poFeature->GetFieldAsString( iIndex ));
1434 1 : VSIFPrintf(fp, " %s=\"%s\"", "xml:base", pszValue);
1435 1 : CPLFree(pszValue);
1436 : }
1437 1 : CPLFree(pszFieldName);
1438 :
1439 1 : VSIFPrintf(fp, ">");
1440 1 : if (bIsXHTML)
1441 1 : VSIFPrintf(fp, "%s", poFeature->GetFieldAsString(i));
1442 : else
1443 : {
1444 : char* pszValue =
1445 0 : OGRGetXML_UTF8_EscapedString(poFeature->GetFieldAsString( i ));
1446 0 : VSIFPrintf(fp, "%s", pszValue);
1447 0 : CPLFree(pszValue);
1448 : }
1449 1 : VSIFPrintf(fp, " </%s>\n", pszName);
1450 : }
1451 : }
1452 41 : else if (strncmp(pszName, "dc_subject", strlen("dc_subject")) == 0)
1453 : {
1454 : char* pszFieldName;
1455 : int iIndex;
1456 0 : if (strchr(pszName+strlen("dc_subject"), '_') == NULL)
1457 : {
1458 0 : VSIFPrintf(fp, " <%s", "dc:subject");
1459 :
1460 0 : pszFieldName = CPLStrdup(CPLSPrintf("%s_%s", pszName, "xml_lang"));
1461 0 : iIndex = poFeatureDefn->GetFieldIndex(pszFieldName);
1462 0 : if (iIndex != -1 && poFeature->IsFieldSet( iIndex ))
1463 : {
1464 : char* pszValue =
1465 0 : OGRGetXML_UTF8_EscapedString(poFeature->GetFieldAsString( iIndex ));
1466 0 : VSIFPrintf(fp, " %s=\"%s\"", "xml:lang", pszValue);
1467 0 : CPLFree(pszValue);
1468 : }
1469 0 : CPLFree(pszFieldName);
1470 :
1471 : char* pszValue =
1472 0 : OGRGetXML_UTF8_EscapedString(poFeature->GetFieldAsString( i ));
1473 0 : VSIFPrintf(fp, ">%s</%s>\n", pszValue, "dc:subject");
1474 0 : CPLFree(pszValue);
1475 : }
1476 : }
1477 : else
1478 : {
1479 41 : char* pszTagName = CPLStrdup(pszName);
1480 41 : if (IsStandardField(pszName) == FALSE)
1481 : {
1482 : int j;
1483 3 : int nCountUnderscore = 0;
1484 29 : for(j=0;pszTagName[j] != 0;j++)
1485 : {
1486 26 : if (pszTagName[j] == '_')
1487 : {
1488 2 : if (nCountUnderscore == 0)
1489 2 : pszTagName[j] = ':';
1490 2 : nCountUnderscore ++;
1491 : }
1492 24 : else if (pszTagName[j] == ' ')
1493 0 : pszTagName[j] = '_';
1494 : }
1495 3 : if (nCountUnderscore == 0)
1496 : {
1497 1 : char* pszTemp = CPLStrdup(CPLSPrintf("ogr:%s", pszTagName));
1498 1 : CPLFree(pszTagName);
1499 1 : pszTagName = pszTemp;
1500 : }
1501 : }
1502 : char* pszValue =
1503 41 : OGRGetXML_UTF8_EscapedString(poFeature->GetFieldAsString( i ));
1504 41 : VSIFPrintf(fp, " <%s>%s</%s>\n", pszTagName, pszValue, pszTagName);
1505 41 : CPLFree(pszValue);
1506 41 : CPLFree(pszTagName);
1507 : }
1508 :
1509 83 : CPLFree(pszElementName);
1510 83 : CPLFree(pszNumber);
1511 83 : CPLFree(pszAttributeName);
1512 : }
1513 :
1514 15 : CPLFree(pbUsed);
1515 :
1516 15 : OGRGeoRSSGeomDialect eGeomDialect = poDS->GetGeomDialect();
1517 15 : OGRGeometry* poGeom = poFeature->GetGeometryRef();
1518 15 : if ( poGeom != NULL && !poGeom->IsEmpty() )
1519 : {
1520 13 : char* pszURN = NULL;
1521 13 : int bSwapCoordinates = FALSE;
1522 13 : if (eGeomDialect == GEORSS_GML)
1523 : {
1524 5 : if (poSRS != NULL)
1525 : {
1526 1 : const char* pszAuthorityName = poSRS->GetAuthorityName(NULL);
1527 1 : const char* pszAuthorityCode = poSRS->GetAuthorityCode(NULL);
1528 2 : if (pszAuthorityName != NULL && EQUAL(pszAuthorityName, "EPSG") &&
1529 : pszAuthorityCode != NULL)
1530 : {
1531 1 : if (!EQUAL(pszAuthorityCode, "4326"))
1532 1 : pszURN = CPLStrdup(CPLSPrintf("urn:ogc:def:crs:EPSG::%s", pszAuthorityCode));
1533 :
1534 : /* In case the SRS is a geographic SRS and that we have no axis */
1535 : /* defintion, we assume that the order is lon/lat */
1536 1 : const char* pszAxisName = poSRS->GetAxis(NULL, 0, NULL);
1537 1 : if (poSRS->IsGeographic() &&
1538 : (pszAxisName == NULL || EQUALN(pszAxisName, "Lon", 3)))
1539 : {
1540 0 : bSwapCoordinates = TRUE;
1541 : }
1542 : }
1543 : else
1544 : {
1545 : static int bOnce = FALSE;
1546 0 : if (!bOnce)
1547 : {
1548 0 : bOnce = TRUE;
1549 0 : CPLError(CE_Warning, CPLE_AppDefined, "Could not translate SRS into GML urn");
1550 : }
1551 : }
1552 : }
1553 : else
1554 : {
1555 4 : bSwapCoordinates = TRUE;
1556 : }
1557 : }
1558 :
1559 13 : switch( wkbFlatten(poGeom->getGeometryType()) )
1560 : {
1561 : case wkbPoint:
1562 : {
1563 4 : OGRPoint* poPoint = (OGRPoint*)poGeom;
1564 4 : double x = poPoint->getX();
1565 4 : double y = poPoint->getY();
1566 4 : if (eGeomDialect == GEORSS_GML)
1567 : {
1568 2 : VSIFPrintf(fp, " <georss:where><gml:Point");
1569 2 : if (pszURN != NULL)
1570 1 : VSIFPrintf(fp, " srsName=\"%s\"", pszURN);
1571 2 : if (poGeom->getCoordinateDimension() == 3)
1572 : {
1573 : VSIFPrintf(fp, " srsDimension=\"3\"><gml:pos>%.15f %.15f %.15f",
1574 : (bSwapCoordinates) ? y : x, (bSwapCoordinates) ? x : y,
1575 0 : poPoint->getZ());
1576 : }
1577 : else
1578 : {
1579 : VSIFPrintf(fp, "><gml:pos>%.15f %.15f",
1580 2 : (bSwapCoordinates) ? y : x, (bSwapCoordinates) ? x : y);
1581 : }
1582 2 : VSIFPrintf(fp, "</gml:pos></gml:Point></georss:where>\n");
1583 : }
1584 2 : else if (eGeomDialect == GEORSS_SIMPLE)
1585 : {
1586 1 : VSIFPrintf(fp, " <georss:point>%.15f %.15f</georss:point>\n", y, x);
1587 : }
1588 1 : else if (eGeomDialect == GEORSS_W3C_GEO)
1589 : {
1590 1 : VSIFPrintf(fp, " <geo:lat>%.15f</geo:lat>\n", y);
1591 1 : VSIFPrintf(fp, " <geo:long>%.15f</geo:long>\n", x);
1592 : }
1593 4 : break;
1594 : }
1595 :
1596 : case wkbLineString:
1597 : {
1598 3 : OGRLineString* poLineString = (OGRLineString*)poGeom;
1599 3 : if (eGeomDialect == GEORSS_GML)
1600 : {
1601 1 : VSIFPrintf(fp, " <georss:where><gml:LineString");
1602 1 : if (pszURN != NULL)
1603 0 : VSIFPrintf(fp, " srsName=\"%s\"", pszURN);
1604 1 : VSIFPrintf(fp, "><gml:posList>\n");
1605 1 : int n = poLineString->getNumPoints();
1606 4 : for(int i=0;i<n;i++)
1607 : {
1608 3 : double x = poLineString->getX(i);
1609 3 : double y = poLineString->getY(i);
1610 : VSIFPrintf(fp, "%.15f %.15f ",
1611 3 : (bSwapCoordinates) ? y : x, (bSwapCoordinates) ? x : y);
1612 : }
1613 1 : VSIFPrintf(fp, "</gml:posList></gml:LineString></georss:where>\n");
1614 : }
1615 2 : else if (eGeomDialect == GEORSS_SIMPLE)
1616 : {
1617 1 : VSIFPrintf(fp, " <georss:line>\n");
1618 1 : int n = poLineString->getNumPoints();
1619 4 : for(int i=0;i<n;i++)
1620 : {
1621 3 : double x = poLineString->getX(i);
1622 3 : double y = poLineString->getY(i);
1623 3 : VSIFPrintf(fp, "%.15f %.15f ", y, x);
1624 : }
1625 1 : VSIFPrintf(fp, "</georss:line>\n");
1626 : }
1627 : else
1628 : {
1629 : /* Not supported */
1630 : }
1631 3 : break;
1632 : }
1633 :
1634 : case wkbPolygon:
1635 : {
1636 6 : OGRPolygon* poPolygon = (OGRPolygon*)poGeom;
1637 6 : OGRLineString* poLineString = poPolygon->getExteriorRing();
1638 6 : if (poLineString == NULL)
1639 0 : break;
1640 :
1641 6 : if (eGeomDialect == GEORSS_GML)
1642 : {
1643 2 : VSIFPrintf(fp, " <georss:where><gml:Polygon");
1644 2 : if (pszURN != NULL)
1645 0 : VSIFPrintf(fp, " srsName=\"%s\"", pszURN);
1646 2 : VSIFPrintf(fp, "><gml:exterior><gml:LinearRing><gml:posList>\n");
1647 2 : int n = poLineString->getNumPoints();
1648 12 : for(int i=0;i<n;i++)
1649 : {
1650 10 : double x = poLineString->getX(i);
1651 10 : double y = poLineString->getY(i);
1652 : VSIFPrintf(fp, "%.15f %.15f ",
1653 10 : (bSwapCoordinates) ? y : x, (bSwapCoordinates) ? x : y);
1654 : }
1655 2 : VSIFPrintf(fp, "</gml:posList></gml:LinearRing></gml:exterior></gml:Polygon></georss:where>\n");
1656 : }
1657 4 : else if (eGeomDialect == GEORSS_SIMPLE)
1658 : {
1659 2 : VSIFPrintf(fp, " <georss:polygon>\n");
1660 2 : int n = poLineString->getNumPoints();
1661 12 : for(int i=0;i<n;i++)
1662 : {
1663 10 : double x = poLineString->getX(i);
1664 10 : double y = poLineString->getY(i);
1665 10 : VSIFPrintf(fp, "%.15f %.15f ", y, x);
1666 : }
1667 2 : VSIFPrintf(fp, "</georss:polygon>\n");
1668 : }
1669 : else
1670 : {
1671 : /* Not supported */
1672 : }
1673 : break;
1674 : }
1675 :
1676 : default:
1677 : /* Not supported */
1678 : break;
1679 : }
1680 13 : CPLFree(pszURN);
1681 : }
1682 :
1683 15 : if (eFormat == GEORSS_RSS)
1684 14 : VSIFPrintf(fp, " </item>\n");
1685 : else
1686 1 : VSIFPrintf(fp, " </entry>\n");
1687 :
1688 15 : return OGRERR_NONE;
1689 : }
1690 :
1691 :
1692 :
1693 : /************************************************************************/
1694 : /* CreateField() */
1695 : /************************************************************************/
1696 :
1697 50 : OGRErr OGRGeoRSSLayer::CreateField( OGRFieldDefn *poFieldDefn, int bApproxOK )
1698 :
1699 : {
1700 50 : const char* pszName = poFieldDefn->GetNameRef();
1701 50 : if (((eFormat == GEORSS_RSS && strcmp(pszName, "pubDate") == 0) ||
1702 : (eFormat == GEORSS_ATOM && (strcmp(pszName, "updated") == 0 ||
1703 : strcmp(pszName, "published") == 0 )) ||
1704 : strcmp(pszName, "dc:date") == 0) &&
1705 : poFieldDefn->GetType() != OFTDateTime)
1706 : {
1707 0 : CPLError(CE_Failure, CPLE_AppDefined, "Wrong field type for %s", pszName);
1708 0 : return OGRERR_FAILURE;
1709 : }
1710 :
1711 351 : for( int iField = 0; iField < poFeatureDefn->GetFieldCount(); iField++ )
1712 : {
1713 301 : if (strcmp(poFeatureDefn->GetFieldDefn(iField)->GetNameRef(),
1714 : pszName ) == 0)
1715 : {
1716 0 : return OGRERR_FAILURE;
1717 : }
1718 : }
1719 :
1720 50 : if (IsStandardField(pszName))
1721 : {
1722 47 : poFeatureDefn->AddFieldDefn( poFieldDefn );
1723 47 : return OGRERR_NONE;
1724 : }
1725 :
1726 3 : if (poDS->GetUseExtensions() == FALSE)
1727 : {
1728 : CPLError(CE_Failure, CPLE_NotSupported,
1729 : "Field of name '%s' is not supported in %s schema. "
1730 : "Use USE_EXTENSIONS creation option to allow use of extensions.",
1731 0 : pszName, (eFormat == GEORSS_RSS) ? "RSS" : "ATOM");
1732 0 : return OGRERR_FAILURE;
1733 : }
1734 : else
1735 : {
1736 3 : poFeatureDefn->AddFieldDefn( poFieldDefn );
1737 3 : return OGRERR_NONE;
1738 : }
1739 : }
1740 :
1741 : #ifdef HAVE_EXPAT
1742 :
1743 276 : static void XMLCALL startElementLoadSchemaCbk(void *pUserData, const char *pszName, const char **ppszAttr)
1744 : {
1745 276 : ((OGRGeoRSSLayer*)pUserData)->startElementLoadSchemaCbk(pszName, ppszAttr);
1746 276 : }
1747 :
1748 276 : static void XMLCALL endElementLoadSchemaCbk(void *pUserData, const char *pszName)
1749 : {
1750 276 : ((OGRGeoRSSLayer*)pUserData)->endElementLoadSchemaCbk(pszName);
1751 276 : }
1752 :
1753 792 : static void XMLCALL dataHandlerLoadSchemaCbk(void *pUserData, const char *data, int nLen)
1754 : {
1755 792 : ((OGRGeoRSSLayer*)pUserData)->dataHandlerLoadSchemaCbk(data, nLen);
1756 792 : }
1757 :
1758 :
1759 : /************************************************************************/
1760 : /* LoadSchema() */
1761 : /************************************************************************/
1762 :
1763 : /** This function parses the whole file to detect the fields */
1764 18 : void OGRGeoRSSLayer::LoadSchema()
1765 : {
1766 18 : if (bHasReadSchema)
1767 0 : return;
1768 :
1769 18 : bHasReadSchema = TRUE;
1770 :
1771 18 : if (fpGeoRSS == NULL)
1772 6 : return;
1773 :
1774 12 : oSchemaParser = OGRCreateExpatXMLParser();
1775 12 : XML_SetElementHandler(oSchemaParser, ::startElementLoadSchemaCbk, ::endElementLoadSchemaCbk);
1776 12 : XML_SetCharacterDataHandler(oSchemaParser, ::dataHandlerLoadSchemaCbk);
1777 12 : XML_SetUserData(oSchemaParser, this);
1778 :
1779 12 : VSIFSeekL( fpGeoRSS, 0, SEEK_SET );
1780 :
1781 12 : bInFeature = FALSE;
1782 12 : currentDepth = 0;
1783 12 : currentFieldDefn = NULL;
1784 12 : pszSubElementName = NULL;
1785 12 : pszSubElementValue = NULL;
1786 12 : nSubElementValueLen = 0;
1787 12 : bSameSRS = TRUE;
1788 12 : CPLFree(pszGMLSRSName);
1789 12 : pszGMLSRSName = NULL;
1790 12 : eGeomType = wkbUnknown;
1791 12 : bFoundGeom = FALSE;
1792 12 : bInTagWithSubTag = FALSE;
1793 12 : pszTagWithSubTag = NULL;
1794 12 : bStopParsing = FALSE;
1795 12 : nWithoutEventCounter = 0;
1796 12 : nTotalFeatureCount = 0;
1797 12 : setOfFoundFields = NULL;
1798 :
1799 : char aBuf[BUFSIZ];
1800 : int nDone;
1801 12 : do
1802 : {
1803 12 : nDataHandlerCounter = 0;
1804 12 : unsigned int nLen = (unsigned int)VSIFReadL( aBuf, 1, sizeof(aBuf), fpGeoRSS );
1805 12 : nDone = VSIFEofL(fpGeoRSS);
1806 12 : if (XML_Parse(oSchemaParser, aBuf, nLen, nDone) == XML_STATUS_ERROR)
1807 : {
1808 : CPLError(CE_Failure, CPLE_AppDefined,
1809 : "XML parsing of GeoRSS file failed : %s at line %d, column %d",
1810 : XML_ErrorString(XML_GetErrorCode(oSchemaParser)),
1811 : (int)XML_GetCurrentLineNumber(oSchemaParser),
1812 0 : (int)XML_GetCurrentColumnNumber(oSchemaParser));
1813 0 : bStopParsing = TRUE;
1814 : }
1815 12 : nWithoutEventCounter ++;
1816 : } while (!nDone && !bStopParsing && nWithoutEventCounter < 10);
1817 :
1818 12 : XML_ParserFree(oSchemaParser);
1819 :
1820 12 : if (nWithoutEventCounter == 10)
1821 : {
1822 : CPLError(CE_Failure, CPLE_AppDefined,
1823 0 : "Too much data inside one element. File probably corrupted");
1824 0 : bStopParsing = TRUE;
1825 : }
1826 :
1827 : CPLAssert(poSRS == NULL);
1828 12 : if (bSameSRS && bFoundGeom)
1829 : {
1830 9 : if (pszGMLSRSName == NULL)
1831 : {
1832 8 : poSRS = new OGRSpatialReference();
1833 8 : poSRS->SetWellKnownGeogCS( "WGS84" ); /* no AXIS definition ! */
1834 : }
1835 : else
1836 : {
1837 1 : poSRS = new OGRSpatialReference();
1838 1 : poSRS->importFromURN(pszGMLSRSName);
1839 : }
1840 : }
1841 :
1842 12 : if (eGeomType != wkbUnknown)
1843 5 : poFeatureDefn->SetGeomType(eGeomType);
1844 :
1845 12 : if (setOfFoundFields)
1846 12 : CPLHashSetDestroy(setOfFoundFields);
1847 12 : setOfFoundFields = NULL;
1848 12 : CPLFree(pszGMLSRSName);
1849 12 : pszGMLSRSName = NULL;
1850 12 : CPLFree(pszTagWithSubTag);
1851 12 : pszTagWithSubTag = NULL;
1852 :
1853 12 : VSIFSeekL( fpGeoRSS, 0, SEEK_SET );
1854 : }
1855 :
1856 :
1857 : /************************************************************************/
1858 : /* OGRGeoRSSIsInt() */
1859 : /************************************************************************/
1860 :
1861 3 : static int OGRGeoRSSIsInt(const char* pszStr)
1862 : {
1863 : int i;
1864 :
1865 6 : while(*pszStr == ' ')
1866 0 : pszStr++;
1867 :
1868 12 : for(i=0;pszStr[i];i++)
1869 : {
1870 9 : if (pszStr[i] == '+' || pszStr[i] == '-')
1871 : {
1872 0 : if (i != 0)
1873 0 : return FALSE;
1874 : }
1875 9 : else if (!(pszStr[i] >= '0' && pszStr[i] <= '9'))
1876 0 : return FALSE;
1877 : }
1878 3 : return TRUE;
1879 : }
1880 :
1881 : /************************************************************************/
1882 : /* startElementLoadSchemaCbk() */
1883 : /************************************************************************/
1884 :
1885 276 : void OGRGeoRSSLayer::startElementLoadSchemaCbk(const char *pszName, const char **ppszAttr)
1886 : {
1887 276 : if (bStopParsing) return;
1888 :
1889 276 : nWithoutEventCounter = 0;
1890 :
1891 303 : if ((eFormat == GEORSS_ATOM && currentDepth == 1 && strcmp(pszName, "entry") == 0) ||
1892 : (eFormat == GEORSS_RSS && currentDepth == 2 && strcmp(pszName, "item") == 0))
1893 : {
1894 27 : bInFeature = TRUE;
1895 27 : featureDepth = currentDepth;
1896 :
1897 27 : nTotalFeatureCount ++;
1898 :
1899 27 : if (setOfFoundFields)
1900 15 : CPLHashSetDestroy(setOfFoundFields);
1901 27 : setOfFoundFields = CPLHashSetNew(CPLHashSetHashStr, CPLHashSetEqualStr, CPLFree);
1902 : }
1903 259 : else if (bInTagWithSubTag && currentDepth == 3)
1904 : {
1905 10 : char* pszFieldName = CPLStrdup(CPLSPrintf("%s_%s", pszTagWithSubTag, pszName));
1906 10 : if (poFeatureDefn->GetFieldIndex(pszFieldName) == -1)
1907 : {
1908 10 : OGRFieldDefn newFieldDefn(pszFieldName, OFTString);
1909 10 : poFeatureDefn->AddFieldDefn(&newFieldDefn);
1910 :
1911 10 : if (poFeatureDefn->GetFieldCount() == 100)
1912 : {
1913 : CPLError(CE_Failure, CPLE_AppDefined,
1914 0 : "Too many fields. File probably corrupted");
1915 0 : XML_StopParser(oSchemaParser, XML_FALSE);
1916 0 : bStopParsing = TRUE;
1917 10 : }
1918 : }
1919 10 : CPLFree(pszFieldName);
1920 : }
1921 239 : else if (bInFeature && eFormat == GEORSS_ATOM &&
1922 : currentDepth == 2 && OGRGeoRSSLayerATOMTagHasSubElement(pszName))
1923 : {
1924 6 : CPLFree(pszTagWithSubTag);
1925 6 : pszTagWithSubTag = CPLStrdup(pszName);
1926 :
1927 6 : int count = 1;
1928 14 : while(CPLHashSetLookup(setOfFoundFields, pszTagWithSubTag) != NULL)
1929 : {
1930 2 : count ++;
1931 2 : CPLFree(pszTagWithSubTag);
1932 2 : pszTagWithSubTag = CPLStrdup(CPLSPrintf("%s%d", pszName, count));
1933 : }
1934 6 : CPLHashSetInsert(setOfFoundFields, CPLStrdup(pszTagWithSubTag));
1935 :
1936 6 : bInTagWithSubTag = TRUE;
1937 : }
1938 353 : else if (bInFeature && currentDepth == featureDepth + 1 && !IS_GEO_ELEMENT(pszName))
1939 : {
1940 120 : CPLFree(pszSubElementName);
1941 120 : pszSubElementName = CPLStrdup(pszName);
1942 :
1943 120 : int count = 1;
1944 247 : while(CPLHashSetLookup(setOfFoundFields, pszSubElementName) != NULL)
1945 : {
1946 7 : count ++;
1947 7 : CPLFree(pszSubElementName);
1948 7 : pszSubElementName = CPLStrdup(CPLSPrintf("%s%d", pszName, count));
1949 : }
1950 120 : CPLHashSetInsert(setOfFoundFields, CPLStrdup(pszSubElementName));
1951 :
1952 : /* Create field definition for element */
1953 120 : char* pszCompatibleName = OGRGeoRSS_GetOGRCompatibleTagName(pszSubElementName);
1954 120 : int iField = poFeatureDefn->GetFieldIndex(pszCompatibleName);
1955 120 : if (iField >= 0)
1956 : {
1957 66 : currentFieldDefn = poFeatureDefn->GetFieldDefn(iField);
1958 : }
1959 54 : else if ( ! (eFormat == GEORSS_RSS && strcmp(pszName, "enclosure") == 0) &&
1960 : ! (eFormat == GEORSS_ATOM && strcmp(pszName, "link") == 0) &&
1961 : ! (eFormat == GEORSS_ATOM && strcmp(pszName, "category") == 0))
1962 : {
1963 : OGRFieldType eFieldType;
1964 60 : if ((eFormat == GEORSS_RSS && strcmp(pszName, "pubDate") == 0) ||
1965 : (eFormat == GEORSS_ATOM && strcmp(pszName, "updated") == 0) ||
1966 : (eFormat == GEORSS_ATOM && strcmp(pszName, "published") == 0) ||
1967 : strcmp(pszName, "dc:date") == 0)
1968 10 : eFieldType = OFTDateTime;
1969 : else
1970 40 : eFieldType = OFTInteger;
1971 :
1972 50 : OGRFieldDefn newFieldDefn(pszCompatibleName, eFieldType);
1973 50 : poFeatureDefn->AddFieldDefn(&newFieldDefn);
1974 50 : currentFieldDefn = poFeatureDefn->GetFieldDefn(poFeatureDefn->GetFieldCount() - 1);
1975 :
1976 50 : if (poFeatureDefn->GetFieldCount() == 100)
1977 : {
1978 : CPLError(CE_Failure, CPLE_AppDefined,
1979 0 : "Too many fields. File probably corrupted");
1980 0 : XML_StopParser(oSchemaParser, XML_FALSE);
1981 0 : bStopParsing = TRUE;
1982 50 : }
1983 : }
1984 :
1985 : /* Create field definitions for attributes */
1986 151 : for(int i=0; ppszAttr[i] != NULL && ppszAttr[i+1] != NULL && !bStopParsing; i+= 2)
1987 : {
1988 : char* pszAttrCompatibleName =
1989 31 : OGRGeoRSS_GetOGRCompatibleTagName(CPLSPrintf("%s_%s", pszSubElementName, ppszAttr[i]));
1990 31 : iField = poFeatureDefn->GetFieldIndex(pszAttrCompatibleName);
1991 : OGRFieldDefn* currentAttrFieldDefn;
1992 31 : if (iField >= 0)
1993 : {
1994 0 : currentAttrFieldDefn = poFeatureDefn->GetFieldDefn(iField);
1995 : }
1996 : else
1997 : {
1998 31 : OGRFieldDefn newFieldDefn(pszAttrCompatibleName, OFTInteger);
1999 31 : poFeatureDefn->AddFieldDefn(&newFieldDefn);
2000 31 : currentAttrFieldDefn = poFeatureDefn->GetFieldDefn(poFeatureDefn->GetFieldCount() - 1);
2001 :
2002 31 : if (poFeatureDefn->GetFieldCount() == 100)
2003 : {
2004 : CPLError(CE_Failure, CPLE_AppDefined,
2005 0 : "Too many fields. File probably corrupted");
2006 0 : XML_StopParser(oSchemaParser, XML_FALSE);
2007 0 : bStopParsing = TRUE;
2008 31 : }
2009 : }
2010 31 : if (currentAttrFieldDefn->GetType() == OFTInteger ||
2011 : currentAttrFieldDefn->GetType() == OFTReal)
2012 : {
2013 31 : char* pszRemainingStr = NULL;
2014 31 : CPLStrtod(ppszAttr[i + 1], &pszRemainingStr);
2015 33 : if (pszRemainingStr == NULL ||
2016 : *pszRemainingStr == 0 ||
2017 : *pszRemainingStr == ' ')
2018 : {
2019 2 : if (currentAttrFieldDefn->GetType() == OFTInteger)
2020 : {
2021 2 : if (OGRGeoRSSIsInt(ppszAttr[i + 1]) == FALSE)
2022 : {
2023 0 : currentAttrFieldDefn->SetType(OFTReal);
2024 : }
2025 : }
2026 : }
2027 : else
2028 : {
2029 29 : currentAttrFieldDefn->SetType(OFTString);
2030 : }
2031 : }
2032 31 : CPLFree(pszAttrCompatibleName);
2033 : }
2034 :
2035 120 : CPLFree(pszCompatibleName);
2036 : }
2037 124 : else if (strcmp(pszName, "georss:point") == 0 ||
2038 : strcmp(pszName, "georss:line") == 0 ||
2039 : strcmp(pszName, "geo:line") == 0 ||
2040 : IS_LAT_ELEMENT(pszName) ||
2041 : strcmp(pszName, "georss:polygon") == 0 ||
2042 : strcmp(pszName, "georss:box") == 0)
2043 : {
2044 11 : if (bSameSRS)
2045 : {
2046 11 : if (pszGMLSRSName != NULL)
2047 0 : bSameSRS = FALSE;
2048 : }
2049 : }
2050 102 : else if (strcmp(pszName, "gml:Point") == 0 ||
2051 : strcmp(pszName, "gml:LineString") == 0 ||
2052 : strcmp(pszName, "gml:Polygon") == 0 ||
2053 : strcmp(pszName, "gml:Envelope") == 0)
2054 : {
2055 10 : if (bSameSRS)
2056 : {
2057 10 : int bFoundSRS = FALSE;
2058 10 : for(int i = 0; ppszAttr[i] != NULL; i+=2)
2059 : {
2060 1 : if (strcmp(ppszAttr[i], "srsName") == 0)
2061 : {
2062 1 : bFoundSRS = TRUE;
2063 1 : if (pszGMLSRSName != NULL)
2064 : {
2065 0 : if (strcmp(pszGMLSRSName , ppszAttr[i+1]) != 0)
2066 0 : bSameSRS = FALSE;
2067 : }
2068 : else
2069 1 : pszGMLSRSName = CPLStrdup(ppszAttr[i+1]);
2070 1 : break;
2071 : }
2072 : }
2073 10 : if (!bFoundSRS && pszGMLSRSName != NULL)
2074 0 : bSameSRS = FALSE;
2075 : }
2076 : }
2077 :
2078 276 : if (!bInFeature || currentDepth >= featureDepth + 1)
2079 : {
2080 249 : int nDimension = 2;
2081 317 : for(int i = 0; ppszAttr[i] != NULL; i+=2)
2082 : {
2083 68 : if (strcmp(ppszAttr[i], "srsDimension") == 0)
2084 : {
2085 0 : nDimension = atoi(ppszAttr[i+1]);
2086 0 : break;
2087 : }
2088 : }
2089 :
2090 249 : OGRwkbGeometryType eFoundGeomType = wkbUnknown;
2091 256 : if (strcmp(pszName, "georss:point") == 0 ||
2092 : IS_LAT_ELEMENT(pszName) ||
2093 : strcmp(pszName, "gml:Point") == 0)
2094 : {
2095 7 : eFoundGeomType = wkbPoint;
2096 : }
2097 247 : else if (strcmp(pszName, "georss:line") == 0 ||
2098 : strcmp(pszName, "geo:line") == 0 ||
2099 : strcmp(pszName, "gml:LineString") == 0)
2100 : {
2101 5 : eFoundGeomType = wkbLineString;
2102 : }
2103 237 : else if (strcmp(pszName, "georss:polygon") == 0 ||
2104 : strcmp(pszName, "gml:Polygon") == 0 ||
2105 : strcmp(pszName, "gml:Envelope") == 0 ||
2106 : strcmp(pszName, "georss:box") == 0)
2107 : {
2108 9 : eFoundGeomType = wkbPolygon;
2109 : }
2110 :
2111 249 : if (eFoundGeomType != wkbUnknown)
2112 : {
2113 21 : if (!bFoundGeom)
2114 : {
2115 9 : eGeomType = eFoundGeomType;
2116 9 : bFoundGeom = TRUE;
2117 : }
2118 12 : else if (wkbFlatten(eGeomType) != eFoundGeomType)
2119 12 : eGeomType = wkbUnknown;
2120 :
2121 21 : if (nDimension == 3)
2122 0 : eGeomType = (OGRwkbGeometryType) (eGeomType | wkb25DBit);
2123 : }
2124 : }
2125 :
2126 276 : currentDepth++;
2127 : }
2128 :
2129 : /************************************************************************/
2130 : /* endElementLoadSchemaCbk() */
2131 : /************************************************************************/
2132 :
2133 276 : void OGRGeoRSSLayer::endElementLoadSchemaCbk(const char *pszName)
2134 : {
2135 276 : if (bStopParsing) return;
2136 :
2137 276 : nWithoutEventCounter = 0;
2138 :
2139 276 : currentDepth--;
2140 :
2141 276 : if (!bInFeature)
2142 58 : return;
2143 :
2144 245 : if ((eFormat == GEORSS_ATOM && currentDepth == 1 && strcmp(pszName, "entry") == 0) ||
2145 : (eFormat == GEORSS_RSS && currentDepth == 2 && strcmp(pszName, "item") == 0))
2146 : {
2147 27 : bInFeature = FALSE;
2148 : }
2149 191 : else if (bInFeature && eFormat == GEORSS_ATOM &&
2150 : currentDepth == 2 && OGRGeoRSSLayerATOMTagHasSubElement(pszName))
2151 : {
2152 6 : bInTagWithSubTag = FALSE;
2153 : }
2154 185 : else if (currentDepth == featureDepth + 1 && pszSubElementName)
2155 : {
2156 : /* Patch field type */
2157 120 : if (pszSubElementValue && nSubElementValueLen && currentFieldDefn)
2158 : {
2159 116 : pszSubElementValue[nSubElementValueLen] = 0;
2160 116 : if (currentFieldDefn->GetType() == OFTInteger ||
2161 : currentFieldDefn->GetType() == OFTReal)
2162 : {
2163 40 : char* pszRemainingStr = NULL;
2164 40 : CPLStrtod(pszSubElementValue, &pszRemainingStr);
2165 41 : if (pszRemainingStr == NULL ||
2166 : *pszRemainingStr == 0 ||
2167 : *pszRemainingStr == ' ')
2168 : {
2169 1 : if (currentFieldDefn->GetType() == OFTInteger)
2170 : {
2171 1 : if (OGRGeoRSSIsInt(pszSubElementValue) == FALSE)
2172 : {
2173 0 : currentFieldDefn->SetType(OFTReal);
2174 : }
2175 : }
2176 : }
2177 : else
2178 : {
2179 39 : currentFieldDefn->SetType(OFTString);
2180 : }
2181 : }
2182 : }
2183 :
2184 120 : CPLFree(pszSubElementName);
2185 120 : pszSubElementName = NULL;
2186 120 : CPLFree(pszSubElementValue);
2187 120 : pszSubElementValue = NULL;
2188 120 : nSubElementValueLen = 0;
2189 120 : currentFieldDefn = NULL;
2190 : }
2191 : }
2192 :
2193 : /************************************************************************/
2194 : /* dataHandlerLoadSchemaCbk() */
2195 : /************************************************************************/
2196 :
2197 792 : void OGRGeoRSSLayer::dataHandlerLoadSchemaCbk(const char *data, int nLen)
2198 : {
2199 792 : if (bStopParsing) return;
2200 :
2201 792 : nDataHandlerCounter ++;
2202 792 : if (nDataHandlerCounter >= BUFSIZ)
2203 : {
2204 0 : CPLError(CE_Failure, CPLE_AppDefined, "File probably corrupted (million laugh pattern)");
2205 0 : XML_StopParser(oSchemaParser, XML_FALSE);
2206 0 : bStopParsing = TRUE;
2207 0 : return;
2208 : }
2209 :
2210 792 : nWithoutEventCounter = 0;
2211 :
2212 792 : if (pszSubElementName)
2213 : {
2214 125 : char* pszNewSubElementValue = (char*) VSIRealloc(pszSubElementValue, nSubElementValueLen + nLen + 1);
2215 125 : if (pszNewSubElementValue == NULL)
2216 : {
2217 0 : CPLError(CE_Failure, CPLE_OutOfMemory, "Out of memory");
2218 0 : XML_StopParser(oSchemaParser, XML_FALSE);
2219 0 : bStopParsing = TRUE;
2220 0 : return;
2221 : }
2222 125 : pszSubElementValue = pszNewSubElementValue;
2223 125 : memcpy(pszSubElementValue + nSubElementValueLen, data, nLen);
2224 125 : nSubElementValueLen += nLen;
2225 125 : if (nSubElementValueLen > 100000)
2226 : {
2227 : CPLError(CE_Failure, CPLE_AppDefined,
2228 0 : "Too much data inside one element. File probably corrupted");
2229 0 : XML_StopParser(oSchemaParser, XML_FALSE);
2230 0 : bStopParsing = TRUE;
2231 : }
2232 : }
2233 : }
2234 : #else
2235 : void OGRGeoRSSLayer::LoadSchema()
2236 : {
2237 : }
2238 : #endif
2239 :
2240 : /************************************************************************/
2241 : /* TestCapability() */
2242 : /************************************************************************/
2243 :
2244 0 : int OGRGeoRSSLayer::TestCapability( const char * pszCap )
2245 :
2246 : {
2247 0 : if( EQUAL(pszCap,OLCFastFeatureCount) )
2248 : return !bWriteMode && bHasReadSchema &&
2249 0 : m_poFilterGeom == NULL && m_poAttrQuery == NULL;
2250 :
2251 0 : else if( EQUAL(pszCap,OLCStringsAsUTF8) )
2252 0 : return TRUE;
2253 :
2254 0 : else if( EQUAL(pszCap,OLCSequentialWrite) )
2255 0 : return bWriteMode;
2256 : else
2257 0 : return FALSE;
2258 : }
2259 :
2260 : /************************************************************************/
2261 : /* GetFeatureCount() */
2262 : /************************************************************************/
2263 :
2264 0 : int OGRGeoRSSLayer::GetFeatureCount( int bForce )
2265 :
2266 : {
2267 0 : if (bWriteMode)
2268 : {
2269 : CPLError(CE_Failure, CPLE_NotSupported,
2270 0 : "Cannot read features when writing a GeoRSS file");
2271 0 : return 0;
2272 : }
2273 :
2274 0 : if (!bHasReadSchema)
2275 0 : LoadSchema();
2276 :
2277 0 : if( m_poFilterGeom != NULL || m_poAttrQuery != NULL )
2278 0 : return OGRLayer::GetFeatureCount( bForce );
2279 : else
2280 0 : return nTotalFeatureCount;
2281 : }
|