/**********************************************************************
 *                   TABSeamless::GetFeatureRef()
 *
 * Fill and return a TABFeature object for the specified feature id.
 *
 * The returned pointer is a reference to an object owned and maintained
 * by this TABSeamless object.  It should not be altered or freed by the 
 * caller and its contents is guaranteed to be valid only until the next
 * call to GetFeatureRef() or Close().
 *
 * Returns NULL if the specified feature id does not exist of if an
 * error happened.  In any case, CPLError() will have been called to
 * report the reason of the failure.
 **********************************************************************/
TABFeature *TABSeamless::GetFeatureRef(int nFeatureId)
{
    if (m_poIndexTable == NULL)
        return NULL; // File is not opened yet

    if (nFeatureId == m_nCurFeatureId && m_poCurFeature)
        return m_poCurFeature;

    if (m_nCurBaseTableId != ExtractBaseTableId(nFeatureId))
    {
        if (OpenBaseTable(ExtractBaseTableId(nFeatureId)) != 0)
            return NULL;
    }

    if (m_poCurBaseTable)
    {
        if (m_poCurFeature)
            delete m_poCurFeature;

        m_poCurFeature = (TABFeature*)m_poCurBaseTable->GetFeature(ExtractBaseFeatureId(nFeatureId));
        m_nCurFeatureId = nFeatureId;

        m_poCurFeature->SetFID(nFeatureId);

        return m_poCurFeature;
    }

    return NULL;
}
/**********************************************************************
 *                   TABSeamless::OpenNextBaseTable()
 *
 * Open the next base table in the dataset, using GetNextFeature() so that
 * the spatial filter is respected.
 *
 * m_bEOF will be set if there are no more base tables to read.
 *
 * Returns 0 on success, -1 on error.
 **********************************************************************/
int TABSeamless::OpenNextBaseTable(GBool bTestOpenNoError /*=FALSE*/)
{
    CPLAssert(m_poIndexTable);

    TABFeature *poIndexFeature = (TABFeature*)m_poIndexTable->GetNextFeature();
    
    if (poIndexFeature)
    {
        if (OpenBaseTable(poIndexFeature, bTestOpenNoError) != 0)
        {
            // Open Failed... an error has already been reported.
            if (bTestOpenNoError)
                CPLErrorReset();
            delete poIndexFeature;
            return -1;
        }
        delete poIndexFeature;
        m_bEOF = FALSE;
    }
    else
    {
        // Reached EOF
        m_bEOF = TRUE;
    }

    return 0;
}
void TABSeamless::ResetReading()
{
    if (m_poIndexTable)
        OpenBaseTable(-1);  // Asking for first table resets everything

    // Reset m_nCurFeatureId so that next pass via GetNextFeatureId()
    // will start from the beginning
    m_nCurFeatureId = -1;
}
/**********************************************************************
 *                   TABSeamless::OpenBaseTable()
 *
 * Open the base table for specified IndexFeature.
 *
 * Returns 0 on success, -1 on error.
 **********************************************************************/
int TABSeamless::OpenBaseTable(int nTableId, GBool bTestOpenNoError /*=FALSE*/)
{

    if (nTableId == -1)
    {
        // Open first table from dataset
        m_poIndexTable->ResetReading();
        if (OpenNextBaseTable(bTestOpenNoError) != 0)
        {
            // Open Failed... an error has already been reported.
            if (bTestOpenNoError)
                CPLErrorReset();
            return -1;
        }
    }
    else if (nTableId == m_nCurBaseTableId && m_poCurBaseTable != NULL)
    {
        // The right table is already opened.  Not much to do!
        m_poCurBaseTable->ResetReading();
        return 0;
    }
    else
    {
        TABFeature *poIndexFeature = m_poIndexTable->GetFeatureRef(nTableId);
    
        if (poIndexFeature)
        {
            if (OpenBaseTable(poIndexFeature, bTestOpenNoError) != 0)
            {
                // Open Failed... an error has already been reported.
                if (bTestOpenNoError)
                    CPLErrorReset();
                return -1;
            }
        }
    }

    return 0;
}
Exemple #5
0
/**********************************************************************
 *                   TABSeamless::GetNextFeatureId()
 *
 * Returns feature id that follows nPrevId, or -1 if it is the
 * last feature id.  Pass nPrevId=-1 to fetch the first valid feature id.
 **********************************************************************/
GIntBig TABSeamless::GetNextFeatureId(GIntBig nPrevId)
{
    if (m_poIndexTable == nullptr)
        return -1; // File is not opened yet

    if (nPrevId == -1 || m_nCurBaseTableId != ExtractBaseTableId(nPrevId))
    {
        if (OpenBaseTable(ExtractBaseTableId(nPrevId)) != 0)
            return -1;
    }

    int nId = ExtractBaseFeatureId(nPrevId);
    do
    {
        nId = (int) m_poCurBaseTable->GetNextFeatureId(nId);
        if (nId != -1)
            return EncodeFeatureId(m_nCurBaseTableId, nId);  // Found one!
        else
            OpenNextBaseTable();  // Skip to next tile and loop again
    } while (nId == -1 && !m_bEOF && m_poCurBaseTable);

    return -1;
}
Exemple #6
0
/**********************************************************************
 *                   TABSeamless::GetFeatureRef()
 *
 * Fill and return a TABFeature object for the specified feature id.
 *
 * The returned pointer is a reference to an object owned and maintained
 * by this TABSeamless object.  It should not be altered or freed by the
 * caller and its contents is guaranteed to be valid only until the next
 * call to GetFeatureRef() or Close().
 *
 * Returns NULL if the specified feature id does not exist of if an
 * error happened.  In any case, CPLError() will have been called to
 * report the reason of the failure.
 **********************************************************************/
TABFeature *TABSeamless::GetFeatureRef(GIntBig nFeatureId)
{
    if (m_poIndexTable == nullptr)
        return nullptr; // File is not opened yet

    if (nFeatureId == m_nCurFeatureId && m_poCurFeature)
        return m_poCurFeature;

    if (m_nCurBaseTableId != ExtractBaseTableId(nFeatureId))
    {
        if (OpenBaseTable(ExtractBaseTableId(nFeatureId)) != 0)
            return nullptr;
    }

    if (m_poCurBaseTable)
    {
        if (m_poCurFeature)
            delete m_poCurFeature;
        m_poCurFeature = nullptr;

        TABFeature* poCurFeature = (TABFeature*)m_poCurBaseTable->GetFeature(ExtractBaseFeatureId(nFeatureId));
        if( poCurFeature == nullptr )
            return nullptr;
        m_poCurFeature = new TABFeature(m_poFeatureDefnRef);
        m_poCurFeature->SetFrom(poCurFeature);
        delete poCurFeature;

        m_nCurFeatureId = nFeatureId;

        m_poCurFeature->SetFID(nFeatureId);

        return m_poCurFeature;
    }

    return nullptr;
}
/**********************************************************************
 *                   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;
}
Exemple #8
0
void TABSeamless::ResetReading()
{
    if (m_poIndexTable)
        OpenBaseTable(-1);  // Asking for first table resets everything
}