GDALDriverManager::GetDriver

GDALDriver * GDALDriverManager::GetDriver( int iDriver )

{
    CPLMutexHolderD( &hDMMutex );

    return GetDriver_unlocked(iDriver);
}


/************************************************************************/
/*                             GDALOpenEx()                             */
/************************************************************************/

/**
 * \brief Open a raster or vector file as a GDALDataset.
 *
 * This function will try to open the passed file, or virtual dataset
 * name by invoking the Open method of each registered GDALDriver in turn.
 * The first successful open will result in a returned dataset.  If all
 * drivers fail then NULL is returned and an error is issued.
 *
 * Several recommendations :
 * <ul>
 * <li>If you open a dataset object with GDAL_OF_UPDATE access, it is not
 * recommended to open a new dataset on the same underlying file.</li>
 * <li>The returned dataset should only be accessed by one thread at a time. If
 * you want to use it from different threads, you must add all necessary code
 * (mutexes, etc.)  to avoid concurrent use of the object. (Some drivers, such
 * as GeoTIFF, maintain internal state variables that are updated each time a
 * new block is read, thus preventing concurrent use.) </li>
 * </ul>
 *
 * For drivers supporting the VSI virtual file API, it is possible to open a
 * file in a .zip archive (see VSIInstallZipFileHandler()), in a
 * .tar/.tar.gz/.tgz archive (see VSIInstallTarFileHandler()) or on a HTTP / FTP
 * server (see VSIInstallCurlFileHandler())
 *
 * In some situations (dealing with unverified data), the datasets can be opened
 * in another process through the \ref gdal_api_proxy mechanism.
 *
 * In order to reduce the need for searches through the operating system
 * file system machinery, it is possible to give an optional list of files with
 * the papszSiblingFiles parameter.
 * This is the list of all files at the same level in the file system as the
 * target file, including the target file. The filenames must not include any
 * path components, are essentially just the output of VSIReadDir() on the
 * parent directory. If the target object does not have filesystem semantics
 * then the file list should be NULL.
 *
 * @param pszFilename the name of the file to access.  In the case of
 * exotic drivers this may not refer to a physical file, but instead contain
 * information for the driver on how to access a dataset.  It should be in UTF-8
 * encoding.
 *
 * @param nOpenFlags a combination of GDAL_OF_ flags that may be combined
 * through logical or operator.
 * <ul>
 * <li>Driver kind: GDAL_OF_RASTER for raster drivers, GDAL_OF_VECTOR for vector
 *     drivers.  If none of the value is specified, both kinds are implied.</li>
 * <li>Access mode: GDAL_OF_READONLY (exclusive)or GDAL_OF_UPDATE.</li>
 * <li>Shared mode: GDAL_OF_SHARED. If set, it allows the sharing of GDALDataset
 * handles for a dataset with other callers that have set GDAL_OF_SHARED.
 * In particular, GDALOpenEx() will first consult its list of currently
 * open and shared GDALDataset's, and if the GetDescription() name for one
 * exactly matches the pszFilename passed to GDALOpenEx() it will be
 * referenced and returned, if GDALOpenEx() is called from the same thread.</li>
 * <li>Verbose error: GDAL_OF_VERBOSE_ERROR. If set, a failed attempt to open
 * the file will lead to an error message to be reported.</li>
 * </ul>
 *
 * @param papszAllowedDrivers NULL to consider all candidate drivers, or a NULL
 * terminated list of strings with the driver short names that must be
 * considered.
 *
 * @param papszOpenOptions NULL, or a NULL terminated list of strings with open
 * options passed to candidate drivers. An option exists for all drivers,
 * OVERVIEW_LEVEL=level, to select a particular overview level of a dataset.
 * The level index starts at 0. The level number can be suffixed by "only" to
 * specify that only this overview level must be visible, and not sub-levels.
 * Open options are validated by default, and a warning is emitted in case the
 * option is not recognized. In some scenarios, it might be not desirable (e.g.
 * when not knowing which driver will open the file), so the special open option
 * VALIDATE_OPEN_OPTIONS can be set to NO to avoid such warnings. Alternatively,
 * since GDAL 2.1, an option name can be preceded by the @ character to indicate
 * that it may not cause a warning if the driver doesn't declare this option.
 *
 * @param papszSiblingFiles NULL, or a NULL terminated list of strings that are
 * filenames that are auxiliary to the main filename. If NULL is passed, a
 * probing of the file system will be done.
 *
 * @return A GDALDatasetH handle or NULL on failure.  For C++ applications
 * this handle can be cast to a GDALDataset *.
 *
 * @since GDAL 2.0
 */

