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

📄 mitab_datfile.cpp

📁 mitab,读取MapInfo的地图文件
💻 CPP
📖 第 1 页 / 共 5 页
字号:
    for(i=0; i<m_numFields; i++)
    {
        m_nRecordSize += m_pasFieldDef[i].byLength;
    }

    /*-------------------------------------------------------------
     * Create m_poRecordBlock the size of a data record.
     *------------------------------------------------------------*/
    m_nBlockSize = m_nRecordSize;

    CPLAssert( m_poRecordBlock == NULL );
    m_poRecordBlock = new TABRawBinBlock(m_eAccessMode, FALSE);
    m_poRecordBlock->InitNewBlock(m_fp, m_nBlockSize);
    m_poRecordBlock->SetFirstBlockPtr(m_nFirstRecordPtr);

    /*-------------------------------------------------------------
     * Make sure this init. will be performed only once
     *------------------------------------------------------------*/
    m_bWriteHeaderInitialized = TRUE;

    return 0;
}

/**********************************************************************
 *                   TABDATFile::WriteHeader()
 *
 * Init the header members to be ready to write the header and data records
 * to a newly created data file.
 *
 * Returns 0 on success, -1 on error.
 **********************************************************************/
int  TABDATFile::WriteHeader()
{
    int i;

    if (m_eAccessMode != TABWrite)
    {
        CPLError(CE_Failure, CPLE_NotSupported,
                 "WriteHeader() can be used only with Write access.");
        return -1;
    }

    if (!m_bWriteHeaderInitialized)
        InitWriteHeader();

    /*------------------------------------------------------------
     * Create a single block that will be used to generate the whole header.
     *-----------------------------------------------------------*/
    if (m_poHeaderBlock == NULL)
        m_poHeaderBlock = new TABRawBinBlock(m_eAccessMode, TRUE);
    m_poHeaderBlock->InitNewBlock(m_fp, m_nFirstRecordPtr, 0);

    /*------------------------------------------------------------
     * First 32 bytes: main header block
     *-----------------------------------------------------------*/
    m_poHeaderBlock->WriteByte(0x03);  // Table type ??? 0x03

    // __TODO__ Write the correct update date value
    m_poHeaderBlock->WriteByte(99);    // Last update year
    m_poHeaderBlock->WriteByte(9);     // Last update month
    m_poHeaderBlock->WriteByte(9);     // Last update day

    m_poHeaderBlock->WriteInt32(m_numRecords);
    m_poHeaderBlock->WriteInt16(m_nFirstRecordPtr);
    m_poHeaderBlock->WriteInt16(m_nRecordSize);

    m_poHeaderBlock->WriteZeros(20);    // Pad rest with zeros

    /*-------------------------------------------------------------
     * Field definitions follow.  Each field def is 32 bytes.
     *------------------------------------------------------------*/
    for(i=0; i<m_numFields; i++)
    {
        m_poHeaderBlock->WriteBytes(11, (GByte*)m_pasFieldDef[i].szName);
        m_poHeaderBlock->WriteByte(m_pasFieldDef[i].cType);

        m_poHeaderBlock->WriteInt32(0);       // Skip Bytes 12-15

        m_poHeaderBlock->WriteByte(m_pasFieldDef[i].byLength);
        m_poHeaderBlock->WriteByte(m_pasFieldDef[i].byDecimals);

        m_poHeaderBlock->WriteZeros(14);    // Pad rest with zeros
    }

    /*-------------------------------------------------------------
     * Header ends with a 0x0d character.
     *------------------------------------------------------------*/
    m_poHeaderBlock->WriteByte(0x0d);

    /*-------------------------------------------------------------
     * Write the block to the file and return.
     *------------------------------------------------------------*/
    return m_poHeaderBlock->CommitToFile();
}



/**********************************************************************
 *                   TABDATFile::GetNumFields()
 *
 * Return the number of fields in this table.
 *
 * Returns a value >= 0 on success, -1 on error.
 **********************************************************************/
int  TABDATFile::GetNumFields()
{
    return m_numFields;
}

/**********************************************************************
 *                   TABDATFile::GetNumRecords()
 *
 * Return the number of records in this table.
 *
 * Returns a value >= 0 on success, -1 on error.
 **********************************************************************/
int  TABDATFile::GetNumRecords()
{
    return m_numRecords;
}

/**********************************************************************
 *                   TABDATFile::GetRecordBlock()
 *
 * Return a TABRawBinBlock reference positioned at the beginning of the
 * specified record and ready to read (or write) field values from/to it.
 * In read access, the returned block is guaranteed to contain at least one
 * full record of data, and in write access, it is at least big enough to
 * hold one full record.
 * 
 * Note that record ids are positive and start at 1.
 *
 * In Write access, CommitRecordToFile() MUST be called after the
 * data items have been written to the record, otherwise the record 
 * will never make it to the file.
 *
 * Returns a reference to the TABRawBinBlock on success or NULL on error.
 * The returned pointer is a reference to a block object owned by this 
 * TABDATFile object and should not be freed by the caller.
 **********************************************************************/
TABRawBinBlock *TABDATFile::GetRecordBlock(int nRecordId)
{
    m_bCurRecordDeletedFlag = FALSE;

    if (m_eAccessMode == TABRead)
    {
        /*-------------------------------------------------------------
         * READ ACCESS
         *------------------------------------------------------------*/
        int nFileOffset;

        nFileOffset = m_nFirstRecordPtr+(nRecordId-1)*m_nRecordSize;

        /*-------------------------------------------------------------
         * Move record block pointer to the right location
         *------------------------------------------------------------*/
        if ( m_poRecordBlock == NULL || 
             nRecordId < 1 || nRecordId > m_numRecords ||
             m_poRecordBlock->GotoByteInFile(nFileOffset) != 0 )
        {
            CPLError(CE_Failure, CPLE_FileIO,
                     "Failed reading .DAT record block for record #%d in %s",
                     nRecordId, m_pszFname);
            return NULL;
        }

        /*-------------------------------------------------------------
         * The first char of the record is a ' ' for an active record, or
         * '*' for a deleted one.
         * In the case of a deleted record, we simply return default
         * values for each attribute... this is what MapInfo seems to do
         * when it takes a .TAB with deleted records and exports it to .MIF
         *------------------------------------------------------------*/
        if (m_poRecordBlock->ReadByte() != ' ')
        {
            m_bCurRecordDeletedFlag = TRUE;
        }
    }
    else if (m_eAccessMode == TABWrite && nRecordId > 0)
    {
        /*-------------------------------------------------------------
         * WRITE ACCESS
         *------------------------------------------------------------*/
        int nFileOffset;

        /*-------------------------------------------------------------
         * Before writing the first record, we must generate the file 
         * header.  We will also initialize class members such as record
         * size, etc. and will create m_poRecordBlock.
         *------------------------------------------------------------*/
        if (!m_bWriteHeaderInitialized)
        {
            WriteHeader();
        }

        m_numRecords = MAX(nRecordId, m_numRecords);

        nFileOffset = m_nFirstRecordPtr+(nRecordId-1)*m_nRecordSize;

        m_poRecordBlock->InitNewBlock(m_fp, m_nRecordSize, nFileOffset);

        /*-------------------------------------------------------------
         * The first char of the record is the active/deleted flag.
         * Automatically set it to ' ' (active).
         *------------------------------------------------------------*/
        m_poRecordBlock->WriteByte(' ');

    }

    m_nCurRecordId = nRecordId;

    return m_poRecordBlock;
}

/**********************************************************************
 *                   TABDATFile::CommitRecordToFile()
 *
 * Commit the data record previously initialized with GetRecordBlock()
 * to the file.  This function must be called after writing the data
 * values to a record otherwise the record will never make it to the
 * file.
 *
 * Returns 0 on success, -1 on error.
 **********************************************************************/
int  TABDATFile::CommitRecordToFile()
{
    if (m_eAccessMode != TABWrite || m_poRecordBlock == NULL)
        return -1;

    return m_poRecordBlock->CommitToFile();
}


/**********************************************************************
 *                   TABDATFile::ValidateFieldInfoFromTAB()
 *
 * Check that the value read from the .TAB file by the caller are 
 * consistent with what is found in the .DAT header.
 *
 * Note that field ids are positive and start at 0.
 *
 * We have to use this function when opening a file for reading since 
 * the .DAT file does not contain the full field types information...
 * a .DAT file is actually a .DBF file in which the .DBF types are
 * handled in a special way... type 'C' fields are used to store binary 
 * values for most MapInfo types.
 *
 * For TABTableDBF, we actually have no validation to do since all types
 * are stored as strings internally, so we'll just convert from string.
 *
 * Returns a value >= 0 if OK, -1 on error.
 **********************************************************************/
int  TABDATFile::ValidateFieldInfoFromTAB(int iField, const char *pszName,
                                          TABFieldType eType,
                                          int nWidth, int nPrecision)
{
    int i = iField;  // Just to make things shorter

    CPLAssert(m_pasFieldDef);

    if (m_pasFieldDef == NULL || iField < 0 || iField >= m_numFields)
    {
        CPLError(CE_Failure, CPLE_FileIO,
          "Invalid field %d (%s) in .TAB header. %s contains only %d fields.",
                 iField+1, pszName, m_pszFname, m_pasFieldDef? m_numFields:0);
        return -1;
    }

    /*-----------------------------------------------------------------
     * We used to check that the .TAB field name matched the .DAT
     * name stored internally, but apparently some tools that rename table
     * field names only update the .TAB file and not the .DAT, so we won't
     * do that name validation any more... we'll just check the type.
     *
     * With TABTableNative, we have to validate the field sizes as well
     * because .DAT files use char fields to store binary values.
     * With TABTableDBF, no need to validate field type since all
     * fields are stored as strings internally.
     *----------------------------------------------------------------*/
    if ((m_eTableType == TABTableNative && 
         ((eType == TABFChar && (m_pasFieldDef[i].cType != 'C' ||
                                m_pasFieldDef[i].byLength != nWidth )) ||
          (eType == TABFDecimal && (m_pasFieldDef[i].cType != 'N' ||
                                  m_pasFieldDef[i].byLength != nWidth||
                                   m_pasFieldDef[i].byDecimals!=nPrecision)) ||
          (eType == TABFInteger && (m_pasFieldDef[i].cType != 'C' ||
                                   m_pasFieldDef[i].byLength != 4  )) ||
          (eType == TABFSmallInt && (m_pasFieldDef[i].cType != 'C' ||
                                    m_pasFieldDef[i].byLength != 2 )) ||
          (eType == TABFFloat && (m_pasFieldDef[i].cType != 'C' ||
                                 m_pasFieldDef[i].byLength != 8    )) ||
          (eType == TABFDate && (m_pasFieldDef[i].cType != 'C' ||
                                m_pasFieldDef[i].byLength != 4     )) ||
          (eType == TABFTime && (m_pasFieldDef[i].cType != 'C' ||
                                 m_pasFieldDef[i].byLength != 4    )) ||
          (eType == TABFDateTime && (m_pasFieldDef[i].cType != 'C' ||
                                    m_pasFieldDef[i].byLength != 8 )) ||
          (eType == TABFLogical && (m_pasFieldDef[i].cType != 'L' ||
                                   m_pasFieldDef[i].byLength != 1  ))   ) ))
    {
        CPLError(CE_Failure, CPLE_FileIO,
                 "Definition of field %d (%s) from .TAB file does not match "
                 "what is found in %s (name=%s, type=%c, width=%d, prec=%d)",
                 iField+1, pszName, m_pszFname,
                 m_pasFieldDef[i].szName, m_pasFieldDef[i].cType, 
                 m_pasFieldDef[i].byLength, m_pasFieldDef[i].byDecimals);
        return -1;
    }

    m_pasFieldDef[i].eTABType = eType;

    return 0;
}

/**********************************************************************
 *                   TABDATFile::AddField()
 *
 * Create a new field (column) in a newly created table.  This function
 * must be called after the file has been opened, but before writing the
 * first record.
 *
 * Returns the new field index (a value >= 0) if OK, -1 on error.
 **********************************************************************/
int  TABDATFile::AddField(const char *pszName, TABFieldType eType,
                          int nWidth, int nPrecision /*=0*/)
{
    if (m_eAccessMode != TABWrite || m_bWriteHeaderInitialized ||
        m_eTableType != TABTableNative)
    {
        CPLError(CE_Failure, CPLE_NotSupported,
                 "Addition of new table fields is not supported after the "
                 "first data item has been written.");
        return -1;
    }

    /*-----------------------------------------------------------------
     * Validate field width... must be <= 254
     *----------------------------------------------------------------*/
    if (nWidth > 254)
    {
        CPLError(CE_Failure, CPLE_IllegalArg,
                 "Invalid size (%d) for field '%s'.  "
                 "Size must be 254 or less.", nWidth, pszName);
        return -1;
    }

    /*-----------------------------------------------------------------
     * Map fields with width=0 (variable length in OGR) to a valid default
     *----------------------------------------------------------------*/
    if (eType == TABFDecimal && nWidth == 0)
        nWidth=20;
    else if (nWidth == 0)
        nWidth=254; /* char fields */

    if (m_numFields < 0)
        m_numFields = 0;

    m_numFields++;
    m_pasFieldDef = (TABDATFieldDef*)CPLRealloc(m_pasFieldDef, 
                                          m_numFields*sizeof(TABDATFieldDef));

    strncpy(m_pasFieldDef[m_numFields-1].szName, pszName, 10);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -