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