1 /******************************************************************************
2  *
3  * Name:     georaster_wrapper.cpp
4  * Project:  Oracle Spatial GeoRaster Driver
5  * Purpose:  Implement GeoRasterWrapper methods
6  * Author:   Ivan Lucena [ivan.lucena at oracle.com]
7  *
8  ******************************************************************************
9  * Copyright (c) 2008, Ivan Lucena
10  *
11  * Permission is hereby granted, free of charge, to any person obtaining a
12  * copy of this software and associated documentation files ( the "Software" ),
13  * to deal in the Software without restriction, including without limitation
14  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
15  * and/or sell copies of the Software, and to permit persons to whom the
16  * Software is furnished to do so, subject to the following conditions:
17  *
18  * The above copyright notice and this permission notice shall be included
19  * in all copies or substantial portions of the Software.
20  *
21  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
22  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
24  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
26  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
27  * DEALINGS IN THE SOFTWARE.
28  *****************************************************************************/
29 
30 #include <string.h>
31 
32 #include "georaster_priv.h"
33 #include "cpl_error.h"
34 #include "cpl_string.h"
35 #include "cpl_minixml.h"
36 
37 CPL_CVSID("$Id: georaster_wrapper.cpp 453a032f70e60f749c4d05678374363748a59d2c 2021-07-14 06:36:36 -0400 fechen123 $")
38 
39 //  ---------------------------------------------------------------------------
40 //                                                           GeoRasterWrapper()
41 //  ---------------------------------------------------------------------------
42 
GeoRasterWrapper()43 GeoRasterWrapper::GeoRasterWrapper() :
44     sPyramidResampling  ( "NN" ),
45     sCompressionType    ( "NONE" ),
46     sInterleaving       ( "BSQ" )
47 {
48     nRasterId           = -1;
49     phMetadata          = nullptr;
50     nRasterRows         = 0;
51     nRasterColumns      = 0;
52     nRasterBands        = 0;
53     nRowBlockSize       = 0;
54     nColumnBlockSize    = 0;
55     nBandBlockSize      = 0;
56     nTotalColumnBlocks  = 0;
57     nTotalRowBlocks     = 0;
58     nTotalBandBlocks    = 0;
59     nCellSizeBits       = 0;
60     nGDALCellBytes      = 0;
61     dfXCoefficient[0]   = 1.0;
62     dfXCoefficient[1]   = 0.0;
63     dfXCoefficient[2]   = 0.0;
64     dfYCoefficient[0]   = 0.0;
65     dfYCoefficient[1]   = 1.0;
66     dfYCoefficient[2]   = 0.0;
67     nCompressQuality    = 75;
68     bGenPyramid         = false;
69     nPyramidLevels      = 0;
70     pahLocator          = nullptr;
71     pabyBlockBuf        = nullptr;
72     pabyCompressBuf     = nullptr;
73     bIsReferenced       = false;
74     poBlockStmt         = nullptr;
75     nCacheBlockId       = -1;
76     nCurrentLevel       = -1;
77     pahLevels           = nullptr;
78     nLevelOffset        = 0L;
79     bUpdate             = false;
80     bInitializeIO       = false;
81     bFlushMetadata      = false;
82     nSRID               = DEFAULT_CRS;;
83     nExtentSRID         = 0;
84     bGenSpatialExtent    = false;
85     bCreateObjectTable  = false;
86     nPyramidMaxLevel    = 0;
87     nBlockCount         = 0L;
88     nGDALBlockBytes     = 0L;
89     sDInfo.global_state = 0;
90     sCInfo.global_state = 0;
91     bHasBitmapMask      = false;
92     nBlockBytes         = 0L;
93     bFlushBlock         = false;
94     nFlushBlockSize     = 0L;
95     bUniqueFound        = false;
96     psNoDataList        = nullptr;
97     bWriteOnly          = false;
98     bBlocking           = true;
99     bAutoBlocking       = false;
100     eModelCoordLocation = MCL_DEFAULT;
101     phRPC               = nullptr;
102     poConnection        = nullptr;
103     iDefaultRedBand     = 0;
104     iDefaultGreenBand   = 0;
105     iDefaultBlueBand    = 0;
106     anULTCoordinate[0]  = 0;
107     anULTCoordinate[1]  = 0;
108     anULTCoordinate[2]  = 0;
109     pasGCPList          = nullptr;
110     nGCPCount           = 0;
111     bFlushGCP           = false;
112     memset(&sCInfo, 0, sizeof(sCInfo));
113     memset(&sDInfo, 0, sizeof(sDInfo));
114     memset(&sJErr, 0, sizeof(sJErr));
115 }
116 
117 //  ---------------------------------------------------------------------------
118 //                                                           GeoRasterDataset()
119 //  ---------------------------------------------------------------------------
120 
~GeoRasterWrapper()121 GeoRasterWrapper::~GeoRasterWrapper()
122 {
123     FlushMetadata();
124 
125     if( pahLocator && nBlockCount )
126     {
127         OWStatement::Free( pahLocator, static_cast<int>(nBlockCount) );
128     }
129 
130     CPLFree( pahLocator );
131     CPLFree( pabyBlockBuf );
132     CPLFree( pabyCompressBuf );
133     CPLFree( pahLevels );
134 
135     if( bFlushGCP )
136     {
137         FlushGCP();
138         GDALDeinitGCPs( nGCPCount, pasGCPList );
139         CPLFree( pasGCPList );
140         pasGCPList = nullptr;
141         nGCPCount = 0;
142     }
143 
144     if( CPLListCount( psNoDataList ) )
145     {
146         CPLList* psList = nullptr;
147 
148         for( psList = psNoDataList; psList ; psList = psList->psNext )
149         {
150             CPLFree( psList->pData );
151         }
152 
153         CPLListDestroy( psNoDataList );
154     }
155 
156     if( poBlockStmt )
157     {
158         delete poBlockStmt;
159     }
160 
161     CPLDestroyXMLNode( phMetadata );
162 
163     if( sDInfo.global_state )
164     {
165         jpeg_destroy_decompress( &sDInfo );
166     }
167 
168     if( sCInfo.global_state )
169     {
170         jpeg_destroy_compress( &sCInfo );
171     }
172 
173     if( poConnection )
174     {
175         delete poConnection;
176     }
177 
178     if( phRPC )
179     {
180         CPLFree( phRPC );
181     }
182 }
183 
184 //  ---------------------------------------------------------------------------
185 //                                                         ParseIdentificator()
186 //  ---------------------------------------------------------------------------
187 //
188 //  StringID:
189 //      {georaster,geor}:<name>{/,,}<password>{/,@}<db>,<tab>,<col>,<where>
190 //      {georaster,geor}:<name>{/,,}<password>{/,@}<db>,<rdt>,<rid>
191 //
192 //  ---------------------------------------------------------------------------
193 
ParseIdentificator(const char * pszStringID)194 char** GeoRasterWrapper::ParseIdentificator( const char* pszStringID )
195 {
196 
197     char* pszStartPos = (char*) strstr( pszStringID, ":" ) + 1;
198 
199     char** papszParam = CSLTokenizeString2( pszStartPos, ",@",
200                             CSLT_HONOURSTRINGS | CSLT_ALLOWEMPTYTOKENS |
201                             CSLT_STRIPLEADSPACES | CSLT_STRIPENDSPACES );
202 
203     //  -------------------------------------------------------------------
204     //  The "/" should not be catch on the previous parser
205     //  -------------------------------------------------------------------
206 
207     if( CSLCount( papszParam ) > 0 )
208     {
209         char** papszFirst2 = CSLTokenizeString2( papszParam[0], "/",
210                              CSLT_HONOURSTRINGS | CSLT_ALLOWEMPTYTOKENS );
211         if( CSLCount( papszFirst2 ) == 2 )
212         {
213             papszParam = CSLInsertStrings( papszParam, 0, papszFirst2 );
214             papszParam = CSLRemoveStrings( papszParam, 2, 1, nullptr );
215         }
216         CSLDestroy( papszFirst2 );
217     }
218 
219     return papszParam;
220 }
221 
222 //  ---------------------------------------------------------------------------
223 //                                                                       Open()
224 //  ---------------------------------------------------------------------------
225 
Open(const char * pszStringId,bool bUpdate)226 GeoRasterWrapper* GeoRasterWrapper::Open( const char* pszStringId, bool bUpdate )
227 {
228     char** papszParam = ParseIdentificator( pszStringId );
229 
230     //  ---------------------------------------------------------------
231     //  Validate identificator
232     //  ---------------------------------------------------------------
233 
234     int nArgc = CSLCount( papszParam );
235 
236     for( ; nArgc < 3; nArgc++ )
237     {
238         papszParam = CSLAddString( papszParam, "" );
239     }
240 
241     //  ---------------------------------------------------------------
242     //  Create a GeoRasterWrapper object
243     //  ---------------------------------------------------------------
244 
245     GeoRasterWrapper* poGRW = new GeoRasterWrapper();
246 
247     if( ! poGRW )
248     {
249         CSLDestroy(papszParam);
250         return nullptr;
251     }
252 
253     poGRW->bUpdate = bUpdate;
254 
255     //  ---------------------------------------------------------------
256     //  Get a connection with Oracle server
257     //  ---------------------------------------------------------------
258 
259     if( strlen( papszParam[0] ) == 0 &&
260         strlen( papszParam[1] ) == 0 &&
261         strlen( papszParam[2] ) == 0 )
262     {
263         /* In an external procedure environment, before opening any
264          * dataset, the caller must pass the with_context as an
265          * string metadata item OCI_CONTEXT_PTR to the driver. */
266 
267         OCIExtProcContext* with_context = nullptr;
268 
269         const char* pszContext = GDALGetMetadataItem(
270                                            GDALGetDriverByName("GEORASTER"),
271                                           "OCI_CONTEXT_PTR", nullptr );
272 
273         if( pszContext )
274         {
275             sscanf( pszContext, "%p", &with_context );
276 
277             poGRW->poConnection = new OWConnection( with_context );
278         }
279     }
280     else
281     {
282         poGRW->poConnection = new OWConnection( papszParam[0],
283                                                 papszParam[1],
284                                                 papszParam[2] );
285     }
286 
287     if( ! poGRW->poConnection ||
288         ! poGRW->poConnection->Succeeded() )
289     {
290         CSLDestroy( papszParam );
291         delete poGRW;
292         return nullptr;
293     }
294 
295     //  -------------------------------------------------------------------
296     //  Extract schema name
297     //  -------------------------------------------------------------------
298 
299     if( poGRW->poConnection->IsExtProc() )
300     {
301         poGRW->sOwner  = poGRW->poConnection->GetExtProcUser();
302         poGRW->sSchema = poGRW->poConnection->GetExtProcSchema();
303     }
304     else
305     {
306         char** papszSchema = CSLTokenizeString2( papszParam[3], ".",
307                                 CSLT_HONOURSTRINGS | CSLT_ALLOWEMPTYTOKENS );
308 
309         if( CSLCount( papszSchema ) == 2 )
310         {
311             poGRW->sOwner  = papszSchema[0];
312             poGRW->sSchema = CPLSPrintf( "%s.", poGRW->sOwner.c_str() );
313 
314             papszParam = CSLRemoveStrings( papszParam, 3, 1, nullptr );
315 
316             if( ! EQUAL( papszSchema[1], "" ) )
317             {
318                 papszParam = CSLInsertString( papszParam, 3, papszSchema[1] );
319             }
320 
321             nArgc = CSLCount( papszParam );
322         }
323         else
324         {
325             poGRW->sSchema = "";
326             poGRW->sOwner  = poGRW->poConnection->GetUser();
327         }
328 
329         CSLDestroy( papszSchema );
330     }
331 
332     //  -------------------------------------------------------------------
333     //  Assign parameters from Identification string
334     //  -------------------------------------------------------------------
335 
336     switch( nArgc )
337     {
338     case 6 :
339         poGRW->sTable   = papszParam[3];
340         poGRW->sColumn  = papszParam[4];
341         poGRW->sWhere   = papszParam[5];
342         break;
343     case 5 :
344         if( OWIsNumeric( papszParam[4] ) )
345         {
346             poGRW->sDataTable   = papszParam[3];
347             poGRW->nRasterId    = (long long) CPLAtoGIntBig( papszParam[4]);
348             break;
349         }
350         else
351         {
352             poGRW->sTable   = papszParam[3];
353             poGRW->sColumn  = papszParam[4];
354             CSLDestroy(papszParam);
355             return poGRW;
356         }
357     case 4 :
358         poGRW->sTable   = papszParam[3];
359         CSLDestroy(papszParam);
360         return poGRW;
361     default :
362         CSLDestroy(papszParam);
363         return poGRW;
364     }
365 
366     CSLDestroy( papszParam );
367 
368     //  -------------------------------------------------------------------
369     //  Query all the basic information at once to reduce round trips
370     //  -------------------------------------------------------------------
371 
372     char szOwner[OWCODE];
373     char szTable[OWCODE];
374     char szColumn[OWTEXT];
375     char szDataTable[OWCODE];
376     char szWhere[OWTEXT];
377     long long nRasterId = -1;
378     OCILobLocator* phLocator = nullptr;
379 
380     szOwner[0]     = '\0';
381     szTable[0]     = '\0';
382     szColumn[0]    = '\0';
383     szDataTable[0] = '\0';
384     szWhere[0]     = '\0';
385 
386     if( ! poGRW->sOwner.empty() )
387     {
388       snprintf( szOwner, sizeof(szOwner), "%s", poGRW->sOwner.c_str() );
389     }
390 
391     if( ! poGRW->sTable.empty() )
392     {
393       snprintf( szTable, sizeof(szTable), "%s", poGRW->sTable.c_str() );
394     }
395 
396     if( ! poGRW->sColumn.empty() )
397     {
398       snprintf( szColumn, sizeof(szColumn), "%s", poGRW->sColumn.c_str() );
399     }
400 
401     if( ! poGRW->sDataTable.empty() )
402     {
403       snprintf( szDataTable, sizeof(szDataTable), "%s", poGRW->sDataTable.c_str() );
404     }
405 
406     nRasterId = poGRW->nRasterId;
407 
408     if( ! poGRW->sWhere.empty() )
409     {
410       snprintf( szWhere, sizeof(szWhere), "%s", poGRW->sWhere.c_str() );
411     }
412 
413     OWStatement* poStmt = poGRW->poConnection->CreateStatement(
414       "BEGIN\n"
415       "\n"
416       "    IF :datatable IS NOT NULL AND :rasterid IS NOT NULL THEN\n"
417       "\n"
418       "      EXECUTE IMMEDIATE\n"
419       "        'SELECT OWNER, TABLE_NAME, COLUMN_NAME\n"
420       "         FROM   ALL_SDO_GEOR_SYSDATA\n"
421       "         WHERE  RDT_TABLE_NAME = UPPER(:1)\n"
422       "           AND  RASTER_ID = :2'\n"
423       "        INTO  :owner, :table, :column\n"
424       "        USING :datatable, :rasterid;\n"
425       "\n"
426       "      EXECUTE IMMEDIATE\n"
427       "        'SELECT T.'||:column||'.METADATA.getClobVal()\n"
428       "         FROM   '||:owner||'.'||:table||' T\n"
429       "         WHERE  T.'||:column||'.RASTERDATATABLE = UPPER(:1)\n"
430       "           AND  T.'||:column||'.RASTERID = :2'\n"
431       "        INTO  :metadata\n"
432       "        USING :datatable, :rasterid;\n"
433       "      :counter := 1;\n"
434       "\n"
435       "    ELSE\n"
436       "\n"
437       "      EXECUTE IMMEDIATE\n"
438       "        'SELECT T.'||:column||'.RASTERDATATABLE,\n"
439       "                T.'||:column||'.RASTERID,\n"
440       "                T.'||:column||'.METADATA.getClobVal()\n"
441       "         FROM  '||:owner||'.'||:table||' T\n"
442       "         WHERE '||:where\n"
443       "        INTO  :datatable, :rasterid, :metadata;\n"
444       "      :counter := 1;\n"
445       "\n"
446       "    END IF;\n"
447       "\n"
448       "  EXCEPTION\n"
449       "    WHEN no_data_found THEN :counter := 0;\n"
450       "    WHEN too_many_rows THEN :counter := 2;\n"
451       "END;" );
452 
453     int nCounter = 0;
454 
455     poStmt->BindName( ":datatable", szDataTable );
456     poStmt->BindName( ":rasterid", &nRasterId );
457     poStmt->BindName( ":owner", szOwner );
458     poStmt->BindName( ":table", szTable );
459     poStmt->BindName( ":column", szColumn );
460     poStmt->BindName( ":where", szWhere );
461     poStmt->BindName( ":counter", &nCounter );
462     poStmt->BindName( ":metadata", &phLocator );
463 
464     CPLErrorReset();
465 
466     if( ! poStmt->Execute() )
467     {
468         delete poStmt;
469         delete poGRW;
470         return nullptr;
471     }
472 
473     if( nCounter < 1 )
474     {
475         delete poStmt;
476         delete poGRW;
477         return nullptr;
478     }
479 
480     poGRW->sSchema  = CPLSPrintf( "%s.", szOwner );
481     poGRW->sOwner   = szOwner;
482     poGRW->sTable   = szTable;
483     poGRW->sColumn  = szColumn;
484 
485     if( nCounter == 1 )
486     {
487         poGRW->bUniqueFound = true;
488     }
489     else
490     {
491         poGRW->bUniqueFound = false;
492 
493         delete poStmt;
494         return poGRW;
495     }
496 
497     poGRW->sDataTable   = szDataTable;
498     poGRW->nRasterId    = nRasterId;
499     poGRW->sWhere       = CPLSPrintf(
500         "T.%s.RASTERDATATABLE = UPPER('%s') AND T.%s.RASTERID = %lld",
501         poGRW->sColumn.c_str(),
502         poGRW->sDataTable.c_str(),
503         poGRW->sColumn.c_str(),
504         poGRW->nRasterId );
505 
506     //  -------------------------------------------------------------------
507     //  Read Metadata XML in text
508     //  -------------------------------------------------------------------
509 
510     CPLPushErrorHandler( CPLQuietErrorHandler );
511 
512     char* pszXML = poStmt->ReadCLob( phLocator );
513 
514     CPLPopErrorHandler();
515 
516     if( pszXML )
517     {
518         //  -----------------------------------------------------------
519         //  Get basic information from xml metadata
520         //  -----------------------------------------------------------
521 
522         poGRW->phMetadata = CPLParseXMLString( pszXML );
523         poGRW->GetRasterInfo();
524         poGRW->GetSpatialReference();
525     }
526     else
527     {
528         poGRW->sDataTable = "";
529         poGRW->nRasterId  = 0;
530     }
531 
532     //  -------------------------------------------------------------------
533     //  Clean up
534     //  -------------------------------------------------------------------
535 
536     poStmt->FreeLob(phLocator);
537     CPLFree( pszXML );
538     delete poStmt;
539 
540     //  -------------------------------------------------------------------
541     //  Return a GeoRasterWrapper object
542     //  -------------------------------------------------------------------
543 
544     return poGRW;
545 }
546 
547 //  ---------------------------------------------------------------------------
548 //                                                                     Create()
549 //  ---------------------------------------------------------------------------
550 
Create(char * pszDescription,char * pszInsert,bool bUpdateIn)551 bool GeoRasterWrapper::Create( char* pszDescription,
552                                char* pszInsert,
553                                bool bUpdateIn )
554 {
555     CPLString sValues;
556     CPLString sFormat;
557 
558     if( sTable.empty() ||
559         sColumn.empty() )
560     {
561         return false;
562     }
563 
564     //  -------------------------------------------------------------------
565     //  Parse RDT/RID from the current szValues
566     //  -------------------------------------------------------------------
567 
568     char szRDT[OWNAME];
569     char szRID[OWCODE];
570 
571     if( ! sDataTable.empty() )
572     {
573         snprintf( szRDT, sizeof(szRDT), "'%s'", sDataTable.c_str() );
574     }
575     else
576     {
577         snprintf( szRDT, sizeof(szRDT), "%s",
578                   OWParseSDO_GEOR_INIT( sValues.c_str(), 1 ).c_str() );
579     }
580 
581     if ( nRasterId > 0 )
582     {
583         snprintf( szRID, sizeof(szRID), "%lld", nRasterId );
584     }
585     else
586     {
587         snprintf( szRID, sizeof(szRID), "%s",
588                   OWParseSDO_GEOR_INIT( sValues.c_str(), 2 ).c_str() );
589 
590         if ( EQUAL( szRID, "" ) )
591         {
592             strcpy( szRID, "NULL" );
593         }
594     }
595 
596     //  -------------------------------------------------------------------
597     //  Description parameters
598     //  -------------------------------------------------------------------
599 
600     char szDescription[OWTEXT];
601 
602     if( bUpdateIn == false )
603     {
604 
605         if ( pszDescription  )
606         {
607             snprintf( szDescription, sizeof(szDescription), "%s", pszDescription );
608         }
609         else
610         {
611              snprintf( szDescription, sizeof(szDescription),
612                 "(%s MDSYS.SDO_GEORASTER)", sColumn.c_str() );
613         }
614 
615         //  ---------------------------------------------------------------
616         //  Insert parameters
617         //  ---------------------------------------------------------------
618 
619         if( pszInsert )
620         {
621             sValues = pszInsert;
622 
623             if( pszInsert[0] == '(' && sValues.ifind( "VALUES" ) == std::string::npos )
624             {
625                 sValues = CPLSPrintf( "VALUES %s", pszInsert );
626             }
627         }
628         else
629         {
630             sValues = CPLSPrintf( "VALUES (SDO_GEOR.INIT(%s,%s))", szRDT, szRID );
631         }
632     }
633 
634     //  -----------------------------------------------------------
635     //  Storage parameters
636     //  -----------------------------------------------------------
637 
638     nColumnBlockSize = nColumnBlockSize == 0 ? DEFAULT_BLOCK_COLUMNS : nColumnBlockSize;
639     nRowBlockSize    = nRowBlockSize    == 0 ? DEFAULT_BLOCK_ROWS    : nRowBlockSize;
640     nBandBlockSize   = nBandBlockSize   == 0 ? 1 : nBandBlockSize;
641 
642     //  -----------------------------------------------------------
643     //  Blocking storage parameters
644     //  -----------------------------------------------------------
645 
646     CPLString sBlocking;
647 
648     if( bBlocking == true )
649     {
650         if( bAutoBlocking == true )
651         {
652             int nBlockXSize = nColumnBlockSize;
653             int nBlockYSize = nRowBlockSize;
654             int nBlockBSize = nBandBlockSize;
655 
656             OWStatement* poStmt = poConnection->CreateStatement(
657                 "DECLARE\n"
658                 "  dimensionSize    sdo_number_array;\n"
659                 "  blockSize        sdo_number_array;\n"
660                 "BEGIN\n"
661                 "  dimensionSize := sdo_number_array(:1, :2, :3);\n"
662                 "  blockSize     := sdo_number_array(:4, :5, :6);\n"
663                 "  sdo_geor_utl.calcOptimizedBlockSize(dimensionSize,blockSize);\n"
664                 "  :4 := blockSize(1);\n"
665                 "  :5 := blockSize(2);\n"
666                 "  :6 := blockSize(3);\n"
667                 "END;" );
668 
669             poStmt->Bind( &nRasterColumns );
670             poStmt->Bind( &nRasterRows );
671             poStmt->Bind( &nRasterBands );
672             poStmt->Bind( &nBlockXSize );
673             poStmt->Bind( &nBlockYSize );
674             poStmt->Bind( &nBlockBSize );
675 
676             if( poStmt->Execute() )
677             {
678                 nColumnBlockSize = nBlockXSize;
679                 nRowBlockSize = nBlockYSize;
680                 nBandBlockSize = nBlockBSize;
681             }
682 
683             delete poStmt;
684         }
685 
686         if( nRasterBands == 1 )
687         {
688             sBlocking = CPLSPrintf(
689                 "blockSize=(%d, %d)",
690                 nRowBlockSize,
691                 nColumnBlockSize );
692         }
693         else
694         {
695             sBlocking = CPLSPrintf(
696                 "blockSize=(%d, %d, %d)",
697                 nRowBlockSize,
698                 nColumnBlockSize,
699                 nBandBlockSize );
700         }
701     }
702     else
703     {
704         sBlocking = "blocking=FALSE";
705 
706         nColumnBlockSize = nRasterColumns;
707         nRowBlockSize = nRasterRows;
708         nBandBlockSize = nRasterBands;
709     }
710 
711     //  -----------------------------------------------------------
712     //  Complete format parameters
713     //  -----------------------------------------------------------
714 
715     if( poConnection->GetVersion() > 10 )
716     {
717         if( nRasterBands == 1 )
718         {
719             sFormat = CPLSPrintf(
720                 "20001, '"
721                 "dimSize=(%d,%d) ",
722                 nRasterRows, nRasterColumns );
723         }
724         else
725         {
726             sFormat = CPLSPrintf(
727                 "21001, '"
728                 "dimSize=(%d,%d,%d) ",
729                 nRasterRows, nRasterColumns, nRasterBands );
730         }
731 
732         if( STARTS_WITH_CI(sCompressionType.c_str(), "JPEG") )
733         {
734             sFormat.append( CPLSPrintf(
735                     "%s "
736                     "cellDepth=%s "
737                     "interleaving=%s "
738                     "compression=%s "
739                     "quality=%d'",
740                     sBlocking.c_str(),
741                     sCellDepth.c_str(),
742                     sInterleaving.c_str(),
743                     sCompressionType.c_str(),
744                     nCompressQuality) );
745         }
746         else
747         {
748             sFormat.append( CPLSPrintf(
749                     "%s "
750                     "cellDepth=%s "
751                     "interleaving=%s "
752                     "compression=%s'",
753                     sBlocking.c_str(),
754                     sCellDepth.c_str(),
755                     sInterleaving.c_str(),
756                     sCompressionType.c_str() ) );
757         }
758     }
759     else
760     {
761         //  -------------------------------------------------------
762         //  For versions 10g or older
763         //  -------------------------------------------------------
764 
765         sFormat = CPLSPrintf(
766             "%s "
767             "cellDepth=%s "
768             "interleaving=%s "
769             "pyramid=FALSE "
770             "compression=NONE",
771             sBlocking.c_str(),
772             sCellDepth.c_str(),
773             sInterleaving.c_str() );
774     }
775 
776     nTotalColumnBlocks = (int)
777         ( ( nRasterColumns + nColumnBlockSize - 1 ) / nColumnBlockSize );
778 
779     nTotalRowBlocks = (int)
780         ( ( nRasterRows + nRowBlockSize - 1 ) / nRowBlockSize );
781 
782     nTotalBandBlocks = (int)
783         ( ( nRasterBands + nBandBlockSize - 1) / nBandBlockSize );
784 
785     //  -------------------------------------------------------------------
786     //  Create Georaster Table if needed
787     //  -------------------------------------------------------------------
788 
789     OWStatement* poStmt;
790 
791     if( ! bUpdateIn )
792     {
793         poStmt = poConnection->CreateStatement( CPLSPrintf(
794             "DECLARE\n"
795             "  TAB VARCHAR2(68)  := UPPER('%s');\n"
796             "  COL VARCHAR2(68)  := UPPER('%s');\n"
797             "  OWN VARCHAR2(68)  := UPPER('%s');\n"
798             "  CNT NUMBER        := 0;\n"
799             "BEGIN\n"
800             "  EXECUTE IMMEDIATE 'SELECT COUNT(*) FROM ALL_TABLES\n"
801             "    WHERE TABLE_NAME = :1 AND OWNER = UPPER(:2)'\n"
802             "      INTO CNT USING TAB, OWN;\n"
803             "\n"
804             "  IF CNT = 0 THEN\n"
805             "    EXECUTE IMMEDIATE 'CREATE TABLE %s%s %s';\n"
806             "    SDO_GEOR_UTL.createDMLTrigger( TAB,  COL );\n"
807             "  END IF;\n"
808             "END;",
809                 sTable.c_str(),
810                 sColumn.c_str(),
811                 sOwner.c_str(),
812                 sSchema.c_str(),
813                 sTable.c_str(),
814                 szDescription ) );
815 
816         if( ! poStmt->Execute() )
817         {
818             delete ( poStmt );
819             return false;
820         }
821 
822         delete poStmt;
823     }
824 
825     //  -----------------------------------------------------------
826     //  Prepare UPDATE or INSERT command
827     //  -----------------------------------------------------------
828 
829     CPLString sCommand;
830 
831     if( bUpdateIn )
832     {
833         sCommand = CPLSPrintf(
834             "SELECT %s INTO GR1 FROM %s%s T WHERE %s FOR UPDATE;",
835             sColumn.c_str(),
836             sSchema.c_str(),
837             sTable.c_str(),
838             sWhere.c_str() );
839     }
840     else
841     {
842         sCommand = CPLSPrintf(
843             "INSERT INTO %s%s %s RETURNING %s INTO GR1;",
844             sSchema.c_str(),
845             sTable.c_str(),
846             sValues.c_str(),
847             sColumn.c_str() );
848     }
849 
850     //  -----------------------------------------------------------
851     //  Create RTD if needed and insert/update GeoRaster
852     //  -----------------------------------------------------------
853 
854     char szBindRDT[OWNAME];
855     long long nBindRID = 0;
856     szBindRDT[0] = '\0';
857 
858     CPLString sObjectTable;
859     CPLString sSecureFile;
860 
861     // For version > 11 create RDT as relational table by default,
862     // if it is not specified by create-option OBJECTTABLE=TRUE
863 
864     if( poConnection->GetVersion() <= 11 || bCreateObjectTable )
865     {
866         sObjectTable = "OF MDSYS.SDO_RASTER\n      (";
867     }
868     else
869     {
870         sObjectTable = CPLSPrintf("(\n"
871                        "      RASTERID           NUMBER,\n"
872                        "      PYRAMIDLEVEL       NUMBER,\n"
873                        "      BANDBLOCKNUMBER    NUMBER,\n"
874                        "      ROWBLOCKNUMBER     NUMBER,\n"
875                        "      COLUMNBLOCKNUMBER  NUMBER,\n"
876                        "      BLOCKMBR           SDO_GEOMETRY,\n"
877                        "      RASTERBLOCK        BLOB,\n"
878                        "      CONSTRAINT '||:rdt||'_RDT_PK ");
879     }
880 
881     // For version >= 11 create RDT rasterBlock as securefile
882 
883     if( poConnection->GetVersion() >= 11 )
884     {
885         sSecureFile = "SECUREFILE(CACHE)";
886     }
887     else
888     {
889         sSecureFile = "(NOCACHE NOLOGGING)";
890     }
891 
892     if( poConnection->GetVersion() > 10 )
893     {
894         poStmt = poConnection->CreateStatement( CPLSPrintf(
895             "DECLARE\n"
896             "  TAB  VARCHAR2(68)    := UPPER('%s');\n"
897             "  COL  VARCHAR2(68)    := UPPER('%s');\n"
898             "  OWN  VARCHAR2(68)    := UPPER('%s');\n"
899             "  CNT  NUMBER          := 0;\n"
900             "  GR1  SDO_GEORASTER   := NULL;\n"
901             "BEGIN\n"
902             "\n"
903             "  %s\n"
904             "\n"
905             "  GR1.spatialExtent := NULL;\n"
906             "\n"
907             "  SELECT GR1.RASTERDATATABLE INTO :rdt FROM DUAL;\n"
908             "  SELECT GR1.RASTERID        INTO :rid FROM DUAL;\n"
909             "\n"
910             "  EXECUTE IMMEDIATE 'SELECT COUNT(*) FROM ALL_OBJECT_TABLES\n"
911             "    WHERE TABLE_NAME = :1 AND OWNER = UPPER(:2)'\n"
912             "      INTO CNT USING :rdt, OWN;\n"
913             "\n"
914             "  IF CNT = 0 THEN\n"
915             "    EXECUTE IMMEDIATE 'SELECT COUNT(*) FROM ALL_TABLES\n"
916             "      WHERE TABLE_NAME = :1 AND OWNER = UPPER(:2)'\n"
917             "        INTO CNT USING :rdt, OWN;\n"
918             "  END IF;\n"
919             "\n"
920             "  IF CNT = 0 THEN\n"
921             "    EXECUTE IMMEDIATE 'CREATE TABLE %s'||:rdt||' %s"
922             "PRIMARY KEY (RASTERID, PYRAMIDLEVEL,\n"
923             "      BANDBLOCKNUMBER, ROWBLOCKNUMBER, COLUMNBLOCKNUMBER))\n"
924             "      LOB(RASTERBLOCK) STORE AS %s';\n"
925             "  END IF;\n"
926             "\n"
927             "  SDO_GEOR.createTemplate(GR1, %s, null, 'TRUE');\n"
928             "\n"
929             "  UPDATE %s%s T SET %s = GR1 WHERE\n"
930             "    T.%s.RasterDataTable = :rdt AND\n"
931             "    T.%s.RasterId = :rid;\n"
932             "\n"
933             "  EXECUTE IMMEDIATE\n"
934             "    'SELECT T.%s.METADATA.getClobVal()\n"
935             "     FROM   %s%s T\n"
936             "     WHERE  T.%s.RASTERDATATABLE = UPPER(:1)\n"
937             "       AND  T.%s.RASTERID = :2'\n"
938             "      INTO  :metadata\n"
939             "     USING  :rdt, :rid;\n"
940             "\n"
941             "END;\n",
942                 sTable.c_str(),
943                 sColumn.c_str(),
944                 sOwner.c_str(),
945                 sCommand.c_str(),
946                 sSchema.c_str(),
947                 sObjectTable.c_str(),
948                 sSecureFile.c_str(),
949                 sFormat.c_str(),
950                 sSchema.c_str(),
951                 sTable.c_str(),
952                 sColumn.c_str(),
953                 sColumn.c_str(),
954                 sColumn.c_str(),
955                 sColumn.c_str(),
956                 sSchema.c_str(),
957                 sTable.c_str(),
958                 sColumn.c_str(),
959                 sColumn.c_str() ) );
960 
961         OCILobLocator* phLocator = nullptr;
962 
963         poStmt->BindName( ":metadata", &phLocator );
964         poStmt->BindName( ":rdt", szBindRDT );
965         poStmt->BindName( ":rid", &nBindRID );
966 
967         CPLErrorReset();
968 
969         if( ! poStmt->Execute() )
970         {
971             delete poStmt;
972             return false;
973         }
974 
975         sDataTable = szBindRDT;
976         nRasterId  = nBindRID;
977 
978         poStmt->FreeLob(phLocator);
979 
980         delete poStmt;
981 
982         return true;
983     }
984 
985     //  -----------------------------------------------------------
986     //  Procedure for Server version older than 11
987     //  -----------------------------------------------------------
988 
989     char szCreateBlank[OWTEXT];
990 
991     if( nRasterBands == 1 )
992     {
993         snprintf( szCreateBlank, sizeof(szCreateBlank),
994             "SDO_GEOR.createBlank(20001, "
995             "SDO_NUMBER_ARRAY(0, 0), "
996             "SDO_NUMBER_ARRAY(%d, %d), 0, :rdt, :rid)",
997             nRasterRows, nRasterColumns );
998     }
999     else
1000     {
1001         snprintf( szCreateBlank, sizeof(szCreateBlank),
1002             "SDO_GEOR.createBlank(21001, "
1003             "SDO_NUMBER_ARRAY(0, 0, 0), "
1004             "SDO_NUMBER_ARRAY(%d, %d, %d), 0, :rdt, :rid)",
1005             nRasterRows, nRasterColumns, nRasterBands );
1006     }
1007 
1008     poStmt = poConnection->CreateStatement( CPLSPrintf(
1009         "DECLARE\n"
1010         "  W    NUMBER          := :1;\n"
1011         "  H    NUMBER          := :2;\n"
1012         "  BB   NUMBER          := :3;\n"
1013         "  RB   NUMBER          := :4;\n"
1014         "  CB   NUMBER          := :5;\n"
1015         "  OWN  VARCHAR2(68)    := UPPER('%s');\n"
1016         "  X    NUMBER          := 0;\n"
1017         "  Y    NUMBER          := 0;\n"
1018         "  CNT  NUMBER          := 0;\n"
1019         "  GR1  SDO_GEORASTER   := NULL;\n"
1020         "  GR2  SDO_GEORASTER   := NULL;\n"
1021         "  STM  VARCHAR2(1024)  := '';\n"
1022         "BEGIN\n"
1023         "\n"
1024         "  %s\n"
1025         "\n"
1026         "  SELECT GR1.RASTERDATATABLE INTO :rdt FROM DUAL;\n"
1027         "  SELECT GR1.RASTERID        INTO :rid FROM DUAL;\n"
1028         "\n"
1029         "  SELECT %s INTO GR2 FROM %s%s T WHERE"
1030         " T.%s.RasterDataTable = :rdt AND"
1031         " T.%s.RasterId = :rid FOR UPDATE;\n"
1032         "\n"
1033         "  GR1 := %s;\n"
1034         "\n"
1035         "  SDO_GEOR.changeFormatCopy(GR1, '%s', GR2);\n"
1036         "\n"
1037         "  UPDATE %s%s T SET %s = GR2 WHERE"
1038         " T.%s.RasterDataTable = :rdt AND"
1039         " T.%s.RasterId = :rid;\n"
1040         "\n"
1041         "  EXECUTE IMMEDIATE 'SELECT COUNT(*) FROM ALL_OBJECT_TABLES\n"
1042         "    WHERE TABLE_NAME = :1 AND OWNER = UPPER(:2)'\n"
1043         "      INTO CNT USING :rdt, OWN;\n"
1044         "\n"
1045         "  IF CNT = 0 THEN\n"
1046         "    EXECUTE IMMEDIATE 'CREATE TABLE %s'||:rdt||' OF MDSYS.SDO_RASTER\n"
1047         "      (PRIMARY KEY (RASTERID, PYRAMIDLEVEL, BANDBLOCKNUMBER,\n"
1048         "      ROWBLOCKNUMBER, COLUMNBLOCKNUMBER))\n"
1049         "      LOB(RASTERBLOCK) STORE AS (NOCACHE NOLOGGING)';\n"
1050         "  ELSE\n"
1051         "    EXECUTE IMMEDIATE 'DELETE FROM %s'||:rdt||' WHERE RASTERID ='||:rid||' ';\n"
1052         "  END IF;\n"
1053         "\n"
1054         "  STM := 'INSERT INTO %s'||:rdt||' VALUES (:1,0,:2-1,:3-1,:4-1,\n"
1055         "    SDO_GEOMETRY(2003, NULL, NULL, SDO_ELEM_INFO_ARRAY(1, 1003, 3),\n"
1056         "    SDO_ORDINATE_ARRAY(:5,:6,:7-1,:8-1)), EMPTY_BLOB() )';\n\n"
1057         "  FOR b IN 1..BB LOOP\n"
1058         "    Y := 0;\n"
1059         "    FOR r IN 1..RB LOOP\n"
1060         "      X := 0;\n"
1061         "      FOR c IN 1..CB LOOP\n"
1062         "        EXECUTE IMMEDIATE STM USING :rid, b, r, c, Y, X, (Y+H), (X+W);\n"
1063         "        X := X + W;\n"
1064         "      END LOOP;\n"
1065         "      Y := Y + H;\n"
1066         "    END LOOP;\n"
1067         "  END LOOP;\n"
1068         "\n"
1069         "  SDO_GEOR.georeference(GR1, %d, %d,"
1070         " SDO_NUMBER_ARRAY(1.0, 0.0, 0.0),"
1071         " SDO_NUMBER_ARRAY(0.0, 1.0, 0.0));\n"
1072         "\n"
1073         "  UPDATE %s%s T SET %s = GR1 WHERE"
1074         " T.%s.RasterDataTable = :rdt AND"
1075         " T.%s.RasterId = :rid;\n"
1076         "\n"
1077         "END;",
1078             sOwner.c_str(),
1079             sCommand.c_str(),
1080             sColumn.c_str(), sSchema.c_str(), sTable.c_str(),
1081             sColumn.c_str(), sColumn.c_str(),
1082             szCreateBlank,
1083             sFormat.c_str(),
1084             sSchema.c_str(), sTable.c_str(),
1085             sColumn.c_str(), sColumn.c_str(), sColumn.c_str(),
1086             sSchema.c_str(), sSchema.c_str(), sSchema.c_str(),
1087             DEFAULT_CRS, MCL_DEFAULT,
1088             sSchema.c_str(), sTable.c_str(),
1089             sColumn.c_str(), sColumn.c_str(), sColumn.c_str() ) );
1090 
1091     poStmt->Bind( &nColumnBlockSize );
1092     poStmt->Bind( &nRowBlockSize );
1093     poStmt->Bind( &nTotalBandBlocks );
1094     poStmt->Bind( &nTotalRowBlocks );
1095     poStmt->Bind( &nTotalColumnBlocks );
1096 
1097     poStmt->BindName( ":rdt", szBindRDT );
1098     poStmt->BindName( ":rid", &nBindRID );
1099 
1100     if( ! poStmt->Execute() )
1101     {
1102         delete poStmt;
1103         return false;
1104     }
1105 
1106     sDataTable = szBindRDT;
1107     nRasterId  = nBindRID;
1108 
1109     delete poStmt;
1110 
1111     return true;
1112 }
1113 
1114 //  ---------------------------------------------------------------------------
1115 //                                                         PrepareToOverwrite()
1116 //  ---------------------------------------------------------------------------
1117 
PrepareToOverwrite(void)1118 void GeoRasterWrapper::PrepareToOverwrite( void )
1119 {
1120     nTotalColumnBlocks  = 0;
1121     nTotalRowBlocks     = 0;
1122     nTotalBandBlocks    = 0;
1123     if( sscanf( sCellDepth.c_str(), "%dBIT", &nCellSizeBits ) )
1124     {
1125         nGDALCellBytes   = GDALGetDataTypeSize(
1126                           OWGetDataType( sCellDepth.c_str() ) ) / 8;
1127     }
1128     else
1129     {
1130         nGDALCellBytes   = 1;
1131     }
1132     dfXCoefficient[0]   = 1.0;
1133     dfXCoefficient[1]   = 0.0;
1134     dfXCoefficient[2]   = 0.0;
1135     dfYCoefficient[0]   = 0.0;
1136     dfYCoefficient[1]   = 1.0;
1137     dfYCoefficient[2]   = 0.0;
1138     sCompressionType    = "NONE";
1139     nCompressQuality    = 75;
1140     bGenPyramid         = false;
1141     nPyramidLevels      = 0;
1142     sPyramidResampling  = "NN";
1143     bIsReferenced       = false;
1144     nCacheBlockId       = -1;
1145     nCurrentLevel       = -1;
1146     pahLevels           = nullptr;
1147     nLevelOffset        = 0L;
1148     sInterleaving       = "BSQ";
1149     bUpdate             = false;
1150     bInitializeIO       = false;
1151     bFlushMetadata      = false;
1152     nSRID               = DEFAULT_CRS;;
1153     nExtentSRID         = 0;
1154     bGenSpatialExtent    = false;
1155     bCreateObjectTable  = false;
1156     nPyramidMaxLevel    = 0;
1157     nBlockCount         = 0L;
1158     sDInfo.global_state = 0;
1159     sCInfo.global_state = 0;
1160     bHasBitmapMask      = false;
1161     bWriteOnly          = false;
1162     bBlocking           = true;
1163     bAutoBlocking       = false;
1164     eModelCoordLocation = MCL_DEFAULT;
1165     bFlushBlock         = false;
1166     nFlushBlockSize     = 0L;
1167     phRPC               = nullptr;
1168 }
1169 
1170 //  ---------------------------------------------------------------------------
1171 //                                                                     Delete()
1172 //  ---------------------------------------------------------------------------
1173 
Delete(void)1174 bool GeoRasterWrapper::Delete( void )
1175 {
1176     if( ! bUniqueFound )
1177     {
1178         return false;
1179     }
1180 
1181     OWStatement* poStmt = poConnection->CreateStatement( CPLSPrintf(
1182       "UPDATE %s%s T SET %s = NULL WHERE %s\n",
1183             sSchema.c_str(),
1184             sTable.c_str(),
1185             sColumn.c_str(),
1186             sWhere.c_str() ) );
1187 
1188     bool bReturn = poStmt->Execute();
1189 
1190     delete poStmt;
1191 
1192     return bReturn;
1193 }
1194 
1195 //  ---------------------------------------------------------------------------
1196 //                                                            SetGeoReference()
1197 //  ---------------------------------------------------------------------------
1198 
SetGeoReference(long long nSRIDIn)1199 void GeoRasterWrapper::SetGeoReference( long long nSRIDIn )
1200 {
1201     nSRID = nSRIDIn;
1202 
1203     bIsReferenced = true;
1204 
1205     bFlushMetadata = true;
1206 }
1207 
1208 //  ---------------------------------------------------------------------------
1209 //                                                              GetRasterInfo()
1210 //  ---------------------------------------------------------------------------
1211 
GetRasterInfo(void)1212 void GeoRasterWrapper::GetRasterInfo( void )
1213 {
1214     //  -------------------------------------------------------------------
1215     //  Get dimensions
1216     //  -------------------------------------------------------------------
1217 
1218     int nCount      = atoi( CPLGetXMLValue( phMetadata,
1219                   "rasterInfo.totalDimensions", "0" ) );
1220     CPLXMLNode* phDimSize   = CPLGetXMLNode( phMetadata, "rasterInfo.dimensionSize" );
1221 
1222     int i = 0;
1223 
1224     for( i = 0; i < nCount; i++ )
1225     {
1226         const char* pszType = CPLGetXMLValue( phDimSize, "type", "0" );
1227 
1228         if( EQUAL( pszType, "ROW" ) )
1229         {
1230             nRasterRows = atoi( CPLGetXMLValue( phDimSize, "size", "0" ) );
1231         }
1232 
1233         if( EQUAL( pszType, "COLUMN" ) )
1234         {
1235             nRasterColumns = atoi( CPLGetXMLValue( phDimSize, "size", "0" ) );
1236         }
1237 
1238         if( EQUAL( pszType, "BAND" ) )
1239         {
1240             nRasterBands = atoi( CPLGetXMLValue( phDimSize, "size", "0" ) );
1241         }
1242 
1243         phDimSize = phDimSize->psNext;
1244     }
1245 
1246     if( nRasterBands == 0 )
1247     {
1248         nRasterBands = 1;
1249     }
1250 
1251     //  -------------------------------------------------------------------
1252     //  Load NoData Values
1253     //  -------------------------------------------------------------------
1254 
1255     LoadNoDataValues();
1256 
1257     //  -------------------------------------------------------------------
1258     //  Get ULTCoordinate values
1259     //  -------------------------------------------------------------------
1260 
1261     anULTCoordinate[0] = atoi(CPLGetXMLValue(
1262             phMetadata, "rasterInfo.ULTCoordinate.column", "0"));
1263 
1264     anULTCoordinate[1] = atoi(CPLGetXMLValue(
1265             phMetadata, "rasterInfo.ULTCoordinate.row", "0"));
1266 
1267     anULTCoordinate[2] = atoi(CPLGetXMLValue(
1268             phMetadata, "rasterInfo.ULTCoordinate.band", "0"));
1269 
1270     //  -------------------------------------------------------------------
1271     //  Get Interleaving mode
1272     //  -------------------------------------------------------------------
1273 
1274     sInterleaving = CPLGetXMLValue( phMetadata,
1275         "rasterInfo.interleaving", "BSQ" );
1276 
1277     //  -------------------------------------------------------------------
1278     //  Get blocking
1279     //  -------------------------------------------------------------------
1280 
1281     nRowBlockSize       = atoi( CPLGetXMLValue( phMetadata,
1282                             "rasterInfo.blocking.rowBlockSize",
1283                             CPLSPrintf( "%d", nRasterRows ) ) );
1284 
1285     nColumnBlockSize    = atoi( CPLGetXMLValue( phMetadata,
1286                             "rasterInfo.blocking.columnBlockSize",
1287                             CPLSPrintf( "%d", nRasterColumns ) ) );
1288 
1289     nBandBlockSize      = atoi( CPLGetXMLValue( phMetadata,
1290                             "rasterInfo.blocking.bandBlockSize",
1291                             CPLSPrintf( "%d", nRasterBands ) ) );
1292 
1293     nTotalColumnBlocks  = atoi( CPLGetXMLValue( phMetadata,
1294                             "rasterInfo.blocking.totalColumnBlocks","1") );
1295 
1296     nTotalRowBlocks     = atoi( CPLGetXMLValue( phMetadata,
1297                             "rasterInfo.blocking.totalRowBlocks", "1" ) );
1298 
1299     nTotalBandBlocks    = atoi( CPLGetXMLValue( phMetadata,
1300                             "rasterInfo.blocking.totalBandBlocks", "1" ) );
1301 
1302     if( nBandBlockSize == -1 )
1303     {
1304        nBandBlockSize = nRasterBands;
1305     }
1306 
1307     //  -------------------------------------------------------------------
1308     //  Get data type
1309     //  -------------------------------------------------------------------
1310 
1311     sCellDepth = CPLGetXMLValue( phMetadata, "rasterInfo.cellDepth", "8BIT_U" );
1312 
1313     if( sscanf( sCellDepth.c_str(), "%dBIT", &nCellSizeBits ) )
1314     {
1315         nGDALCellBytes   = GDALGetDataTypeSize(
1316             OWGetDataType( sCellDepth.c_str() ) ) / 8;
1317     }
1318     else
1319     {
1320         nGDALCellBytes   = 1;
1321     }
1322 
1323     sCompressionType  = CPLGetXMLValue( phMetadata,
1324         "rasterInfo.compression.type", "NONE" );
1325 
1326     if( STARTS_WITH_CI(sCompressionType.c_str(), "JPEG") )
1327     {
1328         nCompressQuality = atoi( CPLGetXMLValue( phMetadata,
1329                             "rasterInfo.compression.quality", "75" ) );
1330     }
1331 
1332     if( STARTS_WITH_CI(sCompressionType.c_str(), "JPEG") )
1333     {
1334         sInterleaving = "BIP";
1335     }
1336 
1337     //  -------------------------------------------------------------------
1338     //  Get default RGB Bands
1339     //  -------------------------------------------------------------------
1340 
1341     iDefaultRedBand     = atoi( CPLGetXMLValue( phMetadata,
1342                             "objectInfo.defaultRed", "-1" ) );
1343 
1344     iDefaultGreenBand   = atoi( CPLGetXMLValue( phMetadata,
1345                             "objectInfo.defaultGreen", "-1" ) );
1346 
1347     iDefaultBlueBand    = atoi( CPLGetXMLValue( phMetadata,
1348                             "objectInfo.defaultBlue", "-1" ) );
1349 
1350     //  -------------------------------------------------------------------
1351     //  Get Pyramid details
1352     //  -------------------------------------------------------------------
1353 
1354     char szPyramidType[OWCODE];
1355 
1356     snprintf( szPyramidType, sizeof(szPyramidType), "%s",
1357               CPLGetXMLValue( phMetadata,
1358                             "rasterInfo.pyramid.type", "None" ) );
1359 
1360     if( EQUAL( szPyramidType, "DECREASE" ) )
1361     {
1362         nPyramidMaxLevel = atoi( CPLGetXMLValue( phMetadata,
1363                             "rasterInfo.pyramid.maxLevel", "0" ) );
1364     }
1365 
1366     //  -------------------------------------------------------------------
1367     //  Check for RPCs
1368     //  -------------------------------------------------------------------
1369 
1370     CPLXMLNode* phModelType = CPLGetXMLNode( phMetadata,
1371         "spatialReferenceInfo.modelType");
1372 
1373     for( int n = 1 ; phModelType ; phModelType = phModelType->psNext, n++ )
1374     {
1375         const char* pszModelType = CPLGetXMLValue( phModelType, ".", "None" );
1376 
1377         if( EQUAL( pszModelType, "StoredFunction" ) )
1378         {
1379             GetGCP();
1380         }
1381 
1382         if( EQUAL( pszModelType, "FunctionalFitting" ) )
1383         {
1384             GetRPC();
1385         }
1386     }
1387 
1388     //  -------------------------------------------------------------------
1389     //  Prepare to get Spatial reference system
1390     //  -------------------------------------------------------------------
1391 
1392     bIsReferenced       = EQUAL( "TRUE", CPLGetXMLValue( phMetadata,
1393                             "spatialReferenceInfo.isReferenced", "FALSE" ) );
1394 
1395     nSRID               = (long long) CPLAtoGIntBig( CPLGetXMLValue( phMetadata,
1396                             "spatialReferenceInfo.SRID", "0" ) );
1397 
1398     if( bIsReferenced == false || nSRID == 0 || nSRID == UNKNOWN_CRS )
1399     {
1400         return;
1401     }
1402 
1403 }
1404 
1405 //  ---------------------------------------------------------------------------
1406 //                                                                QueryWKText()
1407 //  ---------------------------------------------------------------------------
1408 
QueryWKText()1409 void GeoRasterWrapper::QueryWKText()
1410 {
1411     char* pszWKText = (char*) VSI_MALLOC2_VERBOSE( sizeof(char), 3 * OWTEXT);
1412     char* pszAuthority = (char*) VSI_MALLOC2_VERBOSE( sizeof(char), OWTEXT);
1413 
1414     OWStatement* poStmt = poConnection->CreateStatement(
1415         "select wktext, auth_name from mdsys.cs_srs "
1416         "where srid = :1 and wktext is not null" );
1417 
1418     poStmt->Bind( &nSRID );
1419     poStmt->Define( pszWKText, 3 * OWTEXT );
1420     poStmt->Define( pszAuthority, OWTEXT );
1421 
1422     if( poStmt->Execute() )
1423     {
1424         sWKText = pszWKText;
1425         sAuthority = pszAuthority;
1426     }
1427 
1428     CPLFree( pszWKText );
1429     CPLFree( pszAuthority );
1430 
1431     delete poStmt;
1432 }
1433 
1434 //  ---------------------------------------------------------------------------
1435 //                                                              GetStatistics()
1436 //  ---------------------------------------------------------------------------
1437 
GetStatistics(int nBand,char * pszMin,char * pszMax,char * pszMean,char * pszMedian,char * pszMode,char * pszStdDev,char * pszSampling)1438 bool GeoRasterWrapper::GetStatistics( int nBand,
1439                                       char* pszMin,
1440                                       char* pszMax,
1441                                       char* pszMean,
1442                                       char* pszMedian,
1443                                       char* pszMode,
1444                                       char* pszStdDev,
1445                                       char* pszSampling )
1446 {
1447     int n = 1;
1448 
1449     CPLXMLNode *phSubLayer = CPLGetXMLNode( phMetadata, "layerInfo.subLayer" );
1450 
1451     for( n = 1 ; phSubLayer ; phSubLayer = phSubLayer->psNext, n++ )
1452     {
1453         if( n == nBand && CPLGetXMLNode( phSubLayer, "statisticDataset" ) )
1454         {
1455             strncpy( pszSampling, CPLGetXMLValue( phSubLayer,
1456                 "statisticDataset.samplingFactor",  "0.0" ), MAX_DOUBLE_STR_REP );
1457             strncpy( pszMin, CPLGetXMLValue( phSubLayer,
1458                 "statisticDataset.MIN",  "0.0" ), MAX_DOUBLE_STR_REP );
1459             strncpy( pszMax, CPLGetXMLValue( phSubLayer,
1460                 "statisticDataset.MAX",  "0.0" ), MAX_DOUBLE_STR_REP );
1461             strncpy( pszMean, CPLGetXMLValue( phSubLayer,
1462                 "statisticDataset.MEAN", "0.0" ), MAX_DOUBLE_STR_REP );
1463             strncpy( pszMedian, CPLGetXMLValue( phSubLayer,
1464                 "statisticDataset.MEDIAN", "0.0" ), MAX_DOUBLE_STR_REP );
1465             strncpy( pszMode, CPLGetXMLValue( phSubLayer,
1466                 "statisticDataset.MODEVALUE", "0.0" ), MAX_DOUBLE_STR_REP );
1467             strncpy( pszStdDev, CPLGetXMLValue( phSubLayer,
1468                 "statisticDataset.STD",  "0.0" ), MAX_DOUBLE_STR_REP );
1469             return true;
1470         }
1471     }
1472     return false;
1473 }
1474 
1475 //  ---------------------------------------------------------------------------
1476 //                                                              SetStatistics()
1477 //  ---------------------------------------------------------------------------
1478 
SetStatistics(int nBand,const char * pszMin,const char * pszMax,const char * pszMean,const char * pszMedian,const char * pszMode,const char * pszStdDev,const char * pszSampling)1479 bool GeoRasterWrapper::SetStatistics( int nBand,
1480                                       const char* pszMin,
1481                                       const char* pszMax,
1482                                       const char* pszMean,
1483                                       const char* pszMedian,
1484                                       const char* pszMode,
1485                                       const char* pszStdDev,
1486                                       const char* pszSampling )
1487 {
1488     InitializeLayersNode();
1489 
1490     bFlushMetadata = true;
1491 
1492     int n = 1;
1493 
1494     CPLXMLNode* phSubLayer = CPLGetXMLNode( phMetadata, "layerInfo.subLayer" );
1495 
1496     for( n = 1 ; phSubLayer ; phSubLayer = phSubLayer->psNext, n++ )
1497     {
1498         if( n != nBand )
1499         {
1500             continue;
1501         }
1502 
1503         CPLXMLNode* psSDaset = CPLGetXMLNode( phSubLayer, "statisticDataset" );
1504 
1505         if( psSDaset != nullptr )
1506         {
1507             CPLRemoveXMLChild( phSubLayer, psSDaset );
1508             CPLDestroyXMLNode( psSDaset );
1509         }
1510 
1511         psSDaset = CPLCreateXMLNode(phSubLayer,CXT_Element,"statisticDataset");
1512 
1513         CPLCreateXMLElementAndValue(psSDaset,"samplingFactor", pszSampling );
1514         CPLCreateXMLElementAndValue(psSDaset,"MIN", pszMin );
1515         CPLCreateXMLElementAndValue(psSDaset,"MAX", pszMax );
1516         CPLCreateXMLElementAndValue(psSDaset,"MEAN", pszMean );
1517         CPLCreateXMLElementAndValue(psSDaset,"MEDIAN", pszMedian );
1518         CPLCreateXMLElementAndValue(psSDaset,"MODEVALUE", pszMode );
1519         CPLCreateXMLElementAndValue(psSDaset,"STD", pszStdDev );
1520 
1521         return true;
1522     }
1523     return false;
1524 }
1525 
1526 //  ---------------------------------------------------------------------------
1527 //                                                              HasColorTable()
1528 //  ---------------------------------------------------------------------------
1529 
HasColorMap(int nBand)1530 bool GeoRasterWrapper::HasColorMap( int nBand )
1531 {
1532     int n = 1;
1533 
1534     CPLXMLNode *psLayers = CPLGetXMLNode( phMetadata, "layerInfo.subLayer" );
1535 
1536     for( ; psLayers; psLayers = psLayers->psNext, n++ )
1537     {
1538         if( n == nBand )
1539         {
1540             if( CPLGetXMLNode( psLayers, "colorMap.colors" ) )
1541             {
1542                 return true;
1543             }
1544         }
1545     }
1546 
1547     return false;
1548 }
1549 
1550 //  ---------------------------------------------------------------------------
1551 //                                                        InitializeLayersNode()
1552 //  ---------------------------------------------------------------------------
1553 
InitializeLayersNode()1554 void GeoRasterWrapper::InitializeLayersNode()
1555 {
1556     CPLXMLNode *pslInfo  = CPLGetXMLNode( phMetadata, "layerInfo" );
1557 
1558     int n = 1;
1559 
1560     for( n = 0 ; n < nRasterBands; n++ )
1561     {
1562         CPLXMLNode *psSLayer = CPLGetXMLNode( pslInfo,    "subLayer" );
1563 
1564         if( psSLayer == nullptr )
1565         {
1566             psSLayer = CPLCreateXMLNode( pslInfo, CXT_Element, "subLayer" );
1567 
1568             CPLCreateXMLElementAndValue( psSLayer, "layerNumber",
1569                 CPLSPrintf( "%d", n + 1 ) );
1570 
1571             CPLCreateXMLElementAndValue( psSLayer, "layerDimensionOrdinate",
1572                 CPLSPrintf( "%d", n ) );
1573 
1574             CPLCreateXMLElementAndValue( psSLayer, "layerID", "" );
1575         }
1576     }
1577 }
1578 
1579 //  ---------------------------------------------------------------------------
1580 //                                                              GetColorTable()
1581 //  ---------------------------------------------------------------------------
1582 
GetColorMap(int nBand,GDALColorTable * poCT)1583 void GeoRasterWrapper::GetColorMap( int nBand, GDALColorTable* poCT )
1584 {
1585     GDALColorEntry oEntry;
1586 
1587     int n = 1;
1588 
1589     CPLXMLNode* psLayers = CPLGetXMLNode( phMetadata, "layerInfo.subLayer" );
1590 
1591     for( ; psLayers; psLayers = psLayers->psNext, n++ )
1592     {
1593         if( n != nBand )
1594         {
1595             continue;
1596         }
1597 
1598         CPLXMLNode* psColors = CPLGetXMLNode( psLayers, "colorMap.colors.cell" );
1599 
1600         for(  ; psColors; psColors = psColors->psNext )
1601         {
1602             const int iColor    = (short) atoi( CPLGetXMLValue( psColors, "value","0"));
1603             oEntry.c1 = (short) atoi( CPLGetXMLValue( psColors, "red",  "0"));
1604             oEntry.c2 = (short) atoi( CPLGetXMLValue( psColors, "green","0"));
1605             oEntry.c3 = (short) atoi( CPLGetXMLValue( psColors, "blue", "0"));
1606             oEntry.c4 = (short) atoi( CPLGetXMLValue( psColors, "alpha","0"));
1607             poCT->SetColorEntry( iColor, &oEntry );
1608         }
1609         break;
1610     }
1611 }
1612 
1613 //  ---------------------------------------------------------------------------
1614 //                                                              SetColorTable()
1615 //  ---------------------------------------------------------------------------
1616 
SetColorMap(int nBand,GDALColorTable * poCT)1617 void GeoRasterWrapper::SetColorMap( int nBand, GDALColorTable* poCT )
1618 {
1619     InitializeLayersNode();
1620 
1621     bFlushMetadata = true;
1622 
1623     GDALColorEntry oEntry;
1624 
1625     int n = 1;
1626 
1627     CPLXMLNode* phSubLayer = CPLGetXMLNode( phMetadata, "layerInfo.subLayer" );
1628 
1629     for( n = 1 ; phSubLayer ; phSubLayer = phSubLayer->psNext, n++ )
1630     {
1631         if( n != nBand )
1632         {
1633             continue;
1634         }
1635 
1636         CPLXMLNode* psCMap = CPLGetXMLNode( phSubLayer, "colorMap" );
1637 
1638         if( psCMap != nullptr )
1639         {
1640             CPLRemoveXMLChild( phSubLayer, psCMap );
1641             CPLDestroyXMLNode( psCMap );
1642         }
1643 
1644         psCMap = CPLCreateXMLNode( phSubLayer, CXT_Element, "colorMap" );
1645 
1646         CPLXMLNode* psColor = CPLCreateXMLNode( psCMap, CXT_Element, "colors" );
1647 
1648         // ------------------------------------------------
1649         // Clean existing colors entry (RGB color table)
1650         // ------------------------------------------------
1651 
1652         if( psColor != nullptr )
1653         {
1654             CPLRemoveXMLChild( psCMap, psColor );
1655             CPLDestroyXMLNode( psColor );
1656         }
1657 
1658         psColor = CPLCreateXMLNode( psCMap, CXT_Element, "colors" );
1659 
1660         int iColor = 0;
1661 
1662         int nCount = 0;
1663 
1664         switch( nCellSizeBits )
1665         {
1666             case 1 :
1667                 nCount = 2;
1668                 break;
1669             case 2 :
1670                 nCount = 4;
1671                 break;
1672             case 4:
1673                 nCount = 16;
1674                 break;
1675             default:
1676                 nCount = poCT->GetColorEntryCount();
1677         }
1678 
1679         for( iColor = 0; iColor < nCount; iColor++ )
1680         {
1681             poCT->GetColorEntryAsRGB( iColor, &oEntry );
1682 
1683             CPLXMLNode* psCell = CPLCreateXMLNode( psColor, CXT_Element, "cell" );
1684 
1685             CPLSetXMLValue( psCell, "#value", CPLSPrintf("%d", iColor) );
1686             CPLSetXMLValue( psCell, "#blue",  CPLSPrintf("%d", oEntry.c3) );
1687             CPLSetXMLValue( psCell, "#red",   CPLSPrintf("%d", oEntry.c1) );
1688             CPLSetXMLValue( psCell, "#green", CPLSPrintf("%d", oEntry.c2) );
1689             CPLSetXMLValue( psCell, "#alpha", CPLSPrintf("%d", oEntry.c4) );
1690         }
1691     }
1692 }
1693 
1694 //  ---------------------------------------------------------------------------
1695 //                                                               InitializeIO()
1696 //  ---------------------------------------------------------------------------
1697 
InitializeIO(void)1698 bool GeoRasterWrapper::InitializeIO( void )
1699 {
1700     bInitializeIO = true;
1701 
1702     // --------------------------------------------------------------------
1703     // Initialize Pyramid level details
1704     // --------------------------------------------------------------------
1705 
1706     pahLevels = (hLevelDetails*) CPLCalloc( sizeof(hLevelDetails),
1707                                             nPyramidMaxLevel + 1 );
1708 
1709     // --------------------------------------------------------------------
1710     // Calculate number and size of the blocks in level zero
1711     // --------------------------------------------------------------------
1712 
1713     nBlockCount = (unsigned long) ( nTotalColumnBlocks * nTotalRowBlocks * nTotalBandBlocks );
1714     nBlockBytes = (unsigned long) ( nColumnBlockSize * nRowBlockSize * nBandBlockSize *
1715                                     nCellSizeBits / 8L );
1716     nGDALBlockBytes = (unsigned long) ( nColumnBlockSize * nRowBlockSize * nGDALCellBytes );
1717 
1718     pahLevels[0].nColumnBlockSize   = nColumnBlockSize;
1719     pahLevels[0].nRowBlockSize      = nRowBlockSize;
1720     pahLevels[0].nTotalColumnBlocks = nTotalColumnBlocks;
1721     pahLevels[0].nTotalRowBlocks    = nTotalRowBlocks;
1722     pahLevels[0].nBlockCount        = nBlockCount;
1723     pahLevels[0].nBlockBytes        = nBlockBytes;
1724     pahLevels[0].nGDALBlockBytes    = nGDALBlockBytes;
1725     pahLevels[0].nOffset            = 0L;
1726 
1727     // --------------------------------------------------------------------
1728     // Calculate number and size of the blocks in Pyramid levels
1729     // --------------------------------------------------------------------
1730 
1731     int iLevel = 1;
1732 
1733     for( iLevel = 1; iLevel <= nPyramidMaxLevel; iLevel++ )
1734     {
1735         int nRBS = nRowBlockSize;
1736         int nCBS = nColumnBlockSize;
1737         int nTCB;
1738         int nTRB;
1739 
1740         // --------------------------------------------------------------------
1741         // Calculate the actual size of a lower resolution block
1742         // --------------------------------------------------------------------
1743 
1744         double dfScale = pow( (double) 2.0, (double) iLevel );
1745 
1746         int nXSize  = (int) floor( (double) nRasterColumns / dfScale );
1747         int nYSize  = (int) floor( (double) nRasterRows / dfScale );
1748         int nXBlock = (int) floor( (double) nCBS / 2.0 );
1749         int nYBlock = (int) floor( (double) nRBS / 2.0 );
1750 
1751         if( nXSize <= nXBlock && nYSize <= nYBlock )
1752         {
1753             // ------------------------------------------------------------
1754             // Calculate the size of the single small blocks
1755             // ------------------------------------------------------------
1756 
1757             nCBS = nXSize;
1758             nRBS = nYSize;
1759             nTCB = 1;
1760             nTRB = 1;
1761         }
1762         else
1763         {
1764             // ------------------------------------------------------------
1765             // Recalculate blocks quantity
1766             // ------------------------------------------------------------
1767 
1768             nTCB = (int) ceil( (double) nXSize / nCBS );
1769             nTRB = (int) ceil( (double) nYSize / nRBS );
1770         }
1771 
1772         // --------------------------------------------------------------------
1773         // Save level datails
1774         // --------------------------------------------------------------------
1775 
1776         pahLevels[iLevel].nColumnBlockSize   = nCBS;
1777         pahLevels[iLevel].nRowBlockSize      = nRBS;
1778         pahLevels[iLevel].nTotalColumnBlocks = nTCB;
1779         pahLevels[iLevel].nTotalRowBlocks    = nTRB;
1780         pahLevels[iLevel].nBlockCount        = (unsigned long ) ( nTCB * nTRB * nTotalBandBlocks );
1781         pahLevels[iLevel].nBlockBytes        = (unsigned long ) ( nCBS * nRBS * nBandBlockSize *
1782                                                                   nCellSizeBits / 8L );
1783         pahLevels[iLevel].nGDALBlockBytes    = (unsigned long ) ( nCBS * nRBS * nGDALCellBytes );
1784         pahLevels[iLevel].nOffset            = 0L;
1785     }
1786 
1787     // --------------------------------------------------------------------
1788     // Calculate total row count and level's offsets
1789     // --------------------------------------------------------------------
1790 
1791     nBlockCount = 0L;
1792 
1793     for( iLevel = 0; iLevel <= nPyramidMaxLevel; iLevel++ )
1794     {
1795         pahLevels[iLevel].nOffset = nBlockCount;
1796         nBlockCount += pahLevels[iLevel].nBlockCount;
1797     }
1798 
1799     // --------------------------------------------------------------------
1800     // Allocate buffer for one raster block
1801     // --------------------------------------------------------------------
1802 
1803     long nMaxBufferSize = MAX( nBlockBytes, nGDALBlockBytes );
1804 
1805     pabyBlockBuf = (GByte*) VSI_MALLOC_VERBOSE( nMaxBufferSize );
1806 
1807     if ( pabyBlockBuf == nullptr )
1808     {
1809         return false;
1810     }
1811 
1812     // --------------------------------------------------------------------
1813     // Allocate buffer for one compressed raster block
1814     // --------------------------------------------------------------------
1815 
1816     if( bUpdate && ! EQUAL( sCompressionType.c_str(), "NONE") )
1817     {
1818         pabyCompressBuf = (GByte*) VSI_MALLOC_VERBOSE( nMaxBufferSize );
1819 
1820         if ( pabyCompressBuf == nullptr )
1821         {
1822             return false;
1823         }
1824     }
1825 
1826     // --------------------------------------------------------------------
1827     // Allocate array of LOB Locators
1828     // --------------------------------------------------------------------
1829 
1830     pahLocator = (OCILobLocator**) VSI_MALLOC_VERBOSE( sizeof(void*) * nBlockCount );
1831 
1832     if ( pahLocator == nullptr )
1833     {
1834         return false;
1835     }
1836 
1837     //  --------------------------------------------------------------------
1838     //  Issue a statement to load the locators
1839     //  --------------------------------------------------------------------
1840 
1841     const char* pszUpdate = bUpdate ? "\nFOR UPDATE" : "";
1842 
1843     delete poBlockStmt;
1844     poBlockStmt = poConnection->CreateStatement( CPLSPrintf(
1845         "SELECT RASTERBLOCK\n"
1846         "FROM   %s%s\n"
1847         "WHERE  RASTERID = :1\n"
1848         "ORDER BY\n"
1849         "       PYRAMIDLEVEL ASC,\n"
1850         "       BANDBLOCKNUMBER ASC,\n"
1851         "       ROWBLOCKNUMBER ASC,\n"
1852         "       COLUMNBLOCKNUMBER ASC%s",
1853         sSchema.c_str(),
1854         sDataTable.c_str(),
1855         pszUpdate ) );
1856 
1857     poBlockStmt->Bind( &nRasterId );
1858     poBlockStmt->Define( pahLocator, nBlockCount );
1859 
1860     if( ! poBlockStmt->Execute( static_cast<int>(nBlockCount) ) )
1861     {
1862         return false;
1863     }
1864 
1865     return true;
1866 }
1867 
1868 //  ---------------------------------------------------------------------------
1869 //                                                            InitializeLevel()
1870 //  ---------------------------------------------------------------------------
1871 
InitializeLevel(int nLevel)1872 void GeoRasterWrapper::InitializeLevel( int nLevel )
1873 {
1874     nCurrentLevel       = nLevel;
1875     nColumnBlockSize    = pahLevels[nLevel].nColumnBlockSize;
1876     nRowBlockSize       = pahLevels[nLevel].nRowBlockSize;
1877     nTotalColumnBlocks  = pahLevels[nLevel].nTotalColumnBlocks;
1878     nTotalRowBlocks     = pahLevels[nLevel].nTotalRowBlocks;
1879     nBlockBytes         = pahLevels[nLevel].nBlockBytes;
1880     nGDALBlockBytes     = pahLevels[nLevel].nGDALBlockBytes;
1881     nLevelOffset        = pahLevels[nLevel].nOffset;
1882 }
1883 
1884 //  ---------------------------------------------------------------------------
1885 //                                                               GetDataBlock()
1886 //  ---------------------------------------------------------------------------
1887 
GetDataBlock(int nBand,int nLevel,int nXOffset,int nYOffset,void * pData)1888 bool GeoRasterWrapper::GetDataBlock( int nBand,
1889                                      int nLevel,
1890                                      int nXOffset,
1891                                      int nYOffset,
1892                                      void* pData )
1893 {
1894     if( ! bInitializeIO )
1895     {
1896         if( InitializeIO() == false )
1897         {
1898             return false;
1899         }
1900     }
1901 
1902     if( nCurrentLevel != nLevel && nLevel != DEFAULT_BMP_MASK )
1903     {
1904         InitializeLevel( nLevel );
1905     }
1906 
1907     long nBlock = GetBlockNumber( nBand, nXOffset, nYOffset );
1908 
1909     CPLDebug( "Read  ",
1910               "Block = %4ld Size = %7ld Band = %d Level = %d X = %d Y = %d",
1911               nBlock, nBlockBytes, nBand, nLevel, nXOffset, nYOffset );
1912 
1913     if( nCacheBlockId != nBlock )
1914     {
1915         if ( bFlushBlock )
1916         {
1917             if( ! FlushBlock( nCacheBlockId ) )
1918             {
1919                 return false;
1920             }
1921         }
1922 
1923         nCacheBlockId = nBlock;
1924 
1925         unsigned long nBytesRead = 0;
1926 
1927         nBytesRead = poBlockStmt->ReadBlob( pahLocator[nBlock],
1928                                             pabyBlockBuf,
1929                                             nBlockBytes );
1930 
1931         CPLDebug( "Load  ", "Block = %4ld Size = %7ld", nBlock, nBlockBytes );
1932 
1933         if( nBytesRead == 0 )
1934         {
1935             memset( pData, 0, nGDALBlockBytes );
1936             return true;
1937         }
1938 
1939         if( nBytesRead < nBlockBytes &&
1940             EQUAL( sCompressionType.c_str(), "NONE") )
1941         {
1942             CPLError( CE_Warning, CPLE_AppDefined,
1943                 "BLOB size (%ld) is smaller than expected (%ld) !",
1944                 nBytesRead,  nBlockBytes );
1945             memset( pData, 0, nGDALBlockBytes );
1946             return true;
1947         }
1948 
1949         if( nBytesRead > nBlockBytes )
1950         {
1951             CPLError( CE_Warning, CPLE_AppDefined,
1952                 "BLOB size (%ld) is bigger than expected (%ld) !",
1953                 nBytesRead,  nBlockBytes );
1954             memset( pData, 0, nGDALBlockBytes );
1955             return true;
1956         }
1957 
1958         //  ----------------------------------------------------------------
1959         //  GeoRaster BLOB is always Big endian
1960         //  ----------------------------------------------------------------
1961 
1962 #ifndef CPL_MSB
1963         if( nCellSizeBits > 8 &&
1964             EQUAL( sCompressionType.c_str(), "DEFLATE") == false )
1965         {
1966             int nWordSize  = nCellSizeBits / 8;
1967             int nWordCount = nColumnBlockSize * nRowBlockSize * nBandBlockSize;
1968             GDALSwapWords( pabyBlockBuf, nWordSize, nWordCount, nWordSize );
1969         }
1970 #endif
1971 
1972         //  ----------------------------------------------------------------
1973         //  Uncompress
1974         //  ----------------------------------------------------------------
1975 
1976         if( STARTS_WITH_CI(sCompressionType.c_str(), "JPEG") )
1977         {
1978             UncompressJpeg( nBytesRead );
1979         }
1980         else if ( EQUAL( sCompressionType.c_str(), "DEFLATE" ) )
1981         {
1982             UncompressDeflate( nBytesRead );
1983 #ifndef CPL_MSB
1984             if( nCellSizeBits > 8 )
1985             {
1986                 int nWordSize  = nCellSizeBits / 8;
1987                 int nWordCount = nColumnBlockSize * nRowBlockSize * nBandBlockSize;
1988                 GDALSwapWords( pabyBlockBuf, nWordSize, nWordCount, nWordSize );
1989             }
1990 #endif
1991         }
1992 
1993         //  ----------------------------------------------------------------
1994         //  Unpack NBits
1995         //  ----------------------------------------------------------------
1996 
1997         if( nCellSizeBits < 8 || nLevel == DEFAULT_BMP_MASK )
1998         {
1999             UnpackNBits( pabyBlockBuf );
2000         }
2001     }
2002 
2003     //  --------------------------------------------------------------------
2004     //  Uninterleaving, extract band from block buffer
2005     //  --------------------------------------------------------------------
2006 
2007     int nStart = ( nBand - 1 ) % nBandBlockSize;
2008 
2009     if( EQUAL( sInterleaving.c_str(), "BSQ" ) || nBandBlockSize == 1 )
2010     {
2011         nStart *= nGDALBlockBytes;
2012 
2013         memcpy( pData, &pabyBlockBuf[nStart], nGDALBlockBytes );
2014     }
2015     else
2016     {
2017         int nIncr   = nBandBlockSize * nGDALCellBytes;
2018         int nSize   = nGDALCellBytes;
2019 
2020         if( EQUAL( sInterleaving.c_str(), "BIL" ) )
2021         {
2022             nStart  *= nColumnBlockSize;
2023             nIncr   *= nColumnBlockSize;
2024             nSize   *= nColumnBlockSize;
2025         }
2026 
2027         GByte* pabyData = (GByte*) pData;
2028 
2029         unsigned long ii = 0;
2030         unsigned long jj = nStart * nGDALCellBytes;
2031 
2032         for( ii = 0; ii < nGDALBlockBytes; ii += nSize, jj += nIncr )
2033         {
2034             memcpy( &pabyData[ii], &pabyBlockBuf[jj], nSize );
2035         }
2036     }
2037 
2038     return true;
2039 }
2040 
2041 //  ---------------------------------------------------------------------------
2042 //                                                               SetDataBlock()
2043 //  ---------------------------------------------------------------------------
2044 
SetDataBlock(int nBand,int nLevel,int nXOffset,int nYOffset,void * pData)2045 bool GeoRasterWrapper::SetDataBlock( int nBand,
2046                                      int nLevel,
2047                                      int nXOffset,
2048                                      int nYOffset,
2049                                      void* pData )
2050 {
2051 #ifndef CPL_MSB
2052     if( nCellSizeBits > 8 )
2053     {
2054         int nWordSize  = nCellSizeBits / 8;
2055         int nWordCount = nColumnBlockSize * nRowBlockSize;
2056         GDALSwapWords( pData, nWordSize, nWordCount, nWordSize );
2057     }
2058 #endif
2059 
2060     if( ! bInitializeIO )
2061     {
2062         if( InitializeIO() == false )
2063         {
2064             return false;
2065         }
2066     }
2067 
2068     if( nCurrentLevel != nLevel )
2069     {
2070         InitializeLevel( nLevel );
2071     }
2072 
2073     long nBlock = GetBlockNumber( nBand, nXOffset, nYOffset );
2074 
2075     CPLDebug( "Write ",
2076               "Block = %4ld Size = %7ld Band = %d Level = %d X = %d Y = %d",
2077               nBlock, nBlockBytes, nBand, nLevel, nXOffset, nYOffset );
2078 
2079     //  --------------------------------------------------------------------
2080     //  Flush previous block
2081     //  --------------------------------------------------------------------
2082 
2083     if( nCacheBlockId != nBlock && bFlushBlock )
2084     {
2085         if( ! FlushBlock( nCacheBlockId ) )
2086         {
2087             return false;
2088         }
2089     }
2090 
2091     //  --------------------------------------------------------------------
2092     //  Re-load interleaved block
2093     //  --------------------------------------------------------------------
2094 
2095     if( nBandBlockSize > 1 && bWriteOnly == false && nCacheBlockId != nBlock )
2096     {
2097         nCacheBlockId = nBlock;
2098 
2099         unsigned long nBytesRead = 0;
2100 
2101         nBytesRead = poBlockStmt->ReadBlob( pahLocator[nBlock],
2102                                             pabyBlockBuf,
2103                                             static_cast<unsigned long>(nBlockBytes) );
2104 
2105         CPLDebug( "Reload", "Block = %4ld Size = %7ld", nBlock, nBlockBytes );
2106 
2107         if( nBytesRead == 0 )
2108         {
2109             memset( pabyBlockBuf, 0, nBlockBytes );
2110         }
2111         else
2112         {
2113             //  ------------------------------------------------------------
2114             //  Uncompress
2115             //  ------------------------------------------------------------
2116 
2117             if( STARTS_WITH_CI(sCompressionType.c_str(), "JPEG") )
2118             {
2119                 UncompressJpeg( nBytesRead );
2120             }
2121             else if ( EQUAL( sCompressionType.c_str(), "DEFLATE" ) )
2122             {
2123                 UncompressDeflate( nBytesRead );
2124             }
2125 
2126             //  ------------------------------------------------------------
2127             //  Unpack NBits
2128             //  ------------------------------------------------------------
2129 
2130             if( nCellSizeBits < 8 || nLevel == DEFAULT_BMP_MASK )
2131             {
2132                 UnpackNBits( pabyBlockBuf );
2133             }
2134         }
2135     }
2136 
2137     GByte *pabyInBuf = (GByte *) pData;
2138 
2139     //  --------------------------------------------------------------------
2140     //  Interleave
2141     //  --------------------------------------------------------------------
2142 
2143     int nStart = ( nBand - 1 ) % nBandBlockSize;
2144 
2145     if( EQUAL( sInterleaving.c_str(), "BSQ" ) || nBandBlockSize == 1 )
2146     {
2147         nStart *= nGDALBlockBytes;
2148 
2149         memcpy( &pabyBlockBuf[nStart], pabyInBuf, nGDALBlockBytes );
2150     }
2151     else
2152     {
2153         int nIncr   = nBandBlockSize * nGDALCellBytes;
2154         int nSize   = nGDALCellBytes;
2155 
2156         if( EQUAL( sInterleaving.c_str(), "BIL" ) )
2157         {
2158             nStart  *= nColumnBlockSize;
2159             nIncr   *= nColumnBlockSize;
2160             nSize   *= nColumnBlockSize;
2161         }
2162 
2163         unsigned long ii = 0;
2164         unsigned long jj = nStart * nGDALCellBytes;
2165 
2166         for( ii = 0; ii < nGDALBlockBytes; ii += nSize, jj += nIncr )
2167         {
2168             memcpy( &pabyBlockBuf[jj], &pabyInBuf[ii], nSize );
2169         }
2170     }
2171 
2172     //  --------------------------------------------------------------------
2173     //  Flag the flush block
2174     //  --------------------------------------------------------------------
2175 
2176     nCacheBlockId   = nBlock;
2177     bFlushBlock     = true;
2178     nFlushBlockSize = nBlockBytes;
2179 
2180     return true;
2181 }
2182 
2183 //  ---------------------------------------------------------------------------
2184 //                                                                 FlushBlock()
2185 //  ---------------------------------------------------------------------------
2186 
FlushBlock(long nCacheBlock)2187 bool GeoRasterWrapper::FlushBlock( long nCacheBlock )
2188 {
2189     GByte* pabyFlushBuffer = (GByte *) pabyBlockBuf;
2190 
2191     //  --------------------------------------------------------------------
2192     //  Pack bits ( inside pabyOutBuf )
2193     //  --------------------------------------------------------------------
2194 
2195     if( nCellSizeBits < 8 || nCurrentLevel == DEFAULT_BMP_MASK )
2196     {
2197         PackNBits( pabyFlushBuffer );
2198     }
2199 
2200     //  --------------------------------------------------------------------
2201     //  Compress ( from pabyBlockBuf to pabyBlockBuf2 )
2202     //  --------------------------------------------------------------------
2203 
2204     if( ! EQUAL( sCompressionType.c_str(), "NONE" ) )
2205     {
2206         if( STARTS_WITH_CI(sCompressionType.c_str(), "JPEG") )
2207         {
2208             nFlushBlockSize = CompressJpeg();
2209         }
2210         else if ( EQUAL( sCompressionType.c_str(), "DEFLATE" ) )
2211         {
2212             nFlushBlockSize = CompressDeflate();
2213         }
2214 
2215         pabyFlushBuffer = pabyCompressBuf;
2216     }
2217 
2218     //  --------------------------------------------------------------------
2219     //  Write BLOB
2220     //  --------------------------------------------------------------------
2221 
2222     CPLDebug( "Flush ", "Block = %4ld Size = %7ld", nCacheBlock,
2223               nFlushBlockSize );
2224 
2225     if( ! poBlockStmt->WriteBlob( pahLocator[nCacheBlock],
2226                                   pabyFlushBuffer,
2227                                   nFlushBlockSize ) )
2228     {
2229         return false;
2230     }
2231 
2232     bFlushBlock     = false;
2233     bFlushMetadata  = true;
2234     nFlushBlockSize = nBlockBytes;
2235 
2236     return true;
2237 }
2238 
2239 //  ---------------------------------------------------------------------------
2240 //                                                           LoadNoDataValues()
2241 //  ---------------------------------------------------------------------------
2242 static
AddToNoDataList(CPLXMLNode * phNode,int nNumber,CPLList * poList)2243 CPLList* AddToNoDataList( CPLXMLNode* phNode, int nNumber, CPLList* poList )
2244 {
2245     CPLXMLNode* psChild = phNode->psChild;
2246 
2247     const char* pszMin = nullptr;
2248     const char* pszMax = nullptr;
2249 
2250     for( ; psChild ; psChild = psChild->psNext )
2251     {
2252         if( EQUAL( psChild->pszValue, "value" ) )
2253         {
2254             pszMin = CPLGetXMLValue( psChild, nullptr, "NONE" );
2255             pszMax = pszMin;
2256         }
2257         else if ( EQUAL( psChild->pszValue, "range" ) )
2258         {
2259             pszMin = CPLGetXMLValue( psChild, "min", "NONE" );
2260             pszMax = CPLGetXMLValue( psChild, "max", "NONE" );
2261         }
2262         else
2263         {
2264             continue;
2265         }
2266 
2267         hNoDataItem* poItem = (hNoDataItem*) CPLMalloc( sizeof( hNoDataItem ) );
2268 
2269         poItem->nBand = nNumber;
2270         poItem->dfLower = CPLAtof( pszMin );
2271         poItem->dfUpper = CPLAtof( pszMax );
2272 
2273         poList = CPLListAppend( poList, poItem );
2274     }
2275 
2276     return poList;
2277 }
2278 
LoadNoDataValues(void)2279 void GeoRasterWrapper::LoadNoDataValues( void )
2280 {
2281     if( psNoDataList )
2282         return;
2283 
2284     CPLXMLNode* phLayerInfo = CPLGetXMLNode( phMetadata, "layerInfo" );
2285 
2286     if( phLayerInfo == nullptr )
2287     {
2288         return;
2289     }
2290 
2291     //  -------------------------------------------------------------------
2292     //  Load NoData from list of values and list of value ranges
2293     //  -------------------------------------------------------------------
2294 
2295     CPLXMLNode* phObjNoData = CPLGetXMLNode( phLayerInfo, "objectLayer.NODATA" );
2296 
2297     for( ; phObjNoData ; phObjNoData = phObjNoData->psNext )
2298     {
2299         psNoDataList = AddToNoDataList( phObjNoData, 0, psNoDataList );
2300     }
2301 
2302     CPLXMLNode* phSubLayer = CPLGetXMLNode( phLayerInfo, "subLayer" );
2303 
2304     for( ; phSubLayer ; phSubLayer = phSubLayer->psNext )
2305     {
2306         int nNumber = atoi( CPLGetXMLValue( phSubLayer, "layerNumber", "-1") );
2307 
2308         CPLXMLNode* phSubNoData = CPLGetXMLNode( phSubLayer, "NODATA" );
2309 
2310         if( phSubNoData )
2311         {
2312             psNoDataList = AddToNoDataList( phSubNoData, nNumber, psNoDataList );
2313         }
2314     }
2315 }
2316 
2317 //  ---------------------------------------------------------------------------
2318 //                                                        GetSpatialReference()
2319 //  ---------------------------------------------------------------------------
2320 
GetSpatialReference()2321 void GeoRasterWrapper::GetSpatialReference()
2322 {
2323     int i;
2324 
2325     CPLXMLNode* phSRSInfo = CPLGetXMLNode( phMetadata, "spatialReferenceInfo" );
2326 
2327     if( phSRSInfo == nullptr )
2328     {
2329         return;
2330     }
2331 
2332     const char* pszMCL = CPLGetXMLValue( phSRSInfo, "modelCoordinateLocation",
2333                                                     "CENTER" );
2334 
2335     if( EQUAL( pszMCL, "CENTER" ) )
2336     {
2337       eModelCoordLocation = MCL_CENTER;
2338     }
2339     else
2340     {
2341       eModelCoordLocation = MCL_UPPERLEFT;
2342     }
2343 
2344     const char* pszModelType = CPLGetXMLValue( phSRSInfo, "modelType", "None" );
2345 
2346     if( EQUAL( pszModelType, "FunctionalFitting" ) == false )
2347     {
2348         return;
2349     }
2350 
2351     CPLXMLNode* phPolyModel = CPLGetXMLNode( phSRSInfo, "polynomialModel" );
2352 
2353     if ( phPolyModel == nullptr )
2354     {
2355         return;
2356     }
2357 
2358     CPLXMLNode* phPolynomial = CPLGetXMLNode( phPolyModel, "pPolynomial" );
2359 
2360     if ( phPolynomial == nullptr )
2361     {
2362         return;
2363     }
2364 
2365     int nNumCoeff = atoi( CPLGetXMLValue( phPolynomial, "nCoefficients", "0" ));
2366 
2367     if ( nNumCoeff != 3 )
2368     {
2369         return;
2370     }
2371 
2372     const char* pszPolyCoeff = CPLGetXMLValue(phPolynomial,
2373                                               "polynomialCoefficients", "None");
2374 
2375     if ( EQUAL( pszPolyCoeff, "None" ) )
2376     {
2377         return;
2378     }
2379 
2380     char** papszCeoff = CSLTokenizeString2( pszPolyCoeff, " ",
2381                                            CSLT_STRIPLEADSPACES );
2382 
2383     if( CSLCount( papszCeoff ) < 3 )
2384     {
2385         CSLDestroy(papszCeoff);
2386         return;
2387     }
2388 
2389     double adfPCoef[3];
2390 
2391     for( i = 0; i < 3; i++ )
2392     {
2393         adfPCoef[i] = CPLAtof( papszCeoff[i] );
2394     }
2395     CSLDestroy(papszCeoff);
2396 
2397     phPolynomial = CPLGetXMLNode( phPolyModel, "rPolynomial" );
2398 
2399     if ( phPolynomial == nullptr )
2400     {
2401         return;
2402     }
2403 
2404     pszPolyCoeff = CPLGetXMLValue( phPolynomial, "polynomialCoefficients", "None" );
2405 
2406     if ( EQUAL( pszPolyCoeff, "None" ) )
2407     {
2408         return;
2409     }
2410 
2411     papszCeoff = CSLTokenizeString2( pszPolyCoeff, " ", CSLT_STRIPLEADSPACES );
2412 
2413     if( CSLCount( papszCeoff ) < 3 )
2414     {
2415         CSLDestroy(papszCeoff);
2416         return;
2417     }
2418 
2419     double adfRCoef[3];
2420 
2421     for( i = 0; i < 3; i++ )
2422     {
2423         adfRCoef[i] = CPLAtof( papszCeoff[i] );
2424     }
2425     CSLDestroy(papszCeoff);
2426 
2427     //  -------------------------------------------------------------------
2428     //  Inverse the transformation matrix
2429     //  -------------------------------------------------------------------
2430 
2431     double adfVal[6] = {1.0, 0.0, 0.0, 1.0, 0.0, 0.0};
2432 
2433     double dfDet = adfRCoef[1] * adfPCoef[2] - adfRCoef[2] * adfPCoef[1];
2434 
2435     if( CPLIsEqual( dfDet, 0.0 ) )
2436     {
2437         dfDet = 0.0000000001; // to avoid divide by zero
2438         CPLError( CE_Warning, CPLE_AppDefined, "Determinant is ZERO!!!");
2439     }
2440 
2441     adfVal[0] =   adfPCoef[2] / dfDet;
2442     adfVal[1] =  -adfRCoef[2] / dfDet;
2443     adfVal[2] = -(adfRCoef[0] * adfPCoef[2] - adfPCoef[0] * adfRCoef[2]) / dfDet;
2444     adfVal[3] =  -adfPCoef[1] / dfDet;
2445     adfVal[4] =   adfRCoef[1] / dfDet;
2446     adfVal[5] =  (adfRCoef[0] * adfPCoef[1] - adfPCoef[0] * adfRCoef[1]) / dfDet;
2447 
2448     //  -------------------------------------------------------------------
2449     //  Adjust Model Coordinate Location
2450     //  -------------------------------------------------------------------
2451 
2452     if ( eModelCoordLocation == MCL_CENTER )
2453     {
2454        adfVal[2] -= ( adfVal[0] / 2.0 );
2455        adfVal[5] -= ( adfVal[4] / 2.0 );
2456     }
2457 
2458     dfXCoefficient[0] = adfVal[0];
2459     dfXCoefficient[1] = adfVal[1];
2460     dfXCoefficient[2] = adfVal[2];
2461     dfYCoefficient[0] = adfVal[3];
2462     dfYCoefficient[1] = adfVal[4];
2463     dfYCoefficient[2] = adfVal[5];
2464 
2465     //  -------------------------------------------------------------------
2466     //  Apply ULTCoordinate
2467     //  -------------------------------------------------------------------
2468 
2469     dfXCoefficient[2] += ( anULTCoordinate[0] * dfXCoefficient[0] );
2470 
2471     dfYCoefficient[2] += ( anULTCoordinate[1] * dfYCoefficient[1] );
2472 }
2473 
2474 //  ---------------------------------------------------------------------------
2475 //                                                                     GetGCP()
2476 //  ---------------------------------------------------------------------------
2477 
GetGCP()2478 void GeoRasterWrapper::GetGCP()
2479 {
2480     CPLXMLNode* psGCP = CPLGetXMLNode( phMetadata,
2481                 "spatialReferenceInfo.gcpGeoreferenceModel.gcp" );
2482 
2483     CPLXMLNode* psFirst = psGCP;
2484 
2485     if( nGCPCount > 0 && pasGCPList )
2486     {
2487         GDALDeinitGCPs( nGCPCount, pasGCPList );
2488         CPLFree( pasGCPList );
2489     }
2490 
2491     pasGCPList = nullptr;
2492     nGCPCount = 0;
2493 
2494     for( int i = 1 ; psGCP ; psGCP = psGCP->psNext, i++ )
2495     {
2496         if( ! EQUAL( CPLGetXMLValue( psGCP, "type",  "" ), "ControlPoint" ) )
2497         {
2498             continue;
2499         }
2500         nGCPCount++;
2501     }
2502 
2503     pasGCPList = static_cast<GDAL_GCP *>(
2504             CPLCalloc(sizeof(GDAL_GCP), nGCPCount) );
2505 
2506     psGCP = psFirst;
2507 
2508     for( int i = 0 ; psGCP ; psGCP = psGCP->psNext, i++ )
2509     {
2510         if( ! EQUAL( CPLGetXMLValue( psGCP, "type",  "" ), "ControlPoint" ) )
2511         {
2512             continue;
2513         }
2514         pasGCPList[i].pszId    = CPLStrdup( CPLGetXMLValue( psGCP, "ID", "" ) );
2515         pasGCPList[i].pszInfo  = CPLStrdup( "" );
2516         pasGCPList[i].dfGCPLine  = CPLAtof( CPLGetXMLValue( psGCP, "row", "0.0" ) );
2517         pasGCPList[i].dfGCPPixel = CPLAtof( CPLGetXMLValue( psGCP, "column", "0.0" ) );
2518         pasGCPList[i].dfGCPX     = CPLAtof( CPLGetXMLValue( psGCP, "X", "0.0" ) );
2519         pasGCPList[i].dfGCPY     = CPLAtof( CPLGetXMLValue( psGCP, "Y", "0.0" ) );
2520         pasGCPList[i].dfGCPZ     = CPLAtof( CPLGetXMLValue( psGCP, "Z", "0.0" ));
2521     }
2522 }
2523 
2524 //  ---------------------------------------------------------------------------
2525 //                                                                     SetGCP()
2526 //  ---------------------------------------------------------------------------
2527 
SetGCP(int nGCPCountIn,const GDAL_GCP * pasGCPListIn)2528 void GeoRasterWrapper::SetGCP( int nGCPCountIn, const GDAL_GCP *pasGCPListIn)
2529 {
2530     if( nGCPCount > 0 )
2531     {
2532         GDALDeinitGCPs( nGCPCount, pasGCPList );
2533         CPLFree( pasGCPList );
2534     }
2535 
2536     nGCPCount  = nGCPCountIn;
2537     pasGCPList = GDALDuplicateGCPs(nGCPCount, pasGCPListIn);
2538     bFlushGCP  = true;
2539 }
2540 
FlushGCP()2541 void GeoRasterWrapper::FlushGCP()
2542 {
2543     const char* pszStatement = CPLSPrintf(
2544         "DECLARE\n"
2545         "  gr   sdo_georaster;\n"
2546         "BEGIN\n"
2547         "  SELECT %s INTO gr FROM %s%s t WHERE %s FOR UPDATE;\n",
2548             sColumn.c_str(),
2549             sSchema.c_str(),
2550             sTable.c_str(),
2551             sWhere.c_str());
2552 
2553     int nDimns = 2;
2554 
2555     for( int iGCP = 0; iGCP < nGCPCount; ++iGCP )
2556     {
2557         if( pasGCPList[iGCP].dfGCPZ != 0.0 )
2558         {
2559             nDimns = 3;
2560             break;
2561         }
2562     }
2563 
2564     if ( nDimns == 3 )
2565     {
2566         pszStatement = CPLSPrintf(
2567             "%s"
2568             "  sdo_geor.setControlPoint(gr,\n"
2569             "    SDO_GEOR_GCP(TO_CHAR(:1), '', 1,\n"
2570             "      2, sdo_number_array(:2, :3),\n"
2571             "      3, sdo_number_array(:4, :5, :6),\n"
2572             "      NULL, NULL));\n",
2573             pszStatement);
2574     }
2575     else
2576     {
2577         pszStatement = CPLSPrintf(
2578             "%s"
2579             "  sdo_geor.setControlPoint(gr,\n"
2580             "    SDO_GEOR_GCP(TO_CHAR(:1), '', 1,\n"
2581             "      2, sdo_number_array(:2, :3),\n"
2582             "      2, sdo_number_array(:4, :5),\n"
2583             "      NULL, NULL));\n",
2584             pszStatement);
2585     }
2586 
2587     pszStatement = CPLSPrintf(
2588             "%s"
2589             "  UPDATE %s%s t SET %s = gr WHERE %s;\n"
2590             "END;\n",
2591             pszStatement,
2592             sSchema.c_str(),
2593             sTable.c_str(),
2594             sColumn.c_str(),
2595             sWhere.c_str());
2596 
2597     OWStatement* poStmt = poConnection->CreateStatement( pszStatement );
2598 
2599     long   lBindN = 0L;
2600     double dBindL = 0.0;
2601     double dBindP = 0.0;
2602     double dBindX = 0.0;
2603     double dBindY = 0.0;
2604     double dBindZ = 0.0;
2605 
2606     poStmt->Bind( &lBindN );
2607     poStmt->Bind( &dBindL );
2608     poStmt->Bind( &dBindP );
2609     poStmt->Bind( &dBindX );
2610     poStmt->Bind( &dBindY );
2611 
2612     if ( nDimns == 3 )
2613     {
2614         poStmt->Bind( &dBindZ );
2615     }
2616 
2617     for( int iGCP = 0; iGCP < nGCPCount; ++iGCP )
2618     {
2619 
2620         // Assign bound variables
2621 
2622         lBindN = iGCP + 1;
2623         dBindL = pasGCPList[iGCP].dfGCPLine;
2624         dBindP = pasGCPList[iGCP].dfGCPPixel;
2625         dBindX = pasGCPList[iGCP].dfGCPX;
2626         dBindY = pasGCPList[iGCP].dfGCPY;
2627         dBindZ = nDimns == 3 ? pasGCPList[iGCP].dfGCPZ : 0.0;
2628 
2629         // To avoid cppcheck false positive complaints about unreadVariable
2630         CPL_IGNORE_RET_VAL(lBindN);
2631         CPL_IGNORE_RET_VAL(dBindL);
2632         CPL_IGNORE_RET_VAL(dBindP);
2633         CPL_IGNORE_RET_VAL(dBindX);
2634         CPL_IGNORE_RET_VAL(dBindY);
2635         CPL_IGNORE_RET_VAL(dBindZ);
2636 
2637         // Consume bound values
2638 
2639         if( ! poStmt->Execute() )
2640         {
2641             CPLError( CE_Failure, CPLE_AppDefined, "Error loading GCP.");
2642         }
2643     }
2644 
2645     delete poStmt;
2646 }
2647 
2648 //  ---------------------------------------------------------------------------
2649 //                                                                     GetRPC()
2650 //  ---------------------------------------------------------------------------
2651 
2652 /* This is the order for storing 20 coefficients in GeoRaster Metadata */
2653 
2654 constexpr int anOrder[] = {
2655     1, 2, 8, 12, 3, 5, 15, 9, 13, 16, 4, 6, 18, 7, 11, 19, 10, 14, 17, 20
2656 };
2657 
GetRPC()2658 void GeoRasterWrapper::GetRPC()
2659 {
2660     int i;
2661 
2662     CPLXMLNode* phSRSInfo = CPLGetXMLNode( phMetadata,
2663                                            "spatialReferenceInfo" );
2664 
2665     if( phSRSInfo == nullptr )
2666     {
2667         return;
2668     }
2669 
2670     CPLXMLNode* phPolyModel = CPLGetXMLNode( phSRSInfo, "polynomialModel" );
2671 
2672     if ( phPolyModel == nullptr )
2673     {
2674         return;
2675     }
2676 
2677     // pPolynomial refers to LINE_NUM
2678 
2679     CPLXMLNode* phPolynomial = CPLGetXMLNode( phPolyModel, "pPolynomial" );
2680 
2681     if ( phPolynomial == nullptr )
2682     {
2683         return;
2684     }
2685 
2686     int nNumCoeff = atoi( CPLGetXMLValue( phPolynomial, "nCoefficients", "0" ) );
2687 
2688     if ( nNumCoeff != 20 )
2689     {
2690         return;
2691     }
2692 
2693     const char* pszPolyCoeff = CPLGetXMLValue( phPolynomial, "polynomialCoefficients", "None" );
2694 
2695     if ( EQUAL( pszPolyCoeff, "None" ) )
2696     {
2697         return;
2698     }
2699 
2700     char** papszCeoff = CSLTokenizeString2( pszPolyCoeff, " ", CSLT_STRIPLEADSPACES );
2701 
2702     if( CSLCount( papszCeoff ) != 20 )
2703     {
2704         CSLDestroy(papszCeoff);
2705         return;
2706     }
2707 
2708     phRPC = (GDALRPCInfoV2*) VSIMalloc( sizeof(GDALRPCInfoV2) );
2709 
2710     phRPC->dfERR_BIAS = -1.0;
2711     phRPC->dfERR_RAND = -1.0;
2712     phRPC->dfLINE_OFF     = CPLAtof( CPLGetXMLValue( phPolyModel, "rowOff", "0" ) );
2713     phRPC->dfSAMP_OFF     = CPLAtof( CPLGetXMLValue( phPolyModel, "columnOff", "0" ) );
2714     phRPC->dfLONG_OFF     = CPLAtof( CPLGetXMLValue( phPolyModel, "xOff", "0" ) );
2715     phRPC->dfLAT_OFF      = CPLAtof( CPLGetXMLValue( phPolyModel, "yOff", "0" ) );
2716     phRPC->dfHEIGHT_OFF   = CPLAtof( CPLGetXMLValue( phPolyModel, "zOff", "0" ) );
2717 
2718     phRPC->dfLINE_SCALE   = CPLAtof( CPLGetXMLValue( phPolyModel, "rowScale", "0" ) );
2719     phRPC->dfSAMP_SCALE   = CPLAtof( CPLGetXMLValue( phPolyModel, "columnScale", "0" ) );
2720     phRPC->dfLONG_SCALE   = CPLAtof( CPLGetXMLValue( phPolyModel, "xScale", "0" ) );
2721     phRPC->dfLAT_SCALE    = CPLAtof( CPLGetXMLValue( phPolyModel, "yScale", "0" ) );
2722     phRPC->dfHEIGHT_SCALE = CPLAtof( CPLGetXMLValue( phPolyModel, "zScale", "0" ) );
2723 
2724     for( i = 0; i < 20; i++ )
2725     {
2726         phRPC->adfLINE_NUM_COEFF[anOrder[i] - 1] = CPLAtof( papszCeoff[i] );
2727     }
2728     CSLDestroy(papszCeoff);
2729 
2730     // qPolynomial refers to LINE_DEN
2731 
2732     phPolynomial = CPLGetXMLNode( phPolyModel, "qPolynomial" );
2733 
2734     if ( phPolynomial == nullptr )
2735     {
2736         CPLFree( phRPC );
2737         phRPC = nullptr;
2738         return;
2739     }
2740 
2741     pszPolyCoeff = CPLGetXMLValue( phPolynomial, "polynomialCoefficients", "None" );
2742 
2743     if ( EQUAL( pszPolyCoeff, "None" ) )
2744     {
2745         CPLFree( phRPC );
2746         phRPC = nullptr;
2747         return;
2748     }
2749 
2750     papszCeoff = CSLTokenizeString2( pszPolyCoeff, " ", CSLT_STRIPLEADSPACES );
2751 
2752     if( CSLCount( papszCeoff ) != 20 )
2753     {
2754         CPLFree( phRPC );
2755         phRPC = nullptr;
2756         CSLDestroy(papszCeoff);
2757         return;
2758     }
2759 
2760     for( i = 0; i < 20; i++ )
2761     {
2762         phRPC->adfLINE_DEN_COEFF[anOrder[i] - 1] = CPLAtof( papszCeoff[i] );
2763     }
2764     CSLDestroy(papszCeoff);
2765 
2766     // rPolynomial refers to SAMP_NUM
2767 
2768     phPolynomial = CPLGetXMLNode( phPolyModel, "rPolynomial" );
2769 
2770     if ( phPolynomial == nullptr )
2771     {
2772         CPLFree( phRPC );
2773         phRPC = nullptr;
2774         return;
2775     }
2776 
2777     pszPolyCoeff = CPLGetXMLValue( phPolynomial, "polynomialCoefficients", "None" );
2778 
2779     if ( EQUAL( pszPolyCoeff, "None" ) )
2780     {
2781         CPLFree( phRPC );
2782         phRPC = nullptr;
2783         return;
2784     }
2785 
2786     papszCeoff = CSLTokenizeString2( pszPolyCoeff, " ", CSLT_STRIPLEADSPACES );
2787 
2788     if( CSLCount( papszCeoff ) != 20 )
2789     {
2790         CPLFree( phRPC );
2791         phRPC = nullptr;
2792         CSLDestroy(papszCeoff);
2793         return;
2794     }
2795 
2796     for( i = 0; i < 20; i++ )
2797     {
2798         phRPC->adfSAMP_NUM_COEFF[anOrder[i] - 1] = CPLAtof( papszCeoff[i] );
2799     }
2800     CSLDestroy(papszCeoff);
2801 
2802     // sPolynomial refers to SAMP_DEN
2803 
2804     phPolynomial = CPLGetXMLNode( phPolyModel, "sPolynomial" );
2805 
2806     if ( phPolynomial == nullptr )
2807     {
2808         CPLFree( phRPC );
2809         phRPC = nullptr;
2810         return;
2811     }
2812 
2813     pszPolyCoeff = CPLGetXMLValue( phPolynomial, "polynomialCoefficients", "None" );
2814 
2815     if ( EQUAL( pszPolyCoeff, "None" ) )
2816     {
2817         CPLFree( phRPC );
2818         phRPC = nullptr;
2819         return;
2820     }
2821 
2822     papszCeoff = CSLTokenizeString2( pszPolyCoeff, " ", CSLT_STRIPLEADSPACES );
2823 
2824     if( CSLCount( papszCeoff ) != 20 )
2825     {
2826         CPLFree( phRPC );
2827         phRPC = nullptr;
2828         CSLDestroy(papszCeoff);
2829         return;
2830     }
2831 
2832     for( i = 0; i < 20; i++ )
2833     {
2834         phRPC->adfSAMP_DEN_COEFF[anOrder[i] - 1] = CPLAtof( papszCeoff[i] );
2835     }
2836     CSLDestroy(papszCeoff);
2837 }
2838 
2839 //  ---------------------------------------------------------------------------
2840 //                                                                     SetRPC()
2841 //  ---------------------------------------------------------------------------
2842 
SetRPC()2843 void GeoRasterWrapper::SetRPC()
2844 {
2845     //  -------------------------------------------------------------------
2846     //  Remove "layerInfo" tree
2847     //  -------------------------------------------------------------------
2848 
2849     CPLXMLNode* phLayerInfo = CPLGetXMLNode( phMetadata, "layerInfo" );
2850     CPLXMLNode* phClone = nullptr;
2851 
2852     if( phLayerInfo )
2853     {
2854         phClone = CPLCloneXMLTree( phLayerInfo );
2855         CPLRemoveXMLChild( phMetadata, phLayerInfo );
2856     }
2857 
2858     //  -------------------------------------------------------------------
2859     //  Start loading the RPC to "spatialReferenceInfo" tree
2860     //  -------------------------------------------------------------------
2861 
2862     int i = 0;
2863     CPLString osField, osMultiField;
2864     CPLXMLNode* phPolynomial = nullptr;
2865 
2866     CPLXMLNode* phSRSInfo = CPLGetXMLNode( phMetadata,
2867                                            "spatialReferenceInfo" );
2868 
2869     if( ! phSRSInfo )
2870     {
2871         phSRSInfo = CPLCreateXMLNode( phMetadata, CXT_Element,
2872                                       "spatialReferenceInfo" );
2873     }
2874     else
2875     {
2876         CPLXMLNode* phNode = CPLGetXMLNode( phSRSInfo, "isReferenced" );
2877         if( phNode )
2878         {
2879             CPLRemoveXMLChild( phSRSInfo, phNode );
2880         }
2881 
2882         phNode = CPLGetXMLNode( phSRSInfo, "SRID" );
2883         if( phNode )
2884         {
2885             CPLRemoveXMLChild( phSRSInfo, phNode );
2886         }
2887 
2888         phNode = CPLGetXMLNode( phSRSInfo, "modelCoordinateLocation" );
2889         if( phNode )
2890         {
2891             CPLRemoveXMLChild( phSRSInfo, phNode );
2892         }
2893 
2894         phNode = CPLGetXMLNode( phSRSInfo, "modelType" );
2895         if( phNode )
2896         {
2897             CPLRemoveXMLChild( phSRSInfo, phNode );
2898         }
2899 
2900         phNode = CPLGetXMLNode( phSRSInfo, "polynomialModel" );
2901         if( phNode )
2902         {
2903             CPLRemoveXMLChild( phSRSInfo, phNode );
2904         }
2905     }
2906 
2907     CPLCreateXMLElementAndValue( phSRSInfo, "isReferenced", "true" );
2908     CPLCreateXMLElementAndValue( phSRSInfo, "SRID", "4327" );
2909     CPLCreateXMLElementAndValue( phSRSInfo, "modelCoordinateLocation",
2910                                             "CENTER" );
2911     CPLCreateXMLElementAndValue( phSRSInfo, "modelType", "FunctionalFitting" );
2912     CPLSetXMLValue( phSRSInfo, "polynomialModel.#rowOff",
2913                                     CPLSPrintf( "%.15g", phRPC->dfLINE_OFF ) );
2914     CPLSetXMLValue( phSRSInfo, "polynomialModel.#columnOff",
2915                                     CPLSPrintf( "%.15g", phRPC->dfSAMP_OFF ) );
2916     CPLSetXMLValue( phSRSInfo, "polynomialModel.#xOff",
2917                                     CPLSPrintf( "%.15g", phRPC->dfLONG_OFF ) );
2918     CPLSetXMLValue( phSRSInfo, "polynomialModel.#yOff",
2919                                     CPLSPrintf( "%.15g", phRPC->dfLAT_OFF ) );
2920     CPLSetXMLValue( phSRSInfo, "polynomialModel.#zOff",
2921                                     CPLSPrintf( "%.15g", phRPC->dfHEIGHT_OFF ) );
2922     CPLSetXMLValue( phSRSInfo, "polynomialModel.#rowScale",
2923                                     CPLSPrintf( "%.15g", phRPC->dfLINE_SCALE ) );
2924     CPLSetXMLValue( phSRSInfo, "polynomialModel.#columnScale",
2925                                     CPLSPrintf( "%.15g", phRPC->dfSAMP_SCALE ) );
2926     CPLSetXMLValue( phSRSInfo, "polynomialModel.#xScale",
2927                                     CPLSPrintf( "%.15g", phRPC->dfLONG_SCALE ) );
2928     CPLSetXMLValue( phSRSInfo, "polynomialModel.#yScale",
2929                                     CPLSPrintf( "%.15g", phRPC->dfLAT_SCALE ) );
2930     CPLSetXMLValue( phSRSInfo, "polynomialModel.#zScale",
2931                                     CPLSPrintf( "%.15g", phRPC->dfHEIGHT_SCALE ) );
2932     CPLXMLNode*     phPloyModel = CPLGetXMLNode( phSRSInfo, "polynomialModel" );
2933 
2934     // pPolynomial refers to LINE_NUM
2935 
2936     CPLSetXMLValue( phPloyModel, "pPolynomial.#pType",         "1" );
2937     CPLSetXMLValue( phPloyModel, "pPolynomial.#nVars",         "3" );
2938     CPLSetXMLValue( phPloyModel, "pPolynomial.#order",         "3" );
2939     CPLSetXMLValue( phPloyModel, "pPolynomial.#nCoefficients", "20" );
2940     for( i = 0; i < 20; i++ )
2941     {
2942         osField.Printf( "%.15g", phRPC->adfLINE_NUM_COEFF[anOrder[i] - 1] );
2943         if( i > 0 )
2944             osMultiField += " ";
2945         else
2946             osMultiField = "";
2947         osMultiField += osField;
2948     }
2949     phPolynomial = CPLGetXMLNode( phPloyModel, "pPolynomial" );
2950     CPLCreateXMLElementAndValue( phPolynomial, "polynomialCoefficients",
2951                                  osMultiField );
2952 
2953     // qPolynomial refers to LINE_DEN
2954 
2955     CPLSetXMLValue( phPloyModel, "qPolynomial.#pType",         "1" );
2956     CPLSetXMLValue( phPloyModel, "qPolynomial.#nVars",         "3" );
2957     CPLSetXMLValue( phPloyModel, "qPolynomial.#order",         "3" );
2958     CPLSetXMLValue( phPloyModel, "qPolynomial.#nCoefficients", "20" );
2959     for( i = 0; i < 20; i++ )
2960     {
2961         osField.Printf( "%.15g", phRPC->adfLINE_DEN_COEFF[anOrder[i] - 1] );
2962         if( i > 0 )
2963             osMultiField += " ";
2964         else
2965             osMultiField = "";
2966         osMultiField += osField;
2967     }
2968     phPolynomial = CPLGetXMLNode( phPloyModel, "qPolynomial" );
2969     CPLCreateXMLElementAndValue( phPolynomial, "polynomialCoefficients",
2970                                  osMultiField );
2971 
2972     // rPolynomial refers to SAMP_NUM
2973 
2974     CPLSetXMLValue( phPloyModel, "rPolynomial.#pType",         "1" );
2975     CPLSetXMLValue( phPloyModel, "rPolynomial.#nVars",         "3" );
2976     CPLSetXMLValue( phPloyModel, "rPolynomial.#order",         "3" );
2977     CPLSetXMLValue( phPloyModel, "rPolynomial.#nCoefficients", "20" );
2978     for( i = 0; i < 20; i++ )
2979     {
2980         osField.Printf( "%.15g", phRPC->adfSAMP_NUM_COEFF[anOrder[i] - 1] );
2981         if( i > 0 )
2982             osMultiField += " ";
2983         else
2984             osMultiField = "";
2985         osMultiField += osField;
2986     }
2987     phPolynomial = CPLGetXMLNode( phPloyModel, "rPolynomial" );
2988     CPLCreateXMLElementAndValue( phPolynomial, "polynomialCoefficients",
2989                                  osMultiField );
2990 
2991     // sPolynomial refers to SAMP_DEN
2992 
2993     CPLSetXMLValue( phPloyModel, "sPolynomial.#pType",         "1" );
2994     CPLSetXMLValue( phPloyModel, "sPolynomial.#nVars",         "3" );
2995     CPLSetXMLValue( phPloyModel, "sPolynomial.#order",         "3" );
2996     CPLSetXMLValue( phPloyModel, "sPolynomial.#nCoefficients", "20" );
2997     for( i = 0; i < 20; i++ )
2998     {
2999         osField.Printf( "%.15g", phRPC->adfSAMP_DEN_COEFF[anOrder[i] - 1] );
3000         if( i > 0 )
3001             osMultiField += " ";
3002         else
3003             osMultiField = "";
3004         osMultiField += osField;
3005     }
3006     phPolynomial = CPLGetXMLNode( phPloyModel, "sPolynomial" );
3007     CPLCreateXMLElementAndValue( phPolynomial, "polynomialCoefficients",
3008                                  osMultiField );
3009 
3010     //  -------------------------------------------------------------------
3011     //  Add "layerInfo" tree back
3012     //  -------------------------------------------------------------------
3013 
3014     if( phClone )
3015     {
3016         CPLAddXMLChild( phMetadata, phClone );
3017     }
3018 }
3019 
3020 //  ---------------------------------------------------------------------------
3021 //                                                                 SetMaxLeve()
3022 //  ---------------------------------------------------------------------------
3023 
SetMaxLevel(int nLevels)3024 void GeoRasterWrapper::SetMaxLevel( int nLevels )
3025 {
3026     CPLXMLNode* psNode = CPLGetXMLNode( phMetadata, "rasterInfo.pyramid" );
3027 
3028     if( psNode )
3029     {
3030         CPLSetXMLValue( psNode, "type", "DECREASE" );
3031         CPLSetXMLValue( psNode, "maxLevel", CPLSPrintf( "%d", nLevels ) );
3032     }
3033 }
3034 
3035 //  ---------------------------------------------------------------------------
3036 //                                                                  GetNoData()
3037 //  ---------------------------------------------------------------------------
3038 
GetNoData(int nLayer,double * pdfNoDataValue)3039 bool GeoRasterWrapper::GetNoData( int nLayer, double* pdfNoDataValue )
3040 {
3041     if( psNoDataList == nullptr || CPLListCount( psNoDataList ) == 0 )
3042     {
3043         return false;
3044     }
3045 
3046     //  -------------------------------------------------------------------
3047     //  Get only single value NoData, no list of values or value ranges
3048     //  -------------------------------------------------------------------
3049 
3050     int nCount = 0;
3051     double dfValue = 0.0;
3052 
3053     CPLList* psList = nullptr;
3054 
3055     //  -------------------------------------------------------------------
3056     //  Process Object Layer values
3057     //  -------------------------------------------------------------------
3058 
3059     for( psList = psNoDataList; psList ; psList = psList->psNext )
3060     {
3061         hNoDataItem* phItem = (hNoDataItem*) psList->pData;
3062 
3063         if( phItem->nBand == 0 )
3064         {
3065             if( phItem->dfLower == phItem->dfUpper )
3066             {
3067                 dfValue = phItem->dfLower;
3068                 nCount++;
3069             }
3070             else
3071             {
3072                 return false; // value range
3073             }
3074         }
3075     }
3076 
3077     //  -------------------------------------------------------------------
3078     //  Values from the Object Layer override values from the layers
3079     //  -------------------------------------------------------------------
3080 
3081     if( nCount == 1 )
3082     {
3083         *pdfNoDataValue = dfValue;
3084         return true;
3085     }
3086 
3087     //  -------------------------------------------------------------------
3088     //  Process SubLayer values
3089     //  -------------------------------------------------------------------
3090 
3091     for( psList = psNoDataList; psList ; psList = psList->psNext )
3092     {
3093         hNoDataItem* phItem = (hNoDataItem*) psList->pData;
3094 
3095         if( phItem->nBand == nLayer )
3096         {
3097             if( phItem->dfLower == phItem->dfUpper )
3098             {
3099                 dfValue = phItem->dfLower;
3100                 nCount++;
3101             }
3102             else
3103             {
3104                 return false; // value range
3105             }
3106         }
3107     }
3108 
3109     if( nCount == 1 )
3110     {
3111         *pdfNoDataValue = dfValue;
3112         return true;
3113     }
3114 
3115     return false;
3116 }
3117 
3118 //  ---------------------------------------------------------------------------
3119 //                                                             SetNoDataValue()
3120 //  ---------------------------------------------------------------------------
3121 
SetNoData(int nLayer,const char * pszValue)3122 bool GeoRasterWrapper::SetNoData( int nLayer, const char* pszValue )
3123 {
3124     // ------------------------------------------------------------
3125     //  Set one NoData per dataset on "rasterInfo" section (10g)
3126     // ------------------------------------------------------------
3127 
3128     if( poConnection->GetVersion() < 11 )
3129     {
3130         CPLXMLNode* psRInfo = CPLGetXMLNode( phMetadata, "rasterInfo" );
3131         CPLXMLNode* psNData = CPLSearchXMLNode( psRInfo, "NODATA" );
3132 
3133         if( psNData == nullptr )
3134         {
3135             psNData = CPLCreateXMLNode( nullptr, CXT_Element, "NODATA" );
3136 
3137             CPLXMLNode* psCDepth = CPLGetXMLNode( psRInfo, "cellDepth" );
3138 
3139             CPLXMLNode* psPointer = psCDepth->psNext;
3140             psCDepth->psNext = psNData;
3141             psNData->psNext = psPointer;
3142         }
3143 
3144         CPLSetXMLValue( psRInfo, "NODATA", pszValue );
3145         bFlushMetadata = true;
3146         return true;
3147     }
3148 
3149     // ------------------------------------------------------------
3150     //  Add NoData for all bands (layer=0) or for a specific band
3151     // ------------------------------------------------------------
3152 
3153     char szRDT[OWCODE];
3154     char szNoData[OWTEXT];
3155 
3156     snprintf( szRDT, sizeof(szRDT), "%s", sDataTable.c_str() );
3157     snprintf( szNoData, sizeof(szNoData), "%s", pszValue );
3158 
3159     long long  nRID = nRasterId;
3160 
3161     // ------------------------------------------------------------
3162     //  Write the in memory XML metadata to avoid losing other changes.
3163     // ------------------------------------------------------------
3164 
3165     char* pszMetadata = CPLSerializeXMLTree( phMetadata );
3166 
3167     if( pszMetadata == nullptr )
3168     {
3169         return false;
3170     }
3171 
3172     OCILobLocator* phLocatorR = nullptr;
3173     OCILobLocator* phLocatorW = nullptr;
3174 
3175     OWStatement* poStmt = poConnection->CreateStatement( CPLSPrintf(
3176         "DECLARE\n"
3177         "  GR1 sdo_georaster;\n"
3178         "BEGIN\n"
3179         "  SELECT %s INTO GR1 FROM %s%s T WHERE %s FOR UPDATE;\n"
3180         "\n"
3181         "  GR1.metadata := sys.xmltype.createxml(:1);\n"
3182         "\n"
3183         "  SDO_GEOR.addNODATA( GR1, :2, :3 );\n"
3184         "\n"
3185         "  UPDATE %s%s T SET %s = GR1 WHERE %s;\n"
3186         "\n"
3187         "  EXECUTE IMMEDIATE\n"
3188         "    'SELECT T.%s.METADATA.getClobVal() FROM %s%s T \n"
3189         "     WHERE  T.%s.RASTERDATATABLE = UPPER(:1)\n"
3190         "       AND  T.%s.RASTERID = :2'\n"
3191         "    INTO :metadata USING :rdt, :rid;\n"
3192         "END;",
3193             sColumn.c_str(), sSchema.c_str(), sTable.c_str(), sWhere.c_str(),
3194             sSchema.c_str(), sTable.c_str(), sColumn.c_str(), sWhere.c_str(),
3195             sColumn.c_str(), sSchema.c_str(), sTable.c_str(),
3196             sColumn.c_str(),
3197             sColumn.c_str() ) );
3198 
3199     poStmt->WriteCLob( &phLocatorW, pszMetadata );
3200 
3201     poStmt->Bind( &phLocatorW );
3202     poStmt->Bind( &nLayer );
3203     poStmt->Bind( szNoData );
3204     poStmt->BindName( ":metadata", &phLocatorR );
3205     poStmt->BindName( ":rdt", szRDT );
3206     poStmt->BindName( ":rid", &nRID );
3207 
3208     CPLFree( pszMetadata );
3209 
3210     if( ! poStmt->Execute() )
3211     {
3212         poStmt->FreeLob(phLocatorR);
3213         poStmt->FreeLob(phLocatorW);
3214         delete poStmt;
3215         return false;
3216     }
3217 
3218     poStmt->FreeLob(phLocatorW);
3219 
3220     // ------------------------------------------------------------
3221     //  Read the XML metadata from db to memory with nodata updates
3222     // ------------------------------------------------------------
3223 
3224     char* pszXML = poStmt->ReadCLob( phLocatorR );
3225 
3226     if( pszXML )
3227     {
3228         CPLDestroyXMLNode( phMetadata );
3229         phMetadata = CPLParseXMLString( pszXML );
3230         CPLFree( pszXML );
3231     }
3232 
3233     poStmt->FreeLob(phLocatorR);
3234 
3235     bFlushMetadata = true;
3236     delete poStmt;
3237     return false;
3238 }
3239 
3240 //  ---------------------------------------------------------------------------
3241 //                                                                     SetVAT()
3242 //  ---------------------------------------------------------------------------
3243 
SetVAT(int nBand,const char * pszName)3244 bool GeoRasterWrapper::SetVAT( int nBand, const char* pszName )
3245 {
3246     InitializeLayersNode();
3247 
3248     bFlushMetadata = true;
3249 
3250     int n = 1;
3251 
3252     CPLXMLNode* psLayers = CPLGetXMLNode( phMetadata, "layerInfo.subLayer" );
3253 
3254     for( ; psLayers; psLayers = psLayers->psNext, n++ )
3255     {
3256         if( n != nBand )
3257         {
3258             continue;
3259         }
3260 
3261         CPLXMLNode* psVAT = CPLGetXMLNode( psLayers, "vatTableName" );
3262 
3263         if( psVAT != nullptr )
3264         {
3265             CPLRemoveXMLChild( psLayers, psVAT );
3266             CPLDestroyXMLNode( psVAT );
3267         }
3268 
3269         CPLCreateXMLElementAndValue(psLayers, "vatTableName", pszName );
3270 
3271         // ------------------------------------------------------------
3272         // To be updated at Flush Metadata in SDO_GEOR.setVAT()
3273         // ------------------------------------------------------------
3274 
3275         sValueAttributeTab = pszName;
3276 
3277         return true;
3278     }
3279 
3280     return false;
3281 }
3282 
3283 //  ---------------------------------------------------------------------------
3284 //                                                                     GetVAT()
3285 //  ---------------------------------------------------------------------------
3286 
GetVAT(int nBand)3287 char* GeoRasterWrapper::GetVAT( int nBand )
3288 {
3289     CPLXMLNode* psLayers = CPLGetXMLNode( phMetadata, "layerInfo.subLayer" );
3290 
3291     if( psLayers == nullptr )
3292     {
3293         return nullptr;
3294     }
3295 
3296     char* pszTablename = nullptr;
3297 
3298     int n = 1;
3299 
3300     for( ; psLayers; psLayers = psLayers->psNext, n++ )
3301     {
3302         if( n != nBand )
3303         {
3304             continue;
3305         }
3306 
3307         CPLXMLNode* psVAT = CPLGetXMLNode( psLayers, "vatTableName" );
3308 
3309         if( psVAT != nullptr )
3310         {
3311             pszTablename = CPLStrdup(
3312                 CPLGetXMLValue( psLayers, "vatTableName", "" ) );
3313         }
3314 
3315         break;
3316     }
3317 
3318     return pszTablename;
3319 }
3320 
3321 //  ---------------------------------------------------------------------------
3322 //                                                              FlushMetadata()
3323 //  ---------------------------------------------------------------------------
3324 
FlushMetadata()3325 bool GeoRasterWrapper::FlushMetadata()
3326 {
3327     if( bFlushBlock )
3328     {
3329         FlushBlock( nCacheBlockId );
3330     }
3331 
3332     if( ! bFlushMetadata )
3333     {
3334         return true;
3335     }
3336 
3337     bFlushMetadata = false;
3338 
3339     //  --------------------------------------------------------------------
3340     //  Change the isBlank setting left by SDO_GEOR.createBlank() to 'false'
3341     //  --------------------------------------------------------------------
3342 
3343     CPLXMLNode* psOInfo = CPLGetXMLNode( phMetadata, "objectInfo" );
3344 
3345     CPLSetXMLValue( psOInfo,  "isBlank", "false" );
3346 
3347     CPLXMLNode* psNode  = CPLGetXMLNode( psOInfo, "blankCellValue" );
3348 
3349     if( psNode != nullptr )
3350     {
3351         CPLRemoveXMLChild( psOInfo, psNode );
3352         CPLDestroyXMLNode( psNode );
3353     }
3354 
3355     const char* pszRed   = "1";
3356     const char* pszGreen = "1";
3357     const char* pszBlue  = "1";
3358 
3359     if( ( nRasterBands > 2 ) &&
3360         ( ! HasColorMap( 1 ) ) &&
3361         ( ! HasColorMap( 2 ) ) &&
3362         ( ! HasColorMap( 3 ) ) )
3363     {
3364         pszRed   = "1";
3365         pszGreen = "2";
3366         pszBlue  = "3";
3367     }
3368 
3369     psNode = CPLGetXMLNode( psOInfo, "defaultRed" );
3370     if( psNode )
3371     {
3372         CPLRemoveXMLChild( psOInfo, psNode );
3373         CPLDestroyXMLNode( psNode );
3374     }
3375     CPLCreateXMLElementAndValue( psOInfo, "defaultRed",   pszRed );
3376 
3377     psNode = CPLGetXMLNode( psOInfo, "defaultGreen" );
3378     if( psNode )
3379     {
3380         CPLRemoveXMLChild( psOInfo, psNode );
3381         CPLDestroyXMLNode( psNode );
3382     }
3383     CPLCreateXMLElementAndValue( psOInfo, "defaultGreen",   pszGreen );
3384 
3385     psNode = CPLGetXMLNode( psOInfo, "defaultBlue" );
3386     if( psNode )
3387     {
3388         CPLRemoveXMLChild( psOInfo, psNode );
3389         CPLDestroyXMLNode( psNode );
3390     }
3391     CPLCreateXMLElementAndValue( psOInfo, "defaultBlue",   pszBlue );
3392 
3393     //  --------------------------------------------------------------------
3394     //  Set compression
3395     //  --------------------------------------------------------------------
3396 
3397     psNode = CPLGetXMLNode( phMetadata, "rasterInfo.compression" );
3398 
3399     if( psNode )
3400     {
3401         CPLSetXMLValue( psNode, "type", sCompressionType.c_str() );
3402 
3403         if( STARTS_WITH_CI(sCompressionType.c_str(), "JPEG") )
3404         {
3405             CPLSetXMLValue( psNode, "quality",
3406                 CPLSPrintf( "%d", nCompressQuality ) );
3407         }
3408     }
3409 
3410     //  --------------------------------------------------------------------
3411     //  Update BitmapMask info
3412     //  --------------------------------------------------------------------
3413 
3414     if( bHasBitmapMask )
3415     {
3416         CPLXMLNode* psLayers = CPLGetXMLNode( phMetadata, "layerInfo" );
3417 
3418         if( psLayers )
3419         {
3420             CPLCreateXMLElementAndValue( psLayers, "bitmapMask", "true" );
3421         }
3422     }
3423 
3424     //  --------------------------------------------------------------------
3425     //  Update the Metadata directly from the XML text
3426     //  --------------------------------------------------------------------
3427 
3428     double dfXCoef[3];
3429     double dfYCoef[3];
3430     int nMLC;
3431 
3432     dfXCoef[0] = dfXCoefficient[0];
3433     dfXCoef[1] = dfXCoefficient[1];
3434     dfXCoef[2] = dfXCoefficient[2];
3435 
3436     dfYCoef[0] = dfYCoefficient[0];
3437     dfYCoef[1] = dfYCoefficient[1];
3438     dfYCoef[2] = dfYCoefficient[2];
3439 
3440     if ( eModelCoordLocation == MCL_CENTER )
3441     {
3442         dfXCoef[2] += ( dfXCoefficient[0] / 2.0 );
3443         dfYCoef[2] += ( dfYCoefficient[1] / 2.0 );
3444         nMLC = MCL_CENTER;
3445     }
3446     else
3447     {
3448         nMLC = MCL_UPPERLEFT;
3449     }
3450 
3451     if( phRPC )
3452     {
3453         SetRPC();
3454         nSRID = NO_CRS;
3455     }
3456 
3457     //  --------------------------------------------------------------------
3458     //  Serialize XML metadata to plain text
3459     //  --------------------------------------------------------------------
3460 
3461     char* pszMetadata = CPLSerializeXMLTree( phMetadata );
3462 
3463     if( pszMetadata == nullptr )
3464     {
3465         return false;
3466     }
3467 
3468     //  --------------------------------------------------------------------
3469     //  Search for existing Spatial Index SRID
3470     //  --------------------------------------------------------------------
3471 
3472     OWStatement* poStmt = (OWStatement*) nullptr;
3473 
3474     if ( nSRID != UNKNOWN_CRS && bGenSpatialExtent )
3475     {
3476         long long nIdxSRID = -1;
3477 
3478         poStmt = poConnection->CreateStatement( CPLSPrintf(
3479             "DECLARE\n"
3480             "  IDX_SRID NUMBER;\n"
3481             "BEGIN\n"
3482             "  BEGIN\n"
3483             "    EXECUTE IMMEDIATE \n"
3484             "         'SELECT SRID FROM ALL_SDO_GEOM_METADATA ' || \n"
3485             "         'WHERE OWNER = ''%s'' AND ' || \n"
3486             "         'TABLE_NAME  = ''%s'' AND ' || \n"
3487             "         'COLUMN_NAME = ''%s'' || ''.SPATIALEXTENT'' '\n"
3488             "      INTO IDX_SRID;\n"
3489             "  EXCEPTION\n"
3490             "    WHEN NO_DATA_FOUND THEN\n"
3491             "      IDX_SRID := -1;\n"
3492             "  END;\n"
3493             "  :idx_srid := IDX_SRID;\n"
3494             "END;",
3495                 sOwner.c_str(),
3496                 sTable.c_str(),
3497                 sColumn.c_str()));
3498 
3499         poStmt->BindName( ":idx_srid", &nIdxSRID );
3500 
3501         if( ! poStmt->Execute() )
3502         {
3503             nIdxSRID = -1;
3504         }
3505 
3506         if ( nIdxSRID != -1 )
3507         {
3508             if ( nExtentSRID == 0 )
3509             {
3510                 nExtentSRID = nIdxSRID;
3511             }
3512             else
3513             {
3514                 if ( nExtentSRID != nIdxSRID )
3515                 {
3516                     CPLError( CE_Warning, CPLE_AppDefined,
3517                       "Cannot generate spatialExtent, "
3518                       "Spatial Index SRID is (%lld)",
3519                       nIdxSRID );
3520 
3521                     nExtentSRID = 0;
3522                 }
3523             }
3524         }
3525         else
3526         {
3527             if (nExtentSRID == 0)
3528                 nExtentSRID = nSRID;
3529         }
3530 
3531         delete poStmt;
3532 
3533         CPLDebug("GEOR","nIdxSRID    = %lld",nIdxSRID);
3534     }
3535     else
3536     {
3537         nExtentSRID = 0;
3538     }
3539 
3540     if ( nSRID == 0 || nSRID == UNKNOWN_CRS )
3541     {
3542         nExtentSRID = 0;
3543     }
3544 
3545     CPLDebug("GEOR","nExtentSRID = %lld",nExtentSRID);
3546     CPLDebug("GEOR","nSRID       = %lld",nSRID);
3547 
3548     //  --------------------------------------------------------------------
3549     //  Update GeoRaster Metadata
3550     //  --------------------------------------------------------------------
3551 
3552     int nException = 0;
3553 
3554     OCILobLocator* phLocator = nullptr;
3555 
3556     poStmt = poConnection->CreateStatement( CPLSPrintf(
3557         "DECLARE\n"
3558         "  GR1      sdo_georaster;\n"
3559         "  GM1      sdo_geometry;\n"
3560         "  SRID     number  := :1;\n"
3561         "  EXT_SRID number  := :2;\n"
3562         "  VAT      varchar2(128);\n"
3563         "BEGIN\n"
3564         "\n"
3565         "  SELECT %s INTO GR1 FROM %s%s T WHERE %s FOR UPDATE;\n"
3566         "\n"
3567         "  GR1.metadata := sys.xmltype.createxml(:3);\n"
3568         "\n"
3569         "  IF SRID != 0 THEN\n"
3570         "    SDO_GEOR.georeference( GR1, SRID, :4, \n"
3571         "      SDO_NUMBER_ARRAY(:5, :6, :7), SDO_NUMBER_ARRAY(:8, :9, :10));\n"
3572         "  END IF;\n"
3573         "\n"
3574         "  IF EXT_SRID = 0 THEN\n"
3575         "    GM1 := NULL;\n"
3576         "  ELSE\n"
3577         "    GM1 := SDO_GEOR.generateSpatialExtent( GR1 );\n"
3578         "    IF EXT_SRID != SRID THEN\n"
3579         "      GM1 := SDO_CS.transform( GM1, EXT_SRID );\n"
3580         "    END IF;\n"
3581         "  END IF;\n"
3582         "\n"
3583         "  GR1.spatialExtent := GM1;\n"
3584         "\n"
3585         "  VAT := '%s';\n"
3586         "  IF VAT != '' THEN\n"
3587         "    SDO_GEOR.setVAT(GR1, 1, VAT);\n"
3588         "  END IF;\n"
3589         "\n"
3590         "  BEGIN\n"
3591         "    UPDATE %s%s T SET %s = GR1\n"
3592         "    WHERE %s;\n"
3593         "  EXCEPTION\n"
3594         "    WHEN OTHERS THEN\n"
3595         "      :except := SQLCODE;\n"
3596         "  END;\n"
3597         "\n"
3598         "  COMMIT;\n"
3599         "END;",
3600             sColumn.c_str(),
3601             sSchema.c_str(),
3602             sTable.c_str(),
3603             sWhere.c_str(),
3604             sValueAttributeTab.c_str(),
3605             sSchema.c_str(),
3606             sTable.c_str(),
3607             sColumn.c_str(),
3608             sWhere.c_str() ) );
3609 
3610     poStmt->WriteCLob( &phLocator, pszMetadata );
3611 
3612     poStmt->Bind( &nSRID );
3613     poStmt->Bind( &nExtentSRID );
3614     poStmt->Bind( &phLocator );
3615     poStmt->Bind( &nMLC );
3616     poStmt->Bind( &dfXCoef[0] );
3617     poStmt->Bind( &dfXCoef[1] );
3618     poStmt->Bind( &dfXCoef[2] );
3619     poStmt->Bind( &dfYCoef[0] );
3620     poStmt->Bind( &dfYCoef[1] );
3621     poStmt->Bind( &dfYCoef[2] );
3622     poStmt->BindName( ":except", &nException );
3623 
3624     CPLFree( pszMetadata );
3625 
3626     if( ! poStmt->Execute() )
3627     {
3628         poStmt->FreeLob(phLocator);
3629         delete poStmt;
3630         return false;
3631     }
3632 
3633     poStmt->FreeLob(phLocator);
3634 
3635     delete poStmt;
3636 
3637     if( nException )
3638     {
3639         CPLError( CE_Warning, CPLE_AppDefined,
3640             "Fail to update GeoRaster Metadata (ORA-%d) ", nException );
3641     }
3642 
3643     if (bGenPyramid)
3644     {
3645         if (GeneratePyramid( nPyramidLevels, sPyramidResampling.c_str(), true ))
3646         {
3647             CPLDebug("GEOR", "Generated pyramid successfully.");
3648         }
3649         else
3650         {
3651             CPLError( CE_Warning, CPLE_AppDefined, "Error generating pyramid!");
3652         }
3653     }
3654 
3655     return true;
3656 }
3657 
3658 //  ---------------------------------------------------------------------------
3659 //                                                            GeneratePyramid()
3660 //  ---------------------------------------------------------------------------
3661 
GeneratePyramid(int nLevels,const char * pszResampling,bool bInternal)3662 bool GeoRasterWrapper::GeneratePyramid( int nLevels,
3663                                         const char* pszResampling,
3664                                         bool bInternal )
3665 {
3666     nPyramidMaxLevel = nLevels;
3667 
3668     if( bInternal )
3669     {
3670         CPLString sLevels = "";
3671 
3672         if (nLevels > 0)
3673         {
3674             sLevels = CPLSPrintf("rlevel=%d", nLevels);
3675         }
3676 
3677         OWStatement* poStmt = poConnection->CreateStatement( CPLSPrintf(
3678             "DECLARE\n"
3679             "  gr sdo_georaster;\n"
3680             "BEGIN\n"
3681             "  SELECT %s INTO gr FROM %s t WHERE %s FOR UPDATE;\n"
3682             "  sdo_geor.generatePyramid(gr, '%s resampling=%s');\n"
3683             "  UPDATE %s t SET %s = gr WHERE %s;\n"
3684             "  COMMIT;\n"
3685             "END;\n",
3686                 sColumn.c_str(),
3687                 sTable.c_str(),
3688                 sWhere.c_str(),
3689                 sLevels.c_str(),
3690                 pszResampling,
3691                 sTable.c_str(),
3692                 sColumn.c_str(),
3693                 sWhere.c_str() ) );
3694 
3695         if( poStmt->Execute() )
3696         {
3697             delete poStmt;
3698             return true;
3699         }
3700 
3701         delete poStmt;
3702         return false;
3703     }
3704 
3705     //  -----------------------------------------------------------
3706     //  Create rows for pyramid levels
3707     //  -----------------------------------------------------------
3708 
3709     OWStatement* poStmt = poConnection->CreateStatement(
3710         "DECLARE\n"
3711         "  SCL  NUMBER         := 0;\n"
3712         "  RC   NUMBER         := 0;\n"
3713         "  RR   NUMBER         := 0;\n"
3714         "  CBS2 NUMBER         := 0;\n"
3715         "  RBS2 NUMBER         := 0;\n"
3716         "  TBB  NUMBER         := 0;\n"
3717         "  TRB  NUMBER         := 0;\n"
3718         "  TCB  NUMBER         := 0;\n"
3719         "  X    NUMBER         := 0;\n"
3720         "  Y    NUMBER         := 0;\n"
3721         "  W    NUMBER         := 0;\n"
3722         "  H    NUMBER         := 0;\n"
3723         "  STM  VARCHAR2(1024) := '';\n"
3724         "BEGIN\n"
3725         "  EXECUTE IMMEDIATE 'DELETE FROM '||:rdt||' \n"
3726         "    WHERE RASTERID = '||:rid||' AND PYRAMIDLEVEL > 0';\n"
3727         "  STM := 'INSERT INTO '||:rdt||' VALUES (:1, :2, :3-1, :4-1, :5-1 ,\n"
3728         "    SDO_GEOMETRY(2003, NULL, NULL, SDO_ELEM_INFO_ARRAY(1, 1003, 3),\n"
3729         "    SDO_ORDINATE_ARRAY(:6, :7, :8-1, :9-1)), EMPTY_BLOB() )';\n"
3730         "  TBB  := :TotalBandBlocks;\n"
3731         "  RBS2 := floor(:RowBlockSize / 2);\n"
3732         "  CBS2 := floor(:ColumnBlockSize / 2);\n"
3733         "  FOR l IN 1..:level LOOP\n"
3734         "    SCL := 2 ** l;\n"
3735         "    RR  := floor(:RasterRows / SCL);\n"
3736         "    RC  := floor(:RasterColumns / SCL);\n"
3737         "    IF (RC <= CBS2) OR (RR <= RBS2) THEN\n"
3738         "      H   := RR;\n"
3739         "      W   := RC;\n"
3740         "    ELSE\n"
3741         "      H   := :RowBlockSize;\n"
3742         "      W   := :ColumnBlockSize;\n"
3743         "    END IF;\n"
3744         "    TRB := greatest(1, ceil( ceil(:RasterColumns / :ColumnBlockSize) / SCL));\n"
3745         "    TCB := greatest(1, ceil( ceil(:RasterRows / :RowBlockSize) / SCL));\n"
3746         "    FOR b IN 1..TBB LOOP\n"
3747         "      Y := 0;\n"
3748         "      FOR r IN 1..TCB LOOP\n"
3749         "        X := 0;\n"
3750         "        FOR c IN 1..TRB LOOP\n"
3751         "          EXECUTE IMMEDIATE STM USING :rid, l, b, r, c, Y, X, (Y+H), (X+W);\n"
3752         "          X := X + W;\n"
3753         "        END LOOP;\n"
3754         "        Y := Y + H;\n"
3755         "      END LOOP;\n"
3756         "    END LOOP;\n"
3757         "  END LOOP;\n"
3758         "  COMMIT;\n"
3759         "END;" );
3760 
3761     const char* pszDataTable = sDataTable.c_str();
3762 
3763     poStmt->BindName( ":rdt",             (char*) pszDataTable );
3764     poStmt->BindName( ":rid",             &nRasterId );
3765     poStmt->BindName( ":level",           &nLevels );
3766     poStmt->BindName( ":TotalBandBlocks", &nTotalBandBlocks );
3767     poStmt->BindName( ":RowBlockSize",    &nRowBlockSize );
3768     poStmt->BindName( ":ColumnBlockSize", &nColumnBlockSize );
3769     poStmt->BindName( ":RasterRows",      &nRasterRows );
3770     poStmt->BindName( ":RasterColumns",   &nRasterColumns );
3771 
3772     if( ! poStmt->Execute() )
3773     {
3774         delete poStmt;
3775         return false;
3776     }
3777     delete poStmt;
3778 
3779     CPLXMLNode* psNode = CPLGetXMLNode( phMetadata, "rasterInfo.pyramid" );
3780 
3781     if( psNode )
3782     {
3783         CPLSetXMLValue( psNode, "type", "DECREASE" );
3784         CPLSetXMLValue( psNode, "resampling", pszResampling );
3785         CPLSetXMLValue( psNode, "maxLevel", CPLSPrintf( "%d", nLevels ) );
3786     }
3787 
3788     bFlushMetadata = true;
3789 
3790     return true;
3791 }
3792 
3793 //  ---------------------------------------------------------------------------
3794 //                                                            GeneratePyramid()
3795 //  ---------------------------------------------------------------------------
3796 
DeletePyramid()3797 void GeoRasterWrapper::DeletePyramid()
3798 {
3799     OWStatement* poStmt = poConnection->CreateStatement( CPLSPrintf(
3800         "DECLARE\n"
3801         "  gr sdo_georaster;\n"
3802         "BEGIN\n"
3803         "  SELECT %s INTO gr FROM %s t WHERE %s FOR UPDATE;\n"
3804         "  sdo_geor.deletePyramid(gr);\n"
3805         "  UPDATE %s t SET %s = gr WHERE %s;\n"
3806         "  COMMIT;\n"
3807         "END;\n",
3808             sColumn.c_str(),
3809             sTable.c_str(),
3810             sWhere.c_str(),
3811             sTable.c_str(),
3812             sColumn.c_str(),
3813             sWhere.c_str() ) );
3814 
3815     CPL_IGNORE_RET_VAL(poStmt->Execute());
3816 
3817     delete poStmt;
3818 }
3819 
3820 //  ---------------------------------------------------------------------------
3821 //                                                           CreateBitmapMask()
3822 //  ---------------------------------------------------------------------------
3823 
InitializeMask(int nLevel,int nBlockColumns,int nBlockRows,int nColumnBlocks,int nRowBlocks,int nBandBlocks)3824 bool GeoRasterWrapper::InitializeMask( int nLevel,
3825                                        int nBlockColumns,
3826                                        int nBlockRows,
3827                                        int nColumnBlocks,
3828                                        int nRowBlocks,
3829                                        int nBandBlocks )
3830 {
3831     //  -----------------------------------------------------------
3832     //  Create rows for the bitmap mask
3833     //  -----------------------------------------------------------
3834 
3835     OWStatement* poStmt = poConnection->CreateStatement(
3836         "DECLARE\n"
3837         "  W    NUMBER          := :1;\n"
3838         "  H    NUMBER          := :2;\n"
3839         "  BB   NUMBER          := :3;\n"
3840         "  RB   NUMBER          := :4;\n"
3841         "  CB   NUMBER          := :5;\n"
3842         "  X    NUMBER          := 0;\n"
3843         "  Y    NUMBER          := 0;\n"
3844         "  STM  VARCHAR2(1024)  := '';\n"
3845         "BEGIN\n"
3846         "\n"
3847         "  EXECUTE IMMEDIATE 'DELETE FROM '||:rdt||' \n"
3848         "    WHERE RASTERID = '||:rid||' AND PYRAMIDLEVEL = '||:lev||' ';\n"
3849         "\n"
3850         "  STM := 'INSERT INTO '||:rdt||' VALUES (:1, :lev, :2-1, :3-1, :4-1 ,\n"
3851         "    SDO_GEOMETRY(2003, NULL, NULL, SDO_ELEM_INFO_ARRAY(1, 1003, 3),\n"
3852         "    SDO_ORDINATE_ARRAY(:5, :6, :7-1, :8-1)), EMPTY_BLOB() )';\n"
3853         "\n"
3854         "  FOR b IN 1..BB LOOP\n"
3855         "    Y := 0;\n"
3856         "    FOR r IN 1..RB LOOP\n"
3857         "      X := 0;\n"
3858         "      FOR c IN 1..CB LOOP\n"
3859         "        EXECUTE IMMEDIATE STM USING :rid, b, r, c, Y, X, (Y+H), (X+W);\n"
3860         "        X := X + W;\n"
3861         "      END LOOP;\n"
3862         "      Y := Y + H;\n"
3863         "    END LOOP;\n"
3864         "  END LOOP;\n"
3865         "END;" );
3866 
3867     char pszDataTable[OWNAME];
3868 
3869     poStmt->Bind( &nBlockColumns );
3870     poStmt->Bind( &nBlockRows );
3871     poStmt->Bind( &nBandBlocks );
3872     poStmt->Bind( &nRowBlocks );
3873     poStmt->Bind( &nColumnBlocks );
3874     poStmt->BindName( ":rdt", pszDataTable );
3875     poStmt->BindName( ":rid", &nRasterId );
3876     poStmt->BindName( ":lev", &nLevel );
3877 
3878     if( ! poStmt->Execute() )
3879     {
3880         delete poStmt;
3881         return false;
3882     }
3883 
3884     delete poStmt;
3885     return true;
3886 }
3887 
3888 //  ---------------------------------------------------------------------------
3889 //                                                                UnpackNBits()
3890 //  ---------------------------------------------------------------------------
3891 
UnpackNBits(GByte * pabyData)3892 void GeoRasterWrapper::UnpackNBits( GByte* pabyData )
3893 {
3894     int nPixCount = nColumnBlockSize * nRowBlockSize * nBandBlockSize;
3895 
3896     if( EQUAL( sCellDepth.c_str(), "4BIT" ) )
3897     {
3898         for( int ii = nPixCount - 2; ii >= 0; ii -= 2 )
3899         {
3900             int k = ii >> 1;
3901             pabyData[ii+1] = (pabyData[k]     ) & 0xf;
3902             pabyData[ii]   = (pabyData[k] >> 4) & 0xf;
3903         }
3904     }
3905     else if( EQUAL( sCellDepth.c_str(), "2BIT" ) )
3906     {
3907         for( int ii = nPixCount - 4; ii >= 0; ii -= 4 )
3908         {
3909             int k = ii >> 2;
3910             pabyData[ii+3] = (pabyData[k]     ) & 0x3;
3911             pabyData[ii+2] = (pabyData[k] >> 2) & 0x3;
3912             pabyData[ii+1] = (pabyData[k] >> 4) & 0x3;
3913             pabyData[ii]   = (pabyData[k] >> 6) & 0x3;
3914         }
3915     }
3916     else
3917     {
3918         for( int ii = nPixCount - 1; ii >= 0; ii-- )
3919         {
3920             if( ( pabyData[ii>>3] & ( 128 >> (ii & 0x7) ) ) )
3921                 pabyData[ii] = 1;
3922             else
3923                 pabyData[ii] = 0;
3924         }
3925     }
3926 }
3927 
3928 //  ---------------------------------------------------------------------------
3929 //                                                                  PackNBits()
3930 //  ---------------------------------------------------------------------------
3931 
PackNBits(GByte * pabyData) const3932 void GeoRasterWrapper::PackNBits( GByte* pabyData ) const
3933 {
3934     int nPixCount = nBandBlockSize * nRowBlockSize * nColumnBlockSize;
3935 
3936     GByte* pabyBuffer = (GByte*) VSI_MALLOC_VERBOSE( nPixCount );
3937 
3938     if( pabyBuffer == nullptr )
3939     {
3940         return;
3941     }
3942 
3943     if( nCellSizeBits == 4 )
3944     {
3945         for( int ii = 0; ii < nPixCount - 1; ii += 2 )
3946         {
3947             int k = ii >> 1;
3948             pabyBuffer[k] =
3949                   ((((GByte *) pabyData)[ii+1] & 0xf)     )
3950                 | ((((GByte *) pabyData)[ii]   & 0xf) << 4);
3951         }
3952     }
3953     else if( nCellSizeBits == 2 )
3954     {
3955         for( int ii = 0; ii < nPixCount - 3; ii += 4 )
3956         {
3957             int k = ii >> 2;
3958             pabyBuffer[k] =
3959                   ((((GByte *) pabyData)[ii+3] & 0x3)     )
3960                 | ((((GByte *) pabyData)[ii+2] & 0x3) << 2)
3961                 | ((((GByte *) pabyData)[ii+1] & 0x3) << 4)
3962                 | ((((GByte *) pabyData)[ii]   & 0x3) << 6);
3963         }
3964     }
3965     else
3966     {
3967         for( int ii = 0; ii < nPixCount - 7; ii += 8 )
3968         {
3969             int k = ii >> 3;
3970             pabyBuffer[k] =
3971                   ((((GByte *) pabyData)[ii+7] & 0x1)     )
3972                 | ((((GByte *) pabyData)[ii+6] & 0x1) << 1)
3973                 | ((((GByte *) pabyData)[ii+5] & 0x1) << 2)
3974                 | ((((GByte *) pabyData)[ii+4] & 0x1) << 3)
3975                 | ((((GByte *) pabyData)[ii+3] & 0x1) << 4)
3976                 | ((((GByte *) pabyData)[ii+2] & 0x1) << 5)
3977                 | ((((GByte *) pabyData)[ii+1] & 0x1) << 6)
3978                 | ((((GByte *) pabyData)[ii]   & 0x1) << 7);
3979         }
3980     }
3981 
3982     memcpy( pabyData, pabyBuffer, nPixCount );
3983 
3984     CPLFree( pabyBuffer );
3985 }
3986 
3987 //  ---------------------------------------------------------------------------
3988 //                                                             UncompressJpeg()
3989 //  ---------------------------------------------------------------------------
3990 
3991 const static int K2Chrominance[64] =
3992 {
3993     17, 18, 24, 47, 99, 99, 99, 99,
3994     18, 21, 26, 66, 99, 99, 99, 99,
3995     24, 26, 56, 99, 99, 99, 99, 99,
3996     47, 66, 99, 99, 99, 99, 99, 99,
3997     99, 99, 99, 99, 99, 99, 99, 99,
3998     99, 99, 99, 99, 99, 99, 99, 99,
3999     99, 99, 99, 99, 99, 99, 99, 99,
4000     99, 99, 99, 99, 99, 99, 99, 99
4001 };
4002 
4003 constexpr int AC_BITS[16] =
4004 {
4005     0, 2, 1, 2, 4, 4, 3, 4, 7, 5, 4, 4, 0, 1, 2, 119
4006 };
4007 
4008 constexpr int AC_HUFFVAL[256] =
4009 {
4010       0,   1,   2,   3,  17,   4,   5,  33,  49,   6,  18,
4011      65,  81,   7,  97, 113,  19,  34,  50, 129,   8,  20,
4012      66, 145, 161, 177, 193,   9,  35,  51,  82, 240,  21,
4013      98, 114, 209,  10,  22,  36,  52, 225,  37, 241,  23,
4014      24,  25,  26,  38,  39,  40,  41,  42,  53,  54,  55,
4015      56,  57,  58,  67,  68,  69,  70,  71,  72,  73,  74,
4016      83,  84,  85,  86,  87,  88,  89,  90,  99, 100, 101,
4017     102, 103, 104, 105, 106, 115, 116, 117, 118, 119, 120,
4018     121, 122, 130, 131, 132, 133, 134, 135, 136, 137, 138,
4019     146, 147, 148, 149, 150, 151, 152, 153, 154, 162, 163,
4020     164, 165, 166, 167, 168, 169, 170, 178, 179, 180, 181,
4021     182, 183, 184, 185, 186, 194, 195, 196, 197, 198, 199,
4022     200, 201, 202, 210, 211, 212, 213, 214, 215, 216, 217,
4023     218, 226, 227, 228, 229, 230, 231, 232, 233, 234, 242,
4024     243, 244, 245, 246, 247, 248, 249, 250
4025 };
4026 
4027 constexpr int DC_BITS[16] =
4028 {
4029     0, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0
4030 };
4031 
4032 constexpr int DC_HUFFVAL[256] =
4033 {
4034     0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11
4035 };
4036 
4037 /***
4038  *
4039  * Load the tables based on the Java's JAI default values.
4040  *
4041  * JPEGQTable.K2Chrominance.getScaledInstance()
4042  * JPEGHuffmanTable.StdACChrominance
4043  * JPEGHuffmanTable.StdDCChrominance
4044  *
4045  ***/
4046 static
JPEG_LoadTables(JQUANT_TBL * hquant_tbl_ptr,JHUFF_TBL * huff_ac_ptr,JHUFF_TBL * huff_dc_ptr,unsigned int nQuality)4047 void JPEG_LoadTables( JQUANT_TBL* hquant_tbl_ptr,
4048                       JHUFF_TBL* huff_ac_ptr,
4049                       JHUFF_TBL* huff_dc_ptr,
4050                       unsigned int nQuality )
4051 {
4052     int i = 0;
4053     float fscale_factor;
4054 
4055     //  --------------------------------------------------------------------
4056     //  Scale Quantization table based on quality
4057     //  --------------------------------------------------------------------
4058 
4059     fscale_factor = (float) jpeg_quality_scaling( nQuality ) / (float) 100.0;
4060 
4061     for ( i = 0; i < 64; i++ )
4062     {
4063         UINT16 temp = (UINT16) floor( K2Chrominance[i] * fscale_factor + 0.5 );
4064         if ( temp <= 0 )
4065             temp = 1;
4066         if ( temp > 255 )
4067             temp = 255;
4068         hquant_tbl_ptr->quantval[i] = (UINT16) temp;
4069     }
4070 
4071     //  --------------------------------------------------------------------
4072     //  Load AC huffman table
4073     //  --------------------------------------------------------------------
4074 
4075     for ( i = 1; i <= 16; i++ )
4076     {
4077         /* counts[i] is number of Huffman codes of length i bits, i=1..16 */
4078         huff_ac_ptr->bits[i] = (UINT8) AC_BITS[i-1];
4079     }
4080 
4081     for ( i = 0; i < 256; i++ )
4082     {
4083         /* symbols[] is the list of Huffman symbols, in code-length order */
4084         huff_ac_ptr->huffval[i] = (UINT8) AC_HUFFVAL[i];
4085     }
4086 
4087     //  --------------------------------------------------------------------
4088     //  Load DC huffman table
4089     //  --------------------------------------------------------------------
4090 
4091     for ( i = 1; i <= 16; i++ )
4092     {
4093         /* counts[i] is number of Huffman codes of length i bits, i=1..16 */
4094         huff_dc_ptr->bits[i] = (UINT8) DC_BITS[i-1];
4095     }
4096 
4097     for ( i = 0; i < 256; i++ )
4098     {
4099         /* symbols[] is the list of Huffman symbols, in code-length order */
4100         huff_dc_ptr->huffval[i] = (UINT8) DC_HUFFVAL[i];
4101     }
4102 }
4103 
UncompressJpeg(unsigned long nInSize)4104 void GeoRasterWrapper::UncompressJpeg( unsigned long nInSize )
4105 {
4106     //  --------------------------------------------------------------------
4107     //  Load JPEG in a virtual file
4108     //  --------------------------------------------------------------------
4109 
4110     const char* pszMemFile = CPLSPrintf( "/vsimem/geor_%p.jpg", pabyBlockBuf );
4111 
4112     VSILFILE *fpImage = VSIFOpenL( pszMemFile, "wb" );
4113     VSIFWriteL( pabyBlockBuf, nInSize, 1, fpImage );
4114     VSIFCloseL( fpImage );
4115 
4116     fpImage = VSIFOpenL( pszMemFile, "rb" );
4117 
4118     //  --------------------------------------------------------------------
4119     //  Initialize decompressor
4120     //  --------------------------------------------------------------------
4121 
4122     if( ! sDInfo.global_state )
4123     {
4124         sDInfo.err = jpeg_std_error( &sJErr );
4125         jpeg_create_decompress( &sDInfo );
4126 
4127         // -----------------------------------------------------------------
4128         // Load table for abbreviated JPEG-B
4129         // -----------------------------------------------------------------
4130 
4131         int nComponentsToLoad = -1; /* doesn't load any table */
4132 
4133         if( EQUAL( sCompressionType.c_str(), "JPEG-B") )
4134         {
4135             nComponentsToLoad = nBandBlockSize;
4136         }
4137 
4138         for( int n = 0; n < nComponentsToLoad; n++ )
4139         {
4140             sDInfo.quant_tbl_ptrs[n] =
4141                 jpeg_alloc_quant_table( (j_common_ptr) &sDInfo );
4142             sDInfo.ac_huff_tbl_ptrs[n] =
4143                 jpeg_alloc_huff_table( (j_common_ptr) &sDInfo );
4144             sDInfo.dc_huff_tbl_ptrs[n] =
4145                 jpeg_alloc_huff_table( (j_common_ptr) &sDInfo );
4146 
4147             JPEG_LoadTables( sDInfo.quant_tbl_ptrs[n],
4148                              sDInfo.ac_huff_tbl_ptrs[n],
4149                              sDInfo.dc_huff_tbl_ptrs[n],
4150                              nCompressQuality );
4151         }
4152     }
4153 
4154     jpeg_vsiio_src( &sDInfo, fpImage );
4155     jpeg_read_header( &sDInfo, TRUE );
4156 
4157     sDInfo.out_color_space = ( nBandBlockSize == 1 ? JCS_GRAYSCALE : JCS_RGB );
4158 
4159     jpeg_start_decompress( &sDInfo );
4160 
4161     GByte* pabyScanline = pabyBlockBuf;
4162 
4163     for( int iLine = 0; iLine < nRowBlockSize; iLine++ )
4164     {
4165         JSAMPLE* ppSamples = (JSAMPLE*) pabyScanline;
4166         jpeg_read_scanlines( &sDInfo, &ppSamples, 1 );
4167         pabyScanline += ( nColumnBlockSize * nBandBlockSize );
4168     }
4169 
4170     jpeg_finish_decompress( &sDInfo );
4171 
4172     VSIFCloseL( fpImage );
4173 
4174     VSIUnlink( pszMemFile );
4175 }
4176 
4177 //  ---------------------------------------------------------------------------
4178 //                                                               CompressJpeg()
4179 //  ---------------------------------------------------------------------------
4180 
CompressJpeg(void)4181 unsigned long GeoRasterWrapper::CompressJpeg( void )
4182 {
4183     //  --------------------------------------------------------------------
4184     //  Load JPEG in a virtual file
4185     //  --------------------------------------------------------------------
4186 
4187     const char* pszMemFile = CPLSPrintf( "/vsimem/geor_%p.jpg", pabyBlockBuf );
4188 
4189     VSILFILE *fpImage = VSIFOpenL( pszMemFile, "wb" );
4190 
4191     bool write_all_tables = TRUE;
4192 
4193     if( EQUAL( sCompressionType.c_str(), "JPEG-B") )
4194     {
4195         write_all_tables = FALSE;
4196     }
4197 
4198     //  --------------------------------------------------------------------
4199     //  Initialize compressor
4200     //  --------------------------------------------------------------------
4201 
4202     if( ! sCInfo.global_state )
4203     {
4204         sCInfo.err = jpeg_std_error( &sJErr );
4205         jpeg_create_compress( &sCInfo );
4206 
4207         jpeg_vsiio_dest( &sCInfo, fpImage );
4208 
4209         sCInfo.image_width = nColumnBlockSize;
4210         sCInfo.image_height = nRowBlockSize;
4211         sCInfo.input_components = nBandBlockSize;
4212         sCInfo.in_color_space = (nBandBlockSize == 1 ? JCS_GRAYSCALE : JCS_RGB);
4213         jpeg_set_defaults( &sCInfo );
4214         sCInfo.JFIF_major_version = 1;
4215         sCInfo.JFIF_minor_version = 2;
4216         jpeg_set_quality( &sCInfo, nCompressQuality, TRUE );
4217 
4218         // -----------------------------------------------------------------
4219         // Load table for abbreviated JPEG-B
4220         // -----------------------------------------------------------------
4221 
4222         int nComponentsToLoad = -1; /* doesn't load any table */
4223 
4224         if( EQUAL( sCompressionType.c_str(), "JPEG-B") )
4225         {
4226             nComponentsToLoad = nBandBlockSize;
4227         }
4228 
4229         for( int n = 0; n < nComponentsToLoad; n++ )
4230         {
4231             sCInfo.quant_tbl_ptrs[n] =
4232                 jpeg_alloc_quant_table( (j_common_ptr) &sCInfo );
4233             sCInfo.ac_huff_tbl_ptrs[n] =
4234                 jpeg_alloc_huff_table( (j_common_ptr) &sCInfo );
4235             sCInfo.dc_huff_tbl_ptrs[n] =
4236                 jpeg_alloc_huff_table( (j_common_ptr) &sCInfo );
4237 
4238             JPEG_LoadTables( sCInfo.quant_tbl_ptrs[n],
4239                              sCInfo.ac_huff_tbl_ptrs[n],
4240                              sCInfo.dc_huff_tbl_ptrs[n],
4241                              nCompressQuality );
4242         }
4243     }
4244     else
4245     {
4246         jpeg_vsiio_dest( &sCInfo, fpImage );
4247     }
4248 
4249     jpeg_suppress_tables( &sCInfo, ! write_all_tables );
4250     jpeg_start_compress( &sCInfo, write_all_tables );
4251 
4252     GByte* pabyScanline = pabyBlockBuf;
4253 
4254     for( int iLine = 0; iLine < nRowBlockSize; iLine++ )
4255     {
4256         JSAMPLE* ppSamples = (JSAMPLE*) pabyScanline;
4257         jpeg_write_scanlines( &sCInfo, &ppSamples, 1 );
4258         pabyScanline += ( nColumnBlockSize * nBandBlockSize );
4259     }
4260 
4261     jpeg_finish_compress( &sCInfo );
4262 
4263     VSIFCloseL( fpImage );
4264 
4265     fpImage = VSIFOpenL( pszMemFile, "rb" );
4266     size_t nSize = VSIFReadL( pabyCompressBuf, 1, nBlockBytes, fpImage );
4267     VSIFCloseL( fpImage );
4268 
4269     VSIUnlink( pszMemFile );
4270 
4271     return (unsigned long) nSize;
4272 }
4273 
4274 //  ---------------------------------------------------------------------------
4275 //                                                          UncompressDeflate()
4276 //  ---------------------------------------------------------------------------
4277 
UncompressDeflate(unsigned long nBufferSize)4278 bool GeoRasterWrapper::UncompressDeflate( unsigned long nBufferSize )
4279 {
4280     GByte* pabyBuf = (GByte*) VSI_MALLOC_VERBOSE( nBufferSize );
4281 
4282     if( pabyBuf == nullptr )
4283     {
4284         return false;
4285     }
4286 
4287     memcpy( pabyBuf, pabyBlockBuf, nBufferSize );
4288 
4289     // Call ZLib uncompress
4290 
4291     unsigned long nDestLen = nBlockBytes;
4292 
4293     int nRet = uncompress( pabyBlockBuf, &nDestLen, pabyBuf, nBufferSize );
4294 
4295     CPLFree( pabyBuf );
4296 
4297     if( nRet != Z_OK )
4298     {
4299         CPLError( CE_Failure, CPLE_AppDefined, "ZLib return code (%d)", nRet );
4300         return false;
4301     }
4302 
4303     if( nDestLen != nBlockBytes )
4304     {
4305         CPLError( CE_Failure, CPLE_AppDefined,
4306             "ZLib decompressed buffer size (%ld) expected (%ld)", nDestLen, nBlockBytes );
4307         return false;
4308     }
4309 
4310     return true;
4311 }
4312 
4313 //  ---------------------------------------------------------------------------
4314 //                                                            CompressDeflate()
4315 //  ---------------------------------------------------------------------------
4316 
CompressDeflate(void)4317 unsigned long GeoRasterWrapper::CompressDeflate( void )
4318 {
4319     unsigned long nLen = ((unsigned long)(nBlockBytes * 1.1)) + 12;
4320 
4321     GByte* pabyBuf = (GByte*) VSI_MALLOC_VERBOSE( nBlockBytes );
4322 
4323     if( pabyBuf == nullptr )
4324     {
4325         return 0;
4326     }
4327 
4328     memcpy( pabyBuf, pabyBlockBuf, nBlockBytes );
4329 
4330     // Call ZLib compress
4331 
4332     int nRet = compress( pabyCompressBuf, &nLen, pabyBuf, nBlockBytes );
4333 
4334     CPLFree( pabyBuf );
4335 
4336     if( nRet != Z_OK )
4337     {
4338         CPLError( CE_Failure, CPLE_AppDefined, "ZLib return code (%d)", nRet );
4339         return 0;
4340     }
4341 
4342     return nLen;
4343 }
4344