/********************************************************************** * IMapInfoFile::SmartOpen() * * Use this static method to automatically open any flavour of MapInfo * dataset. This method will detect the file type, create an object * of the right type, and open the file. * * Call GetFileClass() on the returned object if you need to find out * its exact type. (To access format-specific methods for instance) * * Returns the new object ptr. , or NULL if the open failed. **********************************************************************/ IMapInfoFile *IMapInfoFile::SmartOpen(const char *pszFname, GBool bTestOpenNoError /*=FALSE*/) { IMapInfoFile *poFile = NULL; int nLen = 0; if (pszFname) nLen = strlen(pszFname); if (nLen > 4 && (EQUAL(pszFname + nLen-4, ".MIF") || EQUAL(pszFname + nLen-4, ".MID") ) ) { /*------------------------------------------------------------- * MIF/MID file *------------------------------------------------------------*/ poFile = new MIFFile; } else if (nLen > 4 && EQUAL(pszFname + nLen-4, ".TAB")) { /*------------------------------------------------------------- * .TAB file ... is it a TABFileView or a TABFile? * We have to read the .tab header to find out. *------------------------------------------------------------*/ FILE *fp; const char *pszLine; char *pszAdjFname = CPLStrdup(pszFname); GBool bFoundFields = FALSE, bFoundView=FALSE, bFoundSeamless=FALSE; TABAdjustFilenameExtension(pszAdjFname); fp = VSIFOpen(pszAdjFname, "r"); while(fp && (pszLine = CPLReadLine(fp)) != NULL) { while (isspace((unsigned char)*pszLine)) pszLine++; if (EQUALN(pszLine, "Fields", 6)) bFoundFields = TRUE; else if (EQUALN(pszLine, "create view", 11)) bFoundView = TRUE; else if (EQUALN(pszLine, "\"\\IsSeamless\" = \"TRUE\"", 21)) bFoundSeamless = TRUE; } if (bFoundView) poFile = new TABView; else if (bFoundFields && bFoundSeamless) poFile = new TABSeamless; else if (bFoundFields) poFile = new TABFile; if (fp) VSIFClose(fp); CPLFree(pszAdjFname); } /*----------------------------------------------------------------- * Perform the open() call *----------------------------------------------------------------*/ if (poFile && poFile->Open(pszFname, "r", bTestOpenNoError) != 0) { delete poFile; poFile = NULL; } if (!bTestOpenNoError && poFile == NULL) { CPLError(CE_Failure, CPLE_FileIO, "%s could not be opened as a MapInfo dataset.", pszFname); } return poFile; }
/********************************************************************** * TABSeamless::OpenForRead() * * Open for reading * * Returns 0 on success, -1 on error. **********************************************************************/ int TABSeamless::OpenForRead(const char *pszFname, GBool bTestOpenNoError /*= FALSE*/ ) { int nFnameLen = 0; m_eAccessMode = TABRead; /*----------------------------------------------------------------- * Read main .TAB (text) file *----------------------------------------------------------------*/ m_pszFname = CPLStrdup(pszFname); #ifndef _WIN32 /*----------------------------------------------------------------- * On Unix, make sure extension uses the right cases * We do it even for write access because if a file with the same * extension already exists we want to overwrite it. *----------------------------------------------------------------*/ TABAdjustFilenameExtension(m_pszFname); #endif /*----------------------------------------------------------------- * Open .TAB file... since it's a small text file, we will just load * it as a stringlist in memory. *----------------------------------------------------------------*/ char **papszTABFile = TAB_CSLLoad(m_pszFname); if (papszTABFile == NULL) { if (!bTestOpenNoError) { CPLError(CE_Failure, CPLE_FileIO, "Failed opening %s.", m_pszFname); } CPLFree(m_pszFname); CSLDestroy(papszTABFile); return -1; } /*------------------------------------------------------------- * Look for a metadata line with "\IsSeamless" = "TRUE". * If there is no such line, then we may have a valid .TAB file, * but we do not support it in this class. *------------------------------------------------------------*/ GBool bSeamlessFound = FALSE; for (int i=0; !bSeamlessFound && papszTABFile && papszTABFile[i]; i++) { const char *pszStr = papszTABFile[i]; while(*pszStr != '\0' && isspace((unsigned char)*pszStr)) pszStr++; if (EQUALN(pszStr, "\"\\IsSeamless\" = \"TRUE\"", 21)) bSeamlessFound = TRUE; } CSLDestroy(papszTABFile); if ( !bSeamlessFound ) { if (!bTestOpenNoError) CPLError(CE_Failure, CPLE_NotSupported, "%s does not appear to be a Seamless TAB File. " "This type of .TAB file cannot be read by this library.", m_pszFname); else CPLErrorReset(); CPLFree(m_pszFname); return -1; } /*----------------------------------------------------------------- * OK, this appears to be a valid seamless TAB dataset... * Extract the path component from the main .TAB filename * to build the filename of the base tables *----------------------------------------------------------------*/ m_pszPath = CPLStrdup(m_pszFname); nFnameLen = strlen(m_pszPath); for( ; nFnameLen > 0; nFnameLen--) { if (m_pszPath[nFnameLen-1] == '/' || m_pszPath[nFnameLen-1] == '\\' ) { break; } m_pszPath[nFnameLen-1] = '\0'; } /*----------------------------------------------------------------- * Open the main Index table and look for the "Table" field that * should contain the path to the base table for each rectangle MBR *----------------------------------------------------------------*/ m_poIndexTable = new TABFile; if (m_poIndexTable->Open(m_pszFname, "rb", bTestOpenNoError) != 0) { // Open Failed... an error has already been reported, just return. if (bTestOpenNoError) CPLErrorReset(); Close(); return -1; } OGRFeatureDefn *poDefn = m_poIndexTable->GetLayerDefn(); if (poDefn == NULL || (m_nTableNameField = poDefn->GetFieldIndex("Table")) == -1) { if (!bTestOpenNoError) CPLError(CE_Failure, CPLE_NotSupported, "Open Failed: Field 'Table' not found in Seamless " "Dataset '%s'. This is type of file not currently " "supported.", m_pszFname); Close(); return -1; } /* Set the number of bits required to encode features for this index * table. (Based of the number of features) */ int s=0, numFeatures = m_poIndexTable->GetFeatureCount(FALSE); do s++, numFeatures>>=1; while(numFeatures); m_nIndexTableFIDBits= s+1; /*----------------------------------------------------------------- * We need to open the first table to get its FeatureDefn *----------------------------------------------------------------*/ if (OpenBaseTable(-1, bTestOpenNoError) != 0 ) { // Open Failed... an error has already been reported, just return. if (bTestOpenNoError) CPLErrorReset(); Close(); return -1; } CPLAssert(m_poCurBaseTable); m_poFeatureDefnRef = m_poCurBaseTable->GetLayerDefn(); m_poFeatureDefnRef->Reference(); return 0; }
/********************************************************************** * TABIDFile::Open() * * Open a .ID file, and initialize the structures to be ready to read * objects from it. * * If the filename that is passed in contains a .MAP extension then * the extension will be changed to .ID before trying to open the file. * * Returns 0 on success, -1 on error. **********************************************************************/ int TABIDFile::Open(const char *pszFname, TABAccess eAccess) { 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 in Write mode we need TABReadWrite since we do random * updates in the index as data blocks are split *----------------------------------------------------------------*/ const char* pszAccess = NULL; if (eAccess == TABRead) { m_eAccessMode = TABRead; pszAccess = "rb"; } else if (eAccess == TABWrite) { m_eAccessMode = TABReadWrite; pszAccess = "wb+"; } else if (eAccess == TABReadWrite) { m_eAccessMode = TABReadWrite; pszAccess = "rb+"; } else { CPLError(CE_Failure, CPLE_FileIO, "Open() failed: access mode \"%d\" not supported", eAccess); return -1; } /*----------------------------------------------------------------- * Change .MAP extension to .ID if necessary *----------------------------------------------------------------*/ m_pszFname = CPLStrdup(pszFname); int nLen = static_cast<int>(strlen(m_pszFname)); if (nLen > 4 && strcmp(m_pszFname+nLen-4, ".MAP")==0) strcpy(m_pszFname+nLen-4, ".ID"); else if (nLen > 4 && strcmp(m_pszFname+nLen-4, ".map")==0) strcpy(m_pszFname+nLen-4, ".id"); /*----------------------------------------------------------------- * Change .MAP extension to .ID if necessary *----------------------------------------------------------------*/ #ifndef _WIN32 TABAdjustFilenameExtension(m_pszFname); #endif /*----------------------------------------------------------------- * Open file *----------------------------------------------------------------*/ m_fp = VSIFOpenL(m_pszFname, pszAccess); 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 || m_eAccessMode == TABReadWrite) { /*------------------------------------------------------------- * READ access: * Establish the number of object IDs from the size of the file *------------------------------------------------------------*/ VSIStatBufL sStatBuf; if ( VSIStatL(m_pszFname, &sStatBuf) == -1 ) { CPLError(CE_Failure, CPLE_FileIO, "stat() failed for %s\n", m_pszFname); Close(); return -1; } if( static_cast<vsi_l_offset>(sStatBuf.st_size) > static_cast<vsi_l_offset>(INT_MAX / 4) ) m_nMaxId = INT_MAX / 4; else m_nMaxId = (int)(sStatBuf.st_size/4); m_nBlockSize = MIN(1024, m_nMaxId*4); /*------------------------------------------------------------- * Read the first block from the file *------------------------------------------------------------*/ m_poIDBlock = new TABRawBinBlock(m_eAccessMode, FALSE); if (m_nMaxId == 0) { // .ID file size = 0 ... just allocate a blank block but // it won't get really used anyways. m_nBlockSize = 512; m_poIDBlock->InitNewBlock(m_fp, m_nBlockSize, 0); } else if (m_poIDBlock->ReadFromFile(m_fp, 0, m_nBlockSize) != 0) { // CPLError() has already been called. Close(); return -1; } } else { /*------------------------------------------------------------- * WRITE access: * Get ready to write to the file *------------------------------------------------------------*/ m_poIDBlock = new TABRawBinBlock(m_eAccessMode, FALSE); m_nMaxId = 0; m_nBlockSize = 1024; m_poIDBlock->InitNewBlock(m_fp, m_nBlockSize, 0); } return 0; }
/********************************************************************** * TABIDFile::Open() * * Open a .ID file, and initialize the structures to be ready to read * objects from it. * * If the filename that is passed in contains a .MAP extension then * the extension will be changed to .ID before trying to open the file. * * Returns 0 on success, -1 on error. **********************************************************************/ int TABIDFile::Open(const char *pszFname, const char *pszAccess) { 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. *----------------------------------------------------------------*/ 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 .MAP extension to .ID if necessary *----------------------------------------------------------------*/ m_pszFname = CPLStrdup(pszFname); nLen = strlen(m_pszFname); if (nLen > 4 && strcmp(m_pszFname+nLen-4, ".MAP")==0) strcpy(m_pszFname+nLen-4, ".ID"); else if (nLen > 4 && strcmp(m_pszFname+nLen-4, ".map")==0) strcpy(m_pszFname+nLen-4, ".id"); /*----------------------------------------------------------------- * Change .MAP extension to .ID if necessary *----------------------------------------------------------------*/ #ifndef _WIN32 TABAdjustFilenameExtension(m_pszFname); #endif /*----------------------------------------------------------------- * Open file *----------------------------------------------------------------*/ m_fp = VSIFOpen(m_pszFname, pszAccess); 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: * Establish the number of object IDs from the size of the file *------------------------------------------------------------*/ VSIStatBuf sStatBuf; if ( VSIStat(m_pszFname, &sStatBuf) == -1 ) { CPLError(CE_Failure, CPLE_FileIO, "stat() failed for %s\n", m_pszFname); Close(); return -1; } m_nMaxId = sStatBuf.st_size/4; m_nBlockSize = MIN(1024, m_nMaxId*4); /*------------------------------------------------------------- * Read the first block from the file *------------------------------------------------------------*/ m_poIDBlock = new TABRawBinBlock(m_eAccessMode, FALSE); if (m_nMaxId == 0) { // .ID file size = 0 ... just allocate a blank block but // it won't get really used anyways. m_nBlockSize = 512; m_poIDBlock->InitNewBlock(m_fp, m_nBlockSize, 0); } else if (m_poIDBlock->ReadFromFile(m_fp, 0, m_nBlockSize) != 0) { // CPLError() has already been called. Close(); return -1; } } else { /*------------------------------------------------------------- * WRITE access: * Get ready to write to the file *------------------------------------------------------------*/ m_poIDBlock = new TABRawBinBlock(m_eAccessMode, FALSE); m_nMaxId = 0; m_nBlockSize = 1024; m_poIDBlock->InitNewBlock(m_fp, m_nBlockSize, 0); } return 0; }
/********************************************************************** * IMapInfoFile::SmartOpen() * * Use this static method to automatically open any flavor of MapInfo * dataset. This method will detect the file type, create an object * of the right type, and open the file. * * Call GetFileClass() on the returned object if you need to find out * its exact type. (To access format-specific methods for instance) * * Returns the new object ptr. , or NULL if the open failed. **********************************************************************/ IMapInfoFile *IMapInfoFile::SmartOpen(const char *pszFname, GBool bUpdate, GBool bTestOpenNoError /*=FALSE*/) { IMapInfoFile *poFile = nullptr; int nLen = 0; if (pszFname) nLen = static_cast<int>(strlen(pszFname)); if (nLen > 4 && (EQUAL(pszFname + nLen-4, ".MIF") || EQUAL(pszFname + nLen-4, ".MID") ) ) { /*------------------------------------------------------------- * MIF/MID file *------------------------------------------------------------*/ poFile = new MIFFile; } else if (nLen > 4 && EQUAL(pszFname + nLen-4, ".TAB")) { /*------------------------------------------------------------- * .TAB file ... is it a TABFileView or a TABFile? * We have to read the .tab header to find out. *------------------------------------------------------------*/ char *pszAdjFname = CPLStrdup(pszFname); GBool bFoundFields = FALSE; GBool bFoundView = FALSE; GBool bFoundSeamless = FALSE; TABAdjustFilenameExtension(pszAdjFname); VSILFILE *fp = VSIFOpenL(pszAdjFname, "r"); const char *pszLine = nullptr; while(fp && (pszLine = CPLReadLineL(fp)) != nullptr) { while (isspace(static_cast<unsigned char>(*pszLine))) pszLine++; if (STARTS_WITH_CI(pszLine, "Fields")) bFoundFields = TRUE; else if (STARTS_WITH_CI(pszLine, "create view")) bFoundView = TRUE; else if (STARTS_WITH_CI(pszLine, "\"\\IsSeamless\" = \"TRUE\"")) bFoundSeamless = TRUE; } if (bFoundView) poFile = new TABView; else if (bFoundFields && bFoundSeamless) poFile = new TABSeamless; else if (bFoundFields) poFile = new TABFile; if (fp) VSIFCloseL(fp); CPLFree(pszAdjFname); } /*----------------------------------------------------------------- * Perform the open() call *----------------------------------------------------------------*/ if (poFile && poFile->Open(pszFname, bUpdate ? TABReadWrite : TABRead, bTestOpenNoError) != 0) { delete poFile; poFile = nullptr; } if (!bTestOpenNoError && poFile == nullptr) { CPLError(CE_Failure, CPLE_FileIO, "%s could not be opened as a MapInfo dataset.", pszFname); } return poFile; }