/********************************************************************** * DumpIndFileObjects() * * Read and dump a .IND file **********************************************************************/ static int DumpIndFileObjects(const char *pszFname) { TABINDFile oINDFile; /*--------------------------------------------------------------------- * Try to open source file *--------------------------------------------------------------------*/ if (oINDFile.Open(pszFname, "rb") != 0) { printf("Failed to open %s\n", pszFname); return -1; } // oINDFile.SetIndexFieldType(1,TABFChar); oINDFile.Dump(); /*--------------------------------------------------------------------- * Read/Dump objects until EOF is reached *--------------------------------------------------------------------*/ while ( 0 ) { } /*--------------------------------------------------------------------- * Cleanup and exit. *--------------------------------------------------------------------*/ oINDFile.Close(); return 0; }
GIntBig *OGRMIAttrIndex::GetAllMatches( OGRField *psKey, GIntBig* panFIDList, int* nFIDCount, int* nLength ) { GByte *pabyKey = BuildKey( psKey ); if (panFIDList == nullptr) { panFIDList = static_cast<GIntBig *>(CPLMalloc(sizeof(GIntBig) * 2)); *nFIDCount = 0; *nLength = 2; } GIntBig nFID = poINDFile->FindFirst( iIndex, pabyKey ); while( nFID > 0 ) { if( *nFIDCount >= *nLength-1 ) { *nLength = (*nLength) * 2 + 10; panFIDList = static_cast<GIntBig *>(CPLRealloc(panFIDList, sizeof(GIntBig)* (*nLength))); } panFIDList[(*nFIDCount)++] = nFID - 1; nFID = poINDFile->FindNext( iIndex, pabyKey ); } panFIDList[*nFIDCount] = OGRNullFID; return panFIDList; }
long *OGRMIAttrIndex::GetAllMatches( OGRField *psKey ) { GByte *pabyKey = BuildKey( psKey ); long *panFIDList = NULL, nFID; int nFIDCount=0, nFIDMax=2; panFIDList = (long *) CPLMalloc(sizeof(long) * 2); nFID = poINDFile->FindFirst( iIndex, pabyKey ); while( nFID > 0 ) { if( nFIDCount >= nFIDMax-1 ) { nFIDMax = nFIDMax * 2 + 10; panFIDList = (long *) CPLRealloc(panFIDList, sizeof(long)*nFIDMax); } panFIDList[nFIDCount++] = nFID - 1; nFID = poINDFile->FindNext( iIndex, pabyKey ); } panFIDList[nFIDCount] = OGRNullFID; return panFIDList; }
GByte *OGRMIAttrIndex::BuildKey( OGRField *psKey ) { GByte* ret = nullptr; switch( poFldDefn->GetType() ) { case OFTInteger: ret = poINDFile->BuildKey( iIndex, psKey->Integer ); break; case OFTInteger64: { if( !CPL_INT64_FITS_ON_INT32(psKey->Integer64) ) { CPLError(CE_Warning, CPLE_NotSupported, "64bit integer value passed to OGRMIAttrIndex::BuildKey()"); } ret = poINDFile->BuildKey( iIndex, static_cast<int>(psKey->Integer64) ); break; } case OFTReal: ret = poINDFile->BuildKey( iIndex, psKey->Real ); break; case OFTString: ret = poINDFile->BuildKey( iIndex, psKey->String ); break; default: CPLAssert( false ); break; } return ret; }
GByte *OGRMIAttrIndex::BuildKey( OGRField *psKey ) { switch( poFldDefn->GetType() ) { case OFTInteger: return poINDFile->BuildKey( iIndex, psKey->Integer ); break; case OFTInteger64: { if( !CPL_INT64_FITS_ON_INT32(psKey->Integer64) ) { CPLError(CE_Warning, CPLE_NotSupported, "64bit integer value passed to OGRMIAttrIndex::BuildKey()"); } return poINDFile->BuildKey( iIndex, (int)psKey->Integer64 ); break; } case OFTReal: return poINDFile->BuildKey( iIndex, psKey->Real ); break; case OFTString: return poINDFile->BuildKey( iIndex, psKey->String ); break; default: CPLAssert( FALSE ); return NULL; } }
/********************************************************************** * SearchIndex() * * Search a TAB dataset's .IND file for pszVal in index nIndexNo **********************************************************************/ static int SearchIndex(const char *pszFname, int nIndexNo, const char *pszVal) { TABFile oTABFile; TABINDFile *poINDFile; /*--------------------------------------------------------------------- * Try to open source file *--------------------------------------------------------------------*/ if (oTABFile.Open(pszFname, "rb") != 0) { printf("Failed to open %s as a TABFile.\n", pszFname); return -1; } /*--------------------------------------------------------------------- * Fetch IND file handle *--------------------------------------------------------------------*/ if ((poINDFile = oTABFile.GetINDFileRef()) == NULL) { printf("Dataset %s has no .IND file\n", pszFname); return -1; } /*--------------------------------------------------------------------- * Search the index. * For now we search only 'char' index types!!! *--------------------------------------------------------------------*/ GByte *pKey; int nRecordNo; pKey = poINDFile->BuildKey(nIndexNo, pszVal); nRecordNo = poINDFile->FindFirst(nIndexNo, pKey); if (nRecordNo < 1) { printf("Value '%s' not found in index #%d\n", pszVal, nIndexNo); } else { while(nRecordNo > 0) { printf("Record %d...\n", nRecordNo); nRecordNo = poINDFile->FindNext(nIndexNo, pKey); } } /*--------------------------------------------------------------------- * Cleanup and exit. *--------------------------------------------------------------------*/ oTABFile.Close(); return 0; }
GIntBig OGRMIAttrIndex::GetFirstMatch( OGRField *psKey ) { GByte *pabyKey = BuildKey( psKey ); const GIntBig nFID = poINDFile->FindFirst( iIndex, pabyKey ); if( nFID < 1 ) return OGRNullFID; else return nFID - 1; }
OGRErr OGRMIAttrIndex::AddEntry( OGRField *psKey, long nFID ) { GByte *pabyKey = BuildKey( psKey ); if( psKey == NULL ) return OGRERR_FAILURE; if( poINDFile->AddEntry( iIndex, pabyKey, nFID+1 ) != 0 ) return OGRERR_FAILURE; else return OGRERR_NONE; }
GByte *OGRMIAttrIndex::BuildKey( OGRField *psKey ) { switch( poFldDefn->GetType() ) { case OFTInteger: return poINDFile->BuildKey( iIndex, psKey->Integer ); break; case OFTReal: return poINDFile->BuildKey( iIndex, psKey->Real ); break; case OFTString: return poINDFile->BuildKey( iIndex, psKey->String ); break; default: CPLAssert( FALSE ); return NULL; } }
OGRErr OGRMIAttrIndex::AddEntry( OGRField *psKey, GIntBig nFID ) { if( psKey == nullptr ) return OGRERR_FAILURE; if( nFID >= INT_MAX ) return OGRERR_FAILURE; GByte *pabyKey = BuildKey( psKey ); if( pabyKey == nullptr ) return OGRERR_FAILURE; if( poINDFile->AddEntry( iIndex, pabyKey, static_cast<int>(nFID)+1 ) != 0 ) return OGRERR_FAILURE; else return OGRERR_NONE; }
OGRErr OGRMIAttrIndex::AddEntry( OGRField *psKey, GIntBig nFID ) { if( psKey == NULL ) return OGRERR_FAILURE; if( nFID >= INT_MAX ) return OGRERR_FAILURE; GByte *pabyKey = BuildKey( psKey ); if( pabyKey == NULL ) return OGRERR_FAILURE; if( poINDFile->AddEntry( iIndex, pabyKey, (int)nFID+1 ) != 0 ) return OGRERR_FAILURE; else return OGRERR_NONE; }
OGRErr OGRMILayerAttrIndex::CreateIndex( int iField ) { /* -------------------------------------------------------------------- */ /* Do we have an open .ID file yet? If not, create it now. */ /* -------------------------------------------------------------------- */ if( poINDFile == NULL ) { poINDFile = new TABINDFile(); if( poINDFile->Open( pszMIINDFilename, "w+" ) != 0 ) { delete poINDFile; poINDFile = NULL; CPLError( CE_Failure, CPLE_OpenFailed, "Failed to create %s.", pszMIINDFilename ); return OGRERR_FAILURE; } } /* -------------------------------------------------------------------- */ /* Do we have this field indexed already? */ /* -------------------------------------------------------------------- */ int i; OGRFieldDefn *poFldDefn=poLayer->GetLayerDefn()->GetFieldDefn(iField); for( i = 0; i < nIndexCount; i++ ) { if( papoIndexList[i]->iField == iField ) { CPLError( CE_Failure, CPLE_AppDefined, "It seems we already have an index for field %d/%s\n" "of layer %s.", poFldDefn->GetNameRef(), poLayer->GetLayerDefn()->GetName() ); return OGRERR_FAILURE; } } /* -------------------------------------------------------------------- */ /* What is the corresponding field type in TAB? Note that we */ /* don't allow indexing of any of the list types. */ /* -------------------------------------------------------------------- */ TABFieldType eTABFT; int nFieldWidth = 0; switch( poFldDefn->GetType() ) { case OFTInteger: eTABFT = TABFInteger; break; case OFTReal: eTABFT = TABFFloat; break; case OFTString: eTABFT = TABFChar; if( poFldDefn->GetWidth() > 0 ) nFieldWidth = poFldDefn->GetWidth(); else nFieldWidth = 64; break; default: CPLError( CE_Failure, CPLE_AppDefined, "Indexing not support for the field type of field %s.", poFldDefn->GetNameRef() ); return OGRERR_FAILURE; } /* -------------------------------------------------------------------- */ /* Create the index. */ /* -------------------------------------------------------------------- */ int iINDIndex; iINDIndex = poINDFile->CreateIndex( eTABFT, nFieldWidth ); // CreateIndex() reports it's own errors. if( iINDIndex < 0 ) return OGRERR_FAILURE; AddAttrInd( iField, iINDIndex ); /* -------------------------------------------------------------------- */ /* Save the new configuration. */ /* -------------------------------------------------------------------- */ return SaveConfigToXML(); }
OGRErr OGRMILayerAttrIndex::LoadConfigFromXML() { FILE *fp; int nXMLSize; char *pszRawXML; CPLAssert( poINDFile == NULL ); /* -------------------------------------------------------------------- */ /* Read the XML file. */ /* -------------------------------------------------------------------- */ fp = VSIFOpen( pszMetadataFilename, "rb" ); if( fp == NULL ) return OGRERR_NONE; VSIFSeek( fp, 0, SEEK_END ); nXMLSize = VSIFTell( fp ); VSIFSeek( fp, 0, SEEK_SET ); pszRawXML = (char *) CPLMalloc(nXMLSize+1); pszRawXML[nXMLSize] = '\0'; VSIFRead( pszRawXML, nXMLSize, 1, fp ); VSIFClose( fp ); /* -------------------------------------------------------------------- */ /* Parse the XML. */ /* -------------------------------------------------------------------- */ CPLXMLNode *psRoot = CPLParseXMLString( pszRawXML ); CPLFree( pszRawXML ); if( psRoot == NULL ) return OGRERR_FAILURE; /* -------------------------------------------------------------------- */ /* Open the index file. */ /* -------------------------------------------------------------------- */ poINDFile = new TABINDFile(); if( poINDFile->Open( pszMetadataFilename, "r+" ) != 0 ) { CPLDestroyXMLNode( psRoot ); CPLError( CE_Failure, CPLE_OpenFailed, "Failed to open index file %s.", pszMIINDFilename ); return OGRERR_FAILURE; } /* -------------------------------------------------------------------- */ /* Process each attrindex. */ /* -------------------------------------------------------------------- */ CPLXMLNode *psAttrIndex; for( psAttrIndex = psRoot->psChild; psAttrIndex != NULL; psAttrIndex = psAttrIndex->psNext ) { int iField, iIndexIndex; if( psAttrIndex->eType != CXT_Element || !EQUAL(psAttrIndex->pszValue,"OGRMIAttrIndex") ) continue; iField = atoi(CPLGetXMLValue(psAttrIndex,"FieldIndex","-1")); iIndexIndex = atoi(CPLGetXMLValue(psAttrIndex,"IndexIndex","-1")); if( iField == -1 || iIndexIndex == -1 ) { CPLError( CE_Warning, CPLE_AppDefined, "Skipping corrupt OGRMIAttrIndex entry." ); continue; } AddAttrInd( iField, iIndexIndex ); } CPLDestroyXMLNode( psRoot ); CPLDebug( "OGR", "Restored %d field indexes for layer %s from %s on %s.", nIndexCount, poLayer->GetLayerDefn()->GetName(), pszMetadataFilename, pszMIINDFilename ); return OGRERR_NONE; }
OGRErr OGRMILayerAttrIndex::LoadConfigFromXML(const char* pszRawXML) { /* -------------------------------------------------------------------- */ /* Parse the XML. */ /* -------------------------------------------------------------------- */ CPLXMLNode *psRoot = CPLParseXMLString( pszRawXML ); if( psRoot == nullptr ) return OGRERR_FAILURE; /* -------------------------------------------------------------------- */ /* Open the index file. */ /* -------------------------------------------------------------------- */ poINDFile = new TABINDFile(); if (pszMIINDFilename == nullptr) pszMIINDFilename = CPLStrdup(CPLGetXMLValue(psRoot,"MIIDFilename","")); if( pszMIINDFilename == nullptr ) return OGRERR_FAILURE; /* NOTE: Replaced r+ with r according to explanation in Ticket #1620. * This change has to be observed if it doesn't cause any * problems in future. (mloskot) */ if( poINDFile->Open( pszMIINDFilename, "r" ) != 0 ) { CPLDestroyXMLNode( psRoot ); CPLError( CE_Failure, CPLE_OpenFailed, "Failed to open index file %s.", pszMIINDFilename ); return OGRERR_FAILURE; } /* -------------------------------------------------------------------- */ /* Process each attrindex. */ /* -------------------------------------------------------------------- */ for( CPLXMLNode *psAttrIndex = psRoot->psChild; psAttrIndex != nullptr; psAttrIndex = psAttrIndex->psNext ) { if( psAttrIndex->eType != CXT_Element || !EQUAL(psAttrIndex->pszValue,"OGRMIAttrIndex") ) continue; int iField = atoi(CPLGetXMLValue(psAttrIndex,"FieldIndex","-1")); int iIndexIndex = atoi(CPLGetXMLValue(psAttrIndex,"IndexIndex","-1")); if( iField == -1 || iIndexIndex == -1 ) { CPLError( CE_Warning, CPLE_AppDefined, "Skipping corrupt OGRMIAttrIndex entry." ); continue; } AddAttrInd( iField, iIndexIndex ); } CPLDestroyXMLNode( psRoot ); CPLDebug( "OGR", "Restored %d field indexes for layer %s from %s on %s.", nIndexCount, poLayer->GetLayerDefn()->GetName(), pszMetadataFilename ? pszMetadataFilename : "--unknown--", pszMIINDFilename ); return OGRERR_NONE; }
/********************************************************************** * CreateIndex() * * Create index for specified field in an existing TAB dataset. **********************************************************************/ static int CreateIndex(const char *pszSrcFname, const char *pszField) { IMapInfoFile *poSrcFile = NULL; int nFeatureId, iField; TABFeature *poFeature; TABINDFile *poINDFile; /*--------------------------------------------------------------------- * Try to open source file *--------------------------------------------------------------------*/ if ((poSrcFile = IMapInfoFile::SmartOpen(pszSrcFname)) == NULL) { printf("Failed to open %s\n", pszSrcFname); return -1; } if (poSrcFile->GetFileClass() != TABFC_TABFile) { printf("Indexes cannot be added to this type of TAB datasets\n"); poSrcFile->Close(); delete poSrcFile; return -1; } /*--------------------------------------------------------------------- * Make sure field exists and is not already indexed *--------------------------------------------------------------------*/ OGRFeatureDefn *poDefn = poSrcFile->GetLayerDefn(); if ( poDefn == NULL || (iField = poDefn->GetFieldIndex(pszField)) == -1 || poSrcFile->IsFieldIndexed(iField)) { printf("Cannot create index: field '%s' not found or is already indexed.\n", pszField); poSrcFile->Close(); delete poSrcFile; return -1; } /*--------------------------------------------------------------------- * Things seem OK... open IND file for update * (Note that TABINDFile automagically adjusts file extension) *--------------------------------------------------------------------*/ poINDFile = new TABINDFile; if ( poINDFile->Open(pszSrcFname, "r+", TRUE) != 0 && poINDFile->Open(pszSrcFname, "w", TRUE) != 0) { printf("Unable to create IND file for %s.\n", pszSrcFname); delete poINDFile; poSrcFile->Close(); delete poSrcFile; return -1; } int nNewIndexNo = -1; OGRFieldDefn *poFieldDefn = poDefn->GetFieldDefn(iField); TABFieldType eFieldType = poSrcFile->GetNativeFieldType(iField); if (poFieldDefn == NULL || (nNewIndexNo = poINDFile->CreateIndex(eFieldType, poFieldDefn->GetWidth()) ) < 1) { // Failed... an error has already been reported. delete poINDFile; poSrcFile->Close(); delete poSrcFile; return -1; } printf("Index number %d will be created for field %s...\n\n" "This program does not update the TAB header file (yet!) so you \n" "should edit %s and add 'Index %d' at the end of the definition \n" "of field %s.\n\n", nNewIndexNo, pszField, pszSrcFname, nNewIndexNo, pszField); /*--------------------------------------------------------------------- * Add index entries until we reach EOF *--------------------------------------------------------------------*/ nFeatureId = -1; while ( (nFeatureId = poSrcFile->GetNextFeatureId(nFeatureId)) != -1 ) { poFeature = poSrcFile->GetFeatureRef(nFeatureId); if (poFeature) { GByte *pKey = NULL; switch(eFieldType) { case TABFChar: pKey = poINDFile->BuildKey(nNewIndexNo, poFeature->GetFieldAsString(iField)); break; case TABFInteger: case TABFSmallInt: pKey = poINDFile->BuildKey(nNewIndexNo, poFeature->GetFieldAsInteger(iField)); break; case TABFDecimal: case TABFFloat: case TABFLogical: pKey = poINDFile->BuildKey(nNewIndexNo, poFeature->GetFieldAsDouble(iField)); break; default: case TABFDate: CPLAssert(FALSE); // Unsupported for now. } if (poINDFile->AddEntry(nNewIndexNo, pKey, nFeatureId) != 0) return -1; } else break; // GetFeatureRef() failed: Abort the loop } /*--------------------------------------------------------------------- * Cleanup and exit. *--------------------------------------------------------------------*/ poINDFile->Close(); delete poINDFile; poSrcFile->Close(); delete poSrcFile; MITABFreeCoordSysTable(); return 0; }