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