1 /******************************************************************************
2  *
3  * Project:  FIT Driver
4  * Purpose:  Implement FIT Support - not using the SGI iflFIT library.
5  * Author:   Philip Nemec, nemec@keyholecorp.com
6  *
7  ******************************************************************************
8  * Copyright (c) 2001, Keyhole, Inc.
9  * Copyright (c) 2007-2011, Even Rouault <even dot rouault at spatialys.com>
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 "cpl_string.h"
31 #include "fit.h"
32 #include "gdal_frmts.h"
33 #include "gdal_pam.h"
34 #include "gstEndian.h"
35 #include "cpl_safemaths.hpp"
36 
37 #include <algorithm>
38 
39 CPL_CVSID("$Id: fitdataset.cpp 9c79c3b6133e164c0362bb3e76ca2d9bae0d7835 2020-11-06 20:26:14 +0100 Even Rouault $")
40 
41 constexpr size_t FIT_PAGE_SIZE = 128;
42 
43 using namespace gstEndian;
44 
45 /************************************************************************/
46 /* ==================================================================== */
47 /*                              FITDataset                              */
48 /* ==================================================================== */
49 /************************************************************************/
50 
51 class FITRasterBand;
52 
53 class FITDataset final: public GDALPamDataset
54 {
55     friend class FITRasterBand;
56 
57     VSILFILE    *fp;
58     FITinfo     *info;
59     double      adfGeoTransform[6];
60 
61   public:
62     FITDataset();
63     ~FITDataset();
64     static GDALDataset *Open( GDALOpenInfo * );
65     // virtual CPLErr GetGeoTransform( double * );
66 };
67 
68 static GDALDataset *FITCreateCopy(const char * pszFilename,
69                                   GDALDataset *poSrcDS,
70                                   int bStrict, char ** papszOptions,
71                                   GDALProgressFunc pfnProgress,
72                                   void * pProgressData );
73 
74 /************************************************************************/
75 /* ==================================================================== */
76 /*                            FITRasterBand                             */
77 /* ==================================================================== */
78 /************************************************************************/
79 
80 class FITRasterBand final: public GDALPamRasterBand
81 {
82     friend class FITDataset;
83 
84     unsigned long recordSize; // number of bytes of a single page/block/record
85     unsigned long numXBlocks; // number of pages in the X direction
86     unsigned long numYBlocks; // number of pages in the Y direction
87     unsigned long bytesPerComponent;
88     unsigned long bytesPerPixel;
89     char *tmpImage;
90 
91 public:
92     FITRasterBand( FITDataset *, int nBandIn, int nBandsIn );
93     ~FITRasterBand() override;
94 
95     // should override RasterIO eventually.
96 
97     CPLErr IReadBlock( int, int, void * ) override;
98     // virtual CPLErr WriteBlock( int, int, void * );
99     double GetMinimum( int *pbSuccess ) override;
100     double GetMaximum( int *pbSuccess ) override;
101     GDALColorInterp GetColorInterpretation() override;
102 };
103 
104 /************************************************************************/
105 /*                           FITRasterBand()                            */
106 /************************************************************************/
107 
FITRasterBand(FITDataset * poDSIn,int nBandIn,int nBandsIn)108 FITRasterBand::FITRasterBand( FITDataset *poDSIn, int nBandIn, int nBandsIn ) :
109     recordSize(0),
110     numXBlocks(0),
111     numYBlocks(0),
112     bytesPerComponent(0),
113     bytesPerPixel(0),
114     tmpImage( nullptr )
115 {
116     poDS = poDSIn;
117     nBand = nBandIn;
118 
119 /* -------------------------------------------------------------------- */
120 /*      Get the GDAL data type.                                         */
121 /* -------------------------------------------------------------------- */
122     eDataType = fitDataType(poDSIn->info->dtype);
123 
124 /* -------------------------------------------------------------------- */
125 /*      Get the page sizes.                                             */
126 /* -------------------------------------------------------------------- */
127     nBlockXSize = poDSIn->info->xPageSize;
128     nBlockYSize = poDSIn->info->yPageSize;
129 
130 /* -------------------------------------------------------------------- */
131 /*      Calculate the values for record offset calculations.             */
132 /* -------------------------------------------------------------------- */
133     bytesPerComponent = GDALGetDataTypeSizeBytes(eDataType);
134     if( bytesPerComponent == 0 )
135         return;
136     bytesPerPixel = nBandsIn * bytesPerComponent;
137     const auto knIntMax = std::numeric_limits<int>::max();
138     if( nBlockXSize <= 0 || nBlockYSize <= 0 ||
139         nBlockXSize > knIntMax / static_cast<int>(bytesPerPixel) ||
140         nBlockYSize > knIntMax /
141             (nBlockXSize * static_cast<int>(bytesPerPixel)) )
142         return;
143     recordSize = bytesPerPixel * nBlockXSize * nBlockYSize;
144     numXBlocks =
145         (unsigned long) ceil((double) poDSIn->info->xSize / nBlockXSize);
146     numYBlocks =
147         (unsigned long) ceil((double) poDSIn->info->ySize / nBlockYSize);
148 
149     tmpImage = (char *) VSI_MALLOC_VERBOSE(recordSize);
150 /* -------------------------------------------------------------------- */
151 /*      Set the access flag.  For now we set it the same as the         */
152 /*      whole dataset, but eventually this should take account of       */
153 /*      locked channels, or read-only secondary data files.             */
154 /* -------------------------------------------------------------------- */
155     /* ... */
156 }
157 
~FITRasterBand()158 FITRasterBand::~FITRasterBand()
159 {
160     VSIFree ( tmpImage );
161 }
162 
163 /************************************************************************/
164 /*                            IReadBlock()                              */
165 /************************************************************************/
166 
167 #define COPY_XFIRST(t) { \
168                 t *dstp = (t *) pImage; \
169                 t *srcp = (t *) tmpImage; \
170                 srcp += nBand-1; \
171                 long imacro = 0; \
172                 for(long y=ystart; y != ystop; y+= yinc) \
173                     for(long x=xstart; x != xstop; x+= xinc, imacro++) { \
174                         dstp[imacro] = srcp[(y * nBlockXSize + x) * \
175                                        poFIT_DS->nBands]; \
176                     } \
177     }
178 
179 #define COPY_YFIRST(t) { \
180                 t *dstp = (t *) pImage; \
181                 t *srcp = (t *) tmpImage; \
182                 srcp += nBand-1; \
183                 long imacro = 0; \
184                 for(long x=xstart; x != xstop; x+= xinc, imacro++) \
185                     for(long y=ystart; y != ystop; y+= yinc) { \
186                         dstp[imacro] = srcp[(x * nBlockYSize + y) * \
187                                        poFIT_DS->nBands]; \
188                     } \
189     }
190 
IReadBlock(int nBlockXOff,int nBlockYOff,void * pImage)191 CPLErr FITRasterBand::IReadBlock( int nBlockXOff, int nBlockYOff,
192                                   void * pImage )
193 
194 {
195     FITDataset *poFIT_DS = (FITDataset *) poDS;
196 
197     uint64 tilenum = 0;
198 
199     switch (poFIT_DS->info->space) {
200     case 1:
201         // iflUpperLeftOrigin - from upper left corner
202         // scan right then down
203         tilenum = nBlockYOff * numXBlocks + nBlockXOff;
204         break;
205     case 2:
206         // iflUpperRightOrigin - from upper right corner
207         // scan left then down
208         tilenum = numYBlocks * numXBlocks + (numXBlocks-1-nBlockXOff);
209         break;
210     case 3:
211         // iflLowerRightOrigin - from lower right corner
212         // scan left then up
213         tilenum = (numYBlocks-1-nBlockYOff) * numXBlocks +
214             (numXBlocks-1-nBlockXOff);
215         break;
216     case 4:
217         // iflLowerLeftOrigin - from lower left corner
218         // scan right then up
219         tilenum = (numYBlocks-1-nBlockYOff) * numXBlocks + nBlockXOff;
220         break;
221     case 5:
222         // iflLeftUpperOrigin -* from upper left corner
223         // scan down then right
224         tilenum = nBlockXOff * numYBlocks + nBlockYOff;
225         break;
226     case 6:
227         // iflRightUpperOrigin - from upper right corner
228         // scan down then left
229         tilenum = (numXBlocks-1-nBlockXOff) * numYBlocks + nBlockYOff;
230         break;
231     case 7:
232         // iflRightLowerOrigin - from lower right corner
233         // scan up then left
234         tilenum = nBlockXOff * numYBlocks + (numYBlocks-1-nBlockYOff);
235         break;
236     case 8:
237         // iflLeftLowerOrigin -* from lower left corner
238         // scan up then right
239         tilenum = (numXBlocks-1-nBlockXOff) * numYBlocks +
240             (numYBlocks-1-nBlockYOff);
241         break;
242     default:
243         CPLError(CE_Failure, CPLE_NotSupported,
244                  "FIT - unrecognized image space %i",
245                  poFIT_DS->info->space);
246         return CE_Failure;
247     } // switch
248 
249     uint64 offset = poFIT_DS->info->dataOffset + recordSize * tilenum;
250 //     CPLDebug("FIT", "%i RasterBand::IReadBlock %i %i (out of %i %i) -- %i",
251 //              poFIT_DS->info->space,
252 //              nBlockXOff, nBlockYOff, numXBlocks, numYBlocks, tilenum);
253 
254     if ( VSIFSeekL( poFIT_DS->fp, offset, SEEK_SET ) == -1 ) {
255         CPLError(CE_Failure, CPLE_NotSupported,
256                  "FIT - 64bit file seek failure, handle=%p", poFIT_DS->fp );
257             return CE_Failure;
258     }
259 
260     // XXX - should handle status
261     // fast path is single component (ll?) - no copy needed
262     int fastpath = FALSE;
263 
264     if ((poFIT_DS->nBands == 1) && (poFIT_DS->info->space == 1)) // upper left
265         fastpath = TRUE;
266 
267     size_t nRead = 0;
268     char *p = nullptr;
269     if (! fastpath) {
270         nRead = VSIFReadL( tmpImage, recordSize, 1, poFIT_DS->fp );
271         // offset to correct component to swap
272         p = (char *) tmpImage + nBand-1;
273     }
274     else {
275         nRead = VSIFReadL( pImage, recordSize, 1, poFIT_DS->fp );
276         p = (char *) pImage;
277     }
278     if( nRead != 1 )
279     {
280         CPLError(CE_Failure, CPLE_FileIO, "Cannot read record");
281         return CE_Failure;
282     }
283 
284 #ifdef swapping
285     unsigned long i = 0;
286 
287     switch(bytesPerComponent) {
288     case 1:
289         // do nothing
290         break;
291     case 2:
292         for(i=0; i < recordSize; i+= bytesPerPixel)
293             gst_swap16(p + i);
294         break;
295     case 4:
296         for(i=0; i < recordSize; i+= bytesPerPixel)
297             gst_swap32(p + i);
298         break;
299     case 8:
300         for(i=0; i < recordSize; i+= bytesPerPixel)
301             gst_swap64(p + i);
302         break;
303     default:
304         CPLError(CE_Failure, CPLE_NotSupported,
305                  "FITRasterBand::IReadBlock unsupported bytesPerPixel %lu",
306                  bytesPerComponent);
307     } // switch
308 #else
309     (void) p; // avoid warnings.
310 #endif // swapping
311 
312     if (! fastpath) {
313         long xinc, yinc, xstart, ystart, xstop, ystop;
314         if (poFIT_DS->info->space <= 4) {
315             // scan left/right first
316 
317             switch (poFIT_DS->info->space) {
318             case 1:
319                 // iflUpperLeftOrigin - from upper left corner
320                 // scan right then down
321                 xinc = 1;
322                 yinc = 1;
323                 break;
324             case 2:
325                 // iflUpperRightOrigin - from upper right corner
326                 // scan left then down
327                 xinc = -1;
328                 yinc = 1;
329                 break;
330             case 3:
331                 // iflLowerRightOrigin - from lower right corner
332                 // scan left then up
333                 xinc = -1;
334                 yinc = -1;
335                 break;
336             case 4:
337                 // iflLowerLeftOrigin - from lower left corner
338                 // scan right then up
339                 xinc = 1;
340                 yinc = -1;
341                break;
342             default:
343                 CPLError(CE_Failure, CPLE_NotSupported,
344                          "FIT - unrecognized image space %i",
345                          poFIT_DS->info->space);
346                 xinc = 1;
347                 yinc = 1;
348             } // switch
349 
350             if (xinc == 1) {
351                 xstart = 0;
352                 xstop = nBlockXSize;
353             }
354             else {
355                 xstart = nBlockXSize-1;
356                 xstop = -1;
357             }
358             if (yinc == 1) {
359                 ystart = 0;
360                 ystop = nBlockYSize;
361             }
362             else {
363                 int localBlockYSize = nBlockYSize;
364                 long maxy_full =
365                     (long) floor(poFIT_DS->info->ySize / (double) nBlockYSize);
366                 if (nBlockYOff >= maxy_full)
367                     localBlockYSize = poFIT_DS->info->ySize % nBlockYSize;
368                 ystart = localBlockYSize-1;
369                 ystop = -1;
370             }
371 
372             switch(bytesPerComponent) {
373             case 1:
374                 COPY_XFIRST(char);
375                 break;
376             case 2:
377                 COPY_XFIRST(uint16);
378                 break;
379             case 4:
380                 COPY_XFIRST(uint32);
381                 break;
382             case 8:
383                 COPY_XFIRST(uint64);
384                 break;
385             default:
386                 CPLError(CE_Failure, CPLE_NotSupported,
387                          "FITRasterBand::IReadBlock unsupported "
388                          "bytesPerComponent %lu", bytesPerComponent);
389             } // switch
390         } // Scan left/right first.
391         else
392         {
393             // Scan up/down first.
394             switch (poFIT_DS->info->space)
395             {
396             case 5:
397                 // iflLeftUpperOrigin -* from upper left corner
398                 // scan down then right
399                 xinc = 1;
400                 yinc = 1;
401                 break;
402             case 6:
403                 // iflRightUpperOrigin - from upper right corner
404                 // scan down then left
405                 xinc = -1;
406                 yinc = 1;
407                 break;
408             case 7:
409                 // iflRightLowerOrigin - from lower right corner
410                 // scan up then left
411                 xinc = -1;
412                 yinc = -1;
413                 break;
414             case 8:
415                 // iflLeftLowerOrigin -* from lower left corner
416                 // scan up then right
417                 xinc = 1;
418                 yinc = -1;
419                 break;
420             default:
421                 CPLError(CE_Failure, CPLE_NotSupported,
422                          "FIT - unrecognized image space %i",
423                          poFIT_DS->info->space);
424                 xinc = 1;
425                 yinc = 1;
426             } // switch
427 
428             if (xinc == 1) {
429                 xstart = 0;
430                 xstop = nBlockXSize;
431             }
432             else {
433                 int localBlockXSize = nBlockXSize;
434                 long maxx_full =
435                     (long) floor(poFIT_DS->info->xSize / (double) nBlockXSize);
436                 if (nBlockXOff >= maxx_full)
437                     localBlockXSize = poFIT_DS->info->xSize % nBlockXSize;
438                 xstart = localBlockXSize-1;
439                 xstop = -1;
440             }
441             if (yinc == 1) {
442                 ystart = 0;
443                 ystop = nBlockYSize;
444             }
445             else {
446                 ystart = nBlockYSize-1;
447                 ystop = -1;
448             }
449 
450             switch(bytesPerComponent) {
451             case 1:
452                 COPY_YFIRST(char);
453                 break;
454             case 2:
455                 COPY_YFIRST(uint16);
456                 break;
457             case 4:
458                 COPY_YFIRST(uint32);
459                 break;
460             case 8:
461                 COPY_YFIRST(uint64);
462                 break;
463             default:
464                 CPLError(CE_Failure, CPLE_NotSupported,
465                          "FITRasterBand::IReadBlock unsupported "
466                          "bytesPerComponent %lu", bytesPerComponent);
467             } // switch
468         } // Scan up/down first.
469     } // !fastpath
470     return CE_None;
471 }
472 
473 #if 0
474 /************************************************************************/
475 /*                             ReadBlock()                              */
476 /************************************************************************/
477 
478 CPLErr FITRasterBand::ReadBlock( int nBlockXOff, int nBlockYOff,
479                                  void * pImage )
480 
481 {
482     FITDataset *poFIT_DS = (FITDataset *) poDS;
483 
484     return CE_None;
485 }
486 
487 /************************************************************************/
488 /*                             WriteBlock()                             */
489 /************************************************************************/
490 
491 CPLErr FITRasterBand::WriteBlock( int nBlockXOff, int nBlockYOff,
492                                  void * pImage )
493 
494 {
495     FITDataset *poFIT_DS = (FITDataset *) poDS;
496 
497     return CE_None;
498 }
499 #endif
500 
501 /************************************************************************/
502 /*                             GetMinimum()                             */
503 /************************************************************************/
504 
GetMinimum(int * pbSuccess)505 double FITRasterBand::GetMinimum( int *pbSuccess )
506 {
507     FITDataset *poFIT_DS = (FITDataset *) poDS;
508 
509     if ((! poFIT_DS) || (! poFIT_DS->info))
510         return GDALRasterBand::GetMinimum( pbSuccess );
511 
512     if (pbSuccess)
513         *pbSuccess = TRUE;
514 
515     if (poFIT_DS->info->version &&
516         STARTS_WITH_CI((const char *) &(poFIT_DS->info->version), "02")) {
517         return poFIT_DS->info->minValue;
518     }
519 
520     return GDALRasterBand::GetMinimum( pbSuccess );
521 }
522 
523 /************************************************************************/
524 /*                             GetMaximum()                             */
525 /************************************************************************/
526 
GetMaximum(int * pbSuccess)527 double FITRasterBand::GetMaximum( int *pbSuccess )
528 {
529     FITDataset *poFIT_DS = (FITDataset *) poDS;
530 
531     if ((! poFIT_DS) || (! poFIT_DS->info))
532         return GDALRasterBand::GetMaximum( pbSuccess );
533 
534     if (pbSuccess)
535         *pbSuccess = TRUE;
536 
537     if (STARTS_WITH_CI((const char *) &poFIT_DS->info->version, "02")) {
538         return poFIT_DS->info->maxValue;
539     }
540 
541     return GDALRasterBand::GetMaximum( pbSuccess );
542 }
543 
544 /************************************************************************/
545 /*                       GetColorInterpretation()                       */
546 /************************************************************************/
547 
GetColorInterpretation()548 GDALColorInterp FITRasterBand::GetColorInterpretation()
549 {
550     FITDataset *poFIT_DS = (FITDataset *) poDS;
551 
552     if ((! poFIT_DS) || (! poFIT_DS->info))
553         return GCI_Undefined;
554 
555     switch(poFIT_DS->info->cm) {
556     case 1: // iflNegative - inverted luminance (min value is white)
557         CPLError( CE_Warning, CPLE_NotSupported,
558                   "FIT - color model Negative not supported - ignoring model");
559             return GCI_Undefined;
560 
561     case 2: // iflLuminance - luminance
562         if (poFIT_DS->nBands != 1) {
563             CPLError( CE_Failure, CPLE_NotSupported,
564                       "FIT - color model Luminance mismatch with %i bands",
565                       poFIT_DS->nBands);
566             return GCI_Undefined;
567         }
568         switch (nBand) {
569         case 1:
570             return GCI_GrayIndex;
571         default:
572             CPLError( CE_Failure, CPLE_NotSupported,
573                       "FIT - color model Luminance unknown band %i", nBand);
574             return GCI_Undefined;
575         } // switch nBand
576 
577     case 3: // iflRGB - full color (Red, Green, Blue triplets)
578         if (poFIT_DS->nBands != 3) {
579             CPLError( CE_Failure, CPLE_NotSupported,
580                       "FIT - color model RGB mismatch with %i bands",
581                       poFIT_DS->nBands);
582             return GCI_Undefined;
583         }
584         switch (nBand) {
585         case 1:
586             return GCI_RedBand;
587         case 2:
588             return GCI_GreenBand;
589         case 3:
590             return GCI_BlueBand;
591         default:
592             CPLError( CE_Failure, CPLE_NotSupported,
593                       "FIT - color model RGB unknown band %i", nBand);
594             return GCI_Undefined;
595         } // switch nBand
596 
597     case 4: // iflRGBPalette - color mapped values
598         CPLError( CE_Warning, CPLE_NotSupported,
599                   "FIT - color model  RGBPalette not supported - "
600                   "ignoring model");
601             return GCI_Undefined;
602 
603     case 5: // iflRGBA - full color with transparency (alpha channel)
604         if (poFIT_DS->nBands != 4) {
605             CPLError( CE_Failure, CPLE_NotSupported,
606                       "FIT - color model RGBA mismatch with %i bands",
607                       poFIT_DS->nBands);
608             return GCI_Undefined;
609         }
610         switch (nBand) {
611         case 1:
612             return GCI_RedBand;
613         case 2:
614             return GCI_GreenBand;
615         case 3:
616             return GCI_BlueBand;
617         case 4:
618             return GCI_AlphaBand;
619         default:
620             CPLError( CE_Failure, CPLE_NotSupported,
621                       "FIT - color model RGBA unknown band %i", nBand);
622             return GCI_Undefined;
623         } // switch nBand
624 
625     case 6: // iflHSV - Hue, Saturation, Value
626         if (poFIT_DS->nBands != 3) {
627             CPLError( CE_Failure, CPLE_NotSupported,
628                       "FIT - color model HSV mismatch with %i bands",
629                       poFIT_DS->nBands);
630             return GCI_Undefined;
631         }
632         switch (nBand) {
633         case 1:
634             return GCI_HueBand;
635         case 2:
636             return GCI_SaturationBand;
637         case 3:
638             return GCI_LightnessBand;
639         default:
640             CPLError( CE_Failure, CPLE_NotSupported,
641                       "FIT - color model HSV unknown band %i", nBand);
642             return GCI_Undefined;
643         } // switch nBand
644 
645     case 7: // iflCMY - Cyan, Magenta, Yellow
646         if (poFIT_DS->nBands != 3) {
647             CPLError( CE_Failure, CPLE_NotSupported,
648                       "FIT - color model CMY mismatch with %i bands",
649                       poFIT_DS->nBands);
650             return GCI_Undefined;
651         }
652         switch (nBand) {
653         case 1:
654             return GCI_CyanBand;
655         case 2:
656             return GCI_MagentaBand;
657         case 3:
658             return GCI_YellowBand;
659         default:
660             CPLError( CE_Failure, CPLE_NotSupported,
661                       "FIT - color model CMY unknown band %i", nBand);
662             return GCI_Undefined;
663         } // switch nBand
664 
665     case 8: // iflCMYK - Cyan, Magenta, Yellow, Black
666         if (poFIT_DS->nBands != 4) {
667             CPLError( CE_Failure, CPLE_NotSupported,
668                       "FIT - color model CMYK mismatch with %i bands",
669                       poFIT_DS->nBands);
670             return GCI_Undefined;
671         }
672         switch (nBand) {
673         case 1:
674             return GCI_CyanBand;
675         case 2:
676             return GCI_MagentaBand;
677         case 3:
678             return GCI_YellowBand;
679         case 4:
680             return GCI_BlackBand;
681         default:
682             CPLError( CE_Failure, CPLE_NotSupported,
683                       "FIT - color model CMYK unknown band %i", nBand);
684             return GCI_Undefined;
685         } // switch nBand
686 
687     case 9: // iflBGR - full color (ordered Blue, Green, Red)
688         if (poFIT_DS->nBands != 3) {
689             CPLError( CE_Failure, CPLE_NotSupported,
690                       "FIT - color model BGR mismatch with %i bands",
691                       poFIT_DS->nBands);
692             return GCI_Undefined;
693         }
694         switch (nBand) {
695         case 1:
696             return GCI_BlueBand;
697         case 2:
698             return GCI_GreenBand;
699         case 3:
700             return GCI_RedBand;
701         default:
702             CPLError( CE_Failure, CPLE_NotSupported,
703                       "FIT - color model BGR unknown band %i", nBand);
704             return GCI_Undefined;
705         } // switch nBand
706 
707     case 10: // iflABGR - Alpha, Blue, Green, Red (SGI frame buffers)
708         if (poFIT_DS->nBands != 4) {
709             CPLError( CE_Failure, CPLE_NotSupported,
710                       "FIT - color model ABGR mismatch with %i bands",
711                       poFIT_DS->nBands);
712             return GCI_Undefined;
713         }
714         switch (nBand) {
715         case 1:
716             return GCI_AlphaBand;
717         case 2:
718             return GCI_BlueBand;
719         case 3:
720             return GCI_GreenBand;
721         case 4:
722             return GCI_RedBand;
723         default:
724             CPLError( CE_Failure, CPLE_NotSupported,
725                       "FIT - color model ABGR unknown band %i", nBand);
726             return GCI_Undefined;
727         } // switch nBand
728 
729     case 11: // iflMultiSpectral - multi-spectral data, arbitrary number of
730         // chans
731         return GCI_Undefined;
732 
733     case 12: // iflYCC PhotoCD color model (Luminance, Chrominance)
734         CPLError( CE_Warning, CPLE_NotSupported,
735                   "FIT - color model YCC not supported - ignoring model");
736             return GCI_Undefined;
737 
738     case 13: // iflLuminanceAlpha - Luminance plus alpha
739         if (poFIT_DS->nBands != 2) {
740             CPLError( CE_Failure, CPLE_NotSupported,
741                       "FIT - color model LuminanceAlpha mismatch with "
742                       "%i bands",
743                       poFIT_DS->nBands);
744             return GCI_Undefined;
745         }
746         switch (nBand) {
747         case 1:
748             return GCI_GrayIndex;
749         case 2:
750             return GCI_AlphaBand;
751         default:
752             CPLError( CE_Failure, CPLE_NotSupported,
753                       "FIT - color model LuminanceAlpha unknown band %i",
754                       nBand);
755             return GCI_Undefined;
756         } // switch nBand
757 
758     default:
759         CPLError( CE_Warning, CPLE_NotSupported,
760                   "FIT - unrecognized color model %i - ignoring model",
761                   poFIT_DS->info->cm);
762         return GCI_Undefined;
763     } // switch
764 }
765 
766 /************************************************************************/
767 /*                             FITDataset()                             */
768 /************************************************************************/
769 
FITDataset()770 FITDataset::FITDataset() :
771     fp( nullptr ),
772     info( nullptr )
773 {
774     adfGeoTransform[0] = 0.0; // x origin (top left corner)
775     adfGeoTransform[1] = 1.0; // x pixel size
776     adfGeoTransform[2] = 0.0;
777     adfGeoTransform[3] = 0.0; // y origin (top left corner)
778     adfGeoTransform[4] = 0.0;
779     adfGeoTransform[5] = 1.0; // y pixel size
780 }
781 
782 /************************************************************************/
783 /*                             ~FITDataset()                             */
784 /************************************************************************/
785 
~FITDataset()786 FITDataset::~FITDataset()
787 {
788     FlushCache();
789     if( info )
790         delete(info);
791     if( fp )
792     {
793         if( VSIFCloseL(fp) != 0 )
794         {
795             CPLError(CE_Failure, CPLE_FileIO, "I/O error");
796         }
797     }
798 }
799 
800 // simple guard object to delete memory
801 // when the guard goes out of scope
802 template< class T >
803 class DeleteGuard
804 {
805 public:
DeleteGuard(T * p)806     explicit DeleteGuard( T *p ) : _ptr( p ) { }
~DeleteGuard()807     ~DeleteGuard()
808     {
809         delete _ptr;
810     }
811 
take()812     T *take()
813     {
814         T *tmp = _ptr;
815         _ptr = nullptr;
816         return tmp;
817     }
818 
819 private:
820     T *_ptr;
821     // prevent default copy constructor and assignment operator
822     DeleteGuard( const DeleteGuard & );
823     DeleteGuard &operator=( const DeleteGuard & );
824 };
825 
826 // simple guard object to free memory
827 // when the guard goes out of scope
828 template< class T >
829 class FreeGuard
830 {
831 public:
FreeGuard(T * p)832     explicit FreeGuard( T *p ) : _ptr( p ) { }
~FreeGuard()833     ~FreeGuard()
834     {
835         if ( _ptr )
836             free( _ptr );
837     }
838 
take()839     T *take()
840     {
841         T *tmp = _ptr;
842         _ptr = NULL;
843         return tmp;
844     }
845 
846 private:
847     T *_ptr;
848     // prevent default copy constructor and assignment operator
849     FreeGuard( const FreeGuard & );
850     FreeGuard &operator=( const FreeGuard & );
851 };
852 
853 /************************************************************************/
854 /*                                Open()                                */
855 /************************************************************************/
856 
Open(GDALOpenInfo * poOpenInfo)857 GDALDataset *FITDataset::Open( GDALOpenInfo * poOpenInfo )
858 {
859 /* -------------------------------------------------------------------- */
860 /*      First we check to see if the file has the expected header       */
861 /*      bytes.                                                          */
862 /* -------------------------------------------------------------------- */
863 
864     if( poOpenInfo->nHeaderBytes < 5 || poOpenInfo->fpL == nullptr)
865         return nullptr;
866 
867     if( !STARTS_WITH_CI((const char *) poOpenInfo->pabyHeader, "IT01") &&
868         !STARTS_WITH_CI((const char *) poOpenInfo->pabyHeader, "IT02") )
869         return nullptr;
870 
871     if( poOpenInfo->eAccess == GA_Update )
872     {
873         CPLError( CE_Failure, CPLE_NotSupported,
874                   "The FIT driver does not support update access to existing"
875                   " files.\n" );
876         return nullptr;
877     }
878 
879 /* -------------------------------------------------------------------- */
880 /*      Create a corresponding GDALDataset.                             */
881 /* -------------------------------------------------------------------- */
882     FITDataset *poDS = new FITDataset();
883     DeleteGuard<FITDataset> guard( poDS );
884     poDS->eAccess = poOpenInfo->eAccess;
885     poDS->fp = poOpenInfo->fpL;
886     poOpenInfo->fpL = nullptr;
887 
888     poDS->info = new FITinfo;
889     FITinfo *info = poDS->info;
890 
891 /* -------------------------------------------------------------------- */
892 /*      Read other header values.                                       */
893 /* -------------------------------------------------------------------- */
894     FIThead02 *head = (FIThead02 *) poOpenInfo->pabyHeader;
895 
896     // extract the image attributes from the file header
897     if (STARTS_WITH_CI((const char *) &head->version, "02")) {
898         // incomplete header
899         if( poOpenInfo->nHeaderBytes < (signed) sizeof(FIThead02) )
900             return nullptr;
901 
902         CPLDebug("FIT", "Loading file with header version 02");
903 
904         gst_swapb(head->minValue);
905         info->minValue = head->minValue;
906         gst_swapb(head->maxValue);
907         info->maxValue = head->maxValue;
908         gst_swapb(head->dataOffset);
909         info->dataOffset = head->dataOffset;
910 
911         info->userOffset = sizeof(FIThead02);
912     }
913     else if (STARTS_WITH_CI((const char *) &head->version, "01")) {
914         // incomplete header
915         if( poOpenInfo->nHeaderBytes < (signed) sizeof(FIThead01) )
916             return nullptr;
917 
918         CPLDebug("FIT", "Loading file with header version 01");
919 
920         // map old style header into new header structure
921         FIThead01* head01 = (FIThead01*)head;
922         gst_swapb(head->dataOffset);
923         info->dataOffset = head01->dataOffset;
924 
925         info->userOffset = sizeof(FIThead01);
926     }
927     else {
928         // unrecognized header version
929         CPLError( CE_Failure, CPLE_NotSupported,
930                   "FIT - unsupported header version %.2s\n",
931                   (const char*) &head->version);
932         return nullptr;
933     }
934 
935     CPLDebug("FIT", "userOffset %i, dataOffset %i",
936              info->userOffset, info->dataOffset);
937 
938     info->magic = head->magic;
939     info->version = head->version;
940 
941     gst_swapb(head->xSize);
942     info->xSize = head->xSize;
943     gst_swapb(head->ySize);
944     info->ySize = head->ySize;
945     gst_swapb(head->zSize);
946     info->zSize = head->zSize;
947     gst_swapb(head->cSize);
948     info->cSize = head->cSize;
949     gst_swapb(head->dtype);
950     info->dtype = head->dtype;
951     gst_swapb(head->order);
952     info->order = head->order;
953     gst_swapb(head->space);
954     info->space = head->space;
955     gst_swapb(head->cm);
956     info->cm = head->cm;
957     gst_swapb(head->xPageSize);
958     info->xPageSize = head->xPageSize;
959     gst_swapb(head->yPageSize);
960     info->yPageSize = head->yPageSize;
961     gst_swapb(head->zPageSize);
962     info->zPageSize = head->zPageSize;
963     gst_swapb(head->cPageSize);
964     info->cPageSize = head->cPageSize;
965 
966     CPLDebug("FIT", "size %i %i %i %i, pageSize %i %i %i %i",
967              info->xSize, info->ySize, info->zSize, info->cSize,
968              info->xPageSize, info->yPageSize, info->zPageSize,
969              info->cPageSize);
970 
971     CPLDebug("FIT", "dtype %i order %i space %i cm %i",
972              info->dtype, info->order, info->space, info->cm);
973 
974     /**************************/
975 
976     poDS->nRasterXSize = head->xSize;
977     poDS->nRasterYSize = head->ySize;
978 
979     if (!GDALCheckDatasetDimensions(poDS->nRasterXSize, poDS->nRasterYSize) ||
980         !GDALCheckBandCount(head->cSize, FALSE) ||
981         head->xPageSize == 0 ||
982         head->yPageSize == 0)
983     {
984         return nullptr;
985     }
986 
987 /* -------------------------------------------------------------------- */
988 /*      Verify all "unused" header values.                              */
989 /* -------------------------------------------------------------------- */
990 
991     if( info->zSize != 1 )
992     {
993         CPLError( CE_Failure, CPLE_NotSupported,
994                   "FIT driver - unsupported zSize %i\n", info->zSize);
995         return nullptr;
996     }
997 
998     if( info->order != 1 ) // interleaved - RGBRGB
999     {
1000         CPLError( CE_Failure, CPLE_NotSupported,
1001                   "FIT driver - unsupported order %i\n", info->order);
1002         return nullptr;
1003     }
1004 
1005     if( info->zPageSize != 1 )
1006     {
1007         CPLError( CE_Failure, CPLE_NotSupported,
1008                   "FIT driver - unsupported zPageSize %i\n", info->zPageSize);
1009         return nullptr;
1010     }
1011 
1012     if( info->cPageSize != info->cSize )
1013     {
1014         CPLError( CE_Failure, CPLE_NotSupported,
1015                   "FIT driver - unsupported cPageSize %i (!= %i)\n",
1016                   info->cPageSize, info->cSize);
1017         return nullptr;
1018     }
1019 
1020 /* -------------------------------------------------------------------- */
1021 /*      Create band information objects.                                */
1022 /* -------------------------------------------------------------------- */
1023     // Verified by above GDALCheckBandCount()
1024     // coverity[tainted_data]
1025     for( int i = 0; i < (int)head->cSize; i++ )
1026     {
1027         FITRasterBand* poBand = new FITRasterBand( poDS, i+1, (int)head->cSize );
1028         poDS->SetBand( i+1,  poBand);
1029         if( poBand->tmpImage == nullptr )
1030             return nullptr;
1031     }
1032 
1033 /* -------------------------------------------------------------------- */
1034 /*      Initialize any PAM information.                                 */
1035 /* -------------------------------------------------------------------- */
1036     poDS->SetDescription( poOpenInfo->pszFilename );
1037     poDS->TryLoadXML();
1038 
1039 /* -------------------------------------------------------------------- */
1040 /*      Check for external overviews.                                   */
1041 /* -------------------------------------------------------------------- */
1042     poDS->oOvManager.Initialize( poDS, poOpenInfo->pszFilename, poOpenInfo->GetSiblingFiles() );
1043 
1044     return guard.take();
1045 }
1046 
1047 /************************************************************************/
1048 /*                           FITCreateCopy()                            */
1049 /************************************************************************/
1050 
FITCreateCopy(const char * pszFilename,GDALDataset * poSrcDS,int bStrict,char ** papszOptions,GDALProgressFunc pfnProgress,void * pProgressData)1051 static GDALDataset *FITCreateCopy(const char * pszFilename,
1052                                   GDALDataset *poSrcDS,
1053                                   int bStrict, char ** papszOptions,
1054                                   GDALProgressFunc pfnProgress,
1055                                   void * pProgressData )
1056 {
1057     CPLDebug("FIT", "CreateCopy %s - %i", pszFilename, bStrict);
1058 
1059     int nBands = poSrcDS->GetRasterCount();
1060     if (nBands == 0)
1061     {
1062         CPLError( CE_Failure, CPLE_NotSupported,
1063                   "FIT driver does not support source dataset with zero band.\n");
1064         return nullptr;
1065     }
1066 
1067 /* -------------------------------------------------------------------- */
1068 /*      Create the dataset.                                             */
1069 /* -------------------------------------------------------------------- */
1070     if( !pfnProgress( 0.0, nullptr, pProgressData ) )
1071     {
1072         CPLError( CE_Failure, CPLE_UserInterrupt, "User terminated" );
1073         return nullptr;
1074     }
1075 
1076     VSILFILE *fpImage = VSIFOpenL( pszFilename, "wb" );
1077     if( fpImage == nullptr )
1078     {
1079         CPLError( CE_Failure, CPLE_OpenFailed,
1080                   "FIT - unable to create file %s.\n",
1081                   pszFilename );
1082         return nullptr;
1083     }
1084 
1085 /* -------------------------------------------------------------------- */
1086 /*      Generate header.                                                */
1087 /* -------------------------------------------------------------------- */
1088     // XXX - should FIT_PAGE_SIZE be based on file page size ??
1089 
1090     const size_t size = std::max(sizeof(FIThead02), FIT_PAGE_SIZE);
1091     FIThead02 *head = (FIThead02 *) malloc(size);
1092     FreeGuard<FIThead02> guardHead( head );
1093 
1094     // clean header so padding (past real header) is all zeros
1095     memset( head, 0, size );
1096 
1097     memcpy((char *) &head->magic, "IT", 2);
1098     memcpy((char *) &head->version, "02", 2);
1099 
1100     head->xSize = poSrcDS->GetRasterXSize();
1101     gst_swapb(head->xSize);
1102     head->ySize = poSrcDS->GetRasterYSize();
1103     gst_swapb(head->ySize);
1104     head->zSize = 1;
1105     gst_swapb(head->zSize);
1106 
1107     head->cSize = nBands;
1108     gst_swapb(head->cSize);
1109 
1110     GDALRasterBand *firstBand = poSrcDS->GetRasterBand(1);
1111     if (! firstBand) {
1112         CPL_IGNORE_RET_VAL(VSIFCloseL(fpImage));
1113         return nullptr;
1114     }
1115 
1116     head->dtype = fitGetDataType(firstBand->GetRasterDataType());
1117     if (! head->dtype) {
1118         CPL_IGNORE_RET_VAL(VSIFCloseL(fpImage));
1119         return nullptr;
1120     }
1121     gst_swapb(head->dtype);
1122     head->order = 1; // interleaved - RGBRGB
1123     gst_swapb(head->order);
1124     head->space = 1; // upper left
1125     gst_swapb(head->space);
1126 
1127     // XXX - need to check all bands
1128     head->cm = fitGetColorModel(firstBand->GetColorInterpretation(), nBands);
1129     gst_swapb(head->cm);
1130 
1131     int blockX, blockY;
1132     firstBand->GetBlockSize(&blockX, &blockY);
1133     blockX = std::min(blockX, poSrcDS->GetRasterXSize());
1134     blockY = std::min(blockY, poSrcDS->GetRasterYSize());
1135     int nDTSize = GDALGetDataTypeSizeBytes(firstBand->GetRasterDataType());
1136     try
1137     {
1138         CPL_IGNORE_RET_VAL(
1139             CPLSM(blockX) * CPLSM(blockY) * CPLSM(nDTSize) * CPLSM(nBands));
1140         CPLDebug("FIT write", "inherited block size %ix%i", blockX, blockY);
1141     }
1142     catch( ... )
1143     {
1144         blockX = std::min(256, poSrcDS->GetRasterXSize());
1145         blockY = std::min(256, poSrcDS->GetRasterYSize());
1146     }
1147 
1148     if( CSLFetchNameValue(papszOptions,"PAGESIZE") != nullptr )
1149     {
1150         const char *str = CSLFetchNameValue(papszOptions,"PAGESIZE");
1151         int newBlockX, newBlockY;
1152         sscanf(str, "%i,%i", &newBlockX, &newBlockY);
1153         if (newBlockX > 0 && newBlockY > 0) {
1154             blockX = newBlockX;
1155             blockY = newBlockY;
1156             try
1157             {
1158                 CPL_IGNORE_RET_VAL(
1159                     CPLSM(blockX) * CPLSM(blockY) * CPLSM(nDTSize) * CPLSM(nBands));
1160             }
1161             catch( ... )
1162             {
1163                 CPLError(CE_Failure, CPLE_AppDefined,
1164                          "Too big values in PAGESIZE");
1165                 CPL_IGNORE_RET_VAL(VSIFCloseL(fpImage));
1166                 return nullptr;
1167             }
1168         }
1169         else {
1170             CPLError(CE_Failure, CPLE_OpenFailed,
1171                      "FIT - Unable to parse option PAGESIZE values [%s]", str);
1172         }
1173     }
1174 
1175     // XXX - need to do lots of checking of block size
1176     // * provide ability to override block size with options
1177     // * handle non-square block size (like scanline)
1178     //   - probably default from non-tiled image - have default block size
1179     // * handle block size bigger than image size
1180     // * undesirable block size (non power of 2, others?)
1181     // * mismatched block sizes for different bands
1182     // * image that isn't even pages (i.e. partially empty pages at edge)
1183     CPLDebug("FIT write", "using block size %ix%i", blockX, blockY);
1184 
1185     head->xPageSize = blockX;
1186     gst_swapb(head->xPageSize);
1187     head->yPageSize = blockY;
1188     gst_swapb(head->yPageSize);
1189     head->zPageSize = 1;
1190     gst_swapb(head->zPageSize);
1191     head->cPageSize = nBands;
1192     gst_swapb(head->cPageSize);
1193 
1194     // XXX - need to check all bands
1195     head->minValue = firstBand->GetMinimum();
1196     gst_swapb(head->minValue);
1197     // XXX - need to check all bands
1198     head->maxValue = firstBand->GetMaximum();
1199     gst_swapb(head->maxValue);
1200     head->dataOffset = static_cast<unsigned int>(size);
1201     gst_swapb(head->dataOffset);
1202 
1203     CPL_IGNORE_RET_VAL(VSIFWriteL(head, size, 1, fpImage));
1204 
1205 /* -------------------------------------------------------------------- */
1206 /*      Loop over image, copying image data.                            */
1207 /* -------------------------------------------------------------------- */
1208     unsigned long bytesPerPixel = nBands * nDTSize;
1209 
1210     size_t pageBytes = blockX * blockY * bytesPerPixel;
1211     char *output = (char *) calloc(1, pageBytes);
1212     if (! output)
1213     {
1214         CPLError(CE_Failure, CPLE_OutOfMemory,
1215                  "FITRasterBand couldn't allocate %lu bytes",
1216                  static_cast<unsigned long>(pageBytes));
1217         CPL_IGNORE_RET_VAL(VSIFCloseL(fpImage));
1218         return nullptr;
1219     }
1220     FreeGuard<char> guardOutput( output );
1221 
1222     long maxx = (long) ceil(poSrcDS->GetRasterXSize() / (double) blockX);
1223     long maxy = (long) ceil(poSrcDS->GetRasterYSize() / (double) blockY);
1224     long maxx_full = (long) floor(poSrcDS->GetRasterXSize() / (double) blockX);
1225     long maxy_full = (long) floor(poSrcDS->GetRasterYSize() / (double) blockY);
1226 
1227     CPLDebug("FIT", "about to write %ld x %ld blocks", maxx, maxy);
1228 
1229     for(long y=0; y < maxy; y++)
1230         for(long x=0; x < maxx; x++) {
1231             long readX = blockX;
1232             long readY = blockY;
1233             int do_clean = FALSE;
1234 
1235             // handle cases where image size isn't an exact multiple
1236             // of page size
1237             if (x >= maxx_full) {
1238                 readX = poSrcDS->GetRasterXSize() % blockX;
1239                 do_clean = TRUE;
1240             }
1241             if (y >= maxy_full) {
1242                 readY = poSrcDS->GetRasterYSize() % blockY;
1243                 do_clean = TRUE;
1244             }
1245 
1246             // clean out image if only doing partial reads
1247             if (do_clean)
1248                 memset( output, 0, pageBytes );
1249 
1250             for( int iBand = 0; iBand < nBands; iBand++ ) {
1251                 GDALRasterBand * poBand = poSrcDS->GetRasterBand( iBand+1 );
1252                 CPLErr eErr =
1253                     poBand->RasterIO( GF_Read, // eRWFlag
1254                                       static_cast<int>(x * blockX), // nXOff
1255                                       static_cast<int>(y * blockY), // nYOff
1256                                       static_cast<int>(readX), // nXSize
1257                                       static_cast<int>(readY), // nYSize
1258                                       output + iBand * nDTSize,
1259                                       // pData
1260                                       blockX, // nBufXSize
1261                                       blockY, // nBufYSize
1262                                       firstBand->GetRasterDataType(),
1263                                       // eBufType
1264                                       bytesPerPixel, // nPixelSpace
1265                                       bytesPerPixel * blockX, nullptr); // nLineSpace
1266                 if (eErr != CE_None)
1267                 {
1268                     CPLError(CE_Failure, CPLE_FileIO,
1269                              "FIT write - CreateCopy got read error %i", eErr);
1270                     CPL_IGNORE_RET_VAL(VSIFCloseL( fpImage ));
1271                     VSIUnlink( pszFilename );
1272                     return nullptr;
1273                 }
1274             } // for iBand
1275 
1276 #ifdef swapping
1277             char *p = output;
1278             unsigned long i;
1279             switch(nDTSize) {
1280             case 1:
1281                 // do nothing
1282                 break;
1283             case 2:
1284                 for(i=0; i < pageBytes; i+= nDTSize)
1285                     gst_swap16(p + i);
1286                 break;
1287             case 4:
1288                 for(i=0; i < pageBytes; i+= nDTSize)
1289                     gst_swap32(p + i);
1290                 break;
1291             case 8:
1292                 for(i=0; i < pageBytes; i+= nDTSize)
1293                     gst_swap64(p + i);
1294                 break;
1295             default:
1296                 CPLError(CE_Failure, CPLE_NotSupported,
1297                          "FIT write - unsupported bytesPerPixel %d",
1298                          nDTSize);
1299             } // switch
1300 #endif // swapping
1301 
1302             if( VSIFWriteL(output, 1, pageBytes, fpImage) != pageBytes )
1303             {
1304                 CPLError( CE_Failure, CPLE_FileIO, "Write failed" );
1305                 CPL_IGNORE_RET_VAL(VSIFCloseL( fpImage ));
1306                 VSIUnlink( pszFilename );
1307                 return nullptr;
1308             }
1309 
1310             double perc = ((double) (y * maxx + x)) / (maxx * maxy);
1311             if( !pfnProgress( perc, nullptr, pProgressData ) )
1312             {
1313                 CPLError( CE_Failure, CPLE_UserInterrupt, "User terminated" );
1314                 //free(output);
1315                 CPL_IGNORE_RET_VAL(VSIFCloseL( fpImage ));
1316                 VSIUnlink( pszFilename );
1317                 return nullptr;
1318             }
1319         } // for x
1320 
1321     //free(output);
1322 
1323     CPL_IGNORE_RET_VAL(VSIFCloseL( fpImage ));
1324 
1325     pfnProgress( 1.0, nullptr, pProgressData );
1326 
1327 /* -------------------------------------------------------------------- */
1328 /*      Re-open dataset, and copy any auxiliary pam information.         */
1329 /* -------------------------------------------------------------------- */
1330     GDALPamDataset *poDS = (GDALPamDataset *)
1331         GDALOpen( pszFilename, GA_ReadOnly );
1332 
1333     if( poDS )
1334         poDS->CloneInfo( poSrcDS, GCIF_PAM_DEFAULT );
1335 
1336     return poDS;
1337 }
1338 
1339 /************************************************************************/
1340 /*                           GetGeoTransform()                          */
1341 /************************************************************************/
1342 
1343 // CPLErr FITDataset::GetGeoTransform( double * padfTransform )
1344 // {
1345 //     CPLDebug("FIT", "FITDataset::GetGeoTransform");
1346 //     memcpy( padfTransform, adfGeoTransform, sizeof(double) * 6 );
1347 //     return CE_None;
1348 // }
1349 
1350 /************************************************************************/
1351 /*                          GDALRegister_FIT()                          */
1352 /************************************************************************/
1353 
GDALRegister_FIT()1354 void GDALRegister_FIT()
1355 
1356 {
1357     if( GDALGetDriverByName( "FIT" ) != nullptr )
1358         return;
1359 
1360     GDALDriver *poDriver = new GDALDriver();
1361 
1362     poDriver->SetDescription( "FIT" );
1363     poDriver->SetMetadataItem( GDAL_DCAP_RASTER, "YES" );
1364     poDriver->SetMetadataItem( GDAL_DMD_LONGNAME, "FIT Image" );
1365     poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC, "drivers/raster/fit.html" );
1366     poDriver->SetMetadataItem( GDAL_DMD_EXTENSION, "" );
1367     poDriver->SetMetadataItem( GDAL_DCAP_VIRTUALIO, "YES" );
1368 
1369     poDriver->pfnOpen = FITDataset::Open;
1370     poDriver->pfnCreateCopy = FITCreateCopy;
1371     poDriver->SetMetadataItem( GDAL_DMD_CREATIONDATATYPES,
1372                                "Byte UInt16 Int16 UInt32 Int32 "
1373                                "Float32 Float64" );
1374 
1375     GetGDALDriverManager()->RegisterDriver( poDriver );
1376 }
1377