1 : /******************************************************************************
2 : * $Id: ogrgftlayer.cpp 22268 2011-04-30 13:10:40Z rouault $
3 : *
4 : * Project: GFT Translator
5 : * Purpose: Implements OGRGFTLayer class.
6 : * Author: Even Rouault, <even dot rouault at mines dash paris dot org>
7 : *
8 : ******************************************************************************
9 : * Copyright (c) 2011, Even Rouault <even dot rouault at mines dash paris dot org>
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_gft.h"
31 : #include "cpl_minixml.h"
32 :
33 : CPL_CVSID("$Id: ogrgftlayer.cpp 22268 2011-04-30 13:10:40Z rouault $");
34 :
35 : /************************************************************************/
36 : /* OGRGFTLayer() */
37 : /************************************************************************/
38 :
39 292 : OGRGFTLayer::OGRGFTLayer(OGRGFTDataSource* poDS)
40 :
41 : {
42 292 : this->poDS = poDS;
43 :
44 292 : nNextInSeq = 0;
45 :
46 292 : poSRS = new OGRSpatialReference(SRS_WKT_WGS84);
47 :
48 292 : poFeatureDefn = NULL;
49 :
50 292 : nOffset = 0;
51 292 : bEOF = FALSE;
52 :
53 292 : iLatitudeField = iLongitudeField = -1;
54 292 : iGeometryField = -1;
55 292 : bHiddenGeometryField = FALSE;
56 :
57 292 : bFirstTokenIsFID = FALSE;
58 292 : }
59 :
60 : /************************************************************************/
61 : /* ~OGRGFTLayer() */
62 : /************************************************************************/
63 :
64 292 : OGRGFTLayer::~OGRGFTLayer()
65 :
66 : {
67 292 : if( poSRS != NULL )
68 292 : poSRS->Release();
69 :
70 292 : if( poFeatureDefn != NULL )
71 24 : poFeatureDefn->Release();
72 292 : }
73 :
74 : /************************************************************************/
75 : /* ResetReading() */
76 : /************************************************************************/
77 :
78 8 : void OGRGFTLayer::ResetReading()
79 :
80 : {
81 8 : nNextInSeq = 0;
82 8 : nOffset = 0;
83 8 : bEOF = FALSE;
84 8 : }
85 :
86 : /************************************************************************/
87 : /* GetLayerDefn() */
88 : /************************************************************************/
89 :
90 0 : OGRFeatureDefn * OGRGFTLayer::GetLayerDefn()
91 : {
92 0 : CPLAssert(poFeatureDefn);
93 0 : return poFeatureDefn;
94 : }
95 :
96 : /************************************************************************/
97 : /* GetNextFeature() */
98 : /************************************************************************/
99 :
100 14 : OGRFeature *OGRGFTLayer::GetNextFeature()
101 : {
102 : OGRFeature *poFeature;
103 :
104 14 : GetLayerDefn();
105 :
106 0 : while(TRUE)
107 : {
108 14 : if (nNextInSeq < nOffset ||
109 : nNextInSeq >= nOffset + (int)aosRows.size())
110 : {
111 10 : if (bEOF)
112 2 : return NULL;
113 :
114 8 : nOffset += aosRows.size();
115 8 : if (!FetchNextRows())
116 0 : return NULL;
117 : }
118 :
119 12 : poFeature = GetNextRawFeature();
120 12 : if (poFeature == NULL)
121 0 : return NULL;
122 :
123 12 : if((m_poFilterGeom == NULL
124 : || FilterGeometry( poFeature->GetGeometryRef() ) )
125 : && (m_poAttrQuery == NULL
126 : || m_poAttrQuery->Evaluate( poFeature )) )
127 : {
128 12 : return poFeature;
129 : }
130 : else
131 0 : delete poFeature;
132 : }
133 : }
134 :
135 : /************************************************************************/
136 : /* CSVSplitLine() */
137 : /* */
138 : /* Tokenize a CSV line into fields in the form of a string */
139 : /* list. This is used instead of the CPLTokenizeString() */
140 : /* because it provides correct CSV escaping and quoting */
141 : /* semantics. */
142 : /************************************************************************/
143 :
144 38 : char **OGRGFTCSVSplitLine( const char *pszString, char chDelimiter )
145 :
146 : {
147 38 : char **papszRetList = NULL;
148 : char *pszToken;
149 : int nTokenMax, nTokenLen;
150 :
151 38 : pszToken = (char *) CPLCalloc(10,1);
152 38 : nTokenMax = 10;
153 :
154 258 : while( pszString != NULL && *pszString != '\0' )
155 : {
156 182 : int bInString = FALSE;
157 :
158 182 : nTokenLen = 0;
159 :
160 : /* Try to find the next delimeter, marking end of token */
161 2688 : for( ; *pszString != '\0'; pszString++ )
162 : {
163 :
164 : /* End if this is a delimeter skip it and break. */
165 2650 : if( !bInString && *pszString == chDelimiter )
166 : {
167 144 : pszString++;
168 144 : break;
169 : }
170 :
171 2506 : if( *pszString == '"' )
172 : {
173 28 : if( !bInString || pszString[1] != '"' )
174 : {
175 28 : bInString = !bInString;
176 28 : continue;
177 : }
178 : else /* doubled quotes in string resolve to one quote */
179 : {
180 0 : pszString++;
181 : }
182 : }
183 :
184 2478 : if( nTokenLen >= nTokenMax-2 )
185 : {
186 38 : nTokenMax = nTokenMax * 2 + 10;
187 38 : pszToken = (char *) CPLRealloc( pszToken, nTokenMax );
188 : }
189 :
190 2478 : pszToken[nTokenLen] = *pszString;
191 2478 : nTokenLen++;
192 : }
193 :
194 182 : pszToken[nTokenLen] = '\0';
195 182 : papszRetList = CSLAddString( papszRetList, pszToken );
196 :
197 : /* If the last token is an empty token, then we have to catch
198 : * it now, otherwise we won't reenter the loop and it will be lost.
199 : */
200 182 : if ( *pszString == '\0' && *(pszString-1) == chDelimiter )
201 : {
202 0 : papszRetList = CSLAddString( papszRetList, "" );
203 : }
204 : }
205 :
206 38 : if( papszRetList == NULL )
207 0 : papszRetList = (char **) CPLCalloc(sizeof(char *),1);
208 :
209 38 : CPLFree( pszToken );
210 :
211 38 : return papszRetList;
212 : }
213 : /************************************************************************/
214 : /* ParseKMLGeometry() */
215 : /************************************************************************/
216 :
217 8 : static void ParseLineString(OGRLineString* poLS,
218 : const char* pszCoordinates)
219 : {
220 8 : char** papszTuples = CSLTokenizeString2(pszCoordinates, " ", 0);
221 40 : for(int iTuple = 0; papszTuples && papszTuples[iTuple]; iTuple++)
222 : {
223 32 : char** papszTokens = CSLTokenizeString2(papszTuples[iTuple], ",", 0);
224 32 : if (CSLCount(papszTokens) == 2)
225 32 : poLS->addPoint(atof(papszTokens[0]), atof(papszTokens[1]));
226 0 : else if (CSLCount(papszTokens) == 3)
227 0 : poLS->addPoint(atof(papszTokens[0]), atof(papszTokens[1]),
228 0 : atof(papszTokens[2]));
229 32 : CSLDestroy(papszTokens);
230 : }
231 8 : CSLDestroy(papszTuples);
232 8 : }
233 :
234 : /* Could be moved somewhere else */
235 :
236 14 : static OGRGeometry* ParseKMLGeometry(/* const */ CPLXMLNode* psXML)
237 : {
238 14 : OGRGeometry* poGeom = NULL;
239 14 : const char* pszGeomType = psXML->pszValue;
240 14 : if (strcmp(pszGeomType, "Point") == 0)
241 : {
242 10 : const char* pszCoordinates = CPLGetXMLValue(psXML, "coordinates", NULL);
243 10 : if (pszCoordinates)
244 : {
245 10 : char** papszTokens = CSLTokenizeString2(pszCoordinates, ",", 0);
246 10 : if (CSLCount(papszTokens) == 2)
247 10 : poGeom = new OGRPoint(atof(papszTokens[0]), atof(papszTokens[1]));
248 0 : else if (CSLCount(papszTokens) == 3)
249 0 : poGeom = new OGRPoint(atof(papszTokens[0]), atof(papszTokens[1]),
250 0 : atof(papszTokens[2]));
251 10 : CSLDestroy(papszTokens);
252 : }
253 : }
254 4 : else if (strcmp(pszGeomType, "LineString") == 0)
255 : {
256 0 : const char* pszCoordinates = CPLGetXMLValue(psXML, "coordinates", NULL);
257 0 : if (pszCoordinates)
258 : {
259 0 : OGRLineString* poLS = new OGRLineString();
260 0 : ParseLineString(poLS, pszCoordinates);
261 0 : poGeom = poLS;
262 : }
263 : }
264 4 : else if (strcmp(pszGeomType, "Polygon") == 0)
265 : {
266 4 : OGRPolygon* poPoly = NULL;
267 4 : CPLXMLNode* psOuterBoundary = CPLGetXMLNode(psXML, "outerBoundaryIs");
268 4 : if (psOuterBoundary)
269 : {
270 4 : CPLXMLNode* psLinearRing = CPLGetXMLNode(psOuterBoundary, "LinearRing");
271 : const char* pszCoordinates = CPLGetXMLValue(
272 4 : psLinearRing ? psLinearRing : psOuterBoundary, "coordinates", NULL);
273 4 : if (pszCoordinates)
274 : {
275 4 : OGRLinearRing* poLS = new OGRLinearRing();
276 4 : ParseLineString(poLS, pszCoordinates);
277 8 : poPoly = new OGRPolygon();
278 4 : poPoly->addRingDirectly(poLS);
279 4 : poGeom = poPoly;
280 : }
281 :
282 4 : if (poPoly)
283 : {
284 4 : CPLXMLNode* psIter = psXML->psChild;
285 16 : while(psIter)
286 : {
287 8 : if (psIter->eType == CXT_Element &&
288 : strcmp(psIter->pszValue, "innerBoundaryIs") == 0)
289 : {
290 4 : CPLXMLNode* psLinearRing = CPLGetXMLNode(psIter, "LinearRing");
291 : const char* pszCoordinates = CPLGetXMLValue(
292 4 : psLinearRing ? psLinearRing : psIter, "coordinates", NULL);
293 4 : if (pszCoordinates)
294 : {
295 4 : OGRLinearRing* poLS = new OGRLinearRing();
296 4 : ParseLineString(poLS, pszCoordinates);
297 4 : poPoly->addRingDirectly(poLS);
298 : }
299 : }
300 8 : psIter = psIter->psNext;
301 : }
302 : }
303 : }
304 : }
305 0 : else if (strcmp(pszGeomType, "MultiGeometry") == 0)
306 : {
307 : CPLXMLNode* psIter;
308 0 : OGRwkbGeometryType eType = wkbUnknown;
309 0 : for(psIter = psXML->psChild; psIter; psIter = psIter->psNext)
310 : {
311 0 : if (psIter->eType == CXT_Element)
312 : {
313 0 : OGRwkbGeometryType eNewType = wkbUnknown;
314 0 : if (strcmp(psIter->pszValue, "Point") == 0)
315 : {
316 0 : eNewType = wkbPoint;
317 : }
318 0 : else if (strcmp(psIter->pszValue, "LineString") == 0)
319 : {
320 0 : eNewType = wkbLineString;
321 : }
322 0 : else if (strcmp(psIter->pszValue, "Polygon") == 0)
323 : {
324 0 : eNewType = wkbPolygon;
325 : }
326 : else
327 0 : break;
328 0 : if (eType == wkbUnknown)
329 0 : eType = eNewType;
330 0 : else if (eType != eNewType)
331 0 : break;
332 : }
333 : }
334 0 : OGRGeometryCollection* poColl = NULL;
335 0 : if (psIter != NULL)
336 0 : poColl = new OGRGeometryCollection();
337 0 : else if (eType == wkbPoint)
338 0 : poColl = new OGRMultiPoint();
339 0 : else if (eType == wkbLineString)
340 0 : poColl = new OGRMultiLineString();
341 0 : else if (eType == wkbPolygon)
342 0 : poColl = new OGRMultiPolygon();
343 : else
344 0 : CPLAssert(0);
345 :
346 0 : psIter = psXML->psChild;
347 0 : for(psIter = psXML->psChild; psIter; psIter = psIter->psNext)
348 : {
349 0 : if (psIter->eType == CXT_Element)
350 : {
351 0 : OGRGeometry* poSubGeom = ParseKMLGeometry(psIter);
352 0 : if (poSubGeom)
353 0 : poColl->addGeometryDirectly(poSubGeom);
354 : }
355 : }
356 :
357 0 : poGeom = poColl;
358 : }
359 :
360 14 : return poGeom;
361 : }
362 :
363 14 : static OGRGeometry* ParseKMLGeometry(const char* pszKML)
364 : {
365 14 : CPLXMLNode* psXML = CPLParseXMLString(pszKML);
366 14 : if (psXML == NULL)
367 0 : return NULL;
368 :
369 14 : if (psXML->eType != CXT_Element)
370 : {
371 0 : CPLDestroyXMLNode(psXML);
372 0 : return NULL;
373 : }
374 :
375 14 : OGRGeometry* poGeom = ParseKMLGeometry(psXML);
376 :
377 14 : CPLDestroyXMLNode(psXML);
378 14 : return poGeom;
379 : }
380 :
381 :
382 : /************************************************************************/
383 : /* BuildFeatureFromSQL() */
384 : /************************************************************************/
385 :
386 14 : OGRFeature *OGRGFTLayer::BuildFeatureFromSQL(const char* pszLine)
387 : {
388 14 : OGRFeature* poFeature = new OGRFeature(poFeatureDefn);
389 :
390 14 : char** papszTokens = OGRGFTCSVSplitLine(pszLine, ',');
391 14 : int nTokens = CSLCount(papszTokens);
392 14 : CPLString osFID;
393 :
394 14 : int nAttrOffset = 0;
395 14 : int iROWID = -1;
396 14 : if (bFirstTokenIsFID)
397 : {
398 14 : osFID = papszTokens[0];
399 14 : nAttrOffset = 1;
400 : }
401 : else
402 : {
403 0 : iROWID = poFeatureDefn->GetFieldIndex("rowid");
404 0 : if (iROWID < 0)
405 0 : iROWID = poFeatureDefn->GetFieldIndex("ROWID");
406 : }
407 :
408 14 : int nFieldCount = poFeatureDefn->GetFieldCount();
409 14 : if (nTokens == nFieldCount + bHiddenGeometryField + nAttrOffset)
410 : {
411 56 : for(int i=0;i<nFieldCount+bHiddenGeometryField;i++)
412 : {
413 42 : const char* pszVal = papszTokens[i+nAttrOffset];
414 42 : if (pszVal[0])
415 : {
416 42 : if (i<nFieldCount)
417 38 : poFeature->SetField(i, pszVal);
418 :
419 56 : if (i == iGeometryField && i != iLatitudeField)
420 : {
421 14 : if (pszVal[0] == '-' || (pszVal[0] >= '0' && pszVal[0] <= '9'))
422 : {
423 0 : char** papszLatLon = CSLTokenizeString2(pszVal, " ,", 0);
424 0 : if (CSLCount(papszLatLon) == 2 &&
425 0 : CPLGetValueType(papszLatLon[0]) != CPL_VALUE_STRING &&
426 0 : CPLGetValueType(papszLatLon[1]) != CPL_VALUE_STRING)
427 : {
428 0 : OGRPoint* poPoint = new OGRPoint(atof( papszLatLon[1]),
429 0 : atof( papszLatLon[0]));
430 0 : poPoint->assignSpatialReference(poSRS);
431 0 : poFeature->SetGeometryDirectly(poPoint);
432 : }
433 0 : CSLDestroy(papszLatLon);
434 : }
435 14 : else if (strstr(pszVal, "<Point>") ||
436 : strstr(pszVal, "<LineString>") ||
437 : strstr(pszVal, "<Polygon>"))
438 : {
439 14 : OGRGeometry* poGeom = ParseKMLGeometry(pszVal);
440 14 : if (poGeom)
441 : {
442 14 : poGeom->assignSpatialReference(poSRS);
443 14 : poFeature->SetGeometryDirectly(poGeom);
444 : }
445 : }
446 : }
447 28 : else if (i == iROWID)
448 : {
449 0 : osFID = pszVal;
450 : }
451 : }
452 : }
453 :
454 14 : if (iLatitudeField >= 0 && iLongitudeField >= 0)
455 : {
456 0 : const char* pszLat = papszTokens[iLatitudeField+nAttrOffset];
457 0 : const char* pszLong = papszTokens[iLongitudeField+nAttrOffset];
458 0 : if (pszLat[0] != 0 && pszLong[0] != 0 &&
459 : CPLGetValueType(pszLat) != CPL_VALUE_STRING &&
460 : CPLGetValueType(pszLong) != CPL_VALUE_STRING)
461 : {
462 0 : OGRPoint* poPoint = new OGRPoint(atof(pszLong), atof(pszLat));
463 0 : poPoint->assignSpatialReference(poSRS);
464 0 : poFeature->SetGeometryDirectly(poPoint);
465 : }
466 : }
467 : }
468 : else
469 : {
470 0 : CPLDebug("GFT", "Only %d columns for feature %s", nTokens, osFID.c_str());
471 : }
472 14 : CSLDestroy(papszTokens);
473 :
474 14 : int nFID = atoi(osFID);
475 14 : if (strcmp(CPLSPrintf("%d", nFID), osFID.c_str()) == 0)
476 14 : poFeature->SetFID(nFID);
477 : else
478 0 : poFeature->SetFID(nNextInSeq);
479 :
480 14 : return poFeature;
481 : }
482 :
483 : /************************************************************************/
484 : /* GetNextRawFeature() */
485 : /************************************************************************/
486 :
487 12 : OGRFeature *OGRGFTLayer::GetNextRawFeature()
488 : {
489 12 : if (nNextInSeq < nOffset ||
490 : nNextInSeq - nOffset >= (int)aosRows.size())
491 0 : return NULL;
492 :
493 12 : OGRFeature* poFeature = BuildFeatureFromSQL(aosRows[nNextInSeq - nOffset]);
494 :
495 12 : nNextInSeq ++;
496 :
497 12 : return poFeature;
498 : }
499 :
500 : /************************************************************************/
501 : /* SetNextByIndex() */
502 : /************************************************************************/
503 :
504 0 : OGRErr OGRGFTLayer::SetNextByIndex( long nIndex )
505 : {
506 0 : if (nIndex < 0)
507 0 : return OGRERR_FAILURE;
508 0 : bEOF = FALSE;
509 0 : nNextInSeq = nIndex;
510 0 : return OGRERR_NONE;
511 : }
512 :
513 : /************************************************************************/
514 : /* TestCapability() */
515 : /************************************************************************/
516 :
517 0 : int OGRGFTLayer::TestCapability( const char * pszCap )
518 :
519 : {
520 0 : if ( EQUAL(pszCap, OLCStringsAsUTF8) )
521 0 : return TRUE;
522 0 : else if ( EQUAL(pszCap, OLCFastSetNextByIndex) )
523 0 : return TRUE;
524 0 : return FALSE;
525 : }
526 :
527 : /************************************************************************/
528 : /* GetGeometryColumn() */
529 : /************************************************************************/
530 :
531 22 : const char *OGRGFTLayer::GetGeometryColumn()
532 : {
533 22 : GetLayerDefn();
534 22 : if (iGeometryField < 0)
535 0 : return "";
536 :
537 22 : if (iGeometryField == poFeatureDefn->GetFieldCount())
538 : {
539 14 : CPLAssert(bHiddenGeometryField);
540 14 : return GetDefaultGeometryColumnName();
541 : }
542 :
543 8 : return poFeatureDefn->GetFieldDefn(iGeometryField)->GetNameRef();
544 : }
545 :
546 : /************************************************************************/
547 : /* ParseCSVResponse() */
548 : /************************************************************************/
549 :
550 18 : int OGRGFTLayer::ParseCSVResponse(char* pszLine,
551 : std::vector<CPLString>& aosRes)
552 : {
553 90 : while(pszLine != NULL && *pszLine != 0)
554 : {
555 54 : char* pszNextLine = OGRGFTGotoNextLine(pszLine);
556 54 : if (pszNextLine)
557 54 : pszNextLine[-1] = 0;
558 :
559 54 : int nDoubleQuotes = 0;
560 54 : char* pszIter = pszLine;
561 4400 : while(*pszIter)
562 : {
563 4292 : if (*pszIter == '"')
564 : {
565 44 : if (pszIter[1] != '"')
566 44 : nDoubleQuotes ++;
567 : else
568 0 : pszIter ++;
569 : }
570 4292 : pszIter ++;
571 : }
572 :
573 54 : if ((nDoubleQuotes % 2) == 0)
574 54 : aosRes.push_back(pszLine);
575 : else
576 : {
577 0 : CPLString osLine(pszLine);
578 :
579 0 : pszLine = pszNextLine;
580 0 : while(pszLine != NULL && *pszLine != 0)
581 : {
582 0 : pszNextLine = OGRGFTGotoNextLine(pszLine);
583 0 : if (pszNextLine)
584 0 : pszNextLine[-1] = 0;
585 :
586 0 : osLine += "\n";
587 0 : osLine += pszLine;
588 :
589 0 : pszIter = pszLine;
590 0 : while(*pszIter)
591 : {
592 0 : if (*pszIter == '"')
593 : {
594 0 : if (pszIter[1] != '"')
595 0 : nDoubleQuotes ++;
596 : else
597 0 : pszIter ++;
598 : }
599 0 : pszIter ++;
600 : }
601 :
602 0 : if ((nDoubleQuotes % 2) == 0)
603 : {
604 0 : break;
605 : }
606 :
607 0 : pszLine = pszNextLine;
608 : }
609 :
610 0 : aosRes.push_back(osLine);
611 : }
612 :
613 54 : pszLine = pszNextLine;
614 : }
615 :
616 18 : return TRUE;
617 : }
618 :
619 : /************************************************************************/
620 : /* PatchSQL() */
621 : /************************************************************************/
622 :
623 2 : CPLString OGRGFTLayer::PatchSQL(const char* pszSQL)
624 : {
625 2 : CPLString osSQL;
626 :
627 46 : while(*pszSQL)
628 : {
629 42 : if (EQUALN(pszSQL, "COUNT(", 5) && strchr(pszSQL, ')'))
630 : {
631 0 : const char* pszNext = strchr(pszSQL, ')');
632 0 : osSQL += "COUNT()";
633 0 : pszSQL = pszNext + 1;
634 : }
635 42 : else if ((*pszSQL == '<' && pszSQL[1] == '>') ||
636 0 : (*pszSQL == '!' && pszSQL[1] == '='))
637 : {
638 0 : osSQL += " NOT EQUAL TO ";
639 0 : pszSQL += 2;
640 : }
641 : else
642 : {
643 42 : osSQL += *pszSQL;
644 42 : pszSQL ++;
645 : }
646 : }
647 0 : return osSQL;
648 : }
649 :
650 : /************************************************************************/
651 : /* GetSpatialRef() */
652 : /************************************************************************/
653 :
654 2 : OGRSpatialReference* OGRGFTLayer::GetSpatialRef()
655 : {
656 2 : GetLayerDefn();
657 :
658 2 : if (iGeometryField < 0)
659 0 : return NULL;
660 :
661 2 : return poSRS;
662 : }
663 :
664 : /************************************************************************/
665 : /* LaunderColName() */
666 : /************************************************************************/
667 :
668 82 : CPLString OGRGFTLayer::LaunderColName(const char* pszColName)
669 : {
670 82 : CPLString osLaunderedColName;
671 :
672 802 : for(int i=0;pszColName[i];i++)
673 : {
674 720 : if (pszColName[i] == '\n')
675 0 : osLaunderedColName += "\\n";
676 : else
677 720 : osLaunderedColName += pszColName[i];
678 : }
679 0 : return osLaunderedColName;
680 : }
|