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

📄 mitab_datfile.cpp

📁 mitab,读取MapInfo的地图文件
💻 CPP
📖 第 1 页 / 共 5 页
字号:
/**********************************************************************
 * $Id: mitab_datfile.cpp,v 1.19 2008/01/29 20:46:32 dmorissette Exp $
 *
 * Name:     mitab_datfile.cpp
 * Project:  MapInfo TAB Read/Write library
 * Language: C++
 * Purpose:  Implementation of the TABIDFile class used to handle
 *           reading/writing of the .DAT file
 * Author:   Daniel Morissette, dmorissette@dmsolutions.ca
 *
 **********************************************************************
 * Copyright (c) 1999-2001, Daniel Morissette
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:
 * 
 * The above copyright notice and this permission notice shall be included
 * in all copies or substantial portions of the Software.
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 
 * DEALINGS IN THE SOFTWARE.
 **********************************************************************
 *
 * $Log: mitab_datfile.cpp,v $
 * Revision 1.19  2008/01/29 20:46:32  dmorissette
 * Added support for v9 Time and DateTime fields (byg 1754)
 *
 * Revision 1.18  2007/10/09 17:43:16  fwarmerdam
 * Remove static variables that interfere with reentrancy. (GDAL #1883)
 *
 * Revision 1.17  2004/06/30 20:29:03  dmorissette
 * Fixed refs to old address danmo@videotron.ca
 *
 * Revision 1.16  2001/05/01 12:32:03  daniel
 * Get rid of leading spaces in WriteDateField().
 *
 * Revision 1.15  2000/04/27 15:42:03  daniel
 * Map variable field length (width=0) coming from OGR to acceptable default
 *
 * Revision 1.14  2000/02/28 16:52:52  daniel
 * Added support for writing indexes, removed validation on field name in
 * NATIVE tables, and remove trailing spaces in DBF char field values
 *
 * Revision 1.13  2000/01/28 07:31:49  daniel
 * Validate char field width (must be <= 254 chars)
 *
 * Revision 1.12  2000/01/16 19:08:48  daniel
 * Added support for reading 'Table Type DBF' tables
 *
 * Revision 1.11  2000/01/15 22:30:43  daniel
 * Switch to MIT/X-Consortium OpenSource license
 *
 * Revision 1.10  1999/12/20 18:59:20  daniel
 * Dates again... now returned as "YYYYMMDD"
 *
 * Revision 1.9  1999/12/16 17:11:45  daniel
 * Date fields: return as "YYYY/MM/DD", and accept 3 diff. formats as input
 *
 * Revision 1.8  1999/12/14 03:58:29  daniel
 * Fixed date read/write (bytes were reversed)
 *
 * Revision 1.7  1999/11/09 07:34:35  daniel
 * Return default values when deleted attribute records are encountered
 *
 * Revision 1.6  1999/10/19 06:09:25  daniel
 * Removed obsolete GetFieldDef() method
 *
 * Revision 1.5  1999/10/01 03:56:28  daniel
 * Avoid multiple InitWriteHeader() calls (caused a leak) and added a fix
 * in WriteCharField() to prevent reading bytes past end of string buffer
 *
 * Revision 1.4  1999/10/01 02:02:36  warmerda
 * Added assertions to try and track TABRawBinBlock leak.
 *
 * Revision 1.3  1999/09/26 14:59:36  daniel
 * Implemented write support
 *
 * Revision 1.2  1999/09/20 18:43:20  daniel
 * Use binary access to open file.
 *
 * Revision 1.1  1999/07/12 04:18:23  daniel
 * Initial checkin
 *
 **********************************************************************/

#include "mitab.h"

/*=====================================================================
 *                      class TABDATFile
 *
 * Note that the .DAT files are .DBF files with some exceptions:
 *
 * All fields in the DBF header are defined as 'C' type (strings),
 * even for binary integers.  So we have to look in the associated .TAB
 * file to find the real field definition.
 *
 * Even though binary integers are defined as 'C' type, they are stored
 * in binary form inside a 4 bytes string field.
 *====================================================================*/


/**********************************************************************
 *                   TABDATFile::TABDATFile()
 *
 * Constructor.
 **********************************************************************/
TABDATFile::TABDATFile()
{
    m_fp = NULL;
    m_pszFname = NULL;
    m_eTableType = TABTableNative;

    m_poHeaderBlock = NULL;
    m_poRecordBlock = NULL;
    m_pasFieldDef = NULL;

    m_numFields = -1;
    m_numRecords = -1;
    m_nFirstRecordPtr = 0;
    m_nBlockSize = 0;
    m_nRecordSize = -1;
    m_nCurRecordId = -1;
    m_bCurRecordDeletedFlag = FALSE;
    m_bWriteHeaderInitialized = FALSE;
}

/**********************************************************************
 *                   TABDATFile::~TABDATFile()
 *
 * Destructor.
 **********************************************************************/
TABDATFile::~TABDATFile()
{
    Close();
}

/**********************************************************************
 *                   TABDATFile::Open()
 *
 * Open a .DAT file, and initialize the structures to be ready to read
 * records from it.
 *
 * We currently support NATIVE and DBF tables for reading, and only
 * NATIVE tables for writing.
 *
 * Returns 0 on success, -1 on error.
 **********************************************************************/
int TABDATFile::Open(const char *pszFname, const char *pszAccess,
                     TABTableType eTableType /*=TABNativeTable*/)
{
    int i;

    if (m_fp)
    {
        CPLError(CE_Failure, CPLE_FileIO,
                 "Open() failed: object already contains an open file");
        return -1;
    }

    /*-----------------------------------------------------------------
     * Validate access mode and make sure we use binary access.
     *----------------------------------------------------------------*/
    if (EQUALN(pszAccess, "r", 1) && (eTableType==TABTableNative ||
                                      eTableType==TABTableDBF)  )
    {
        m_eAccessMode = TABRead;
        pszAccess = "rb";
    }
    else if (EQUALN(pszAccess, "w", 1) && eTableType==TABTableNative)
    {
        m_eAccessMode = TABWrite;
        pszAccess = "wb";
    }
    else
    {
        CPLError(CE_Failure, CPLE_FileIO,
                 "Open() failed: access mode \"%s\" not supported", pszAccess);
        return -1;
    }

    /*-----------------------------------------------------------------
     * Open file for reading
     *----------------------------------------------------------------*/
    m_pszFname = CPLStrdup(pszFname);
    m_fp = VSIFOpen(m_pszFname, pszAccess);
    m_eTableType = eTableType;

    if (m_fp == NULL)
    {
        CPLError(CE_Failure, CPLE_FileIO,
                 "Open() failed for %s", m_pszFname);
        CPLFree(m_pszFname);
        m_pszFname = NULL;
        return -1;
    }

    if (m_eAccessMode == TABRead)
    {
        /*------------------------------------------------------------
         * READ ACCESS:
         * Read .DAT file header (record size, num records, etc...)
         * m_poHeaderBlock will be reused later to read field definition
         *-----------------------------------------------------------*/
        m_poHeaderBlock = new TABRawBinBlock(m_eAccessMode, TRUE);
        m_poHeaderBlock->ReadFromFile(m_fp, 0, 32);

        m_poHeaderBlock->ReadByte();       // Table type ??? 0x03
        m_poHeaderBlock->ReadByte();       // Last update year
        m_poHeaderBlock->ReadByte();       // Last update month
        m_poHeaderBlock->ReadByte();       // Last update day

        m_numRecords      = m_poHeaderBlock->ReadInt32();
        m_nFirstRecordPtr = m_poHeaderBlock->ReadInt16();
        m_nRecordSize     = m_poHeaderBlock->ReadInt16();

        m_numFields = m_nFirstRecordPtr/32 - 1;

        /*-------------------------------------------------------------
         * Read the field definitions
         * First 32 bytes field definition starts at byte 32 in file
         *------------------------------------------------------------*/
        m_pasFieldDef = (TABDATFieldDef*)CPLCalloc(m_numFields, 
                                                   sizeof(TABDATFieldDef));

        for(i=0; i<m_numFields; i++)
        {
            m_poHeaderBlock->GotoByteInFile((i+1)*32);
            m_poHeaderBlock->ReadBytes(11, (GByte*)m_pasFieldDef[i].szName);
            m_pasFieldDef[i].szName[10] = '\0';
            m_pasFieldDef[i].cType = (char)m_poHeaderBlock->ReadByte();

            m_poHeaderBlock->ReadInt32();       // Skip Bytes 12-15
            m_pasFieldDef[i].byLength = m_poHeaderBlock->ReadByte();
            m_pasFieldDef[i].byDecimals = m_poHeaderBlock->ReadByte();

            m_pasFieldDef[i].eTABType = TABFUnknown;
        }

        /*-------------------------------------------------------------
         * Establish a good record block size to use based on record size, and 
         * then create m_poRecordBlock
         * Record block size has to be a multiple of record size.
         *------------------------------------------------------------*/
        m_nBlockSize = ((1024/m_nRecordSize)+1)*m_nRecordSize;
        m_nBlockSize = MIN(m_nBlockSize, (m_numRecords*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);
    }
    else
    {
        /*------------------------------------------------------------
         * WRITE ACCESS:
         * Set acceptable defaults for all class members.
         * The real header initialization will be done when the first
         * record is written
         *-----------------------------------------------------------*/
        m_poHeaderBlock = NULL;

        m_numRecords      = 0;
        m_nFirstRecordPtr = 0;
        m_nRecordSize     = 0;
        m_numFields = 0;
        m_pasFieldDef = NULL;
        m_bWriteHeaderInitialized = FALSE;
    }

    return 0;
}

/**********************************************************************
 *                   TABDATFile::Close()
 *
 * Close current file, and release all memory used.
 *
 * Returns 0 on success, -1 on error.
 **********************************************************************/
int TABDATFile::Close()
{
    if (m_fp == NULL)
        return 0;

    /*----------------------------------------------------------------
     * Write access: Update the header with number of records, etc.
     * and add a CTRL-Z char at the end of the file.
     *---------------------------------------------------------------*/
    if (m_eAccessMode == TABWrite)
    {
        WriteHeader();

        char cEOF = 26;
        if (VSIFSeek(m_fp, 0L, SEEK_END) == 0)
            VSIFWrite(&cEOF, 1, 1, m_fp);
    }
    
    // Delete all structures 
    if (m_poHeaderBlock)
    {
        delete m_poHeaderBlock;
        m_poHeaderBlock = NULL;
    }

    if (m_poRecordBlock)
    {
        delete m_poRecordBlock;
        m_poRecordBlock = NULL;
    }

    // Close file
    VSIFClose(m_fp);
    m_fp = NULL;

    CPLFree(m_pszFname);
    m_pszFname = NULL;

    CPLFree(m_pasFieldDef);
    m_pasFieldDef = NULL;

    m_numFields = -1;
    m_numRecords = -1;
    m_nFirstRecordPtr = 0;
    m_nBlockSize = 0;
    m_nRecordSize = -1;
    m_nCurRecordId = -1;
    m_bWriteHeaderInitialized = FALSE;

    return 0;
}


/**********************************************************************
 *                   TABDATFile::InitWriteHeader()
 *
 * 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::InitWriteHeader()
{
    int i;

    if (m_eAccessMode != TABWrite || m_bWriteHeaderInitialized)
        return 0;

    /*------------------------------------------------------------
     * Compute values for Record size, header size, etc.
     *-----------------------------------------------------------*/
    m_nFirstRecordPtr = (m_numFields+1)*32 + 1;

    m_nRecordSize = 1;

⌨️ 快捷键说明

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