?? mitab_indfile.cpp
字號:
/**********************************************************************
* $Id: mitab_indfile.cpp,v 1.13 2008/01/29 20:46:32 dmorissette Exp $
*
* Name: mitab_indfile.cpp
* Project: MapInfo TAB Read/Write library
* Language: C++
* Purpose: Implementation of the TABINDFile class used to handle
* access to .IND file (table field indexes) attached to a .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_indfile.cpp,v $
* Revision 1.13 2008/01/29 20:46:32 dmorissette
* Added support for v9 Time and DateTime fields (byg 1754)
*
* Revision 1.12 2007/12/11 03:43:03 dmorissette
* Added reporting access mode to error message in TABINDFile::Open()
* (GDAL changeset r12460, ticket 1620)
*
* Revision 1.11 2005/04/29 19:08:56 dmorissette
* Produce an error if m_nSubtreeDepth > 255 when creating a .IND (OGR bug 839)
*
* Revision 1.10 2004/06/30 20:29:04 dmorissette
* Fixed refs to old address danmo@videotron.ca
*
* Revision 1.9 2003/07/24 02:45:57 daniel
* Fixed problem scanning node in TABINDNode::FindNext() - bug 2176, FW
*
* Revision 1.8 2001/05/01 03:38:23 daniel
* Added update support (allows creating new index in existing IND files).
*
* Revision 1.7 2000/11/13 22:17:57 daniel
* When a (child) node's first entry is replaced by InsertEntry() then make
* sure that node's key is updated in its parent node.
*
* Revision 1.6 2000/03/01 00:32:00 daniel
* Added support for float keys, and completed support for generating indexes
*
* Revision 1.5 2000/02/28 16:57:42 daniel
* Added support for writing indexes
*
* Revision 1.4 2000/01/15 22:30:44 daniel
* Switch to MIT/X-Consortium OpenSource license
*
* Revision 1.3 1999/12/14 05:52:05 daniel
* Fixed compile error on Windows
*
* Revision 1.2 1999/12/14 02:19:42 daniel
* Completed .IND support for simple TABViews
*
* Revision 1.1 1999/11/20 15:49:07 daniel
* Initial version
*
**********************************************************************/
#include "mitab.h"
#include "mitab_utils.h"
#include <ctype.h> /* toupper() */
/*=====================================================================
* class TABINDFile
*====================================================================*/
#define IND_MAGIC_COOKIE 24242424
/**********************************************************************
* TABINDFile::TABINDFile()
*
* Constructor.
**********************************************************************/
TABINDFile::TABINDFile()
{
m_fp = NULL;
m_pszFname = NULL;
m_eAccessMode = TABRead;
m_numIndexes = 0;
m_papoIndexRootNodes = NULL;
m_papbyKeyBuffers = NULL;
}
/**********************************************************************
* TABINDFile::~TABINDFile()
*
* Destructor.
**********************************************************************/
TABINDFile::~TABINDFile()
{
Close();
}
/**********************************************************************
* TABINDFile::Open()
*
* Open a .IND file, read the header and the root nodes for all the
* field indexes, and be ready to search the indexes.
*
* If the filename that is passed in contains a .DAT extension then
* the extension will be changed to .IND before trying to open the file.
*
* Note that we pass a pszAccess flag, but only read access is supported
* for now (and there are no plans to support write.)
*
* Set bTestOpenNoError=TRUE to silently return -1 with no error message
* if the file cannot be opened because it does not exist.
*
* Returns 0 on success, -1 on error.
**********************************************************************/
int TABINDFile::Open(const char *pszFname, const char *pszAccess,
GBool bTestOpenNoError /*=FALSE*/)
{
int nLen;
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.
* Note that for write access, we actually need read/write access to
* the file.
*----------------------------------------------------------------*/
if (EQUALN(pszAccess, "r", 1) && strchr(pszAccess, '+') != NULL)
{
m_eAccessMode = TABReadWrite;
pszAccess = "rb+";
}
else if (EQUALN(pszAccess, "r", 1))
{
m_eAccessMode = TABRead;
pszAccess = "rb";
}
else if (EQUALN(pszAccess, "w", 1))
{
m_eAccessMode = TABWrite;
pszAccess = "wb+";
}
else
{
CPLError(CE_Failure, CPLE_FileIO,
"Open() failed: access mode \"%s\" not supported", pszAccess);
return -1;
}
/*-----------------------------------------------------------------
* Change .DAT (or .TAB) extension to .IND if necessary
*----------------------------------------------------------------*/
m_pszFname = CPLStrdup(pszFname);
nLen = strlen(m_pszFname);
if (nLen > 4 && !EQUAL(m_pszFname+nLen-4, ".IND") )
strcpy(m_pszFname+nLen-4, ".ind");
#ifndef _WIN32
TABAdjustFilenameExtension(m_pszFname);
#endif
/*-----------------------------------------------------------------
* Open file
*----------------------------------------------------------------*/
m_fp = VSIFOpen(m_pszFname, pszAccess);
if (m_fp == NULL)
{
if (!bTestOpenNoError)
CPLError(CE_Failure, CPLE_FileIO,
"Open() failed for %s (%s)", m_pszFname, pszAccess);
CPLFree(m_pszFname);
m_pszFname = NULL;
return -1;
}
/*-----------------------------------------------------------------
* Reset block manager to allocate first block at byte 512, after header.
*----------------------------------------------------------------*/
m_oBlockManager.Reset();
m_oBlockManager.AllocNewBlock();
/*-----------------------------------------------------------------
* Read access: Read the header block
* This will also alloc and init the array of index root nodes.
*----------------------------------------------------------------*/
if ((m_eAccessMode == TABRead || m_eAccessMode == TABReadWrite) &&
ReadHeader() != 0)
{
// Failed reading header... CPLError() has already been called
Close();
return -1;
}
/*-----------------------------------------------------------------
* Write access: Init class members and write a dummy header block
*----------------------------------------------------------------*/
if (m_eAccessMode == TABWrite)
{
m_numIndexes = 0;
if (WriteHeader() != 0)
{
// Failed writing header... CPLError() has already been called
Close();
return -1;
}
}
return 0;
}
/**********************************************************************
* TABINDFile::Close()
*
* Close current file, and release all memory used.
*
* Returns 0 on success, -1 on error.
**********************************************************************/
int TABINDFile::Close()
{
if (m_fp == NULL)
return 0;
/*-----------------------------------------------------------------
* In Write Mode, commit all indexes to the file
*----------------------------------------------------------------*/
if (m_eAccessMode == TABWrite || m_eAccessMode == TABReadWrite)
{
WriteHeader();
for(int iIndex=0; iIndex<m_numIndexes; iIndex++)
{
if (m_papoIndexRootNodes &&
m_papoIndexRootNodes[iIndex])
{
m_papoIndexRootNodes[iIndex]->CommitToFile();
}
}
}
/*-----------------------------------------------------------------
* Free index nodes in memory
*----------------------------------------------------------------*/
for (int iIndex=0; iIndex<m_numIndexes; iIndex++)
{
if (m_papoIndexRootNodes && m_papoIndexRootNodes[iIndex])
delete m_papoIndexRootNodes[iIndex];
if (m_papbyKeyBuffers && m_papbyKeyBuffers[iIndex])
CPLFree(m_papbyKeyBuffers[iIndex]);
}
CPLFree(m_papoIndexRootNodes);
m_papoIndexRootNodes = NULL;
CPLFree(m_papbyKeyBuffers);
m_papbyKeyBuffers = NULL;
m_numIndexes = 0;
/*-----------------------------------------------------------------
* Close file
*----------------------------------------------------------------*/
VSIFClose(m_fp);
m_fp = NULL;
CPLFree(m_pszFname);
m_pszFname = NULL;
return 0;
}
/**********************************************************************
* TABINDFile::ReadHeader()
*
* (private method)
* Read the header block and init all class members for read access.
*
* Returns 0 on success, -1 on error.
**********************************************************************/
int TABINDFile::ReadHeader()
{
CPLAssert(m_fp);
CPLAssert(m_eAccessMode == TABRead || m_eAccessMode == TABReadWrite);
/*-----------------------------------------------------------------
* In ReadWrite mode, we need to init BlockManager with file size
*----------------------------------------------------------------*/
VSIStatBuf sStatBuf;
if (m_eAccessMode == TABReadWrite && VSIStat(m_pszFname, &sStatBuf) != -1)
{
m_oBlockManager.SetLastPtr(((sStatBuf.st_size-1)/512)*512);
}
/*-----------------------------------------------------------------
* Read the header block
*----------------------------------------------------------------*/
TABRawBinBlock *poHeaderBlock;
poHeaderBlock = new TABRawBinBlock(m_eAccessMode, TRUE);
if (poHeaderBlock->ReadFromFile(m_fp, 0, 512) != 0)
{
// CPLError() has already been called.
delete poHeaderBlock;
return -1;
}
poHeaderBlock->GotoByteInBlock(0);
GUInt32 nMagicCookie = poHeaderBlock->ReadInt32();
if (nMagicCookie != IND_MAGIC_COOKIE)
{
CPLError(CE_Failure, CPLE_FileIO,
"%s: Invalid Magic Cookie: got %d, expected %d",
m_pszFname, nMagicCookie, IND_MAGIC_COOKIE);
delete poHeaderBlock;
return -1;
}
poHeaderBlock->GotoByteInBlock(12);
m_numIndexes = poHeaderBlock->ReadInt16();
if (m_numIndexes < 1 || m_numIndexes > 29)
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -