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