📄 mitab_indfile.cpp
字号:
{
CPLError(CE_Failure, CPLE_FileIO,
"Invalid number of indexes (%d) in file %s",
m_numIndexes, m_pszFname);
delete poHeaderBlock;
return -1;
}
/*-----------------------------------------------------------------
* Alloc and init the array of index root nodes.
*----------------------------------------------------------------*/
m_papoIndexRootNodes = (TABINDNode**)CPLCalloc(m_numIndexes,
sizeof(TABINDNode*));
m_papbyKeyBuffers = (GByte **)CPLCalloc(m_numIndexes, sizeof(GByte*));
/* First index def. starts at byte 48 */
poHeaderBlock->GotoByteInBlock(48);
for(int iIndex=0; iIndex<m_numIndexes; iIndex++)
{
/*-------------------------------------------------------------
* Read next index definition
*------------------------------------------------------------*/
GInt32 nRootNodePtr = poHeaderBlock->ReadInt32();
poHeaderBlock->ReadInt16(); // skip... max. num of entries per node
int nTreeDepth = poHeaderBlock->ReadByte();
int nKeyLength = poHeaderBlock->ReadByte();
poHeaderBlock->GotoByteRel(8); // skip next 8 bytes;
/*-------------------------------------------------------------
* And init root node for this index.
* Note that if nRootNodePtr==0 then this means that the
* corresponding index does not exist (i.e. has been deleted?)
* so we simply do not allocate the root node in this case.
* An error will be produced if the user tries to access this index
* later during execution.
*------------------------------------------------------------*/
if (nRootNodePtr > 0)
{
m_papoIndexRootNodes[iIndex] = new TABINDNode(m_eAccessMode);
if (m_papoIndexRootNodes[iIndex]->InitNode(m_fp, nRootNodePtr,
nKeyLength, nTreeDepth,
FALSE,
&m_oBlockManager)!= 0)
{
// CPLError has already been called
delete poHeaderBlock;
return -1;
}
// Alloc a temporary key buffer for this index.
// This buffer will be used by the BuildKey() method
m_papbyKeyBuffers[iIndex] = (GByte *)CPLCalloc(nKeyLength+1,
sizeof(GByte));
}
else
{
m_papoIndexRootNodes[iIndex] = NULL;
m_papbyKeyBuffers[iIndex] = NULL;
}
}
/*-----------------------------------------------------------------
* OK, we won't need the header block any more... free it.
*----------------------------------------------------------------*/
delete poHeaderBlock;
return 0;
}
/**********************************************************************
* TABINDFile::WriteHeader()
*
* (private method)
* Write the header block based on current index information.
*
* Returns 0 on success, -1 on error.
**********************************************************************/
int TABINDFile::WriteHeader()
{
CPLAssert(m_fp);
CPLAssert(m_eAccessMode == TABWrite || m_eAccessMode == TABReadWrite);
/*-----------------------------------------------------------------
* Write the 48 bytes of file header
*----------------------------------------------------------------*/
TABRawBinBlock *poHeaderBlock;
poHeaderBlock = new TABRawBinBlock(m_eAccessMode, TRUE);
poHeaderBlock->InitNewBlock(m_fp, 512, 0);
poHeaderBlock->WriteInt32( IND_MAGIC_COOKIE );
poHeaderBlock->WriteInt16( 100 ); // ???
poHeaderBlock->WriteInt16( 512 ); // ???
poHeaderBlock->WriteInt32( 0 ); // ???
poHeaderBlock->WriteInt16( m_numIndexes );
poHeaderBlock->WriteInt16( 0x15e7); // ???
poHeaderBlock->WriteInt16( 10 ); // ???
poHeaderBlock->WriteInt16( 0x611d); // ???
poHeaderBlock->WriteZeros( 28 );
/*-----------------------------------------------------------------
* The first index definition starts at byte 48
*----------------------------------------------------------------*/
for(int iIndex=0; iIndex<m_numIndexes; iIndex++)
{
TABINDNode *poRootNode = m_papoIndexRootNodes[iIndex];
if (poRootNode)
{
/*---------------------------------------------------------
* Write next index definition
*--------------------------------------------------------*/
poHeaderBlock->WriteInt32(poRootNode->GetNodeBlockPtr());
poHeaderBlock->WriteInt16(poRootNode->GetMaxNumEntries());
poHeaderBlock->WriteByte( poRootNode->GetSubTreeDepth());
poHeaderBlock->WriteByte( poRootNode->GetKeyLength());
poHeaderBlock->WriteZeros( 8 );
/*---------------------------------------------------------
* Look for overflow of the SubTreeDepth field (byte)
*--------------------------------------------------------*/
if (poRootNode->GetSubTreeDepth() > 255)
{
CPLError(CE_Failure, CPLE_AssertionFailed,
"Index no %d is too large and will not be useable. "
"(SubTreeDepth = %d, cannot exceed 255).",
iIndex+1, poRootNode->GetSubTreeDepth());
return -1;
}
}
else
{
/*---------------------------------------------------------
* NULL Root Node: This index has likely been deleted
*--------------------------------------------------------*/
poHeaderBlock->WriteZeros( 16 );
}
}
/*-----------------------------------------------------------------
* OK, we won't need the header block any more... write and free it.
*----------------------------------------------------------------*/
if (poHeaderBlock->CommitToFile() != 0)
return -1;
delete poHeaderBlock;
return 0;
}
/**********************************************************************
* TABINDFile::ValidateIndexNo()
*
* Private method to validate the index no parameter of some methods...
* returns 0 if index no. is OK, or produces an error ands returns -1
* if index no is not valid.
**********************************************************************/
int TABINDFile::ValidateIndexNo(int nIndexNumber)
{
if (m_fp == NULL)
{
CPLError(CE_Failure, CPLE_AssertionFailed,
"TABINDFile: File has not been opened yet!");
return -1;
}
if (nIndexNumber < 1 || nIndexNumber > m_numIndexes ||
m_papoIndexRootNodes == NULL ||
m_papoIndexRootNodes[nIndexNumber-1] == NULL)
{
CPLError(CE_Failure, CPLE_AssertionFailed,
"No field index number %d in %s: Valid range is [1..%d].",
nIndexNumber, m_pszFname, m_numIndexes);
return -1;
}
return 0; // Index seems valid
}
/**********************************************************************
* TABINDFile::SetIndexFieldType()
*
* Sets the field type for the specified index.
* This information will then be used in building the key values, etc.
*
* Returns 0 on success, -1 on error.
**********************************************************************/
int TABINDFile::SetIndexFieldType(int nIndexNumber, TABFieldType eType)
{
if (ValidateIndexNo(nIndexNumber) != 0)
return -1;
return m_papoIndexRootNodes[nIndexNumber-1]->SetFieldType(eType);
}
/**********************************************************************
* TABINDFile::SetIndexUnique()
*
* Indicate that an index's keys are unique. This allows for some
* optimization with read access. By default, an index is treated as if
* its keys could have duplicates.
*
* Returns 0 on success, -1 on error.
**********************************************************************/
int TABINDFile::SetIndexUnique(int nIndexNumber, GBool bUnique/*=TRUE*/)
{
if (ValidateIndexNo(nIndexNumber) != 0)
return -1;
m_papoIndexRootNodes[nIndexNumber-1]->SetUnique(bUnique);
return 0;
}
/**********************************************************************
* TABINDFile::BuildKey()
*
* Encode a field value in the form required to be compared with index
* keys in the specified index.
*
* Note that index numbers are positive values starting at 1.
*
* Returns a reference to an internal buffer that is valid only until the
* next call to BuildKey(). (should not be freed by the caller).
* Returns NULL if field index is invalid.
*
* The first flavour of the function handles integer type of values, this
* corresponds to MapInfo types: integer, smallint, logical and date
**********************************************************************/
GByte *TABINDFile::BuildKey(int nIndexNumber, GInt32 nValue)
{
if (ValidateIndexNo(nIndexNumber) != 0)
return NULL;
int nKeyLength = m_papoIndexRootNodes[nIndexNumber-1]->GetKeyLength();
/*-----------------------------------------------------------------
* Convert all int values to MSB using the right number of bytes
* Note:
* The most significant bit has to be unset for negative values,
* and to be set for positive ones... that's the reverse of what it
* should usually be. Adding 0x80 to the MSB byte will do the job.
*----------------------------------------------------------------*/
switch(nKeyLength)
{
case 1:
m_papbyKeyBuffers[nIndexNumber-1][0] = (GByte)(nValue & 0xff)+0x80;
break;
case 2:
m_papbyKeyBuffers[nIndexNumber-1][0] =
(GByte)(nValue/0x100 & 0xff)+0x80;
m_papbyKeyBuffers[nIndexNumber-1][1] = (GByte)(nValue & 0xff);
break;
case 4:
m_papbyKeyBuffers[nIndexNumber-1][0] =
(GByte)(nValue/0x1000000 &0xff)+0x80;
m_papbyKeyBuffers[nIndexNumber-1][1] = (GByte)(nValue/0x10000 & 0xff);
m_papbyKeyBuffers[nIndexNumber-1][2] = (GByte)(nValue/0x100 &0xff);
m_papbyKeyBuffers[nIndexNumber-1][3] = (GByte)(nValue & 0xff);
break;
default:
CPLError(CE_Failure, CPLE_AssertionFailed,
"BuildKey(): %d bytes integer key length not supported",
nKeyLength);
break;
}
return m_papbyKeyBuffers[nIndexNumber-1];
}
/**********************************************************************
* TABINDFile::BuildKey()
*
* BuildKey() for string fields
**********************************************************************/
GByte *TABINDFile::BuildKey(int nIndexNumber, const char *pszStr)
{
if (ValidateIndexNo(nIndexNumber) != 0 || pszStr == NULL)
return NULL;
int nKeyLength = m_papoIndexRootNodes[nIndexNumber-1]->GetKeyLength();
/*-----------------------------------------------------------------
* Strings keys are all in uppercase, and padded with '\0'
*----------------------------------------------------------------*/
int i=0;
for (i=0; i<nKeyLength && pszStr[i] != '\0'; i++)
{
m_papbyKeyBuffers[nIndexNumber-1][i] = (GByte)toupper(pszStr[i]);
}
/* Pad the end of the buffer with '\0' */
for( ; i<nKeyLength; i++)
{
m_papbyKeyBuffers[nIndexNumber-1][i] = '\0';
}
return m_papbyKeyBuffers[nIndexNumber-1];
}
/**********************************************************************
* TABINDFile::BuildKey()
*
* BuildKey() for float and decimal fields
**********************************************************************/
GByte *TABINDFile::BuildKey(int nIndexNumber, double dValue)
{
if (ValidateIndexNo(nIndexNumber) != 0)
return NULL;
int nKeyLength = m_papoIndexRootNodes[nIndexNumber-1]->GetKeyLength();
CPLAssert(nKeyLength == 8 && sizeof(double) == 8);
/*-----------------------------------------------------------------
* Convert double and decimal values...
* Reverse the sign of the value, and convert to MSB
*----------------------------------------------------------------*/
dValue = -dValue;
#ifndef CPL_MSB
CPL_SWAPDOUBLE(&dValue);
#endif
memcpy(m_papbyKeyBuffers[nIndexNumber-1], (GByte*)(&dValue), nKeyLength);
return m_papbyKeyBuffers[nIndexNumber-1];
}
/**********************************************************************
* TABINDFile::FindFirst()
*
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -