1 /*
2  *  kearat.cpp
3  *
4  *  Created by Pete Bunting on 01/08/2012.
5  *  Copyright 2012 LibKEA. All rights reserved.
6  *
7  *  This file is part of LibKEA.
8  *
9  *  Permission is hereby granted, free of charge, to any person
10  *  obtaining a copy of this software and associated documentation
11  *  files (the "Software"), to deal in the Software without restriction,
12  *  including without limitation the rights to use, copy, modify,
13  *  merge, publish, distribute, sublicense, and/or sell copies of the
14  *  Software, and to permit persons to whom the Software is furnished
15  *  to do so, subject to the following conditions:
16  *
17  *  The above copyright notice and this permission notice shall be
18  *  included in all copies or substantial portions of the Software.
19  *
20  *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21  *  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
22  *  OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
23  *  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
24  *  ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
25  *  CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
26  *  WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
27  *
28  */
29 
30 #include "kearat.h"
31 
32 CPL_CVSID("$Id: kearat.cpp 980fee897f6fd8cf10fa0f62936cca216cd76cf7 2020-04-03 17:54:46 +1000 Sam Gillingham $")
33 
KEARasterAttributeTable(kealib::KEAAttributeTable * poKEATable,KEARasterBand * poBand)34 KEARasterAttributeTable::KEARasterAttributeTable(kealib::KEAAttributeTable *poKEATable,
35                             KEARasterBand *poBand)
36 {
37     this->m_hMutex = CPLCreateMutex();
38     CPLReleaseMutex( this->m_hMutex );
39     for( size_t nColumnIndex = 0; nColumnIndex < poKEATable->getMaxGlobalColIdx(); nColumnIndex++ )
40     {
41         kealib::KEAATTField sKEAField;
42         try
43         {
44             sKEAField = poKEATable->getField(nColumnIndex);
45         }
46         catch(const kealib::KEAATTException &)
47         {
48             // pKEATable->getField raised exception because we have a missing column
49             continue;
50         }
51         m_aoFields.push_back(sKEAField);
52     }
53     m_poKEATable = poKEATable;
54     m_poBand = poBand;
55 }
56 
~KEARasterAttributeTable()57 KEARasterAttributeTable::~KEARasterAttributeTable()
58 {
59     // can't just delete thanks to Windows
60     kealib::KEAAttributeTable::destroyAttributeTable(m_poKEATable);
61     CPLDestroyMutex( m_hMutex );
62     m_hMutex = nullptr;
63 }
64 
Clone() const65 GDALDefaultRasterAttributeTable *KEARasterAttributeTable::Clone() const
66 {
67     if( ( GetRowCount() * GetColumnCount() ) > RAT_MAX_ELEM_FOR_CLONE )
68         return nullptr;
69 
70     GDALDefaultRasterAttributeTable *poRAT = new GDALDefaultRasterAttributeTable();
71 
72     for( int iCol = 0; iCol < (int)m_aoFields.size(); iCol++)
73     {
74         CPLString sName = m_aoFields[iCol].name;
75         CPLString sUsage = m_aoFields[iCol].usage;
76         GDALRATFieldUsage eGDALUsage;
77         if( sUsage == "PixelCount" )
78             eGDALUsage = GFU_PixelCount;
79         else if( sUsage == "Name" )
80             eGDALUsage = GFU_Name;
81         else if( sUsage == "Red" )
82             eGDALUsage = GFU_Red;
83         else if( sUsage == "Green" )
84             eGDALUsage = GFU_Green;
85         else if( sUsage == "Blue" )
86             eGDALUsage = GFU_Blue;
87         else if( sUsage == "Alpha" )
88             eGDALUsage = GFU_Alpha;
89         else
90         {
91             // don't recognise any other special names - generic column
92             eGDALUsage = GFU_Generic;
93         }
94 
95         GDALRATFieldType eGDALType;
96         switch( m_aoFields[iCol].dataType )
97         {
98             case kealib::kea_att_bool:
99             case kealib::kea_att_int:
100                 eGDALType = GFT_Integer;
101                 break;
102             case kealib::kea_att_float:
103                 eGDALType = GFT_Real;
104                 break;
105             case kealib::kea_att_string:
106                 eGDALType = GFT_String;
107                 break;
108             default:
109                 eGDALType = GFT_Integer;
110                 break;
111         }
112         poRAT->CreateColumn(sName, eGDALType, eGDALUsage);
113         poRAT->SetRowCount(static_cast<int>(m_poKEATable->getSize()));
114 
115         if( m_poKEATable->getSize() == 0 )
116             continue;
117 
118         if( eGDALType == GFT_Integer )
119         {
120             int *panColData = (int*)VSI_MALLOC2_VERBOSE(sizeof(int), m_poKEATable->getSize());
121             if( panColData == nullptr )
122             {
123                 delete poRAT;
124                 return nullptr;
125             }
126 
127             if( (const_cast<KEARasterAttributeTable*>(this))->
128                         ValuesIO(GF_Read, iCol, 0, static_cast<int>(m_poKEATable->getSize()), panColData ) != CE_None )
129             {
130                 CPLFree(panColData);
131                 delete poRAT;
132                 return nullptr;
133             }
134 
135             for( int iRow = 0; iRow < (int)m_poKEATable->getSize(); iRow++ )
136             {
137                 poRAT->SetValue(iRow, iCol, panColData[iRow]);
138             }
139             CPLFree(panColData);
140         }
141         if( eGDALType == GFT_Real )
142         {
143             double *padfColData = (double*)VSI_MALLOC2_VERBOSE(sizeof(double), m_poKEATable->getSize());
144             if( padfColData == nullptr )
145             {
146                 delete poRAT;
147                 return nullptr;
148             }
149             if( (const_cast<KEARasterAttributeTable*>(this))->
150                         ValuesIO(GF_Read, iCol, 0, static_cast<int>(m_poKEATable->getSize()), padfColData ) != CE_None )
151             {
152                 CPLFree(padfColData);
153                 delete poRAT;
154                 return nullptr;
155             }
156 
157             for( int iRow = 0; iRow < (int)m_poKEATable->getSize(); iRow++ )
158             {
159                 poRAT->SetValue(iRow, iCol, padfColData[iRow]);
160             }
161             CPLFree(padfColData);
162         }
163         if( eGDALType == GFT_String )
164         {
165             char **papszColData = (char**)VSI_MALLOC2_VERBOSE(sizeof(char*), m_poKEATable->getSize());
166             if( papszColData == nullptr )
167             {
168                 delete poRAT;
169                 return nullptr;
170             }
171 
172             if( (const_cast<KEARasterAttributeTable*>(this))->
173                     ValuesIO(GF_Read, iCol, 0, static_cast<int>(m_poKEATable->getSize()), papszColData ) != CE_None )
174             {
175                 CPLFree(papszColData);
176                 delete poRAT;
177                 return nullptr;
178             }
179 
180             for( int iRow = 0; iRow < (int)m_poKEATable->getSize(); iRow++ )
181             {
182                 poRAT->SetValue(iRow, iCol, papszColData[iRow]);
183                 CPLFree(papszColData[iRow]);
184             }
185             CPLFree(papszColData);
186         }
187     }
188 
189     poRAT->SetTableType(this->GetTableType());
190 
191     return poRAT;
192 }
193 
GetColumnCount() const194 int KEARasterAttributeTable::GetColumnCount() const
195 {
196     return (int)m_aoFields.size();
197 }
198 
GetNameOfCol(int nCol) const199 const char *KEARasterAttributeTable::GetNameOfCol(int nCol) const
200 {
201      if( ( nCol < 0 ) || ( nCol >= (int)m_aoFields.size() ) )
202         return nullptr;
203 
204     return m_aoFields[nCol].name.c_str();
205 }
206 
GetUsageOfCol(int nCol) const207 GDALRATFieldUsage KEARasterAttributeTable::GetUsageOfCol( int nCol ) const
208 {
209     if( ( nCol < 0 ) || ( nCol >= (int)m_aoFields.size() ) )
210         return GFU_Generic;
211 
212     GDALRATFieldUsage eGDALUsage;
213     std::string keausage = m_aoFields[nCol].usage;
214 
215     if( keausage == "PixelCount" )
216         eGDALUsage = GFU_PixelCount;
217     else if( keausage == "Name" )
218         eGDALUsage = GFU_Name;
219     else if( keausage == "Red" )
220         eGDALUsage = GFU_Red;
221     else if( keausage == "Green" )
222         eGDALUsage = GFU_Green;
223     else if( keausage == "Blue" )
224         eGDALUsage = GFU_Blue;
225     else if( keausage == "Alpha" )
226         eGDALUsage = GFU_Alpha;
227     else
228     {
229         // don't recognise any other special names - generic column
230         eGDALUsage = GFU_Generic;
231     }
232 
233     return eGDALUsage;
234 }
235 
GetTypeOfCol(int nCol) const236 GDALRATFieldType KEARasterAttributeTable::GetTypeOfCol( int nCol ) const
237 {
238     if( ( nCol < 0 ) || ( nCol >= (int)m_aoFields.size() ) )
239         return GFT_Integer;
240 
241     GDALRATFieldType eGDALType;
242     switch( m_aoFields[nCol].dataType )
243     {
244         case kealib::kea_att_bool:
245         case kealib::kea_att_int:
246             eGDALType = GFT_Integer;
247             break;
248         case kealib::kea_att_float:
249             eGDALType = GFT_Real;
250             break;
251         case kealib::kea_att_string:
252             eGDALType = GFT_String;
253             break;
254         default:
255             eGDALType = GFT_Integer;
256             break;
257     }
258     return eGDALType;
259 }
260 
GetColOfUsage(GDALRATFieldUsage eUsage) const261 int KEARasterAttributeTable::GetColOfUsage( GDALRATFieldUsage eUsage ) const
262 {
263     unsigned int i;
264 
265     std::string keausage;
266     switch(eUsage)
267     {
268     case GFU_PixelCount:
269         keausage = "PixelCount";
270         break;
271     case GFU_Name:
272         keausage = "Name";
273         break;
274     case GFU_Red:
275         keausage = "Red";
276         break;
277     case GFU_Green:
278         keausage = "Green";
279         break;
280     case GFU_Blue:
281         keausage = "Blue";
282         break;
283     case GFU_Alpha:
284         keausage = "Alpha";
285         break;
286     default:
287         keausage = "Generic";
288         break;
289     }
290 
291     for( i = 0; i < m_aoFields.size(); i++ )
292     {
293         if( m_aoFields[i].usage == keausage )
294             return i;
295     }
296     return -1;
297 }
298 
GetRowCount() const299 int KEARasterAttributeTable::GetRowCount() const
300 {
301     return (int)m_poKEATable->getSize();
302 }
303 
GetValueAsString(int iRow,int iField) const304 const char *KEARasterAttributeTable::GetValueAsString( int iRow, int iField ) const
305 {
306     // Get ValuesIO do do the work
307     char *apszStrList[1];
308     if( (const_cast<KEARasterAttributeTable*>(this))->
309                 ValuesIO(GF_Read, iField, iRow, 1, apszStrList ) != CE_None )
310     {
311         return "";
312     }
313 
314     const_cast<KEARasterAttributeTable*>(this)->osWorkingResult = apszStrList[0];
315     CPLFree(apszStrList[0]);
316 
317     return osWorkingResult;
318 }
319 
GetValueAsInt(int iRow,int iField) const320 int KEARasterAttributeTable::GetValueAsInt( int iRow, int iField ) const
321 {
322     // Get ValuesIO do do the work
323     int nValue = 0;
324     if( (const_cast<KEARasterAttributeTable*>(this))->
325                 ValuesIO(GF_Read, iField, iRow, 1, &nValue ) != CE_None )
326     {
327         return 0;
328     }
329 
330     return nValue;
331 }
332 
GetValueAsDouble(int iRow,int iField) const333 double KEARasterAttributeTable::GetValueAsDouble( int iRow, int iField ) const
334 {
335     // Get ValuesIO do do the work
336     double dfValue = 0.0;
337     if( (const_cast<KEARasterAttributeTable*>(this))->
338                 ValuesIO(GF_Read, iField, iRow, 1, &dfValue ) != CE_None )
339     {
340         return 0;
341     }
342 
343     return dfValue;
344 }
345 
SetValue(int iRow,int iField,const char * pszValue)346 void KEARasterAttributeTable::SetValue( int iRow, int iField, const char *pszValue )
347 {
348     // Get ValuesIO do do the work
349     ValuesIO(GF_Write, iField, iRow, 1, const_cast<char**>(&pszValue) );
350 }
351 
SetValue(int iRow,int iField,double dfValue)352 void KEARasterAttributeTable::SetValue( int iRow, int iField, double dfValue)
353 {
354     // Get ValuesIO do do the work
355     ValuesIO(GF_Write, iField, iRow, 1, &dfValue );
356 }
357 
SetValue(int iRow,int iField,int nValue)358 void KEARasterAttributeTable::SetValue( int iRow, int iField, int nValue )
359 {
360     // Get ValuesIO do do the work
361     ValuesIO(GF_Write, iField, iRow, 1, &nValue );
362 }
363 
ValuesIO(GDALRWFlag eRWFlag,int iField,int iStartRow,int iLength,double * pdfData)364 CPLErr KEARasterAttributeTable::ValuesIO(GDALRWFlag eRWFlag, int iField, int iStartRow, int iLength, double *pdfData)
365 {
366     /*if( ( eRWFlag == GF_Write ) && ( this->eAccess == GA_ReadOnly ) )
367     {
368         CPLError( CE_Failure, CPLE_NoWriteAccess,
369             "Dataset not open in update mode");
370         return CE_Failure;
371     }*/
372     CPLMutexHolderD( &m_hMutex );
373 
374     if( iField < 0 || iField >= (int) m_aoFields.size() )
375     {
376         CPLError( CE_Failure, CPLE_AppDefined,
377                   "iField (%d) out of range.", iField );
378 
379         return CE_Failure;
380     }
381 
382     if( iStartRow < 0 || (iStartRow+iLength) > (int)m_poKEATable->getSize() )
383     {
384         CPLError( CE_Failure, CPLE_AppDefined,
385                   "iStartRow (%d) + iLength(%d) out of range.", iStartRow, iLength );
386 
387         return CE_Failure;
388     }
389 
390     switch( m_aoFields[iField].dataType )
391     {
392         case kealib::kea_att_bool:
393         case kealib::kea_att_int:
394         {
395             // allocate space for ints
396             int *panColData = (int*)VSI_MALLOC2_VERBOSE(iLength, sizeof(int) );
397             if( panColData == nullptr )
398             {
399                 return CE_Failure;
400             }
401 
402             if( eRWFlag == GF_Write )
403             {
404                 // copy the application supplied doubles to ints
405                 for( int i = 0; i < iLength; i++ )
406                     panColData[i] = static_cast<int>(pdfData[i]);
407             }
408 
409             // do the ValuesIO as ints
410             CPLErr eVal = ValuesIO(eRWFlag, iField, iStartRow, iLength, panColData );
411             if( eVal != CE_None )
412             {
413                 CPLFree(panColData);
414                 return eVal;
415             }
416 
417             if( eRWFlag == GF_Read )
418             {
419                 // copy them back to doubles
420                 for( int i = 0; i < iLength; i++ )
421                     pdfData[i] = panColData[i];
422             }
423 
424             CPLFree(panColData);
425         }
426         break;
427         case kealib::kea_att_float:
428         {
429             try
430             {
431                 if( eRWFlag == GF_Read )
432                     m_poKEATable->getFloatFields(iStartRow, iLength, m_aoFields[iField].idx, pdfData);
433                 else
434                     m_poKEATable->setFloatFields(iStartRow, iLength, m_aoFields[iField].idx, pdfData);
435             }
436             catch(kealib::KEAException &e)
437             {
438                 CPLError( CE_Failure, CPLE_AppDefined, "Failed to read/write attribute table: %s", e.what() );
439                 return CE_Failure;
440             }
441         }
442         break;
443         case kealib::kea_att_string:
444         {
445             // allocate space for string pointers
446             char **papszColData = (char**)VSI_MALLOC2_VERBOSE(iLength, sizeof(char*));
447             if( papszColData == nullptr )
448             {
449                 return CE_Failure;
450             }
451 
452             if( eRWFlag == GF_Write )
453             {
454                 // copy the application supplied doubles to strings
455                 for( int i = 0; i < iLength; i++ )
456                 {
457                     osWorkingResult.Printf( "%.16g", pdfData[i] );
458                     papszColData[i] = CPLStrdup(osWorkingResult);
459                 }
460             }
461 
462             // do the ValuesIO as strings
463             CPLErr eVal = ValuesIO(eRWFlag, iField, iStartRow, iLength, papszColData );
464             if( eVal != CE_None )
465             {
466                 if( eRWFlag == GF_Write )
467                 {
468                     for( int i = 0; i < iLength; i++ )
469                         CPLFree(papszColData[i]);
470                 }
471                 CPLFree(papszColData);
472                 return eVal;
473             }
474 
475             if( eRWFlag == GF_Read )
476             {
477                 // copy them back to doubles
478                 for( int i = 0; i < iLength; i++ )
479                     pdfData[i] = CPLAtof(papszColData[i]);
480             }
481 
482             // either we allocated them for write, or they were allocated
483             // by ValuesIO on read
484             for( int i = 0; i < iLength; i++ )
485                 CPLFree(papszColData[i]);
486 
487             CPLFree(papszColData);
488         }
489         break;
490         default:
491             break;
492     }
493     return CE_None;
494 }
495 
ValuesIO(GDALRWFlag eRWFlag,int iField,int iStartRow,int iLength,int * pnData)496 CPLErr KEARasterAttributeTable::ValuesIO(GDALRWFlag eRWFlag, int iField, int iStartRow, int iLength, int *pnData)
497 {
498     /*if( ( eRWFlag == GF_Write ) && ( this->eAccess == GA_ReadOnly ) )
499     {
500         CPLError( CE_Failure, CPLE_NoWriteAccess,
501             "Dataset not open in update mode");
502         return CE_Failure;
503     }*/
504     CPLMutexHolderD( &m_hMutex );
505 
506     if( iField < 0 || iField >= (int) m_aoFields.size() )
507     {
508         CPLError( CE_Failure, CPLE_AppDefined,
509                   "iField (%d) out of range.", iField );
510 
511         return CE_Failure;
512     }
513 
514     if( iStartRow < 0 || (iStartRow+iLength) > (int)m_poKEATable->getSize() )
515     {
516         CPLError( CE_Failure, CPLE_AppDefined,
517                   "iStartRow (%d) + iLength(%d) out of range.", iStartRow, iLength );
518 
519         return CE_Failure;
520     }
521 
522     switch( m_aoFields[iField].dataType )
523     {
524         case kealib::kea_att_bool:
525         {
526             // need to convert to/from bools
527             bool *panColData = (bool*)VSI_MALLOC2_VERBOSE(iLength, sizeof(bool) );
528             if( panColData == nullptr )
529             {
530                 return CE_Failure;
531             }
532 
533             if( eRWFlag == GF_Write )
534             {
535                 // copy the application supplied ints to bools
536                 for( int i = 0; i < iLength; i++ )
537                 {
538                     panColData[i] = (pnData[i] != 0);
539                 }
540             }
541 
542             try
543             {
544                 if( eRWFlag == GF_Read )
545                     m_poKEATable->getBoolFields(iStartRow, iLength, m_aoFields[iField].idx, panColData);
546                 else
547                     m_poKEATable->setBoolFields(iStartRow, iLength, m_aoFields[iField].idx, panColData);
548             }
549             catch(kealib::KEAException &e)
550             {
551                 CPLError( CE_Failure, CPLE_AppDefined, "Failed to read/write attribute table: %s", e.what() );
552                 return CE_Failure;
553             }
554 
555             if( eRWFlag == GF_Read )
556             {
557                 // copy them back to ints
558                 for( int i = 0; i < iLength; i++ )
559                     pnData[i] = panColData[i]? 1 : 0;
560             }
561             CPLFree(panColData);
562         }
563         break;
564         case kealib::kea_att_int:
565         {
566             // need to convert to/from int64_t
567             int64_t *panColData = (int64_t*)VSI_MALLOC2_VERBOSE(iLength, sizeof(int64_t) );
568             if( panColData == nullptr )
569             {
570                 return CE_Failure;
571             }
572 
573             if( eRWFlag == GF_Write )
574             {
575                 // copy the application supplied ints to int64t
576                 for( int i = 0; i < iLength; i++ )
577                     panColData[i] = pnData[i];
578             }
579 
580             try
581             {
582                 if( eRWFlag == GF_Read )
583                     m_poKEATable->getIntFields(iStartRow, iLength, m_aoFields[iField].idx, panColData);
584                 else
585                     m_poKEATable->setIntFields(iStartRow, iLength, m_aoFields[iField].idx, panColData);
586             }
587             catch(kealib::KEAException &e)
588             {
589                 //fprintf(stderr,"Failed to read/write attribute table: %s %d %d %ld\n", e.what(), iStartRow, iLength, m_poKEATable->getSize() );
590                 CPLError( CE_Failure, CPLE_AppDefined, "Failed to read/write attribute table: %s", e.what() );
591                 return CE_Failure;
592             }
593 
594             if( eRWFlag == GF_Read )
595             {
596                 // copy them back to ints
597                 for( int i = 0; i < iLength; i++ )
598                     pnData[i] = static_cast<int>(panColData[i]);
599             }
600             CPLFree(panColData);
601         }
602         break;
603         case kealib::kea_att_float:
604         {
605             // allocate space for doubles
606             double *padfColData = (double*)VSI_MALLOC2_VERBOSE(iLength, sizeof(double) );
607             if( padfColData == nullptr )
608             {
609                 return CE_Failure;
610             }
611 
612             if( eRWFlag == GF_Write )
613             {
614                 // copy the application supplied ints to doubles
615                 for( int i = 0; i < iLength; i++ )
616                     padfColData[i] = pnData[i];
617             }
618 
619             // do the ValuesIO as doubles
620             CPLErr eVal = ValuesIO(eRWFlag, iField, iStartRow, iLength, padfColData );
621             if( eVal != CE_None )
622             {
623                 CPLFree(padfColData);
624                 return eVal;
625             }
626 
627             if( eRWFlag == GF_Read )
628             {
629                 // copy them back to ints
630                 for( int i = 0; i < iLength; i++ )
631                     pnData[i] = static_cast<int>(padfColData[i]);
632             }
633 
634             CPLFree(padfColData);
635         }
636         break;
637         case kealib::kea_att_string:
638         {
639             // allocate space for string pointers
640             char **papszColData = (char**)VSI_MALLOC2_VERBOSE(iLength, sizeof(char*));
641             if( papszColData == nullptr )
642             {
643                 return CE_Failure;
644             }
645 
646             if( eRWFlag == GF_Write )
647             {
648                 // copy the application supplied ints to strings
649                 for( int i = 0; i < iLength; i++ )
650                 {
651                     osWorkingResult.Printf( "%d", pnData[i] );
652                     papszColData[i] = CPLStrdup(osWorkingResult);
653                 }
654             }
655 
656             // do the ValuesIO as strings
657             CPLErr eVal = ValuesIO(eRWFlag, iField, iStartRow, iLength, papszColData );
658             if( eVal != CE_None )
659             {
660                 if( eRWFlag == GF_Write )
661                 {
662                     for( int i = 0; i < iLength; i++ )
663                         CPLFree(papszColData[i]);
664                 }
665                 CPLFree(papszColData);
666                 return eVal;
667             }
668 
669             if( eRWFlag == GF_Read )
670             {
671                 // copy them back to ints
672                 for( int i = 0; i < iLength; i++ )
673                     pnData[i] = atoi(papszColData[i]);
674             }
675 
676             // either we allocated them for write, or they were allocated
677             // by ValuesIO on read
678             for( int i = 0; i < iLength; i++ )
679                 CPLFree(papszColData[i]);
680 
681             CPLFree(papszColData);
682         }
683         break;
684         default:
685             break;
686     }
687     return CE_None;
688 }
689 
ValuesIO(GDALRWFlag eRWFlag,int iField,int iStartRow,int iLength,char ** papszStrList)690 CPLErr KEARasterAttributeTable::ValuesIO(GDALRWFlag eRWFlag, int iField, int iStartRow, int iLength, char **papszStrList)
691 {
692     /*if( ( eRWFlag == GF_Write ) && ( this->eAccess == GA_ReadOnly ) )
693     {
694         CPLError( CE_Failure, CPLE_NoWriteAccess,
695             "Dataset not open in update mode");
696         return CE_Failure;
697     }*/
698     CPLMutexHolderD( &m_hMutex );
699 
700     if( iField < 0 || iField >= (int) m_aoFields.size() )
701     {
702         CPLError( CE_Failure, CPLE_AppDefined,
703                   "iField (%d) out of range.", iField );
704 
705         return CE_Failure;
706     }
707 
708     if( iStartRow < 0 || (iStartRow+iLength) > (int)m_poKEATable->getSize() )
709     {
710         CPLError( CE_Failure, CPLE_AppDefined,
711                   "iStartRow (%d) + iLength(%d) out of range.", iStartRow, iLength );
712 
713         return CE_Failure;
714     }
715 
716     switch( m_aoFields[iField].dataType )
717     {
718         case kealib::kea_att_bool:
719         case kealib::kea_att_int:
720         {
721             // allocate space for ints
722             int *panColData = (int*)VSI_MALLOC2_VERBOSE(iLength, sizeof(int) );
723             if( panColData == nullptr )
724             {
725                 return CE_Failure;
726             }
727             if( eRWFlag == GF_Write )
728             {
729                 // convert user supplied strings to ints
730                 for( int i = 0; i < iLength; i++ )
731                     panColData[i] = atoi(papszStrList[i]);
732             }
733 
734             // call values IO to read/write ints
735             CPLErr eVal = ValuesIO(eRWFlag, iField, iStartRow, iLength, panColData);
736             if( eVal != CE_None )
737             {
738                 CPLFree(panColData);
739                 return eVal;
740             }
741 
742             if( eRWFlag == GF_Read )
743             {
744                 // convert ints back to strings
745                 for( int i = 0; i < iLength; i++ )
746                 {
747                     osWorkingResult.Printf( "%d", panColData[i]);
748                     papszStrList[i] = CPLStrdup(osWorkingResult);
749                 }
750             }
751             CPLFree(panColData);
752         }
753         break;
754         case kealib::kea_att_float:
755         {
756             // allocate space for doubles
757             double *padfColData = (double*)VSI_MALLOC2_VERBOSE(iLength, sizeof(double) );
758             if( padfColData == nullptr )
759             {
760                 return CE_Failure;
761             }
762 
763             if( eRWFlag == GF_Write )
764             {
765                 // convert user supplied strings to doubles
766                 for( int i = 0; i < iLength; i++ )
767                     padfColData[i] = CPLAtof(papszStrList[i]);
768             }
769 
770             // call value IO to read/write doubles
771             CPLErr eVal = ValuesIO(eRWFlag, iField, iStartRow, iLength, padfColData);
772             if( eVal != CE_None )
773             {
774                 CPLFree(padfColData);
775                 return eVal;
776             }
777 
778             if( eRWFlag == GF_Read )
779             {
780                 // convert doubles back to strings
781                 for( int i = 0; i < iLength; i++ )
782                 {
783                     osWorkingResult.Printf( "%.16g", padfColData[i]);
784                     papszStrList[i] = CPLStrdup(osWorkingResult);
785                 }
786             }
787             CPLFree(padfColData);
788         }
789         break;
790         case kealib::kea_att_string:
791         {
792             try
793             {
794                 if( eRWFlag == GF_Read )
795                 {
796                     std::vector<std::string> aStrings;
797                     m_poKEATable->getStringFields(iStartRow, iLength, m_aoFields[iField].idx, &aStrings);
798                     for( std::vector<std::string>::size_type i = 0; i < aStrings.size(); i++ )
799                     {
800                         // Copy using CPLStrdup so user can call CPLFree
801                         papszStrList[i] = CPLStrdup(aStrings[i].c_str());
802                     }
803                 }
804                 else
805                 {
806                     // need to convert to a vector first
807                     std::vector<std::string> aStrings;
808                     for( int i = 0; i < iLength; i++ )
809                     {
810                         aStrings.push_back(papszStrList[i]);
811                     }
812                     m_poKEATable->setStringFields(iStartRow, iLength, m_aoFields[iField].idx, &aStrings);
813                 }
814             }
815             catch(kealib::KEAException &e)
816             {
817                 CPLError( CE_Failure, CPLE_AppDefined, "Failed to read/write attribute table: %s", e.what() );
818                 return CE_Failure;
819             }
820         }
821         break;
822         default:
823             break;
824     }
825     return CE_None;
826 }
827 
ChangesAreWrittenToFile()828 int KEARasterAttributeTable::ChangesAreWrittenToFile()
829 {
830     return TRUE;
831 }
832 
SetRowCount(int iCount)833 void KEARasterAttributeTable::SetRowCount( int iCount )
834 {
835     /*if( this->eAccess == GA_ReadOnly )
836     {
837         CPLError( CE_Failure, CPLE_NoWriteAccess,
838             "Dataset not open in update mode");
839         return;
840     }*/
841 
842     if( iCount > (int)m_poKEATable->getSize() )
843     {
844         m_poKEATable->addRows(iCount - m_poKEATable->getSize());
845     }
846     // can't shrink
847 }
848 
CreateColumn(const char * pszFieldName,GDALRATFieldType eFieldType,GDALRATFieldUsage eFieldUsage)849 CPLErr KEARasterAttributeTable::CreateColumn( const char *pszFieldName,
850                                 GDALRATFieldType eFieldType,
851                                 GDALRATFieldUsage eFieldUsage )
852 {
853     /*if( this->eAccess == GA_ReadOnly )
854     {
855         CPLError( CE_Failure, CPLE_NoWriteAccess,
856             "Dataset not open in update mode");
857         return CE_Failure;
858     }*/
859     CPLMutexHolderD( &m_hMutex );
860 
861     std::string strUsage = "Generic";
862     switch(eFieldUsage)
863     {
864         case GFU_PixelCount:
865             strUsage = "PixelCount";
866             eFieldType = GFT_Real;
867             break;
868         case GFU_Name:
869             strUsage = "Name";
870             eFieldType = GFT_String;
871             break;
872         case GFU_Red:
873             strUsage = "Red";
874             eFieldType = GFT_Integer;
875             break;
876         case GFU_Green:
877             strUsage = "Green";
878             eFieldType = GFT_Integer;
879             break;
880         case GFU_Blue:
881             strUsage = "Blue";
882             eFieldType = GFT_Integer;
883             break;
884         case GFU_Alpha:
885             strUsage = "Alpha";
886             eFieldType = GFT_Integer;
887             break;
888         default:
889             // leave as "Generic"
890             break;
891     }
892 
893     try
894     {
895         if(eFieldType == GFT_Integer)
896         {
897             m_poKEATable->addAttIntField(pszFieldName, 0, strUsage);
898         }
899         else if(eFieldType == GFT_Real)
900         {
901             m_poKEATable->addAttFloatField(pszFieldName, 0, strUsage);
902         }
903         else
904         {
905             m_poKEATable->addAttStringField(pszFieldName, "", strUsage);
906         }
907 
908         // assume we can just grab this now
909         kealib::KEAATTField sKEAField = m_poKEATable->getField(pszFieldName);
910         m_aoFields.push_back(sKEAField);
911     }
912     catch(kealib::KEAException &e)
913     {
914         CPLError( CE_Failure, CPLE_AppDefined, "Failed to add column: %s", e.what() );
915         return CE_Failure;
916     }
917 
918     return CE_None;
919 }
920 
SetLinearBinning(double ldfRow0Min,double ldfBinSize)921 CPLErr KEARasterAttributeTable::SetLinearBinning( double ldfRow0Min,
922                                             double ldfBinSize )
923 {
924     size_t nRows = m_poKEATable->getSize();
925 
926     osWorkingResult.Printf( "%.16g", ldfRow0Min);
927     m_poBand->SetMetadataItem("STATISTICS_HISTOMIN", osWorkingResult);
928     osWorkingResult.Printf( "%.16g", (nRows - 1) * ldfBinSize + ldfRow0Min);
929     m_poBand->SetMetadataItem("STATISTICS_HISTOMAX", osWorkingResult);
930 
931     // STATISTICS_HISTONUMBINS now returned by metadata
932 
933     return CE_None;
934 }
935 
GetLinearBinning(double * pdfRow0Min,double * pdfBinSize) const936 int KEARasterAttributeTable::GetLinearBinning( double *pdfRow0Min,
937                                             double *pdfBinSize ) const
938 {
939     const char *pszMin = m_poBand->GetMetadataItem("STATISTICS_HISTOMIN");
940     const char *pszMax = m_poBand->GetMetadataItem("STATISTICS_HISTOMAX");
941     if( ( pszMin == nullptr ) || ( pszMax == nullptr ) )
942     {
943         return FALSE;
944     }
945     *pdfRow0Min = atof(pszMin);
946     *pdfBinSize = (atof(pszMax) - *pdfRow0Min) / (m_poKEATable->getSize() - 1);
947 
948     return TRUE;
949 }
950 
Serialize() const951 CPLXMLNode *KEARasterAttributeTable::Serialize() const
952 {
953     if( ( GetRowCount() * GetColumnCount() ) > RAT_MAX_ELEM_FOR_CLONE )
954         return nullptr;
955 
956     return GDALRasterAttributeTable::Serialize();
957 }
958 
GetTableType() const959 GDALRATTableType KEARasterAttributeTable::GetTableType() const
960 {
961     kealib::KEALayerType keaType = m_poBand->getLayerType();
962     if( keaType == kealib::kea_continuous )
963     {
964         return GRTT_ATHEMATIC;
965     }
966     else
967     {
968         return GRTT_THEMATIC;
969     }
970 }
971 
SetTableType(const GDALRATTableType eInTableType)972 CPLErr KEARasterAttributeTable::SetTableType(const GDALRATTableType eInTableType)
973 {
974     kealib::KEALayerType keaType = (eInTableType == GRTT_ATHEMATIC) ? kealib::kea_continuous : kealib::kea_thematic;
975     try
976     {
977         m_poBand->setLayerType(keaType);
978         return CE_None;
979     }
980     catch (const kealib::KEAIOException &)
981     {
982         return CE_Failure;
983     }
984 }
985