// Copyright 2021 Airbus Defence and Space // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #define _GNU_SOURCE 1 #include "godal.h" #include #include #include #include "cpl_port.h" #include "cpl_string.h" #include "cpl_vsi.h" #include "cpl_vsi_virtual.h" #include #include #include #include #include #include #include extern "C" { extern long long int _gogdalSizeCallback(char* key, char** errorString); extern int _gogdalMultiReadCallback(char* key, int nRanges, void* pocbuffers, void* coffsets, void* clengths, char** errorString); extern size_t _gogdalReadCallback(char* key, void* buffer, size_t off, size_t clen, char** errorString); extern int goErrorHandler(int loggerID, CPLErr lvl, int code, const char *msg); } static void godalErrorHandler(CPLErr e, CPLErrorNum n, const char* msg) { cctx *ctx = (cctx*)CPLGetErrorHandlerUserData(); assert(ctx!=nullptr); if (ctx->handlerIdx !=0) { int ret = goErrorHandler(ctx->handlerIdx, e, n, msg); if(ret!=0 && ctx->failed==0) { ctx->failed=1; } } else { //let's be strict and treat all warnings as errors if (e < CE_Warning) { fprintf(stderr, "GDAL: %s\n", msg); return; } if (ctx->errMessage == nullptr) { ctx->errMessage = (char *)malloc(strlen(msg) + 1); strcpy(ctx->errMessage, msg); } else { ctx->errMessage = (char *)realloc(ctx->errMessage, strlen(ctx->errMessage) + strlen(msg) + 3); strcat(ctx->errMessage, "\n"); strcat(ctx->errMessage, msg); } } } static void godalWrap(cctx *ctx) { CPLPushErrorHandlerEx(&godalErrorHandler,ctx); if(ctx->configOptions!=nullptr) { char **options = ctx->configOptions; for(char* option=*options; option; option=*(++options)) { char *idx = strchr(option,'='); if(idx) { *idx='\0'; CPLSetThreadLocalConfigOption(option,idx+1); *idx='='; } } } } static void godalUnwrap() { cctx *ctx = (cctx*)CPLGetErrorHandlerUserData(); CPLPopErrorHandler(); if(ctx->configOptions!=nullptr) { char **options = ctx->configOptions; for(char* option=*options; option; option=*(++options)) { char *idx = strchr(option,'='); if(idx) { *idx='\0'; CPLSetThreadLocalConfigOption(option,nullptr); *idx='='; } } } } inline int failed(cctx *ctx) { if (ctx->errMessage!=nullptr || ctx->failed!=0) { return 1; } return 0; } inline void forceError(cctx *ctx) { if (ctx->errMessage == nullptr && ctx->failed==0) { CPLError(CE_Failure, CPLE_AppDefined, "unknown error"); } } inline void forceCPLError(cctx *ctx, CPLErr err) { if (ctx->errMessage == nullptr && ctx->failed==0) { CPLError(CE_Failure, CPLE_AppDefined, "unknown cpl error %d", err); } } inline void forceOGRError(cctx *ctx, OGRErr err) { if (ctx->errMessage == nullptr && ctx->failed==0) { CPLError(CE_Failure, CPLE_AppDefined, "unknown ogr error %d", err); } } void godalSetMetadataItem(cctx *ctx, GDALMajorObjectH mo, char *ckey, char *cval, char *cdom) { godalWrap(ctx); CPLErr ret = GDALSetMetadataItem(mo,ckey,cval,cdom); if(ret!=0) { forceCPLError(ctx, ret); } godalUnwrap(); } void godalClearMetadata(cctx *ctx, GDALMajorObjectH mo, char *cdom) { godalWrap(ctx); CPLErr ret = GDALSetMetadata(mo,nullptr,cdom); if(ret!=0) { forceCPLError(ctx, ret); } godalUnwrap(); } void godalSetDescription(cctx *ctx, GDALMajorObjectH mo, char *desc) { godalWrap(ctx); GDALSetDescription(mo,desc); godalUnwrap(); } void godalSetRasterColorInterpretation(cctx *ctx, GDALRasterBandH bnd, GDALColorInterp ci) { godalWrap(ctx); CPLErr ret = GDALSetRasterColorInterpretation(bnd,ci); if(ret!=0) { forceCPLError(ctx, ret); } godalUnwrap(); } GDALDatasetH godalOpen(cctx *ctx, const char *name, unsigned int nOpenFlags, const char *const *papszAllowedDrivers, const char *const *papszOpenOptions, const char *const *papszSiblingFiles) { godalWrap(ctx); GDALDatasetH ret = GDALOpenEx(name,nOpenFlags,papszAllowedDrivers,papszOpenOptions,papszSiblingFiles); if (ret == nullptr) { forceError(ctx); } godalUnwrap(); return ret; } void godalClose(cctx *ctx, GDALDatasetH ds) { godalWrap(ctx); GDALClose(ds); godalUnwrap(); } typedef void (*fn_def)(void); int _go_registerDriver(const char *driver, const char *prefix) { char *fnname = (char*)calloc(1,strlen(driver)+strlen(prefix)+1); sprintf(fnname,"%s%s",prefix,driver); void *fcn = dlsym(RTLD_DEFAULT,fnname); free(fnname); if (fcn != nullptr) { fn_def fnptr = (fn_def)fcn; fnptr(); } else { return 1; } return 0; } int godalRegisterDriver(const char *fnname) { void *fcn = dlsym(RTLD_DEFAULT,fnname); if (fcn != nullptr) { fn_def fnptr = (fn_def)fcn; fnptr(); return 0; } return -1; } void godalRegisterPlugins(){ #if GDAL_VERSION_NUM >= GDAL_COMPUTE_VERSION(3, 8, 0) GDALRegisterPlugins(); #endif } void godalRegisterPlugin(cctx *ctx, const char *name){ godalWrap(ctx); #if GDAL_VERSION_NUM >= GDAL_COMPUTE_VERSION(3, 8, 0) CPLErr ret = GDALRegisterPlugin(name); if (ret != 0) { forceCPLError(ctx, ret); } #else CPLError(CE_Failure, CPLE_NotSupported, "GDALRegisterPlugin is only supported in GDAL version >= 3.8"); #endif godalUnwrap(); } GDALDatasetH godalCreate(cctx *ctx, GDALDriverH drv, const char* name, int width, int height, int nbands, GDALDataType dtype, char **options) { godalWrap(ctx); GDALDatasetH ret = GDALCreate(drv,name,width,height,nbands,dtype,options); if (ret==nullptr) { forceError(ctx); } godalUnwrap(); return ret; } void godalDatasetSetSpatialRef(cctx *ctx, GDALDatasetH ds, OGRSpatialReferenceH sr) { godalWrap(ctx); CPLErr ret = GDALSetSpatialRef(ds,sr); if (ret!=0) { forceCPLError(ctx,ret); } godalUnwrap(); } char *exportToWKT(cctx *ctx, OGRSpatialReferenceH sr) { char *pszSRS = nullptr; OGRErr gret = OSRExportToWkt(sr,&pszSRS); if (gret!=OGRERR_NONE && !failed(ctx)) { forceOGRError(ctx, gret); } if(failed(ctx)) { CPLFree(pszSRS); pszSRS=nullptr; } /*TODO: handle wkt2 retry if (gret!=OGRERR_NONE || failed(ctx)) { CPLFree(pszSRS); pszSRS = nullptr; const char *const apszOptions[] = {"FORMAT=WKT2", nullptr}; gret = oOutputSRS.exportToWkt(&pszSRS, apszOptions); if (gret!=OGRERR_NONE || failed(ctx)) { forceOGRError(ctx, gret); godalUnwrap(); return; } } */ return pszSRS; } void godalSetProjection(cctx *ctx, GDALDatasetH ds, char *wkt) { godalWrap(ctx); if(wkt==nullptr||*wkt==0) { CPLErr ret = GDALSetSpatialRef(ds,nullptr); if (ret != 0) { forceCPLError(ctx, ret); } godalUnwrap(); return; } OGRSpatialReferenceH sr = OSRNewSpatialReference(nullptr); OSRSetAxisMappingStrategy(sr, OAMS_TRADITIONAL_GIS_ORDER); OGRErr gret = OSRSetFromUserInput(sr,wkt); if (gret!=OGRERR_NONE || failed(ctx)) { forceOGRError(ctx,gret); godalUnwrap(); OSRDestroySpatialReference(sr); return; } CPLErr ret = GDALSetSpatialRef(ds,sr); if (ret!=0) { forceCPLError(ctx,ret); } godalUnwrap(); OSRDestroySpatialReference(sr); } char *godalExportToWKT(cctx *ctx, OGRSpatialReferenceH sr) { godalWrap(ctx); char *pszSRS = exportToWKT(ctx, sr); godalUnwrap(); return pszSRS; } OGRSpatialReferenceH godalCreateWKTSpatialRef(cctx *ctx, char *wkt){ godalWrap(ctx); OGRSpatialReferenceH sr = OSRNewSpatialReference(nullptr); OSRSetAxisMappingStrategy(sr, OAMS_TRADITIONAL_GIS_ORDER); OGRErr gret = OSRImportFromWkt(sr, &wkt); if(gret!=0) { forceOGRError(ctx,gret); } godalUnwrap(); if( failed(ctx) ) { OSRDestroySpatialReference(sr); return nullptr; } return sr; } OGRSpatialReferenceH godalCreateProj4SpatialRef(cctx *ctx, char *proj) { godalWrap(ctx); OGRSpatialReferenceH sr = OSRNewSpatialReference(nullptr); OSRSetAxisMappingStrategy(sr, OAMS_TRADITIONAL_GIS_ORDER); OGRErr gret = OSRImportFromProj4(sr, proj); if(gret!=0) { forceOGRError(ctx,gret); } godalUnwrap(); if( failed(ctx) ) { OSRDestroySpatialReference(sr); return nullptr; } return sr; } OGRSpatialReferenceH godalCreateEPSGSpatialRef(cctx *ctx, int epsgCode) { godalWrap(ctx); OGRSpatialReferenceH sr = OSRNewSpatialReference(nullptr); OSRSetAxisMappingStrategy(sr, OAMS_TRADITIONAL_GIS_ORDER); OGRErr gret = OSRImportFromEPSG(sr, epsgCode); if(gret!=0) { forceOGRError(ctx,gret); } godalUnwrap(); if( failed(ctx) ) { OSRDestroySpatialReference(sr); return nullptr; } return sr; } OGRSpatialReferenceH godalCreateUserSpatialRef(cctx *ctx, char *userInput) { godalWrap(ctx); OGRSpatialReferenceH sr = OSRNewSpatialReference(nullptr); OSRSetAxisMappingStrategy(sr, OAMS_TRADITIONAL_GIS_ORDER); OGRErr gret = OSRSetFromUserInput(sr, userInput); if(gret!=0) { forceOGRError(ctx,gret); } godalUnwrap(); if( failed(ctx) ) { OSRDestroySpatialReference(sr); return nullptr; } return sr; } void godalValidateSpatialRef(cctx *ctx, OGRSpatialReferenceH sr) { godalWrap(ctx); OGRErr gret = OSRValidate(sr); if(gret!=0) { forceOGRError(ctx,gret); } godalUnwrap(); } OGRCoordinateTransformationH godalNewCoordinateTransformation(cctx *ctx, OGRSpatialReferenceH src, OGRSpatialReferenceH dst) { godalWrap(ctx); OGRCoordinateTransformationH tr = OCTNewCoordinateTransformation(src,dst); if ( tr == nullptr ) { forceError(ctx); } godalUnwrap(); return tr; } void godalSetGeoTransform(cctx *ctx, GDALDatasetH ds, double *gt){ godalWrap(ctx); CPLErr ret = GDALSetGeoTransform(ds,gt); if( ret != 0 ) { forceCPLError(ctx,ret); } godalUnwrap(); } void godalGetGeoTransform(cctx *ctx, GDALDatasetH ds, double *gt){ godalWrap(ctx); CPLErr ret = GDALGetGeoTransform(ds,gt); if( ret != 0 ) { forceCPLError(ctx,ret); } godalUnwrap(); } void godalRasterSize(GDALDatasetH ds, int *xsize, int *ysize) { *xsize = GDALGetRasterXSize(ds); *ysize = GDALGetRasterYSize(ds); } GDALRasterBandH* godalBandOverviews(GDALRasterBandH bnd) { int count = GDALGetOverviewCount(bnd); if(count == 0) { return nullptr; } GDALRasterBandH *ret = (GDALRasterBandH*)malloc((count+1)*sizeof(GDALRasterBandH)); ret[count]=nullptr; for(int i=0; i 0 ) { GDALRasterBandH band = GDALGetRasterBand(ds,1); *dtype = GDALGetRasterDataType(band); GDALGetBlockSize(band,bsx,bsy); godalBandScaleOffset(band, scale, offset); } } void godalBandStructure(GDALRasterBandH bnd, int *sx, int *sy, int *bsx, int *bsy, double *scale, double *offset, int *dtype) { *sx=GDALGetRasterBandXSize(bnd); *sy=GDALGetRasterBandYSize(bnd); *dtype=GDT_Unknown; *bsx=*bsy=0; *dtype = GDALGetRasterDataType(bnd); GDALGetBlockSize(bnd, bsx, bsy); godalBandScaleOffset(bnd, scale, offset); } void godalBandRasterIO(cctx *ctx, GDALRasterBandH bnd, GDALRWFlag rw, int nDSXOff, int nDSYOff, int nDSXSize, int nDSYSize, void *pBuffer, int nBXSize, int nBYSize, GDALDataType eBDataType, int nPixelSpace, int nLineSpace, GDALRIOResampleAlg alg) { godalWrap(ctx); GDALRasterIOExtraArg exargs; INIT_RASTERIO_EXTRA_ARG(exargs); if (alg != GRIORA_NearestNeighbour) { exargs.eResampleAlg = alg; } CPLErr ret = GDALRasterIOEx(bnd, rw, nDSXOff, nDSYOff, nDSXSize, nDSYSize, pBuffer, nBXSize, nBYSize, eBDataType, nPixelSpace, nLineSpace, &exargs); if(ret!=0){ forceCPLError(ctx,ret); } godalUnwrap(); } void godalDatasetRasterIO(cctx *ctx, GDALDatasetH ds, GDALRWFlag rw, int nDSXOff, int nDSYOff, int nDSXSize, int nDSYSize, void *pBuffer, int nBXSize, int nBYSize, GDALDataType eBDataType, int nBandCount, int *panBandCount, int nPixelSpace, int nLineSpace, int nBandSpace, GDALRIOResampleAlg alg) { godalWrap(ctx); GDALRasterIOExtraArg exargs; INIT_RASTERIO_EXTRA_ARG(exargs); if (alg != GRIORA_NearestNeighbour) { exargs.eResampleAlg = alg; } CPLErr ret = GDALDatasetRasterIOEx(ds, rw, nDSXOff, nDSYOff, nDSXSize, nDSYSize, pBuffer, nBXSize, nBYSize, eBDataType, nBandCount, panBandCount, nPixelSpace, nLineSpace, nBandSpace, &exargs); if(ret!=0){ forceCPLError(ctx,ret); } godalUnwrap(); } void godalFillRaster(cctx *ctx, GDALRasterBandH bnd, double real, double imag) { godalWrap(ctx); CPLErr ret = GDALFillRaster(bnd,real,imag); if(ret!=0){ forceCPLError(ctx,ret); } godalUnwrap(); } void godalPolygonize(cctx *ctx, GDALRasterBandH in, GDALRasterBandH mask, OGRLayerH layer,int fieldIndex, char **opts) { godalWrap(ctx); if (fieldIndex >= OGR_FD_GetFieldCount(OGR_L_GetLayerDefn(layer))) { CPLError(CE_Failure, CPLE_AppDefined, "invalid fieldIndex"); godalUnwrap(); return; } CPLErr ret = GDALPolygonize(in,mask,layer,fieldIndex,opts,nullptr,nullptr); if(ret!=0){ forceCPLError(ctx,ret); } godalUnwrap(); } void godalSieveFilter(cctx *ctx, GDALRasterBandH bnd, GDALRasterBandH mask, GDALRasterBandH dst, int sizeThreshold, int connectedNess) { godalWrap(ctx); CPLErr ret = GDALSieveFilter(bnd,mask,dst,sizeThreshold,connectedNess,nullptr,nullptr,nullptr); if(ret!=0){ forceCPLError(ctx,ret); } godalUnwrap(); } void godalFillNoData(cctx *ctx, GDALRasterBandH in, GDALRasterBandH mask, int maxDistance, int iterations, char **opts) { godalWrap(ctx); CPLErr ret = GDALFillNodata(in,mask,maxDistance,0,iterations,opts,nullptr,nullptr); if(ret!=0){ forceCPLError(ctx,ret); } godalUnwrap(); } GDALDatasetH godalRasterize(cctx *ctx, char *dstName, GDALDatasetH dstDS, GDALDatasetH ds, char **switches) { godalWrap(ctx); GDALRasterizeOptions *ropts = GDALRasterizeOptionsNew(switches,nullptr); if(failed(ctx)) { GDALRasterizeOptionsFree(ropts); godalUnwrap(); return nullptr; } int usageErr=0; GDALDatasetH ret = GDALRasterize(dstName, dstDS, ds, ropts, &usageErr); GDALRasterizeOptionsFree(ropts); if(ret==nullptr || usageErr!=0) { forceError(ctx); } godalUnwrap(); return ret; } void godalRasterizeGeometry(cctx *ctx, GDALDatasetH ds, OGRGeometryH geom, int *bands, int nBands, double *vals, int allTouched) { const char *opts[2] = { "ALL_TOUCHED=TRUE",nullptr }; char **copts=(char**)opts; if (!allTouched) { copts=nullptr; } godalWrap(ctx); CPLErr ret = GDALRasterizeGeometries(ds,nBands,bands,1,&geom,nullptr,nullptr,vals,copts,nullptr,nullptr); if(ret!=0){ forceCPLError(ctx,ret); } godalUnwrap(); } void godalLayerDeleteFeature(cctx *ctx, OGRLayerH layer, OGRFeatureH feat) { godalWrap(ctx); GIntBig fid = OGR_F_GetFID(feat); if (fid == OGRNullFID) { CPLError(CE_Failure, CPLE_AppDefined, "cannot delete feature with no FID"); godalUnwrap(); return; } OGRErr gret = OGR_L_DeleteFeature(layer,fid); if(gret!=0){ forceOGRError(ctx,gret); } godalUnwrap(); } void godalLayerSetFeature(cctx *ctx, OGRLayerH layer, OGRFeatureH feat) { godalWrap(ctx); OGRErr gret = OGR_L_SetFeature(layer,feat); if(gret!=0){ forceOGRError(ctx,gret); } godalUnwrap(); } void godalLayerSetGeometryColumnName(cctx *ctx, OGRLayerH layer, char *name) { godalWrap(ctx); #if GDAL_VERSION_NUM >= GDAL_COMPUTE_VERSION(3, 6, 0) OGRGeomFieldDefnH fieldWithNewName = OGR_GFld_Create(name, OGRwkbGeometryType(0)); OGRErr gret = OGR_L_AlterGeomFieldDefn(layer, 0, fieldWithNewName, ALTER_GEOM_FIELD_DEFN_NAME_FLAG); if(gret!=0){ forceOGRError(ctx,gret); } #else CPLError(CE_Failure, CPLE_NotSupported, "OGR_L_AlterGeomFieldDefn is only supported in GDAL version >= 3.6"); #endif godalUnwrap(); } void godalFeatureSetGeometryColumnName(cctx *ctx, OGRFeatureH feat, char *name) { godalWrap(ctx); OGRGeomFieldDefnH gfdef = OGR_F_GetGeomFieldDefnRef(feat, 0); if(gfdef != nullptr){ OGR_GFld_SetName(gfdef, name); } godalUnwrap(); } void godalFeatureSetGeometry(cctx *ctx, OGRFeatureH feat, OGRGeometryH geom) { godalWrap(ctx); OGRErr gret = OGR_F_SetGeometry(feat,geom); if(gret!=0){ forceOGRError(ctx,gret); } godalUnwrap(); } void godalFeatureSetFieldInteger(cctx *ctx, OGRFeatureH feat, int fieldIndex, int value) { godalWrap(ctx); OGR_F_SetFieldInteger(feat, fieldIndex, value); godalUnwrap(); } void godalFeatureSetFieldInteger64(cctx *ctx, OGRFeatureH feat, int fieldIndex, long long value) { godalWrap(ctx); OGR_F_SetFieldInteger64(feat, fieldIndex, value); godalUnwrap(); } void godalFeatureSetFieldDouble(cctx *ctx, OGRFeatureH feat, int fieldIndex, double value) { godalWrap(ctx); OGR_F_SetFieldDouble(feat, fieldIndex, value); godalUnwrap(); } void godalFeatureSetFieldString(cctx *ctx, OGRFeatureH feat, int fieldIndex, char *value) { godalWrap(ctx); OGR_F_SetFieldString(feat, fieldIndex, value); godalUnwrap(); } void godalFeatureSetFieldDateTime(cctx *ctx, OGRFeatureH feat, int fieldIndex, int year, int month, int day, int hour, int minute, int second, int tzFlag) { godalWrap(ctx); OGR_F_SetFieldDateTime(feat, fieldIndex, year, month, day, hour, minute, second, tzFlag); godalUnwrap(); } void godalFeatureSetFieldIntegerList(cctx *ctx, OGRFeatureH feat, int fieldIndex, int nbValues, int *values) { godalWrap(ctx); OGR_F_SetFieldIntegerList(feat, fieldIndex, nbValues, values); godalUnwrap(); } void godalFeatureSetFieldInteger64List(cctx *ctx, OGRFeatureH feat, int fieldIndex, int nbValues, long long *values) { godalWrap(ctx); OGR_F_SetFieldInteger64List(feat, fieldIndex, nbValues, values); godalUnwrap(); } void godalFeatureSetFieldDoubleList(cctx *ctx, OGRFeatureH feat, int fieldIndex, int nbValues, double *values) { godalWrap(ctx); OGR_F_SetFieldDoubleList(feat, fieldIndex, nbValues, values); godalUnwrap(); } void godalFeatureSetFieldStringList(cctx *ctx, OGRFeatureH feat, int fieldIndex, char **values) { godalWrap(ctx); OGR_F_SetFieldStringList(feat, fieldIndex, values); godalUnwrap(); } void godalFeatureSetFieldBinary(cctx *ctx, OGRFeatureH feat, int fieldIndex, int nbBytes, void *value) { godalWrap(ctx); OGR_F_SetFieldBinary(feat, fieldIndex, nbBytes, value); godalUnwrap(); } void godal_OGR_G_AddGeometry(cctx *ctx, OGRGeometryH geom, OGRGeometryH subGeom) { godalWrap(ctx); OGRErr gret = OGR_G_AddGeometry(geom,subGeom); if(gret!=0){ forceOGRError(ctx,gret); } godalUnwrap(); } OGRGeometryH godal_OGR_G_Simplify(cctx *ctx, OGRGeometryH in, double tolerance) { godalWrap(ctx); OGRGeometryH ret = OGR_G_Simplify(in,tolerance); if(ret==nullptr) { forceError(ctx); } godalUnwrap(); return ret; } OGRGeometryH godal_OGR_G_Buffer(cctx *ctx, OGRGeometryH in, double tolerance, int segments) { godalWrap(ctx); OGRGeometryH ret = OGR_G_Buffer(in,tolerance,segments); if(ret==nullptr) { forceError(ctx); } godalUnwrap(); return ret; } OGRGeometryH godal_OGR_G_Difference(cctx *ctx, OGRGeometryH geom1, OGRGeometryH geom2) { godalWrap(ctx); OGRGeometryH ret = OGR_G_Difference(geom1, geom2); if(ret==nullptr) { forceError(ctx); } godalUnwrap(); return ret; } OGRGeometryH godal_OGR_G_GetGeometryRef(cctx *ctx, OGRGeometryH in, int subGeomIndex) { godalWrap(ctx); OGRGeometryH ret = OGR_G_GetGeometryRef(in, subGeomIndex); if(ret==nullptr) { forceError(ctx); } godalUnwrap(); return ret; } int godal_OGR_G_Intersects(cctx *ctx, OGRGeometryH geom1, OGRGeometryH geom2) { godalWrap(ctx); int ret = OGR_G_Intersects(geom1, geom2); godalUnwrap(); return ret; } OGRGeometryH godal_OGR_G_Intersection(cctx *ctx, OGRGeometryH geom1, OGRGeometryH geom2) { godalWrap(ctx); OGRGeometryH ret = OGR_G_Intersection(geom1, geom2); if(ret==nullptr) { forceError(ctx); } godalUnwrap(); return ret; } OGRGeometryH godal_OGR_G_Union(cctx *ctx, OGRGeometryH geom1, OGRGeometryH geom2) { godalWrap(ctx); OGRGeometryH ret = OGR_G_Union(geom1, geom2); if(ret==nullptr) { forceError(ctx); } godalUnwrap(); return ret; } OGRLayerH godalCreateLayer(cctx *ctx, GDALDatasetH ds, char *name, OGRSpatialReferenceH sr, OGRwkbGeometryType gtype) { godalWrap(ctx); OGRLayerH ret = OGR_DS_CreateLayer(ds,name,sr,gtype,nullptr); if(ret==nullptr) { forceError(ctx); } godalUnwrap(); return ret; } OGRLayerH godalCopyLayer(cctx *ctx, GDALDatasetH ds, OGRLayerH layer, char *name) { godalWrap(ctx); OGRLayerH ret = OGR_DS_CopyLayer(ds,layer, name,nullptr); if(ret==nullptr) { forceError(ctx); } godalUnwrap(); return ret; } void godalLayerGetExtent(cctx *ctx, OGRLayerH layer, OGREnvelope *envelope) { godalWrap(ctx); OGRErr gret = OGR_L_GetExtent(layer, envelope, 1); if (gret != OGRERR_NONE) { forceOGRError(ctx,gret); } else if(envelope==nullptr) { forceError(ctx); } godalUnwrap(); } void godalLayerFeatureCount(cctx *ctx, OGRLayerH layer, int *count) { godalWrap(ctx); GIntBig gcount = OGR_L_GetFeatureCount(layer, 1); *count=(int)gcount; godalUnwrap(); } void godalGetColorTable(GDALRasterBandH bnd, GDALPaletteInterp *interp, int *nEntries, short **entries) { GDALColorTableH ct = GDALGetRasterColorTable(bnd); if( ct == nullptr ) { *interp=GPI_Gray; *nEntries=0; *entries=nullptr; return; } *interp = GDALGetPaletteInterpretation(ct); *nEntries = GDALGetColorEntryCount(ct); *entries = (short*)malloc(*nEntries*4*sizeof(short)); for (int i=0;i<*nEntries;i++) { const GDALColorEntry *ce = GDALGetColorEntry(ct,i); (*entries)[i*4]=ce->c1; (*entries)[i*4+1]=ce->c2; (*entries)[i*4+2]=ce->c3; (*entries)[i*4+3]=ce->c4; } } void godalSetColorTable(cctx *ctx, GDALRasterBandH bnd, GDALPaletteInterp interp, int nEntries, short *entries) { godalWrap(ctx); CPLErr gret; if (nEntries == 0) { gret = GDALSetRasterColorTable(bnd, nullptr); } else { GDALColorTableH ct = GDALCreateColorTable(interp); for (int i = nEntries - 1; i >= 0; i--) { GDALColorEntry gce = {entries[i * 4], entries[i * 4 + 1], entries[i * 4 + 2], entries[i * 4 + 3]}; GDALSetColorEntry(ct, i, &gce); } gret = GDALSetRasterColorTable(bnd, ct); GDALDestroyColorTable(ct); } if (gret != 0) { forceOGRError(ctx,gret); } godalUnwrap(); } VSILFILE *godalVSIOpen(cctx *ctx, const char *name) { godalWrap(ctx); VSILFILE *fp = VSIFOpenExL(name,"r",1); if(fp==nullptr) { forceError(ctx); } if(failed(ctx)&&fp!=nullptr) { VSIFCloseL(fp); fp=nullptr; } godalUnwrap(); return fp; } void godalVSIUnlink(cctx *ctx, const char *fname) { godalWrap(ctx); int ret = VSIUnlink(fname); if(ret!=0) { forceError(ctx); } godalUnwrap(); } char* godalVSIClose(VSILFILE *f) { cctx ctx{nullptr,0,0,nullptr}; godalWrap(&ctx); int ret = VSIFCloseL(f); if(ret!=0) { forceError(&ctx); } godalUnwrap(); return ctx.errMessage; } size_t godalVSIRead(VSILFILE *f, void *buf, int len, char **errmsg) { cctx ctx{nullptr,0,0,nullptr}; godalWrap(&ctx); size_t read = VSIFReadL(buf,1,len,f); godalUnwrap(); *errmsg=ctx.errMessage; return read; } void godalRasterHistogram(cctx *ctx, GDALRasterBandH bnd, double *min, double *max, int *buckets, unsigned long long **values, int bIncludeOutOfRange, int bApproxOK) { godalWrap(ctx); CPLErr ret = CE_None; if (*buckets == 0) { ret=GDALGetDefaultHistogramEx(bnd,min,max,buckets,values,1,nullptr,nullptr); } else { *values = (unsigned long long*) VSIMalloc(*buckets*sizeof(GUIntBig)); ret=GDALGetRasterHistogramEx(bnd,*min,*max,*buckets,*values,bIncludeOutOfRange,bApproxOK,nullptr,nullptr); } if (ret != 0) { forceCPLError(ctx,ret); } godalUnwrap(); } void godalComputeRasterStatistics(cctx *ctx, GDALRasterBandH bnd, int bApproxOK, double *pdfMin, double *pdfMax, double *pdfMean, double *pdfStdDev){ godalWrap(ctx); CPLErr ret = CE_None; ret = GDALComputeRasterStatistics(bnd, bApproxOK, pdfMin, pdfMax, pdfMean, pdfStdDev, nullptr, nullptr); if (ret != 0) { forceCPLError(ctx,ret); } godalUnwrap(); } int godalGetRasterStatistics(cctx *ctx, GDALRasterBandH bnd, int bApproxOK, double *pdfMin, double *pdfMax, double *pdfMean, double *pdfStdDev){ godalWrap(ctx); CPLErr ret = CE_None; ret = GDALGetRasterStatistics(bnd, bApproxOK, 0, pdfMin, pdfMax, pdfMean, pdfStdDev); if (ret != 0 && ret != CE_Warning) { forceCPLError(ctx,ret); } godalUnwrap(); return (ret == 0); } void godalSetRasterStatistics(cctx *ctx, GDALRasterBandH bnd, double dfMin, double dfMax, double dfMean, double dfStdDev){ godalWrap(ctx); CPLErr ret = CE_None; ret = GDALSetRasterStatistics(bnd, dfMin, dfMax, dfMean, dfStdDev); if (ret != 0) { forceCPLError(ctx,ret); } godalUnwrap(); } void godalClearRasterStatistics(cctx *ctx, GDALDatasetH ds){ godalWrap(ctx); #if GDAL_VERSION_NUM >= GDAL_COMPUTE_VERSION(3, 2, 0) GDALDatasetClearStatistics(ds); #else CPLError(CE_Failure, CPLE_NotSupported, "GDALDatasetClearStatistics not supported with gdal < 3.2"); #endif godalUnwrap(); } OGRGeometryH godalNewGeometryFromGeoJSON(cctx *ctx, char *geoJSON) { godalWrap(ctx); OGRGeometryH gptr = OGR_G_CreateGeometryFromJson(geoJSON); if (gptr == nullptr) { forceError(ctx); } if (failed(ctx) && gptr != nullptr) { OGR_G_DestroyGeometry(gptr); gptr = nullptr; } godalUnwrap(); return gptr; } OGRGeometryH godalNewGeometryFromWKT(cctx *ctx, char *wkt, OGRSpatialReferenceH sr) { godalWrap(ctx); OGRGeometryH gptr = nullptr; char **wktPtr = &wkt; OGRErr gret = OGR_G_CreateFromWkt(wktPtr,sr,&gptr); if (gret != OGRERR_NONE) { forceOGRError(ctx,gret); } else if(gptr==nullptr) { forceError(ctx); } if(failed(ctx) && gptr!=nullptr) { OGR_G_DestroyGeometry(gptr); gptr=nullptr; } godalUnwrap(); return gptr; } OGRGeometryH godalNewGeometryFromWKB(cctx *ctx, void *wkb, int wkbLen, OGRSpatialReferenceH sr) { godalWrap(ctx); OGRGeometryH gptr=nullptr; OGRErr gret = OGR_G_CreateFromWkb(wkb,sr,&gptr, wkbLen); if (gret != OGRERR_NONE) { forceOGRError(ctx,gret); } else if(gptr==nullptr) { forceError(ctx); } if(failed(ctx) && gptr!=nullptr) { OGR_G_DestroyGeometry(gptr); gptr=nullptr; } godalUnwrap(); return gptr; } char* godalExportGeometryWKT(cctx *ctx, OGRGeometryH in) { godalWrap(ctx); char *wkt=nullptr; OGRErr gret = OGR_G_ExportToWkt(in,&wkt); if (gret != OGRERR_NONE) { forceOGRError(ctx,gret); } else if(wkt==nullptr) { forceError(ctx); } if(failed(ctx) && wkt!=nullptr) { CPLFree(wkt); wkt=nullptr; } godalUnwrap(); return wkt; } void godalExportGeometryWKB(cctx *ctx, void **wkb, int *wkbLen, OGRGeometryH in) { godalWrap(ctx); *wkbLen=OGR_G_WkbSize(in); if (*wkbLen == 0) { *wkb=nullptr; godalUnwrap(); return; } *wkb = malloc(*wkbLen); OGRErr gret = OGR_G_ExportToIsoWkb(in,wkbNDR,(unsigned char*)*wkb); if (gret != 0) { forceOGRError(ctx,gret); free(*wkb); *wkb=nullptr; } godalUnwrap(); } char* godalExportGeometryGeoJSON(cctx *ctx, OGRGeometryH in, int precision) { godalWrap(ctx); char* opts[2]; char precOpt[64]; snprintf(precOpt,64,"COORDINATE_PRECISION=%d",precision); opts[0]=precOpt; opts[1]=nullptr; char *gj = OGR_G_ExportToJsonEx(in,opts); if (gj==nullptr) { forceError(ctx); } if (failed(ctx) && gj!=nullptr) { CPLFree(gj); gj=nullptr; } godalUnwrap(); return gj; } char* godalExportGeometryGML(cctx *ctx, OGRGeometryH in, char **switches) { godalWrap(ctx); char *gml = OGR_G_ExportToGMLEx(in, switches); if(gml==nullptr) { forceError(ctx); } if (failed(ctx) && gml!=nullptr) { CPLFree(gml); gml=nullptr; } godalUnwrap(); return gml; } void godalGeometryTransformTo(cctx *ctx, OGRGeometryH geom, OGRSpatialReferenceH sr) { godalWrap(ctx); OGRErr gret = OGR_G_TransformTo(geom,sr); if (gret != 0) { forceOGRError(ctx,gret); } OGR_G_AssignSpatialReference(geom, sr); godalUnwrap(); } void godalGeometryTransform(cctx *ctx, OGRGeometryH geom, OGRCoordinateTransformationH trn, OGRSpatialReferenceH dst) { godalWrap(ctx); OGRErr gret = OGR_G_Transform(geom,trn); if (gret != 0) { forceOGRError(ctx,gret); } OGR_G_AssignSpatialReference(geom, dst); godalUnwrap(); } void godalLayerCreateFeature(cctx *ctx, OGRLayerH layer, OGRFeatureH feat) { godalWrap(ctx); OGRErr oe = OGR_L_CreateFeature(layer,feat); if(oe != OGRERR_NONE) { forceOGRError(ctx,oe); } godalUnwrap(); } OGRFeatureH godalLayerNewFeature(cctx *ctx, OGRLayerH layer, OGRGeometryH geom) { godalWrap(ctx); OGRFeatureH hFeature = OGR_F_Create( OGR_L_GetLayerDefn( layer ) ); if(hFeature==nullptr) { forceError(ctx); godalUnwrap(); return nullptr; } OGRErr oe=OGRERR_NONE; if (hFeature!=nullptr && geom!=nullptr) { oe = OGR_F_SetGeometry(hFeature,geom); if (oe == OGRERR_NONE) { oe = OGR_L_CreateFeature(layer,hFeature); } } if(oe != OGRERR_NONE) { forceOGRError(ctx,oe); } if(failed(ctx) && hFeature!=nullptr) { OGR_F_Destroy(hFeature); hFeature=nullptr; } godalUnwrap(); return hFeature; } GDALDatasetH godalBuildVRT(cctx *ctx, char *dstName, char **sources, char **switches) { godalWrap(ctx); GDALBuildVRTOptions *ropts = GDALBuildVRTOptionsNew(switches,nullptr); if(failed(ctx)) { GDALBuildVRTOptionsFree(ropts); godalUnwrap(); return nullptr; } int usageErr=0; int nSources = 0; char **src = sources; for( char **src = sources; *src; src++) { nSources++; } GDALDatasetH ret = GDALBuildVRT(dstName, nSources, nullptr, sources, ropts, &usageErr); GDALBuildVRTOptionsFree(ropts); if(ret==nullptr || usageErr!=0) { forceError(ctx); } godalUnwrap(); return ret; } namespace cpl { /************************************************************************/ /* VSIGoFilesystemHandler */ /************************************************************************/ class VSIGoFilesystemHandler final : public VSIFilesystemHandler { CPL_DISALLOW_COPY_ASSIGN(VSIGoFilesystemHandler) private: size_t m_buffer, m_cache; public: VSIGoFilesystemHandler(size_t bufferSize, size_t cacheSize); ~VSIGoFilesystemHandler() override; VSIVirtualHandle *Open(const char *pszFilename, const char *pszAccess, bool bSetError #if GDAL_VERSION_NUM >= GDAL_COMPUTE_VERSION(3, 3, 0) , CSLConstList /*papszOptions*/ #endif ) override; int Stat(const char *pszFilename, VSIStatBufL *pStatBuf, int nFlags) override; #if GDAL_VERSION_NUM >= 3020000 char **SiblingFiles(const char *pszFilename) override; #endif int HasOptimizedReadMultiRange(const char *pszPath) override; }; /************************************************************************/ /* VSIGoHandle */ /************************************************************************/ class VSIGoHandle final : public VSIVirtualHandle { CPL_DISALLOW_COPY_ASSIGN(VSIGoHandle) private: char *m_filename; vsi_l_offset m_cur, m_size; int m_eof; public: VSIGoHandle(const char *filename, vsi_l_offset size); ~VSIGoHandle() override; #if GDAL_VERSION_NUM >= 3060000 bool HasPRead() const override; size_t PRead(void * /*pBuffer*/, size_t /* nSize */, vsi_l_offset /*nOffset*/) const override; #endif vsi_l_offset Tell() override; int Seek(vsi_l_offset nOffset, int nWhence) override; size_t Read(void *pBuffer, size_t nSize, size_t nCount) override; int ReadMultiRange(int nRanges, void **ppData, const vsi_l_offset *panOffsets, const size_t *panSizes) override; VSIRangeStatus GetRangeStatus(vsi_l_offset nOffset, vsi_l_offset nLength) override; int Eof() override; int Close() override; size_t Write(const void *pBuffer, size_t nSize, size_t nCount) override; int Flush() override; int Truncate(vsi_l_offset nNewSize) override; }; VSIGoHandle::VSIGoHandle(const char *filename, vsi_l_offset size) { m_filename = strdup(filename); m_cur = 0; m_eof = 0; m_size = size; } VSIGoHandle::~VSIGoHandle() { free(m_filename); } size_t VSIGoHandle::Write(const void *pBuffer, size_t nSize, size_t nCount) { CPLError(CE_Failure, CPLE_AppDefined, "Write not implemented for go handlers"); return -1; } int VSIGoHandle::Flush() { CPLError(CE_Failure, CPLE_AppDefined, "Flush not implemented for go handlers"); return -1; } int VSIGoHandle::Truncate(vsi_l_offset nNewSize) { CPLError(CE_Failure, CPLE_AppDefined, "Truncate not implemented for go handlers"); return -1; } int VSIGoHandle::Seek(vsi_l_offset nOffset, int nWhence) { if (nWhence == SEEK_SET) { m_cur = nOffset; } else if (nWhence == SEEK_CUR) { m_cur += nOffset; } else { m_cur = m_size; } m_eof = 0; return 0; } vsi_l_offset VSIGoHandle::Tell() { return m_cur; } int VSIGoHandle::Eof() { return m_eof; } int VSIGoHandle::Close() { return 0; } size_t VSIGoHandle::Read(void *pBuffer, size_t nSize, size_t nCount) { if (nSize * nCount == 0) { return 0; } char *err = nullptr; size_t read = _gogdalReadCallback(m_filename, pBuffer, m_cur, nSize * nCount, &err); if (err) { CPLError(CE_Failure, CPLE_AppDefined, "%s", err); errno = EIO; free(err); return 0; } if (read != nSize * nCount) { m_eof = 1; } size_t readblocks = read / nSize; m_cur += readblocks * nSize; return readblocks; } #if GDAL_VERSION_NUM >= 3060000 bool VSIGoHandle::HasPRead() const { return true; } size_t VSIGoHandle::PRead( void* pBuffer, size_t nSize, vsi_l_offset nOffset ) const { char *err = nullptr; _gogdalMultiReadCallback(m_filename, 1, &pBuffer, (void *)&nOffset, (void *)&nSize, &err); if (err) { CPLError(CE_Failure, CPLE_AppDefined, "%s", err); errno = EIO; free(err); return 0; } return nSize; } #endif int VSIGoHandle::ReadMultiRange(int nRanges, void **ppData, const vsi_l_offset *panOffsets, const size_t *panSizes) { int iRange; int nMergedRanges = 1; for (iRange = 0; iRange < nRanges - 1; iRange++) { if (panOffsets[iRange] + panSizes[iRange] != panOffsets[iRange + 1]) { nMergedRanges++; } } char *err = nullptr; if (nMergedRanges == nRanges) { int ret = _gogdalMultiReadCallback(m_filename, nRanges, (void *)ppData, (void *)panOffsets, (void *)panSizes, &err); if (err) { CPLError(CE_Failure, CPLE_AppDefined, "%s", err); errno = EIO; free(err); return -1; } return ret; } vsi_l_offset *mOffsets = new vsi_l_offset[nMergedRanges]; size_t *mSizes = new size_t[nMergedRanges]; char **mData = new char *[nMergedRanges]; int curRange = 0; mSizes[curRange] = panSizes[0]; mOffsets[curRange] = panOffsets[0]; for (iRange = 0; iRange < nRanges - 1; iRange++) { if (panOffsets[iRange] + panSizes[iRange] == panOffsets[iRange + 1]) { mSizes[curRange] += panSizes[iRange + 1]; } else { mData[curRange] = new char[mSizes[curRange]]; //start a new range curRange++; mSizes[curRange] = panSizes[iRange + 1]; mOffsets[curRange] = panOffsets[iRange + 1]; } } mData[curRange] = new char[mSizes[curRange]]; int ret = _gogdalMultiReadCallback(m_filename, nRanges, (void *)ppData, (void *)panOffsets, (void *)panSizes, &err); if (err == nullptr) { curRange = 0; size_t curOffset = panSizes[0]; memcpy(ppData[0], mData[0], panSizes[0]); for (iRange = 0; iRange < nRanges - 1; iRange++) { if (panOffsets[iRange] + panSizes[iRange] == panOffsets[iRange + 1]) { memcpy(ppData[iRange + 1], mData[curRange] + curOffset, panSizes[iRange + 1]); curOffset += panSizes[iRange + 1]; } else { curRange++; memcpy(ppData[iRange + 1], mData[curRange], panSizes[iRange + 1]); curOffset = panSizes[iRange + 1]; } } } else { CPLError(CE_Failure, CPLE_AppDefined, "%s", err); errno = EIO; free(err); ret = -1; } delete[] mOffsets; delete[] mSizes; for (int i = 0; i < nMergedRanges; i++) { delete[] mData[i]; } delete[] mData; return ret; } VSIRangeStatus VSIGoHandle::GetRangeStatus(vsi_l_offset nOffset, vsi_l_offset nLength) { return VSI_RANGE_STATUS_UNKNOWN; } VSIGoFilesystemHandler::VSIGoFilesystemHandler(size_t bufferSize, size_t cacheSize) { m_buffer = bufferSize; m_cache = (cacheSize < bufferSize) ? bufferSize : cacheSize; } VSIGoFilesystemHandler::~VSIGoFilesystemHandler() {} VSIVirtualHandle *VSIGoFilesystemHandler::Open(const char *pszFilename, const char *pszAccess, bool bSetError #if GDAL_VERSION_NUM >= GDAL_COMPUTE_VERSION(3, 3, 0) , CSLConstList /*papszOptions*/ #endif ) { if (strchr(pszAccess, 'w') != NULL || strchr(pszAccess, '+') != NULL) { CPLError(CE_Failure, CPLE_AppDefined, "Only read-only mode is supported"); return nullptr; } char *err = nullptr; long long s = _gogdalSizeCallback((char *)pszFilename, &err); if (s == -1) { if (err != nullptr && bSetError) { VSIError(VSIE_FileError, "%s", err); } errno = ENOENT; return nullptr; } if (m_buffer == 0) { return new VSIGoHandle(pszFilename, s); } else { return VSICreateCachedFile(new VSIGoHandle(pszFilename, s), m_buffer, m_cache); } } int VSIGoFilesystemHandler::Stat(const char *pszFilename, VSIStatBufL *pStatBuf, int nFlags) { char *err = nullptr; long long s = _gogdalSizeCallback((char *)pszFilename, &err); if (s == -1) { if (nFlags & VSI_STAT_SET_ERROR_FLAG) { CPLError(CE_Failure, CPLE_AppDefined, "%s", err); errno = ENOENT; } return -1; } memset(pStatBuf, 0, sizeof(VSIStatBufL)); pStatBuf->st_mode = S_IFREG; if (nFlags & VSI_STAT_SIZE_FLAG) { pStatBuf->st_size = s; } return 0; } int VSIGoFilesystemHandler::HasOptimizedReadMultiRange(const char * /*pszPath*/) { return TRUE; } #if GDAL_VERSION_NUM >= 3020000 char **VSIGoFilesystemHandler::SiblingFiles(const char *pszFilename) { return (char **)calloc(1, sizeof(char *)); } #endif } // namespace cpl void VSIInstallGoHandler(cctx *ctx, const char *pszPrefix, size_t bufferSize, size_t cacheSize) { godalWrap(ctx); CSLConstList papszPrefix = VSIFileManager::GetPrefixes(); for( size_t i = 0; papszPrefix && papszPrefix[i]; ++i ) { if(strcmp(papszPrefix[i],pszPrefix)==0) { CPLError(CE_Failure, CPLE_AppDefined, "handler already registered on prefix"); godalUnwrap(); return; } } VSIFilesystemHandler *poHandler = new cpl::VSIGoFilesystemHandler(bufferSize, cacheSize); const std::string sPrefix(pszPrefix); VSIFileManager::InstallHandler(sPrefix, poHandler); godalUnwrap(); } void test_godal_error_handling(cctx *ctx) { godalWrap(ctx); CPLDebug("godal","this is a debug message"); CPLError(CE_Warning, CPLE_AppDefined, "this is a warning message"); CPLError(CE_Failure, CPLE_AppDefined, "this is a failure message"); godalUnwrap(); } void godalGridCreate(cctx *ctx, char *pszAlgorithm, GDALGridAlgorithm eAlgorithm, GUInt32 nPoints, const double *padfX, const double *padfY, const double *padfZ, double dfXMin, double dfXMax, double dfYMin, double dfYMax, GUInt32 nXSize, GUInt32 nYSize, GDALDataType eType, void *pData) { godalWrap(ctx); CPLErr ret; if (!GDALHasTriangulation() && eAlgorithm == GGA_Linear) { CPLError(CE_Failure, CPLE_AppDefined, "unable to run GGA_Linear algorithm, since GDAL built without QHull support"); godalUnwrap(); return; } void *ppOptions; #if GDAL_VERSION_NUM >= GDAL_COMPUTE_VERSION(3, 7, 0) ret = GDALGridParseAlgorithmAndOptions(pszAlgorithm, &eAlgorithm, &ppOptions); #else ret = ParseAlgorithmAndOptions(pszAlgorithm, &eAlgorithm, &ppOptions); #endif if(ret!=0) { forceCPLError(ctx, ret); godalUnwrap(); return; } ret = GDALGridCreate(eAlgorithm, ppOptions, nPoints, padfX, padfY, padfZ, dfXMin, dfXMax, dfYMin, dfYMax, nXSize, nYSize, eType, pData, nullptr, nullptr); if(ret!=0) { forceCPLError(ctx, ret); } godalUnwrap(); } GDALDatasetH godalGrid(cctx *ctx, const char *pszDest, GDALDatasetH hSrcDS, char **switches) { godalWrap(ctx); GDALGridOptions *gridopts = GDALGridOptionsNew(switches,nullptr); if(failed(ctx)) { GDALGridOptionsFree(gridopts); godalUnwrap(); return nullptr; } int usageErr=0; GDALDatasetH ret = GDALGrid(pszDest, hSrcDS, gridopts, &usageErr); GDALGridOptionsFree(gridopts); if(ret==nullptr || usageErr!=0) { forceError(ctx); } godalUnwrap(); return ret; } GDALDatasetH godalNearblack(cctx *ctx, const char *pszDest, GDALDatasetH hDstDS, GDALDatasetH hSrcDS, char **switches) { godalWrap(ctx); GDALNearblackOptions *nbopts = GDALNearblackOptionsNew(switches,nullptr); if(failed(ctx)) { GDALNearblackOptionsFree(nbopts); godalUnwrap(); return nullptr; } int usageErr=0; GDALDatasetH ret = GDALNearblack(pszDest, hDstDS, hSrcDS, nbopts, &usageErr); GDALNearblackOptionsFree(nbopts); if(ret==nullptr || usageErr!=0) { forceError(ctx); } godalUnwrap(); return ret; } GDALDatasetH godalDem(cctx *ctx, const char *pszDest, const char *pszProcessing, const char *pszColorFilename, GDALDatasetH hSrcDS, char **switches) { godalWrap(ctx); GDALDEMProcessingOptions *demopts = GDALDEMProcessingOptionsNew(switches,nullptr); if(failed(ctx)) { GDALDEMProcessingOptionsFree(demopts); godalUnwrap(); return nullptr; } int usageErr=0; GDALDatasetH ret = GDALDEMProcessing(pszDest, hSrcDS, pszProcessing, pszColorFilename, demopts, &usageErr); GDALDEMProcessingOptionsFree(demopts); if(ret==nullptr || usageErr!=0) { forceError(ctx); } godalUnwrap(); return ret; } OGRSpatialReferenceH godalGetGCPSpatialRef(GDALDatasetH hSrcDS) { return GDALGetGCPSpatialRef(hSrcDS); } const GCPsAndCount godalGetGCPs(GDALDatasetH hSrcDS) { return GCPsAndCount { .gcpList = GDALGetGCPs(hSrcDS), .numGCPs = GDALGetGCPCount(hSrcDS), }; } const char *godalGetGCPProjection(GDALDatasetH hSrcDS) { return GDALGetGCPProjection(hSrcDS); } void godalSetGCPs(cctx *ctx, GDALDatasetH hSrcDS, int numGCPs, goGCPList GCPList, const char *pszGCPProjection) { godalWrap(ctx); GDAL_GCP *GDALGCPList = goGCPListToGDALGCP(GCPList, numGCPs); CPLErr ret = GDALSetGCPs(hSrcDS, numGCPs, GDALGCPList, pszGCPProjection); if(ret!=0) { forceCPLError(ctx, ret); } GDALDeinitGCPs(numGCPs, GDALGCPList); CPLFree(GDALGCPList); godalUnwrap(); return; } void godalSetGCPs2(cctx *ctx, GDALDatasetH hSrcDS, int numGCPs, goGCPList GCPList, OGRSpatialReferenceH hSRS) { godalWrap(ctx); GDAL_GCP *GDALGCPList = goGCPListToGDALGCP(GCPList, numGCPs); CPLErr ret = GDALSetGCPs2(hSrcDS, numGCPs, GDALGCPList, hSRS); if(ret!=0) { forceCPLError(ctx, ret); } GDALDeinitGCPs(numGCPs, GDALGCPList); CPLFree(GDALGCPList); godalUnwrap(); return; } GDAL_GCP *goGCPListToGDALGCP(goGCPList GCPList, int numGCPs) { GDAL_GCP *ret = static_cast(CPLCalloc(numGCPs, sizeof(GDAL_GCP))); GDALInitGCPs(numGCPs, ret); for (int i = 0; i < numGCPs; i++) { ret[i].pszId = CPLStrdup(GCPList.pszIds[i]); ret[i].pszInfo = CPLStrdup(GCPList.pszInfos[i]); ret[i].dfGCPPixel = GCPList.dfGCPPixels[i]; ret[i].dfGCPLine = GCPList.dfGCPLines[i]; ret[i].dfGCPX = GCPList.dfGCPXs[i]; ret[i].dfGCPY = GCPList.dfGCPYs[i]; ret[i].dfGCPZ = GCPList.dfGCPZs[i]; } return ret; } void godalGCPListToGeoTransform(cctx *ctx, goGCPList GCPList, int numGCPs, double *gt){ godalWrap(ctx); GDAL_GCP *GDALGCPList = goGCPListToGDALGCP(GCPList, numGCPs); int ret = GDALGCPsToGeoTransform(numGCPs, GDALGCPList, gt, TRUE); if(ret!=TRUE) { forceError(ctx); } GDALDeinitGCPs(numGCPs, GDALGCPList); CPLFree(GDALGCPList); godalUnwrap(); }