📄 tabdatfile.cpp
字号:
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 assert(m_pasFieldDef); if (m_pasFieldDef == NULL || iField < 0 || iField >= m_numFields) { UGKError(ET_Failure, UGKErr_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 )) ) )) { UGKError(ET_Failure, UGKErr_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) { UGKError(ET_Failure, UGKErr_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) { UGKError(ET_Failure, UGKErr_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 UGK) 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*)UGK_Realloc(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 = (UGKByte)nWidth; m_pasFieldDef[m_numFields-1].byDecimals = (UGKByte)nPrecision; switch(eType) { case TABFChar: m_pasFieldDef[m_numFields-1].cType = 'C'; break; case TABFDecimal: m_pasFieldDef[m_numFields-1].cType = 'N'; break; case TABFInteger: m_pasFieldDef[m_numFields-1].cType = 'C'; m_pasFieldDef[m_numFields-1].byLength = 4; break; case TABFSmallInt: m_pasFieldDef[m_numFields-1].cType = 'C'; m_pasFieldDef[m_numFields-1].byLength = 2; break; case TABFFloat: m_pasFieldDef[m_numFields-1].cType = 'C'; m_pasFieldDef[m_numFields-1].byLength = 8; break; case TABFDate: m_pasFieldDef[m_numFields-1].cType = 'C'; m_pasFieldDef[m_numFields-1].byLength = 4; break; case TABFLogical: m_pasFieldDef[m_numFields-1].cType = 'L'; m_pasFieldDef[m_numFields-1].byLength = 1; break; default: UGKError(ET_Failure, UGKErr_NotSupported, "Unsupported field type for field `%s'", pszName); return -1; } return 0;}/********************************************************************** * TABDATFile::GetFieldType() * * Returns the native field type for field # nFieldId as previously set * by ValidateFieldInfoFromTAB(). * * Note that field ids are positive and start at 0. **********************************************************************/TABFieldType TABDATFile::GetFieldType(int nFieldId){ if (m_pasFieldDef == NULL || nFieldId < 0 || nFieldId >= m_numFields) return TABFUnknown; return m_pasFieldDef[nFieldId].eTABType;}/********************************************************************** * TABDATFile::GetFieldWidth() * * Returns the width for field # nFieldId as previously read from the * .DAT header. * * Note that field ids are positive and start at 0. **********************************************************************/int TABDATFile::GetFieldWidth(int nFieldId){ if (m_pasFieldDef == NULL || nFieldId < 0 || nFieldId >= m_numFields) return 0; return m_pasFieldDef[nFieldId].byLength;}/********************************************************************** * TABDATFile::GetFieldPrecision() * * Returns the precision for field # nFieldId as previously read from the * .DAT header. * * Note that field ids are positive and start at 0. **********************************************************************/int TABDATFile::GetFieldPrecision(int nFieldId){ if (m_pasFieldDef == NULL || nFieldId < 0 || nFieldId >= m_numFields) return 0; return m_pasFieldDef[nFieldId].byDecimals;}/********************************************************************** * TABDATFile::ReadCharField() * * Read the character field value at the current position in the data * block. * * Use GetRecordBlock() to position the data block to the beginning of * a record before attempting to read values. * * nWidth is the field length, as defined in the .DAT header. * * Returns a reference to an internal buffer that will be valid only until * the next field is read, or "" if the operation failed, in which case * CPLError() will have been called. **********************************************************************/const char *TABDATFile::ReadCharField(int nWidth){ // We know that character strings are limited to 254 chars in MapInfo static char szBuf[256]; // If current record has been deleted, then return an acceptable // default value. if (m_bCurRecordDeletedFlag) return ""; if (m_poRecordBlock == NULL) { UGKError(ET_Failure, UGKErr_AssertionFailed, "Can't read field value: file is not opened."); return ""; } if (nWidth < 1 || nWidth > 255) { UGKError(ET_Failure, UGKErr_AssertionFailed, "Illegal width for a char field: %d", nWidth); return ""; } if (m_poRecordBlock->ReadBytes(nWidth, (UGKByte*)szBuf) != 0) return ""; szBuf[nWidth] = '\0'; // NATIVE tables are padded with '\0' chars, but DBF tables are padded // with spaces... get rid of the trailing spaces. if (m_eTableType == TABTableDBF) { int nLen = strlen(szBuf)-1; while(nLen>=0 && szBuf[nLen] == ' ') szBuf[nLen--] = '\0'; } return szBuf;}/********************************************************************** * TABDATFile::ReadIntegerField() * * Read the integer field value at the current position in the data * block. * * Note: nWidth is used only with TABTableDBF types. * * CPLError() will have been called if something fails. **********************************************************************/UGKInt32 TABDATFile::ReadIntegerField(int nWidth){ // If current record has been deleted, then return an acceptable // default value. if (m_bCurRecordDeletedFlag) return 0; if (m_poRecordBlock == NULL) { UGKError(ET_Failure, UGKErr_AssertionFailed, "Can't read field value: file is not opened."); return 0; } if (m_eTableType == TABTableDBF) return atoi(ReadCharField(nWidth)); return m_poRecordBlock->ReadInt32();}/********************************************************************** * TABDATFile::ReadSmallIntField() * * Read the smallint field value at the current position in the data * block. * * Note: nWidth is used only with TABTableDBF types. * * CPLError() will have been called if something fails. **********************************************************************/UGKInt16 TABDATFile::ReadSmallIntField(int nWidth){ // If current record has been deleted, then return an acceptable // default value. if (m_bCurRecordDeletedFlag) return 0; if (m_poRecordBlock == NULL) { UGKError(ET_Failure, UGKErr_AssertionFailed, "Can't read field value: file is not opened."); return 0; } if (m_eTableType == TABTableDBF) return atoi(ReadCharField(nWidth)); return m_poRecordBlock->ReadInt16();}/********************************************************************** * TABDATFile::ReadFloatField() * * Read the float field value at the current position in the data * block. * * Note: nWidth is used only with TABTableDBF types. * * CPLError() will have been called if something fails. **********************************************************************/double TABDATFile::ReadFloatField(int nWidth){ // If current record has been deleted, then return an acceptable // default value. if (m_bCurRecordDeletedFlag) return 0.0; if (m_poRecordBlock == NULL) { UGKError(ET_Failure, UGKErr_AssertionFailed, "Can't read field value: file is not opened."); return 0.0; } if (m_eTableType == TABTableDBF) return atof(ReadCharField(nWidth)); return m_poRecordBlock->ReadDouble();}/********************************************************************** * TABDATFile::ReadLogicalField() * * Read the logical field value at the current position in the data * block. * * The file contains either 0 or 1, and we return a string with * "F" (false) or "T" (true) * * Note: nWidth is used only with TABTableDBF types. * * CPLError() will have been called if something fails. **********************************************************************/const char *TABDATFile::ReadLogicalField(int nWidth){ UGKByte bValue; // If current record has been deleted, then return an acceptable // default value. if (m_bCurRecordDeletedFlag) return "F"; if (m_poRecordBlock == NULL) { UGKError(ET_Failure, UGKErr_AssertionFailed, "Can't read field value: file is not opened."); return ""; } if (m_eTableType == TABTableDBF) { const char *pszVal = ReadCharField(nWidth); bValue = (pszVal && strchr("1YyTt", pszVal[0]) != NULL); } else {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -