1 /******************************************************************************
2 * $Id: ogrmemlayer.cpp 28382 2015-01-30 15:29:41Z rouault $
3 *
4 * Project: OpenGIS Simple Features Reference Implementation
5 * Purpose: Implements OGRMemLayer class.
6 * Author: Frank Warmerdam, warmerdam@pobox.com
7 *
8 ******************************************************************************
9 * Copyright (c) 2003, Frank Warmerdam <warmerdam@pobox.com>
10 * Copyright (c) 2009-2013, Even Rouault <even dot rouault at mines-paris dot org>
11 *
12 * Permission is hereby granted, free of charge, to any person obtaining a
13 * copy of this software and associated documentation files (the "Software"),
14 * to deal in the Software without restriction, including without limitation
15 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
16 * and/or sell copies of the Software, and to permit persons to whom the
17 * Software is furnished to do so, subject to the following conditions:
18 *
19 * The above copyright notice and this permission notice shall be included
20 * in all copies or substantial portions of the Software.
21 *
22 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
23 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
25 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
27 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
28 * DEALINGS IN THE SOFTWARE.
29 ****************************************************************************/
30
31 #include "ogr_mem.h"
32 #include "cpl_conv.h"
33 #include "ogr_p.h"
34
35 CPL_CVSID("$Id: ogrmemlayer.cpp 28382 2015-01-30 15:29:41Z rouault $");
36
37 /************************************************************************/
38 /* OGRMemLayer() */
39 /************************************************************************/
40
OGRMemLayer(const char * pszName,OGRSpatialReference * poSRSIn,OGRwkbGeometryType eReqType)41 OGRMemLayer::OGRMemLayer( const char * pszName, OGRSpatialReference *poSRSIn,
42 OGRwkbGeometryType eReqType )
43
44 {
45 iNextReadFID = 0;
46 iNextCreateFID = 0;
47
48 nFeatureCount = 0;
49 nMaxFeatureCount = 0;
50 papoFeatures = NULL;
51
52 poFeatureDefn = new OGRFeatureDefn( pszName );
53 SetDescription( poFeatureDefn->GetName() );
54 poFeatureDefn->SetGeomType( eReqType );
55 if( eReqType != wkbNone && poSRSIn != NULL )
56 {
57 OGRSpatialReference* poSRS = poSRSIn->Clone();
58 poFeatureDefn->GetGeomFieldDefn(0)->SetSpatialRef(poSRS);
59 poSRS->Release();
60 }
61 poFeatureDefn->Reference();
62
63 bUpdatable = TRUE;
64 bAdvertizeUTF8 = FALSE;
65 bHasHoles = FALSE;
66 }
67
68 /************************************************************************/
69 /* ~OGRMemLayer() */
70 /************************************************************************/
71
~OGRMemLayer()72 OGRMemLayer::~OGRMemLayer()
73
74 {
75 if( m_nFeaturesRead > 0 && poFeatureDefn != NULL )
76 {
77 CPLDebug( "Mem", CPL_FRMT_GIB " features read on layer '%s'.",
78 m_nFeaturesRead,
79 poFeatureDefn->GetName() );
80 }
81
82 for( GIntBig i = 0; i < nMaxFeatureCount; i++ )
83 {
84 if( papoFeatures[i] != NULL )
85 delete papoFeatures[i];
86 }
87 CPLFree( papoFeatures );
88
89 if( poFeatureDefn )
90 poFeatureDefn->Release();
91 }
92
93 /************************************************************************/
94 /* ResetReading() */
95 /************************************************************************/
96
ResetReading()97 void OGRMemLayer::ResetReading()
98
99 {
100 iNextReadFID = 0;
101 }
102
103 /************************************************************************/
104 /* GetNextFeature() */
105 /************************************************************************/
106
GetNextFeature()107 OGRFeature *OGRMemLayer::GetNextFeature()
108
109 {
110 while( iNextReadFID < nMaxFeatureCount )
111 {
112 OGRFeature *poFeature = papoFeatures[iNextReadFID++];
113
114 if( poFeature == NULL )
115 continue;
116
117 if( (m_poFilterGeom == NULL
118 || FilterGeometry( poFeature->GetGeomFieldRef(m_iGeomFieldFilter) ) )
119 && (m_poAttrQuery == NULL
120 || m_poAttrQuery->Evaluate( poFeature ) ) )
121 {
122 m_nFeaturesRead++;
123 return poFeature->Clone();
124 }
125 }
126
127 return NULL;
128 }
129
130 /************************************************************************/
131 /* SetNextByIndex() */
132 /************************************************************************/
133
SetNextByIndex(GIntBig nIndex)134 OGRErr OGRMemLayer::SetNextByIndex( GIntBig nIndex )
135
136 {
137 if( m_poFilterGeom != NULL || m_poAttrQuery != NULL || bHasHoles )
138 return OGRLayer::SetNextByIndex( nIndex );
139
140 if (nIndex < 0 || nIndex >= nMaxFeatureCount)
141 return OGRERR_FAILURE;
142
143 iNextReadFID = nIndex;
144
145 return OGRERR_NONE;
146 }
147
148 /************************************************************************/
149 /* GetFeature() */
150 /************************************************************************/
151
GetFeature(GIntBig nFeatureId)152 OGRFeature *OGRMemLayer::GetFeature( GIntBig nFeatureId )
153
154 {
155 if( nFeatureId < 0 || nFeatureId >= nMaxFeatureCount )
156 return NULL;
157 else if( papoFeatures[nFeatureId] == NULL )
158 return NULL;
159 else
160 return papoFeatures[nFeatureId]->Clone();
161 }
162
163 /************************************************************************/
164 /* ISetFeature() */
165 /************************************************************************/
166
ISetFeature(OGRFeature * poFeature)167 OGRErr OGRMemLayer::ISetFeature( OGRFeature *poFeature )
168
169 {
170 if (!bUpdatable)
171 return OGRERR_FAILURE;
172
173 if( poFeature == NULL )
174 return OGRERR_FAILURE;
175
176 if( poFeature->GetFID() == OGRNullFID )
177 {
178 while( iNextCreateFID < nMaxFeatureCount
179 && papoFeatures[iNextCreateFID] != NULL )
180 iNextCreateFID++;
181 poFeature->SetFID( iNextCreateFID++ );
182 }
183 else if ( poFeature->GetFID() < OGRNullFID )
184 {
185 CPLError(CE_Failure, CPLE_NotSupported,
186 "negative FID are not supported");
187 return OGRERR_FAILURE;
188 }
189
190 if( poFeature->GetFID() >= nMaxFeatureCount )
191 {
192 GIntBig nNewCount = MAX(2*nMaxFeatureCount+10, poFeature->GetFID() + 1 );
193 if( (GIntBig)(size_t)(sizeof(OGRFeature *) * nNewCount) !=
194 (GIntBig)sizeof(OGRFeature *) * nNewCount )
195 {
196 CPLError(CE_Failure, CPLE_OutOfMemory,
197 "Cannot allocate array of " CPL_FRMT_GIB " elements", nNewCount);
198 return OGRERR_FAILURE;
199 }
200
201 OGRFeature** papoNewFeatures = (OGRFeature **)
202 VSIRealloc( papoFeatures, (size_t)(sizeof(OGRFeature *) * nNewCount) );
203 if (papoNewFeatures == NULL)
204 {
205 CPLError(CE_Failure, CPLE_OutOfMemory,
206 "Cannot allocate array of " CPL_FRMT_GIB " elements", nNewCount);
207 return OGRERR_FAILURE;
208 }
209 papoFeatures = papoNewFeatures;
210 memset( papoFeatures + nMaxFeatureCount, 0,
211 sizeof(OGRFeature *) * (size_t)(nNewCount - nMaxFeatureCount) );
212 nMaxFeatureCount = nNewCount;
213 }
214
215 if( papoFeatures[poFeature->GetFID()] != NULL )
216 {
217 delete papoFeatures[poFeature->GetFID()];
218 papoFeatures[poFeature->GetFID()] = NULL;
219 nFeatureCount--;
220 }
221
222 papoFeatures[poFeature->GetFID()] = poFeature->Clone();
223 int i;
224 for(i = 0; i < poFeatureDefn->GetGeomFieldCount(); i ++)
225 {
226 OGRGeometry* poGeom = papoFeatures[poFeature->GetFID()]->GetGeomFieldRef(i);
227 if( poGeom != NULL && poGeom->getSpatialReference() == NULL )
228 {
229 poGeom->assignSpatialReference(
230 poFeatureDefn->GetGeomFieldDefn(i)->GetSpatialRef());
231 }
232 }
233 nFeatureCount++;
234
235 return OGRERR_NONE;
236 }
237
238 /************************************************************************/
239 /* ICreateFeature() */
240 /************************************************************************/
241
ICreateFeature(OGRFeature * poFeature)242 OGRErr OGRMemLayer::ICreateFeature( OGRFeature *poFeature )
243
244 {
245 if (!bUpdatable)
246 return OGRERR_FAILURE;
247
248 if( poFeature->GetFID() != OGRNullFID &&
249 poFeature->GetFID() != iNextCreateFID )
250 bHasHoles = TRUE;
251
252 if( poFeature->GetFID() != OGRNullFID
253 && poFeature->GetFID() >= 0
254 && poFeature->GetFID() < nMaxFeatureCount )
255 {
256 if( papoFeatures[poFeature->GetFID()] != NULL )
257 poFeature->SetFID( OGRNullFID );
258 }
259
260 if( poFeature->GetFID() > 10000000 )
261 poFeature->SetFID( OGRNullFID );
262
263 return SetFeature( poFeature );
264 }
265
266 /************************************************************************/
267 /* DeleteFeature() */
268 /************************************************************************/
269
DeleteFeature(GIntBig nFID)270 OGRErr OGRMemLayer::DeleteFeature( GIntBig nFID )
271
272 {
273 if (!bUpdatable)
274 return OGRERR_FAILURE;
275
276 if( nFID < 0 || nFID >= nMaxFeatureCount
277 || papoFeatures[nFID] == NULL )
278 {
279 return OGRERR_FAILURE;
280 }
281 else
282 {
283 bHasHoles = TRUE;
284
285 delete papoFeatures[nFID];
286 papoFeatures[nFID] = NULL;
287 nFeatureCount--;
288 return OGRERR_NONE;
289 }
290 }
291
292 /************************************************************************/
293 /* GetFeatureCount() */
294 /* */
295 /* If a spatial filter is in effect, we turn control over to */
296 /* the generic counter. Otherwise we return the total count. */
297 /* Eventually we should consider implementing a more efficient */
298 /* way of counting features matching a spatial query. */
299 /************************************************************************/
300
GetFeatureCount(int bForce)301 GIntBig OGRMemLayer::GetFeatureCount( int bForce )
302
303 {
304 if( m_poFilterGeom != NULL || m_poAttrQuery != NULL )
305 return OGRLayer::GetFeatureCount( bForce );
306 else
307 return nFeatureCount;
308 }
309
310 /************************************************************************/
311 /* TestCapability() */
312 /************************************************************************/
313
TestCapability(const char * pszCap)314 int OGRMemLayer::TestCapability( const char * pszCap )
315
316 {
317 if( EQUAL(pszCap,OLCRandomRead) )
318 return TRUE;
319
320 else if( EQUAL(pszCap,OLCSequentialWrite)
321 || EQUAL(pszCap,OLCRandomWrite) )
322 return bUpdatable;
323
324 else if( EQUAL(pszCap,OLCFastFeatureCount) )
325 return m_poFilterGeom == NULL && m_poAttrQuery == NULL;
326
327 else if( EQUAL(pszCap,OLCFastSpatialFilter) )
328 return FALSE;
329
330 else if( EQUAL(pszCap,OLCDeleteFeature) )
331 return bUpdatable;
332
333 else if( EQUAL(pszCap,OLCCreateField) ||
334 EQUAL(pszCap,OLCCreateGeomField) ||
335 EQUAL(pszCap,OLCDeleteField) ||
336 EQUAL(pszCap,OLCReorderFields) ||
337 EQUAL(pszCap,OLCAlterFieldDefn) )
338 return bUpdatable;
339
340 else if( EQUAL(pszCap,OLCFastSetNextByIndex) )
341 return m_poFilterGeom == NULL && m_poAttrQuery == NULL && !bHasHoles;
342
343 else if( EQUAL(pszCap,OLCStringsAsUTF8) )
344 return bAdvertizeUTF8;
345
346 else if( EQUAL(pszCap,OLCCurveGeometries) )
347 return TRUE;
348 else
349 return FALSE;
350 }
351
352 /************************************************************************/
353 /* CreateField() */
354 /************************************************************************/
355
CreateField(OGRFieldDefn * poField,CPL_UNUSED int bApproxOK)356 OGRErr OGRMemLayer::CreateField( OGRFieldDefn *poField,
357 CPL_UNUSED int bApproxOK )
358 {
359 if (!bUpdatable)
360 return OGRERR_FAILURE;
361
362 /* -------------------------------------------------------------------- */
363 /* simple case, no features exist yet. */
364 /* -------------------------------------------------------------------- */
365 if( nFeatureCount == 0 )
366 {
367 poFeatureDefn->AddFieldDefn( poField );
368 return OGRERR_NONE;
369 }
370
371 /* -------------------------------------------------------------------- */
372 /* Add field definition and setup remap definition. */
373 /* -------------------------------------------------------------------- */
374 int *panRemap;
375 GIntBig i;
376
377 poFeatureDefn->AddFieldDefn( poField );
378
379 panRemap = (int *) CPLMalloc(sizeof(int) * poFeatureDefn->GetFieldCount());
380 for( i = 0; i < poFeatureDefn->GetFieldCount(); i++ )
381 {
382 if( i < poFeatureDefn->GetFieldCount() - 1 )
383 panRemap[i] = (int)i;
384 else
385 panRemap[i] = -1;
386 }
387
388 /* -------------------------------------------------------------------- */
389 /* Remap all the internal features. Hopefully there aren't any */
390 /* external features referring to our OGRFeatureDefn! */
391 /* -------------------------------------------------------------------- */
392 for( i = 0; i < nMaxFeatureCount; i++ )
393 {
394 if( papoFeatures[i] != NULL )
395 papoFeatures[i]->RemapFields( NULL, panRemap );
396 }
397
398 CPLFree( panRemap );
399
400 return OGRERR_NONE;
401 }
402
403 /************************************************************************/
404 /* DeleteField() */
405 /************************************************************************/
406
DeleteField(int iField)407 OGRErr OGRMemLayer::DeleteField( int iField )
408 {
409 if (!bUpdatable)
410 return OGRERR_FAILURE;
411
412 if (iField < 0 || iField >= poFeatureDefn->GetFieldCount())
413 {
414 CPLError( CE_Failure, CPLE_NotSupported,
415 "Invalid field index");
416 return OGRERR_FAILURE;
417 }
418
419 /* -------------------------------------------------------------------- */
420 /* Update all the internal features. Hopefully there aren't any */
421 /* external features referring to our OGRFeatureDefn! */
422 /* -------------------------------------------------------------------- */
423 for( GIntBig i = 0; i < nMaxFeatureCount; i++ )
424 {
425 if( papoFeatures[i] == NULL )
426 continue;
427
428 OGRField* poFieldRaw = papoFeatures[i]->GetRawFieldRef(iField);
429 if( papoFeatures[i]->IsFieldSet(iField) )
430 {
431 /* Little trick to unallocate the field */
432 OGRField sField;
433 sField.Set.nMarker1 = OGRUnsetMarker;
434 sField.Set.nMarker2 = OGRUnsetMarker;
435 papoFeatures[i]->SetField(iField, &sField);
436 }
437
438 if (iField < poFeatureDefn->GetFieldCount() - 1)
439 {
440 memmove( poFieldRaw, poFieldRaw + 1,
441 sizeof(OGRField) * (poFeatureDefn->GetFieldCount() - 1 - iField) );
442 }
443 }
444
445 return poFeatureDefn->DeleteFieldDefn( iField );
446 }
447
448 /************************************************************************/
449 /* ReorderFields() */
450 /************************************************************************/
451
ReorderFields(int * panMap)452 OGRErr OGRMemLayer::ReorderFields( int* panMap )
453 {
454 if (!bUpdatable)
455 return OGRERR_FAILURE;
456
457 if (poFeatureDefn->GetFieldCount() == 0)
458 return OGRERR_NONE;
459
460 OGRErr eErr = OGRCheckPermutation(panMap, poFeatureDefn->GetFieldCount());
461 if (eErr != OGRERR_NONE)
462 return eErr;
463
464 /* -------------------------------------------------------------------- */
465 /* Remap all the internal features. Hopefully there aren't any */
466 /* external features referring to our OGRFeatureDefn! */
467 /* -------------------------------------------------------------------- */
468 for( GIntBig i = 0; i < nMaxFeatureCount; i++ )
469 {
470 if( papoFeatures[i] != NULL )
471 papoFeatures[i]->RemapFields( NULL, panMap );
472 }
473
474 return poFeatureDefn->ReorderFieldDefns( panMap );
475 }
476
477 /************************************************************************/
478 /* AlterFieldDefn() */
479 /************************************************************************/
480
AlterFieldDefn(int iField,OGRFieldDefn * poNewFieldDefn,int nFlags)481 OGRErr OGRMemLayer::AlterFieldDefn( int iField, OGRFieldDefn* poNewFieldDefn, int nFlags )
482 {
483 if (!bUpdatable)
484 return OGRERR_FAILURE;
485
486 if (iField < 0 || iField >= poFeatureDefn->GetFieldCount())
487 {
488 CPLError( CE_Failure, CPLE_NotSupported,
489 "Invalid field index");
490 return OGRERR_FAILURE;
491 }
492
493 OGRFieldDefn* poFieldDefn = poFeatureDefn->GetFieldDefn(iField);
494
495 if ((nFlags & ALTER_TYPE_FLAG) &&
496 poFieldDefn->GetType() != poNewFieldDefn->GetType())
497 {
498 if ((poNewFieldDefn->GetType() == OFTDate ||
499 poNewFieldDefn->GetType() == OFTTime ||
500 poNewFieldDefn->GetType() == OFTDateTime) &&
501 (poFieldDefn->GetType() == OFTDate ||
502 poFieldDefn->GetType() == OFTTime ||
503 poFieldDefn->GetType() == OFTDateTime))
504 {
505 /* do nothing on features */
506 }
507 else if (poNewFieldDefn->GetType() == OFTInteger64 &&
508 poFieldDefn->GetType() == OFTInteger)
509 {
510 /* -------------------------------------------------------------------- */
511 /* Update all the internal features. Hopefully there aren't any */
512 /* external features referring to our OGRFeatureDefn! */
513 /* -------------------------------------------------------------------- */
514 for( GIntBig i = 0; i < nMaxFeatureCount; i++ )
515 {
516 if( papoFeatures[i] == NULL )
517 continue;
518
519 OGRField* poFieldRaw = papoFeatures[i]->GetRawFieldRef(iField);
520 if( papoFeatures[i]->IsFieldSet(iField) )
521 {
522 poFieldRaw->Integer64 = poFieldRaw->Integer;
523 }
524 }
525 }
526 else if (poNewFieldDefn->GetType() == OFTReal &&
527 poFieldDefn->GetType() == OFTInteger)
528 {
529 /* -------------------------------------------------------------------- */
530 /* Update all the internal features. Hopefully there aren't any */
531 /* external features referring to our OGRFeatureDefn! */
532 /* -------------------------------------------------------------------- */
533 for( GIntBig i = 0; i < nMaxFeatureCount; i++ )
534 {
535 if( papoFeatures[i] == NULL )
536 continue;
537
538 OGRField* poFieldRaw = papoFeatures[i]->GetRawFieldRef(iField);
539 if( papoFeatures[i]->IsFieldSet(iField) )
540 {
541 poFieldRaw->Real = poFieldRaw->Integer;
542 }
543 }
544 }
545 else if (poNewFieldDefn->GetType() == OFTReal &&
546 poFieldDefn->GetType() == OFTInteger64)
547 {
548 /* -------------------------------------------------------------------- */
549 /* Update all the internal features. Hopefully there aren't any */
550 /* external features referring to our OGRFeatureDefn! */
551 /* -------------------------------------------------------------------- */
552 for( GIntBig i = 0; i < nMaxFeatureCount; i++ )
553 {
554 if( papoFeatures[i] == NULL )
555 continue;
556
557 OGRField* poFieldRaw = papoFeatures[i]->GetRawFieldRef(iField);
558 if( papoFeatures[i]->IsFieldSet(iField) )
559 {
560 poFieldRaw->Real = (double) poFieldRaw->Integer64;
561 }
562 }
563 }
564 else
565 {
566 if (poNewFieldDefn->GetType() != OFTString)
567 {
568 CPLError( CE_Failure, CPLE_NotSupported,
569 "Can only convert from OFTInteger to OFTReal, or from anything to OFTString");
570 return OGRERR_FAILURE;
571 }
572
573 /* -------------------------------------------------------------------- */
574 /* Update all the internal features. Hopefully there aren't any */
575 /* external features referring to our OGRFeatureDefn! */
576 /* -------------------------------------------------------------------- */
577 for( GIntBig i = 0; i < nMaxFeatureCount; i++ )
578 {
579 if( papoFeatures[i] == NULL )
580 continue;
581
582 OGRField* poFieldRaw = papoFeatures[i]->GetRawFieldRef(iField);
583 if( papoFeatures[i]->IsFieldSet(iField) )
584 {
585 char* pszVal = CPLStrdup(papoFeatures[i]->GetFieldAsString(iField));
586
587 /* Little trick to unallocate the field */
588 OGRField sField;
589 sField.Set.nMarker1 = OGRUnsetMarker;
590 sField.Set.nMarker2 = OGRUnsetMarker;
591 papoFeatures[i]->SetField(iField, &sField);
592
593 poFieldRaw->String = pszVal;
594 }
595 }
596 }
597
598 poFieldDefn->SetType(poNewFieldDefn->GetType());
599 }
600
601 if (nFlags & ALTER_NAME_FLAG)
602 poFieldDefn->SetName(poNewFieldDefn->GetNameRef());
603 if (nFlags & ALTER_WIDTH_PRECISION_FLAG)
604 {
605 poFieldDefn->SetWidth(poNewFieldDefn->GetWidth());
606 poFieldDefn->SetPrecision(poNewFieldDefn->GetPrecision());
607 }
608
609 return OGRERR_NONE;
610 }
611
612
613 /************************************************************************/
614 /* CreateGeomField() */
615 /************************************************************************/
616
CreateGeomField(OGRGeomFieldDefn * poGeomField,CPL_UNUSED int bApproxOK)617 OGRErr OGRMemLayer::CreateGeomField( OGRGeomFieldDefn *poGeomField,
618 CPL_UNUSED int bApproxOK )
619 {
620 if (!bUpdatable)
621 return OGRERR_FAILURE;
622
623 /* -------------------------------------------------------------------- */
624 /* simple case, no features exist yet. */
625 /* -------------------------------------------------------------------- */
626 if( nFeatureCount == 0 )
627 {
628 poFeatureDefn->AddGeomFieldDefn( poGeomField );
629 return OGRERR_NONE;
630 }
631
632 /* -------------------------------------------------------------------- */
633 /* Add field definition and setup remap definition. */
634 /* -------------------------------------------------------------------- */
635 int *panRemap;
636 GIntBig i;
637
638 poFeatureDefn->AddGeomFieldDefn( poGeomField );
639
640 panRemap = (int *) CPLMalloc(sizeof(int) * poFeatureDefn->GetGeomFieldCount());
641 for( i = 0; i < poFeatureDefn->GetGeomFieldCount(); i++ )
642 {
643 if( i < poFeatureDefn->GetGeomFieldCount() - 1 )
644 panRemap[i] = (int) i;
645 else
646 panRemap[i] = -1;
647 }
648
649 /* -------------------------------------------------------------------- */
650 /* Remap all the internal features. Hopefully there aren't any */
651 /* external features referring to our OGRFeatureDefn! */
652 /* -------------------------------------------------------------------- */
653 for( i = 0; i < nMaxFeatureCount; i++ )
654 {
655 if( papoFeatures[i] != NULL )
656 papoFeatures[i]->RemapGeomFields( NULL, panRemap );
657 }
658
659 CPLFree( panRemap );
660
661 return OGRERR_NONE;
662 }
663