⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 mitab_indfile.cpp

📁 mitab,读取MapInfo的地图文件
💻 CPP
📖 第 1 页 / 共 5 页
字号:
    {
        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 + -