GDALDatasetH CPL_STDCALL GDALOpenEx( const char *pszFilename,
                                     unsigned int nOpenFlags,
                                     const char *const *papszAllowedDrivers,
                                     const char *const *papszOpenOptions,
                                     const char *const *papszSiblingFiles )
{
    VALIDATE_POINTER1(pszFilename, "GDALOpen", nullptr);

/* -------------------------------------------------------------------- */
/*      In case of shared dataset, first scan the existing list to see  */
/*      if it could already contain the requested dataset.              */
/* -------------------------------------------------------------------- */
    if( nOpenFlags & GDAL_OF_SHARED )
    {
        if( nOpenFlags & GDAL_OF_INTERNAL )
        {
            CPLError(CE_Failure, CPLE_IllegalArg,
                     "GDAL_OF_SHARED and GDAL_OF_INTERNAL are exclusive");
            return nullptr;
        }

        CPLMutexHolderD(&hDLMutex);

        if (phSharedDatasetSet != nullptr)
        {
            const GIntBig nThisPID = GDALGetResponsiblePIDForCurrentThread();
            SharedDatasetCtxt sStruct;

            sStruct.nPID = nThisPID;
            sStruct.pszDescription = const_cast<char *>(pszFilename);
            sStruct.eAccess =
                (nOpenFlags & GDAL_OF_UPDATE) ? GA_Update : GA_ReadOnly;
            SharedDatasetCtxt *psStruct = static_cast<SharedDatasetCtxt *>(
                CPLHashSetLookup(phSharedDatasetSet, &sStruct));
            if (psStruct == nullptr && (nOpenFlags & GDAL_OF_UPDATE) == 0)
            {
                sStruct.eAccess = GA_Update;
                psStruct = static_cast<SharedDatasetCtxt *>(
                    CPLHashSetLookup(phSharedDatasetSet, &sStruct));
            }
            if (psStruct)
            {
                psStruct->poDS->Reference();
                return psStruct->poDS;
            }
        }
    }

    // If no driver kind is specified, assume all are to be probed.
    if( (nOpenFlags & GDAL_OF_KIND_MASK) == 0 )
        nOpenFlags |= GDAL_OF_KIND_MASK;

    GDALDriverManager *poDM = GetGDALDriverManager();
    // CPLLocaleC  oLocaleForcer;

    CPLErrorReset();
    VSIErrorReset();
    CPLAssert(nullptr != poDM);

    // Build GDALOpenInfo just now to avoid useless file stat'ing if a
    // shared dataset was asked before.
    GDALOpenInfo oOpenInfo(pszFilename, nOpenFlags,
                           const_cast<char **>(papszSiblingFiles));
    oOpenInfo.papszAllowedDrivers = papszAllowedDrivers;

    // Prevent infinite recursion.
    {
        int *pnRecCount =
            static_cast<int *>(CPLGetTLS(CTLS_GDALDATASET_REC_PROTECT_MAP));
        if( pnRecCount == nullptr )
        {
            pnRecCount = static_cast<int *>(CPLMalloc(sizeof(int)));
            *pnRecCount = 0;
            CPLSetTLS(CTLS_GDALDATASET_REC_PROTECT_MAP, pnRecCount, TRUE);
        }
        if( *pnRecCount == 100 )
        {
            CPLError(CE_Failure, CPLE_AppDefined,
                     "GDALOpen() called with too many recursion levels");
            return nullptr;
        }
        (*pnRecCount)++;
    }

    // Remove leading @ if present.
    char **papszOpenOptionsCleaned =
        CSLDuplicate(const_cast<char **>(papszOpenOptions));
    for(char **papszIter = papszOpenOptionsCleaned; papszIter && *papszIter;
        ++papszIter)
    {
        char *pszOption = *papszIter;
        if( pszOption[0] == '@' )
            memmove(pszOption, pszOption + 1, strlen(pszOption + 1) + 1);
    }

    oOpenInfo.papszOpenOptions = papszOpenOptionsCleaned;

    for( int iDriver = -1; iDriver < poDM->GetDriverCount(); ++iDriver )
    {
        GDALDriver *poDriver = nullptr;

        if( iDriver < 0 )
        {
            poDriver = GDALGetAPIPROXYDriver();
        }
        else
        {
            poDriver = poDM->GetDriver(iDriver);
            if (papszAllowedDrivers != nullptr &&
                CSLFindString(papszAllowedDrivers,
                              GDALGetDriverShortName(poDriver)) == -1)
                continue;
        }

        if( (nOpenFlags & GDAL_OF_RASTER) != 0 &&
            (nOpenFlags & GDAL_OF_VECTOR) == 0 &&
            poDriver->GetMetadataItem(GDAL_DCAP_RASTER) == nullptr )
            continue;
        if( (nOpenFlags & GDAL_OF_VECTOR) != 0 &&
            (nOpenFlags & GDAL_OF_RASTER) == 0 &&
            poDriver->GetMetadataItem(GDAL_DCAP_VECTOR) == nullptr )
            continue;

        // Remove general OVERVIEW_LEVEL open options from list before passing
        // it to the driver, if it isn't a driver specific option already.
        char **papszTmpOpenOptions = nullptr;
        char **papszTmpOpenOptionsToValidate = nullptr;
        char **papszOptionsToValidate = const_cast<char **>(papszOpenOptions);
        if( CSLFetchNameValue(papszOpenOptionsCleaned, "OVERVIEW_LEVEL") !=
               nullptr &&
            (poDriver->GetMetadataItem(GDAL_DMD_OPENOPTIONLIST) == nullptr ||
             CPLString(poDriver->GetMetadataItem(GDAL_DMD_OPENOPTIONLIST))
                    .ifind("OVERVIEW_LEVEL") == std::string::npos) )
        {
            papszTmpOpenOptions = CSLDuplicate(papszOpenOptionsCleaned);
            papszTmpOpenOptions =
                CSLSetNameValue(papszTmpOpenOptions, "OVERVIEW_LEVEL", nullptr);
            oOpenInfo.papszOpenOptions = papszTmpOpenOptions;

            papszOptionsToValidate = CSLDuplicate(papszOptionsToValidate);
            papszOptionsToValidate =
                CSLSetNameValue(papszOptionsToValidate, "OVERVIEW_LEVEL", nullptr);
            papszTmpOpenOptionsToValidate = papszOptionsToValidate;
        }

        const bool bIdentifyRes =
            poDriver->pfnIdentify && poDriver->pfnIdentify(&oOpenInfo) > 0;
        if( bIdentifyRes )
        {
            GDALValidateOpenOptions(poDriver, papszOptionsToValidate);
        }

#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
        const bool bFpAvailableBefore = oOpenInfo.fpL != nullptr;
        CPLErrorReset();
#endif

        GDALDataset *poDS = nullptr;
        if ( poDriver->pfnOpen != nullptr )
        {
            poDS = poDriver->pfnOpen(&oOpenInfo);
            // If we couldn't determine for sure with Identify() (it returned
            // -1), but Open() managed to open the file, post validate options.
            if( poDS != nullptr && poDriver->pfnIdentify && !bIdentifyRes )
                GDALValidateOpenOptions(poDriver, papszOptionsToValidate);
        }
        else if( poDriver->pfnOpenWithDriverArg != nullptr )
        {
            poDS = poDriver->pfnOpenWithDriverArg(poDriver, &oOpenInfo);
        }
        else
        {
            CSLDestroy(papszTmpOpenOptions);
            CSLDestroy(papszTmpOpenOptionsToValidate);
            oOpenInfo.papszOpenOptions = papszOpenOptionsCleaned;
            continue;
        }

        CSLDestroy(papszTmpOpenOptions);
        CSLDestroy(papszTmpOpenOptionsToValidate);
        oOpenInfo.papszOpenOptions = papszOpenOptionsCleaned;

        if( poDS != nullptr )
        {
            poDS->nOpenFlags = nOpenFlags;

            if( strlen(poDS->GetDescription()) == 0 )
                poDS->SetDescription(pszFilename);

            if( poDS->poDriver == nullptr )
                poDS->poDriver = poDriver;

            if( poDS->papszOpenOptions == nullptr )
            {
                poDS->papszOpenOptions = papszOpenOptionsCleaned;
                papszOpenOptionsCleaned = nullptr;
            }

            if( !(nOpenFlags & GDAL_OF_INTERNAL) )
            {
                if( CPLGetPID() != GDALGetResponsiblePIDForCurrentThread() )
                    CPLDebug("GDAL",
                             "GDALOpen(%s, this=%p) succeeds as "
                             "%s (pid=%d, responsiblePID=%d).",
                             pszFilename, poDS, poDriver->GetDescription(),
                             static_cast<int>(CPLGetPID()),
                             static_cast<int>(
                                 GDALGetResponsiblePIDForCurrentThread()));
                else
                    CPLDebug("GDAL", "GDALOpen(%s, this=%p) succeeds as %s.",
                             pszFilename, poDS, poDriver->GetDescription());

                poDS->AddToDatasetOpenList();
            }

            int *pnRecCount =
                static_cast<int *>(CPLGetTLS(CTLS_GDALDATASET_REC_PROTECT_MAP));
            if( pnRecCount )
                (*pnRecCount)--;

            if( nOpenFlags & GDAL_OF_SHARED )
            {
                if (strcmp(pszFilename, poDS->GetDescription()) != 0)
                {
                    CPLError(CE_Warning, CPLE_NotSupported,
                             "A dataset opened by GDALOpenShared should have "
                             "the same filename (%s) "
                             "and description (%s)",
                             pszFilename, poDS->GetDescription());
                }
                else
                {
                    poDS->MarkAsShared();
                }
            }

            // Deal with generic OVERVIEW_LEVEL open option, unless it is
            // driver specific.
            if( CSLFetchNameValue(papszOpenOptions, "OVERVIEW_LEVEL") != nullptr &&
                (poDriver->GetMetadataItem(GDAL_DMD_OPENOPTIONLIST) == nullptr ||
                CPLString(poDriver->GetMetadataItem(GDAL_DMD_OPENOPTIONLIST))
                        .ifind("OVERVIEW_LEVEL") == std::string::npos) )
            {
                CPLString osVal(
                    CSLFetchNameValue(papszOpenOptions, "OVERVIEW_LEVEL"));
                const int nOvrLevel = atoi(osVal);
                const bool bThisLevelOnly =
                    osVal.ifind("only") != std::string::npos;
                GDALDataset *poOvrDS = GDALCreateOverviewDataset(
                    poDS, nOvrLevel, bThisLevelOnly);
                poDS->ReleaseRef();
                poDS = poOvrDS;
                if( poDS == nullptr )
                {
                    if( nOpenFlags & GDAL_OF_VERBOSE_ERROR )
                    {
                        CPLError(CE_Failure, CPLE_OpenFailed,
                                 "Cannot open overview level %d of %s",
                                 nOvrLevel, pszFilename);
                    }
                }
            }
            VSIErrorReset();

            CSLDestroy(papszOpenOptionsCleaned);
            return poDS;
        }

#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
        if( bFpAvailableBefore && oOpenInfo.fpL == nullptr )
        {
            // In case the file descriptor was "consumed" by a driver
            // that ultimately failed, re-open it for next drivers.
            oOpenInfo.fpL = VSIFOpenL(
                pszFilename,
                (oOpenInfo.eAccess == GA_Update) ? "r+b" : "rb");
        }
#else
        if( CPLGetLastErrorNo() != 0 && CPLGetLastErrorType() > CE_Warning)
        {
            int *pnRecCount =
                static_cast<int *>(CPLGetTLS(CTLS_GDALDATASET_REC_PROTECT_MAP));
            if( pnRecCount )
                (*pnRecCount)--;

            CSLDestroy(papszOpenOptionsCleaned);
            return nullptr;
        }
#endif
    }

    CSLDestroy(papszOpenOptionsCleaned);

    if( nOpenFlags & GDAL_OF_VERBOSE_ERROR )
    {
        // Check to see if there was a filesystem error, and report it if so.
        // If not, return a more generic error.
        if(!VSIToCPLError(CE_Failure, CPLE_OpenFailed))
        {
            if( oOpenInfo.bStatOK )
            {
                CPLError(CE_Failure, CPLE_OpenFailed,
                         "`%s' not recognized as a supported file format.",
                         pszFilename);
            }
            else
            {
                // If Stat failed and no VSI error was set, assume it is because
                // the file did not exist on the filesystem.
                CPLError(CE_Failure, CPLE_OpenFailed,
                         "`%s' does not exist in the file system, "
                         "and is not recognized as a supported dataset name.",
                         pszFilename);
            }
        }
    }

    int *pnRecCount =
        static_cast<int *>(CPLGetTLS(CTLS_GDALDATASET_REC_PROTECT_MAP));
    if( pnRecCount )
        (*pnRecCount)--;

    return nullptr;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值