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