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