📄 mitab_rawbinblock.cpp
字号:
/**********************************************************************
* $Id: mitab_rawbinblock.cpp,v 1.11 2007/06/11 14:40:03 dmorissette Exp $
*
* Name: mitab_rawbinblock.cpp
* Project: MapInfo TAB Read/Write library
* Language: C++
* Purpose: Implementation of the TABRawBinBlock class used to handle
* reading/writing blocks in the .MAP files
* Author: Daniel Morissette, dmorissette@dmsolutions.ca
*
**********************************************************************
* Copyright (c) 1999, 2000, 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_rawbinblock.cpp,v $
* Revision 1.11 2007/06/11 14:40:03 dmorissette
* Fixed another issue related to attempting to read past EOF while writing
* collections (bug 1657)
*
* Revision 1.10 2007/02/22 18:35:53 dmorissette
* Fixed problem writing collections where MITAB was sometimes trying to
* read past EOF in write mode (bug 1657).
*
* Revision 1.9 2006/11/28 18:49:08 dmorissette
* Completed changes to split TABMAPObjectBlocks properly and produce an
* optimal spatial index (bug 1585)
*
* Revision 1.8 2005/10/06 19:15:31 dmorissette
* Collections: added support for reading/writing pen/brush/symbol ids and
* for writing collection objects to .TAB/.MAP (bug 1126)
*
* Revision 1.7 2004/12/01 18:25:03 dmorissette
* Fixed potential memory leaks in error conditions (bug 881)
*
* Revision 1.6 2004/06/30 20:29:04 dmorissette
* Fixed refs to old address danmo@videotron.ca
*
* Revision 1.5 2000/02/28 17:06:06 daniel
* Added m_bModified flag
*
* Revision 1.4 2000/01/15 22:30:45 daniel
* Switch to MIT/X-Consortium OpenSource license
*
* Revision 1.3 1999/09/26 14:59:37 daniel
* Implemented write support
*
* Revision 1.2 1999/09/16 02:39:17 daniel
* Completed read support for most feature types
*
* Revision 1.1 1999/07/12 04:18:25 daniel
* Initial checkin
*
**********************************************************************/
#include "mitab.h"
/*=====================================================================
* class TABRawBinBlock
*====================================================================*/
/**********************************************************************
* TABRawBinBlock::TABRawBinBlock()
*
* Constructor.
**********************************************************************/
TABRawBinBlock::TABRawBinBlock(TABAccess eAccessMode /*= TABRead*/,
GBool bHardBlockSize /*= TRUE*/)
{
m_fp = NULL;
m_pabyBuf = NULL;
m_nFirstBlockPtr = 0;
m_nBlockSize = m_nSizeUsed = m_nFileOffset = m_nCurPos = 0;
m_bHardBlockSize = bHardBlockSize;
m_bModified = FALSE;
m_eAccess = eAccessMode;
}
/**********************************************************************
* TABRawBinBlock::~TABRawBinBlock()
*
* Destructor.
**********************************************************************/
TABRawBinBlock::~TABRawBinBlock()
{
if (m_pabyBuf)
CPLFree(m_pabyBuf);
}
/**********************************************************************
* TABRawBinBlock::ReadFromFile()
*
* Load data from the specified file location and initialize the block.
*
* Returns 0 if succesful or -1 if an error happened, in which case
* CPLError() will have been called.
**********************************************************************/
int TABRawBinBlock::ReadFromFile(FILE *fpSrc, int nOffset,
int nSize /*= 512*/)
{
GByte *pabyBuf;
if (fpSrc == NULL || nSize == 0)
{
CPLError(CE_Failure, CPLE_AssertionFailed,
"TABRawBinBlock::ReadFromFile(): Assertion Failed!");
return -1;
}
m_fp = fpSrc;
m_nFileOffset = nOffset;
m_nCurPos = 0;
m_bModified = FALSE;
/*----------------------------------------------------------------
* Alloc a buffer to contain the data
*---------------------------------------------------------------*/
pabyBuf = (GByte*)CPLMalloc(nSize*sizeof(GByte));
/*----------------------------------------------------------------
* Read from the file
*---------------------------------------------------------------*/
if (VSIFSeek(fpSrc, nOffset, SEEK_SET) != 0 ||
(m_nSizeUsed = VSIFRead(pabyBuf, sizeof(GByte), nSize, fpSrc) ) == 0 ||
(m_bHardBlockSize && m_nSizeUsed != nSize ) )
{
CPLError(CE_Failure, CPLE_FileIO,
"ReadFromFile() failed reading %d bytes at offset %d.",
nSize, nOffset);
CPLFree(pabyBuf);
return -1;
}
/*----------------------------------------------------------------
* Init block with the data we just read
*---------------------------------------------------------------*/
return InitBlockFromData(pabyBuf, nSize, m_nSizeUsed,
FALSE, fpSrc, nOffset);
}
/**********************************************************************
* TABRawBinBlock::CommitToFile()
*
* Commit the current state of the binary block to the file to which
* it has been previously attached.
*
* Derived classes may want to (optionally) reimplement this method if
* they need to do special processing before committing the block to disk.
*
* For files created with bHardBlockSize=TRUE, a complete block of
* the specified size is always written, otherwise only the number of
* used bytes in the block will be written to disk.
*
* Returns 0 if succesful or -1 if an error happened, in which case
* CPLError() will have been called.
**********************************************************************/
int TABRawBinBlock::CommitToFile()
{
int nStatus = 0;
if (m_fp == NULL || m_nBlockSize <= 0 || m_pabyBuf == NULL ||
m_nFileOffset < 0)
{
CPLError(CE_Failure, CPLE_AssertionFailed,
"TABRawBinBlock::CommitToFile(): Block has not been initialized yet!");
return -1;
}
/*----------------------------------------------------------------
* If block has not been modified, then just return... nothing to do.
*---------------------------------------------------------------*/
if (!m_bModified)
return 0;
/*----------------------------------------------------------------
* Move the output file pointer to the right position...
*---------------------------------------------------------------*/
if (VSIFSeek(m_fp, m_nFileOffset, SEEK_SET) != 0)
{
/*------------------------------------------------------------
* Moving pointer failed... we may need to pad with zeros if
* block destination is beyond current end of file.
*-----------------------------------------------------------*/
int nCurPos;
nCurPos = VSIFTell(m_fp);
if (nCurPos < m_nFileOffset &&
VSIFSeek(m_fp, 0L, SEEK_END) == 0 &&
(nCurPos = VSIFTell(m_fp)) < m_nFileOffset)
{
GByte cZero = 0;
while(nCurPos < m_nFileOffset && nStatus == 0)
{
if (VSIFWrite(&cZero, 1, 1, m_fp) != 1)
{
CPLError(CE_Failure, CPLE_FileIO,
"Failed writing 1 byte at offset %d.", nCurPos);
nStatus = -1;
break;
}
nCurPos++;
}
}
if (nCurPos != m_nFileOffset)
nStatus = -1; // Error message will follow below
}
/*----------------------------------------------------------------
* At this point we are ready to write to the file.
*
* If m_bHardBlockSize==FALSE, then we do not write a complete block;
* we write only the part of the block that was used.
*---------------------------------------------------------------*/
int numBytesToWrite = m_bHardBlockSize?m_nBlockSize:m_nSizeUsed;
if (nStatus != 0 ||
VSIFWrite(m_pabyBuf,sizeof(GByte),
numBytesToWrite, m_fp) != (size_t)numBytesToWrite )
{
CPLError(CE_Failure, CPLE_FileIO,
"Failed writing %d bytes at offset %d.",
numBytesToWrite, m_nFileOffset);
return -1;
}
fflush(m_fp);
m_bModified = FALSE;
return 0;
}
/**********************************************************************
* TABRawBinBlock::CommitAsDeleted()
*
* Commit current block to file using block type 4 (garbage block)
*
* Returns 0 if succesful or -1 if an error happened, in which case
* CPLError() will have been called.
**********************************************************************/
int TABRawBinBlock::CommitAsDeleted(GInt32 nNextBlockPtr)
{
int nStatus = 0;
CPLErrorReset();
if ( m_pabyBuf == NULL )
{
CPLError(CE_Failure, CPLE_AssertionFailed,
"CommitAsDeleted(): Block has not been initialized yet!");
return -1;
}
/*-----------------------------------------------------------------
* Create deleted block header
*----------------------------------------------------------------*/
GotoByteInBlock(0x000);
WriteInt32(nNextBlockPtr);
if( CPLGetLastErrorType() == CE_Failure )
nStatus = CPLGetLastErrorNo();
/*-----------------------------------------------------------------
* OK, call the base class to write the block to disk.
*----------------------------------------------------------------*/
if (nStatus == 0)
nStatus = TABRawBinBlock::CommitToFile();
return nStatus;
}
/**********************************************************************
* TABRawBinBlock::InitBlockFromData()
*
* Set the binary data buffer and initialize the block.
*
* Calling ReadFromFile() will automatically call InitBlockFromData() to
* complete the initialization of the block after the data is read from the
* file. Derived classes should implement their own version of
* InitBlockFromData() if they need specific initialization... in this
* case the derived InitBlockFromData() should call
* TABRawBinBlock::InitBlockFromData() before doing anything else.
*
* By default, the buffer will be copied, but if bMakeCopy = FALSE then
* it won't be copied, and the object will keep a reference to the
* user's buffer... and this object will eventually free the user's buffer.
*
* Returns 0 if succesful or -1 if an error happened, in which case
* CPLError() will have been called.
**********************************************************************/
int TABRawBinBlock::InitBlockFromData(GByte *pabyBuf,
int nBlockSize, int nSizeUsed,
GBool bMakeCopy /* = TRUE */,
FILE *fpSrc /* = NULL */,
int nOffset /* = 0 */)
{
m_fp = fpSrc;
m_nFileOffset = nOffset;
m_nCurPos = 0;
m_bModified = FALSE;
/*----------------------------------------------------------------
* Alloc or realloc the buffer to contain the data if necessary
*---------------------------------------------------------------*/
if (!bMakeCopy)
{
if (m_pabyBuf != NULL)
CPLFree(m_pabyBuf);
m_pabyBuf = pabyBuf;
m_nBlockSize = nBlockSize;
m_nSizeUsed = nSizeUsed;
}
else if (m_pabyBuf == NULL || nBlockSize != m_nBlockSize)
{
m_pabyBuf = (GByte*)CPLRealloc(m_pabyBuf, nBlockSize*sizeof(GByte));
m_nBlockSize = nBlockSize;
m_nSizeUsed = nSizeUsed;
memcpy(m_pabyBuf, pabyBuf, m_nSizeUsed);
}
/*----------------------------------------------------------------
* Extract block type... header block (first block in a file) has
* no block type, so we assign one by default.
*---------------------------------------------------------------*/
if (m_nFileOffset == 0)
m_nBlockType = TABMAP_HEADER_BLOCK;
else
{
// Block type will be validated only if GetBlockType() is called
m_nBlockType = (int)m_pabyBuf[0];
}
return 0;
}
/**********************************************************************
* TABRawBinBlock::InitNewBlock()
*
* Initialize the block so that it knows to which file is is attached,
* its block size, etc.
*
* This is an alternative to calling ReadFromFile() or InitBlockFromData()
* that puts the block in a stable state without loading any initial
* data in it.
*
* Returns 0 if succesful or -1 if an error happened, in which case
* CPLError() will have been called.
**********************************************************************/
int TABRawBinBlock::InitNewBlock(FILE *fpSrc, int nBlockSize,
int nFileOffset /* = 0*/)
{
m_fp = fpSrc;
m_nBlockSize = nBlockSize;
m_nSizeUsed = 0;
m_nCurPos = 0;
m_bModified = FALSE;
if (nFileOffset > 0)
m_nFileOffset = nFileOffset;
else
m_nFileOffset = 0;
m_nBlockType = -1;
m_pabyBuf = (GByte*)CPLRealloc(m_pabyBuf, m_nBlockSize*sizeof(GByte));
memset(m_pabyBuf, 0, m_nBlockSize);
return 0;
}
/**********************************************************************
* TABRawBinBlock::GetBlockType()
*
* Return the block type for the current object.
*
* Returns a block type >= 0 if succesful or -1 if an error happened, in
* which case CPLError() will have been called.
**********************************************************************/
int TABRawBinBlock::GetBlockType()
{
if (m_pabyBuf == NULL)
{
CPLError(CE_Failure, CPLE_AppDefined,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -