Line data Source code
1 : /******************************************************************************
2 : *
3 : * Project: Raster Matrix Format
4 : * Purpose: Read/write raster files used in GIS "Integratsia"
5 : * (also known as "Panorama" GIS).
6 : * Author: Andrey Kiselev, dron@ak4719.spb.edu
7 : *
8 : ******************************************************************************
9 : * Copyright (c) 2005, Andrey Kiselev <dron@ak4719.spb.edu>
10 : * Copyright (c) 2007-2012, Even Rouault <even dot rouault at spatialys.com>
11 : * Copyright (c) 2023, NextGIS <info@nextgis.com>
12 : *
13 : * SPDX-License-Identifier: MIT
14 : ****************************************************************************/
15 : #include <algorithm>
16 : #include <limits>
17 :
18 : #include "cpl_string.h"
19 : #include "gdal_frmts.h"
20 : #include "ogr_spatialref.h"
21 :
22 : #include "rmfdataset.h"
23 :
24 : #include "cpl_safemaths.hpp"
25 :
26 : constexpr int RMF_DEFAULT_BLOCKXSIZE = 256;
27 : constexpr int RMF_DEFAULT_BLOCKYSIZE = 256;
28 :
29 : static const char RMF_SigRSW[] = {'R', 'S', 'W', '\0'};
30 : static const char RMF_SigRSW_BE[] = {'\0', 'W', 'S', 'R'};
31 : static const char RMF_SigMTW[] = {'M', 'T', 'W', '\0'};
32 :
33 : static const char RMF_UnitsEmpty[] = "";
34 : static const char RMF_UnitsM[] = "m";
35 : static const char RMF_UnitsCM[] = "cm";
36 : static const char RMF_UnitsDM[] = "dm";
37 : static const char RMF_UnitsMM[] = "mm";
38 :
39 : constexpr double RMF_DEFAULT_SCALE = 10000.0;
40 : constexpr double RMF_DEFAULT_RESOLUTION = 100.0;
41 :
42 : constexpr const char *MD_VERSION_KEY = "VERSION";
43 : constexpr const char *MD_NAME_KEY = "NAME";
44 : constexpr const char *MD_SCALE_KEY = "SCALE";
45 : constexpr const char *MD_FRAME_KEY = "FRAME";
46 :
47 : constexpr const char *MD_MATH_BASE_MAP_TYPE_KEY = "MATH_BASE.Map type";
48 : constexpr const char *MD_MATH_BASE_PROJECTION_KEY = "MATH_BASE.Projection";
49 :
50 : constexpr int nMaxFramePointCount = 2048;
51 : constexpr GInt32 nPolygonType =
52 : 2147385342; // 2147385342 magic number for polygon
53 :
54 : /* -------------------------------------------------------------------- */
55 : /* Note: Due to the fact that in the early versions of RMF */
56 : /* format the field of the iEPSGCode was marked as a 'reserved', */
57 : /* in the header on its place in many cases garbage values were written.*/
58 : /* Most of them can be weeded out by the minimum EPSG code value. */
59 : /* */
60 : /* see: Surveying and Positioning Guidance Note Number 7, part 1 */
61 : /* Using the EPSG Geodetic Parameter Dataset p. 22 */
62 : /* http://www.epsg.org/Portals/0/373-07-1.pdf */
63 : /* -------------------------------------------------------------------- */
64 : constexpr GInt32 RMF_EPSG_MIN_CODE = 1024;
65 :
66 74 : static char *RMFUnitTypeToStr(GUInt32 iElevationUnit)
67 : {
68 74 : switch (iElevationUnit)
69 : {
70 68 : case 0:
71 68 : return CPLStrdup(RMF_UnitsM);
72 0 : case 1:
73 0 : return CPLStrdup(RMF_UnitsDM);
74 1 : case 2:
75 1 : return CPLStrdup(RMF_UnitsCM);
76 5 : case 3:
77 5 : return CPLStrdup(RMF_UnitsMM);
78 0 : default:
79 0 : return CPLStrdup(RMF_UnitsEmpty);
80 : }
81 : }
82 :
83 80 : static GUInt32 RMFStrToUnitType(const char *pszUnit, int *pbSuccess = nullptr)
84 : {
85 80 : if (pbSuccess != nullptr)
86 : {
87 3 : *pbSuccess = TRUE;
88 : }
89 80 : if (EQUAL(pszUnit, RMF_UnitsM))
90 0 : return 0;
91 80 : else if (EQUAL(pszUnit, RMF_UnitsDM))
92 0 : return 1;
93 80 : else if (EQUAL(pszUnit, RMF_UnitsCM))
94 1 : return 2;
95 79 : else if (EQUAL(pszUnit, RMF_UnitsMM))
96 1 : return 3;
97 : else
98 : {
99 : // There is no 'invalid unit' in RMF format. So meter is default...
100 78 : if (pbSuccess != nullptr)
101 : {
102 1 : *pbSuccess = FALSE;
103 : }
104 78 : return 0;
105 : }
106 : }
107 :
108 : /************************************************************************/
109 : /* ==================================================================== */
110 : /* RMFRasterBand */
111 : /* ==================================================================== */
112 : /************************************************************************/
113 :
114 : /************************************************************************/
115 : /* RMFRasterBand() */
116 : /************************************************************************/
117 :
118 419 : RMFRasterBand::RMFRasterBand(RMFDataset *poDSIn, int nBandIn,
119 419 : GDALDataType eType)
120 838 : : nLastTileWidth(poDSIn->GetRasterXSize() % poDSIn->sHeader.nTileWidth),
121 838 : nLastTileHeight(poDSIn->GetRasterYSize() % poDSIn->sHeader.nTileHeight),
122 419 : nDataSize(GDALGetDataTypeSizeBytes(eType))
123 : {
124 419 : poDS = poDSIn;
125 419 : nBand = nBandIn;
126 :
127 419 : eDataType = eType;
128 419 : nBlockXSize = poDSIn->sHeader.nTileWidth;
129 419 : nBlockYSize = poDSIn->sHeader.nTileHeight;
130 419 : nBlockSize = nBlockXSize * nBlockYSize;
131 419 : nBlockBytes = nBlockSize * nDataSize;
132 :
133 : #ifdef DEBUG
134 419 : CPLDebug("RMF",
135 : "Band %d: tile width is %d, tile height is %d, "
136 : " last tile width %u, last tile height %u, "
137 : "bytes per pixel is %d, data type size is %d",
138 : nBand, nBlockXSize, nBlockYSize, nLastTileWidth, nLastTileHeight,
139 419 : poDSIn->sHeader.nBitDepth / 8, nDataSize);
140 : #endif
141 419 : }
142 :
143 : /************************************************************************/
144 : /* ~RMFRasterBand() */
145 : /************************************************************************/
146 :
147 838 : RMFRasterBand::~RMFRasterBand()
148 : {
149 838 : }
150 :
151 : /************************************************************************/
152 : /* IReadBlock() */
153 : /************************************************************************/
154 :
155 454 : CPLErr RMFRasterBand::IReadBlock(int nBlockXOff, int nBlockYOff, void *pImage)
156 : {
157 454 : RMFDataset *poGDS = reinterpret_cast<RMFDataset *>(poDS);
158 :
159 454 : CPLAssert(poGDS != nullptr && nBlockXOff >= 0 && nBlockYOff >= 0 &&
160 : pImage != nullptr);
161 :
162 454 : memset(pImage, 0, nBlockBytes);
163 :
164 454 : GUInt32 nRawXSize = nBlockXSize;
165 454 : GUInt32 nRawYSize = nBlockYSize;
166 :
167 454 : if (nLastTileWidth && (GUInt32)nBlockXOff == poGDS->nXTiles - 1)
168 176 : nRawXSize = nLastTileWidth;
169 :
170 454 : if (nLastTileHeight && (GUInt32)nBlockYOff == poGDS->nYTiles - 1)
171 198 : nRawYSize = nLastTileHeight;
172 :
173 454 : GUInt32 nRawBytes = nRawXSize * nRawYSize * poGDS->sHeader.nBitDepth / 8;
174 :
175 : // Direct read optimization
176 454 : if (poGDS->nBands == 1 && poGDS->sHeader.nBitDepth >= 8 &&
177 183 : nRawXSize == static_cast<GUInt32>(nBlockXSize) &&
178 71 : nRawYSize == static_cast<GUInt32>(nBlockYSize))
179 : {
180 67 : bool bNullTile = false;
181 67 : if (CE_None != poGDS->ReadTile(nBlockXOff, nBlockYOff,
182 : reinterpret_cast<GByte *>(pImage),
183 : nRawBytes, nRawXSize, nRawYSize,
184 : bNullTile))
185 : {
186 0 : CPLError(CE_Failure, CPLE_FileIO,
187 : "Failed to read tile xOff %d yOff %d", nBlockXOff,
188 : nBlockYOff);
189 0 : return CE_Failure;
190 : }
191 67 : if (bNullTile)
192 : {
193 : const int nChunkSize =
194 1 : std::max(1, GDALGetDataTypeSizeBytes(eDataType));
195 1 : const GPtrDiff_t nWords =
196 1 : static_cast<GPtrDiff_t>(nBlockXSize) * nBlockYSize;
197 1 : GDALCopyWords64(&poGDS->sHeader.dfNoData, GDT_Float64, 0, pImage,
198 : eDataType, nChunkSize, nWords);
199 : }
200 67 : return CE_None;
201 : }
202 : #ifdef DEBUG
203 387 : CPLDebug("RMF", "IReadBlock nBand %d, RawSize [%d, %d], Bits %d", nBand,
204 387 : nRawXSize, nRawYSize, (int)poGDS->sHeader.nBitDepth);
205 : #endif // DEBUG
206 387 : if (poGDS->pabyCurrentTile == nullptr ||
207 290 : poGDS->nCurrentTileXOff != nBlockXOff ||
208 102 : poGDS->nCurrentTileYOff != nBlockYOff ||
209 102 : poGDS->nCurrentTileBytes != nRawBytes)
210 : {
211 285 : if (poGDS->pabyCurrentTile == nullptr)
212 : {
213 97 : GUInt32 nMaxTileBytes = poGDS->sHeader.nTileWidth *
214 97 : poGDS->sHeader.nTileHeight *
215 97 : poGDS->sHeader.nBitDepth / 8;
216 97 : poGDS->pabyCurrentTile = reinterpret_cast<GByte *>(
217 97 : VSIMalloc(std::max(1U, nMaxTileBytes)));
218 97 : if (!poGDS->pabyCurrentTile)
219 : {
220 0 : CPLError(CE_Failure, CPLE_OutOfMemory,
221 : "Can't allocate tile block of size %lu.\n%s",
222 : static_cast<unsigned long>(nMaxTileBytes),
223 0 : VSIStrerror(errno));
224 0 : poGDS->nCurrentTileBytes = 0;
225 0 : return CE_Failure;
226 : }
227 : }
228 :
229 285 : poGDS->nCurrentTileXOff = nBlockXOff;
230 285 : poGDS->nCurrentTileYOff = nBlockYOff;
231 285 : poGDS->nCurrentTileBytes = nRawBytes;
232 :
233 285 : if (CE_None != poGDS->ReadTile(nBlockXOff, nBlockYOff,
234 : poGDS->pabyCurrentTile, nRawBytes,
235 : nRawXSize, nRawYSize,
236 285 : poGDS->bCurrentTileIsNull))
237 : {
238 0 : CPLError(CE_Failure, CPLE_FileIO,
239 : "Failed to read tile xOff %d yOff %d", nBlockXOff,
240 : nBlockYOff);
241 0 : poGDS->nCurrentTileBytes = 0;
242 0 : return CE_Failure;
243 : }
244 : }
245 :
246 : /* -------------------------------------------------------------------- */
247 : /* Deinterleave pixels from input buffer. */
248 : /* -------------------------------------------------------------------- */
249 :
250 387 : if (poGDS->bCurrentTileIsNull)
251 : {
252 0 : const int nChunkSize = std::max(1, GDALGetDataTypeSizeBytes(eDataType));
253 0 : const GPtrDiff_t nWords =
254 0 : static_cast<GPtrDiff_t>(nBlockXSize) * nBlockYSize;
255 0 : GDALCopyWords64(&poGDS->sHeader.dfNoData, GDT_Float64, 0, pImage,
256 : eDataType, nChunkSize, nWords);
257 0 : return CE_None;
258 : }
259 387 : else if ((poGDS->eRMFType == RMFT_RSW &&
260 283 : (poGDS->sHeader.nBitDepth == 8 ||
261 271 : poGDS->sHeader.nBitDepth == 24 ||
262 9 : poGDS->sHeader.nBitDepth == 32)) ||
263 107 : (poGDS->eRMFType == RMFT_MTW))
264 : {
265 384 : const size_t nTilePixelSize = poGDS->sHeader.nBitDepth / 8;
266 384 : const size_t nTileLineSize = nTilePixelSize * nRawXSize;
267 384 : const size_t nBlockLineSize =
268 384 : static_cast<size_t>(nDataSize) * nBlockXSize;
269 384 : int iDstBand = (poGDS->nBands - nBand);
270 50423 : for (GUInt32 iLine = 0; iLine != nRawYSize; ++iLine)
271 : {
272 : GByte *pabySrc;
273 : GByte *pabyDst;
274 50039 : pabySrc = poGDS->pabyCurrentTile + iLine * nTileLineSize +
275 50039 : iDstBand * nDataSize;
276 50039 : pabyDst =
277 50039 : reinterpret_cast<GByte *>(pImage) + iLine * nBlockLineSize;
278 50039 : GDALCopyWords(pabySrc, eDataType, static_cast<int>(nTilePixelSize),
279 50039 : pabyDst, eDataType, static_cast<int>(nDataSize),
280 : nRawXSize);
281 : }
282 384 : return CE_None;
283 : }
284 3 : else if (poGDS->eRMFType == RMFT_RSW && poGDS->sHeader.nBitDepth == 16 &&
285 0 : poGDS->nBands == 3)
286 : {
287 0 : const size_t nTilePixelBits = poGDS->sHeader.nBitDepth;
288 0 : const size_t nTileLineSize = nTilePixelBits * nRawXSize / 8;
289 0 : const size_t nBlockLineSize =
290 0 : static_cast<size_t>(nDataSize) * nBlockXSize;
291 :
292 0 : for (GUInt32 iLine = 0; iLine != nRawYSize; ++iLine)
293 : {
294 : GUInt16 *pabySrc;
295 : GByte *pabyDst;
296 0 : pabySrc = reinterpret_cast<GUInt16 *>(poGDS->pabyCurrentTile +
297 0 : iLine * nTileLineSize);
298 0 : pabyDst =
299 0 : reinterpret_cast<GByte *>(pImage) + iLine * nBlockLineSize;
300 :
301 0 : for (GUInt32 i = 0; i < nRawXSize; i++)
302 : {
303 0 : switch (nBand)
304 : {
305 0 : case 1:
306 0 : pabyDst[i] =
307 0 : static_cast<GByte>((pabySrc[i] & 0x7c00) >> 7);
308 0 : break;
309 0 : case 2:
310 0 : pabyDst[i] =
311 0 : static_cast<GByte>((pabySrc[i] & 0x03e0) >> 2);
312 0 : break;
313 0 : case 3:
314 0 : pabyDst[i] =
315 0 : static_cast<GByte>((pabySrc[i] & 0x1F) << 3);
316 0 : break;
317 0 : default:
318 0 : break;
319 : }
320 : }
321 : }
322 0 : return CE_None;
323 : }
324 3 : else if (poGDS->eRMFType == RMFT_RSW && poGDS->nBands == 1 &&
325 3 : poGDS->sHeader.nBitDepth == 4)
326 : {
327 2 : if (poGDS->nCurrentTileBytes != (nBlockSize + 1) / 2)
328 : {
329 0 : CPLError(CE_Failure, CPLE_AppDefined,
330 : "Tile has %d bytes, %d were expected",
331 0 : poGDS->nCurrentTileBytes, (nBlockSize + 1) / 2);
332 0 : return CE_Failure;
333 : }
334 :
335 2 : const size_t nTilePixelBits = poGDS->sHeader.nBitDepth;
336 2 : const size_t nTileLineSize = nTilePixelBits * nRawXSize / 8;
337 2 : const size_t nBlockLineSize =
338 2 : static_cast<size_t>(nDataSize) * nBlockXSize;
339 :
340 464 : for (GUInt32 iLine = 0; iLine != nRawYSize; ++iLine)
341 : {
342 : GByte *pabySrc;
343 : GByte *pabyDst;
344 462 : pabySrc = poGDS->pabyCurrentTile + iLine * nTileLineSize;
345 462 : pabyDst =
346 462 : reinterpret_cast<GByte *>(pImage) + iLine * nBlockLineSize;
347 112266 : for (GUInt32 i = 0; i < nRawXSize; ++i)
348 : {
349 111804 : if (i & 0x01)
350 55902 : pabyDst[i] = (*pabySrc++ & 0xF0) >> 4;
351 : else
352 55902 : pabyDst[i] = *pabySrc & 0x0F;
353 : }
354 : }
355 2 : return CE_None;
356 : }
357 1 : else if (poGDS->eRMFType == RMFT_RSW && poGDS->nBands == 1 &&
358 1 : poGDS->sHeader.nBitDepth == 1)
359 : {
360 1 : if (poGDS->nCurrentTileBytes != (nBlockSize + 7) / 8)
361 : {
362 0 : CPLError(CE_Failure, CPLE_AppDefined,
363 : "Tile has %d bytes, %d were expected",
364 0 : poGDS->nCurrentTileBytes, (nBlockSize + 7) / 8);
365 0 : return CE_Failure;
366 : }
367 :
368 1 : const size_t nTilePixelBits = poGDS->sHeader.nBitDepth;
369 1 : const size_t nTileLineSize = nTilePixelBits * nRawXSize / 8;
370 1 : const size_t nBlockLineSize =
371 1 : static_cast<size_t>(nDataSize) * nBlockXSize;
372 :
373 232 : for (GUInt32 iLine = 0; iLine != nRawYSize; ++iLine)
374 : {
375 : GByte *pabySrc;
376 : GByte *pabyDst;
377 231 : pabySrc = poGDS->pabyCurrentTile + iLine * nTileLineSize;
378 231 : pabyDst =
379 231 : reinterpret_cast<GByte *>(pImage) + iLine * nBlockLineSize;
380 :
381 57519 : for (GUInt32 i = 0; i < nRawXSize; ++i)
382 : {
383 57288 : switch (i & 0x7)
384 : {
385 7161 : case 0:
386 7161 : pabyDst[i] = (*pabySrc & 0x80) >> 7;
387 7161 : break;
388 7161 : case 1:
389 7161 : pabyDst[i] = (*pabySrc & 0x40) >> 6;
390 7161 : break;
391 7161 : case 2:
392 7161 : pabyDst[i] = (*pabySrc & 0x20) >> 5;
393 7161 : break;
394 7161 : case 3:
395 7161 : pabyDst[i] = (*pabySrc & 0x10) >> 4;
396 7161 : break;
397 7161 : case 4:
398 7161 : pabyDst[i] = (*pabySrc & 0x08) >> 3;
399 7161 : break;
400 7161 : case 5:
401 7161 : pabyDst[i] = (*pabySrc & 0x04) >> 2;
402 7161 : break;
403 7161 : case 6:
404 7161 : pabyDst[i] = (*pabySrc & 0x02) >> 1;
405 7161 : break;
406 7161 : case 7:
407 7161 : pabyDst[i] = *pabySrc++ & 0x01;
408 7161 : break;
409 0 : default:
410 0 : break;
411 : }
412 : }
413 : }
414 1 : return CE_None;
415 : }
416 :
417 0 : CPLError(CE_Failure, CPLE_AppDefined,
418 : "Invalid block data type. BitDepth %d, nBands %d",
419 0 : static_cast<int>(poGDS->sHeader.nBitDepth), poGDS->nBands);
420 :
421 0 : return CE_Failure;
422 : }
423 :
424 : /************************************************************************/
425 : /* IWriteBlock() */
426 : /************************************************************************/
427 :
428 454 : CPLErr RMFRasterBand::IWriteBlock(int nBlockXOff, int nBlockYOff, void *pImage)
429 : {
430 454 : CPLAssert(poDS != nullptr && nBlockXOff >= 0 && nBlockYOff >= 0 &&
431 : pImage != nullptr);
432 :
433 454 : RMFDataset *poGDS = reinterpret_cast<RMFDataset *>(poDS);
434 :
435 : // First drop current tile read by IReadBlock
436 454 : poGDS->nCurrentTileBytes = 0;
437 :
438 454 : GUInt32 nRawXSize = nBlockXSize;
439 454 : GUInt32 nRawYSize = nBlockYSize;
440 :
441 454 : if (nLastTileWidth &&
442 426 : static_cast<GUInt32>(nBlockXOff) == poGDS->nXTiles - 1)
443 103 : nRawXSize = nLastTileWidth;
444 :
445 454 : if (nLastTileHeight &&
446 402 : static_cast<GUInt32>(nBlockYOff) == poGDS->nYTiles - 1)
447 136 : nRawYSize = nLastTileHeight;
448 :
449 454 : const size_t nTilePixelSize =
450 454 : static_cast<size_t>(nDataSize) * poGDS->nBands;
451 454 : const size_t nTileLineSize = nTilePixelSize * nRawXSize;
452 454 : const size_t nTileSize = nTileLineSize * nRawYSize;
453 454 : const size_t nBlockLineSize = static_cast<size_t>(nDataSize) * nBlockXSize;
454 :
455 : #ifdef DEBUG
456 454 : CPLDebug(
457 : "RMF",
458 : "IWriteBlock BlockSize [%d, %d], RawSize [%d, %d], size %d, nBand %d",
459 : nBlockXSize, nBlockYSize, nRawXSize, nRawYSize,
460 : static_cast<int>(nTileSize), nBand);
461 : #endif // DEBUG
462 :
463 454 : if (poGDS->nBands == 1 && nRawXSize == static_cast<GUInt32>(nBlockXSize) &&
464 24 : nRawYSize == static_cast<GUInt32>(nBlockYSize))
465 : { // Immediate write
466 46 : return poGDS->WriteTile(
467 : nBlockXOff, nBlockYOff, reinterpret_cast<GByte *>(pImage),
468 23 : static_cast<size_t>(nRawXSize) * nRawYSize * nDataSize, nRawXSize,
469 23 : nRawYSize);
470 : }
471 : else
472 : { // Try to construct full tile in memory and write later
473 431 : const GUInt32 nTile = nBlockYOff * poGDS->nXTiles + nBlockXOff;
474 :
475 : // Find tile
476 431 : auto poTile(poGDS->oUnfinishedTiles.find(nTile));
477 431 : if (poTile == poGDS->oUnfinishedTiles.end())
478 : {
479 167 : RMFTileData oTile;
480 167 : oTile.oData.resize(nTileSize);
481 : // If not found, but exist on disk than read it
482 167 : if (poGDS->paiTiles[2 * nTile + 1])
483 : {
484 : CPLErr eRes;
485 0 : bool bNullTile = false;
486 : eRes =
487 0 : poGDS->ReadTile(nBlockXOff, nBlockYOff, oTile.oData.data(),
488 : nTileSize, nRawXSize, nRawYSize, bNullTile);
489 0 : if (eRes != CE_None)
490 : {
491 0 : CPLError(CE_Failure, CPLE_FileIO,
492 : "Can't read block with offset [%d, %d]",
493 : nBlockXOff, nBlockYOff);
494 0 : return eRes;
495 : }
496 : }
497 : poTile = poGDS->oUnfinishedTiles.insert(
498 167 : poGDS->oUnfinishedTiles.end(), std::make_pair(nTile, oTile));
499 : }
500 :
501 431 : GByte *pabyTileData = poTile->second.oData.data();
502 :
503 : // Copy new data to a tile
504 431 : int iDstBand = (poGDS->nBands - nBand);
505 79381 : for (GUInt32 iLine = 0; iLine != nRawYSize; ++iLine)
506 : {
507 : const GByte *pabySrc;
508 : GByte *pabyDst;
509 78950 : pabySrc = reinterpret_cast<const GByte *>(pImage) +
510 78950 : iLine * nBlockLineSize;
511 78950 : pabyDst =
512 78950 : pabyTileData + iLine * nTileLineSize + iDstBand * nDataSize;
513 78950 : GDALCopyWords(pabySrc, eDataType, static_cast<int>(nDataSize),
514 : pabyDst, eDataType, static_cast<int>(nTilePixelSize),
515 : nRawXSize);
516 : }
517 431 : ++poTile->second.nBandsWritten;
518 :
519 : // Write to disk if tile is finished
520 431 : if (poTile->second.nBandsWritten == poGDS->nBands)
521 : {
522 167 : poGDS->WriteTile(nBlockXOff, nBlockYOff, pabyTileData, nTileSize,
523 : nRawXSize, nRawYSize);
524 167 : poGDS->oUnfinishedTiles.erase(poTile);
525 : }
526 : #ifdef DEBUG
527 431 : CPLDebug("RMF", "poGDS->oUnfinishedTiles.size() %d",
528 431 : static_cast<int>(poGDS->oUnfinishedTiles.size()));
529 : #endif // DEBUG
530 : }
531 :
532 431 : return CE_None;
533 : }
534 :
535 : /************************************************************************/
536 : /* GetNoDataValue() */
537 : /************************************************************************/
538 :
539 191 : double RMFRasterBand::GetNoDataValue(int *pbSuccess)
540 :
541 : {
542 191 : RMFDataset *poGDS = reinterpret_cast<RMFDataset *>(poDS);
543 :
544 191 : if (pbSuccess)
545 164 : *pbSuccess = TRUE;
546 :
547 191 : return poGDS->sHeader.dfNoData;
548 : }
549 :
550 27 : CPLErr RMFRasterBand::SetNoDataValue(double dfNoData)
551 : {
552 27 : RMFDataset *poGDS = reinterpret_cast<RMFDataset *>(poDS);
553 :
554 27 : poGDS->sHeader.dfNoData = dfNoData;
555 27 : poGDS->bHeaderDirty = true;
556 :
557 27 : return CE_None;
558 : }
559 :
560 : /************************************************************************/
561 : /* GetUnitType() */
562 : /************************************************************************/
563 :
564 10 : const char *RMFRasterBand::GetUnitType()
565 :
566 : {
567 10 : RMFDataset *poGDS = reinterpret_cast<RMFDataset *>(poDS);
568 :
569 10 : return (const char *)poGDS->pszUnitType;
570 : }
571 :
572 : /************************************************************************/
573 : /* SetUnitType() */
574 : /************************************************************************/
575 :
576 3 : CPLErr RMFRasterBand::SetUnitType(const char *pszNewValue)
577 :
578 : {
579 3 : RMFDataset *poGDS = reinterpret_cast<RMFDataset *>(poDS);
580 3 : int bSuccess = FALSE;
581 3 : int iNewUnit = RMFStrToUnitType(pszNewValue, &bSuccess);
582 :
583 3 : if (bSuccess)
584 : {
585 2 : CPLFree(poGDS->pszUnitType);
586 2 : poGDS->pszUnitType = CPLStrdup(pszNewValue);
587 2 : poGDS->sHeader.iElevationUnit = iNewUnit;
588 2 : poGDS->bHeaderDirty = true;
589 2 : return CE_None;
590 : }
591 : else
592 : {
593 1 : CPLError(CE_Warning, CPLE_NotSupported,
594 : "RMF driver does not support '%s' elevation units. "
595 : "Possible values are: m, dm, cm, mm.",
596 : pszNewValue);
597 1 : return CE_Failure;
598 : }
599 : }
600 :
601 : /************************************************************************/
602 : /* GetColorTable() */
603 : /************************************************************************/
604 :
605 28 : GDALColorTable *RMFRasterBand::GetColorTable()
606 : {
607 28 : RMFDataset *poGDS = reinterpret_cast<RMFDataset *>(poDS);
608 :
609 28 : return poGDS->poColorTable;
610 : }
611 :
612 : /************************************************************************/
613 : /* SetColorTable() */
614 : /************************************************************************/
615 :
616 8 : CPLErr RMFRasterBand::SetColorTable(GDALColorTable *poColorTable)
617 : {
618 8 : RMFDataset *poGDS = reinterpret_cast<RMFDataset *>(poDS);
619 :
620 8 : if (poColorTable)
621 : {
622 8 : if (poGDS->eRMFType == RMFT_RSW && poGDS->nBands == 1)
623 : {
624 8 : if (!poGDS->pabyColorTable)
625 0 : return CE_Failure;
626 :
627 : GDALColorEntry oEntry;
628 2056 : for (GUInt32 i = 0; i < poGDS->nColorTableSize; i++)
629 : {
630 2048 : poColorTable->GetColorEntryAsRGB(i, &oEntry);
631 2048 : poGDS->pabyColorTable[i * 4] = (GByte)oEntry.c1; // Red
632 2048 : poGDS->pabyColorTable[i * 4 + 1] = (GByte)oEntry.c2; // Green
633 2048 : poGDS->pabyColorTable[i * 4 + 2] = (GByte)oEntry.c3; // Blue
634 2048 : poGDS->pabyColorTable[i * 4 + 3] = 0;
635 : }
636 :
637 8 : poGDS->bHeaderDirty = true;
638 : }
639 8 : return CE_None;
640 : }
641 :
642 0 : return CE_Failure;
643 : }
644 :
645 59 : int RMFRasterBand::GetOverviewCount()
646 : {
647 59 : RMFDataset *poGDS = reinterpret_cast<RMFDataset *>(poDS);
648 59 : if (poGDS->poOvrDatasets.empty())
649 0 : return GDALRasterBand::GetOverviewCount();
650 : else
651 59 : return static_cast<int>(poGDS->poOvrDatasets.size());
652 : }
653 :
654 79 : GDALRasterBand *RMFRasterBand::GetOverview(int i)
655 : {
656 79 : RMFDataset *poGDS = reinterpret_cast<RMFDataset *>(poDS);
657 79 : size_t n = static_cast<size_t>(i);
658 79 : if (poGDS->poOvrDatasets.empty())
659 0 : return GDALRasterBand::GetOverview(i);
660 : else
661 79 : return poGDS->poOvrDatasets[n]->GetRasterBand(nBand);
662 : }
663 :
664 694 : CPLErr RMFRasterBand::IRasterIO(GDALRWFlag eRWFlag, int nXOff, int nYOff,
665 : int nXSize, int nYSize, void *pData,
666 : int nBufXSize, int nBufYSize,
667 : GDALDataType eType, GSpacing nPixelSpace,
668 : GSpacing nLineSpace,
669 : GDALRasterIOExtraArg *psExtraArg)
670 : {
671 694 : RMFDataset *poGDS = reinterpret_cast<RMFDataset *>(poDS);
672 :
673 743 : if (eRWFlag == GF_Read && poGDS->poCompressData != nullptr &&
674 49 : poGDS->poCompressData->oThreadPool.GetThreadCount() > 0)
675 : {
676 9 : poGDS->poCompressData->oThreadPool.WaitCompletion();
677 : }
678 :
679 694 : return GDALRasterBand::IRasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize,
680 : pData, nBufXSize, nBufYSize, eType,
681 694 : nPixelSpace, nLineSpace, psExtraArg);
682 : }
683 :
684 : /************************************************************************/
685 : /* GetColorInterpretation() */
686 : /************************************************************************/
687 :
688 104 : GDALColorInterp RMFRasterBand::GetColorInterpretation()
689 : {
690 104 : RMFDataset *poGDS = reinterpret_cast<RMFDataset *>(poDS);
691 :
692 104 : if (poGDS->nBands == 3)
693 : {
694 53 : if (nBand == 1)
695 18 : return GCI_RedBand;
696 35 : else if (nBand == 2)
697 17 : return GCI_GreenBand;
698 18 : else if (nBand == 3)
699 18 : return GCI_BlueBand;
700 :
701 0 : return GCI_Undefined;
702 : }
703 :
704 51 : if (poGDS->eRMFType == RMFT_RSW)
705 28 : return GCI_PaletteIndex;
706 :
707 23 : return GCI_Undefined;
708 : }
709 :
710 : /************************************************************************/
711 : /* ==================================================================== */
712 : /* RMFDataset */
713 : /* ==================================================================== */
714 : /************************************************************************/
715 :
716 : /************************************************************************/
717 : /* RMFDataset() */
718 : /************************************************************************/
719 :
720 297 : RMFDataset::RMFDataset()
721 : : eRMFType(RMFT_RSW), nXTiles(0), nYTiles(0), paiTiles(nullptr),
722 : pabyDecompressBuffer(nullptr), pabyCurrentTile(nullptr),
723 : bCurrentTileIsNull(false), nCurrentTileXOff(-1), nCurrentTileYOff(-1),
724 : nCurrentTileBytes(0), nColorTableSize(0), pabyColorTable(nullptr),
725 297 : poColorTable(nullptr), pszUnitType(CPLStrdup(RMF_UnitsEmpty)),
726 : bBigEndian(false), bHeaderDirty(false), fp(nullptr), Decompress(nullptr),
727 594 : Compress(nullptr), nHeaderOffset(0), poParentDS(nullptr)
728 : {
729 297 : m_oSRS.SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
730 297 : nBands = 0;
731 297 : adfGeoTransform[0] = 0.0;
732 297 : adfGeoTransform[1] = 1.0;
733 297 : adfGeoTransform[2] = 0.0;
734 297 : adfGeoTransform[3] = 0.0;
735 297 : adfGeoTransform[4] = 0.0;
736 297 : adfGeoTransform[5] = 1.0;
737 297 : memset(&sHeader, 0, sizeof(sHeader));
738 297 : memset(&sExtHeader, 0, sizeof(sExtHeader));
739 297 : }
740 :
741 : /************************************************************************/
742 : /* ~RMFDataset() */
743 : /************************************************************************/
744 :
745 594 : RMFDataset::~RMFDataset()
746 : {
747 297 : RMFDataset::FlushCache(true);
748 404 : for (size_t n = 0; n != poOvrDatasets.size(); ++n)
749 : {
750 107 : poOvrDatasets[n]->RMFDataset::FlushCache(true);
751 : }
752 :
753 297 : VSIFree(paiTiles);
754 297 : VSIFree(pabyDecompressBuffer);
755 297 : VSIFree(pabyCurrentTile);
756 297 : CPLFree(pszUnitType);
757 297 : CPLFree(pabyColorTable);
758 297 : if (poColorTable != nullptr)
759 68 : delete poColorTable;
760 :
761 404 : for (size_t n = 0; n != poOvrDatasets.size(); ++n)
762 : {
763 107 : GDALClose(poOvrDatasets[n]);
764 : }
765 :
766 297 : if (fp != nullptr && poParentDS == nullptr)
767 : {
768 177 : VSIFCloseL(fp);
769 : }
770 594 : }
771 :
772 : /************************************************************************/
773 : /* GetGeoTransform() */
774 : /************************************************************************/
775 :
776 47 : CPLErr RMFDataset::GetGeoTransform(double *padfTransform)
777 : {
778 47 : memcpy(padfTransform, adfGeoTransform, sizeof(adfGeoTransform[0]) * 6);
779 :
780 47 : if (sHeader.iGeorefFlag)
781 41 : return CE_None;
782 :
783 6 : return CE_Failure;
784 : }
785 :
786 : /************************************************************************/
787 : /* SetGeoTransform() */
788 : /************************************************************************/
789 :
790 41 : CPLErr RMFDataset::SetGeoTransform(double *padfTransform)
791 : {
792 41 : memcpy(adfGeoTransform, padfTransform, sizeof(double) * 6);
793 41 : sHeader.dfPixelSize = adfGeoTransform[1];
794 41 : if (sHeader.dfPixelSize != 0.0)
795 41 : sHeader.dfResolution = sHeader.dfScale / sHeader.dfPixelSize;
796 41 : sHeader.dfLLX = adfGeoTransform[0];
797 41 : sHeader.dfLLY = adfGeoTransform[3] - nRasterYSize * sHeader.dfPixelSize;
798 41 : sHeader.iGeorefFlag = 1;
799 :
800 41 : bHeaderDirty = true;
801 :
802 41 : return CE_None;
803 : }
804 :
805 : /************************************************************************/
806 : /* GetSpatialRef() */
807 : /************************************************************************/
808 :
809 34 : const OGRSpatialReference *RMFDataset::GetSpatialRef() const
810 :
811 : {
812 34 : return m_oSRS.IsEmpty() ? nullptr : &m_oSRS;
813 : }
814 :
815 : /************************************************************************/
816 : /* SetSpatialRef() */
817 : /************************************************************************/
818 :
819 41 : CPLErr RMFDataset::SetSpatialRef(const OGRSpatialReference *poSRS)
820 :
821 : {
822 41 : m_oSRS.Clear();
823 41 : if (poSRS)
824 41 : m_oSRS = *poSRS;
825 :
826 41 : bHeaderDirty = true;
827 :
828 41 : return CE_None;
829 : }
830 :
831 : /************************************************************************/
832 : /* WriteHeader() */
833 : /************************************************************************/
834 :
835 200 : CPLErr RMFDataset::WriteHeader()
836 : {
837 : /* -------------------------------------------------------------------- */
838 : /* Setup projection. */
839 : /* -------------------------------------------------------------------- */
840 200 : if (!m_oSRS.IsEmpty())
841 : {
842 52 : long iProjection = 0;
843 52 : long iDatum = 0;
844 52 : long iEllips = 0;
845 52 : long iZone = 0;
846 52 : int iVertCS = 0;
847 52 : double adfPrjParams[7] = {};
848 :
849 52 : m_oSRS.exportToPanorama(&iProjection, &iDatum, &iEllips, &iZone,
850 : adfPrjParams);
851 52 : m_oSRS.exportVertCSToPanorama(&iVertCS);
852 52 : sHeader.iProjection = static_cast<GInt32>(iProjection);
853 52 : sHeader.dfStdP1 = adfPrjParams[0];
854 52 : sHeader.dfStdP2 = adfPrjParams[1];
855 52 : sHeader.dfCenterLat = adfPrjParams[2];
856 52 : sHeader.dfCenterLong = adfPrjParams[3];
857 52 : if (m_oSRS.GetAuthorityName(nullptr) != nullptr &&
858 62 : m_oSRS.GetAuthorityCode(nullptr) != nullptr &&
859 10 : EQUAL(m_oSRS.GetAuthorityName(nullptr), "EPSG"))
860 : {
861 10 : sHeader.iEPSGCode = atoi(m_oSRS.GetAuthorityCode(nullptr));
862 : }
863 :
864 52 : sExtHeader.nEllipsoid = static_cast<GInt32>(iEllips);
865 52 : sExtHeader.nDatum = static_cast<GInt32>(iDatum);
866 52 : sExtHeader.nZone = static_cast<GInt32>(iZone);
867 52 : sExtHeader.nVertDatum = static_cast<GInt32>(iVertCS);
868 :
869 : // Set map type
870 52 : auto pszMapType = GetMetadataItem(MD_MATH_BASE_MAP_TYPE_KEY);
871 52 : if (pszMapType != nullptr)
872 : {
873 31 : sHeader.iMapType = static_cast<GInt32>(atoi(pszMapType));
874 : }
875 : }
876 :
877 : #define RMF_WRITE_LONG(ptr, value, offset) \
878 : do \
879 : { \
880 : GInt32 iLong = CPL_LSBWORD32(value); \
881 : memcpy((ptr) + (offset), &iLong, 4); \
882 : } while (false);
883 :
884 : #define RMF_WRITE_ULONG(ptr, value, offset) \
885 : do \
886 : { \
887 : GUInt32 iULong = CPL_LSBWORD32(value); \
888 : memcpy((ptr) + (offset), &iULong, 4); \
889 : } while (false);
890 :
891 : #define RMF_WRITE_DOUBLE(ptr, value, offset) \
892 : do \
893 : { \
894 : double dfDouble = (value); \
895 : CPL_LSBPTR64(&dfDouble); \
896 : memcpy((ptr) + (offset), &dfDouble, 8); \
897 : } while (false);
898 :
899 : // Frame if present
900 400 : std::vector<RSWFrameCoord> astFrameCoords;
901 200 : auto pszFrameWKT = GetMetadataItem(MD_FRAME_KEY);
902 200 : if (pszFrameWKT != nullptr)
903 : {
904 2 : CPLDebug("RMF", "Write to header frame: %s", pszFrameWKT);
905 2 : OGRGeometry *poFrameGeom = nullptr;
906 2 : if (OGRGeometryFactory::createFromWkt(pszFrameWKT, nullptr,
907 2 : &poFrameGeom) == OGRERR_NONE)
908 : {
909 2 : if (poFrameGeom->getGeometryType() == wkbPolygon)
910 : {
911 2 : double adfReverseGeoTransform[6] = {0};
912 2 : if (GDALInvGeoTransform(adfGeoTransform,
913 2 : adfReverseGeoTransform) == TRUE)
914 : {
915 2 : OGRPolygon *poFramePoly = poFrameGeom->toPolygon();
916 2 : if (!poFramePoly->IsEmpty())
917 : {
918 : OGRLinearRing *poFrameRing =
919 2 : poFramePoly->getExteriorRing();
920 12 : for (int i = 0; i < poFrameRing->getNumPoints(); i++)
921 : {
922 20 : int nX = int(adfReverseGeoTransform[0] +
923 10 : poFrameRing->getX(i) *
924 10 : adfReverseGeoTransform[1] -
925 10 : 0.5);
926 20 : int nY = int(adfReverseGeoTransform[3] +
927 10 : poFrameRing->getY(i) *
928 10 : adfReverseGeoTransform[5] -
929 10 : 0.5);
930 :
931 10 : CPLDebug("RMF", "X: %d, Y: %d", nX, nY);
932 :
933 10 : astFrameCoords.push_back({nX, nY});
934 : }
935 : }
936 :
937 4 : if (astFrameCoords.empty() ||
938 2 : astFrameCoords.size() > nMaxFramePointCount)
939 : {
940 : // CPLError(CE_Warning, CPLE_AppDefined, "Invalid frame WKT: %s", pszFrameWKT);
941 0 : CPLDebug("RMF", "Write to header frame failed: no "
942 : "points or too many");
943 0 : astFrameCoords.clear();
944 : }
945 : else
946 : {
947 2 : sHeader.nROISize = static_cast<GUInt32>(
948 2 : sizeof(RSWFrame) +
949 : sizeof(RSWFrameCoord) *
950 : astFrameCoords
951 2 : .size()); // Set real size and real point count
952 2 : sHeader.iFrameFlag = 0;
953 : }
954 : }
955 : else
956 : {
957 0 : CPLDebug("RMF", "Write to header frame failed: "
958 : "GDALInvGeoTransform == FALSE");
959 : }
960 : }
961 2 : OGRGeometryFactory::destroyGeometry(poFrameGeom);
962 : }
963 : else
964 : {
965 0 : CPLDebug("RMF", "Write to header frame failed: "
966 : "OGRGeometryFactory::createFromWkt error");
967 : }
968 : }
969 :
970 200 : vsi_l_offset iCurrentFileSize(GetLastOffset());
971 200 : sHeader.nFileSize0 = GetRMFOffset(iCurrentFileSize, &iCurrentFileSize);
972 200 : sHeader.nSize = sHeader.nFileSize0 - GetRMFOffset(nHeaderOffset, nullptr);
973 : /* -------------------------------------------------------------------- */
974 : /* Write out the main header. */
975 : /* -------------------------------------------------------------------- */
976 : {
977 200 : GByte abyHeader[RMF_HEADER_SIZE] = {};
978 :
979 200 : memcpy(abyHeader, sHeader.bySignature, RMF_SIGNATURE_SIZE);
980 200 : RMF_WRITE_ULONG(abyHeader, sHeader.iVersion, 4);
981 200 : RMF_WRITE_ULONG(abyHeader, sHeader.nSize, 8);
982 200 : RMF_WRITE_ULONG(abyHeader, sHeader.nOvrOffset, 12);
983 200 : RMF_WRITE_ULONG(abyHeader, sHeader.iUserID, 16);
984 200 : memcpy(abyHeader + 20, sHeader.byName, RMF_NAME_SIZE);
985 200 : RMF_WRITE_ULONG(abyHeader, sHeader.nBitDepth, 52);
986 200 : RMF_WRITE_ULONG(abyHeader, sHeader.nHeight, 56);
987 200 : RMF_WRITE_ULONG(abyHeader, sHeader.nWidth, 60);
988 200 : RMF_WRITE_ULONG(abyHeader, sHeader.nXTiles, 64);
989 200 : RMF_WRITE_ULONG(abyHeader, sHeader.nYTiles, 68);
990 200 : RMF_WRITE_ULONG(abyHeader, sHeader.nTileHeight, 72);
991 200 : RMF_WRITE_ULONG(abyHeader, sHeader.nTileWidth, 76);
992 200 : RMF_WRITE_ULONG(abyHeader, sHeader.nLastTileHeight, 80);
993 200 : RMF_WRITE_ULONG(abyHeader, sHeader.nLastTileWidth, 84);
994 200 : RMF_WRITE_ULONG(abyHeader, sHeader.nROIOffset, 88);
995 200 : RMF_WRITE_ULONG(abyHeader, sHeader.nROISize, 92);
996 200 : RMF_WRITE_ULONG(abyHeader, sHeader.nClrTblOffset, 96);
997 200 : RMF_WRITE_ULONG(abyHeader, sHeader.nClrTblSize, 100);
998 200 : RMF_WRITE_ULONG(abyHeader, sHeader.nTileTblOffset, 104);
999 200 : RMF_WRITE_ULONG(abyHeader, sHeader.nTileTblSize, 108);
1000 200 : RMF_WRITE_LONG(abyHeader, sHeader.iMapType, 124);
1001 200 : RMF_WRITE_LONG(abyHeader, sHeader.iProjection, 128);
1002 200 : RMF_WRITE_LONG(abyHeader, sHeader.iEPSGCode, 132);
1003 200 : RMF_WRITE_DOUBLE(abyHeader, sHeader.dfScale, 136);
1004 200 : RMF_WRITE_DOUBLE(abyHeader, sHeader.dfResolution, 144);
1005 200 : RMF_WRITE_DOUBLE(abyHeader, sHeader.dfPixelSize, 152);
1006 200 : RMF_WRITE_DOUBLE(abyHeader, sHeader.dfLLY, 160);
1007 200 : RMF_WRITE_DOUBLE(abyHeader, sHeader.dfLLX, 168);
1008 200 : RMF_WRITE_DOUBLE(abyHeader, sHeader.dfStdP1, 176);
1009 200 : RMF_WRITE_DOUBLE(abyHeader, sHeader.dfStdP2, 184);
1010 200 : RMF_WRITE_DOUBLE(abyHeader, sHeader.dfCenterLong, 192);
1011 200 : RMF_WRITE_DOUBLE(abyHeader, sHeader.dfCenterLat, 200);
1012 200 : *(abyHeader + 208) = sHeader.iCompression;
1013 200 : *(abyHeader + 209) = sHeader.iMaskType;
1014 200 : *(abyHeader + 210) = sHeader.iMaskStep;
1015 200 : *(abyHeader + 211) = sHeader.iFrameFlag;
1016 200 : RMF_WRITE_ULONG(abyHeader, sHeader.nFlagsTblOffset, 212);
1017 200 : RMF_WRITE_ULONG(abyHeader, sHeader.nFlagsTblSize, 216);
1018 200 : RMF_WRITE_ULONG(abyHeader, sHeader.nFileSize0, 220);
1019 200 : RMF_WRITE_ULONG(abyHeader, sHeader.nFileSize1, 224);
1020 200 : *(abyHeader + 228) = sHeader.iUnknown;
1021 200 : *(abyHeader + 244) = sHeader.iGeorefFlag;
1022 200 : *(abyHeader + 245) = sHeader.iInverse;
1023 200 : *(abyHeader + 246) = sHeader.iJpegQuality;
1024 200 : memcpy(abyHeader + 248, sHeader.abyInvisibleColors,
1025 : sizeof(sHeader.abyInvisibleColors));
1026 200 : RMF_WRITE_DOUBLE(abyHeader, sHeader.adfElevMinMax[0], 280);
1027 200 : RMF_WRITE_DOUBLE(abyHeader, sHeader.adfElevMinMax[1], 288);
1028 200 : RMF_WRITE_DOUBLE(abyHeader, sHeader.dfNoData, 296);
1029 200 : RMF_WRITE_ULONG(abyHeader, sHeader.iElevationUnit, 304);
1030 200 : *(abyHeader + 308) = sHeader.iElevationType;
1031 200 : RMF_WRITE_ULONG(abyHeader, sHeader.nExtHdrOffset, 312);
1032 200 : RMF_WRITE_ULONG(abyHeader, sHeader.nExtHdrSize, 316);
1033 :
1034 200 : VSIFSeekL(fp, nHeaderOffset, SEEK_SET);
1035 200 : VSIFWriteL(abyHeader, 1, sizeof(abyHeader), fp);
1036 : }
1037 :
1038 : /* -------------------------------------------------------------------- */
1039 : /* Write out the extended header. */
1040 : /* -------------------------------------------------------------------- */
1041 :
1042 200 : if (sHeader.nExtHdrOffset && sHeader.nExtHdrSize >= RMF_MIN_EXT_HEADER_SIZE)
1043 : {
1044 200 : if (sHeader.nExtHdrSize > RMF_MAX_EXT_HEADER_SIZE)
1045 : {
1046 0 : CPLError(CE_Failure, CPLE_FileIO, "RMF File malformed");
1047 0 : return CE_Failure;
1048 : }
1049 : GByte *pabyExtHeader =
1050 200 : reinterpret_cast<GByte *>(CPLCalloc(sHeader.nExtHdrSize, 1));
1051 :
1052 200 : RMF_WRITE_LONG(pabyExtHeader, sExtHeader.nEllipsoid, 24);
1053 200 : RMF_WRITE_LONG(pabyExtHeader, sExtHeader.nVertDatum, 28);
1054 200 : RMF_WRITE_LONG(pabyExtHeader, sExtHeader.nDatum, 32);
1055 200 : RMF_WRITE_LONG(pabyExtHeader, sExtHeader.nZone, 36);
1056 :
1057 200 : VSIFSeekL(fp, GetFileOffset(sHeader.nExtHdrOffset), SEEK_SET);
1058 200 : VSIFWriteL(pabyExtHeader, 1, sHeader.nExtHdrSize, fp);
1059 :
1060 200 : CPLFree(pabyExtHeader);
1061 : }
1062 :
1063 : /* -------------------------------------------------------------------- */
1064 : /* Write out the color table. */
1065 : /* -------------------------------------------------------------------- */
1066 :
1067 200 : if (sHeader.nClrTblOffset && sHeader.nClrTblSize)
1068 : {
1069 59 : VSIFSeekL(fp, GetFileOffset(sHeader.nClrTblOffset), SEEK_SET);
1070 59 : VSIFWriteL(pabyColorTable, 1, sHeader.nClrTblSize, fp);
1071 : }
1072 :
1073 200 : if (sHeader.nROIOffset && sHeader.nROISize)
1074 : {
1075 : GByte *pabyROI =
1076 2 : reinterpret_cast<GByte *>(CPLCalloc(sHeader.nROISize, 1));
1077 2 : memset(pabyROI, 0, sHeader.nROISize);
1078 :
1079 2 : auto nPointCount = astFrameCoords.size();
1080 2 : size_t offset = 0;
1081 2 : RMF_WRITE_LONG(pabyROI, nPolygonType, offset);
1082 2 : offset += 4;
1083 2 : RMF_WRITE_LONG(pabyROI, static_cast<GInt32>((4 + nPointCount * 2) * 4),
1084 : offset);
1085 2 : offset += 4;
1086 2 : RMF_WRITE_LONG(pabyROI, 0, offset);
1087 2 : offset += 4;
1088 2 : RMF_WRITE_LONG(pabyROI, static_cast<GInt32>(32768 * nPointCount * 2),
1089 : offset);
1090 2 : offset += 4;
1091 :
1092 : // Write points
1093 12 : for (size_t i = 0; i < nPointCount; i++)
1094 : {
1095 10 : RMF_WRITE_LONG(pabyROI, astFrameCoords[i].nX, offset);
1096 10 : offset += 4;
1097 10 : RMF_WRITE_LONG(pabyROI, astFrameCoords[i].nY, offset);
1098 10 : offset += 4;
1099 : }
1100 :
1101 2 : VSIFSeekL(fp, GetFileOffset(sHeader.nROIOffset), SEEK_SET);
1102 2 : VSIFWriteL(pabyROI, 1, sHeader.nROISize, fp);
1103 :
1104 2 : CPLFree(pabyROI);
1105 : }
1106 :
1107 200 : if (sHeader.nFlagsTblOffset && sHeader.nFlagsTblSize)
1108 : {
1109 : GByte *pabyFlagsTbl =
1110 200 : reinterpret_cast<GByte *>(CPLCalloc(sHeader.nFlagsTblSize, 1));
1111 :
1112 200 : if (sHeader.iFrameFlag == 0)
1113 : {
1114 : // TODO: Add more strictly check for flag value
1115 2 : memset(
1116 : pabyFlagsTbl, 2,
1117 : sHeader
1118 2 : .nFlagsTblSize); // Mark all blocks as intersected with ROI. 0 - complete outside, 1 - complete inside.
1119 : }
1120 : else
1121 : {
1122 198 : memset(pabyFlagsTbl, 0, sHeader.nFlagsTblSize);
1123 : }
1124 :
1125 200 : VSIFSeekL(fp, GetFileOffset(sHeader.nFlagsTblOffset), SEEK_SET);
1126 200 : VSIFWriteL(pabyFlagsTbl, 1, sHeader.nFlagsTblSize, fp);
1127 :
1128 200 : CPLFree(pabyFlagsTbl);
1129 : }
1130 :
1131 : #undef RMF_WRITE_DOUBLE
1132 : #undef RMF_WRITE_ULONG
1133 : #undef RMF_WRITE_LONG
1134 :
1135 : /* -------------------------------------------------------------------- */
1136 : /* Write out the block table, swap if needed. */
1137 : /* -------------------------------------------------------------------- */
1138 :
1139 200 : VSIFSeekL(fp, GetFileOffset(sHeader.nTileTblOffset), SEEK_SET);
1140 :
1141 : #ifdef CPL_MSB
1142 : GUInt32 *paiTilesSwapped =
1143 : reinterpret_cast<GUInt32 *>(CPLMalloc(sHeader.nTileTblSize));
1144 : if (!paiTilesSwapped)
1145 : return CE_Failure;
1146 :
1147 : memcpy(paiTilesSwapped, paiTiles, sHeader.nTileTblSize);
1148 : for (GUInt32 i = 0; i < sHeader.nTileTblSize / sizeof(GUInt32); i++)
1149 : CPL_SWAP32PTR(paiTilesSwapped + i);
1150 : VSIFWriteL(paiTilesSwapped, 1, sHeader.nTileTblSize, fp);
1151 :
1152 : CPLFree(paiTilesSwapped);
1153 : #else
1154 200 : VSIFWriteL(paiTiles, 1, sHeader.nTileTblSize, fp);
1155 : #endif
1156 :
1157 200 : bHeaderDirty = false;
1158 :
1159 200 : return CE_None;
1160 : }
1161 :
1162 : /************************************************************************/
1163 : /* FlushCache() */
1164 : /************************************************************************/
1165 :
1166 411 : CPLErr RMFDataset::FlushCache(bool bAtClosing)
1167 :
1168 : {
1169 411 : CPLErr eErr = GDALDataset::FlushCache(bAtClosing);
1170 :
1171 549 : if (poCompressData != nullptr &&
1172 138 : poCompressData->oThreadPool.GetThreadCount() > 0)
1173 : {
1174 9 : poCompressData->oThreadPool.WaitCompletion();
1175 : }
1176 :
1177 411 : if (bAtClosing && eRMFType == RMFT_MTW && eAccess == GA_Update)
1178 : {
1179 77 : GDALRasterBand *poBand = GetRasterBand(1);
1180 :
1181 77 : if (poBand)
1182 : {
1183 : // ComputeRasterMinMax can setup error in case of dataset full
1184 : // from NoData values, but it makes no sense here.
1185 77 : CPLErrorStateBackuper oErrorStateBackuper(CPLQuietErrorHandler);
1186 77 : poBand->ComputeRasterMinMax(FALSE, sHeader.adfElevMinMax);
1187 77 : bHeaderDirty = true;
1188 : }
1189 : }
1190 411 : if (bHeaderDirty && WriteHeader() != CE_None)
1191 0 : eErr = CE_Failure;
1192 411 : return eErr;
1193 : }
1194 :
1195 : /************************************************************************/
1196 : /* Identify() */
1197 : /************************************************************************/
1198 :
1199 53764 : int RMFDataset::Identify(GDALOpenInfo *poOpenInfo)
1200 :
1201 : {
1202 53764 : if (poOpenInfo->pabyHeader == nullptr)
1203 48612 : return FALSE;
1204 :
1205 5152 : if (memcmp(poOpenInfo->pabyHeader, RMF_SigRSW, sizeof(RMF_SigRSW)) != 0 &&
1206 4943 : memcmp(poOpenInfo->pabyHeader, RMF_SigRSW_BE, sizeof(RMF_SigRSW_BE)) !=
1207 4931 : 0 &&
1208 4931 : memcmp(poOpenInfo->pabyHeader, RMF_SigMTW, sizeof(RMF_SigMTW)) != 0)
1209 4813 : return FALSE;
1210 :
1211 339 : return TRUE;
1212 : }
1213 :
1214 : /************************************************************************/
1215 : /* Open() */
1216 : /************************************************************************/
1217 :
1218 128 : GDALDataset *RMFDataset::Open(GDALOpenInfo *poOpenInfo)
1219 : {
1220 128 : auto poDS = Open(poOpenInfo, nullptr, 0);
1221 128 : if (poDS == nullptr)
1222 : {
1223 9 : return nullptr;
1224 : }
1225 :
1226 119 : RMFDataset *poCurrentLayer = poDS;
1227 119 : RMFDataset *poParent = poCurrentLayer;
1228 119 : const int nMaxPossibleOvCount = 64;
1229 :
1230 200 : for (int iOv = 0; iOv < nMaxPossibleOvCount && poCurrentLayer != nullptr;
1231 : ++iOv)
1232 : {
1233 200 : poCurrentLayer = poCurrentLayer->OpenOverview(poParent, poOpenInfo);
1234 200 : if (poCurrentLayer == nullptr)
1235 119 : break;
1236 81 : poParent->poOvrDatasets.push_back(poCurrentLayer);
1237 : }
1238 :
1239 119 : return poDS;
1240 : }
1241 :
1242 213 : RMFDataset *RMFDataset::Open(GDALOpenInfo *poOpenInfo, RMFDataset *poParentDS,
1243 : vsi_l_offset nNextHeaderOffset)
1244 : {
1245 341 : if (!Identify(poOpenInfo) ||
1246 128 : (poParentDS == nullptr && poOpenInfo->fpL == nullptr))
1247 2 : return nullptr;
1248 :
1249 : /* -------------------------------------------------------------------- */
1250 : /* Create a corresponding GDALDataset. */
1251 : /* -------------------------------------------------------------------- */
1252 211 : RMFDataset *poDS = new RMFDataset();
1253 :
1254 211 : if (poParentDS == nullptr)
1255 : {
1256 128 : poDS->fp = poOpenInfo->fpL;
1257 128 : poOpenInfo->fpL = nullptr;
1258 128 : poDS->nHeaderOffset = 0;
1259 128 : poDS->poParentDS = nullptr;
1260 : }
1261 : else
1262 : {
1263 83 : poDS->fp = poParentDS->fp;
1264 83 : poDS->poParentDS = poParentDS;
1265 83 : poDS->nHeaderOffset = nNextHeaderOffset;
1266 : }
1267 211 : poDS->eAccess = poOpenInfo->eAccess;
1268 :
1269 : #define RMF_READ_SHORT(ptr, value, offset) \
1270 : do \
1271 : { \
1272 : memcpy(&(value), (GInt16 *)((ptr) + (offset)), sizeof(GInt16)); \
1273 : if (poDS->bBigEndian) \
1274 : { \
1275 : CPL_MSBPTR16(&(value)); \
1276 : } \
1277 : else \
1278 : { \
1279 : CPL_LSBPTR16(&(value)); \
1280 : } \
1281 : } while (false);
1282 :
1283 : #define RMF_READ_ULONG(ptr, value, offset) \
1284 : do \
1285 : { \
1286 : memcpy(&(value), (GUInt32 *)((ptr) + (offset)), sizeof(GUInt32)); \
1287 : if (poDS->bBigEndian) \
1288 : { \
1289 : CPL_MSBPTR32(&(value)); \
1290 : } \
1291 : else \
1292 : { \
1293 : CPL_LSBPTR32(&(value)); \
1294 : } \
1295 : } while (false);
1296 :
1297 : #define RMF_READ_LONG(ptr, value, offset) RMF_READ_ULONG(ptr, value, offset)
1298 :
1299 : #define RMF_READ_DOUBLE(ptr, value, offset) \
1300 : do \
1301 : { \
1302 : memcpy(&(value), (double *)((ptr) + (offset)), sizeof(double)); \
1303 : if (poDS->bBigEndian) \
1304 : { \
1305 : CPL_MSBPTR64(&(value)); \
1306 : } \
1307 : else \
1308 : { \
1309 : CPL_LSBPTR64(&(value)); \
1310 : } \
1311 : } while (false);
1312 :
1313 : /* -------------------------------------------------------------------- */
1314 : /* Read the main header. */
1315 : /* -------------------------------------------------------------------- */
1316 :
1317 : {
1318 211 : GByte abyHeader[RMF_HEADER_SIZE] = {};
1319 :
1320 211 : VSIFSeekL(poDS->fp, nNextHeaderOffset, SEEK_SET);
1321 211 : if (VSIFReadL(abyHeader, 1, sizeof(abyHeader), poDS->fp) !=
1322 : sizeof(abyHeader))
1323 : {
1324 0 : delete poDS;
1325 0 : return nullptr;
1326 : }
1327 :
1328 211 : if (memcmp(abyHeader, RMF_SigMTW, sizeof(RMF_SigMTW)) == 0)
1329 : {
1330 76 : poDS->eRMFType = RMFT_MTW;
1331 : }
1332 135 : else if (memcmp(abyHeader, RMF_SigRSW_BE, sizeof(RMF_SigRSW_BE)) == 0)
1333 : {
1334 6 : poDS->eRMFType = RMFT_RSW;
1335 6 : poDS->bBigEndian = true;
1336 : }
1337 : else
1338 : {
1339 129 : poDS->eRMFType = RMFT_RSW;
1340 : }
1341 :
1342 211 : memcpy(poDS->sHeader.bySignature, abyHeader, RMF_SIGNATURE_SIZE);
1343 211 : RMF_READ_ULONG(abyHeader, poDS->sHeader.iVersion, 4);
1344 211 : RMF_READ_ULONG(abyHeader, poDS->sHeader.nSize, 8);
1345 211 : RMF_READ_ULONG(abyHeader, poDS->sHeader.nOvrOffset, 12);
1346 211 : RMF_READ_ULONG(abyHeader, poDS->sHeader.iUserID, 16);
1347 211 : memcpy(poDS->sHeader.byName, abyHeader + 20,
1348 : sizeof(poDS->sHeader.byName));
1349 211 : poDS->sHeader.byName[sizeof(poDS->sHeader.byName) - 1] = '\0';
1350 211 : RMF_READ_ULONG(abyHeader, poDS->sHeader.nBitDepth, 52);
1351 211 : RMF_READ_ULONG(abyHeader, poDS->sHeader.nHeight, 56);
1352 211 : RMF_READ_ULONG(abyHeader, poDS->sHeader.nWidth, 60);
1353 211 : RMF_READ_ULONG(abyHeader, poDS->sHeader.nXTiles, 64);
1354 211 : RMF_READ_ULONG(abyHeader, poDS->sHeader.nYTiles, 68);
1355 211 : RMF_READ_ULONG(abyHeader, poDS->sHeader.nTileHeight, 72);
1356 211 : RMF_READ_ULONG(abyHeader, poDS->sHeader.nTileWidth, 76);
1357 211 : RMF_READ_ULONG(abyHeader, poDS->sHeader.nLastTileHeight, 80);
1358 211 : RMF_READ_ULONG(abyHeader, poDS->sHeader.nLastTileWidth, 84);
1359 211 : RMF_READ_ULONG(abyHeader, poDS->sHeader.nROIOffset, 88);
1360 211 : RMF_READ_ULONG(abyHeader, poDS->sHeader.nROISize, 92);
1361 211 : RMF_READ_ULONG(abyHeader, poDS->sHeader.nClrTblOffset, 96);
1362 211 : RMF_READ_ULONG(abyHeader, poDS->sHeader.nClrTblSize, 100);
1363 211 : RMF_READ_ULONG(abyHeader, poDS->sHeader.nTileTblOffset, 104);
1364 211 : RMF_READ_ULONG(abyHeader, poDS->sHeader.nTileTblSize, 108);
1365 211 : RMF_READ_LONG(abyHeader, poDS->sHeader.iMapType, 124);
1366 211 : RMF_READ_LONG(abyHeader, poDS->sHeader.iProjection, 128);
1367 211 : RMF_READ_LONG(abyHeader, poDS->sHeader.iEPSGCode, 132);
1368 211 : RMF_READ_DOUBLE(abyHeader, poDS->sHeader.dfScale, 136);
1369 211 : RMF_READ_DOUBLE(abyHeader, poDS->sHeader.dfResolution, 144);
1370 211 : RMF_READ_DOUBLE(abyHeader, poDS->sHeader.dfPixelSize, 152);
1371 211 : RMF_READ_DOUBLE(abyHeader, poDS->sHeader.dfLLY, 160);
1372 211 : RMF_READ_DOUBLE(abyHeader, poDS->sHeader.dfLLX, 168);
1373 211 : RMF_READ_DOUBLE(abyHeader, poDS->sHeader.dfStdP1, 176);
1374 211 : RMF_READ_DOUBLE(abyHeader, poDS->sHeader.dfStdP2, 184);
1375 211 : RMF_READ_DOUBLE(abyHeader, poDS->sHeader.dfCenterLong, 192);
1376 211 : RMF_READ_DOUBLE(abyHeader, poDS->sHeader.dfCenterLat, 200);
1377 211 : poDS->sHeader.iCompression = *(abyHeader + 208);
1378 211 : poDS->sHeader.iMaskType = *(abyHeader + 209);
1379 211 : poDS->sHeader.iMaskStep = *(abyHeader + 210);
1380 211 : poDS->sHeader.iFrameFlag = *(abyHeader + 211);
1381 211 : RMF_READ_ULONG(abyHeader, poDS->sHeader.nFlagsTblOffset, 212);
1382 211 : RMF_READ_ULONG(abyHeader, poDS->sHeader.nFlagsTblSize, 216);
1383 211 : RMF_READ_ULONG(abyHeader, poDS->sHeader.nFileSize0, 220);
1384 211 : RMF_READ_ULONG(abyHeader, poDS->sHeader.nFileSize1, 224);
1385 211 : poDS->sHeader.iUnknown = *(abyHeader + 228);
1386 211 : poDS->sHeader.iGeorefFlag = *(abyHeader + 244);
1387 211 : poDS->sHeader.iInverse = *(abyHeader + 245);
1388 211 : poDS->sHeader.iJpegQuality = *(abyHeader + 246);
1389 211 : memcpy(poDS->sHeader.abyInvisibleColors, abyHeader + 248,
1390 : sizeof(poDS->sHeader.abyInvisibleColors));
1391 211 : RMF_READ_DOUBLE(abyHeader, poDS->sHeader.adfElevMinMax[0], 280);
1392 211 : RMF_READ_DOUBLE(abyHeader, poDS->sHeader.adfElevMinMax[1], 288);
1393 211 : RMF_READ_DOUBLE(abyHeader, poDS->sHeader.dfNoData, 296);
1394 :
1395 211 : RMF_READ_ULONG(abyHeader, poDS->sHeader.iElevationUnit, 304);
1396 211 : poDS->sHeader.iElevationType = *(abyHeader + 308);
1397 211 : RMF_READ_ULONG(abyHeader, poDS->sHeader.nExtHdrOffset, 312);
1398 211 : RMF_READ_ULONG(abyHeader, poDS->sHeader.nExtHdrSize, 316);
1399 211 : poDS->SetMetadataItem(MD_SCALE_KEY,
1400 211 : CPLSPrintf("1 : %u", int(poDS->sHeader.dfScale)));
1401 211 : poDS->SetMetadataItem(MD_NAME_KEY,
1402 211 : CPLSPrintf("%s", poDS->sHeader.byName));
1403 211 : poDS->SetMetadataItem(MD_VERSION_KEY,
1404 : CPLSPrintf("%d", poDS->sHeader.iVersion));
1405 211 : poDS->SetMetadataItem(MD_MATH_BASE_MAP_TYPE_KEY,
1406 : CPLSPrintf("%d", poDS->sHeader.iMapType));
1407 211 : poDS->SetMetadataItem(MD_MATH_BASE_PROJECTION_KEY,
1408 : CPLSPrintf("%d", poDS->sHeader.iProjection));
1409 : }
1410 :
1411 211 : if (poDS->sHeader.nTileTblSize % (sizeof(GUInt32) * 2))
1412 : {
1413 0 : CPLError(CE_Warning, CPLE_IllegalArg, "Invalid tile table size.");
1414 0 : delete poDS;
1415 0 : return nullptr;
1416 : }
1417 :
1418 : bool bInvalidTileSize;
1419 : try
1420 : {
1421 : GUInt64 nMaxTileBits =
1422 211 : (CPLSM(static_cast<GUInt64>(2)) *
1423 422 : CPLSM(static_cast<GUInt64>(poDS->sHeader.nTileWidth)) *
1424 422 : CPLSM(static_cast<GUInt64>(poDS->sHeader.nTileHeight)) *
1425 422 : CPLSM(static_cast<GUInt64>(poDS->sHeader.nBitDepth)))
1426 211 : .v();
1427 211 : bInvalidTileSize =
1428 : (nMaxTileBits >
1429 211 : static_cast<GUInt64>(std::numeric_limits<GUInt32>::max()));
1430 : }
1431 0 : catch (...)
1432 : {
1433 0 : bInvalidTileSize = true;
1434 : }
1435 211 : if (bInvalidTileSize)
1436 : {
1437 0 : CPLError(CE_Warning, CPLE_IllegalArg,
1438 : "Invalid tile size. Width %lu, height %lu, bit depth %lu.",
1439 0 : static_cast<unsigned long>(poDS->sHeader.nTileWidth),
1440 0 : static_cast<unsigned long>(poDS->sHeader.nTileHeight),
1441 0 : static_cast<unsigned long>(poDS->sHeader.nBitDepth));
1442 0 : delete poDS;
1443 0 : return nullptr;
1444 : }
1445 :
1446 211 : if (poDS->sHeader.nLastTileWidth > poDS->sHeader.nTileWidth ||
1447 211 : poDS->sHeader.nLastTileHeight > poDS->sHeader.nTileHeight)
1448 : {
1449 0 : CPLError(CE_Warning, CPLE_IllegalArg,
1450 : "Invalid last tile size %lu x %lu. "
1451 : "It can't be greater than %lu x %lu.",
1452 0 : static_cast<unsigned long>(poDS->sHeader.nLastTileWidth),
1453 0 : static_cast<unsigned long>(poDS->sHeader.nLastTileHeight),
1454 0 : static_cast<unsigned long>(poDS->sHeader.nTileWidth),
1455 0 : static_cast<unsigned long>(poDS->sHeader.nTileHeight));
1456 0 : delete poDS;
1457 0 : return nullptr;
1458 : }
1459 :
1460 211 : if (poParentDS != nullptr)
1461 : {
1462 83 : if (0 != memcmp(poDS->sHeader.bySignature,
1463 83 : poParentDS->sHeader.bySignature, RMF_SIGNATURE_SIZE))
1464 : {
1465 2 : CPLError(CE_Warning, CPLE_IllegalArg,
1466 : "Invalid subheader signature.");
1467 2 : delete poDS;
1468 2 : return nullptr;
1469 : }
1470 : }
1471 :
1472 : /* -------------------------------------------------------------------- */
1473 : /* Read the extended header. */
1474 : /* -------------------------------------------------------------------- */
1475 :
1476 209 : if (poDS->sHeader.nExtHdrOffset &&
1477 198 : poDS->sHeader.nExtHdrSize >= RMF_MIN_EXT_HEADER_SIZE)
1478 : {
1479 198 : if (poDS->sHeader.nExtHdrSize > RMF_MAX_EXT_HEADER_SIZE)
1480 : {
1481 0 : CPLError(CE_Failure, CPLE_FileIO, "RMF File malformed");
1482 0 : delete poDS;
1483 0 : return nullptr;
1484 : }
1485 : GByte *pabyExtHeader =
1486 198 : reinterpret_cast<GByte *>(CPLCalloc(poDS->sHeader.nExtHdrSize, 1));
1487 198 : if (pabyExtHeader == nullptr)
1488 : {
1489 0 : delete poDS;
1490 0 : return nullptr;
1491 : }
1492 :
1493 198 : VSIFSeekL(poDS->fp, poDS->GetFileOffset(poDS->sHeader.nExtHdrOffset),
1494 : SEEK_SET);
1495 198 : VSIFReadL(pabyExtHeader, 1, poDS->sHeader.nExtHdrSize, poDS->fp);
1496 :
1497 198 : RMF_READ_LONG(pabyExtHeader, poDS->sExtHeader.nEllipsoid, 24);
1498 198 : RMF_READ_LONG(pabyExtHeader, poDS->sExtHeader.nVertDatum, 28);
1499 198 : RMF_READ_LONG(pabyExtHeader, poDS->sExtHeader.nDatum, 32);
1500 198 : RMF_READ_LONG(pabyExtHeader, poDS->sExtHeader.nZone, 36);
1501 :
1502 198 : CPLFree(pabyExtHeader);
1503 : }
1504 :
1505 209 : CPLDebug("RMF", "Version %d", poDS->sHeader.iVersion);
1506 :
1507 209 : constexpr GUInt32 ROI_MAX_SIZE_TO_AVOID_EXCESSIVE_RAM_USAGE =
1508 : 10 * 1024 * 1024;
1509 : #ifdef DEBUG
1510 :
1511 418 : CPLDebug("RMF",
1512 : "%s image has width %d, height %d, bit depth %d, "
1513 : "compression scheme %d, %s, nodata %f",
1514 209 : (poDS->eRMFType == RMFT_MTW) ? "MTW" : "RSW", poDS->sHeader.nWidth,
1515 : poDS->sHeader.nHeight, poDS->sHeader.nBitDepth,
1516 209 : poDS->sHeader.iCompression,
1517 209 : poDS->bBigEndian ? "big endian" : "little endian",
1518 : poDS->sHeader.dfNoData);
1519 209 : CPLDebug("RMF",
1520 : "Size %d, offset to overview %#lx, user ID %d, "
1521 : "ROI offset %#lx, ROI size %d",
1522 : poDS->sHeader.nSize,
1523 209 : static_cast<unsigned long>(poDS->sHeader.nOvrOffset),
1524 : poDS->sHeader.iUserID,
1525 209 : static_cast<unsigned long>(poDS->sHeader.nROIOffset),
1526 : poDS->sHeader.nROISize);
1527 209 : CPLDebug("RMF", "Map type %d, projection %d, scale %f, resolution %f, ",
1528 : poDS->sHeader.iMapType, poDS->sHeader.iProjection,
1529 : poDS->sHeader.dfScale, poDS->sHeader.dfResolution);
1530 209 : CPLDebug("RMF", "EPSG %d ", (int)poDS->sHeader.iEPSGCode);
1531 209 : CPLDebug("RMF", "Georeferencing: pixel size %f, LLX %f, LLY %f",
1532 : poDS->sHeader.dfPixelSize, poDS->sHeader.dfLLX,
1533 : poDS->sHeader.dfLLY);
1534 :
1535 209 : if (poDS->sHeader.nROIOffset &&
1536 116 : poDS->sHeader.nROISize >= sizeof(RSWFrame) &&
1537 12 : poDS->sHeader.nROISize <= ROI_MAX_SIZE_TO_AVOID_EXCESSIVE_RAM_USAGE)
1538 : {
1539 : GByte *pabyROI = reinterpret_cast<GByte *>(
1540 12 : VSI_MALLOC_VERBOSE(poDS->sHeader.nROISize));
1541 12 : if (pabyROI == nullptr)
1542 : {
1543 0 : delete poDS;
1544 0 : return nullptr;
1545 : }
1546 :
1547 12 : VSIFSeekL(poDS->fp, poDS->GetFileOffset(poDS->sHeader.nROIOffset),
1548 : SEEK_SET);
1549 12 : if (VSIFReadL(pabyROI, poDS->sHeader.nROISize, 1, poDS->fp) != 1)
1550 : {
1551 0 : CPLError(CE_Failure, CPLE_FileIO, "Cannot read ROI");
1552 0 : CPLFree(pabyROI);
1553 0 : delete poDS;
1554 0 : return nullptr;
1555 : }
1556 :
1557 : GInt32 nValue;
1558 :
1559 12 : CPLDebug("RMF", "ROI coordinates:");
1560 : /* coverity[tainted_data] */
1561 3504 : for (GUInt32 i = 0; i + sizeof(nValue) <= poDS->sHeader.nROISize;
1562 3492 : i += sizeof(nValue))
1563 : {
1564 3492 : RMF_READ_LONG(pabyROI, nValue, i);
1565 3492 : CPLDebug("RMF", "%d", nValue);
1566 : }
1567 :
1568 12 : CPLFree(pabyROI);
1569 : }
1570 : #endif
1571 418 : if (poDS->sHeader.nWidth >= INT_MAX || poDS->sHeader.nHeight >= INT_MAX ||
1572 209 : !GDALCheckDatasetDimensions(poDS->sHeader.nWidth,
1573 209 : poDS->sHeader.nHeight))
1574 : {
1575 0 : delete poDS;
1576 0 : return nullptr;
1577 : }
1578 :
1579 : /* -------------------------------------------------------------------- */
1580 : /* Read array of blocks offsets/sizes. */
1581 : /* -------------------------------------------------------------------- */
1582 :
1583 : // To avoid useless excessive memory allocation
1584 209 : if (poDS->sHeader.nTileTblSize > 1000000)
1585 : {
1586 0 : VSIFSeekL(poDS->fp, 0, SEEK_END);
1587 0 : vsi_l_offset nFileSize = VSIFTellL(poDS->fp);
1588 0 : if (nFileSize < poDS->sHeader.nTileTblSize)
1589 : {
1590 0 : delete poDS;
1591 0 : return nullptr;
1592 : }
1593 : }
1594 :
1595 209 : if (VSIFSeekL(poDS->fp, poDS->GetFileOffset(poDS->sHeader.nTileTblOffset),
1596 209 : SEEK_SET) < 0)
1597 : {
1598 0 : delete poDS;
1599 0 : return nullptr;
1600 : }
1601 :
1602 209 : poDS->paiTiles =
1603 209 : reinterpret_cast<GUInt32 *>(VSIMalloc(poDS->sHeader.nTileTblSize));
1604 209 : if (!poDS->paiTiles)
1605 : {
1606 0 : delete poDS;
1607 0 : return nullptr;
1608 : }
1609 :
1610 209 : if (VSIFReadL(poDS->paiTiles, 1, poDS->sHeader.nTileTblSize, poDS->fp) <
1611 209 : poDS->sHeader.nTileTblSize)
1612 : {
1613 9 : CPLDebug("RMF", "Can't read tiles offsets/sizes table.");
1614 9 : delete poDS;
1615 9 : return nullptr;
1616 : }
1617 :
1618 : #ifdef CPL_MSB
1619 : if (!poDS->bBigEndian)
1620 : {
1621 : for (GUInt32 i = 0; i < poDS->sHeader.nTileTblSize / sizeof(GUInt32);
1622 : i++)
1623 : CPL_SWAP32PTR(poDS->paiTiles + i);
1624 : }
1625 : #else
1626 200 : if (poDS->bBigEndian)
1627 : {
1628 30 : for (GUInt32 i = 0; i < poDS->sHeader.nTileTblSize / sizeof(GUInt32);
1629 : i++)
1630 24 : CPL_SWAP32PTR(poDS->paiTiles + i);
1631 : }
1632 : #endif
1633 :
1634 : #ifdef DEBUG
1635 200 : CPLDebug("RMF", "List of block offsets/sizes:");
1636 :
1637 646 : for (GUInt32 i = 0; i < poDS->sHeader.nTileTblSize / sizeof(GUInt32);
1638 446 : i += 2)
1639 : {
1640 446 : CPLDebug("RMF", " %u / %u", poDS->paiTiles[i],
1641 446 : poDS->paiTiles[i + 1]);
1642 : }
1643 : #endif
1644 :
1645 : /* -------------------------------------------------------------------- */
1646 : /* Set up essential image parameters. */
1647 : /* -------------------------------------------------------------------- */
1648 200 : GDALDataType eType = GDT_Byte;
1649 :
1650 200 : poDS->nRasterXSize = poDS->sHeader.nWidth;
1651 200 : poDS->nRasterYSize = poDS->sHeader.nHeight;
1652 :
1653 200 : if (poDS->eRMFType == RMFT_RSW)
1654 : {
1655 126 : switch (poDS->sHeader.nBitDepth)
1656 : {
1657 58 : case 32:
1658 : case 24:
1659 : case 16:
1660 58 : poDS->nBands = 3;
1661 58 : break;
1662 68 : case 1:
1663 : case 4:
1664 : case 8:
1665 68 : if (poParentDS != nullptr &&
1666 26 : poParentDS->poColorTable != nullptr)
1667 : {
1668 26 : poDS->poColorTable = poParentDS->poColorTable->Clone();
1669 : }
1670 : else
1671 : {
1672 : // Allocate memory for colour table and read it
1673 42 : poDS->nColorTableSize = 1 << poDS->sHeader.nBitDepth;
1674 42 : GUInt32 nExpectedColorTableBytes =
1675 42 : poDS->nColorTableSize * 4;
1676 42 : if (nExpectedColorTableBytes > poDS->sHeader.nClrTblSize)
1677 : {
1678 : // We could probably test for strict equality in
1679 : // the above test ???
1680 0 : CPLDebug("RMF",
1681 : "Wrong color table size. "
1682 : "Expected %u, got %u.",
1683 : nExpectedColorTableBytes,
1684 : poDS->sHeader.nClrTblSize);
1685 0 : delete poDS;
1686 0 : return nullptr;
1687 : }
1688 42 : poDS->pabyColorTable = reinterpret_cast<GByte *>(
1689 42 : VSIMalloc(nExpectedColorTableBytes));
1690 42 : if (poDS->pabyColorTable == nullptr)
1691 : {
1692 0 : CPLDebug("RMF", "Can't allocate color table.");
1693 0 : delete poDS;
1694 0 : return nullptr;
1695 : }
1696 42 : if (VSIFSeekL(
1697 : poDS->fp,
1698 : poDS->GetFileOffset(poDS->sHeader.nClrTblOffset),
1699 42 : SEEK_SET) < 0)
1700 : {
1701 0 : CPLDebug("RMF", "Can't seek to color table location.");
1702 0 : delete poDS;
1703 0 : return nullptr;
1704 : }
1705 42 : if (VSIFReadL(poDS->pabyColorTable, 1,
1706 : nExpectedColorTableBytes,
1707 42 : poDS->fp) < nExpectedColorTableBytes)
1708 : {
1709 0 : CPLDebug("RMF", "Can't read color table.");
1710 0 : delete poDS;
1711 0 : return nullptr;
1712 : }
1713 :
1714 42 : poDS->poColorTable = new GDALColorTable();
1715 9326 : for (GUInt32 i = 0; i < poDS->nColorTableSize; i++)
1716 : {
1717 9284 : const GDALColorEntry oEntry = {
1718 9284 : poDS->pabyColorTable[i * 4], // Red
1719 9284 : poDS->pabyColorTable[i * 4 + 1], // Green
1720 9284 : poDS->pabyColorTable[i * 4 + 2], // Blue
1721 : 255 // Alpha
1722 9284 : };
1723 :
1724 9284 : poDS->poColorTable->SetColorEntry(i, &oEntry);
1725 : }
1726 : }
1727 68 : poDS->nBands = 1;
1728 68 : break;
1729 0 : default:
1730 0 : CPLError(CE_Warning, CPLE_IllegalArg,
1731 : "Invalid RSW bit depth %lu.",
1732 0 : static_cast<unsigned long>(poDS->sHeader.nBitDepth));
1733 0 : delete poDS;
1734 0 : return nullptr;
1735 : }
1736 126 : eType = GDT_Byte;
1737 : }
1738 : else
1739 : {
1740 74 : poDS->nBands = 1;
1741 74 : if (poDS->sHeader.nBitDepth == 8)
1742 : {
1743 0 : eType = GDT_Byte;
1744 : }
1745 74 : else if (poDS->sHeader.nBitDepth == 16)
1746 : {
1747 0 : eType = GDT_Int16;
1748 : }
1749 74 : else if (poDS->sHeader.nBitDepth == 32)
1750 : {
1751 9 : eType = GDT_Int32;
1752 : }
1753 65 : else if (poDS->sHeader.nBitDepth == 64)
1754 : {
1755 65 : eType = GDT_Float64;
1756 : }
1757 : else
1758 : {
1759 0 : CPLError(CE_Warning, CPLE_IllegalArg, "Invalid MTW bit depth %lu.",
1760 0 : static_cast<unsigned long>(poDS->sHeader.nBitDepth));
1761 0 : delete poDS;
1762 0 : return nullptr;
1763 : }
1764 : }
1765 :
1766 200 : if (poDS->sHeader.nTileWidth == 0 || poDS->sHeader.nTileWidth > INT_MAX ||
1767 200 : poDS->sHeader.nTileHeight == 0 || poDS->sHeader.nTileHeight > INT_MAX)
1768 : {
1769 0 : CPLDebug("RMF", "Invalid tile dimension : %u x %u",
1770 : poDS->sHeader.nTileWidth, poDS->sHeader.nTileHeight);
1771 0 : delete poDS;
1772 0 : return nullptr;
1773 : }
1774 :
1775 200 : const int nDataSize = GDALGetDataTypeSizeBytes(eType);
1776 200 : const int nBlockXSize = static_cast<int>(poDS->sHeader.nTileWidth);
1777 200 : const int nBlockYSize = static_cast<int>(poDS->sHeader.nTileHeight);
1778 200 : if (nDataSize == 0 || nBlockXSize > INT_MAX / nBlockYSize ||
1779 200 : nBlockYSize > INT_MAX / nDataSize ||
1780 200 : nBlockXSize > INT_MAX / (nBlockYSize * nDataSize))
1781 : {
1782 0 : CPLDebug("RMF", "Too big raster / tile dimension");
1783 0 : delete poDS;
1784 0 : return nullptr;
1785 : }
1786 :
1787 200 : poDS->nXTiles = DIV_ROUND_UP(poDS->nRasterXSize, nBlockXSize);
1788 200 : poDS->nYTiles = DIV_ROUND_UP(poDS->nRasterYSize, nBlockYSize);
1789 :
1790 : #ifdef DEBUG
1791 200 : CPLDebug("RMF", "Image is %d tiles wide, %d tiles long", poDS->nXTiles,
1792 : poDS->nYTiles);
1793 : #endif
1794 :
1795 : /* -------------------------------------------------------------------- */
1796 : /* Choose compression scheme. */
1797 : /* -------------------------------------------------------------------- */
1798 200 : if (CE_None != poDS->SetupCompression(eType, poOpenInfo->pszFilename))
1799 : {
1800 0 : delete poDS;
1801 0 : return nullptr;
1802 : }
1803 :
1804 200 : if (poOpenInfo->eAccess == GA_Update)
1805 : {
1806 20 : if (poParentDS == nullptr)
1807 : {
1808 12 : if (CE_None !=
1809 12 : poDS->InitCompressorData(poOpenInfo->papszOpenOptions))
1810 : {
1811 0 : delete poDS;
1812 0 : return nullptr;
1813 : }
1814 : }
1815 : else
1816 : {
1817 8 : poDS->poCompressData = poParentDS->poCompressData;
1818 : }
1819 : }
1820 : /* -------------------------------------------------------------------- */
1821 : /* Create band information objects. */
1822 : /* -------------------------------------------------------------------- */
1823 516 : for (int iBand = 1; iBand <= poDS->nBands; iBand++)
1824 316 : poDS->SetBand(iBand, new RMFRasterBand(poDS, iBand, eType));
1825 :
1826 200 : poDS->SetupNBits();
1827 :
1828 200 : if (poDS->nBands > 1)
1829 : {
1830 58 : poDS->SetMetadataItem("INTERLEAVE", "PIXEL", "IMAGE_STRUCTURE");
1831 : }
1832 : /* -------------------------------------------------------------------- */
1833 : /* Set up projection. */
1834 : /* */
1835 : /* XXX: If projection value is not specified, but image still have */
1836 : /* georeferencing information, assume Gauss-Kruger projection. */
1837 : /* -------------------------------------------------------------------- */
1838 200 : if (poDS->sHeader.iEPSGCode > RMF_EPSG_MIN_CODE ||
1839 186 : poDS->sHeader.iProjection > 0 ||
1840 117 : (poDS->sHeader.dfPixelSize != 0.0 && poDS->sHeader.dfLLX != 0.0 &&
1841 15 : poDS->sHeader.dfLLY != 0.0))
1842 : {
1843 98 : GInt32 nProj =
1844 98 : (poDS->sHeader.iProjection) ? poDS->sHeader.iProjection : 1;
1845 98 : double padfPrjParams[8] = {poDS->sHeader.dfStdP1,
1846 98 : poDS->sHeader.dfStdP2,
1847 98 : poDS->sHeader.dfCenterLat,
1848 98 : poDS->sHeader.dfCenterLong,
1849 : 1.0,
1850 : 0.0,
1851 : 0.0,
1852 98 : 0.0};
1853 :
1854 : // XXX: Compute zone number for Gauss-Kruger (Transverse Mercator)
1855 : // projection if it is not specified.
1856 98 : if (nProj == 1L && poDS->sHeader.dfCenterLong == 0.0)
1857 : {
1858 6 : if (poDS->sExtHeader.nZone == 0)
1859 : {
1860 0 : double centerXCoord =
1861 0 : poDS->sHeader.dfLLX +
1862 0 : (poDS->nRasterXSize * poDS->sHeader.dfPixelSize / 2.0);
1863 0 : padfPrjParams[7] = floor((centerXCoord - 500000.0) / 1000000.0);
1864 : }
1865 : else
1866 : {
1867 6 : padfPrjParams[7] = poDS->sExtHeader.nZone;
1868 : }
1869 : }
1870 :
1871 98 : OGRErr res = OGRERR_FAILURE;
1872 98 : if (nProj >= 0 &&
1873 88 : (poDS->sExtHeader.nDatum >= 0 || poDS->sExtHeader.nEllipsoid >= 0))
1874 : {
1875 88 : res = poDS->m_oSRS.importFromPanorama(
1876 88 : nProj, poDS->sExtHeader.nDatum, poDS->sExtHeader.nEllipsoid,
1877 : padfPrjParams);
1878 : }
1879 :
1880 111 : if (poDS->sHeader.iEPSGCode > RMF_EPSG_MIN_CODE &&
1881 13 : (OGRERR_NONE != res || poDS->m_oSRS.IsLocal()))
1882 : {
1883 1 : res = poDS->m_oSRS.importFromEPSG(poDS->sHeader.iEPSGCode);
1884 : }
1885 :
1886 : const char *pszSetVertCS =
1887 98 : CSLFetchNameValueDef(poOpenInfo->papszOpenOptions, "RMF_SET_VERTCS",
1888 : CPLGetConfigOption("RMF_SET_VERTCS", "NO"));
1889 98 : if (CPLTestBool(pszSetVertCS) && res == OGRERR_NONE &&
1890 0 : poDS->sExtHeader.nVertDatum > 0)
1891 : {
1892 0 : poDS->m_oSRS.importVertCSFromPanorama(poDS->sExtHeader.nVertDatum);
1893 : }
1894 : }
1895 :
1896 : /* -------------------------------------------------------------------- */
1897 : /* Set up georeferencing. */
1898 : /* -------------------------------------------------------------------- */
1899 200 : if ((poDS->eRMFType == RMFT_RSW && poDS->sHeader.iGeorefFlag) ||
1900 128 : (poDS->eRMFType == RMFT_MTW && poDS->sHeader.dfPixelSize != 0.0))
1901 : {
1902 146 : poDS->adfGeoTransform[0] = poDS->sHeader.dfLLX;
1903 146 : poDS->adfGeoTransform[3] =
1904 146 : poDS->sHeader.dfLLY +
1905 146 : poDS->nRasterYSize * poDS->sHeader.dfPixelSize;
1906 146 : poDS->adfGeoTransform[1] = poDS->sHeader.dfPixelSize;
1907 146 : poDS->adfGeoTransform[5] = -poDS->sHeader.dfPixelSize;
1908 146 : poDS->adfGeoTransform[2] = 0.0;
1909 146 : poDS->adfGeoTransform[4] = 0.0;
1910 : }
1911 :
1912 : /* -------------------------------------------------------------------- */
1913 : /* Set units. */
1914 : /* -------------------------------------------------------------------- */
1915 :
1916 200 : if (poDS->eRMFType == RMFT_MTW)
1917 : {
1918 74 : CPLFree(poDS->pszUnitType);
1919 74 : poDS->pszUnitType = RMFUnitTypeToStr(poDS->sHeader.iElevationUnit);
1920 : }
1921 :
1922 : /* -------------------------------------------------------------------- */
1923 : /* Report some other dataset related information. */
1924 : /* -------------------------------------------------------------------- */
1925 :
1926 200 : if (poDS->eRMFType == RMFT_MTW)
1927 : {
1928 74 : char szTemp[256] = {};
1929 :
1930 74 : snprintf(szTemp, sizeof(szTemp), "%g", poDS->sHeader.adfElevMinMax[0]);
1931 74 : poDS->SetMetadataItem("ELEVATION_MINIMUM", szTemp);
1932 :
1933 74 : snprintf(szTemp, sizeof(szTemp), "%g", poDS->sHeader.adfElevMinMax[1]);
1934 74 : poDS->SetMetadataItem("ELEVATION_MAXIMUM", szTemp);
1935 :
1936 74 : poDS->SetMetadataItem("ELEVATION_UNITS", poDS->pszUnitType);
1937 :
1938 74 : snprintf(szTemp, sizeof(szTemp), "%d", poDS->sHeader.iElevationType);
1939 74 : poDS->SetMetadataItem("ELEVATION_TYPE", szTemp);
1940 : }
1941 :
1942 : /* -------------------------------------------------------------------- */
1943 : /* Check for overviews. */
1944 : /* -------------------------------------------------------------------- */
1945 200 : if (nNextHeaderOffset == 0 && poParentDS == nullptr)
1946 : {
1947 119 : poDS->oOvManager.Initialize(poDS, poOpenInfo->pszFilename);
1948 : }
1949 :
1950 : /* Set frame */
1951 200 : if (poDS->sHeader.nROIOffset &&
1952 107 : poDS->sHeader.nROISize >= sizeof(RSWFrame) &&
1953 12 : poDS->sHeader.nROISize <= ROI_MAX_SIZE_TO_AVOID_EXCESSIVE_RAM_USAGE)
1954 : {
1955 : GByte *pabyROI = reinterpret_cast<GByte *>(
1956 12 : VSI_MALLOC_VERBOSE(poDS->sHeader.nROISize));
1957 12 : if (pabyROI == nullptr)
1958 : {
1959 0 : delete poDS;
1960 0 : return nullptr;
1961 : }
1962 :
1963 12 : VSIFSeekL(poDS->fp, poDS->GetFileOffset(poDS->sHeader.nROIOffset),
1964 : SEEK_SET);
1965 12 : if (VSIFReadL(pabyROI, poDS->sHeader.nROISize, 1, poDS->fp) != 1)
1966 : {
1967 0 : CPLError(CE_Failure, CPLE_FileIO, "Cannot read ROI");
1968 0 : CPLFree(pabyROI);
1969 0 : delete poDS;
1970 0 : return nullptr;
1971 : }
1972 :
1973 : GInt32 nFrameType;
1974 12 : RMF_READ_LONG(pabyROI, nFrameType, 0);
1975 12 : if (nFrameType == nPolygonType)
1976 : {
1977 24 : CPLString osWKT = "POLYGON((";
1978 12 : bool bFirst = true;
1979 :
1980 12 : CPLDebug("RMF", "ROI coordinates:");
1981 : /* coverity[tainted_data] */
1982 12 : for (GUInt32 i = sizeof(RSWFrame);
1983 1734 : i + sizeof(RSWFrameCoord) <= poDS->sHeader.nROISize;
1984 1722 : i += sizeof(RSWFrameCoord))
1985 : {
1986 : GInt32 nX, nY;
1987 1722 : RMF_READ_LONG(pabyROI, nX, i);
1988 1722 : RMF_READ_LONG(pabyROI, nY, i + 4);
1989 :
1990 1722 : CPLDebug("RMF", "X: %d, Y: %d", nX, nY);
1991 :
1992 1722 : double dfX = poDS->adfGeoTransform[0] +
1993 1722 : nX * poDS->adfGeoTransform[1] +
1994 1722 : nY * poDS->adfGeoTransform[2];
1995 1722 : double dfY = poDS->adfGeoTransform[3] +
1996 1722 : nX * poDS->adfGeoTransform[4] +
1997 1722 : nY * poDS->adfGeoTransform[5];
1998 :
1999 1722 : if (bFirst)
2000 : {
2001 12 : osWKT += CPLSPrintf("%f %f", dfX, dfY);
2002 12 : bFirst = false;
2003 : }
2004 : else
2005 : {
2006 1710 : osWKT += CPLSPrintf(", %f %f", dfX, dfY);
2007 : }
2008 : }
2009 12 : osWKT += "))";
2010 12 : CPLDebug("RMF", "Frame WKT: %s", osWKT.c_str());
2011 12 : poDS->SetMetadataItem(MD_FRAME_KEY, osWKT);
2012 : }
2013 12 : CPLFree(pabyROI);
2014 : }
2015 :
2016 : #undef RMF_READ_DOUBLE
2017 : #undef RMF_READ_LONG
2018 : #undef RMF_READ_ULONG
2019 :
2020 200 : if (poDS->sHeader.nFlagsTblOffset && poDS->sHeader.nFlagsTblSize)
2021 : {
2022 107 : VSIFSeekL(poDS->fp, poDS->GetFileOffset(poDS->sHeader.nFlagsTblOffset),
2023 : SEEK_SET);
2024 107 : CPLDebug("RMF", "Blocks flags:");
2025 : /* coverity[tainted_data] */
2026 416 : for (GUInt32 i = 0; i < poDS->sHeader.nFlagsTblSize; i += sizeof(GByte))
2027 : {
2028 : GByte nValue;
2029 309 : if (VSIFReadL(&nValue, 1, sizeof(nValue), poDS->fp) !=
2030 : sizeof(nValue))
2031 : {
2032 0 : CPLDebug("RMF", "Cannot read Block flag at index %u", i);
2033 0 : break;
2034 : }
2035 309 : CPLDebug("RMF", "Block %u -- flag %d", i, nValue);
2036 : }
2037 : }
2038 200 : return poDS;
2039 : }
2040 :
2041 : /************************************************************************/
2042 : /* Create() */
2043 : /************************************************************************/
2044 89 : GDALDataset *RMFDataset::Create(const char *pszFilename, int nXSize, int nYSize,
2045 : int nBandsIn, GDALDataType eType,
2046 : char **papszParamList)
2047 : {
2048 89 : return Create(pszFilename, nXSize, nYSize, nBandsIn, eType, papszParamList,
2049 89 : nullptr, 1.0);
2050 : }
2051 :
2052 123 : GDALDataset *RMFDataset::Create(const char *pszFilename, int nXSize, int nYSize,
2053 : int nBandsIn, GDALDataType eType,
2054 : char **papszParamList, RMFDataset *poParentDS,
2055 : double dfOvFactor)
2056 :
2057 : {
2058 123 : if (nBandsIn != 1 && nBandsIn != 3)
2059 : {
2060 7 : CPLError(CE_Failure, CPLE_NotSupported,
2061 : "RMF driver doesn't support %d bands. Must be 1 or 3.",
2062 : nBandsIn);
2063 :
2064 7 : return nullptr;
2065 : }
2066 :
2067 116 : if (nBandsIn == 1 && eType != GDT_Byte && eType != GDT_Int16 &&
2068 52 : eType != GDT_Int32 && eType != GDT_Float64)
2069 : {
2070 17 : CPLError(
2071 : CE_Failure, CPLE_AppDefined,
2072 : "Attempt to create RMF dataset with an illegal data type (%s), "
2073 : "only Byte, Int16, Int32 and Float64 types supported "
2074 : "by the format for single-band images.",
2075 : GDALGetDataTypeName(eType));
2076 :
2077 17 : return nullptr;
2078 : }
2079 :
2080 99 : if (nBandsIn == 3 && eType != GDT_Byte)
2081 : {
2082 13 : CPLError(
2083 : CE_Failure, CPLE_AppDefined,
2084 : "Attempt to create RMF dataset with an illegal data type (%s), "
2085 : "only Byte type supported by the format for three-band images.",
2086 : GDALGetDataTypeName(eType));
2087 :
2088 13 : return nullptr;
2089 : }
2090 :
2091 : /* -------------------------------------------------------------------- */
2092 : /* Create the dataset. */
2093 : /* -------------------------------------------------------------------- */
2094 86 : RMFDataset *poDS = new RMFDataset();
2095 :
2096 86 : GUInt32 nBlockXSize =
2097 86 : (nXSize < RMF_DEFAULT_BLOCKXSIZE) ? nXSize : RMF_DEFAULT_BLOCKXSIZE;
2098 86 : GUInt32 nBlockYSize =
2099 86 : (nYSize < RMF_DEFAULT_BLOCKYSIZE) ? nYSize : RMF_DEFAULT_BLOCKYSIZE;
2100 : double dfScale;
2101 : double dfResolution;
2102 : double dfPixelSize;
2103 86 : if (poParentDS == nullptr)
2104 : {
2105 52 : poDS->fp = VSIFOpenL(pszFilename, "w+b");
2106 52 : if (poDS->fp == nullptr)
2107 : {
2108 3 : CPLError(CE_Failure, CPLE_OpenFailed, "Unable to create file %s.",
2109 : pszFilename);
2110 3 : delete poDS;
2111 3 : return nullptr;
2112 : }
2113 :
2114 : const char *pszScaleValue =
2115 49 : CSLFetchNameValue(papszParamList, MD_SCALE_KEY);
2116 49 : if (pszScaleValue != nullptr && CPLStrnlen(pszScaleValue, 10) > 4)
2117 : {
2118 0 : dfScale = atof(pszScaleValue + 4);
2119 : }
2120 : else
2121 : {
2122 49 : dfScale = RMF_DEFAULT_SCALE;
2123 : }
2124 49 : dfResolution = RMF_DEFAULT_RESOLUTION;
2125 49 : dfPixelSize = 1;
2126 :
2127 49 : if (CPLFetchBool(papszParamList, "MTW", false))
2128 12 : poDS->eRMFType = RMFT_MTW;
2129 : else
2130 37 : poDS->eRMFType = RMFT_RSW;
2131 :
2132 49 : GUInt32 iVersion = RMF_VERSION;
2133 49 : const char *pszRMFHUGE = CSLFetchNameValue(papszParamList, "RMFHUGE");
2134 :
2135 49 : if (pszRMFHUGE == nullptr)
2136 35 : pszRMFHUGE = "NO"; // Keep old behavior by default
2137 :
2138 49 : if (EQUAL(pszRMFHUGE, "NO"))
2139 : {
2140 42 : iVersion = RMF_VERSION;
2141 : }
2142 7 : else if (EQUAL(pszRMFHUGE, "YES"))
2143 : {
2144 7 : iVersion = RMF_VERSION_HUGE;
2145 : }
2146 0 : else if (EQUAL(pszRMFHUGE, "IF_SAFER"))
2147 : {
2148 : const double dfImageSize =
2149 0 : static_cast<double>(nXSize) * static_cast<double>(nYSize) *
2150 0 : static_cast<double>(nBandsIn) *
2151 0 : static_cast<double>(GDALGetDataTypeSizeBytes(eType));
2152 0 : if (dfImageSize > 3.0 * 1024.0 * 1024.0 * 1024.0)
2153 : {
2154 0 : iVersion = RMF_VERSION_HUGE;
2155 : }
2156 : else
2157 : {
2158 0 : iVersion = RMF_VERSION;
2159 : }
2160 : }
2161 :
2162 49 : const char *pszValue = CSLFetchNameValue(papszParamList, "BLOCKXSIZE");
2163 49 : if (pszValue != nullptr)
2164 1 : nBlockXSize = atoi(pszValue);
2165 49 : if (static_cast<int>(nBlockXSize) <= 0)
2166 0 : nBlockXSize = RMF_DEFAULT_BLOCKXSIZE;
2167 :
2168 49 : pszValue = CSLFetchNameValue(papszParamList, "BLOCKYSIZE");
2169 49 : if (pszValue != nullptr)
2170 1 : nBlockYSize = atoi(pszValue);
2171 49 : if (static_cast<int>(nBlockYSize) <= 0)
2172 0 : nBlockYSize = RMF_DEFAULT_BLOCKXSIZE;
2173 :
2174 49 : if (poDS->eRMFType == RMFT_MTW)
2175 12 : memcpy(poDS->sHeader.bySignature, RMF_SigMTW, RMF_SIGNATURE_SIZE);
2176 : else
2177 37 : memcpy(poDS->sHeader.bySignature, RMF_SigRSW, RMF_SIGNATURE_SIZE);
2178 49 : poDS->sHeader.iVersion = iVersion;
2179 49 : poDS->sHeader.nOvrOffset = 0x00;
2180 : }
2181 : else
2182 : {
2183 34 : poDS->fp = poParentDS->fp;
2184 34 : memcpy(poDS->sHeader.bySignature, poParentDS->sHeader.bySignature,
2185 : RMF_SIGNATURE_SIZE);
2186 34 : poDS->sHeader.iVersion = poParentDS->sHeader.iVersion;
2187 34 : poDS->eRMFType = poParentDS->eRMFType;
2188 34 : nBlockXSize = poParentDS->sHeader.nTileWidth;
2189 34 : nBlockYSize = poParentDS->sHeader.nTileHeight;
2190 34 : dfScale = poParentDS->sHeader.dfScale;
2191 34 : dfResolution = poParentDS->sHeader.dfResolution / dfOvFactor;
2192 34 : dfPixelSize = poParentDS->sHeader.dfPixelSize * dfOvFactor;
2193 :
2194 34 : poDS->nHeaderOffset = poParentDS->GetLastOffset();
2195 34 : poParentDS->sHeader.nOvrOffset =
2196 34 : poDS->GetRMFOffset(poDS->nHeaderOffset, &poDS->nHeaderOffset);
2197 34 : poParentDS->bHeaderDirty = true;
2198 34 : VSIFSeekL(poDS->fp, poDS->nHeaderOffset, SEEK_SET);
2199 34 : poDS->poParentDS = poParentDS;
2200 34 : CPLDebug("RMF",
2201 : "Create overview subfile at " CPL_FRMT_GUIB
2202 : " with size %dx%d, parent overview offset %d",
2203 : poDS->nHeaderOffset, nXSize, nYSize,
2204 : poParentDS->sHeader.nOvrOffset);
2205 : }
2206 : /* -------------------------------------------------------------------- */
2207 : /* Fill the RMFHeader */
2208 : /* -------------------------------------------------------------------- */
2209 83 : CPLDebug("RMF", "Version %d", poDS->sHeader.iVersion);
2210 :
2211 83 : poDS->sHeader.iUserID = 0x00;
2212 83 : memset(poDS->sHeader.byName, 0, sizeof(poDS->sHeader.byName));
2213 83 : poDS->sHeader.nBitDepth = GDALGetDataTypeSizeBits(eType) * nBandsIn;
2214 83 : poDS->sHeader.nHeight = nYSize;
2215 83 : poDS->sHeader.nWidth = nXSize;
2216 83 : poDS->sHeader.nTileWidth = nBlockXSize;
2217 83 : poDS->sHeader.nTileHeight = nBlockYSize;
2218 :
2219 83 : poDS->nXTiles = poDS->sHeader.nXTiles =
2220 83 : (nXSize + poDS->sHeader.nTileWidth - 1) / poDS->sHeader.nTileWidth;
2221 83 : poDS->nYTiles = poDS->sHeader.nYTiles =
2222 83 : (nYSize + poDS->sHeader.nTileHeight - 1) / poDS->sHeader.nTileHeight;
2223 83 : poDS->sHeader.nLastTileHeight = nYSize % poDS->sHeader.nTileHeight;
2224 83 : if (!poDS->sHeader.nLastTileHeight)
2225 44 : poDS->sHeader.nLastTileHeight = poDS->sHeader.nTileHeight;
2226 83 : poDS->sHeader.nLastTileWidth = nXSize % poDS->sHeader.nTileWidth;
2227 83 : if (!poDS->sHeader.nLastTileWidth)
2228 40 : poDS->sHeader.nLastTileWidth = poDS->sHeader.nTileWidth;
2229 :
2230 : // poDS->sHeader.nROIOffset = 0x00;
2231 : // poDS->sHeader.nROISize = 0x00;
2232 :
2233 83 : vsi_l_offset nCurPtr = poDS->nHeaderOffset + RMF_HEADER_SIZE;
2234 :
2235 : // Extended header
2236 83 : poDS->sHeader.nExtHdrOffset = poDS->GetRMFOffset(nCurPtr, &nCurPtr);
2237 83 : poDS->sHeader.nExtHdrSize = RMF_EXT_HEADER_SIZE;
2238 83 : nCurPtr += poDS->sHeader.nExtHdrSize;
2239 :
2240 : // Color table
2241 83 : if (poDS->eRMFType == RMFT_RSW && nBandsIn == 1)
2242 : {
2243 34 : if (poDS->sHeader.nBitDepth > 8)
2244 : {
2245 6 : CPLError(CE_Failure, CPLE_AppDefined,
2246 : "Cannot create color table of RSW with nBitDepth = %d. "
2247 : "Retry with MTW ?",
2248 : poDS->sHeader.nBitDepth);
2249 6 : delete poDS;
2250 6 : return nullptr;
2251 : }
2252 :
2253 28 : poDS->sHeader.nClrTblOffset = poDS->GetRMFOffset(nCurPtr, &nCurPtr);
2254 28 : poDS->nColorTableSize = 1 << poDS->sHeader.nBitDepth;
2255 28 : poDS->sHeader.nClrTblSize = poDS->nColorTableSize * 4;
2256 28 : poDS->pabyColorTable = reinterpret_cast<GByte *>(
2257 28 : VSI_MALLOC_VERBOSE(poDS->sHeader.nClrTblSize));
2258 28 : if (poDS->pabyColorTable == nullptr)
2259 : {
2260 0 : delete poDS;
2261 0 : return nullptr;
2262 : }
2263 7196 : for (GUInt32 i = 0; i < poDS->nColorTableSize; i++)
2264 : {
2265 7168 : poDS->pabyColorTable[i * 4] = poDS->pabyColorTable[i * 4 + 1] =
2266 7168 : poDS->pabyColorTable[i * 4 + 2] = (GByte)i;
2267 7168 : poDS->pabyColorTable[i * 4 + 3] = 0;
2268 : }
2269 28 : nCurPtr += poDS->sHeader.nClrTblSize;
2270 : }
2271 : else
2272 : {
2273 49 : poDS->sHeader.nClrTblOffset = 0x00;
2274 49 : poDS->sHeader.nClrTblSize = 0x00;
2275 : }
2276 :
2277 : // Add room for ROI (frame)
2278 77 : poDS->sHeader.nROIOffset = poDS->GetRMFOffset(nCurPtr, &nCurPtr);
2279 77 : poDS->sHeader.nROISize = 0x00;
2280 77 : nCurPtr +=
2281 : sizeof(RSWFrame) +
2282 : sizeof(RSWFrameCoord) *
2283 : nMaxFramePointCount; // Allocate nMaxFramePointCount coordinates for frame
2284 :
2285 : // Add blocks flags
2286 77 : poDS->sHeader.nFlagsTblOffset = poDS->GetRMFOffset(nCurPtr, &nCurPtr);
2287 77 : poDS->sHeader.nFlagsTblSize =
2288 77 : sizeof(GByte) * poDS->sHeader.nXTiles * poDS->sHeader.nYTiles;
2289 77 : nCurPtr += poDS->sHeader.nFlagsTblSize;
2290 :
2291 : // Blocks table
2292 77 : poDS->sHeader.nTileTblOffset = poDS->GetRMFOffset(nCurPtr, &nCurPtr);
2293 77 : poDS->sHeader.nTileTblSize =
2294 77 : 2 * sizeof(GUInt32) * poDS->sHeader.nXTiles * poDS->sHeader.nYTiles;
2295 77 : poDS->paiTiles =
2296 77 : reinterpret_cast<GUInt32 *>(CPLCalloc(poDS->sHeader.nTileTblSize, 1));
2297 : // nCurPtr += poDS->sHeader.nTileTblSize;
2298 77 : const GUInt32 nTileSize = poDS->sHeader.nTileWidth *
2299 77 : poDS->sHeader.nTileHeight *
2300 77 : GDALGetDataTypeSizeBytes(eType);
2301 77 : poDS->sHeader.nSize =
2302 77 : poDS->paiTiles[poDS->sHeader.nTileTblSize / 4 - 2] + nTileSize;
2303 :
2304 : // Elevation units
2305 77 : poDS->sHeader.iElevationUnit = RMFStrToUnitType(poDS->pszUnitType);
2306 :
2307 77 : poDS->sHeader.iMapType = -1;
2308 77 : poDS->sHeader.iProjection = -1;
2309 77 : poDS->sHeader.iEPSGCode = -1;
2310 77 : poDS->sHeader.dfScale = dfScale;
2311 77 : poDS->sHeader.dfResolution = dfResolution;
2312 77 : poDS->sHeader.dfPixelSize = dfPixelSize;
2313 77 : poDS->sHeader.iMaskType = 0;
2314 77 : poDS->sHeader.iMaskStep = 0;
2315 77 : poDS->sHeader.iFrameFlag = 1; // 1 - Frame not using
2316 : // poDS->sHeader.nFlagsTblOffset = 0x00;
2317 : // poDS->sHeader.nFlagsTblSize = 0x00;
2318 77 : poDS->sHeader.nFileSize0 = 0x00;
2319 77 : poDS->sHeader.nFileSize1 = 0x00;
2320 77 : poDS->sHeader.iUnknown = 0;
2321 77 : poDS->sHeader.iGeorefFlag = 0;
2322 77 : poDS->sHeader.iInverse = 0;
2323 77 : poDS->sHeader.iJpegQuality = 0;
2324 77 : memset(poDS->sHeader.abyInvisibleColors, 0,
2325 : sizeof(poDS->sHeader.abyInvisibleColors));
2326 77 : poDS->sHeader.iElevationType = 0;
2327 :
2328 77 : poDS->nRasterXSize = nXSize;
2329 77 : poDS->nRasterYSize = nYSize;
2330 77 : poDS->eAccess = GA_Update;
2331 77 : poDS->nBands = nBandsIn;
2332 :
2333 77 : if (poParentDS == nullptr)
2334 : {
2335 43 : poDS->sHeader.adfElevMinMax[0] = 0.0;
2336 43 : poDS->sHeader.adfElevMinMax[1] = 0.0;
2337 43 : poDS->sHeader.dfNoData = 0.0;
2338 43 : poDS->sHeader.iCompression =
2339 43 : GetCompressionType(CSLFetchNameValue(papszParamList, "COMPRESS"));
2340 43 : if (CE_None != poDS->InitCompressorData(papszParamList))
2341 : {
2342 0 : delete poDS;
2343 0 : return nullptr;
2344 : }
2345 :
2346 43 : if (poDS->sHeader.iCompression == RMF_COMPRESSION_JPEG)
2347 : {
2348 : const char *pszJpegQuality =
2349 1 : CSLFetchNameValue(papszParamList, "JPEG_QUALITY");
2350 1 : if (pszJpegQuality == nullptr)
2351 : {
2352 1 : poDS->sHeader.iJpegQuality = 75;
2353 : }
2354 : else
2355 : {
2356 0 : int iJpegQuality = atoi(pszJpegQuality);
2357 0 : if (iJpegQuality < 10 || iJpegQuality > 100)
2358 : {
2359 0 : CPLError(CE_Failure, CPLE_IllegalArg,
2360 : "JPEG_QUALITY=%s is not a legal value in the "
2361 : "range 10-100.\n"
2362 : "Defaulting to 75",
2363 : pszJpegQuality);
2364 0 : iJpegQuality = 75;
2365 : }
2366 0 : poDS->sHeader.iJpegQuality = static_cast<GByte>(iJpegQuality);
2367 : }
2368 : }
2369 :
2370 43 : if (CE_None != poDS->SetupCompression(eType, pszFilename))
2371 : {
2372 0 : delete poDS;
2373 0 : return nullptr;
2374 : }
2375 : }
2376 : else
2377 : {
2378 34 : poDS->sHeader.adfElevMinMax[0] = poParentDS->sHeader.adfElevMinMax[0];
2379 34 : poDS->sHeader.adfElevMinMax[1] = poParentDS->sHeader.adfElevMinMax[1];
2380 34 : poDS->sHeader.dfNoData = poParentDS->sHeader.dfNoData;
2381 34 : poDS->sHeader.iCompression = poParentDS->sHeader.iCompression;
2382 34 : poDS->sHeader.iJpegQuality = poParentDS->sHeader.iJpegQuality;
2383 34 : poDS->Decompress = poParentDS->Decompress;
2384 34 : poDS->Compress = poParentDS->Compress;
2385 34 : poDS->poCompressData = poParentDS->poCompressData;
2386 : }
2387 :
2388 77 : if (nBandsIn > 1)
2389 : {
2390 13 : poDS->SetMetadataItem("INTERLEAVE", "PIXEL", "IMAGE_STRUCTURE");
2391 : }
2392 :
2393 77 : poDS->WriteHeader();
2394 :
2395 : /* -------------------------------------------------------------------- */
2396 : /* Create band information objects. */
2397 : /* -------------------------------------------------------------------- */
2398 180 : for (int iBand = 1; iBand <= poDS->nBands; iBand++)
2399 103 : poDS->SetBand(iBand, new RMFRasterBand(poDS, iBand, eType));
2400 :
2401 77 : poDS->SetupNBits();
2402 :
2403 77 : return GDALDataset::FromHandle(poDS);
2404 : }
2405 :
2406 : // GIS Panorama 11 was introduced new format for huge files (greater than 3 Gb)
2407 3859 : vsi_l_offset RMFDataset::GetFileOffset(GUInt32 iRMFOffset) const
2408 : {
2409 3859 : if (sHeader.iVersion >= RMF_VERSION_HUGE)
2410 : {
2411 1142 : return ((vsi_l_offset)iRMFOffset) * RMF_HUGE_OFFSET_FACTOR;
2412 : }
2413 :
2414 2717 : return (vsi_l_offset)iRMFOffset;
2415 : }
2416 :
2417 966 : GUInt32 RMFDataset::GetRMFOffset(vsi_l_offset nFileOffset,
2418 : vsi_l_offset *pnNewFileOffset) const
2419 : {
2420 966 : if (sHeader.iVersion >= RMF_VERSION_HUGE)
2421 : {
2422 : // Round offset to next RMF_HUGE_OFFSET_FACTOR
2423 272 : const GUInt32 iRMFOffset =
2424 272 : static_cast<GUInt32>((nFileOffset + (RMF_HUGE_OFFSET_FACTOR - 1)) /
2425 : RMF_HUGE_OFFSET_FACTOR);
2426 272 : if (pnNewFileOffset != nullptr)
2427 : {
2428 205 : *pnNewFileOffset = GetFileOffset(iRMFOffset);
2429 : }
2430 272 : return iRMFOffset;
2431 : }
2432 :
2433 694 : if (pnNewFileOffset != nullptr)
2434 : {
2435 561 : *pnNewFileOffset = nFileOffset;
2436 : }
2437 694 : return static_cast<GUInt32>(nFileOffset);
2438 : }
2439 :
2440 200 : RMFDataset *RMFDataset::OpenOverview(RMFDataset *poParent,
2441 : GDALOpenInfo *poOpenInfo)
2442 : {
2443 200 : if (sHeader.nOvrOffset == 0)
2444 : {
2445 111 : return nullptr;
2446 : }
2447 :
2448 89 : if (poParent == nullptr)
2449 : {
2450 0 : return nullptr;
2451 : }
2452 :
2453 89 : vsi_l_offset nSubOffset = GetFileOffset(sHeader.nOvrOffset);
2454 :
2455 89 : CPLDebug("RMF",
2456 : "Try to open overview subfile at " CPL_FRMT_GUIB " for '%s'",
2457 : nSubOffset, poOpenInfo->pszFilename);
2458 :
2459 89 : if (!poParent->poOvrDatasets.empty())
2460 : {
2461 49 : if (poParent->GetFileOffset(poParent->sHeader.nOvrOffset) == nSubOffset)
2462 : {
2463 2 : CPLError(CE_Warning, CPLE_IllegalArg,
2464 : "Recursive subdataset list is detected. "
2465 : "Overview open failed.");
2466 2 : return nullptr;
2467 : }
2468 :
2469 58 : for (size_t n = 0; n != poParent->poOvrDatasets.size() - 1; ++n)
2470 : {
2471 13 : RMFDataset *poOvr(poParent->poOvrDatasets[n]);
2472 :
2473 13 : if (poOvr == nullptr)
2474 0 : continue;
2475 13 : if (poOvr->GetFileOffset(poOvr->sHeader.nOvrOffset) == nSubOffset)
2476 : {
2477 2 : CPLError(CE_Warning, CPLE_IllegalArg,
2478 : "Recursive subdataset list is detected. "
2479 : "Overview open failed.");
2480 2 : return nullptr;
2481 : }
2482 : }
2483 : }
2484 :
2485 85 : size_t nHeaderSize(RMF_HEADER_SIZE);
2486 : GByte *pabyNewHeader;
2487 : pabyNewHeader = static_cast<GByte *>(
2488 85 : CPLRealloc(poOpenInfo->pabyHeader, nHeaderSize + 1));
2489 85 : if (pabyNewHeader == nullptr)
2490 : {
2491 0 : CPLError(CE_Warning, CPLE_OutOfMemory,
2492 : "Can't allocate buffer for overview header");
2493 0 : return nullptr;
2494 : }
2495 :
2496 85 : poOpenInfo->pabyHeader = pabyNewHeader;
2497 85 : memset(poOpenInfo->pabyHeader, 0, nHeaderSize + 1);
2498 85 : VSIFSeekL(fp, nSubOffset, SEEK_SET);
2499 85 : poOpenInfo->nHeaderBytes =
2500 85 : static_cast<int>(VSIFReadL(poOpenInfo->pabyHeader, 1, nHeaderSize, fp));
2501 :
2502 85 : RMFDataset *poSub = (RMFDataset *)Open(poOpenInfo, poParent, nSubOffset);
2503 :
2504 85 : if (poSub == nullptr)
2505 : {
2506 4 : return nullptr;
2507 : }
2508 :
2509 81 : return poSub;
2510 : }
2511 :
2512 17 : CPLErr RMFDataset::IBuildOverviews(const char *pszResampling, int nOverviews,
2513 : const int *panOverviewList, int nBandsIn,
2514 : const int *panBandList,
2515 : GDALProgressFunc pfnProgress,
2516 : void *pProgressData,
2517 : CSLConstList papszOptions)
2518 : {
2519 17 : bool bUseGenericHandling = false;
2520 :
2521 17 : if (GetAccess() != GA_Update)
2522 : {
2523 0 : CPLDebug("RMF", "File open for read-only accessing, "
2524 : "creating overviews externally.");
2525 :
2526 0 : bUseGenericHandling = true;
2527 : }
2528 :
2529 17 : if (bUseGenericHandling)
2530 : {
2531 0 : if (!poOvrDatasets.empty())
2532 : {
2533 0 : CPLError(CE_Failure, CPLE_NotSupported,
2534 : "Cannot add external overviews when there are already "
2535 : "internal overviews");
2536 0 : return CE_Failure;
2537 : }
2538 :
2539 0 : return GDALDataset::IBuildOverviews(
2540 : pszResampling, nOverviews, panOverviewList, nBandsIn, panBandList,
2541 0 : pfnProgress, pProgressData, papszOptions);
2542 : }
2543 :
2544 17 : if (nBandsIn != GetRasterCount())
2545 : {
2546 0 : CPLError(CE_Failure, CPLE_NotSupported,
2547 : "Generation of overviews in RMF is only "
2548 : "supported when operating on all bands. "
2549 : "Operation failed.");
2550 0 : return CE_Failure;
2551 : }
2552 :
2553 17 : if (nOverviews == 0)
2554 : {
2555 0 : if (poOvrDatasets.empty())
2556 : {
2557 0 : return GDALDataset::IBuildOverviews(
2558 : pszResampling, nOverviews, panOverviewList, nBandsIn,
2559 0 : panBandList, pfnProgress, pProgressData, papszOptions);
2560 : }
2561 0 : return CleanOverviews();
2562 : }
2563 :
2564 : // First destroy old overviews
2565 17 : if (CE_None != CleanOverviews())
2566 : {
2567 0 : return CE_Failure;
2568 : }
2569 :
2570 17 : CPLDebug("RMF", "Build overviews on dataset %d x %d size", GetRasterXSize(),
2571 : GetRasterYSize());
2572 :
2573 17 : GDALDataType eMainType = GetRasterBand(1)->GetRasterDataType();
2574 17 : RMFDataset *poParent = this;
2575 17 : double prevOvLevel = 1.0;
2576 51 : for (int n = 0; n != nOverviews; ++n)
2577 : {
2578 34 : int nOvLevel = panOverviewList[n];
2579 34 : const int nOXSize = (GetRasterXSize() + nOvLevel - 1) / nOvLevel;
2580 34 : const int nOYSize = (GetRasterYSize() + nOvLevel - 1) / nOvLevel;
2581 34 : CPLDebug("RMF", "\tCreate overview #%d size %d x %d", nOvLevel, nOXSize,
2582 : nOYSize);
2583 :
2584 : RMFDataset *poOvrDataset;
2585 34 : poOvrDataset = static_cast<RMFDataset *>(RMFDataset::Create(
2586 : nullptr, nOXSize, nOYSize, GetRasterCount(), eMainType, nullptr,
2587 : poParent, nOvLevel / prevOvLevel));
2588 :
2589 34 : if (poOvrDataset == nullptr)
2590 : {
2591 0 : CPLError(CE_Failure, CPLE_AppDefined,
2592 : "Can't create overview dataset #%d size %d x %d", nOvLevel,
2593 : nOXSize, nOYSize);
2594 0 : return CE_Failure;
2595 : }
2596 :
2597 34 : prevOvLevel = nOvLevel;
2598 34 : poParent = poOvrDataset;
2599 34 : poOvrDatasets.push_back(poOvrDataset);
2600 : }
2601 :
2602 : GDALRasterBand ***papapoOverviewBands =
2603 17 : static_cast<GDALRasterBand ***>(CPLCalloc(sizeof(void *), nBandsIn));
2604 : GDALRasterBand **papoBandList =
2605 17 : static_cast<GDALRasterBand **>(CPLCalloc(sizeof(void *), nBandsIn));
2606 :
2607 36 : for (int iBand = 0; iBand < nBandsIn; ++iBand)
2608 : {
2609 19 : GDALRasterBand *poBand = GetRasterBand(panBandList[iBand]);
2610 :
2611 19 : papoBandList[iBand] = poBand;
2612 38 : papapoOverviewBands[iBand] = static_cast<GDALRasterBand **>(
2613 19 : CPLCalloc(sizeof(void *), poBand->GetOverviewCount()));
2614 :
2615 57 : for (int i = 0; i < nOverviews; ++i)
2616 : {
2617 38 : papapoOverviewBands[iBand][i] = poBand->GetOverview(i);
2618 : }
2619 : }
2620 : #ifdef DEBUG
2621 36 : for (int iBand = 0; iBand < nBandsIn; ++iBand)
2622 : {
2623 19 : CPLDebug("RMF", "Try to create overview for #%d size %d x %d",
2624 19 : iBand + 1, papoBandList[iBand]->GetXSize(),
2625 19 : papoBandList[iBand]->GetYSize());
2626 57 : for (int i = 0; i < nOverviews; ++i)
2627 : {
2628 38 : CPLDebug("RMF", "\t%d x %d",
2629 38 : papapoOverviewBands[iBand][i]->GetXSize(),
2630 38 : papapoOverviewBands[iBand][i]->GetYSize());
2631 : }
2632 : }
2633 : #endif // DEBUG
2634 : CPLErr res;
2635 17 : res = GDALRegenerateOverviewsMultiBand(
2636 : nBandsIn, papoBandList, nOverviews, papapoOverviewBands, pszResampling,
2637 : pfnProgress, pProgressData, papszOptions);
2638 :
2639 36 : for (int iBand = 0; iBand < nBandsIn; ++iBand)
2640 : {
2641 19 : CPLFree(papapoOverviewBands[iBand]);
2642 : }
2643 :
2644 17 : CPLFree(papapoOverviewBands);
2645 17 : CPLFree(papoBandList);
2646 :
2647 17 : return res;
2648 : }
2649 :
2650 68 : CPLErr RMFDataset::IRasterIO(GDALRWFlag eRWFlag, int nXOff, int nYOff,
2651 : int nXSize, int nYSize, void *pData, int nBufXSize,
2652 : int nBufYSize, GDALDataType eBufType,
2653 : int nBandCount, BANDMAP_TYPE panBandMap,
2654 : GSpacing nPixelSpace, GSpacing nLineSpace,
2655 : GSpacing nBandSpace,
2656 : GDALRasterIOExtraArg *psExtraArg)
2657 : {
2658 : #ifdef DEBUG
2659 68 : CPLDebug("RMF", "Dataset %p, %s %d %d %d %d, %d %d", this,
2660 : (eRWFlag == GF_Read ? "Read" : "Write"), nXOff, nYOff, nXSize,
2661 : nYSize, nBufXSize, nBufYSize);
2662 : #endif // DEBUG
2663 68 : if (eRWFlag == GF_Read && poCompressData != nullptr &&
2664 0 : poCompressData->oThreadPool.GetThreadCount() > 0)
2665 : {
2666 0 : poCompressData->oThreadPool.WaitCompletion();
2667 : }
2668 :
2669 68 : return GDALDataset::IRasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize, pData,
2670 : nBufXSize, nBufYSize, eBufType, nBandCount,
2671 : panBandMap, nPixelSpace, nLineSpace,
2672 68 : nBandSpace, psExtraArg);
2673 : }
2674 :
2675 238 : vsi_l_offset RMFDataset::GetLastOffset() const
2676 : {
2677 238 : vsi_l_offset nLastTileOff = 0;
2678 238 : GUInt32 nTiles(sHeader.nTileTblSize / sizeof(GUInt32));
2679 :
2680 768 : for (GUInt32 n = 0; n < nTiles; n += 2)
2681 : {
2682 530 : vsi_l_offset nTileOffset = GetFileOffset(paiTiles[n]);
2683 530 : GUInt32 nTileBytes = paiTiles[n + 1];
2684 530 : nLastTileOff = std::max(nLastTileOff, nTileOffset + nTileBytes);
2685 : }
2686 :
2687 238 : nLastTileOff = std::max(nLastTileOff, GetFileOffset(sHeader.nROIOffset) +
2688 238 : sHeader.nROISize);
2689 238 : nLastTileOff = std::max(nLastTileOff, GetFileOffset(sHeader.nClrTblOffset) +
2690 238 : sHeader.nClrTblSize);
2691 238 : nLastTileOff =
2692 238 : std::max(nLastTileOff,
2693 238 : GetFileOffset(sHeader.nTileTblOffset) + sHeader.nTileTblSize);
2694 238 : nLastTileOff =
2695 238 : std::max(nLastTileOff, GetFileOffset(sHeader.nFlagsTblOffset) +
2696 238 : sHeader.nFlagsTblSize);
2697 238 : nLastTileOff = std::max(nLastTileOff, GetFileOffset(sHeader.nExtHdrOffset) +
2698 238 : sHeader.nExtHdrSize);
2699 238 : return nLastTileOff;
2700 : }
2701 :
2702 17 : CPLErr RMFDataset::CleanOverviews()
2703 : {
2704 17 : if (sHeader.nOvrOffset == 0)
2705 : {
2706 13 : return CE_None;
2707 : }
2708 :
2709 4 : if (GetAccess() != GA_Update)
2710 : {
2711 0 : CPLError(CE_Failure, CPLE_NotSupported,
2712 : "File open for read-only accessing, "
2713 : "overviews cleanup failed.");
2714 0 : return CE_Failure;
2715 : }
2716 :
2717 4 : if (poParentDS != nullptr)
2718 : {
2719 0 : CPLError(CE_Failure, CPLE_NotSupported,
2720 : "Overviews cleanup for non-root dataset is not possible.");
2721 0 : return CE_Failure;
2722 : }
2723 :
2724 12 : for (size_t n = 0; n != poOvrDatasets.size(); ++n)
2725 : {
2726 8 : GDALClose(poOvrDatasets[n]);
2727 : }
2728 4 : poOvrDatasets.clear();
2729 :
2730 4 : vsi_l_offset nLastTileOff = GetLastOffset();
2731 :
2732 4 : if (0 != VSIFSeekL(fp, 0, SEEK_END))
2733 : {
2734 0 : CPLError(CE_Failure, CPLE_FileIO,
2735 : "Failed to seek to end of file, "
2736 : "overviews cleanup failed.");
2737 : }
2738 :
2739 4 : vsi_l_offset nFileSize = VSIFTellL(fp);
2740 4 : if (nFileSize < nLastTileOff)
2741 : {
2742 0 : CPLError(CE_Failure, CPLE_FileIO,
2743 : "Invalid file offset, "
2744 : "overviews cleanup failed.");
2745 0 : return CE_Failure;
2746 : }
2747 :
2748 4 : CPLDebug("RMF", "Truncate to " CPL_FRMT_GUIB, nLastTileOff);
2749 4 : CPLDebug("RMF", "File size: " CPL_FRMT_GUIB, nFileSize);
2750 :
2751 4 : if (0 != VSIFTruncateL(fp, nLastTileOff))
2752 : {
2753 0 : CPLError(CE_Failure, CPLE_FileIO,
2754 : "Failed to truncate file, "
2755 : "overviews cleanup failed.");
2756 0 : return CE_Failure;
2757 : }
2758 :
2759 4 : sHeader.nOvrOffset = 0;
2760 4 : bHeaderDirty = true;
2761 :
2762 4 : return CE_None;
2763 : }
2764 :
2765 : /************************************************************************/
2766 : /* GetCompressionType() */
2767 : /************************************************************************/
2768 :
2769 43 : GByte RMFDataset::GetCompressionType(const char *pszCompressName)
2770 : {
2771 43 : if (pszCompressName == nullptr || EQUAL(pszCompressName, "NONE"))
2772 : {
2773 35 : return RMF_COMPRESSION_NONE;
2774 : }
2775 8 : else if (EQUAL(pszCompressName, "LZW"))
2776 : {
2777 5 : return RMF_COMPRESSION_LZW;
2778 : }
2779 3 : else if (EQUAL(pszCompressName, "JPEG"))
2780 : {
2781 1 : return RMF_COMPRESSION_JPEG;
2782 : }
2783 2 : else if (EQUAL(pszCompressName, "RMF_DEM"))
2784 : {
2785 2 : return RMF_COMPRESSION_DEM;
2786 : }
2787 :
2788 0 : CPLError(CE_Failure, CPLE_AppDefined,
2789 : "RMF: Unknown compression scheme <%s>.\n"
2790 : "Defaults to NONE compression.",
2791 : pszCompressName);
2792 0 : return RMF_COMPRESSION_NONE;
2793 : }
2794 :
2795 : /************************************************************************/
2796 : /* SetupCompression() */
2797 : /************************************************************************/
2798 :
2799 243 : int RMFDataset::SetupCompression(GDALDataType eType, const char *pszFilename)
2800 : {
2801 : /* -------------------------------------------------------------------- */
2802 : /* XXX: The DEM compression method seems to be only applicable */
2803 : /* to Int32 data. */
2804 : /* -------------------------------------------------------------------- */
2805 243 : if (sHeader.iCompression == RMF_COMPRESSION_NONE)
2806 : {
2807 173 : Decompress = nullptr;
2808 173 : Compress = nullptr;
2809 : }
2810 70 : else if (sHeader.iCompression == RMF_COMPRESSION_LZW)
2811 : {
2812 57 : Decompress = &LZWDecompress;
2813 57 : Compress = &LZWCompress;
2814 57 : SetMetadataItem("COMPRESSION", "LZW", "IMAGE_STRUCTURE");
2815 : }
2816 13 : else if (sHeader.iCompression == RMF_COMPRESSION_JPEG)
2817 : {
2818 3 : if (eType != GDT_Byte || nBands != RMF_JPEG_BAND_COUNT ||
2819 3 : sHeader.nBitDepth != 24)
2820 : {
2821 0 : CPLError(CE_Failure, CPLE_AppDefined,
2822 : "RMF support only 24 bpp JPEG compressed files.");
2823 0 : return CE_Failure;
2824 : }
2825 : #ifdef HAVE_LIBJPEG
2826 6 : CPLString oBuf;
2827 3 : oBuf.Printf("%d", (int)sHeader.iJpegQuality);
2828 3 : Decompress = &JPEGDecompress;
2829 3 : Compress = &JPEGCompress;
2830 3 : SetMetadataItem("JPEG_QUALITY", oBuf.c_str(), "IMAGE_STRUCTURE");
2831 3 : SetMetadataItem("COMPRESSION", "JPEG", "IMAGE_STRUCTURE");
2832 : #else // HAVE_LIBJPEG
2833 : CPLError(CE_Failure, CPLE_AppDefined,
2834 : "JPEG codec is needed to open <%s>.\n"
2835 : "Please rebuild GDAL with libjpeg support.",
2836 : pszFilename);
2837 : return CE_Failure;
2838 : #endif // HAVE_LIBJPEG
2839 : }
2840 10 : else if (sHeader.iCompression == RMF_COMPRESSION_DEM &&
2841 10 : eType == GDT_Int32 && nBands == RMF_DEM_BAND_COUNT)
2842 : {
2843 10 : Decompress = &DEMDecompress;
2844 10 : Compress = &DEMCompress;
2845 10 : SetMetadataItem("COMPRESSION", "RMF_DEM", "IMAGE_STRUCTURE");
2846 : }
2847 : else
2848 : {
2849 0 : CPLError(CE_Failure, CPLE_AppDefined,
2850 : "Unknown compression #%d at file <%s>.",
2851 0 : (int)sHeader.iCompression, pszFilename);
2852 0 : return CE_Failure;
2853 : }
2854 :
2855 243 : return CE_None;
2856 : }
2857 :
2858 190 : void RMFDataset::WriteTileJobFunc(void *pData)
2859 : {
2860 190 : RMFCompressionJob *psJob = static_cast<RMFCompressionJob *>(pData);
2861 190 : RMFDataset *poDS = psJob->poDS;
2862 :
2863 : GByte *pabyTileData;
2864 : size_t nTileSize;
2865 :
2866 190 : if (poDS->Compress)
2867 : {
2868 : // RMF doesn't store compressed tiles with size greater than 80% of
2869 : // uncompressed size
2870 131 : GUInt32 nMaxCompressedTileSize =
2871 131 : static_cast<GUInt32>((psJob->nUncompressedBytes * 8) / 10);
2872 : size_t nCompressedBytes =
2873 262 : poDS->Compress(psJob->pabyUncompressedData,
2874 131 : static_cast<GUInt32>(psJob->nUncompressedBytes),
2875 : psJob->pabyCompressedData, nMaxCompressedTileSize,
2876 : psJob->nXSize, psJob->nYSize, poDS);
2877 131 : if (nCompressedBytes == 0)
2878 : {
2879 28 : pabyTileData = psJob->pabyUncompressedData;
2880 28 : nTileSize = psJob->nUncompressedBytes;
2881 : }
2882 : else
2883 : {
2884 103 : pabyTileData = psJob->pabyCompressedData;
2885 103 : nTileSize = nCompressedBytes;
2886 : }
2887 : }
2888 : else
2889 : {
2890 59 : pabyTileData = psJob->pabyUncompressedData;
2891 59 : nTileSize = psJob->nUncompressedBytes;
2892 : }
2893 :
2894 : {
2895 190 : CPLMutexHolder oHolder(poDS->poCompressData->hWriteTileMutex);
2896 190 : psJob->eResult = poDS->WriteRawTile(
2897 : psJob->nBlockXOff, psJob->nBlockYOff, pabyTileData, nTileSize);
2898 : }
2899 190 : if (poDS->poCompressData->oThreadPool.GetThreadCount() > 0)
2900 : {
2901 188 : CPLMutexHolder oHolder(poDS->poCompressData->hReadyJobMutex);
2902 94 : poDS->poCompressData->asReadyJobs.push_back(psJob);
2903 : }
2904 190 : }
2905 :
2906 55 : CPLErr RMFDataset::InitCompressorData(char **papszParamList)
2907 : {
2908 : const char *pszNumThreads =
2909 55 : CSLFetchNameValue(papszParamList, "NUM_THREADS");
2910 55 : if (pszNumThreads == nullptr)
2911 51 : pszNumThreads = CPLGetConfigOption("GDAL_NUM_THREADS", nullptr);
2912 :
2913 55 : int nThreads = 0;
2914 55 : if (pszNumThreads != nullptr)
2915 : {
2916 8 : nThreads = EQUAL(pszNumThreads, "ALL_CPUS") ? CPLGetNumCPUs()
2917 4 : : atoi(pszNumThreads);
2918 : }
2919 :
2920 55 : if (nThreads < 0)
2921 : {
2922 0 : nThreads = 0;
2923 : }
2924 55 : if (nThreads > 1024)
2925 : {
2926 0 : nThreads = 1024;
2927 : }
2928 :
2929 55 : poCompressData = std::make_shared<RMFCompressData>();
2930 55 : if (nThreads > 0)
2931 : {
2932 3 : if (!poCompressData->oThreadPool.Setup(nThreads, nullptr, nullptr))
2933 : {
2934 0 : CPLError(CE_Failure, CPLE_AppDefined,
2935 : "Can't setup %d compressor threads", nThreads);
2936 0 : return CE_Failure;
2937 : }
2938 : }
2939 :
2940 55 : poCompressData->asJobs.resize(nThreads + 1);
2941 :
2942 55 : size_t nMaxTileBytes =
2943 55 : sHeader.nTileWidth * sHeader.nTileHeight * sHeader.nBitDepth / 8;
2944 : size_t nCompressBufferSize =
2945 55 : 2 * nMaxTileBytes * poCompressData->asJobs.size();
2946 110 : poCompressData->pabyBuffers =
2947 55 : reinterpret_cast<GByte *>(VSIMalloc(nCompressBufferSize));
2948 :
2949 55 : CPLDebug("RMF", "Setup %d compressor threads and allocate %lu bytes buffer",
2950 : nThreads, (long int)nCompressBufferSize);
2951 55 : if (poCompressData->pabyBuffers == nullptr)
2952 : {
2953 0 : CPLError(CE_Failure, CPLE_OutOfMemory,
2954 : "Can't allocate compress buffer of size %lu.",
2955 : (unsigned long)nCompressBufferSize);
2956 0 : return CE_Failure;
2957 : }
2958 :
2959 122 : for (size_t i = 0; i != poCompressData->asJobs.size(); ++i)
2960 : {
2961 67 : RMFCompressionJob &sJob(poCompressData->asJobs[i]);
2962 67 : sJob.pabyCompressedData =
2963 67 : poCompressData->pabyBuffers + 2 * i * nMaxTileBytes;
2964 67 : sJob.pabyUncompressedData = sJob.pabyCompressedData + nMaxTileBytes;
2965 67 : poCompressData->asReadyJobs.push_back(&sJob);
2966 : }
2967 :
2968 55 : if (nThreads > 0)
2969 : {
2970 3 : poCompressData->hReadyJobMutex = CPLCreateMutex();
2971 3 : CPLReleaseMutex(poCompressData->hReadyJobMutex);
2972 3 : poCompressData->hWriteTileMutex = CPLCreateMutex();
2973 3 : CPLReleaseMutex(poCompressData->hWriteTileMutex);
2974 : }
2975 :
2976 55 : return CE_None;
2977 : }
2978 :
2979 190 : CPLErr RMFDataset::WriteTile(int nBlockXOff, int nBlockYOff, GByte *pabyData,
2980 : size_t nBytes, GUInt32 nRawXSize,
2981 : GUInt32 nRawYSize)
2982 : {
2983 190 : RMFCompressionJob *poJob = nullptr;
2984 190 : if (poCompressData == nullptr)
2985 : {
2986 0 : CPLError(CE_Failure, CPLE_AppDefined, "RMF: Compress data is null");
2987 0 : return CE_Failure;
2988 : }
2989 :
2990 190 : if (poCompressData->oThreadPool.GetThreadCount() > 0)
2991 : {
2992 94 : size_t nJobs(poCompressData->asJobs.size());
2993 :
2994 94 : poCompressData->oThreadPool.WaitCompletion(static_cast<int>(nJobs - 1));
2995 :
2996 188 : CPLMutexHolder oHolder(poCompressData->hReadyJobMutex);
2997 94 : CPLAssert(!poCompressData->asReadyJobs.empty());
2998 94 : poJob = poCompressData->asReadyJobs.front();
2999 94 : poCompressData->asReadyJobs.pop_front();
3000 : }
3001 : else
3002 : {
3003 96 : poJob = poCompressData->asReadyJobs.front();
3004 : }
3005 :
3006 190 : if (poJob->eResult != CE_None)
3007 : {
3008 : // One of the previous jobs is not done.
3009 : // Detailed debug message is already emitted from WriteRawTile
3010 0 : return poJob->eResult;
3011 : }
3012 190 : poJob->poDS = this;
3013 190 : poJob->eResult = CE_Failure;
3014 190 : poJob->nBlockXOff = nBlockXOff;
3015 190 : poJob->nBlockYOff = nBlockYOff;
3016 190 : poJob->nUncompressedBytes = nBytes;
3017 190 : poJob->nXSize = nRawXSize;
3018 190 : poJob->nYSize = nRawYSize;
3019 :
3020 190 : memcpy(poJob->pabyUncompressedData, pabyData, nBytes);
3021 :
3022 190 : if (poCompressData->oThreadPool.GetThreadCount() > 0)
3023 : {
3024 94 : if (!poCompressData->oThreadPool.SubmitJob(WriteTileJobFunc, poJob))
3025 : {
3026 0 : CPLError(CE_Failure, CPLE_NotSupported,
3027 : "Can't submit job to thread pool.");
3028 0 : return CE_Failure;
3029 : }
3030 : }
3031 : else
3032 : {
3033 96 : WriteTileJobFunc(poJob);
3034 96 : if (poJob->eResult != CE_None)
3035 : {
3036 0 : return poJob->eResult;
3037 : }
3038 : }
3039 :
3040 190 : return CE_None;
3041 : }
3042 :
3043 190 : CPLErr RMFDataset::WriteRawTile(int nBlockXOff, int nBlockYOff, GByte *pabyData,
3044 : size_t nTileBytes)
3045 : {
3046 190 : CPLAssert(nBlockXOff >= 0 && nBlockYOff >= 0 && pabyData != nullptr &&
3047 : nTileBytes > 0);
3048 :
3049 190 : const GUInt32 nTile = nBlockYOff * nXTiles + nBlockXOff;
3050 :
3051 190 : vsi_l_offset nTileOffset = GetFileOffset(paiTiles[2 * nTile]);
3052 190 : size_t nTileSize = static_cast<size_t>(paiTiles[2 * nTile + 1]);
3053 :
3054 190 : if (nTileOffset && nTileSize <= nTileBytes)
3055 : {
3056 0 : if (VSIFSeekL(fp, nTileOffset, SEEK_SET) < 0)
3057 : {
3058 0 : CPLError(
3059 : CE_Failure, CPLE_FileIO,
3060 : "Can't seek to offset %ld in output file to write data.\n%s",
3061 0 : static_cast<long>(nTileOffset), VSIStrerror(errno));
3062 0 : return CE_Failure;
3063 : }
3064 : }
3065 : else
3066 : {
3067 190 : if (VSIFSeekL(fp, 0, SEEK_END) < 0)
3068 : {
3069 0 : CPLError(
3070 : CE_Failure, CPLE_FileIO,
3071 : "Can't seek to offset %ld in output file to write data.\n%s",
3072 0 : static_cast<long>(nTileOffset), VSIStrerror(errno));
3073 0 : return CE_Failure;
3074 : }
3075 190 : nTileOffset = VSIFTellL(fp);
3076 190 : vsi_l_offset nNewTileOffset = 0;
3077 190 : paiTiles[2 * nTile] = GetRMFOffset(nTileOffset, &nNewTileOffset);
3078 :
3079 190 : if (nTileOffset != nNewTileOffset)
3080 : {
3081 23 : if (VSIFSeekL(fp, nNewTileOffset, SEEK_SET) < 0)
3082 : {
3083 0 : CPLError(CE_Failure, CPLE_FileIO,
3084 : "Can't seek to offset %ld in output file to "
3085 : "write data.\n%s",
3086 0 : static_cast<long>(nNewTileOffset), VSIStrerror(errno));
3087 0 : return CE_Failure;
3088 : }
3089 : }
3090 190 : bHeaderDirty = true;
3091 : }
3092 :
3093 : #ifdef CPL_MSB
3094 : // Compressed tiles are already with proper byte order
3095 : if (eRMFType == RMFT_MTW && sHeader.iCompression == RMF_COMPRESSION_NONE)
3096 : {
3097 : // Byte swap can be done in place
3098 : if (sHeader.nBitDepth == 16)
3099 : {
3100 : for (size_t i = 0; i < nTileBytes; i += 2)
3101 : CPL_SWAP16PTR(pabyData + i);
3102 : }
3103 : else if (sHeader.nBitDepth == 32)
3104 : {
3105 : for (size_t i = 0; i < nTileBytes; i += 4)
3106 : CPL_SWAP32PTR(pabyData + i);
3107 : }
3108 : else if (sHeader.nBitDepth == 64)
3109 : {
3110 : for (size_t i = 0; i < nTileBytes; i += 8)
3111 : CPL_SWAPDOUBLE(pabyData + i);
3112 : }
3113 : }
3114 : #endif
3115 :
3116 190 : bool bOk = (VSIFWriteL(pabyData, 1, nTileBytes, fp) == nTileBytes);
3117 :
3118 190 : if (!bOk)
3119 : {
3120 0 : CPLError(CE_Failure, CPLE_FileIO,
3121 : "Can't write tile with X offset %d and Y offset %d.\n%s",
3122 0 : nBlockXOff, nBlockYOff, VSIStrerror(errno));
3123 0 : return CE_Failure;
3124 : }
3125 :
3126 190 : paiTiles[2 * nTile + 1] = static_cast<GUInt32>(nTileBytes);
3127 190 : bHeaderDirty = true;
3128 :
3129 190 : return CE_None;
3130 : }
3131 :
3132 352 : CPLErr RMFDataset::ReadTile(int nBlockXOff, int nBlockYOff, GByte *pabyData,
3133 : size_t nRawBytes, GUInt32 nRawXSize,
3134 : GUInt32 nRawYSize, bool &bNullTile)
3135 : {
3136 352 : bNullTile = false;
3137 :
3138 352 : const GUInt32 nTile = nBlockYOff * nXTiles + nBlockXOff;
3139 352 : if (2 * nTile + 1 >= sHeader.nTileTblSize / sizeof(GUInt32))
3140 : {
3141 0 : return CE_Failure;
3142 : }
3143 352 : vsi_l_offset nTileOffset = GetFileOffset(paiTiles[2 * nTile]);
3144 352 : GUInt32 nTileBytes = paiTiles[2 * nTile + 1];
3145 : // RMF doesn't store compressed tiles with size greater than 80% of
3146 : // uncompressed size. But just in case, select twice as many.
3147 352 : GUInt32 nMaxTileBytes =
3148 352 : 2 * sHeader.nTileWidth * sHeader.nTileHeight * sHeader.nBitDepth / 8;
3149 :
3150 352 : if (nTileBytes >= nMaxTileBytes)
3151 : {
3152 0 : CPLError(CE_Failure, CPLE_AppDefined,
3153 : "Invalid tile size %lu at offset %ld. Must be less than %lu",
3154 : static_cast<unsigned long>(nTileBytes),
3155 : static_cast<long>(nTileOffset),
3156 : static_cast<unsigned long>(nMaxTileBytes));
3157 0 : return CE_Failure;
3158 : }
3159 :
3160 352 : if (nTileOffset == 0)
3161 : {
3162 1 : bNullTile = true;
3163 1 : return CE_None;
3164 : }
3165 :
3166 : #ifdef DEBUG
3167 351 : CPLDebug("RMF", "Read RawSize [%d, %d], nTileBytes %d, nRawBytes %d",
3168 : nRawXSize, nRawYSize, static_cast<int>(nTileBytes),
3169 : static_cast<int>(nRawBytes));
3170 : #endif // DEBUG
3171 :
3172 351 : if (VSIFSeekL(fp, nTileOffset, SEEK_SET) < 0)
3173 : {
3174 : // XXX: We will not report error here, because file just may be
3175 : // in update state and data for this block will be available later
3176 0 : if (eAccess == GA_Update)
3177 0 : return CE_None;
3178 :
3179 0 : CPLError(CE_Failure, CPLE_FileIO,
3180 : "Can't seek to offset %ld in input file to read data.\n%s",
3181 0 : static_cast<long>(nTileOffset), VSIStrerror(errno));
3182 0 : return CE_Failure;
3183 : }
3184 :
3185 351 : if (Decompress == nullptr || nTileBytes == nRawBytes)
3186 : {
3187 166 : if (nTileBytes != nRawBytes)
3188 : {
3189 0 : CPLError(CE_Failure, CPLE_AppDefined,
3190 : "RMF: Invalid tile size %lu, expected %lu",
3191 : static_cast<unsigned long>(nTileBytes),
3192 : static_cast<unsigned long>(nRawBytes));
3193 0 : return CE_Failure;
3194 : }
3195 :
3196 166 : if (VSIFReadL(pabyData, 1, nRawBytes, fp) < nRawBytes)
3197 : {
3198 0 : CPLError(CE_Failure, CPLE_FileIO,
3199 : "RMF: Can't read at offset %lu from input file.\n%s",
3200 : static_cast<unsigned long>(nTileOffset),
3201 0 : VSIStrerror(errno));
3202 0 : return CE_Failure;
3203 : }
3204 :
3205 : #ifdef CPL_MSB
3206 : if (eRMFType == RMFT_MTW)
3207 : {
3208 : if (sHeader.nBitDepth == 16)
3209 : {
3210 : for (GUInt32 i = 0; i < nRawBytes; i += 2)
3211 : CPL_SWAP16PTR(pabyData + i);
3212 : }
3213 : else if (sHeader.nBitDepth == 32)
3214 : {
3215 : for (GUInt32 i = 0; i < nRawBytes; i += 4)
3216 : CPL_SWAP32PTR(pabyData + i);
3217 : }
3218 : else if (sHeader.nBitDepth == 64)
3219 : {
3220 : for (GUInt32 i = 0; i < nRawBytes; i += 8)
3221 : CPL_SWAPDOUBLE(pabyData + i);
3222 : }
3223 : }
3224 : #endif
3225 166 : return CE_None;
3226 : }
3227 :
3228 185 : if (pabyDecompressBuffer == nullptr)
3229 : {
3230 21 : pabyDecompressBuffer =
3231 21 : reinterpret_cast<GByte *>(VSIMalloc(std::max(1U, nMaxTileBytes)));
3232 21 : if (!pabyDecompressBuffer)
3233 : {
3234 0 : CPLError(CE_Failure, CPLE_OutOfMemory,
3235 : "Can't allocate decompress buffer of size %lu.\n%s",
3236 : static_cast<unsigned long>(nMaxTileBytes),
3237 0 : VSIStrerror(errno));
3238 0 : return CE_Failure;
3239 : }
3240 : }
3241 :
3242 185 : if (VSIFReadL(pabyDecompressBuffer, 1, nTileBytes, fp) < nTileBytes)
3243 : {
3244 0 : CPLError(CE_Failure, CPLE_FileIO,
3245 : "RMF: Can't read at offset %lu from input file.\n%s",
3246 0 : static_cast<unsigned long>(nTileOffset), VSIStrerror(errno));
3247 0 : return CE_Failure;
3248 : }
3249 :
3250 : size_t nDecompressedSize =
3251 185 : Decompress(pabyDecompressBuffer, nTileBytes, pabyData,
3252 : static_cast<GUInt32>(nRawBytes), nRawXSize, nRawYSize);
3253 :
3254 185 : if (nDecompressedSize != (size_t)nRawBytes)
3255 : {
3256 0 : CPLError(CE_Failure, CPLE_FileIO,
3257 : "Can't decompress tile xOff %d yOff %d. "
3258 : "Raw tile size is %lu but decompressed is %lu. "
3259 : "Compressed tile size is %lu",
3260 : nBlockXOff, nBlockYOff, static_cast<unsigned long>(nRawBytes),
3261 : static_cast<unsigned long>(nDecompressedSize),
3262 : static_cast<unsigned long>(nTileBytes));
3263 0 : return CE_Failure;
3264 : }
3265 : // We don't need to swap bytes here,
3266 : // because decompressed data is in proper byte order
3267 185 : return CE_None;
3268 : }
3269 :
3270 277 : void RMFDataset::SetupNBits()
3271 : {
3272 277 : int nBitDepth = 0;
3273 277 : if (sHeader.nBitDepth < 8 && nBands == 1)
3274 : {
3275 6 : nBitDepth = static_cast<int>(sHeader.nBitDepth);
3276 : }
3277 271 : else if (sHeader.nBitDepth == 16 && nBands == 3 && eRMFType == RMFT_RSW)
3278 : {
3279 0 : nBitDepth = 5;
3280 : }
3281 :
3282 277 : if (nBitDepth > 0)
3283 : {
3284 6 : char szNBits[32] = {};
3285 6 : snprintf(szNBits, sizeof(szNBits), "%d", nBitDepth);
3286 12 : for (int iBand = 1; iBand <= nBands; iBand++)
3287 : {
3288 6 : GetRasterBand(iBand)->SetMetadataItem("NBITS", szNBits,
3289 6 : "IMAGE_STRUCTURE");
3290 : }
3291 : }
3292 277 : }
3293 :
3294 : /************************************************************************/
3295 : /* GDALRegister_RMF() */
3296 : /************************************************************************/
3297 :
3298 1595 : void GDALRegister_RMF()
3299 :
3300 : {
3301 1595 : if (GDALGetDriverByName("RMF") != nullptr)
3302 302 : return;
3303 :
3304 1293 : GDALDriver *poDriver = new GDALDriver();
3305 :
3306 1293 : poDriver->SetDescription("RMF");
3307 1293 : poDriver->SetMetadataItem(GDAL_DCAP_RASTER, "YES");
3308 1293 : poDriver->SetMetadataItem(GDAL_DMD_LONGNAME, "Raster Matrix Format");
3309 1293 : poDriver->SetMetadataItem(GDAL_DMD_HELPTOPIC, "drivers/raster/rmf.html");
3310 1293 : poDriver->SetMetadataItem(GDAL_DMD_EXTENSION, "rsw");
3311 1293 : poDriver->SetMetadataItem(GDAL_DMD_CREATIONDATATYPES,
3312 1293 : "Byte Int16 Int32 Float64");
3313 1293 : poDriver->SetMetadataItem(
3314 : GDAL_DMD_CREATIONOPTIONLIST,
3315 : "<CreationOptionList>"
3316 : " <Option name='MTW' type='boolean' description='Create MTW DEM "
3317 : "matrix'/>"
3318 : " <Option name='BLOCKXSIZE' type='int' description='Tile Width'/>"
3319 : " <Option name='BLOCKYSIZE' type='int' description='Tile Height'/>"
3320 : " <Option name='RMFHUGE' type='string-select' description='Creation "
3321 : "of huge RMF file (Supported by GIS Panorama since v11)'>"
3322 : " <Value>NO</Value>"
3323 : " <Value>YES</Value>"
3324 : " <Value>IF_SAFER</Value>"
3325 : " </Option>"
3326 : " <Option name='COMPRESS' type='string-select' default='NONE'>"
3327 : " <Value>NONE</Value>"
3328 : " <Value>LZW</Value>"
3329 : " <Value>JPEG</Value>"
3330 : " <Value>RMF_DEM</Value>"
3331 : " </Option>"
3332 : " <Option name='JPEG_QUALITY' type='int' description='JPEG quality "
3333 : "1-100' default='75'/>"
3334 : " <Option name='NUM_THREADS' type='string' description='Number of "
3335 : "worker threads for compression. Can be set to ALL_CPUS' default='1'/>"
3336 1293 : "</CreationOptionList>");
3337 1293 : poDriver->SetMetadataItem(GDAL_DCAP_VIRTUALIO, "YES");
3338 :
3339 1293 : poDriver->pfnIdentify = RMFDataset::Identify;
3340 1293 : poDriver->pfnOpen = RMFDataset::Open;
3341 1293 : poDriver->pfnCreate = RMFDataset::Create;
3342 1293 : poDriver->SetMetadataItem(
3343 : GDAL_DMD_OPENOPTIONLIST,
3344 : "<OpenOptionList>"
3345 : " <Option name='RMF_SET_VERTCS' type='string' description='Layers "
3346 : "spatial reference will include vertical coordinate system description "
3347 : "if exist' default='NO'/>"
3348 1293 : "</OpenOptionList>");
3349 :
3350 1293 : GetGDALDriverManager()->RegisterDriver(poDriver);
3351 : }
3352 :
3353 : /************************************************************************/
3354 : /* RMFCompressData */
3355 : /************************************************************************/
3356 :
3357 55 : RMFCompressData::RMFCompressData() : pabyBuffers(nullptr)
3358 : {
3359 55 : }
3360 :
3361 55 : RMFCompressData::~RMFCompressData()
3362 : {
3363 55 : if (pabyBuffers != nullptr)
3364 : {
3365 55 : VSIFree(pabyBuffers);
3366 : }
3367 :
3368 55 : if (hWriteTileMutex != nullptr)
3369 : {
3370 3 : CPLDestroyMutex(hWriteTileMutex);
3371 : }
3372 :
3373 55 : if (hReadyJobMutex != nullptr)
3374 : {
3375 3 : CPLDestroyMutex(hReadyJobMutex);
3376 : }
3377 55 : }
3378 :
3379 : GDALSuggestedBlockAccessPattern
3380 21 : RMFRasterBand::GetSuggestedBlockAccessPattern() const
3381 : {
3382 21 : return GSBAP_RANDOM;
3383 : }
3384 :
3385 1507 : CPLErr RMFDataset::SetMetadataItem(const char *pszName, const char *pszValue,
3386 : const char *pszDomain)
3387 : {
3388 1507 : if (GetAccess() == GA_Update)
3389 : {
3390 190 : CPLDebug("RMF", "SetMetadataItem: %s=%s", pszName, pszValue);
3391 190 : if (EQUAL(pszName, MD_NAME_KEY))
3392 : {
3393 20 : memcpy(sHeader.byName, pszValue,
3394 : CPLStrnlen(pszValue, RMF_NAME_SIZE));
3395 20 : bHeaderDirty = true;
3396 : }
3397 170 : else if (EQUAL(pszName, MD_SCALE_KEY) && CPLStrnlen(pszValue, 10) > 4)
3398 : {
3399 20 : sHeader.dfScale = atof(pszValue + 4);
3400 20 : sHeader.dfResolution = sHeader.dfScale / sHeader.dfPixelSize;
3401 20 : bHeaderDirty = true;
3402 : }
3403 150 : else if (EQUAL(pszName, MD_FRAME_KEY))
3404 : {
3405 0 : bHeaderDirty = true;
3406 : }
3407 : }
3408 1507 : return GDALDataset::SetMetadataItem(pszName, pszValue, pszDomain);
3409 : }
3410 :
3411 39 : CPLErr RMFDataset::SetMetadata(char **papszMetadata, const char *pszDomain)
3412 : {
3413 39 : if (GetAccess() == GA_Update)
3414 : {
3415 39 : auto pszName = CSLFetchNameValue(papszMetadata, MD_NAME_KEY);
3416 39 : if (pszName != nullptr)
3417 : {
3418 21 : memcpy(sHeader.byName, pszName, CPLStrnlen(pszName, RMF_NAME_SIZE));
3419 21 : bHeaderDirty = true;
3420 :
3421 21 : CPLDebug("RMF", "SetMetadata: %s", pszName);
3422 : }
3423 39 : auto pszScale = CSLFetchNameValue(papszMetadata, MD_SCALE_KEY);
3424 39 : if (pszScale != nullptr && CPLStrnlen(pszScale, 10) > 4)
3425 : {
3426 21 : sHeader.dfScale = atof(pszScale + 4);
3427 21 : sHeader.dfResolution = sHeader.dfScale / sHeader.dfPixelSize;
3428 21 : bHeaderDirty = true;
3429 :
3430 21 : CPLDebug("RMF", "SetMetadata: %s", pszScale);
3431 : }
3432 39 : auto pszFrame = CSLFetchNameValue(papszMetadata, MD_FRAME_KEY);
3433 39 : if (pszFrame != nullptr)
3434 : {
3435 2 : bHeaderDirty = true;
3436 :
3437 2 : CPLDebug("RMF", "SetMetadata: %s", pszFrame);
3438 : }
3439 : }
3440 39 : return GDALDataset::SetMetadata(papszMetadata, pszDomain);
3441 : }
|