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