1 : /******************************************************************************
2 : * $Id: ogr_miattrind.cpp 14048 2008-03-20 18:47:21Z rouault $
3 : *
4 : * Project: OpenGIS Simple Features Reference Implementation
5 : * Purpose: Implements interface to MapInfo .ID files used as attribute
6 : * indexes.
7 : * Author: Frank Warmerdam, warmerdam@pobox.com
8 : *
9 : ******************************************************************************
10 : * Copyright (c) 2003, Frank Warmerdam
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_attrind.h"
32 : #include "mitab/mitab_priv.h"
33 : #include "cpl_minixml.h"
34 :
35 : CPL_CVSID("$Id: ogr_miattrind.cpp 14048 2008-03-20 18:47:21Z rouault $");
36 :
37 : /************************************************************************/
38 : /* OGRMIAttrIndex */
39 : /* */
40 : /* MapInfo .ID implementation of access to one fields */
41 : /* indexing. */
42 : /************************************************************************/
43 :
44 : class OGRMILayerAttrIndex;
45 :
46 : class OGRMIAttrIndex : public OGRAttrIndex
47 : {
48 : public:
49 : int iIndex;
50 : TABINDFile *poINDFile;
51 : OGRMILayerAttrIndex *poLIndex;
52 : OGRFieldDefn *poFldDefn;
53 :
54 : int iField;
55 :
56 : OGRMIAttrIndex( OGRMILayerAttrIndex *, int iIndex, int iField);
57 : ~OGRMIAttrIndex();
58 :
59 : GByte *BuildKey( OGRField *psKey );
60 : long GetFirstMatch( OGRField *psKey );
61 : long *GetAllMatches( OGRField *psKey );
62 :
63 : OGRErr AddEntry( OGRField *psKey, long nFID );
64 : OGRErr RemoveEntry( OGRField *psKey, long nFID );
65 :
66 : OGRErr Clear();
67 : };
68 :
69 : /************************************************************************/
70 : /* ==================================================================== */
71 : /* OGRMILayerAttrIndex */
72 : /* */
73 : /* MapInfo .ID specific implementation of a layer attribute */
74 : /* index. */
75 : /* ==================================================================== */
76 : /************************************************************************/
77 :
78 : class OGRMILayerAttrIndex : public OGRLayerAttrIndex
79 : {
80 : public:
81 : TABINDFile *poINDFile;
82 :
83 : int nIndexCount;
84 : OGRMIAttrIndex **papoIndexList;
85 :
86 : char *pszMetadataFilename;
87 : char *pszMIINDFilename;
88 :
89 : OGRMILayerAttrIndex();
90 : virtual ~OGRMILayerAttrIndex();
91 :
92 : /* base class virtual methods */
93 : OGRErr Initialize( const char *pszIndexPath, OGRLayer * );
94 : OGRErr CreateIndex( int iField );
95 : OGRErr DropIndex( int iField );
96 : OGRErr IndexAllFeatures( int iField = -1 );
97 :
98 : OGRErr AddToIndex( OGRFeature *poFeature, int iField = -1 );
99 : OGRErr RemoveFromIndex( OGRFeature *poFeature );
100 :
101 : OGRAttrIndex *GetFieldIndex( int iField );
102 :
103 : /* custom to OGRMILayerAttrIndex */
104 : OGRErr SaveConfigToXML();
105 : OGRErr LoadConfigFromXML();
106 : void AddAttrInd( int iField, int iINDIndex );
107 :
108 9 : OGRLayer *GetLayer() { return poLayer; }
109 : };
110 :
111 : /************************************************************************/
112 : /* OGRMILayerAttrIndex() */
113 : /************************************************************************/
114 :
115 914 : OGRMILayerAttrIndex::OGRMILayerAttrIndex()
116 :
117 : {
118 914 : poINDFile = NULL;
119 914 : nIndexCount = 0;
120 914 : papoIndexList = NULL;
121 914 : }
122 :
123 : /************************************************************************/
124 : /* ~OGRMILayerAttrIndex() */
125 : /************************************************************************/
126 :
127 1828 : OGRMILayerAttrIndex::~OGRMILayerAttrIndex()
128 :
129 : {
130 914 : if( poINDFile != NULL )
131 : {
132 7 : poINDFile->Close();
133 7 : delete poINDFile;
134 7 : poINDFile = NULL;
135 : }
136 :
137 921 : for( int i = 0; i < nIndexCount; i++ )
138 7 : delete papoIndexList[i];
139 914 : CPLFree( papoIndexList );
140 :
141 914 : CPLFree( pszMIINDFilename );
142 914 : CPLFree( pszMetadataFilename );
143 1828 : }
144 :
145 : /************************************************************************/
146 : /* Initialize() */
147 : /************************************************************************/
148 :
149 914 : OGRErr OGRMILayerAttrIndex::Initialize( const char *pszIndexPathIn,
150 : OGRLayer *poLayerIn )
151 :
152 : {
153 914 : if( poLayerIn == poLayer )
154 0 : return OGRERR_NONE;
155 :
156 : /* -------------------------------------------------------------------- */
157 : /* Capture input information and form static pathnames. */
158 : /* -------------------------------------------------------------------- */
159 914 : poLayer = poLayerIn;
160 :
161 914 : pszIndexPath = CPLStrdup( pszIndexPathIn );
162 :
163 : pszMetadataFilename = CPLStrdup(
164 914 : CPLResetExtension( pszIndexPathIn, "idm" ) );
165 :
166 914 : pszMIINDFilename = CPLStrdup(CPLResetExtension( pszIndexPathIn, "ind" ));
167 :
168 : /* -------------------------------------------------------------------- */
169 : /* If a metadata file already exists, load it. */
170 : /* -------------------------------------------------------------------- */
171 : OGRErr eErr;
172 : VSIStatBuf sStat;
173 :
174 914 : if( VSIStat( pszMetadataFilename, &sStat ) == 0 )
175 : {
176 6 : eErr = LoadConfigFromXML();
177 6 : if( eErr != OGRERR_NONE )
178 0 : return eErr;
179 : }
180 :
181 914 : return OGRERR_NONE;
182 : }
183 :
184 : /************************************************************************/
185 : /* LoadConfigFromXML() */
186 : /************************************************************************/
187 :
188 6 : OGRErr OGRMILayerAttrIndex::LoadConfigFromXML()
189 :
190 : {
191 : FILE *fp;
192 : int nXMLSize;
193 : char *pszRawXML;
194 :
195 : CPLAssert( poINDFile == NULL );
196 :
197 : /* -------------------------------------------------------------------- */
198 : /* Read the XML file. */
199 : /* -------------------------------------------------------------------- */
200 6 : fp = VSIFOpen( pszMetadataFilename, "rb" );
201 6 : if( fp == NULL )
202 0 : return OGRERR_NONE;
203 :
204 6 : VSIFSeek( fp, 0, SEEK_END );
205 6 : nXMLSize = VSIFTell( fp );
206 6 : VSIFSeek( fp, 0, SEEK_SET );
207 :
208 6 : pszRawXML = (char *) CPLMalloc(nXMLSize+1);
209 6 : pszRawXML[nXMLSize] = '\0';
210 6 : VSIFRead( pszRawXML, nXMLSize, 1, fp );
211 :
212 6 : VSIFClose( fp );
213 :
214 : /* -------------------------------------------------------------------- */
215 : /* Parse the XML. */
216 : /* -------------------------------------------------------------------- */
217 6 : CPLXMLNode *psRoot = CPLParseXMLString( pszRawXML );
218 6 : CPLFree( pszRawXML );
219 :
220 6 : if( psRoot == NULL )
221 0 : return OGRERR_FAILURE;
222 :
223 : /* -------------------------------------------------------------------- */
224 : /* Open the index file. */
225 : /* -------------------------------------------------------------------- */
226 6 : poINDFile = new TABINDFile();
227 :
228 : /* NOTE: Replaced r+ with r according to explanation in Ticket #1620.
229 : * This change has to be observed if it doesn't cause any
230 : * problems in future. (mloskot)
231 : */
232 6 : if( poINDFile->Open( pszMetadataFilename, "r" ) != 0 )
233 : {
234 0 : CPLDestroyXMLNode( psRoot );
235 : CPLError( CE_Failure, CPLE_OpenFailed,
236 : "Failed to open index file %s.",
237 0 : pszMIINDFilename );
238 0 : return OGRERR_FAILURE;
239 : }
240 :
241 : /* -------------------------------------------------------------------- */
242 : /* Process each attrindex. */
243 : /* -------------------------------------------------------------------- */
244 : CPLXMLNode *psAttrIndex;
245 :
246 19 : for( psAttrIndex = psRoot->psChild;
247 : psAttrIndex != NULL;
248 : psAttrIndex = psAttrIndex->psNext )
249 : {
250 : int iField, iIndexIndex;
251 :
252 13 : if( psAttrIndex->eType != CXT_Element
253 : || !EQUAL(psAttrIndex->pszValue,"OGRMIAttrIndex") )
254 6 : continue;
255 :
256 7 : iField = atoi(CPLGetXMLValue(psAttrIndex,"FieldIndex","-1"));
257 7 : iIndexIndex = atoi(CPLGetXMLValue(psAttrIndex,"IndexIndex","-1"));
258 :
259 7 : if( iField == -1 || iIndexIndex == -1 )
260 : {
261 : CPLError( CE_Warning, CPLE_AppDefined,
262 0 : "Skipping corrupt OGRMIAttrIndex entry." );
263 0 : continue;
264 : }
265 :
266 7 : AddAttrInd( iField, iIndexIndex );
267 : }
268 :
269 6 : CPLDestroyXMLNode( psRoot );
270 :
271 : CPLDebug( "OGR", "Restored %d field indexes for layer %s from %s on %s.",
272 6 : nIndexCount, poLayer->GetLayerDefn()->GetName(),
273 12 : pszMetadataFilename, pszMIINDFilename );
274 :
275 6 : return OGRERR_NONE;
276 : }
277 :
278 : /************************************************************************/
279 : /* SaveConfigToXML() */
280 : /************************************************************************/
281 :
282 3 : OGRErr OGRMILayerAttrIndex::SaveConfigToXML()
283 :
284 : {
285 3 : if( nIndexCount == 0 )
286 0 : return OGRERR_NONE;
287 :
288 : /* -------------------------------------------------------------------- */
289 : /* Create the XML tree corresponding to this layer. */
290 : /* -------------------------------------------------------------------- */
291 : CPLXMLNode *psRoot;
292 :
293 3 : psRoot = CPLCreateXMLNode( NULL, CXT_Element, "OGRMILayerAttrIndex" );
294 :
295 : CPLCreateXMLElementAndValue( psRoot, "MIIDFilename",
296 3 : CPLGetFilename( pszMIINDFilename ) );
297 :
298 7 : for( int i = 0; i < nIndexCount; i++ )
299 : {
300 4 : OGRMIAttrIndex *poAI = papoIndexList[i];
301 : CPLXMLNode *psIndex;
302 :
303 4 : psIndex = CPLCreateXMLNode( psRoot, CXT_Element, "OGRMIAttrIndex" );
304 :
305 : CPLCreateXMLElementAndValue( psIndex, "FieldIndex",
306 4 : CPLSPrintf( "%d", poAI->iField ) );
307 :
308 : CPLCreateXMLElementAndValue( psIndex, "FieldName",
309 4 : poLayer->GetLayerDefn()->GetFieldDefn(poAI->iField)->GetNameRef() );
310 :
311 :
312 : CPLCreateXMLElementAndValue( psIndex, "IndexIndex",
313 4 : CPLSPrintf( "%d", poAI->iIndex ) );
314 : }
315 :
316 : /* -------------------------------------------------------------------- */
317 : /* Save it. */
318 : /* -------------------------------------------------------------------- */
319 3 : char *pszRawXML = CPLSerializeXMLTree( psRoot );
320 : FILE *fp;
321 :
322 3 : CPLDestroyXMLNode( psRoot );
323 :
324 3 : fp = VSIFOpen( pszMetadataFilename, "wb" );
325 3 : if( fp == NULL )
326 : {
327 : CPLError( CE_Failure, CPLE_OpenFailed,
328 : "Failed to pen `%s' for write.",
329 0 : pszMetadataFilename );
330 0 : CPLFree( pszRawXML );
331 0 : return OGRERR_FAILURE;
332 : }
333 :
334 3 : VSIFWrite( pszRawXML, 1, strlen(pszRawXML), fp );
335 3 : VSIFClose( fp );
336 :
337 3 : CPLFree( pszRawXML );
338 :
339 3 : return OGRERR_NONE;
340 : }
341 :
342 : /************************************************************************/
343 : /* IndexAllFeatures() */
344 : /************************************************************************/
345 :
346 2 : OGRErr OGRMILayerAttrIndex::IndexAllFeatures( int iField )
347 :
348 : {
349 : OGRFeature *poFeature;
350 :
351 2 : poLayer->ResetReading();
352 :
353 2 : while( (poFeature = poLayer->GetNextFeature()) != NULL )
354 : {
355 40 : OGRErr eErr = AddToIndex( poFeature, iField );
356 :
357 40 : delete poFeature;
358 :
359 40 : if( eErr != CE_None )
360 0 : return eErr;
361 : }
362 :
363 2 : poLayer->ResetReading();
364 :
365 2 : return OGRERR_NONE;
366 : }
367 :
368 : /************************************************************************/
369 : /* CreateIndex() */
370 : /* */
371 : /* Create an index corresponding to the indicated field, but do */
372 : /* not populate it. Use IndexAllFeatures() for that. */
373 : /************************************************************************/
374 :
375 2 : OGRErr OGRMILayerAttrIndex::CreateIndex( int iField )
376 :
377 : {
378 : /* -------------------------------------------------------------------- */
379 : /* Do we have an open .ID file yet? If not, create it now. */
380 : /* -------------------------------------------------------------------- */
381 2 : if( poINDFile == NULL )
382 : {
383 1 : poINDFile = new TABINDFile();
384 1 : if( poINDFile->Open( pszMIINDFilename, "w+" ) != 0 )
385 : {
386 0 : delete poINDFile;
387 0 : poINDFile = NULL;
388 :
389 : CPLError( CE_Failure, CPLE_OpenFailed,
390 : "Failed to create %s.",
391 0 : pszMIINDFilename );
392 0 : return OGRERR_FAILURE;
393 : }
394 : }
395 :
396 : /* -------------------------------------------------------------------- */
397 : /* Do we have this field indexed already? */
398 : /* -------------------------------------------------------------------- */
399 : int i;
400 2 : OGRFieldDefn *poFldDefn=poLayer->GetLayerDefn()->GetFieldDefn(iField);
401 :
402 3 : for( i = 0; i < nIndexCount; i++ )
403 : {
404 1 : if( papoIndexList[i]->iField == iField )
405 : {
406 : CPLError( CE_Failure, CPLE_AppDefined,
407 : "It seems we already have an index for field %d/%s\n"
408 : "of layer %s.",
409 : iField, poFldDefn->GetNameRef(),
410 0 : poLayer->GetLayerDefn()->GetName() );
411 0 : return OGRERR_FAILURE;
412 : }
413 : }
414 :
415 : /* -------------------------------------------------------------------- */
416 : /* What is the corresponding field type in TAB? Note that we */
417 : /* don't allow indexing of any of the list types. */
418 : /* -------------------------------------------------------------------- */
419 : TABFieldType eTABFT;
420 2 : int nFieldWidth = 0;
421 :
422 2 : switch( poFldDefn->GetType() )
423 : {
424 : case OFTInteger:
425 0 : eTABFT = TABFInteger;
426 0 : break;
427 :
428 : case OFTReal:
429 1 : eTABFT = TABFFloat;
430 1 : break;
431 :
432 : case OFTString:
433 1 : eTABFT = TABFChar;
434 1 : if( poFldDefn->GetWidth() > 0 )
435 1 : nFieldWidth = poFldDefn->GetWidth();
436 : else
437 0 : nFieldWidth = 64;
438 1 : break;
439 :
440 : default:
441 : CPLError( CE_Failure, CPLE_AppDefined,
442 : "Indexing not support for the field type of field %s.",
443 0 : poFldDefn->GetNameRef() );
444 0 : return OGRERR_FAILURE;
445 : }
446 :
447 : /* -------------------------------------------------------------------- */
448 : /* Create the index. */
449 : /* -------------------------------------------------------------------- */
450 : int iINDIndex;
451 :
452 2 : iINDIndex = poINDFile->CreateIndex( eTABFT, nFieldWidth );
453 :
454 : // CreateIndex() reports it's own errors.
455 2 : if( iINDIndex < 0 )
456 0 : return OGRERR_FAILURE;
457 :
458 2 : AddAttrInd( iField, iINDIndex );
459 :
460 : /* -------------------------------------------------------------------- */
461 : /* Save the new configuration. */
462 : /* -------------------------------------------------------------------- */
463 2 : return SaveConfigToXML();
464 : }
465 :
466 : /************************************************************************/
467 : /* DropIndex() */
468 : /* */
469 : /* For now we don't have any capability to remove index data */
470 : /* from the MapInfo index file, so we just limit ourselves to */
471 : /* ignoring it from now on. */
472 : /************************************************************************/
473 :
474 2 : OGRErr OGRMILayerAttrIndex::DropIndex( int iField )
475 :
476 : {
477 : /* -------------------------------------------------------------------- */
478 : /* Do we have this field indexed already? */
479 : /* -------------------------------------------------------------------- */
480 : int i;
481 2 : OGRFieldDefn *poFldDefn=poLayer->GetLayerDefn()->GetFieldDefn(iField);
482 :
483 2 : for( i = 0; i < nIndexCount; i++ )
484 : {
485 2 : if( papoIndexList[i]->iField == iField )
486 2 : break;
487 :
488 : }
489 :
490 2 : if( i == nIndexCount )
491 : {
492 : CPLError( CE_Failure, CPLE_AppDefined,
493 : "DROP INDEX on field (%s) that doesn't have an index.",
494 0 : poFldDefn->GetNameRef() );
495 0 : return OGRERR_FAILURE;
496 : }
497 :
498 : /* -------------------------------------------------------------------- */
499 : /* Remove from the list. */
500 : /* -------------------------------------------------------------------- */
501 2 : OGRMIAttrIndex *poAI = papoIndexList[i];
502 :
503 : memmove( papoIndexList + i, papoIndexList + i + 1,
504 2 : sizeof(void*) * (nIndexCount - i - 1) );
505 :
506 2 : delete poAI;
507 :
508 2 : nIndexCount--;
509 :
510 : /* -------------------------------------------------------------------- */
511 : /* Save the new configuration, or if there is nothing left try */
512 : /* to clean up the index files. */
513 : /* -------------------------------------------------------------------- */
514 2 : if( nIndexCount > 0 )
515 1 : return SaveConfigToXML();
516 : else
517 : {
518 1 : VSIUnlink( pszMetadataFilename );
519 1 : VSIUnlink( pszMIINDFilename );
520 :
521 1 : return OGRERR_NONE;
522 : }
523 : }
524 :
525 : /************************************************************************/
526 : /* AddAttrInd() */
527 : /************************************************************************/
528 :
529 9 : void OGRMILayerAttrIndex::AddAttrInd( int iField, int iINDIndex )
530 :
531 : {
532 9 : OGRMIAttrIndex *poAttrInd = new OGRMIAttrIndex( this, iINDIndex, iField);
533 :
534 9 : nIndexCount++;
535 : papoIndexList = (OGRMIAttrIndex **)
536 9 : CPLRealloc(papoIndexList, sizeof(void*) * nIndexCount);
537 :
538 9 : papoIndexList[nIndexCount-1] = poAttrInd;
539 9 : }
540 :
541 : /************************************************************************/
542 : /* GetFieldAttrIndex() */
543 : /************************************************************************/
544 :
545 73 : OGRAttrIndex *OGRMILayerAttrIndex::GetFieldIndex( int iField )
546 :
547 : {
548 80 : for( int i = 0; i < nIndexCount; i++ )
549 : {
550 17 : if( papoIndexList[i]->iField == iField )
551 10 : return papoIndexList[i];
552 : }
553 :
554 63 : return NULL;
555 : }
556 :
557 : /************************************************************************/
558 : /* AddToIndex() */
559 : /************************************************************************/
560 :
561 40 : OGRErr OGRMILayerAttrIndex::AddToIndex( OGRFeature *poFeature,
562 : int iTargetField )
563 :
564 : {
565 40 : OGRErr eErr = OGRERR_NONE;
566 :
567 40 : if( poFeature->GetFID() == OGRNullFID )
568 : {
569 : CPLError( CE_Failure, CPLE_AppDefined,
570 0 : "Attempt to index feature with no FID." );
571 0 : return OGRERR_FAILURE;
572 : }
573 :
574 100 : for( int i = 0; i < nIndexCount && eErr == OGRERR_NONE; i++ )
575 : {
576 60 : int iField = papoIndexList[i]->iField;
577 :
578 60 : if( iTargetField != -1 && iTargetField != iField )
579 20 : continue;
580 :
581 40 : if( !poFeature->IsFieldSet( iField ) )
582 0 : continue;
583 :
584 : eErr =
585 120 : papoIndexList[i]->AddEntry( poFeature->GetRawFieldRef( iField ),
586 160 : poFeature->GetFID() );
587 : }
588 :
589 40 : return eErr;
590 : }
591 :
592 : /************************************************************************/
593 : /* RemoveFromIndex() */
594 : /************************************************************************/
595 :
596 0 : OGRErr OGRMILayerAttrIndex::RemoveFromIndex( OGRFeature * /*poFeature*/ )
597 :
598 : {
599 0 : return OGRERR_UNSUPPORTED_OPERATION;
600 : }
601 :
602 : /************************************************************************/
603 : /* OGRCreateDefaultLayerIndex() */
604 : /************************************************************************/
605 :
606 914 : OGRLayerAttrIndex *OGRCreateDefaultLayerIndex()
607 :
608 : {
609 914 : return new OGRMILayerAttrIndex();
610 : }
611 :
612 : /************************************************************************/
613 : /* ==================================================================== */
614 : /* OGRMIAttrIndex */
615 : /* ==================================================================== */
616 : /************************************************************************/
617 :
618 : /* class declared at top of file */
619 :
620 : /************************************************************************/
621 : /* OGRMIAttrIndex() */
622 : /************************************************************************/
623 :
624 9 : OGRMIAttrIndex::OGRMIAttrIndex( OGRMILayerAttrIndex *poLayerIndex,
625 9 : int iIndexIn, int iFieldIn )
626 :
627 : {
628 9 : iIndex = iIndexIn;
629 9 : iField = iFieldIn;
630 9 : poLIndex = poLayerIndex;
631 9 : poINDFile = poLayerIndex->poINDFile;
632 :
633 9 : poFldDefn = poLayerIndex->GetLayer()->GetLayerDefn()->GetFieldDefn(iField);
634 9 : }
635 :
636 : /************************************************************************/
637 : /* ~OGRMIAttrIndex() */
638 : /************************************************************************/
639 :
640 18 : OGRMIAttrIndex::~OGRMIAttrIndex()
641 : {
642 18 : }
643 :
644 : /************************************************************************/
645 : /* AddEntry() */
646 : /************************************************************************/
647 :
648 40 : OGRErr OGRMIAttrIndex::AddEntry( OGRField *psKey, long nFID )
649 :
650 : {
651 40 : GByte *pabyKey = BuildKey( psKey );
652 :
653 40 : if( psKey == NULL )
654 0 : return OGRERR_FAILURE;
655 :
656 40 : if( poINDFile->AddEntry( iIndex, pabyKey, nFID+1 ) != 0 )
657 0 : return OGRERR_FAILURE;
658 : else
659 40 : return OGRERR_NONE;
660 : }
661 :
662 : /************************************************************************/
663 : /* RemoveEntry() */
664 : /************************************************************************/
665 :
666 0 : OGRErr OGRMIAttrIndex::RemoveEntry( OGRField * /*psKey*/, long /*nFID*/ )
667 :
668 : {
669 0 : return OGRERR_UNSUPPORTED_OPERATION;
670 : }
671 :
672 : /************************************************************************/
673 : /* BuildKey() */
674 : /************************************************************************/
675 :
676 50 : GByte *OGRMIAttrIndex::BuildKey( OGRField *psKey )
677 :
678 : {
679 50 : switch( poFldDefn->GetType() )
680 : {
681 : case OFTInteger:
682 2 : return poINDFile->BuildKey( iIndex, psKey->Integer );
683 : break;
684 :
685 : case OFTReal:
686 27 : return poINDFile->BuildKey( iIndex, psKey->Real );
687 : break;
688 :
689 : case OFTString:
690 21 : return poINDFile->BuildKey( iIndex, psKey->String );
691 : break;
692 :
693 : default:
694 : CPLAssert( FALSE );
695 :
696 0 : return NULL;
697 : }
698 : }
699 :
700 : /************************************************************************/
701 : /* GetFirstMatch() */
702 : /************************************************************************/
703 :
704 0 : long OGRMIAttrIndex::GetFirstMatch( OGRField *psKey )
705 :
706 : {
707 0 : GByte *pabyKey = BuildKey( psKey );
708 : long nFID;
709 :
710 0 : nFID = poINDFile->FindFirst( iIndex, pabyKey );
711 0 : if( nFID < 1 )
712 0 : return OGRNullFID;
713 : else
714 0 : return nFID - 1;
715 : }
716 :
717 : /************************************************************************/
718 : /* GetAllMatches() */
719 : /************************************************************************/
720 :
721 10 : long *OGRMIAttrIndex::GetAllMatches( OGRField *psKey )
722 :
723 : {
724 10 : GByte *pabyKey = BuildKey( psKey );
725 10 : long *panFIDList = NULL, nFID;
726 10 : int nFIDCount=0, nFIDMax=2;
727 :
728 10 : panFIDList = (long *) CPLMalloc(sizeof(long) * 2);
729 :
730 10 : nFID = poINDFile->FindFirst( iIndex, pabyKey );
731 30 : while( nFID > 0 )
732 : {
733 10 : if( nFIDCount >= nFIDMax-1 )
734 : {
735 0 : nFIDMax = nFIDMax * 2 + 10;
736 0 : panFIDList = (long *) CPLRealloc(panFIDList, sizeof(long)*nFIDMax);
737 : }
738 10 : panFIDList[nFIDCount++] = nFID - 1;
739 :
740 10 : nFID = poINDFile->FindNext( iIndex, pabyKey );
741 : }
742 :
743 10 : panFIDList[nFIDCount] = OGRNullFID;
744 :
745 10 : return panFIDList;
746 : }
747 :
748 : /************************************************************************/
749 : /* Clear() */
750 : /************************************************************************/
751 :
752 0 : OGRErr OGRMIAttrIndex::Clear()
753 :
754 : {
755 0 : return OGRERR_UNSUPPORTED_OPERATION;
756 : }
|