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 33246 : 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 33246 : if (poOpenInfo->nHeaderBytes < 5 || poOpenInfo->fpL == nullptr)
831 28768 : return nullptr;
832 :
833 4478 : if (!STARTS_WITH_CI((const char *)poOpenInfo->pabyHeader, "IT01") &&
834 4478 : !STARTS_WITH_CI((const char *)poOpenInfo->pabyHeader, "IT02"))
835 4453 : return nullptr;
836 :
837 25 : if (poOpenInfo->eAccess == GA_Update)
838 : {
839 0 : ReportUpdateNotSupportedByDriver("FIT");
840 0 : return nullptr;
841 : }
842 :
843 : /* -------------------------------------------------------------------- */
844 : /* Create a corresponding GDALDataset. */
845 : /* -------------------------------------------------------------------- */
846 50 : auto poDS = std::make_unique<FITDataset>();
847 25 : poDS->eAccess = poOpenInfo->eAccess;
848 25 : poDS->fp = poOpenInfo->fpL;
849 25 : poOpenInfo->fpL = nullptr;
850 :
851 25 : poDS->info = new FITinfo;
852 25 : FITinfo *info = poDS->info;
853 :
854 : /* -------------------------------------------------------------------- */
855 : /* Read other header values. */
856 : /* -------------------------------------------------------------------- */
857 25 : FIThead02 *head = (FIThead02 *)poOpenInfo->pabyHeader;
858 :
859 : // extract the image attributes from the file header
860 25 : if (STARTS_WITH_CI((const char *)&head->version, "02"))
861 : {
862 : // incomplete header
863 25 : if (poOpenInfo->nHeaderBytes < (signed)sizeof(FIThead02))
864 0 : return nullptr;
865 :
866 25 : CPLDebug("FIT", "Loading file with header version 02");
867 :
868 25 : gst_swapb(head->minValue);
869 25 : info->minValue = head->minValue;
870 25 : gst_swapb(head->maxValue);
871 25 : info->maxValue = head->maxValue;
872 25 : gst_swapb(head->dataOffset);
873 25 : info->dataOffset = head->dataOffset;
874 :
875 25 : info->userOffset = sizeof(FIThead02);
876 : }
877 0 : else if (STARTS_WITH_CI((const char *)&head->version, "01"))
878 : {
879 : // incomplete header
880 0 : if (poOpenInfo->nHeaderBytes < (signed)sizeof(FIThead01))
881 0 : return nullptr;
882 :
883 0 : CPLDebug("FIT", "Loading file with header version 01");
884 :
885 : // map old style header into new header structure
886 0 : FIThead01 *head01 = (FIThead01 *)head;
887 0 : gst_swapb(head->dataOffset);
888 0 : info->dataOffset = head01->dataOffset;
889 :
890 0 : info->userOffset = sizeof(FIThead01);
891 : }
892 : else
893 : {
894 : // unrecognized header version
895 0 : CPLError(CE_Failure, CPLE_NotSupported,
896 : "FIT - unsupported header version %.2s\n",
897 0 : (const char *)&head->version);
898 0 : return nullptr;
899 : }
900 :
901 25 : CPLDebug("FIT", "userOffset %i, dataOffset %i", info->userOffset,
902 : info->dataOffset);
903 :
904 25 : info->magic = head->magic;
905 25 : info->version = head->version;
906 :
907 25 : gst_swapb(head->xSize);
908 25 : info->xSize = head->xSize;
909 25 : gst_swapb(head->ySize);
910 25 : info->ySize = head->ySize;
911 25 : gst_swapb(head->zSize);
912 25 : info->zSize = head->zSize;
913 25 : gst_swapb(head->cSize);
914 25 : info->cSize = head->cSize;
915 25 : gst_swapb(head->dtype);
916 25 : info->dtype = head->dtype;
917 25 : gst_swapb(head->order);
918 25 : info->order = head->order;
919 25 : gst_swapb(head->space);
920 25 : info->space = head->space;
921 25 : gst_swapb(head->cm);
922 25 : info->cm = head->cm;
923 25 : gst_swapb(head->xPageSize);
924 25 : info->xPageSize = head->xPageSize;
925 25 : gst_swapb(head->yPageSize);
926 25 : info->yPageSize = head->yPageSize;
927 25 : gst_swapb(head->zPageSize);
928 25 : info->zPageSize = head->zPageSize;
929 25 : gst_swapb(head->cPageSize);
930 25 : info->cPageSize = head->cPageSize;
931 :
932 25 : CPLDebug("FIT", "size %i %i %i %i, pageSize %i %i %i %i", info->xSize,
933 : info->ySize, info->zSize, info->cSize, info->xPageSize,
934 : info->yPageSize, info->zPageSize, info->cPageSize);
935 :
936 25 : CPLDebug("FIT", "dtype %i order %i space %i cm %i", info->dtype,
937 : info->order, info->space, info->cm);
938 :
939 : /**************************/
940 :
941 25 : poDS->nRasterXSize = head->xSize;
942 25 : poDS->nRasterYSize = head->ySize;
943 :
944 25 : if (!GDALCheckDatasetDimensions(poDS->nRasterXSize, poDS->nRasterYSize) ||
945 50 : !GDALCheckBandCount(head->cSize, FALSE) || head->xPageSize == 0 ||
946 25 : head->yPageSize == 0)
947 : {
948 0 : return nullptr;
949 : }
950 :
951 : /* -------------------------------------------------------------------- */
952 : /* Verify all "unused" header values. */
953 : /* -------------------------------------------------------------------- */
954 :
955 25 : if (info->zSize != 1)
956 : {
957 0 : CPLError(CE_Failure, CPLE_NotSupported,
958 : "FIT driver - unsupported zSize %i\n", info->zSize);
959 0 : return nullptr;
960 : }
961 :
962 25 : if (info->order != 1) // interleaved - RGBRGB
963 : {
964 0 : CPLError(CE_Failure, CPLE_NotSupported,
965 : "FIT driver - unsupported order %i\n", info->order);
966 0 : return nullptr;
967 : }
968 :
969 25 : if (info->zPageSize != 1)
970 : {
971 0 : CPLError(CE_Failure, CPLE_NotSupported,
972 : "FIT driver - unsupported zPageSize %i\n", info->zPageSize);
973 0 : return nullptr;
974 : }
975 :
976 25 : if (info->cPageSize != info->cSize)
977 : {
978 0 : CPLError(CE_Failure, CPLE_NotSupported,
979 : "FIT driver - unsupported cPageSize %i (!= %i)\n",
980 : info->cPageSize, info->cSize);
981 0 : return nullptr;
982 : }
983 :
984 : /* -------------------------------------------------------------------- */
985 : /* Create band information objects. */
986 : /* -------------------------------------------------------------------- */
987 : // Verified by above GDALCheckBandCount()
988 : // coverity[tainted_data]
989 60 : for (int i = 0; i < (int)head->cSize; i++)
990 : {
991 : FITRasterBand *poBand =
992 35 : new FITRasterBand(poDS.get(), i + 1, (int)head->cSize);
993 35 : poDS->SetBand(i + 1, poBand);
994 35 : if (poBand->tmpImage == nullptr)
995 0 : return nullptr;
996 : }
997 :
998 : /* -------------------------------------------------------------------- */
999 : /* Initialize any PAM information. */
1000 : /* -------------------------------------------------------------------- */
1001 25 : poDS->SetDescription(poOpenInfo->pszFilename);
1002 25 : poDS->TryLoadXML();
1003 :
1004 : /* -------------------------------------------------------------------- */
1005 : /* Check for external overviews. */
1006 : /* -------------------------------------------------------------------- */
1007 50 : poDS->oOvManager.Initialize(poDS.get(), poOpenInfo->pszFilename,
1008 25 : poOpenInfo->GetSiblingFiles());
1009 :
1010 25 : return poDS.release();
1011 : }
1012 :
1013 : /************************************************************************/
1014 : /* FITCreateCopy() */
1015 : /************************************************************************/
1016 :
1017 35 : static GDALDataset *FITCreateCopy(const char *pszFilename, GDALDataset *poSrcDS,
1018 : int bStrict, char **papszOptions,
1019 : GDALProgressFunc pfnProgress,
1020 : void *pProgressData)
1021 : {
1022 35 : CPLDebug("FIT", "CreateCopy %s - %i", pszFilename, bStrict);
1023 :
1024 35 : int nBands = poSrcDS->GetRasterCount();
1025 35 : if (nBands == 0)
1026 : {
1027 1 : CPLError(
1028 : CE_Failure, CPLE_NotSupported,
1029 : "FIT driver does not support source dataset with zero band.\n");
1030 1 : return nullptr;
1031 : }
1032 :
1033 : /* -------------------------------------------------------------------- */
1034 : /* Create the dataset. */
1035 : /* -------------------------------------------------------------------- */
1036 34 : if (!pfnProgress(0.0, nullptr, pProgressData))
1037 : {
1038 0 : CPLError(CE_Failure, CPLE_UserInterrupt, "User terminated");
1039 0 : return nullptr;
1040 : }
1041 :
1042 34 : VSILFILE *fpImage = VSIFOpenL(pszFilename, "wb");
1043 34 : if (fpImage == nullptr)
1044 : {
1045 2 : CPLError(CE_Failure, CPLE_OpenFailed,
1046 : "FIT - unable to create file %s.\n", pszFilename);
1047 2 : return nullptr;
1048 : }
1049 :
1050 : /* -------------------------------------------------------------------- */
1051 : /* Generate header. */
1052 : /* -------------------------------------------------------------------- */
1053 : // XXX - should FIT_PAGE_SIZE be based on file page size ??
1054 :
1055 32 : const size_t size = std::max(sizeof(FIThead02), FIT_PAGE_SIZE);
1056 64 : std::vector<GByte> abyHeader;
1057 32 : abyHeader.resize(size);
1058 32 : FIThead02 *head = reinterpret_cast<FIThead02 *>(abyHeader.data());
1059 :
1060 : // clean header so padding (past real header) is all zeros
1061 32 : memset(head, 0, size);
1062 :
1063 32 : memcpy((char *)&head->magic, "IT", 2);
1064 32 : memcpy((char *)&head->version, "02", 2);
1065 :
1066 32 : head->xSize = poSrcDS->GetRasterXSize();
1067 32 : gst_swapb(head->xSize);
1068 32 : head->ySize = poSrcDS->GetRasterYSize();
1069 32 : gst_swapb(head->ySize);
1070 32 : head->zSize = 1;
1071 32 : gst_swapb(head->zSize);
1072 :
1073 32 : head->cSize = nBands;
1074 32 : gst_swapb(head->cSize);
1075 :
1076 32 : GDALRasterBand *firstBand = poSrcDS->GetRasterBand(1);
1077 32 : if (!firstBand)
1078 : {
1079 0 : CPL_IGNORE_RET_VAL(VSIFCloseL(fpImage));
1080 0 : return nullptr;
1081 : }
1082 :
1083 32 : head->dtype = fitGetDataType(firstBand->GetRasterDataType());
1084 32 : if (!head->dtype)
1085 : {
1086 4 : CPL_IGNORE_RET_VAL(VSIFCloseL(fpImage));
1087 4 : return nullptr;
1088 : }
1089 28 : gst_swapb(head->dtype);
1090 28 : head->order = 1; // interleaved - RGBRGB
1091 28 : gst_swapb(head->order);
1092 28 : head->space = 1; // upper left
1093 28 : gst_swapb(head->space);
1094 :
1095 : // XXX - need to check all bands
1096 28 : head->cm = fitGetColorModel(firstBand->GetColorInterpretation(), nBands);
1097 28 : gst_swapb(head->cm);
1098 :
1099 : int blockX, blockY;
1100 28 : firstBand->GetBlockSize(&blockX, &blockY);
1101 28 : blockX = std::min(blockX, poSrcDS->GetRasterXSize());
1102 28 : blockY = std::min(blockY, poSrcDS->GetRasterYSize());
1103 28 : int nDTSize = GDALGetDataTypeSizeBytes(firstBand->GetRasterDataType());
1104 : try
1105 : {
1106 56 : CPL_IGNORE_RET_VAL(CPLSM(blockX) * CPLSM(blockY) * CPLSM(nDTSize) *
1107 56 : CPLSM(nBands));
1108 28 : CPLDebug("FIT write", "inherited block size %ix%i", blockX, blockY);
1109 : }
1110 0 : catch (...)
1111 : {
1112 0 : blockX = std::min(256, poSrcDS->GetRasterXSize());
1113 0 : blockY = std::min(256, poSrcDS->GetRasterYSize());
1114 : }
1115 :
1116 28 : if (CSLFetchNameValue(papszOptions, "PAGESIZE") != nullptr)
1117 : {
1118 7 : const char *str = CSLFetchNameValue(papszOptions, "PAGESIZE");
1119 : int newBlockX, newBlockY;
1120 7 : sscanf(str, "%i,%i", &newBlockX, &newBlockY);
1121 7 : if (newBlockX > 0 && newBlockY > 0)
1122 : {
1123 7 : blockX = newBlockX;
1124 7 : blockY = newBlockY;
1125 7 : try
1126 : {
1127 14 : CPL_IGNORE_RET_VAL(CPLSM(blockX) * CPLSM(blockY) *
1128 21 : CPLSM(nDTSize) * CPLSM(nBands));
1129 : }
1130 0 : catch (...)
1131 : {
1132 0 : CPLError(CE_Failure, CPLE_AppDefined,
1133 : "Too big values in PAGESIZE");
1134 0 : CPL_IGNORE_RET_VAL(VSIFCloseL(fpImage));
1135 0 : return nullptr;
1136 : }
1137 : }
1138 : else
1139 : {
1140 0 : CPLError(CE_Failure, CPLE_OpenFailed,
1141 : "FIT - Unable to parse option PAGESIZE values [%s]", str);
1142 : }
1143 : }
1144 :
1145 : // XXX - need to do lots of checking of block size
1146 : // * provide ability to override block size with options
1147 : // * handle non-square block size (like scanline)
1148 : // - probably default from non-tiled image - have default block size
1149 : // * handle block size bigger than image size
1150 : // * undesirable block size (non power of 2, others?)
1151 : // * mismatched block sizes for different bands
1152 : // * image that isn't even pages (i.e. partially empty pages at edge)
1153 28 : CPLDebug("FIT write", "using block size %ix%i", blockX, blockY);
1154 :
1155 28 : head->xPageSize = blockX;
1156 28 : gst_swapb(head->xPageSize);
1157 28 : head->yPageSize = blockY;
1158 28 : gst_swapb(head->yPageSize);
1159 28 : head->zPageSize = 1;
1160 28 : gst_swapb(head->zPageSize);
1161 28 : head->cPageSize = nBands;
1162 28 : gst_swapb(head->cPageSize);
1163 :
1164 : // XXX - need to check all bands
1165 28 : head->minValue = firstBand->GetMinimum();
1166 28 : gst_swapb(head->minValue);
1167 : // XXX - need to check all bands
1168 28 : head->maxValue = firstBand->GetMaximum();
1169 28 : gst_swapb(head->maxValue);
1170 28 : head->dataOffset = static_cast<unsigned int>(size);
1171 28 : gst_swapb(head->dataOffset);
1172 :
1173 28 : CPL_IGNORE_RET_VAL(VSIFWriteL(head, size, 1, fpImage));
1174 :
1175 : /* -------------------------------------------------------------------- */
1176 : /* Loop over image, copying image data. */
1177 : /* -------------------------------------------------------------------- */
1178 28 : const size_t bytesPerPixel = static_cast<size_t>(nBands) * nDTSize;
1179 :
1180 28 : const size_t pageBytes =
1181 28 : static_cast<size_t>(blockX) * blockY * bytesPerPixel;
1182 56 : std::vector<GByte> output;
1183 : try
1184 : {
1185 28 : output.resize(pageBytes);
1186 : }
1187 0 : catch (const std::bad_alloc &)
1188 : {
1189 0 : CPLError(CE_Failure, CPLE_OutOfMemory,
1190 : "FITRasterBand couldn't allocate %lu bytes",
1191 : static_cast<unsigned long>(pageBytes));
1192 0 : CPL_IGNORE_RET_VAL(VSIFCloseL(fpImage));
1193 0 : return nullptr;
1194 : }
1195 :
1196 28 : long maxx = (long)ceil(poSrcDS->GetRasterXSize() / (double)blockX);
1197 28 : long maxy = (long)ceil(poSrcDS->GetRasterYSize() / (double)blockY);
1198 28 : long maxx_full = (long)floor(poSrcDS->GetRasterXSize() / (double)blockX);
1199 28 : long maxy_full = (long)floor(poSrcDS->GetRasterYSize() / (double)blockY);
1200 :
1201 28 : CPLDebug("FIT", "about to write %ld x %ld blocks", maxx, maxy);
1202 :
1203 254 : for (long y = 0; y < maxy; y++)
1204 1091 : for (long x = 0; x < maxx; x++)
1205 : {
1206 865 : long readX = blockX;
1207 865 : long readY = blockY;
1208 865 : int do_clean = FALSE;
1209 :
1210 : // handle cases where image size isn't an exact multiple
1211 : // of page size
1212 865 : if (x >= maxx_full)
1213 : {
1214 0 : readX = poSrcDS->GetRasterXSize() % blockX;
1215 0 : do_clean = TRUE;
1216 : }
1217 865 : if (y >= maxy_full)
1218 : {
1219 0 : readY = poSrcDS->GetRasterYSize() % blockY;
1220 0 : do_clean = TRUE;
1221 : }
1222 :
1223 : // clean out image if only doing partial reads
1224 865 : if (do_clean)
1225 0 : memset(output.data(), 0, pageBytes);
1226 :
1227 1830 : for (int iBand = 0; iBand < nBands; iBand++)
1228 : {
1229 965 : GDALRasterBand *poBand = poSrcDS->GetRasterBand(iBand + 1);
1230 3860 : CPLErr eErr = poBand->RasterIO(
1231 : GF_Read, // eRWFlag
1232 : static_cast<int>(x * blockX), // nXOff
1233 : static_cast<int>(y * blockY), // nYOff
1234 : static_cast<int>(readX), // nXSize
1235 : static_cast<int>(readY), // nYSize
1236 965 : output.data() + iBand * nDTSize,
1237 : // pData
1238 : blockX, // nBufXSize
1239 : blockY, // nBufYSize
1240 : firstBand->GetRasterDataType(),
1241 : // eBufType
1242 : bytesPerPixel, // nPixelSpace
1243 965 : bytesPerPixel * blockX, nullptr); // nLineSpace
1244 965 : if (eErr != CE_None)
1245 : {
1246 0 : CPLError(CE_Failure, CPLE_FileIO,
1247 : "FIT write - CreateCopy got read error %i", eErr);
1248 0 : CPL_IGNORE_RET_VAL(VSIFCloseL(fpImage));
1249 0 : VSIUnlink(pszFilename);
1250 0 : return nullptr;
1251 : }
1252 : } // for iBand
1253 :
1254 : #ifdef swapping
1255 865 : GByte *p = output.data();
1256 : unsigned long i;
1257 865 : switch (nDTSize)
1258 : {
1259 205 : case 1:
1260 : // do nothing
1261 205 : break;
1262 220 : case 2:
1263 1220 : for (i = 0; i < pageBytes; i += nDTSize)
1264 : {
1265 1000 : CPL_SWAP16PTR(p + i);
1266 : }
1267 220 : break;
1268 330 : case 4:
1269 1830 : for (i = 0; i < pageBytes; i += nDTSize)
1270 : {
1271 1500 : CPL_SWAP32PTR(p + i);
1272 : }
1273 330 : break;
1274 110 : case 8:
1275 610 : for (i = 0; i < pageBytes; i += nDTSize)
1276 : {
1277 500 : CPL_SWAP64PTR(p + i);
1278 : }
1279 110 : break;
1280 0 : default:
1281 0 : CPLError(CE_Failure, CPLE_NotSupported,
1282 : "FIT write - unsupported bytesPerPixel %d",
1283 : nDTSize);
1284 : } // switch
1285 : #endif // swapping
1286 :
1287 865 : if (VSIFWriteL(output.data(), 1, pageBytes, fpImage) != pageBytes)
1288 : {
1289 9 : CPLError(CE_Failure, CPLE_FileIO, "Write failed");
1290 9 : CPL_IGNORE_RET_VAL(VSIFCloseL(fpImage));
1291 9 : VSIUnlink(pszFilename);
1292 9 : return nullptr;
1293 : }
1294 :
1295 856 : double perc = ((double)(y * maxx + x)) / (maxx * maxy);
1296 856 : if (!pfnProgress(perc, nullptr, pProgressData))
1297 : {
1298 0 : CPLError(CE_Failure, CPLE_UserInterrupt, "User terminated");
1299 0 : CPL_IGNORE_RET_VAL(VSIFCloseL(fpImage));
1300 0 : VSIUnlink(pszFilename);
1301 0 : return nullptr;
1302 : }
1303 : } // for x
1304 :
1305 19 : CPL_IGNORE_RET_VAL(VSIFCloseL(fpImage));
1306 :
1307 19 : pfnProgress(1.0, nullptr, pProgressData);
1308 :
1309 : /* -------------------------------------------------------------------- */
1310 : /* Re-open dataset, and copy any auxiliary pam information. */
1311 : /* -------------------------------------------------------------------- */
1312 19 : GDALPamDataset *poDS = (GDALPamDataset *)GDALOpen(pszFilename, GA_ReadOnly);
1313 :
1314 19 : if (poDS)
1315 18 : poDS->CloneInfo(poSrcDS, GCIF_PAM_DEFAULT);
1316 :
1317 19 : return poDS;
1318 : }
1319 :
1320 : /************************************************************************/
1321 : /* GetGeoTransform() */
1322 : /************************************************************************/
1323 :
1324 : // CPLErr FITDataset::GetGeoTransform( double * padfTransform )
1325 : // {
1326 : // CPLDebug("FIT", "FITDataset::GetGeoTransform");
1327 : // memcpy( padfTransform, adfGeoTransform, sizeof(double) * 6 );
1328 : // return CE_None;
1329 : // }
1330 :
1331 : /************************************************************************/
1332 : /* GDALRegister_FIT() */
1333 : /************************************************************************/
1334 :
1335 1686 : void GDALRegister_FIT()
1336 :
1337 : {
1338 1686 : if (GDALGetDriverByName("FIT") != nullptr)
1339 302 : return;
1340 :
1341 1384 : GDALDriver *poDriver = new GDALDriver();
1342 :
1343 1384 : poDriver->SetDescription("FIT");
1344 1384 : poDriver->SetMetadataItem(GDAL_DCAP_RASTER, "YES");
1345 1384 : poDriver->SetMetadataItem(GDAL_DMD_LONGNAME, "FIT Image");
1346 1384 : poDriver->SetMetadataItem(GDAL_DMD_HELPTOPIC, "drivers/raster/fit.html");
1347 1384 : poDriver->SetMetadataItem(GDAL_DMD_EXTENSION, "");
1348 1384 : poDriver->SetMetadataItem(GDAL_DCAP_VIRTUALIO, "YES");
1349 :
1350 1384 : poDriver->pfnOpen = FITDataset::Open;
1351 1384 : poDriver->pfnCreateCopy = FITCreateCopy;
1352 1384 : poDriver->SetMetadataItem(GDAL_DMD_CREATIONDATATYPES,
1353 : "Byte UInt16 Int16 UInt32 Int32 "
1354 1384 : "Float32 Float64");
1355 :
1356 1384 : GetGDALDriverManager()->RegisterDriver(poDriver);
1357 : }
|