📄 mitab_datfile.cpp
字号:
} /*------------------------------------------------------------- * 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 == 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); m_pasFieldDef[m_numFields-1].szName[10] = '\0'; m_pasFieldDef[m_numFields-1].eTABType = eType; m_pasFieldDef[m_numFields-1].byLength = (GByte)nWidth; m_pasFieldDef[m_numFields-1].byDecimals = (GByte)nPrecision;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -