1 /******************************************************************************
2  *
3  * Name:     georaster_dataset.cpp
4  * Project:  Oracle Spatial GeoRaster Driver
5  * Purpose:  Implement GeoRasterDataset Methods
6  * Author:   Ivan Lucena [ivan.lucena at oracle.com]
7  *
8  ******************************************************************************
9  * Copyright (c) 2008, Ivan Lucena <ivan dot lucena at oracle dot com>
10  * Copyright (c) 2013, Even Rouault <even dot rouault at spatialys.com>
11  *
12  * Permission is hereby granted, free of charge, to any person obtaining a
13  * copy of this software and associated documentation files ( the "Software" ),
14  * to deal in the Software without restriction, including without limitation
15  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
16  * and/or sell copies of the Software, and to permit persons to whom the
17  * Software is furnished to do so, subject to the following conditions:
18  *
19  * The above copyright notice and this permission notice shall be included
20  * in all copies or substantial portions of the Software.
21  *
22  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
23  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
25  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
27  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
28  * DEALINGS IN THE SOFTWARE.
29  *****************************************************************************/
30 
31 #include "cpl_error.h"
32 #include "cpl_vsi_virtual.h"
33 #include "gdaljp2metadata.h"
34 #include "cpl_list.h"
35 
36 #include "gdal.h"
37 #include "gdal_frmts.h"
38 #include "gdal_priv.h"
39 #include "ogr_spatialref.h"
40 
41 #include "georaster_priv.h"
42 
43 #include <memory>
44 
45 CPL_CVSID("$Id: georaster_dataset.cpp 2676511214f0c767cd711dae3cf4b4ed7b16ab82 2021-09-29 14:34:00 -0400 fechen123 $")
46 
47 //  ---------------------------------------------------------------------------
48 //                                                           GeoRasterDataset()
49 //  ---------------------------------------------------------------------------
50 
GeoRasterDataset()51 GeoRasterDataset::GeoRasterDataset()
52 {
53     bGeoTransform       = false;
54     bForcedSRID         = false;
55     poGeoRaster         = nullptr;
56     papszSubdatasets    = nullptr;
57     adfGeoTransform[0]  = 0.0;
58     adfGeoTransform[1]  = 1.0;
59     adfGeoTransform[2]  = 0.0;
60     adfGeoTransform[3]  = 0.0;
61     adfGeoTransform[4]  = 0.0;
62     adfGeoTransform[5]  = 1.0;
63     pszProjection       = nullptr;
64     poMaskBand          = nullptr;
65     bApplyNoDataArray   = false;
66     poJP2Dataset        = nullptr;
67 }
68 
69 //  ---------------------------------------------------------------------------
70 //                                                          ~GeoRasterDataset()
71 //  ---------------------------------------------------------------------------
72 
~GeoRasterDataset()73 GeoRasterDataset::~GeoRasterDataset()
74 {
75     GeoRasterDataset::FlushCache();
76 
77     poGeoRaster->FlushMetadata();
78 
79     delete poGeoRaster;
80 
81     if( poMaskBand )
82     {
83         delete poMaskBand;
84     }
85 
86     if( poJP2Dataset )
87     {
88         delete poJP2Dataset;
89     }
90 
91     CPLFree( pszProjection );
92     CSLDestroy( papszSubdatasets );
93 }
94 
95 //  ---------------------------------------------------------------------------
96 //                                                                   Identify()
97 //  ---------------------------------------------------------------------------
98 
Identify(GDALOpenInfo * poOpenInfo)99 int GeoRasterDataset::Identify( GDALOpenInfo* poOpenInfo )
100 {
101     //  -------------------------------------------------------------------
102     //  Verify georaster prefix
103     //  -------------------------------------------------------------------
104 
105     char* pszFilename = poOpenInfo->pszFilename;
106 
107     if( STARTS_WITH_CI(pszFilename, "georaster:") == false &&
108         STARTS_WITH_CI(pszFilename, "geor:")       == false )
109     {
110         return false;
111     }
112 
113     return true;
114 }
115 
116 //  ---------------------------------------------------------------------------
117 //                                                                       Open()
118 //  ---------------------------------------------------------------------------
119 
Open(GDALOpenInfo * poOpenInfo)120 GDALDataset* GeoRasterDataset::Open( GDALOpenInfo* poOpenInfo )
121 {
122     //  -------------------------------------------------------------------
123     //  It should not have an open file pointer.
124     //  -------------------------------------------------------------------
125 
126     if( poOpenInfo->fpL != nullptr )
127     {
128         return nullptr;
129     }
130 
131     //  -------------------------------------------------------------------
132     //  Check identification string and usage
133     //  -------------------------------------------------------------------
134 
135     if( ! Identify( poOpenInfo ) )
136     {
137         return nullptr;
138     }
139 
140     //  -------------------------------------------------------------------
141     //  Create a GeoRaster wrapper object
142     //  -------------------------------------------------------------------
143 
144     GeoRasterWrapper* poGRW = GeoRasterWrapper::Open(
145             poOpenInfo->pszFilename,
146             poOpenInfo->eAccess == GA_Update );
147 
148     if( ! poGRW )
149     {
150         return nullptr;
151     }
152 
153     //  -------------------------------------------------------------------
154     //  Create a corresponding GDALDataset
155     //  -------------------------------------------------------------------
156 
157     GeoRasterDataset *poGRD = new GeoRasterDataset();
158 
159     if( ! poGRD )
160     {
161         return nullptr;
162     }
163 
164     poGRD->eAccess     = poOpenInfo->eAccess;
165     poGRD->poGeoRaster = poGRW;
166 
167     //  -------------------------------------------------------------------
168     //  List Subdatasets
169     //  -------------------------------------------------------------------
170 
171     if( ! poGRW->bUniqueFound )
172     {
173         if( poGRD->eAccess == GA_ReadOnly )
174         {
175             poGRD->SetSubdatasets( poGRW );
176 
177             if( CSLCount( poGRD->papszSubdatasets ) == 0 )
178             {
179                 delete poGRD;
180                 poGRD = nullptr;
181             }
182         }
183         return (GDALDataset*) poGRD;
184     }
185 
186     //  -------------------------------------------------------------------
187     //  Assign GeoRaster information
188     //  -------------------------------------------------------------------
189 
190     poGRD->poGeoRaster   = poGRW;
191     poGRD->nRasterXSize  = poGRW->nRasterColumns;
192     poGRD->nRasterYSize  = poGRW->nRasterRows;
193     poGRD->nBands        = poGRW->nRasterBands;
194 
195     if( poGRW->bIsReferenced )
196     {
197         poGRD->adfGeoTransform[1] = poGRW->dfXCoefficient[0];
198         poGRD->adfGeoTransform[2] = poGRW->dfXCoefficient[1];
199         poGRD->adfGeoTransform[0] = poGRW->dfXCoefficient[2];
200         poGRD->adfGeoTransform[4] = poGRW->dfYCoefficient[0];
201         poGRD->adfGeoTransform[5] = poGRW->dfYCoefficient[1];
202         poGRD->adfGeoTransform[3] = poGRW->dfYCoefficient[2];
203     }
204 
205     //  -------------------------------------------------------------------
206     //  Copy RPC values to RPC metadata domain
207     //  -------------------------------------------------------------------
208 
209     if( poGRW->phRPC )
210     {
211         char **papszRPC_MD = RPCInfoV2ToMD( poGRW->phRPC );
212         char **papszSanitazed = nullptr;
213 
214         int i = 0;
215         int n = CSLCount( papszRPC_MD );
216 
217         for( i = 0; i < n; i++ )
218         {
219             if ( STARTS_WITH_CI(papszRPC_MD[i], "MIN_LAT")  ||
220                  STARTS_WITH_CI(papszRPC_MD[i], "MIN_LONG") ||
221                  STARTS_WITH_CI(papszRPC_MD[i], "MAX_LAT")  ||
222                  STARTS_WITH_CI(papszRPC_MD[i], "MAX_LONG") )
223             {
224                 continue;
225             }
226             papszSanitazed = CSLAddString( papszSanitazed, papszRPC_MD[i] );
227         }
228 
229         poGRD->SetMetadata( papszSanitazed, "RPC" );
230 
231         CSLDestroy( papszRPC_MD );
232         CSLDestroy( papszSanitazed );
233     }
234 
235     //  -------------------------------------------------------------------
236     //  Open for JPEG 2000 compression for reading
237     //  -------------------------------------------------------------------
238 
239     if( EQUAL( poGRW->sCompressionType.c_str(), "JP2-F" ) &&
240         poGRD->eAccess == GA_ReadOnly )
241     {
242         poGRD->JP2_Open( poOpenInfo->eAccess );
243 
244         if( ! poGRD->poJP2Dataset )
245         {
246             delete poGRD;
247             return nullptr;
248         }
249     }
250 
251     //  -------------------------------------------------------------------
252     //  Load mask band
253     //  -------------------------------------------------------------------
254 
255     poGRW->bHasBitmapMask = EQUAL( "TRUE", CPLGetXMLValue( poGRW->phMetadata,
256                           "layerInfo.objectLayer.bitmapMask", "FALSE" ) );
257 
258     if( poGRW->bHasBitmapMask )
259     {
260         poGRD->poMaskBand = new GeoRasterRasterBand( poGRD, 0, DEFAULT_BMP_MASK );
261     }
262 
263     //  -------------------------------------------------------------------
264     //  Check for filter Nodata environment variable, default is YES
265     //  -------------------------------------------------------------------
266 
267     const char *pszGEOR_FILTER_NODATA =
268         CPLGetConfigOption( "GEOR_FILTER_NODATA_VALUES", "NO" );
269 
270     if( ! EQUAL(pszGEOR_FILTER_NODATA, "NO") )
271     {
272         poGRD->bApplyNoDataArray = true;
273     }
274 
275     //  -------------------------------------------------------------------
276     //  Create bands
277     //  -------------------------------------------------------------------
278 
279     int i = 0;
280 
281     for( i = 1; i <= poGRD->nBands; i++ )
282     {
283         poGRD->SetBand( i, new GeoRasterRasterBand( poGRD, i, 0 ,
284                                                     poGRD->poJP2Dataset) );
285     }
286 
287     //  -------------------------------------------------------------------
288     //  Set IMAGE_STRUCTURE metadata information
289     //  -------------------------------------------------------------------
290 
291     if( poGRW->nBandBlockSize == 1 )
292     {
293         poGRD->SetMetadataItem( "INTERLEAVE", "BSQ", "IMAGE_STRUCTURE" );
294     }
295     else
296     {
297         if( EQUAL( poGRW->sInterleaving.c_str(), "BSQ" ) )
298         {
299             poGRD->SetMetadataItem( "INTERLEAVE", "BSQ", "IMAGE_STRUCTURE" );
300         }
301         else if( EQUAL( poGRW->sInterleaving.c_str(), "BIP" ) )
302         {
303             poGRD->SetMetadataItem( "INTERLEAVE", "PIB", "IMAGE_STRUCTURE" );
304         }
305         else if( EQUAL( poGRW->sInterleaving.c_str(), "BIL" ) )
306         {
307             poGRD->SetMetadataItem( "INTERLEAVE", "BIL", "IMAGE_STRUCTURE" );
308         }
309     }
310 
311     poGRD->SetMetadataItem( "COMPRESSION", CPLGetXMLValue( poGRW->phMetadata,
312         "rasterInfo.compression.type", "NONE" ), "IMAGE_STRUCTURE" );
313 
314     if( STARTS_WITH_CI(poGRW->sCompressionType.c_str(), "JPEG") )
315     {
316         poGRD->SetMetadataItem( "COMPRESSION_QUALITY",
317             CPLGetXMLValue( poGRW->phMetadata,
318             "rasterInfo.compression.quality", "undefined" ), "IMAGE_STRUCTURE" );
319     }
320 
321     if( EQUAL( poGRW->sCellDepth.c_str(), "1BIT" ) )
322     {
323         poGRD->SetMetadataItem( "NBITS", "1", "IMAGE_STRUCTURE" );
324     }
325 
326     if( EQUAL( poGRW->sCellDepth.c_str(), "2BIT" ) )
327     {
328         poGRD->SetMetadataItem( "NBITS", "2", "IMAGE_STRUCTURE" );
329     }
330 
331     if( EQUAL( poGRW->sCellDepth.c_str(), "4BIT" ) )
332     {
333         poGRD->SetMetadataItem( "NBITS", "4", "IMAGE_STRUCTURE" );
334     }
335 
336     //  -------------------------------------------------------------------
337     //  Set Metadata on "ORACLE" domain
338     //  -------------------------------------------------------------------
339 
340     char* pszDoc = CPLSerializeXMLTree( poGRW->phMetadata );
341 
342     poGRD->SetMetadataItem( "TABLE_NAME", CPLSPrintf( "%s%s",
343         poGRW->sSchema.c_str(),
344         poGRW->sTable.c_str()), "ORACLE" );
345 
346     poGRD->SetMetadataItem( "COLUMN_NAME",
347         poGRW->sColumn.c_str(), "ORACLE" );
348 
349     poGRD->SetMetadataItem( "RDT_TABLE_NAME",
350         poGRW->sDataTable.c_str(), "ORACLE" );
351 
352     poGRD->SetMetadataItem( "RASTER_ID", CPLSPrintf( "%lld",
353         poGRW->nRasterId ), "ORACLE" );
354 
355     poGRD->SetMetadataItem( "SRID", CPLSPrintf( "%lld",
356         poGRW->nSRID ), "ORACLE" );
357 
358     poGRD->SetMetadataItem( "WKT", poGRW->sWKText.c_str(), "ORACLE" );
359 
360     poGRD->SetMetadataItem( "COMPRESSION",
361         poGRW->sCompressionType.c_str(), "ORACLE" );
362 
363     poGRD->SetMetadataItem( "METADATA", pszDoc, "ORACLE" );
364 
365     CPLFree( pszDoc );
366 
367     //  -------------------------------------------------------------------
368     //  Return a GDALDataset
369     //  -------------------------------------------------------------------
370 
371     return (GDALDataset*) poGRD;
372 }
373 
374 //  ---------------------------------------------------------------------------
375 //                                                                    JP2Open()
376 //  ---------------------------------------------------------------------------
377 
JP2_Open(GDALAccess)378 void GeoRasterDataset::JP2_Open( GDALAccess /* eAccess */ )
379 {
380     GDALDriver* poJP2Driver = nullptr;
381 
382     static const char * const apszDrivers[] = { "JP2OPENJPEG", "JP2ECW", "JP2MRSID",
383                                                 "JPEG2000", "JP2KAK", nullptr };
384 
385     // Find at least one available JP2 driver
386 
387     for( int iDriver = 0; apszDrivers[iDriver] != nullptr; iDriver++ )
388     {
389         poJP2Driver = (GDALDriver*) GDALGetDriverByName(apszDrivers[iDriver]);
390 
391         if( poJP2Driver )
392         {
393             break;
394         }
395     }
396 
397     // If JP2 driver is installed, try to open the LOB via VSIOCILOB handler
398 
399     poJP2Dataset = nullptr;
400 
401     if( poJP2Driver )
402     {
403         CPLString osDSName;
404 
405         osDSName.Printf( "/vsiocilob/%s,%s,%s,%s,%lld,noext",
406                           poGeoRaster->poConnection->GetUser(),
407                           poGeoRaster->poConnection->GetPassword(),
408                           poGeoRaster->poConnection->GetServer(),
409                           poGeoRaster->sDataTable.c_str(),
410                           poGeoRaster->nRasterId );
411 
412         CPLPushErrorHandler( CPLQuietErrorHandler );
413 
414         poJP2Dataset = (GDALDataset*) GDALOpenEx( osDSName.c_str(),
415                                                   GDAL_OF_RASTER,
416                                                   apszDrivers,
417                                                   nullptr, nullptr );
418 
419         CPLPopErrorHandler();
420 
421         if( ! poJP2Dataset )
422         {
423             CPLString osLastErrorMsg(CPLGetLastErrorMsg());
424             CPLError( CE_Failure, CPLE_AppDefined,
425                 "Unable to open JPEG2000 image within GeoRaster dataset.\n%s",
426                 osLastErrorMsg.c_str() );
427         }
428     }
429     else
430     {
431         CPLError( CE_Failure, CPLE_AppDefined,
432             "Unable to open JPEG2000 image within GeoRaster dataset.\n%s",
433             "No JPEG2000 capable driver (JP2OPENJPEG, "
434             "JP2ECW, JP2MRSID, etc...) is available." );
435     }
436 }
437 
438 //  ---------------------------------------------------------------------------
439 //                                                              JP2CreateCopy()
440 //  ---------------------------------------------------------------------------
441 
JP2_CreateCopy(GDALDataset * poJP2DS,char ** papszOptions,int * pnResolutions,GDALProgressFunc pfnProgress,void * pProgressData)442 void GeoRasterDataset::JP2_CreateCopy( GDALDataset* poJP2DS,
443                                        char** papszOptions,
444                                        int* pnResolutions,
445                                        GDALProgressFunc pfnProgress,
446                                        void* pProgressData )
447 {
448     GDALDriver* poJP2Driver = nullptr;
449 
450     static const char * const apszDrivers[] = { "JP2OPENJPEG", "JP2ECW", "JP2MRSID",
451                                                 "JPEG2000", "JP2KAK", nullptr };
452 
453     // Find at least one available JP2 driver
454 
455     for( int iDriver = 0; apszDrivers[iDriver] != nullptr; iDriver++ )
456     {
457         poJP2Driver = (GDALDriver*) GDALGetDriverByName(apszDrivers[iDriver]);
458 
459         if( poJP2Driver )
460         {
461             break;
462         }
463     }
464 
465     // If a JP2 driver is installed calls driver's CreateCopy
466 
467     poJP2Dataset = nullptr;
468 
469     if( poJP2Driver )
470     {
471         char** papszOpt = nullptr;
472 
473         const char* pszFetched  = CSLFetchNameValue( papszOptions, "JP2_BLOCKXSIZE" );
474 
475         if( pszFetched )
476         {
477             papszOpt = CSLAddNameValue( papszOpt, "BLOCKXSIZE",  pszFetched );
478             papszOpt = CSLAddNameValue( papszOpt, "TILE_HEIGHT", pszFetched );
479         }
480 
481         CPLDebug("GEOR","JP2_BLOCKXSIZE %s", pszFetched );
482 
483         pszFetched = CSLFetchNameValue( papszOptions, "JP2_BLOCKYSIZE" );
484 
485         if( pszFetched )
486         {
487             papszOpt = CSLAddNameValue( papszOpt, "BLOCKYSIZE",  pszFetched );
488             papszOpt = CSLAddNameValue( papszOpt, "TILE_WIDTH",  pszFetched );
489         }
490 
491         pszFetched = CSLFetchNameValue( papszOptions, "JP2_QUALITY" );
492 
493         if( pszFetched )
494         {
495             papszOpt = CSLAddNameValue( papszOpt, "QUALITY", pszFetched );
496 
497             if( STARTS_WITH_CI( pszFetched, "100" ) )
498             {
499                 papszOpt = CSLAddNameValue( papszOpt, "REVERSIBLE",  "TRUE" );
500             }
501 
502             poGeoRaster->nCompressQuality = atoi( pszFetched );
503         }
504         else
505         {
506             poGeoRaster->nCompressQuality = 25; // JP2OpenJPEG default...
507         }
508 
509         pszFetched = CSLFetchNameValue( papszOptions, "JP2_REVERSIBLE" );
510 
511         if( pszFetched )
512         {
513             papszOpt = CSLAddNameValue( papszOpt, "REVERSIBLE", pszFetched );
514         }
515 
516         pszFetched = CSLFetchNameValue( papszOptions, "JP2_RESOLUTIONS" );
517 
518         if( pszFetched )
519         {
520             papszOpt = CSLAddNameValue( papszOpt, "RESOLUTIONS", pszFetched );
521             papszOpt = CSLAddNameValue( papszOpt, "RESOLUTIONS_LEVELS", pszFetched );
522             papszOpt = CSLAddNameValue( papszOpt, "LAYERS", pszFetched );
523         }
524 
525         pszFetched = CSLFetchNameValue( papszOptions, "JP2_PROGRESSION" );
526 
527         if( pszFetched )
528         {
529             papszOpt = CSLAddNameValue( papszOpt, "PROGRESSION", pszFetched );
530         }
531 
532         papszOpt = CSLAddNameValue( papszOpt, "CODEC",       "JP2" );
533         papszOpt = CSLAddNameValue( papszOpt, "GeoJP2",      "NO" );
534         papszOpt = CSLAddNameValue( papszOpt, "GMLJP2",      "NO" );
535         papszOpt = CSLAddNameValue( papszOpt, "YCBCR420",    "NO" );
536         papszOpt = CSLAddNameValue( papszOpt, "TARGET",      "0" );
537 
538         CPLPushErrorHandler( CPLQuietErrorHandler );
539 
540         CPLString osDSName;
541 
542         osDSName.Printf( "/vsiocilob/%s,%s,%s,%s,%lld,noext",
543                           poGeoRaster->poConnection->GetUser(),
544                           poGeoRaster->poConnection->GetPassword(),
545                           poGeoRaster->poConnection->GetServer(),
546                           poGeoRaster->sDataTable.c_str(),
547                           poGeoRaster->nRasterId );
548 
549         poJP2Dataset = (GDALDataset*) GDALCreateCopy( poJP2Driver,
550                                                       osDSName.c_str(),
551                                                       poJP2DS,
552                                                       false,
553                                                       (char**) papszOpt,
554                                                       pfnProgress,
555                                                       pProgressData );
556 
557         CPLPopErrorHandler();
558 
559         CSLDestroy( papszOpt );
560 
561         if( ! poJP2Dataset )
562         {
563             CPLString osLastErrorMsg(CPLGetLastErrorMsg());
564             CPLError( CE_Failure, CPLE_AppDefined,
565                 "Unable to copy JPEG2000 image within GeoRaster dataset.\n%s",
566                 osLastErrorMsg.c_str() );
567             return;
568         }
569     }
570     else
571     {
572         CPLError( CE_Failure, CPLE_AppDefined,
573             "Unable to copy JPEG2000 image within GeoRaster dataset.\n%s",
574             "No JPEG2000 capable driver (JP2OPENJPEG, "
575             "JP2ECW, JP2MRSID, etc...) is available." );
576         return;
577     }
578 
579     // Retrieve the number of resolutions based on the number of overviews
580 
581     CPLPushErrorHandler( CPLQuietErrorHandler );
582 
583     *pnResolutions = poJP2Dataset->GetRasterBand(1)->GetOverviewCount() + 1;
584 
585     delete poJP2Dataset;
586 
587     CPLPopErrorHandler(); // Avoid showing warning regards writing aux.xml file
588 
589     poJP2Dataset = nullptr;
590 }
591 
592 //  ---------------------------------------------------------------------------
593 //                                                             JP2_CopyDirect()
594 //  ---------------------------------------------------------------------------
595 
JP2_CopyDirect(const char * pszJP2Filename,int * pnResolutions,GDALProgressFunc pfnProgress,void * pProgressData)596 boolean GeoRasterDataset::JP2_CopyDirect( const char* pszJP2Filename,
597                                           int* pnResolutions,
598                                           GDALProgressFunc pfnProgress,
599                                           void* pProgressData )
600 {
601     char** papszFileList = GetFileList();
602 
603     if( CSLCount(papszFileList) == 0 )
604     {
605         CSLDestroy( papszFileList );
606         return false;
607     }
608 
609     VSILFILE *fpInput  = VSIFOpenL( pszJP2Filename, "r" );
610     VSILFILE *fpOutput = VSIFOpenL( papszFileList[0], "wb" );
611 
612     size_t nCache = (size_t) ( GDALGetCacheMax() * 0.25 );
613 
614     void *pBuffer = (GByte*) VSIMalloc( sizeof(GByte) * nCache );
615 
616     GDALJP2Box oBox( fpInput );
617 
618     (void) oBox.ReadFirst();
619 
620     GUInt32   nLBox;
621     GUInt32   nTBox;
622 
623     int       nBoxCount = 0;
624 
625     while( strlen(oBox.GetType()) > 0 )
626     {
627         nBoxCount++;
628 
629         if( EQUAL( oBox.GetType(), "jp  " ) ||
630             EQUAL( oBox.GetType(), "ftyp" ) ||
631             EQUAL( oBox.GetType(), "jp2h" ) )
632         {
633             size_t nDataLength = (size_t) oBox.GetDataLength();
634 
635             size_t nSize = VSIFReadL( pBuffer, 1, nDataLength, fpInput);
636 
637             if ( nSize != nDataLength )
638             {
639                 CPLError( CE_Warning, CPLE_AppDefined,
640                           "amount read differs from JP2 Box data length" );
641             }
642 
643             nLBox = CPL_MSBWORD32( (int) nDataLength + 8 );
644 
645             memcpy( &nTBox, oBox.GetType(), 4 );
646 
647             VSIFWriteL( &nLBox, 4, 1, fpOutput );
648             VSIFWriteL( &nTBox, 4, 1, fpOutput );
649             VSIFWriteL( pBuffer, 1, nSize, fpOutput );
650         }
651 
652         if( EQUAL( oBox.GetType(), "jp2c" ) )
653         {
654             size_t nCount = 0;
655             size_t nSize = 0;
656             size_t nDataLength = oBox.GetDataLength();
657 
658             nLBox = CPL_MSBWORD32( (int) nDataLength + 8 );
659 
660             memcpy( &nTBox, oBox.GetType(), 4 );
661 
662             VSIFWriteL( &nLBox, 4, 1, fpOutput );
663             VSIFWriteL( &nTBox, 4, 1, fpOutput );
664 
665             while( nCount < nDataLength )
666             {
667                 size_t nChunk = (size_t) MIN( nCache, nDataLength - nCount );
668 
669                 nSize = VSIFReadL( pBuffer, 1, nChunk, fpInput );
670 
671                 if ( nSize != nChunk )
672                 {
673                     CPLError( CE_Warning, CPLE_AppDefined,
674                               "amount read differs from JP2 data length" );
675                 }
676 
677                 VSIFWriteL( pBuffer, 1, nSize, fpOutput );
678 
679                 nCount += nSize;
680 
681                 pfnProgress( (float) nCount / (float) nDataLength,
682                              nullptr, pProgressData );
683             }
684         }
685 
686         if( ! oBox.ReadNext() )
687         {
688             break;
689         }
690     }
691 
692     VSIFCloseL( fpInput );
693     VSIFCloseL( fpOutput );
694 
695     CSLDestroy( papszFileList );
696     CPLFree( pBuffer );
697 
698     // Retrieve the number of resolutions based on the number of overviews
699 
700     JP2_Open( GA_ReadOnly );
701 
702     if( poJP2Dataset )
703     {
704         *pnResolutions = poJP2Dataset->GetRasterBand(1)->GetOverviewCount() + 1;
705 
706         delete poJP2Dataset;
707         poJP2Dataset = nullptr;
708     }
709 
710     return (nBoxCount > 0);
711 }
712 
713 //  ---------------------------------------------------------------------------
714 //                                                             JPG_CopyDirect()
715 //  ---------------------------------------------------------------------------
716 
JPEG_CopyDirect(const char * pszJPGFilename,GDALProgressFunc pfnProgress,void * pProgressData)717 boolean GeoRasterDataset::JPEG_CopyDirect( const char* pszJPGFilename,
718                                            GDALProgressFunc pfnProgress,
719                                            void* pProgressData )
720 {
721     OWConnection*  poConnection  = poGeoRaster->poConnection;
722     OCILobLocator* poLocator;
723 
724     OWStatement* poStmt = poConnection->CreateStatement( CPLSPrintf(
725                    "select rasterblock from %s where rasterid = %lld "
726                    "and rownum = 1 for update",
727                    poGeoRaster->sDataTable.c_str(),
728                    poGeoRaster->nRasterId ) );
729 
730     poStmt->Define( &poLocator );
731 
732     if( poStmt->Execute() )
733     {
734         VSILFILE *fpInput = VSIFOpenL( pszJPGFilename, "r" );
735 
736         size_t nCache = (size_t) ( GDALGetCacheMax() * 0.25 );
737 
738         void *pBuffer = (GByte*) VSIMalloc( sizeof(GByte) * nCache );
739 
740         VSIFSeekL( fpInput, 0L, SEEK_END);
741 
742         size_t nCount = 0;
743         const size_t nDataLength = VSIFTellL( fpInput );
744 
745         VSIFSeekL( fpInput, 0L, SEEK_SET );
746 
747         GUIntBig nCurOff = 0;
748 
749         while( nCount < nDataLength )
750         {
751             size_t nChunk = (size_t) MIN( nCache, nDataLength - nCount );
752 
753             size_t nSize = VSIFReadL( pBuffer, 1, nChunk, fpInput );
754 
755             if ( nSize != nChunk )
756             {
757                 CPLError( CE_Warning, CPLE_AppDefined,
758                           "amount read differs from JPG length" );
759             }
760 
761             const auto nWrite = poStmt->WriteBlob( poLocator,
762                                         (void*) pBuffer,
763                                         (nCurOff + 1),
764                                         nSize );
765 
766             nCurOff += nWrite;
767             nCount  += nSize;
768 
769             pfnProgress( (float) nCount / (float) nDataLength,
770                          nullptr, pProgressData );
771         }
772 
773         VSIFCloseL( fpInput );
774 
775         CPLFree( pBuffer );
776 
777         delete poStmt;
778 
779         return true;
780     }
781 
782     if( poLocator )
783     {
784         OWStatement::Free( &poLocator, 1 );
785     }
786 
787     delete poStmt;
788 
789     return false;
790 }
791 
792 //  ---------------------------------------------------------------------------
793 //                                                                GetFileList()
794 //  ---------------------------------------------------------------------------
795 
GetFileList()796 char** GeoRasterDataset::GetFileList()
797 {
798     char** papszFileList = nullptr;
799 
800     if( EQUAL( poGeoRaster->sCompressionType.c_str(), "JP2-F" ) )
801     {
802         CPLString osDSName;
803 
804         osDSName.Printf( "/vsiocilob/%s,%s,%s,%s,%lld,noext",
805                 this->poGeoRaster->poConnection->GetUser(),
806                 this->poGeoRaster->poConnection->GetPassword(),
807                 this->poGeoRaster->poConnection->GetServer(),
808                 this->poGeoRaster->sDataTable.c_str(),
809                 this->poGeoRaster->nRasterId );
810 
811         papszFileList = CSLAddString( papszFileList, osDSName.c_str() );
812     }
813 
814     return papszFileList;
815 }
816 
817 //  ---------------------------------------------------------------------------
818 //                                                                     Create()
819 //  ---------------------------------------------------------------------------
820 
Create(const char * pszFilename,int nXSize,int nYSize,int nBands,GDALDataType eType,char ** papszOptions)821 GDALDataset *GeoRasterDataset::Create( const char *pszFilename,
822                                        int nXSize,
823                                        int nYSize,
824                                        int nBands,
825                                        GDALDataType eType,
826                                        char **papszOptions )
827 {
828     //  -------------------------------------------------------------------
829     //  Check for supported Data types
830     //  -------------------------------------------------------------------
831 
832     const char* pszCellDepth = OWSetDataType( eType );
833 
834     if( EQUAL( pszCellDepth, "Unknown" ) )
835     {
836         CPLError( CE_Failure, CPLE_AppDefined,
837             "Attempt to create GeoRaster with unsupported data type (%s)",
838             GDALGetDataTypeName( eType ) );
839         return nullptr;
840     }
841 
842     //  -------------------------------------------------------------------
843     //  Open the Dataset
844     //  -------------------------------------------------------------------
845 
846     GeoRasterDataset* poGRD = (GeoRasterDataset*) GDALOpen( pszFilename, GA_Update );
847 
848     if( ! poGRD )
849     {
850         return nullptr;
851     }
852 
853     //  -------------------------------------------------------------------
854     //  Get the GeoRaster
855     //  -------------------------------------------------------------------
856 
857     GeoRasterWrapper* poGRW = poGRD->poGeoRaster;
858 
859     if( ! poGRW )
860     {
861         delete poGRD;
862         return nullptr;
863     }
864 
865     //  -------------------------------------------------------------------
866     //  Set basic information and default values
867     //  -------------------------------------------------------------------
868 
869     poGRW->nRasterColumns   = nXSize;
870     poGRW->nRasterRows      = nYSize;
871     poGRW->nRasterBands     = nBands;
872     poGRW->sCellDepth       = pszCellDepth;
873     poGRW->nRowBlockSize    = DEFAULT_BLOCK_ROWS;
874     poGRW->nColumnBlockSize = DEFAULT_BLOCK_COLUMNS;
875     poGRW->nBandBlockSize   = 1;
876 
877     if( poGRW->bUniqueFound )
878     {
879         poGRW->PrepareToOverwrite();
880     }
881 
882     //  -------------------------------------------------------------------
883     //  Check the create options to use in initialization
884     //  -------------------------------------------------------------------
885 
886     const char* pszFetched  = "";
887     CPLCharUniquePtr pszDescription;
888     CPLCharUniquePtr pszInsert;
889     int   nQuality          = -1;
890 
891     if( ! poGRW->sTable.empty() )
892     {
893         pszFetched = CSLFetchNameValue( papszOptions, "DESCRIPTION" );
894 
895         if( pszFetched )
896         {
897             pszDescription.reset(CPLStrdup( pszFetched ));
898         }
899     }
900 
901     if( poGRW->sTable.empty() )
902     {
903         poGRW->sTable = "GDAL_IMPORT";
904         poGRW->sDataTable = "GDAL_RDT";
905     }
906 
907     if( poGRW->sColumn.empty() )
908     {
909         poGRW->sColumn = "RASTER";
910     }
911 
912     pszFetched = CSLFetchNameValue( papszOptions, "INSERT" );
913 
914     if( pszFetched )
915     {
916         pszInsert.reset(CPLStrdup( pszFetched ));
917     }
918 
919     pszFetched = CSLFetchNameValue( papszOptions, "BLOCKXSIZE" );
920 
921     if( pszFetched )
922     {
923         poGRW->nColumnBlockSize = atoi( pszFetched );
924     }
925 
926     pszFetched = CSLFetchNameValue( papszOptions, "BLOCKYSIZE" );
927 
928     if( pszFetched )
929     {
930         poGRW->nRowBlockSize = atoi( pszFetched );
931     }
932 
933     pszFetched = CSLFetchNameValue( papszOptions, "NBITS" );
934 
935     if( pszFetched != nullptr )
936     {
937         poGRW->sCellDepth = CPLSPrintf( "%dBIT", atoi( pszFetched ) );
938     }
939 
940     pszFetched = CSLFetchNameValue( papszOptions, "COMPRESS" );
941 
942     if( pszFetched != nullptr &&
943         ( EQUAL( pszFetched, "JPEG-F" ) ||
944           EQUAL( pszFetched, "JP2-F" ) ||
945           EQUAL( pszFetched, "DEFLATE" ) ) )
946     {
947         poGRW->sCompressionType = pszFetched;
948     }
949     else
950     {
951         poGRW->sCompressionType = "NONE";
952     }
953 
954     pszFetched = CSLFetchNameValue( papszOptions, "QUALITY" );
955 
956     if( pszFetched )
957     {
958         poGRW->nCompressQuality = atoi( pszFetched );
959         nQuality = poGRW->nCompressQuality;
960     }
961 
962     pszFetched = CSLFetchNameValue( papszOptions, "INTERLEAVE" );
963 
964     bool bInterleve_ind = false;
965 
966     if( pszFetched )
967     {
968         bInterleve_ind = true;
969 
970         if( EQUAL( pszFetched, "BAND" ) ||  EQUAL( pszFetched, "BSQ" ) )
971         {
972             poGRW->sInterleaving = "BSQ";
973         }
974         if( EQUAL( pszFetched, "LINE" ) ||  EQUAL( pszFetched, "BIL" ) )
975         {
976             poGRW->sInterleaving = "BIL";
977         }
978         if( EQUAL( pszFetched, "PIXEL" ) ||  EQUAL( pszFetched, "BIP" ) )
979         {
980             poGRW->sInterleaving = "BIP";
981         }
982     }
983     else
984     {
985         if( EQUAL( poGRW->sCompressionType.c_str(), "NONE" ) == false )
986         {
987             poGRW->sInterleaving = "BIP";
988         }
989     }
990 
991     pszFetched = CSLFetchNameValue( papszOptions, "BLOCKBSIZE" );
992 
993     if( pszFetched )
994     {
995         poGRW->nBandBlockSize = atoi( pszFetched );
996     }
997     else
998     {
999         if( nBands == 3 || nBands == 4 )
1000         {
1001             poGRW->nBandBlockSize = nBands;
1002         }
1003     }
1004 
1005     if( bInterleve_ind == false &&
1006       ( poGRW->nBandBlockSize == 3 || poGRW->nBandBlockSize == 4 ) )
1007     {
1008       poGRW->sInterleaving = "BIP";
1009     }
1010 
1011     if( STARTS_WITH_CI(poGRW->sCompressionType.c_str(), "JPEG") )
1012     {
1013         if( ! EQUAL( poGRW->sInterleaving.c_str(), "BIP" ) )
1014         {
1015             CPLError( CE_Warning, CPLE_IllegalArg,
1016                 "compress=JPEG assumes interleave=BIP" );
1017             poGRW->sInterleaving = "BIP";
1018         }
1019     }
1020 
1021     pszFetched = CSLFetchNameValue( papszOptions, "BLOCKING" );
1022 
1023     if( pszFetched )
1024     {
1025         if( EQUAL( pszFetched, "NO" ) )
1026         {
1027             poGRW->bBlocking = false;
1028         }
1029 
1030         if( EQUAL( pszFetched, "OPTIMALPADDING" ) )
1031         {
1032             if( poGRW->poConnection->GetVersion() < 11 )
1033             {
1034                 CPLError( CE_Warning, CPLE_IllegalArg,
1035                     "BLOCKING=OPTIMALPADDING not supported on Oracle older than 11g" );
1036             }
1037             else
1038             {
1039                 poGRW->bAutoBlocking = true;
1040                 poGRW->bBlocking = true;
1041             }
1042         }
1043     }
1044 
1045     //  -------------------------------------------------------------------
1046     //  Validate options
1047     //  -------------------------------------------------------------------
1048 
1049     if( pszDescription.get() && poGRW->bUniqueFound )
1050     {
1051         CPLError( CE_Failure, CPLE_IllegalArg,
1052             "Option (DESCRIPTION) cannot be used on a existing GeoRaster." );
1053         delete poGRD;
1054         return nullptr;
1055     }
1056 
1057     if( pszInsert && poGRW->bUniqueFound )
1058     {
1059         CPLError( CE_Failure, CPLE_IllegalArg,
1060             "Option (INSERT) cannot be used on a existing GeoRaster." );
1061         delete poGRD;
1062         return nullptr;
1063     }
1064 
1065     /* Compression JPEG-B is deprecated. It should be able to read but not
1066      * to create new GeoRaster on databases with that compression option.
1067      *
1068      * TODO: Remove that options on next release.
1069      */
1070 
1071     if( EQUAL( poGRW->sCompressionType.c_str(), "JPEG-B" ) )
1072     {
1073         CPLError( CE_Failure, CPLE_IllegalArg,
1074             "Option (COMPRESS=%s) is deprecated and cannot be used.",
1075             poGRW->sCompressionType.c_str() );
1076         delete poGRD;
1077         return nullptr;
1078     }
1079 
1080     if( EQUAL( poGRW->sCompressionType.c_str(), "JPEG-F" ) )
1081     {
1082         /* JPEG-F can only compress byte data type
1083          */
1084         if( eType != GDT_Byte )
1085         {
1086             CPLError( CE_Failure, CPLE_IllegalArg,
1087                 "Option (COMPRESS=%s) can only be used with Byte data type.",
1088                 poGRW->sCompressionType.c_str() );
1089             delete poGRD;
1090             return nullptr;
1091         }
1092 
1093         /* JPEG-F can compress one band per block or 3 for RGB
1094          * or 4 for RGBA.
1095          */
1096         if( ( poGRW->nBandBlockSize != 1 &&
1097               poGRW->nBandBlockSize != 3 &&
1098               poGRW->nBandBlockSize != 4 ) ||
1099           ( ( poGRW->nBandBlockSize != 1 &&
1100             ( poGRW->nBandBlockSize != poGRW->nRasterBands ) ) ) )
1101         {
1102             CPLError( CE_Failure, CPLE_IllegalArg,
1103                 "Option (COMPRESS=%s) requires BLOCKBSIZE to be 1 (for any "
1104                 "number of bands), 3 (for 3 bands RGB) and 4 (for 4 bands RGBA).",
1105                 poGRW->sCompressionType.c_str() );
1106             delete poGRD;
1107             return nullptr;
1108         }
1109 
1110         // There is a limit on how big a compressed block can be.
1111         if( ( poGRW->nColumnBlockSize *
1112               poGRW->nRowBlockSize *
1113               poGRW->nBandBlockSize *
1114               ( GDALGetDataTypeSize( eType ) / 8 ) ) > ( 50 * 1024 * 1024 ) )
1115         {
1116             CPLError( CE_Failure, CPLE_IllegalArg,
1117                 "Option (COMPRESS=%s) each data block must not exceed 50Mb. "
1118                 "Consider reducing BLOCK{X,Y,B}XSIZE.",
1119                 poGRW->sCompressionType.c_str() );
1120             delete poGRD;
1121             return nullptr;
1122         }
1123     }
1124 
1125     if( EQUAL( poGRW->sCompressionType.c_str(), "DEFLATE" ) )
1126     {
1127         if( ( poGRW->nColumnBlockSize *
1128               poGRW->nRowBlockSize *
1129               poGRW->nBandBlockSize *
1130               ( GDALGetDataTypeSize( eType ) / 8 ) ) > ( 1024 * 1024 * 1024 ) )
1131         {
1132             CPLError( CE_Failure, CPLE_IllegalArg,
1133                 "For (COMPRESS=%s) each data block must not exceed 1Gb. "
1134                 "Consider reducing BLOCK{X,Y,B}XSIZE.",
1135                 poGRW->sCompressionType.c_str() );
1136             delete poGRD;
1137             return nullptr;
1138         }
1139     }
1140 
1141     // When the compression is JP2-F it should be just one block
1142 
1143     if( EQUAL( poGRW->sCompressionType.c_str(), "JP2-F" ) )
1144     {
1145         poGRW->nRowBlockSize    = poGRW->nRasterRows;
1146         poGRW->nColumnBlockSize = poGRW->nRasterColumns;
1147         poGRW->nBandBlockSize   = poGRW->nRasterBands;
1148         poGRW->bBlocking        = false;
1149     }
1150 
1151     pszFetched = CSLFetchNameValue( papszOptions, "OBJECTTABLE" );
1152 
1153     if( pszFetched )
1154     {
1155         int nVersion = poGRW->poConnection->GetVersion();
1156         if( nVersion <= 11 )
1157         {
1158             CPLError( CE_Failure, CPLE_IllegalArg,
1159                 "Driver create-option OBJECTTABLE not "
1160                 "supported on Oracle %d", nVersion );
1161             delete poGRD;
1162             return nullptr;
1163         }
1164     }
1165 
1166     poGRD->poGeoRaster->bCreateObjectTable =
1167         CPLFetchBool( papszOptions, "OBJECTTABLE", false );
1168 
1169     //  -------------------------------------------------------------------
1170     //  Create a SDO_GEORASTER object on the server
1171     //  -------------------------------------------------------------------
1172 
1173     const bool bSuccess = poGRW->Create( pszDescription.get(), pszInsert.get(), poGRW->bUniqueFound );
1174 
1175     if( ! bSuccess )
1176     {
1177         delete poGRD;
1178         return nullptr;
1179     }
1180 
1181     //  -------------------------------------------------------------------
1182     //  Prepare an identification string
1183     //  -------------------------------------------------------------------
1184 
1185     char szStringId[OWTEXT];
1186 
1187     snprintf( szStringId, sizeof(szStringId), "georaster:%s,%s,%s,%s,%lld",
1188         poGRW->poConnection->GetUser(),
1189         poGRW->poConnection->GetPassword(),
1190         poGRW->poConnection->GetServer(),
1191         poGRW->sDataTable.c_str(),
1192         poGRW->nRasterId );
1193 
1194     delete poGRD;
1195 
1196     poGRD = (GeoRasterDataset*) GDALOpen( szStringId, GA_Update );
1197 
1198     if( ! poGRD )
1199     {
1200         return nullptr;
1201     }
1202 
1203     //  -------------------------------------------------------------------
1204     //  Load additional options
1205     //  -------------------------------------------------------------------
1206 
1207     pszFetched = CSLFetchNameValue( papszOptions, "VATNAME" );
1208 
1209     if( pszFetched )
1210     {
1211         poGRW->sValueAttributeTab = pszFetched;
1212     }
1213 
1214     pszFetched = CSLFetchNameValue( papszOptions, "SRID" );
1215 
1216     if( pszFetched )
1217     {
1218         poGRD->bForcedSRID = true;
1219         poGRD->poGeoRaster->SetGeoReference( atoi( pszFetched ) );
1220     }
1221 
1222     poGRD->poGeoRaster->bGenSpatialExtent =
1223         CPLFetchBool( papszOptions, "SPATIALEXTENT", TRUE );
1224 
1225     pszFetched = CSLFetchNameValue( papszOptions, "EXTENTSRID" );
1226 
1227     if( pszFetched )
1228     {
1229         poGRD->poGeoRaster->nExtentSRID = atoi( pszFetched );
1230     }
1231 
1232     pszFetched = CSLFetchNameValue( papszOptions, "COORDLOCATION" );
1233 
1234     if( pszFetched )
1235     {
1236         if( EQUAL( pszFetched, "CENTER" ) )
1237         {
1238             poGRD->poGeoRaster->eModelCoordLocation = MCL_CENTER;
1239         }
1240         else if( EQUAL( pszFetched, "UPPERLEFT" ) )
1241         {
1242             poGRD->poGeoRaster->eModelCoordLocation = MCL_UPPERLEFT;
1243         }
1244         else
1245         {
1246             CPLError( CE_Warning, CPLE_IllegalArg,
1247                 "Incorrect COORDLOCATION (%s)", pszFetched );
1248         }
1249     }
1250 
1251     if ( nQuality > 0 )
1252     {
1253         poGRD->poGeoRaster->nCompressQuality = nQuality;
1254     }
1255 
1256     pszFetched = CSLFetchNameValue( papszOptions, "GENPYRAMID" );
1257 
1258     if( pszFetched != nullptr )
1259     {
1260         if (!(EQUAL(pszFetched, "NN") ||
1261               EQUAL(pszFetched, "BILINEAR") ||
1262               EQUAL(pszFetched, "BIQUADRATIC") ||
1263               EQUAL(pszFetched, "CUBIC") ||
1264               EQUAL(pszFetched, "AVERAGE4") ||
1265               EQUAL(pszFetched, "AVERAGE16")))
1266         {
1267             CPLError( CE_Warning, CPLE_IllegalArg, "Wrong resample method for pyramid (%s)", pszFetched);
1268         }
1269 
1270         poGRD->poGeoRaster->bGenPyramid = true;
1271         poGRD->poGeoRaster->sPyramidResampling = pszFetched;
1272     }
1273 
1274     pszFetched = CSLFetchNameValue( papszOptions, "GENPYRLEVELS" );
1275 
1276     if( pszFetched != nullptr )
1277     {
1278         poGRD->poGeoRaster->bGenPyramid = true;
1279         poGRD->poGeoRaster->nPyramidLevels = atoi(pszFetched);
1280     }
1281 
1282     //  -------------------------------------------------------------------
1283     //  Return a new Dataset
1284     //  -------------------------------------------------------------------
1285 
1286     return (GDALDataset*) poGRD;
1287 }
1288 
1289 //  ---------------------------------------------------------------------------
1290 //                                                                 CreateCopy()
1291 //  ---------------------------------------------------------------------------
1292 
CreateCopy(const char * pszFilename,GDALDataset * poSrcDS,int bStrict,char ** papszOptions,GDALProgressFunc pfnProgress,void * pProgressData)1293 GDALDataset *GeoRasterDataset::CreateCopy( const char* pszFilename,
1294                                            GDALDataset* poSrcDS,
1295                                            int bStrict,
1296                                            char** papszOptions,
1297                                            GDALProgressFunc pfnProgress,
1298                                            void* pProgressData )
1299 {
1300     (void) bStrict;
1301 
1302     int nBands = poSrcDS->GetRasterCount();
1303     if (nBands == 0)
1304     {
1305         CPLError( CE_Failure, CPLE_NotSupported,
1306         "GeoRaster driver does not support source dataset with zero band.\n");
1307         return nullptr;
1308     }
1309 
1310     GDALRasterBand* poBand = poSrcDS->GetRasterBand( 1 );
1311     GDALDataType    eType  = poBand->GetRasterDataType();
1312 
1313     //  -----------------------------------------------------------
1314     //  Create a GeoRaster on the server or select one to overwrite
1315     //  -----------------------------------------------------------
1316 
1317     GeoRasterDataset *poDstDS =
1318         (GeoRasterDataset *) GeoRasterDataset::Create(
1319             pszFilename,
1320             poSrcDS->GetRasterXSize(),
1321             poSrcDS->GetRasterYSize(),
1322             poSrcDS->GetRasterCount(),
1323             eType, papszOptions );
1324 
1325     if( poDstDS == nullptr )
1326     {
1327         return nullptr;
1328     }
1329 
1330     //  -----------------------------------------------------------
1331     //  Copy information to the dataset
1332     //  -----------------------------------------------------------
1333 
1334     double adfTransform[6];
1335 
1336     if ( poSrcDS->GetGeoTransform( adfTransform ) == CE_None )
1337     {
1338         if ( ! ( adfTransform[0] == 0.0 &&
1339                  adfTransform[1] == 1.0 &&
1340                  adfTransform[2] == 0.0 &&
1341                  adfTransform[3] == 0.0 &&
1342                  adfTransform[4] == 0.0 &&
1343                  adfTransform[5] == 1.0 ) )
1344         {
1345             poDstDS->SetGeoTransform( adfTransform );
1346 
1347             if( ! poDstDS->bForcedSRID ) /* forced by create option SRID */
1348             {
1349                 poDstDS->SetSpatialRef( poSrcDS->GetSpatialRef() );
1350             }
1351         }
1352     }
1353 
1354     // --------------------------------------------------------------------
1355     //      Copy GCPs
1356     // --------------------------------------------------------------------
1357 
1358     if( poSrcDS->GetGCPCount() > 0 )
1359     {
1360         poDstDS->SetGCPs( poSrcDS->GetGCPCount(),
1361                           poSrcDS->GetGCPs(),
1362                           poSrcDS->GetGCPSpatialRef() );
1363     }
1364 
1365     // --------------------------------------------------------------------
1366     //      Copy RPC
1367     // --------------------------------------------------------------------
1368 
1369     char **papszRPCMetadata = GDALGetMetadata( poSrcDS, "RPC" );
1370 
1371     if ( papszRPCMetadata != nullptr )
1372     {
1373         poDstDS->poGeoRaster->phRPC = (GDALRPCInfoV2*) VSICalloc( 1, sizeof(GDALRPCInfoV2) );
1374         CPL_IGNORE_RET_VAL(
1375             GDALExtractRPCInfoV2( papszRPCMetadata, poDstDS->poGeoRaster->phRPC ));
1376     }
1377 
1378     // --------------------------------------------------------------------
1379     //      Copy information to the raster bands
1380     // --------------------------------------------------------------------
1381 
1382     for( int iBand = 1; iBand <= poSrcDS->GetRasterCount(); iBand++ )
1383     {
1384         GDALRasterBand*      poSrcBand = poSrcDS->GetRasterBand( iBand );
1385         GeoRasterRasterBand* poDstBand = (GeoRasterRasterBand*)
1386                                          poDstDS->GetRasterBand( iBand );
1387 
1388         // ----------------------------------------------------------------
1389         //  Copy Color Table
1390         // ----------------------------------------------------------------
1391 
1392         GDALColorTable* poColorTable = poSrcBand->GetColorTable();
1393 
1394         if( poColorTable )
1395         {
1396             poDstBand->SetColorTable( poColorTable );
1397         }
1398 
1399         // ----------------------------------------------------------------
1400         //  Copy statistics information, without median and mode.
1401         // ----------------------------------------------------------------
1402 
1403         {
1404             double dfMin = 0.0;
1405             double dfMax = 0.0;
1406             double dfMean = 0.0;
1407             double dfStdDev = 0.0;
1408             if( poSrcBand->GetStatistics( false, false, &dfMin, &dfMax,
1409                 &dfMean, &dfStdDev ) == CE_None )
1410             {
1411                 poDstBand->SetStatistics( dfMin, dfMax, dfMean, dfStdDev );
1412 
1413                 /* That will not be recorded in the GeoRaster metadata since it
1414                 * doesn't have median and mode, so those values are only useful
1415                 * at runtime.
1416                 */
1417             }
1418         }
1419 
1420         // ----------------------------------------------------------------
1421         //  Copy statistics metadata information, including median and mode.
1422         // ----------------------------------------------------------------
1423 
1424         const char *pszMin     = poSrcBand->GetMetadataItem( "STATISTICS_MINIMUM" );
1425         const char *pszMax     = poSrcBand->GetMetadataItem( "STATISTICS_MAXIMUM" );
1426         const char *pszMean    = poSrcBand->GetMetadataItem( "STATISTICS_MEAN" );
1427         const char *pszMedian  = poSrcBand->GetMetadataItem( "STATISTICS_MEDIAN" );
1428         const char *pszMode    = poSrcBand->GetMetadataItem( "STATISTICS_MODE" );
1429         const char *pszStdDev  = poSrcBand->GetMetadataItem( "STATISTICS_STDDEV" );
1430         const char *pszSkipFX  = poSrcBand->GetMetadataItem( "STATISTICS_SKIPFACTORX" );
1431         const char *pszSkipFY  = poSrcBand->GetMetadataItem( "STATISTICS_SKIPFACTORY" );
1432 
1433         if ( pszMin    != nullptr && pszMax  != nullptr && pszMean   != nullptr &&
1434              pszMedian != nullptr && pszMode != nullptr && pszStdDev != nullptr )
1435         {
1436             const double dfMin        = CPLScanDouble( pszMin, MAX_DOUBLE_STR_REP );
1437             const double dfMax        = CPLScanDouble( pszMax, MAX_DOUBLE_STR_REP );
1438             const double dfMean       = CPLScanDouble( pszMean, MAX_DOUBLE_STR_REP );
1439             const double dfMedian     = CPLScanDouble( pszMedian, MAX_DOUBLE_STR_REP );
1440             const double dfMode       = CPLScanDouble( pszMode, MAX_DOUBLE_STR_REP );
1441 
1442             if ( ! ( ( dfMin    > dfMax ) ||
1443                      ( dfMean   > dfMax ) || ( dfMean   < dfMin ) ||
1444                      ( dfMedian > dfMax ) || ( dfMedian < dfMin ) ||
1445                      ( dfMode   > dfMax ) || ( dfMode   < dfMin ) ) )
1446             {
1447                 if ( ! pszSkipFX )
1448                 {
1449                     pszSkipFX = pszSkipFY != nullptr ? pszSkipFY : "1";
1450                 }
1451 
1452                 poDstBand->poGeoRaster->SetStatistics( iBand,
1453                                                        pszMin, pszMax, pszMean,
1454                                                        pszMedian, pszMode,
1455                                                        pszStdDev, pszSkipFX );
1456             }
1457         }
1458 
1459         // ----------------------------------------------------------------
1460         //  Copy Raster Attribute Table (RAT)
1461         // ----------------------------------------------------------------
1462 
1463         GDALRasterAttributeTableH poRAT = GDALGetDefaultRAT( poSrcBand );
1464 
1465         if( poRAT != nullptr )
1466         {
1467             poDstBand->SetDefaultRAT( (GDALRasterAttributeTable*) poRAT );
1468         }
1469 
1470         // ----------------------------------------------------------------
1471         //  Copy NoData Value
1472         // ----------------------------------------------------------------
1473         int    bHasNoDataValue = FALSE;
1474         const double dfNoDataValue = poSrcBand->GetNoDataValue( &bHasNoDataValue );
1475 
1476         if( bHasNoDataValue )
1477         {
1478             poDstBand->SetNoDataValue( dfNoDataValue );
1479         }
1480     }
1481 
1482     // --------------------------------------------------------------------
1483     //  Copy actual imagery.
1484     // --------------------------------------------------------------------
1485 
1486     int nXSize = poDstDS->GetRasterXSize();
1487     int nYSize = poDstDS->GetRasterYSize();
1488 
1489     int nBlockXSize = 0;
1490     int nBlockYSize = 0;
1491 
1492     poDstDS->GetRasterBand( 1 )->GetBlockSize( &nBlockXSize, &nBlockYSize );
1493 
1494     // --------------------------------------------------------------------
1495     //  JP2-F has one block with full image size. Use tile size instead
1496     // --------------------------------------------------------------------
1497 
1498     const char* pszFetched = CSLFetchNameValue( papszOptions, "COMPRESS" );
1499 
1500     if( pszFetched != nullptr && EQUAL( pszFetched, "JP2-F" ) )
1501     {
1502         nBlockXSize = DEFAULT_JP2_TILE_COLUMNS;
1503         nBlockYSize = DEFAULT_JP2_TILE_ROWS;
1504         pszFetched = CSLFetchNameValue( papszOptions, "JP2_BLOCKXSIZE" );
1505         if( pszFetched != nullptr )
1506         {
1507             nBlockXSize = atoi( pszFetched );
1508         }
1509         pszFetched = CSLFetchNameValue( papszOptions, "JP2_BLOCKYSIZE" );
1510         if( pszFetched != nullptr )
1511         {
1512             nBlockYSize = atoi( pszFetched );
1513         }
1514     }
1515 
1516     // --------------------------------------------------------------------
1517     //  Allocate memory buffer to read one block from one band
1518     // --------------------------------------------------------------------
1519 
1520     void *pData = VSI_MALLOC3_VERBOSE( nBlockXSize, nBlockYSize,
1521                                        GDALGetDataTypeSizeBytes(eType) );
1522 
1523     if( pData == nullptr )
1524     {
1525         delete poDstDS;
1526         return nullptr;
1527     }
1528 
1529     CPLErr eErr = CE_None;
1530 
1531     int nPixelSize = GDALGetDataTypeSize(
1532         poSrcDS->GetRasterBand(1)->GetRasterDataType() ) / 8;
1533 
1534     if( EQUAL( poDstDS->poGeoRaster->sCompressionType.c_str(), "JPEG-F" ) &&
1535         nBlockXSize == nXSize && nBlockYSize == nYSize )
1536     {
1537         // --------------------------------------------------------------------
1538         // Load JPEG avoiding decompression/compression - direct copy
1539         // --------------------------------------------------------------------
1540 
1541         const char* pszDriverName = poSrcDS->GetDriverName();
1542 
1543         if ( EQUAL( pszDriverName, "JPEG" ) )
1544         {
1545             char** papszFileList = poSrcDS->GetFileList();
1546 
1547             if ( poDstDS->JPEG_CopyDirect( papszFileList[0],
1548                                            pfnProgress,
1549                                            pProgressData ) )
1550             {
1551                 CPLDebug("GEOR","JPEG Direct copy succeed");
1552             }
1553         }
1554 
1555     }
1556     else if( EQUAL( poDstDS->poGeoRaster->sCompressionType.c_str(), "JP2-F" ) )
1557     {
1558         // --------------------------------------------------------------------
1559         // Load JP2K avoiding decompression/compression - direct copy
1560         // --------------------------------------------------------------------
1561 
1562         boolean bJP2CopyDirectSucceed = false;
1563 
1564         const char* pszDriverName = poSrcDS->GetDriverName();
1565 
1566         int nJP2Resolution = -1;
1567 
1568         if ( EQUAL( pszDriverName, "JP2OpenJPEG" ) &&
1569              poSrcDS->GetRasterBand(1)->GetColorTable() == nullptr )
1570         {
1571             //  ---------------------------------------------------------------
1572             //  Try to load the JP2 file directly
1573             //  ---------------------------------------------------------------
1574 
1575             char** papszFileList = poSrcDS->GetFileList();
1576 
1577             bJP2CopyDirectSucceed = poDstDS->JP2_CopyDirect( papszFileList[0],
1578                                                              &nJP2Resolution,
1579                                                              pfnProgress,
1580                                                              pProgressData );
1581 
1582         }
1583 
1584         if( ! bJP2CopyDirectSucceed )
1585         {
1586             //  ---------------------------------------------------------------
1587             //  Use VSIOCILOB to load using a resident JP2 driver
1588             //  ---------------------------------------------------------------
1589 
1590             poDstDS->JP2_CreateCopy( poSrcDS,          /* JP2 dataset */
1591                                      papszOptions,     /* options list */
1592                                      &nJP2Resolution,  /* returned resolution */
1593                                      pfnProgress,      /* progress function */
1594                                      pProgressData );  /* progress data */
1595 
1596         }
1597 
1598         // Number of pyramid levels is the number of resolutions - 1
1599 
1600         poDstDS->poGeoRaster->SetMaxLevel( MAX( 1, nJP2Resolution - 1 ) );
1601     }
1602     else if( poDstDS->poGeoRaster->nBandBlockSize == 1)
1603     {
1604         // ----------------------------------------------------------------
1605         //  Band order
1606         // ----------------------------------------------------------------
1607 
1608         int nBandCount = poSrcDS->GetRasterCount();
1609 
1610         for( int iBand = 1; iBand <= nBandCount; iBand++ )
1611         {
1612             GDALRasterBand *poSrcBand = poSrcDS->GetRasterBand( iBand );
1613             GDALRasterBand *poDstBand = poDstDS->GetRasterBand( iBand );
1614 
1615             for( int iYOffset = 0, iYBlock = 0;
1616                  iYOffset < nYSize;
1617                  iYOffset += nBlockYSize, iYBlock++ )
1618             {
1619                 const int nBlockRows = MIN( nBlockYSize, nYSize - iYOffset );
1620                 for( int iXOffset = 0, iXBlock = 0;
1621                      iXOffset < nXSize;
1622                      iXOffset += nBlockXSize, iXBlock++ )
1623                 {
1624 
1625                     const int nBlockCols = MIN( nBlockXSize, nXSize - iXOffset );
1626 
1627                     eErr = poSrcBand->RasterIO( GF_Read,
1628                         iXOffset, iYOffset,
1629                         nBlockCols, nBlockRows, pData,
1630                         nBlockCols, nBlockRows, eType,
1631                         nPixelSize,
1632                         nPixelSize * nBlockXSize, nullptr );
1633 
1634                     if( eErr != CE_None )
1635                     {
1636                         return nullptr;
1637                     }
1638 
1639                     eErr = poDstBand->WriteBlock( iXBlock, iYBlock, pData );
1640 
1641                     if( eErr != CE_None )
1642                     {
1643                         return nullptr;
1644                     }
1645                 }
1646 
1647                 if( ( eErr == CE_None ) && ( ! pfnProgress(
1648                       ( ( iBand - 1) / (float) nBandCount ) +
1649                       ( iYOffset + nBlockRows ) / (float) (nYSize * nBandCount),
1650                       nullptr, pProgressData ) ) )
1651                 {
1652                     eErr = CE_Failure;
1653                     CPLError( CE_Failure, CPLE_UserInterrupt,
1654                         "User terminated CreateCopy()" );
1655                 }
1656             }
1657         }
1658     }
1659     else
1660     {
1661         // ----------------------------------------------------------------
1662         //  Block order
1663         // ----------------------------------------------------------------
1664 
1665         poDstDS->poGeoRaster->SetWriteOnly( true );
1666 
1667         for( int iYOffset = 0, iYBlock = 0;
1668              iYOffset < nYSize;
1669              iYOffset += nBlockYSize, iYBlock++ )
1670         {
1671             const int nBlockRows = MIN( nBlockYSize, nYSize - iYOffset );
1672             for( int iXOffset = 0, iXBlock = 0;
1673                  iXOffset < nXSize;
1674                  iXOffset += nBlockXSize, iXBlock++ )
1675             {
1676                 const int nBlockCols = MIN( nBlockXSize, nXSize - iXOffset );
1677 
1678                 for( int iBand = 1;
1679                      iBand <= poSrcDS->GetRasterCount();
1680                      iBand++ )
1681                 {
1682                     GDALRasterBand *poSrcBand = poSrcDS->GetRasterBand( iBand );
1683                     GDALRasterBand *poDstBand = poDstDS->GetRasterBand( iBand );
1684 
1685                     eErr = poSrcBand->RasterIO( GF_Read,
1686                         iXOffset, iYOffset,
1687                         nBlockCols, nBlockRows, pData,
1688                         nBlockCols, nBlockRows, eType,
1689                         nPixelSize,
1690                         nPixelSize * nBlockXSize, nullptr );
1691 
1692                     if( eErr != CE_None )
1693                     {
1694                         return nullptr;
1695                     }
1696 
1697                     eErr = poDstBand->WriteBlock( iXBlock, iYBlock, pData );
1698 
1699                     if( eErr != CE_None )
1700                     {
1701                         return nullptr;
1702                     }
1703                 }
1704             }
1705 
1706             if( ( eErr == CE_None ) && ( ! pfnProgress(
1707                 ( iYOffset + nBlockRows ) / (double) nYSize, nullptr,
1708                     pProgressData ) ) )
1709             {
1710                 eErr = CE_Failure;
1711                 CPLError( CE_Failure, CPLE_UserInterrupt,
1712                     "User terminated CreateCopy()" );
1713             }
1714         }
1715     }
1716 
1717     CPLFree( pData );
1718 
1719     // --------------------------------------------------------------------
1720     //      Finalize
1721     // --------------------------------------------------------------------
1722 
1723     poDstDS->FlushCache();
1724 
1725     if( pfnProgress )
1726     {
1727         CPLDebug("GEOR", "Output dataset: (georaster:%s/%s@%s,%s,%lld) on %s%s,%s",
1728             poDstDS->poGeoRaster->poConnection->GetUser(),
1729             poDstDS->poGeoRaster->poConnection->GetPassword(),
1730             poDstDS->poGeoRaster->poConnection->GetServer(),
1731             poDstDS->poGeoRaster->sDataTable.c_str(),
1732             poDstDS->poGeoRaster->nRasterId,
1733             poDstDS->poGeoRaster->sSchema.c_str(),
1734             poDstDS->poGeoRaster->sTable.c_str(),
1735             poDstDS->poGeoRaster->sColumn.c_str() );
1736     }
1737 
1738     return poDstDS;
1739 }
1740 
1741 //  ---------------------------------------------------------------------------
1742 //                                                                  IRasterIO()
1743 //  ---------------------------------------------------------------------------
1744 
IRasterIO(GDALRWFlag eRWFlag,int nXOff,int nYOff,int nXSize,int nYSize,void * pData,int nBufXSize,int nBufYSize,GDALDataType eBufType,int nBandCount,int * panBandMap,GSpacing nPixelSpace,GSpacing nLineSpace,GSpacing nBandSpace,GDALRasterIOExtraArg * psExtraArg)1745 CPLErr GeoRasterDataset::IRasterIO( GDALRWFlag eRWFlag,
1746                                     int nXOff, int nYOff, int nXSize, int nYSize,
1747                                     void *pData, int nBufXSize, int nBufYSize,
1748                                     GDALDataType eBufType,
1749                                     int nBandCount, int *panBandMap,
1750                                     GSpacing nPixelSpace, GSpacing nLineSpace,
1751                                     GSpacing nBandSpace,
1752                                     GDALRasterIOExtraArg* psExtraArg )
1753 
1754 {
1755     if( EQUAL( poGeoRaster->sCompressionType.c_str(), "JP2-F" ) )
1756     {
1757         if( poJP2Dataset )
1758         {
1759             return poJP2Dataset->RasterIO( eRWFlag,
1760                         nXOff, nYOff, nXSize, nYSize,
1761                         pData, nBufXSize, nBufYSize, eBufType,
1762                         nBandCount, panBandMap,
1763                         nPixelSpace, nLineSpace, nBandSpace, psExtraArg );
1764         }
1765         else
1766         {
1767             return CE_Failure;
1768         }
1769     }
1770     else
1771     {
1772         if( poGeoRaster->nBandBlockSize > 1 )
1773         {
1774             return GDALDataset::BlockBasedRasterIO( eRWFlag,
1775                         nXOff, nYOff, nXSize, nYSize,
1776                         pData, nBufXSize, nBufYSize, eBufType,
1777                         nBandCount, panBandMap, nPixelSpace,
1778                         nLineSpace, nBandSpace, psExtraArg );
1779         }
1780         else
1781         {
1782             return GDALDataset::IRasterIO( eRWFlag,
1783                         nXOff, nYOff, nXSize, nYSize,
1784                         pData, nBufXSize, nBufYSize, eBufType,
1785                         nBandCount, panBandMap,
1786                         nPixelSpace, nLineSpace, nBandSpace, psExtraArg );
1787         }
1788     }
1789 }
1790 
1791 //  ---------------------------------------------------------------------------
1792 //                                                                 FlushCache()
1793 //  ---------------------------------------------------------------------------
1794 
FlushCache()1795 void GeoRasterDataset::FlushCache()
1796 {
1797     GDALDataset::FlushCache();
1798 }
1799 
1800 //  ---------------------------------------------------------------------------
1801 //                                                            GetGeoTransform()
1802 //  ---------------------------------------------------------------------------
1803 
GetGeoTransform(double * padfTransform)1804 CPLErr GeoRasterDataset::GetGeoTransform( double *padfTransform )
1805 {
1806     if( poGeoRaster->phRPC )
1807     {
1808         return CE_Failure;
1809     }
1810 
1811     if( poGeoRaster->nSRID == 0 )
1812     {
1813         return CE_Failure;
1814     }
1815 
1816     memcpy( padfTransform, adfGeoTransform, sizeof(double) * 6 );
1817 
1818     bGeoTransform = true;
1819 
1820     return CE_None;
1821 }
1822 
1823 //  ---------------------------------------------------------------------------
1824 //                                                           GetProjectionRef()
1825 //  ---------------------------------------------------------------------------
1826 
_GetProjectionRef(void)1827 const char* GeoRasterDataset::_GetProjectionRef( void )
1828 {
1829     if( poGeoRaster->phRPC )
1830     {
1831         return "";
1832     }
1833 
1834     if( ! poGeoRaster->bIsReferenced )
1835     {
1836         return "";
1837     }
1838 
1839     if( poGeoRaster->nSRID == UNKNOWN_CRS || poGeoRaster->nSRID == 0 )
1840     {
1841         return "";
1842     }
1843 
1844     if( pszProjection )
1845     {
1846         return pszProjection;
1847     }
1848 
1849     OGRSpatialReference oSRS;
1850 
1851     // --------------------------------------------------------------------
1852     // Check if the SRID is a valid EPSG code
1853     // --------------------------------------------------------------------
1854 
1855     CPLPushErrorHandler( CPLQuietErrorHandler );
1856 
1857     if( oSRS.importFromEPSG( static_cast<int>(poGeoRaster->nSRID) ) == OGRERR_NONE )
1858     {
1859         /*
1860          * Ignores the WKT from Oracle and use the one from GDAL's
1861          * EPSG tables. That would ensure that other drivers/software
1862          * will recognize the parameters.
1863          */
1864 
1865         if( oSRS.exportToWkt( &pszProjection ) == OGRERR_NONE )
1866         {
1867             CPLPopErrorHandler();
1868 
1869             return pszProjection;
1870         }
1871         CPLFree(pszProjection);
1872         pszProjection = nullptr;
1873     }
1874 
1875     CPLPopErrorHandler();
1876 
1877     // --------------------------------------------------------------------
1878     // Try to interpreter the WKT text
1879     // --------------------------------------------------------------------
1880 
1881     poGeoRaster->QueryWKText();
1882 
1883     if( ! ( oSRS.importFromWkt( poGeoRaster->sWKText ) == OGRERR_NONE && oSRS.GetRoot() ) )
1884     {
1885         return poGeoRaster->sWKText;
1886     }
1887 
1888     // ----------------------------------------------------------------
1889     // Decorate with Authority name
1890     // ----------------------------------------------------------------
1891 
1892     if( strlen(poGeoRaster->sAuthority) > 0 )
1893     {
1894        oSRS.SetAuthority(oSRS.GetRoot()->GetValue(),
1895            poGeoRaster->sAuthority.c_str(), static_cast<int>(poGeoRaster->nSRID));
1896     }
1897 
1898     int nSpher = OWParseEPSG( oSRS.GetAttrValue("GEOGCS|DATUM|SPHEROID") );
1899 
1900     if( nSpher > 0 )
1901     {
1902         oSRS.SetAuthority( "GEOGCS|DATUM|SPHEROID", "EPSG", nSpher );
1903     }
1904 
1905     int nDatum = OWParseEPSG( oSRS.GetAttrValue("GEOGCS|DATUM") );
1906 
1907     if( nDatum > 0 )
1908     {
1909         oSRS.SetAuthority( "GEOGCS|DATUM", "EPSG", nDatum );
1910     }
1911 
1912     // ----------------------------------------------------------------
1913     // Checks for Projection info
1914     // ----------------------------------------------------------------
1915 
1916     const char *pszProjName = oSRS.GetAttrValue( "PROJECTION" );
1917 
1918     if( pszProjName )
1919     {
1920         int nProj = OWParseEPSG( pszProjName );
1921 
1922         // ----------------------------------------------------------------
1923         // Decorate with EPSG Authority
1924         // ----------------------------------------------------------------
1925 
1926         if( nProj > 0 )
1927         {
1928             oSRS.SetAuthority( "PROJECTION", "EPSG", nProj );
1929         }
1930 
1931         // ----------------------------------------------------------------
1932         // Translate projection names to GDAL's standards
1933         // ----------------------------------------------------------------
1934 
1935         if ( EQUAL( pszProjName, "Transverse Mercator" ) )
1936         {
1937             oSRS.SetProjection( SRS_PT_TRANSVERSE_MERCATOR );
1938         }
1939         else if ( EQUAL( pszProjName, "Albers Conical Equal Area" ) )
1940         {
1941             oSRS.SetProjection( SRS_PT_ALBERS_CONIC_EQUAL_AREA );
1942         }
1943         else if ( EQUAL( pszProjName, "Azimuthal Equidistant" ) )
1944         {
1945             oSRS.SetProjection( SRS_PT_AZIMUTHAL_EQUIDISTANT );
1946         }
1947         else if ( EQUAL( pszProjName, "Miller Cylindrical" ) )
1948         {
1949             oSRS.SetProjection( SRS_PT_MILLER_CYLINDRICAL );
1950         }
1951         else if ( EQUAL( pszProjName, "Hotine Oblique Mercator" ) )
1952         {
1953             oSRS.SetProjection( SRS_PT_HOTINE_OBLIQUE_MERCATOR );
1954         }
1955         else if ( EQUAL( pszProjName, "Wagner IV" ) )
1956         {
1957             oSRS.SetProjection( SRS_PT_WAGNER_IV );
1958         }
1959         else if ( EQUAL( pszProjName, "Wagner VII" ) )
1960         {
1961             oSRS.SetProjection( SRS_PT_WAGNER_VII );
1962         }
1963         else if ( EQUAL( pszProjName, "Eckert IV" ) )
1964         {
1965             oSRS.SetProjection( SRS_PT_ECKERT_IV );
1966         }
1967         else if ( EQUAL( pszProjName, "Eckert VI" ) )
1968         {
1969             oSRS.SetProjection( SRS_PT_ECKERT_VI );
1970         }
1971         else if ( EQUAL( pszProjName, "New Zealand Map Grid" ) )
1972         {
1973             oSRS.SetProjection( SRS_PT_NEW_ZEALAND_MAP_GRID );
1974         }
1975         else if ( EQUAL( pszProjName, "Lambert Conformal Conic" ) )
1976         {
1977             oSRS.SetProjection( SRS_PT_LAMBERT_CONFORMAL_CONIC_1SP );
1978         }
1979         else if ( EQUAL( pszProjName, "Lambert Azimuthal Equal Area" ) )
1980         {
1981             oSRS.SetProjection( SRS_PT_LAMBERT_AZIMUTHAL_EQUAL_AREA );
1982         }
1983         else if ( EQUAL( pszProjName, "Van der Grinten" ) )
1984         {
1985             oSRS.SetProjection( SRS_PT_VANDERGRINTEN );
1986         }
1987         else if ( EQUAL(
1988             pszProjName, "Lambert Conformal Conic (Belgium 1972)" ) )
1989         {
1990             oSRS.SetProjection( SRS_PT_LAMBERT_CONFORMAL_CONIC_2SP_BELGIUM );
1991         }
1992         else if ( EQUAL( pszProjName, "Cylindrical Equal Area" ) )
1993         {
1994             oSRS.SetProjection( SRS_PT_CYLINDRICAL_EQUAL_AREA );
1995         }
1996         else if ( EQUAL( pszProjName, "Interrupted Goode Homolosine" ) )
1997         {
1998             oSRS.SetProjection( SRS_PT_GOODE_HOMOLOSINE );
1999         }
2000     }
2001 
2002     oSRS.exportToWkt( &pszProjection );
2003 
2004     return pszProjection;
2005 }
2006 
2007 //  ---------------------------------------------------------------------------
2008 //                                                            SetGeoTransform()
2009 //  ---------------------------------------------------------------------------
2010 
SetGeoTransform(double * padfTransform)2011 CPLErr GeoRasterDataset::SetGeoTransform( double *padfTransform )
2012 {
2013     memcpy( adfGeoTransform, padfTransform, sizeof( double ) * 6 );
2014 
2015     poGeoRaster->dfXCoefficient[0] = adfGeoTransform[1];
2016     poGeoRaster->dfXCoefficient[1] = adfGeoTransform[2];
2017     poGeoRaster->dfXCoefficient[2] = adfGeoTransform[0];
2018     poGeoRaster->dfYCoefficient[0] = adfGeoTransform[4];
2019     poGeoRaster->dfYCoefficient[1] = adfGeoTransform[5];
2020     poGeoRaster->dfYCoefficient[2] = adfGeoTransform[3];
2021 
2022     bGeoTransform = true;
2023 
2024     return CE_None;
2025 }
2026 
2027 //  ---------------------------------------------------------------------------
2028 //                                                              SetProjection()
2029 //  ---------------------------------------------------------------------------
2030 
_SetProjection(const char * pszProjString)2031 CPLErr GeoRasterDataset::_SetProjection( const char *pszProjString )
2032 {
2033     OGRSpatialReference oSRS;
2034 
2035     OGRErr eOGRErr = oSRS.importFromWkt( pszProjString );
2036 
2037     if( eOGRErr != OGRERR_NONE )
2038     {
2039         poGeoRaster->SetGeoReference( UNKNOWN_CRS );
2040 
2041         return CE_Failure;
2042     }
2043 
2044     // --------------------------------------------------------------------
2045     // Try to extract EPGS authority code
2046     // --------------------------------------------------------------------
2047 
2048     const char *pszAuthName = nullptr;
2049     const char *pszAuthCode = nullptr;
2050 
2051     if( oSRS.IsGeographic() )
2052     {
2053         pszAuthName = oSRS.GetAuthorityName( "GEOGCS" );
2054         pszAuthCode = oSRS.GetAuthorityCode( "GEOGCS" );
2055     }
2056     else if( oSRS.IsProjected() )
2057     {
2058         pszAuthName = oSRS.GetAuthorityName( "PROJCS" );
2059         pszAuthCode = oSRS.GetAuthorityCode( "PROJCS" );
2060     }
2061 
2062     if( pszAuthName != nullptr && pszAuthCode != nullptr )
2063     {
2064         if( EQUAL( pszAuthName, "ORACLE" ) ||
2065             EQUAL( pszAuthName, "EPSG" ) )
2066         {
2067             poGeoRaster->SetGeoReference( atoi( pszAuthCode ) );
2068             return CE_None;
2069         }
2070     }
2071 
2072     // ----------------------------------------------------------------
2073     // Convert SRS into old style format (SF-SQL 1.0)
2074     // ----------------------------------------------------------------
2075 
2076     std::unique_ptr<OGRSpatialReference> poSRS2(oSRS.Clone());
2077 
2078     double dfAngularUnits = poSRS2->GetAngularUnits( nullptr );
2079 
2080     if( fabs(dfAngularUnits - 0.0174532925199433) < 0.0000000000000010 )
2081     {
2082         /* match the precision used on Oracle for that particular value */
2083 
2084         poSRS2->SetAngularUnits( "Decimal Degree", 0.0174532925199433 );
2085     }
2086 
2087     char* pszCloneWKT = nullptr;
2088 
2089     const char* const apszOptions[] = { "FORMAT=SFSQL", nullptr };
2090     if( poSRS2->exportToWkt( &pszCloneWKT, apszOptions ) != OGRERR_NONE )
2091     {
2092         CPLFree(pszCloneWKT);
2093         return CE_Failure;
2094     }
2095 
2096     const char *pszProjName = poSRS2->GetAttrValue( "PROJECTION" );
2097 
2098     if( pszProjName )
2099     {
2100         // ----------------------------------------------------------------
2101         // Translate projection names to Oracle's standards
2102         // ----------------------------------------------------------------
2103 
2104         if ( EQUAL( pszProjName, SRS_PT_TRANSVERSE_MERCATOR ) )
2105         {
2106             poSRS2->SetProjection( "Transverse Mercator" );
2107         }
2108         else if ( EQUAL( pszProjName, SRS_PT_ALBERS_CONIC_EQUAL_AREA ) )
2109         {
2110             poSRS2->SetProjection( "Albers Conical Equal Area" );
2111         }
2112         else if ( EQUAL( pszProjName, SRS_PT_AZIMUTHAL_EQUIDISTANT ) )
2113         {
2114             poSRS2->SetProjection( "Azimuthal Equidistant" );
2115         }
2116         else if ( EQUAL( pszProjName, SRS_PT_MILLER_CYLINDRICAL ) )
2117         {
2118             poSRS2->SetProjection( "Miller Cylindrical" );
2119         }
2120         else if ( EQUAL( pszProjName, SRS_PT_HOTINE_OBLIQUE_MERCATOR ) )
2121         {
2122             poSRS2->SetProjection( "Hotine Oblique Mercator" );
2123         }
2124         else if ( EQUAL( pszProjName, SRS_PT_WAGNER_IV ) )
2125         {
2126             poSRS2->SetProjection( "Wagner IV" );
2127         }
2128         else if ( EQUAL( pszProjName, SRS_PT_WAGNER_VII ) )
2129         {
2130             poSRS2->SetProjection( "Wagner VII" );
2131         }
2132         else if ( EQUAL( pszProjName, SRS_PT_ECKERT_IV ) )
2133         {
2134             poSRS2->SetProjection( "Eckert IV" );
2135         }
2136         else if ( EQUAL( pszProjName, SRS_PT_ECKERT_VI ) )
2137         {
2138             poSRS2->SetProjection( "Eckert VI" );
2139         }
2140         else if ( EQUAL( pszProjName, SRS_PT_NEW_ZEALAND_MAP_GRID ) )
2141         {
2142             poSRS2->SetProjection( "New Zealand Map Grid" );
2143         }
2144         else if ( EQUAL( pszProjName, SRS_PT_LAMBERT_CONFORMAL_CONIC_1SP ) )
2145         {
2146             poSRS2->SetProjection( "Lambert Conformal Conic" );
2147         }
2148         else if ( EQUAL( pszProjName, SRS_PT_LAMBERT_AZIMUTHAL_EQUAL_AREA ) )
2149         {
2150             poSRS2->SetProjection( "Lambert Azimuthal Equal Area" );
2151         }
2152         else if ( EQUAL( pszProjName, SRS_PT_VANDERGRINTEN ) )
2153         {
2154             poSRS2->SetProjection( "Van der Grinten" );
2155         }
2156         else if ( EQUAL(
2157             pszProjName, SRS_PT_LAMBERT_CONFORMAL_CONIC_2SP_BELGIUM ) )
2158         {
2159             poSRS2->SetProjection( "Lambert Conformal Conic (Belgium 1972)" );
2160         }
2161         else if ( EQUAL( pszProjName, SRS_PT_CYLINDRICAL_EQUAL_AREA ) )
2162         {
2163             poSRS2->SetProjection( "Cylindrical Equal Area" );
2164         }
2165         else if ( EQUAL( pszProjName, SRS_PT_GOODE_HOMOLOSINE ) )
2166         {
2167             poSRS2->SetProjection( "Interrupted Goode Homolosine" );
2168         }
2169 
2170         // ----------------------------------------------------------------
2171         // Translate projection's parameters to Oracle's standards
2172         // ----------------------------------------------------------------
2173 
2174         char* pszStart = nullptr;
2175 
2176         CPLFree( pszCloneWKT );
2177         pszCloneWKT = nullptr;
2178 
2179         if( poSRS2->exportToWkt( &pszCloneWKT ) != OGRERR_NONE )
2180         {
2181             CPLFree(pszCloneWKT);
2182             return CE_Failure;
2183         }
2184 
2185         if( ( pszStart = strstr(pszCloneWKT, SRS_PP_AZIMUTH) ) != nullptr )
2186         {
2187             memcpy( pszStart, "Azimuth", strlen(SRS_PP_AZIMUTH) );
2188         }
2189 
2190         if( ( pszStart = strstr(pszCloneWKT, SRS_PP_CENTRAL_MERIDIAN) ) != nullptr )
2191         {
2192             memcpy( pszStart, "Central_Meridian",
2193                                         strlen(SRS_PP_CENTRAL_MERIDIAN) );
2194         }
2195 
2196         if( ( pszStart = strstr(pszCloneWKT, SRS_PP_FALSE_EASTING) ) != nullptr )
2197         {
2198             memcpy( pszStart, "False_Easting", strlen(SRS_PP_FALSE_EASTING) );
2199         }
2200 
2201         if( ( pszStart = strstr(pszCloneWKT, SRS_PP_FALSE_NORTHING) ) != nullptr )
2202         {
2203             memcpy( pszStart, "False_Northing",
2204                                         strlen(SRS_PP_FALSE_NORTHING) );
2205         }
2206 
2207         if( ( pszStart = strstr(pszCloneWKT, SRS_PP_LATITUDE_OF_CENTER) ) != nullptr )
2208         {
2209             memcpy( pszStart, "Latitude_Of_Center",
2210                                         strlen(SRS_PP_LATITUDE_OF_CENTER) );
2211         }
2212 
2213         if( ( pszStart = strstr(pszCloneWKT, SRS_PP_LATITUDE_OF_ORIGIN) ) != nullptr )
2214         {
2215             memcpy( pszStart, "Latitude_Of_Origin",
2216                                         strlen(SRS_PP_LATITUDE_OF_ORIGIN) );
2217         }
2218 
2219         if( ( pszStart = strstr(pszCloneWKT, SRS_PP_LONGITUDE_OF_CENTER) ) != nullptr )
2220         {
2221             memcpy( pszStart, "Longitude_Of_Center",
2222                                         strlen(SRS_PP_LONGITUDE_OF_CENTER) );
2223         }
2224 
2225         if( ( pszStart = strstr(pszCloneWKT, SRS_PP_PSEUDO_STD_PARALLEL_1) ) != nullptr )
2226         {
2227             memcpy( pszStart, "Pseudo_Standard_Parallel_1",
2228                                         strlen(SRS_PP_PSEUDO_STD_PARALLEL_1) );
2229         }
2230 
2231         if( ( pszStart = strstr(pszCloneWKT, SRS_PP_SCALE_FACTOR) ) != nullptr )
2232         {
2233             memcpy( pszStart, "Scale_Factor", strlen(SRS_PP_SCALE_FACTOR) );
2234         }
2235 
2236         if( ( pszStart = strstr(pszCloneWKT, SRS_PP_STANDARD_PARALLEL_1) ) != nullptr )
2237         {
2238             memcpy( pszStart, "Standard_Parallel_1",
2239                                         strlen(SRS_PP_STANDARD_PARALLEL_1) );
2240         }
2241 
2242         if( ( pszStart = strstr(pszCloneWKT, SRS_PP_STANDARD_PARALLEL_2) ) != nullptr )
2243         {
2244             memcpy( pszStart, "Standard_Parallel_2",
2245                                         strlen(SRS_PP_STANDARD_PARALLEL_2) );
2246         }
2247 
2248         if( ( pszStart = strstr(pszCloneWKT, SRS_PP_STANDARD_PARALLEL_2) ) != nullptr )
2249         {
2250             memcpy( pszStart, "Standard_Parallel_2",
2251                                         strlen(SRS_PP_STANDARD_PARALLEL_2) );
2252         }
2253 
2254         // ----------------------------------------------------------------
2255         // Fix Unit name
2256         // ----------------------------------------------------------------
2257 
2258         if( ( pszStart = strstr(pszCloneWKT, "metre") ) != nullptr )
2259         {
2260             memcpy( pszStart, SRS_UL_METER, strlen(SRS_UL_METER) );
2261         }
2262     }
2263 
2264     // --------------------------------------------------------------------
2265     // Tries to find a SRID compatible with the WKT
2266     // --------------------------------------------------------------------
2267 
2268     OWConnection* poConnection  = poGeoRaster->poConnection;
2269     OWStatement* poStmt = nullptr;
2270 
2271     int nNewSRID = 0;
2272 
2273     const char *pszFuncName = "FIND_GEOG_CRS";
2274 
2275     if( poSRS2->IsProjected() )
2276     {
2277         pszFuncName = "FIND_PROJ_CRS";
2278     }
2279 
2280     poStmt = poConnection->CreateStatement( CPLSPrintf(
2281         "DECLARE\n"
2282         "  LIST SDO_SRID_LIST;"
2283         "BEGIN\n"
2284         "  SELECT SDO_CS.%s('%s', null) into LIST FROM DUAL;\n"
2285         "  IF LIST.COUNT() > 0 then\n"
2286         "    SELECT LIST(1) into :out from dual;\n"
2287         "  ELSE\n"
2288         "    SELECT 0 into :out from dual;\n"
2289         "  END IF;\n"
2290         "END;",
2291             pszFuncName,
2292             pszCloneWKT ) );
2293 
2294     poStmt->BindName( ":out", &nNewSRID );
2295 
2296     CPLPushErrorHandler( CPLQuietErrorHandler );
2297 
2298     if( poStmt->Execute() )
2299     {
2300         CPLPopErrorHandler();
2301 
2302         if ( nNewSRID > 0 )
2303         {
2304             poGeoRaster->SetGeoReference( nNewSRID );
2305             CPLFree( pszCloneWKT );
2306             delete poStmt;
2307             return CE_None;
2308         }
2309     }
2310     delete poStmt;
2311 
2312     // --------------------------------------------------------------------
2313     // Search by simplified WKT or insert it as a user defined SRS
2314     // --------------------------------------------------------------------
2315 
2316     int nCounter = 0;
2317 
2318     poStmt = poConnection->CreateStatement( CPLSPrintf(
2319         "SELECT COUNT(*) FROM MDSYS.CS_SRS WHERE WKTEXT = '%s'", pszCloneWKT));
2320 
2321     poStmt->Define( &nCounter );
2322 
2323     CPLPushErrorHandler( CPLQuietErrorHandler );
2324 
2325     if( poStmt->Execute() && nCounter > 0 )
2326     {
2327         delete poStmt;
2328 
2329         poStmt = poConnection->CreateStatement( CPLSPrintf(
2330             "SELECT SRID FROM MDSYS.CS_SRS WHERE WKTEXT = '%s'", pszCloneWKT));
2331 
2332         poStmt->Define( &nNewSRID );
2333 
2334         if( poStmt->Execute() )
2335         {
2336             CPLPopErrorHandler();
2337 
2338             poGeoRaster->SetGeoReference( nNewSRID );
2339             CPLFree( pszCloneWKT );
2340             delete poStmt;
2341             return CE_None;
2342         }
2343     }
2344 
2345     CPLPopErrorHandler();
2346 
2347     delete poStmt;
2348 
2349     poStmt = poConnection->CreateStatement( CPLSPrintf(
2350         "DECLARE\n"
2351         "  MAX_SRID NUMBER := 0;\n"
2352         "BEGIN\n"
2353         "  SELECT MAX(SRID) INTO MAX_SRID FROM MDSYS.CS_SRS;\n"
2354         "  MAX_SRID := MAX_SRID + 1;\n"
2355         "  INSERT INTO MDSYS.CS_SRS (SRID, WKTEXT, CS_NAME)\n"
2356         "        VALUES (MAX_SRID, '%s', '%s');\n"
2357         "  SELECT MAX_SRID INTO :out FROM DUAL;\n"
2358         "END;",
2359             pszCloneWKT,
2360             oSRS.GetRoot()->GetChild(0)->GetValue() ) );
2361 
2362     poStmt->BindName( ":out", &nNewSRID );
2363 
2364     CPLErr eError = CE_None;
2365 
2366     CPLPushErrorHandler( CPLQuietErrorHandler );
2367 
2368     if( poStmt->Execute() )
2369     {
2370         CPLPopErrorHandler();
2371 
2372         poGeoRaster->SetGeoReference( nNewSRID );
2373     }
2374     else
2375     {
2376         CPLPopErrorHandler();
2377 
2378         poGeoRaster->SetGeoReference( UNKNOWN_CRS );
2379 
2380         CPLError( CE_Warning, CPLE_UserInterrupt,
2381             "Insufficient privileges to insert reference system to "
2382             "table MDSYS.CS_SRS." );
2383 
2384         eError = CE_Warning;
2385     }
2386 
2387     CPLFree( pszCloneWKT );
2388 
2389     delete poStmt;
2390 
2391     return eError;
2392 }
2393 
2394 /************************************************************************/
2395 /*                      GetMetadataDomainList()                         */
2396 /************************************************************************/
2397 
GetMetadataDomainList()2398 char **GeoRasterDataset::GetMetadataDomainList()
2399 {
2400     return BuildMetadataDomainList(GDALDataset::GetMetadataDomainList(),
2401                                    TRUE,
2402                                    "SUBDATASETS", nullptr);
2403 }
2404 
2405 //  ---------------------------------------------------------------------------
2406 //                                                                GetMetadata()
2407 //  ---------------------------------------------------------------------------
2408 
GetMetadata(const char * pszDomain)2409 char **GeoRasterDataset::GetMetadata( const char *pszDomain )
2410 {
2411     if( pszDomain != nullptr && STARTS_WITH_CI(pszDomain, "SUBDATASETS") )
2412         return papszSubdatasets;
2413     else
2414         return GDALDataset::GetMetadata( pszDomain );
2415 }
2416 
2417 //  ---------------------------------------------------------------------------
2418 //                                                                     Delete()
2419 //  ---------------------------------------------------------------------------
2420 
Delete(const char * pszFilename)2421 CPLErr GeoRasterDataset::Delete( const char* pszFilename )
2422 {
2423     (void) pszFilename;
2424 /***
2425     GeoRasterDataset* poGRD = nullptr;
2426 
2427     poGRD = (GeoRasterDataset*) GDALOpen( pszFilename, GA_Update );
2428 
2429     if( ! poGRD )
2430     {
2431         return CE_Failure;
2432     }
2433 
2434     if( ! poGRD->poGeoRaster->Delete() )
2435     {
2436         return CE_Failure;
2437     }
2438 ***/
2439     return CE_None;
2440 }
2441 
2442 //  ---------------------------------------------------------------------------
2443 //                                                             SetSubdatasets()
2444 //  ---------------------------------------------------------------------------
2445 
SetSubdatasets(GeoRasterWrapper * poGRW)2446 void GeoRasterDataset::SetSubdatasets( GeoRasterWrapper* poGRW )
2447 {
2448     OWConnection* poConnection  = poGRW->poConnection;
2449 
2450     //  -----------------------------------------------------------
2451     //  List all the GeoRaster Tables of that User/Database
2452     //  -----------------------------------------------------------
2453 
2454     if( poGRW->sTable.empty() &&
2455         poGRW->sColumn.empty() )
2456     {
2457         OWStatement* poStmt = poConnection->CreateStatement(
2458             "SELECT   DISTINCT TABLE_NAME, OWNER FROM ALL_SDO_GEOR_SYSDATA\n"
2459             "  ORDER  BY TABLE_NAME ASC" );
2460 
2461         char szTable[OWNAME];
2462         char szOwner[OWNAME];
2463 
2464         poStmt->Define( szTable );
2465         poStmt->Define( szOwner );
2466 
2467         if( poStmt->Execute() )
2468         {
2469             int nCount = 1;
2470 
2471             do
2472             {
2473                 papszSubdatasets = CSLSetNameValue( papszSubdatasets,
2474                     CPLSPrintf( "SUBDATASET_%d_NAME", nCount ),
2475                     CPLSPrintf( "geor:%s/%s@%s,%s.%s",
2476                         poConnection->GetUser(), poConnection->GetPassword(),
2477                         poConnection->GetServer(), szOwner, szTable ) );
2478 
2479                 papszSubdatasets = CSLSetNameValue( papszSubdatasets,
2480                     CPLSPrintf( "SUBDATASET_%d_DESC", nCount ),
2481                     CPLSPrintf( "%s.Table=%s", szOwner, szTable ) );
2482 
2483                 nCount++;
2484             }
2485             while( poStmt->Fetch() );
2486         }
2487 
2488         delete poStmt;
2489 
2490         return;
2491     }
2492 
2493     //  -----------------------------------------------------------
2494     //  List all the GeoRaster Columns of that Table
2495     //  -----------------------------------------------------------
2496 
2497     if( ! poGRW->sTable.empty() &&
2498           poGRW->sColumn.empty() )
2499     {
2500         OWStatement* poStmt = poConnection->CreateStatement( CPLSPrintf(
2501             "SELECT   DISTINCT COLUMN_NAME, OWNER FROM ALL_SDO_GEOR_SYSDATA\n"
2502             "  WHERE  OWNER = UPPER('%s') AND TABLE_NAME = UPPER('%s')\n"
2503             "  ORDER  BY COLUMN_NAME ASC",
2504                 poGRW->sOwner.c_str(),
2505                 poGRW->sTable.c_str() ) );
2506 
2507         char szColumn[OWNAME];
2508         char szOwner[OWNAME];
2509 
2510         poStmt->Define( szColumn );
2511         poStmt->Define( szOwner );
2512 
2513         if( poStmt->Execute() )
2514         {
2515             int nCount = 1;
2516 
2517             do
2518             {
2519                 papszSubdatasets = CSLSetNameValue( papszSubdatasets,
2520                     CPLSPrintf( "SUBDATASET_%d_NAME", nCount ),
2521                     CPLSPrintf( "geor:%s/%s@%s,%s.%s,%s",
2522                         poConnection->GetUser(), poConnection->GetPassword(),
2523                         poConnection->GetServer(), szOwner,
2524                         poGRW->sTable.c_str(), szColumn ) );
2525 
2526                 papszSubdatasets = CSLSetNameValue( papszSubdatasets,
2527                     CPLSPrintf( "SUBDATASET_%d_DESC", nCount ),
2528                     CPLSPrintf( "Table=%s.%s Column=%s", szOwner,
2529                         poGRW->sTable.c_str(), szColumn ) );
2530 
2531                 nCount++;
2532             }
2533             while( poStmt->Fetch() );
2534         }
2535 
2536         delete poStmt;
2537 
2538         return;
2539     }
2540 
2541     //  -----------------------------------------------------------
2542     //  List all the rows that contains GeoRaster on Table/Column/Where
2543     //  -----------------------------------------------------------
2544 
2545     CPLString osAndWhere = "";
2546 
2547     if( ! poGRW->sWhere.empty() )
2548     {
2549         osAndWhere = CPLSPrintf( "AND %s", poGRW->sWhere.c_str() );
2550     }
2551 
2552     OWStatement* poStmt = poConnection->CreateStatement( CPLSPrintf(
2553         "SELECT T.%s.RASTERDATATABLE, T.%s.RASTERID, \n"
2554         "  extractValue(t.%s.metadata, "
2555 "'/georasterMetadata/rasterInfo/dimensionSize[@type=\"ROW\"]/size','%s'),\n"
2556         "  extractValue(t.%s.metadata, "
2557 "'/georasterMetadata/rasterInfo/dimensionSize[@type=\"COLUMN\"]/size','%s'),\n"
2558         "  extractValue(t.%s.metadata, "
2559 "'/georasterMetadata/rasterInfo/dimensionSize[@type=\"BAND\"]/size','%s'),\n"
2560         "  extractValue(t.%s.metadata, "
2561 "'/georasterMetadata/rasterInfo/cellDepth','%s'),\n"
2562         "  extractValue(t.%s.metadata, "
2563 "'/georasterMetadata/spatialReferenceInfo/SRID','%s')\n"
2564         "  FROM   %s%s T\n"
2565         "  WHERE  %s IS NOT NULL %s\n"
2566         "  ORDER  BY T.%s.RASTERDATATABLE ASC,\n"
2567         "            T.%s.RASTERID ASC",
2568         poGRW->sColumn.c_str(), poGRW->sColumn.c_str(),
2569         poGRW->sColumn.c_str(), OW_XMLNS,
2570         poGRW->sColumn.c_str(), OW_XMLNS,
2571         poGRW->sColumn.c_str(), OW_XMLNS,
2572         poGRW->sColumn.c_str(), OW_XMLNS,
2573         poGRW->sColumn.c_str(), OW_XMLNS,
2574         poGRW->sSchema.c_str(), poGRW->sTable.c_str(),
2575         poGRW->sColumn.c_str(), osAndWhere.c_str(),
2576         poGRW->sColumn.c_str(), poGRW->sColumn.c_str() ) );
2577 
2578     char szDataTable[OWNAME];
2579     char szRasterId[OWNAME];
2580     char szRows[OWNAME];
2581     char szColumns[OWNAME];
2582     char szBands[OWNAME];
2583     char szCellDepth[OWNAME];
2584     char szSRID[OWNAME];
2585 
2586     poStmt->Define( szDataTable );
2587     poStmt->Define( szRasterId );
2588     poStmt->Define( szRows );
2589     poStmt->Define( szColumns );
2590     poStmt->Define( szBands );
2591     poStmt->Define( szCellDepth );
2592     poStmt->Define( szSRID );
2593 
2594     if( poStmt->Execute() )
2595     {
2596         int nCount = 1;
2597 
2598         do
2599         {
2600             papszSubdatasets = CSLSetNameValue( papszSubdatasets,
2601                 CPLSPrintf( "SUBDATASET_%d_NAME", nCount ),
2602                 CPLSPrintf( "geor:%s/%s@%s,%s,%s",
2603                     poConnection->GetUser(), poConnection->GetPassword(),
2604                     poConnection->GetServer(), szDataTable, szRasterId ) );
2605 
2606             const char* pszXBands = "";
2607 
2608             if( ! EQUAL( szBands, "" ) )
2609             {
2610                 pszXBands = CPLSPrintf( "x%s", szBands );
2611             }
2612 
2613             papszSubdatasets = CSLSetNameValue( papszSubdatasets,
2614                 CPLSPrintf( "SUBDATASET_%d_DESC", nCount ),
2615                 CPLSPrintf( "[%sx%s%s] CellDepth=%s SRID=%s",
2616                     szRows, szColumns, pszXBands,
2617                     szCellDepth, szSRID ) );
2618 
2619             nCount++;
2620         }
2621         while( poStmt->Fetch() );
2622     }
2623     delete poStmt;
2624 }
2625 
GetGCPCount()2626 int GeoRasterDataset::GetGCPCount()
2627 {
2628     if ( poGeoRaster )
2629     {
2630         return poGeoRaster->nGCPCount;
2631     }
2632 
2633     return 0;
2634 }
2635 
2636 //  ---------------------------------------------------------------------------
2637 //                                                                    SetGCPs()
2638 //  ---------------------------------------------------------------------------
2639 
_SetGCPs(int nGCPCountIn,const GDAL_GCP * pasGCPListIn,const char * pszGCPProjection)2640 CPLErr GeoRasterDataset::_SetGCPs( int nGCPCountIn, const GDAL_GCP *pasGCPListIn,
2641                                   const char *pszGCPProjection )
2642 {
2643     if( GetAccess() == GA_Update )
2644     {
2645         poGeoRaster->SetGCP( nGCPCountIn, pasGCPListIn );
2646         SetProjection( pszGCPProjection );
2647     }
2648     else
2649     {
2650         CPLError(CE_Failure, CPLE_NotSupported,
2651                  "SetGCPs() is only supported on GeoRaster insert or update.");
2652         return CE_Failure;
2653     }
2654 
2655     return CE_None;
2656 }
2657 
GetGCPs()2658 const GDAL_GCP* GeoRasterDataset::GetGCPs()
2659 {
2660     if( poGeoRaster->nGCPCount > 0 && poGeoRaster->pasGCPList )
2661     {
2662         return poGeoRaster->pasGCPList;
2663     }
2664 
2665     return nullptr;
2666 }
2667 
2668 //  ---------------------------------------------------------------------------
2669 //                                                           GetGCPProjection()
2670 //  ---------------------------------------------------------------------------
2671 
_GetGCPProjection()2672 const char* GeoRasterDataset::_GetGCPProjection()
2673 {
2674     if( poGeoRaster && poGeoRaster->nGCPCount > 0 )
2675         return pszProjection;
2676     else
2677         return "";
2678 }
2679 
2680 //  ---------------------------------------------------------------------------
2681 //                                                            IBuildOverviews()
2682 //  ---------------------------------------------------------------------------
2683 
IBuildOverviews(const char * pszResampling,int nOverviews,int * panOverviewList,int nListBands,int * panBandList,GDALProgressFunc pfnProgress,void * pProgressData)2684 CPLErr GeoRasterDataset::IBuildOverviews( const char* pszResampling,
2685                                           int nOverviews,
2686                                           int* panOverviewList,
2687                                           int nListBands,
2688                                           int* panBandList,
2689                                           GDALProgressFunc pfnProgress,
2690                                           void* pProgressData )
2691 {
2692     (void) panBandList;
2693     (void) nListBands;
2694 
2695     if( EQUAL( poGeoRaster->sCompressionType.c_str(), "JP2-F" ) )
2696     {
2697         return CE_None; // Ignore it, JP2 automatically has overviews
2698     }
2699 
2700     //  ---------------------------------------------------------------
2701     //  Can't update on read-only access mode
2702     //  ---------------------------------------------------------------
2703 
2704     if( GetAccess() != GA_Update )
2705     {
2706         CPLError( CE_Failure, CPLE_AppDefined,
2707             "Can't build overviews/pyramids on read-only access." );
2708         return CE_Failure;
2709     }
2710 
2711     //  ---------------------------------------------------------------
2712     //  Uses internal sdo_generatePyramid at PL/SQL?
2713     //  ---------------------------------------------------------------
2714 
2715     bool bInternal = true;
2716 
2717     const char *pszGEOR_INTERNAL_PYR = CPLGetConfigOption( "GEOR_INTERNAL_PYR",
2718         "YES" );
2719 
2720     if( EQUAL(pszGEOR_INTERNAL_PYR, "NO") )
2721     {
2722         bInternal = false;
2723     }
2724 
2725     //  -----------------------------------------------------------
2726     //  Pyramids applies to the whole dataset not to a specific band
2727     //  -----------------------------------------------------------
2728 
2729     if( nBands < GetRasterCount())
2730     {
2731         CPLError( CE_Failure, CPLE_AppDefined,
2732             "Invalid GeoRaster Pyramids band selection" );
2733         return CE_Failure;
2734     }
2735 
2736     //  ---------------------------------------------------------------
2737     //  Initialize progress reporting
2738     //  ---------------------------------------------------------------
2739 
2740     if( ! pfnProgress( 0.1, nullptr, pProgressData ) )
2741     {
2742         CPLError( CE_Failure, CPLE_UserInterrupt, "User terminated" );
2743         return CE_Failure;
2744     }
2745 
2746     //  ---------------------------------------------------------------
2747     //  Clear existing overviews
2748     //  ---------------------------------------------------------------
2749 
2750     if( nOverviews == 0 )
2751     {
2752         poGeoRaster->DeletePyramid();
2753         return CE_None;
2754     }
2755 
2756     //  -----------------------------------------------------------
2757     //  Pyramids levels can not be treated individually
2758     //  -----------------------------------------------------------
2759 
2760     if( nOverviews > 0 )
2761     {
2762         int i;
2763         for( i = 1; i < nOverviews; i++ )
2764         {
2765             //  -----------------------------------------------------------
2766             //  Power of 2, starting on 2, e.g. 2, 4, 8, 16, 32, 64, 128
2767             //  -----------------------------------------------------------
2768 
2769             if( panOverviewList[0] != 2 ||
2770               ( panOverviewList[i] != panOverviewList[i-1] * 2 ) )
2771             {
2772                 CPLError( CE_Failure, CPLE_AppDefined,
2773                     "Invalid GeoRaster Pyramids levels." );
2774                 return CE_Failure;
2775             }
2776         }
2777     }
2778 
2779     //  -----------------------------------------------------------
2780     //  Re-sampling method:
2781     //    NN, BILINEAR, AVERAGE4, AVERAGE16 and CUBIC
2782     //  -----------------------------------------------------------
2783 
2784     char szMethod[OWNAME];
2785 
2786     if( EQUAL( pszResampling, "NEAREST" ) )
2787     {
2788         strcpy( szMethod, "NN" );
2789     }
2790     else if( STARTS_WITH_CI(pszResampling, "AVERAGE") )
2791     {
2792         strcpy( szMethod, "AVERAGE4" );
2793     }
2794     else
2795     {
2796         CPLError( CE_Failure, CPLE_AppDefined, "Invalid resampling method" );
2797         return CE_Failure;
2798     }
2799 
2800     //  -----------------------------------------------------------
2801     //  Generate pyramids on poGeoRaster
2802     //  -----------------------------------------------------------
2803 
2804     if( ! poGeoRaster->GeneratePyramid( nOverviews, szMethod, bInternal ) )
2805     {
2806         CPLError( CE_Failure, CPLE_AppDefined, "Error generating pyramid" );
2807         return CE_Failure;
2808     }
2809 
2810     //  -----------------------------------------------------------
2811     //  If Pyramid was done internally on the server exit here
2812     //  -----------------------------------------------------------
2813 
2814     if( bInternal )
2815     {
2816         pfnProgress( 1 , nullptr, pProgressData );
2817         return CE_None;
2818     }
2819 
2820     //  -----------------------------------------------------------
2821     //  Load the pyramids data using GDAL methods
2822     //  -----------------------------------------------------------
2823 
2824     CPLErr eErr = CE_None;
2825 
2826     int i = 0;
2827 
2828     for( i = 0; i < nBands; i++ )
2829     {
2830         GeoRasterRasterBand* poBand = (GeoRasterRasterBand*) papoBands[i];
2831 
2832         //  -------------------------------------------------------
2833         //  Clean up previous overviews
2834         //  -------------------------------------------------------
2835 
2836         int j = 0;
2837 
2838         if( poBand->nOverviewCount && poBand->papoOverviews )
2839         {
2840             for( j = 0; j < poBand->nOverviewCount; j++ )
2841             {
2842                 delete poBand->papoOverviews[j];
2843             }
2844             CPLFree( poBand->papoOverviews );
2845         }
2846 
2847         //  -------------------------------------------------------
2848         //  Create new band's overviews list
2849         //  -------------------------------------------------------
2850 
2851         poBand->nOverviewCount = poGeoRaster->nPyramidMaxLevel;
2852         poBand->papoOverviews  = (GeoRasterRasterBand**) VSIMalloc(
2853                 sizeof(GeoRasterRasterBand*) * poBand->nOverviewCount );
2854 
2855         for( j = 0; j < poBand->nOverviewCount; j++ )
2856         {
2857           poBand->papoOverviews[j] = new GeoRasterRasterBand(
2858                 (GeoRasterDataset*) this, ( i + 1 ), ( j + 1 ) );
2859         }
2860     }
2861 
2862     //  -----------------------------------------------------------
2863     //  Load band's overviews
2864     //  -----------------------------------------------------------
2865 
2866     for( i = 0; i < nBands; i++ )
2867     {
2868         GeoRasterRasterBand* poBand = (GeoRasterRasterBand*) papoBands[i];
2869 
2870         void *pScaledProgressData = GDALCreateScaledProgress(
2871             i / (double) nBands, ( i + 1) / (double) nBands,
2872             pfnProgress, pProgressData );
2873 
2874         eErr = GDALRegenerateOverviews(
2875             (GDALRasterBandH) poBand,
2876             poBand->nOverviewCount,
2877             (GDALRasterBandH*) poBand->papoOverviews,
2878             pszResampling,
2879             GDALScaledProgress,
2880             pScaledProgressData );
2881 
2882         GDALDestroyScaledProgress( pScaledProgressData );
2883     }
2884 
2885     return eErr;
2886 }
2887 
2888 //  ---------------------------------------------------------------------------
2889 //                                                             CreateMaskBand()
2890 //  ---------------------------------------------------------------------------
2891 
CreateMaskBand(int)2892 CPLErr GeoRasterDataset::CreateMaskBand( int /*nFlags*/ )
2893 {
2894     if( ! poGeoRaster->InitializeMask( DEFAULT_BMP_MASK,
2895             poGeoRaster->nRowBlockSize,
2896             poGeoRaster->nColumnBlockSize,
2897             poGeoRaster->nTotalRowBlocks,
2898             poGeoRaster->nTotalColumnBlocks,
2899             poGeoRaster->nTotalBandBlocks ) )
2900     {
2901         return CE_Failure;
2902     }
2903 
2904     poGeoRaster->bHasBitmapMask = true;
2905 
2906     return CE_None;
2907 }
2908 
2909 /*****************************************************************************/
2910 /*                          GDALRegister_GEOR                                */
2911 /*****************************************************************************/
2912 
GDALRegister_GEOR()2913 void CPL_DLL GDALRegister_GEOR()
2914 
2915 {
2916     if( !GDAL_CHECK_VERSION( "GeoRaster driver" ) )
2917         return;
2918 
2919     if( GDALGetDriverByName( "GeoRaster" ) != nullptr )
2920         return;
2921 
2922     GDALDriver *poDriver = new GDALDriver();
2923 
2924     poDriver->SetDescription(  "GeoRaster" );
2925     poDriver->SetMetadataItem( GDAL_DCAP_RASTER, "YES" );
2926     poDriver->SetMetadataItem( GDAL_DMD_LONGNAME, "Oracle Spatial GeoRaster" );
2927     poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC, "drivers/raster/georaster.html" );
2928     poDriver->SetMetadataItem( GDAL_DMD_SUBDATASETS, "YES" );
2929     poDriver->SetMetadataItem( GDAL_DMD_CREATIONDATATYPES,
2930                                "Byte UInt16 Int16 UInt32 Int32 Float32 "
2931                                "Float64 CFloat32 CFloat64" );
2932     poDriver->SetMetadataItem( GDAL_DMD_CREATIONOPTIONLIST,
2933 "<CreationOptionList>"
2934 "  <Option name='DESCRIPTION' type='string' description='Table Description'/>"
2935 "  <Option name='INSERT'      type='string' description='Column Values'/>"
2936 "  <Option name='BLOCKXSIZE'  type='int'    description='Column Block Size' "
2937                                            "default='512'/>"
2938 "  <Option name='BLOCKYSIZE'  type='int'    description='Row Block Size' "
2939                                            "default='512'/>"
2940 "  <Option name='BLOCKBSIZE'  type='int'    description='Band Block Size'/>"
2941 "  <Option name='BLOCKING'    type='string-select' default='YES'>"
2942 "       <Value>YES</Value>"
2943 "       <Value>NO</Value>"
2944 "       <Value>OPTIMALPADDING</Value>"
2945 "  </Option>"
2946 "  <Option name='SRID'        type='int'    description='Overwrite EPSG code'/>"
2947 "  <Option name='GENPYRAMID'  type='string-select' "
2948 " description='Generate Pyramid, inform resampling method'>"
2949 "       <Value>NN</Value>"
2950 "       <Value>BILINEAR</Value>"
2951 "       <Value>BIQUADRATIC</Value>"
2952 "       <Value>CUBIC</Value>"
2953 "       <Value>AVERAGE4</Value>"
2954 "       <Value>AVERAGE16</Value>"
2955 "  </Option>"
2956 "  <Option name='GENPYRLEVELS'  type='int'  description='Number of pyramid level to generate'/>"
2957 "  <Option name='OBJECTTABLE' type='boolean' "
2958                                            "description='Create RDT as object table'/>"
2959 "  <Option name='SPATIALEXTENT' type='boolean' "
2960                                            "description='Generate Spatial Extent' "
2961                                            "default='TRUE'/>"
2962 "  <Option name='EXTENTSRID'  type='int'    description='Spatial ExtentSRID code'/>"
2963 "  <Option name='COORDLOCATION'    type='string-select' default='CENTER'>"
2964 "       <Value>CENTER</Value>"
2965 "       <Value>UPPERLEFT</Value>"
2966 "  </Option>"
2967 "  <Option name='VATNAME'     type='string' description='Value Attribute Table Name'/>"
2968 "  <Option name='NBITS'       type='int'    description='BITS for sub-byte "
2969                                            "data types (1,2,4) bits'/>"
2970 "  <Option name='INTERLEAVE'  type='string-select'>"
2971 "       <Value>BSQ</Value>"
2972 "       <Value>BIP</Value>"
2973 "       <Value>BIL</Value>"
2974 "   </Option>"
2975 "  <Option name='COMPRESS'    type='string-select'>"
2976 "       <Value>NONE</Value>"
2977 "       <Value>JPEG-F</Value>"
2978 "       <Value>JP2-F</Value>"
2979 "       <Value>DEFLATE</Value>"
2980 "  </Option>"
2981 "  <Option name='QUALITY'     type='int'    description='JPEG quality 0..100' "
2982                                            "default='75'/>"
2983 "  <Option name='JP2_QUALITY'     type='string' description='For JP2-F compression, single quality value or comma separated list "
2984         "of increasing quality values for several layers, each in the 0-100 range' default='25'/>"
2985 "  <Option name='JP2_BLOCKXSIZE'  type='int' description='For JP2 compression, tile Width' default='1024'/>"
2986 "  <Option name='JP2_BLOCKYSIZE'  type='int' description='For JP2 compression, tile Height' default='1024'/>"
2987 "  <Option name='JP2_REVERSIBLE'  type='boolean' description='For JP2-F compression, True if the compression is reversible' default='false'/>"
2988 "  <Option name='JP2_RESOLUTIONS' type='int' description='For JP2-F compression, Number of resolutions.' min='1' max='30'/>"
2989 "  <Option name='JP2_PROGRESSION' type='string-select' description='For JP2-F compression, progression order' default='LRCP'>"
2990 "    <Value>LRCP</Value>"
2991 "    <Value>RLCP</Value>"
2992 "    <Value>RPCL</Value>"
2993 "    <Value>PCRL</Value>"
2994 "    <Value>CPRL</Value>"
2995 "  </Option>"
2996 "</CreationOptionList>" );
2997 
2998     poDriver->pfnOpen       = GeoRasterDataset::Open;
2999     poDriver->pfnCreate     = GeoRasterDataset::Create;
3000     poDriver->pfnCreateCopy = GeoRasterDataset::CreateCopy;
3001     poDriver->pfnIdentify   = GeoRasterDataset::Identify;
3002     poDriver->pfnDelete     = GeoRasterDataset::Delete;
3003 
3004     GetGDALDriverManager()->RegisterDriver( poDriver );
3005 
3006     VSIInstallOCILobHandler();
3007 }
3008