Line data Source code
1 : /******************************************************************************
2 : *
3 : * Project: MiraMonRaster driver
4 : * Purpose: Implements MMRBand class: This class manages the metadata of each
5 : * band to be processed. It is useful for maintaining a list of bands
6 : * and for determining the number of subdatasets that need to be
7 : * generated.
8 : * Author: Abel Pau
9 : *
10 : ******************************************************************************
11 : * Copyright (c) 2025, Xavier Pons
12 : *
13 : * SPDX-License-Identifier: MIT
14 : ****************************************************************************/
15 : #include <algorithm>
16 : #include <limits>
17 : #include "gdal_rat.h"
18 :
19 : #include "miramon_rel.h"
20 : #include "miramon_band.h"
21 :
22 : #include "../miramon_common/mm_gdal_functions.h" // For MM_CreateDBFHeader
23 :
24 : /************************************************************************/
25 : /* MMRBand() */
26 : /************************************************************************/
27 108 : MMRBand::MMRBand(MMRRel &fRel, const CPLString &osBandSectionIn)
28 : : m_pfRel(&fRel), m_nWidth(0), m_nHeight(0),
29 108 : m_osBandSection(osBandSectionIn)
30 : {
31 : // Getting band and band file name from metadata.
32 108 : CPLString osNomFitxer;
33 108 : osNomFitxer = SECTION_ATTRIBUTE_DATA;
34 108 : osNomFitxer.append(":");
35 108 : osNomFitxer.append(osBandSectionIn);
36 108 : if (!m_pfRel->GetMetadataValue(osNomFitxer, KEY_NomFitxer,
37 161 : m_osRawBandFileName) ||
38 53 : m_osRawBandFileName.empty())
39 : {
40 : // A band name may be empty only if it is the only band present
41 : // in the REL file. Otherwise, inferring the band name from the
42 : // REL filename is considered an error.
43 : // Consequently, for a REL file containing exactly one band, if
44 : // the band name is empty, it shall be inferred from the REL
45 : // filename.
46 : // Example: REL: testI.rel --> IMG: test.img
47 58 : if (m_pfRel->GetNBands() >= 1)
48 0 : m_osBandFileName = "";
49 : else
50 : {
51 232 : m_osBandFileName = m_pfRel->MMRGetFileNameFromRelName(
52 174 : m_pfRel->GetRELName(), pszExtRaster);
53 : }
54 :
55 58 : if (m_osBandFileName.empty())
56 : {
57 0 : m_nWidth = 0;
58 0 : m_nHeight = 0;
59 0 : CPLError(CE_Failure, CPLE_AssertionFailed,
60 : "The REL file '%s' contains a documented \
61 : band with no explicit or wrong name. Section [%s] or [%s:%s].",
62 0 : m_pfRel->GetRELNameChar(), SECTION_ATTRIBUTE_DATA,
63 : SECTION_ATTRIBUTE_DATA, m_osBandSection.c_str());
64 0 : return;
65 : }
66 58 : m_osBandName = CPLGetBasenameSafe(m_osBandFileName);
67 58 : m_osRawBandFileName = m_osBandName;
68 : }
69 : else
70 : {
71 50 : m_osBandName = CPLGetBasenameSafe(m_osRawBandFileName);
72 50 : CPLString osAux = CPLGetPathSafe(m_pfRel->GetRELNameChar());
73 : m_osBandFileName =
74 50 : CPLFormFilenameSafe(osAux.c_str(), m_osRawBandFileName.c_str(), "");
75 :
76 : CPLString osExtension =
77 50 : CPLString(CPLGetExtensionSafe(m_osBandFileName).c_str());
78 50 : if (!EQUAL(osExtension, pszExtRaster + 1))
79 0 : return;
80 : }
81 :
82 : // There is a band file documented?
83 108 : if (m_osBandName.empty())
84 : {
85 0 : m_nWidth = 0;
86 0 : m_nHeight = 0;
87 0 : CPLError(CE_Failure, CPLE_AssertionFailed,
88 : "The REL file '%s' contains a documented \
89 : band with no explicit name. Section [%s] or [%s:%s].",
90 0 : m_pfRel->GetRELNameChar(), SECTION_ATTRIBUTE_DATA,
91 : SECTION_ATTRIBUTE_DATA, m_osBandSection.c_str());
92 0 : return;
93 : }
94 :
95 : // Getting essential metadata documented at
96 : // https://www.miramon.cat/new_note/eng/notes/MiraMon_raster_file_format.pdf
97 :
98 : // Getting number of columns and rows
99 108 : if (!UpdateColumnsNumberFromREL(m_osBandSection))
100 : {
101 1 : m_nWidth = 0;
102 1 : m_nHeight = 0;
103 1 : return;
104 : }
105 :
106 107 : if (!UpdateRowsNumberFromREL(m_osBandSection))
107 : {
108 1 : m_nWidth = 0;
109 1 : m_nHeight = 0;
110 1 : return;
111 : }
112 :
113 106 : if (m_nWidth <= 0 || m_nHeight <= 0)
114 : {
115 1 : m_nWidth = 0;
116 1 : m_nHeight = 0;
117 1 : CPLError(CE_Failure, CPLE_AppDefined,
118 : "MMRBand::MMRBand : (nWidth <= 0 || nHeight <= 0)");
119 1 : return;
120 : }
121 :
122 : // Getting data type and compression.
123 : // If error, message given inside.
124 105 : if (!UpdateDataTypeFromREL(m_osBandSection))
125 2 : return;
126 :
127 : // Let's see if there is RLE compression
128 103 : m_bIsCompressed =
129 154 : (((m_eMMDataType >= MMDataType::DATATYPE_AND_COMPR_BYTE_RLE) &&
130 155 : (m_eMMDataType <= MMDataType::DATATYPE_AND_COMPR_DOUBLE_RLE)) ||
131 52 : m_eMMDataType == MMDataType::DATATYPE_AND_COMPR_BIT);
132 :
133 : // Getting min and max values
134 103 : UpdateMinMaxValuesFromREL(m_osBandSection);
135 :
136 : // Getting unit type
137 103 : UpdateUnitTypeValueFromREL(m_osBandSection);
138 :
139 : // Getting min and max values for simbolization
140 103 : UpdateMinMaxVisuValuesFromREL(m_osBandSection);
141 103 : if (!m_bMinVisuSet)
142 : {
143 98 : if (m_bMinSet)
144 : {
145 95 : m_dfVisuMin = m_dfMin;
146 95 : m_bMinVisuSet = true;
147 : }
148 : }
149 103 : if (!m_bMaxVisuSet)
150 : {
151 98 : if (m_bMaxSet)
152 : {
153 95 : m_dfVisuMax = m_dfMax;
154 95 : m_bMaxVisuSet = true;
155 : }
156 : }
157 :
158 : // Getting the friendly description of the band
159 103 : UpdateFriendlyDescriptionFromREL(m_osBandSection);
160 :
161 : // Getting NoData value and definition
162 103 : UpdateNoDataValue(m_osBandSection);
163 :
164 : // Getting reference system and coordinates of the geographic bounding box
165 103 : UpdateReferenceSystemFromREL();
166 :
167 : // Getting the bounding box: coordinates in the terrain
168 103 : UpdateBoundingBoxFromREL(m_osBandSection);
169 :
170 : // Getting all information about simbolization
171 103 : UpdateSimbolizationInfo(m_osBandSection);
172 :
173 : // Getting all information about RAT
174 103 : UpdateRATInfo(m_osBandSection);
175 :
176 : // MiraMon IMG files are efficient in going to an specified row.
177 : // So le'ts configurate the blocks as line blocks.
178 103 : m_nBlockXSize = m_nWidth;
179 103 : m_nBlockYSize = 1;
180 103 : m_nNRowsPerBlock = 1;
181 :
182 : // Can the binary file that contains all data for this band be opened?
183 103 : m_pfIMG = VSIFOpenL(m_osBandFileName, "rb");
184 103 : if (!m_pfIMG)
185 : {
186 1 : m_nWidth = 0;
187 1 : m_nHeight = 0;
188 1 : CPLError(CE_Failure, CPLE_OpenFailed,
189 : "Failed to open MiraMon band file `%s' with access 'rb'.",
190 : m_osBandFileName.c_str());
191 1 : return;
192 : }
193 :
194 : // We have a valid MMRBand.
195 102 : m_bIsValid = true;
196 : }
197 :
198 : /************************************************************************/
199 : /* ~MMRBand() */
200 : /************************************************************************/
201 198 : MMRBand::~MMRBand()
202 : {
203 108 : if (m_pfIMG == nullptr)
204 6 : return;
205 :
206 102 : CPL_IGNORE_RET_VAL(VSIFCloseL(m_pfIMG));
207 102 : m_pfIMG = nullptr;
208 108 : }
209 :
210 40 : const CPLString MMRBand::GetRELFileName() const
211 : {
212 40 : if (!m_pfRel)
213 0 : return "";
214 40 : return m_pfRel->GetRELName();
215 : }
216 :
217 : /************************************************************************/
218 : /* GetRasterBlock() */
219 : /************************************************************************/
220 115 : CPLErr MMRBand::GetRasterBlock(int /*nXBlock*/, int nYBlock, void *pData,
221 : int nDataSize)
222 :
223 : {
224 115 : if (nYBlock > INT_MAX / (std::max(1, m_nNRowsPerBlock)))
225 : {
226 0 : CPLError(CE_Failure, CPLE_OutOfMemory, "Error in GetRasterBlock");
227 0 : return CE_Failure;
228 : }
229 115 : const int iBlock = nYBlock * m_nNRowsPerBlock;
230 :
231 115 : if (m_nBlockXSize > INT_MAX / (std::max(1, m_nDataTypeSizeBytes)))
232 : {
233 0 : CPLError(CE_Failure, CPLE_OutOfMemory, "Error in GetRasterBlock");
234 0 : return CE_Failure;
235 : }
236 :
237 230 : if (m_nBlockYSize >
238 115 : INT_MAX / (std::max(1, m_nDataTypeSizeBytes * m_nBlockXSize)))
239 : {
240 0 : CPLError(CE_Failure, CPLE_OutOfMemory, "Error in GetRasterBlock");
241 0 : return CE_Failure;
242 : }
243 :
244 115 : const int nGDALBlockSize =
245 115 : m_nDataTypeSizeBytes * m_nBlockXSize * m_nBlockYSize;
246 :
247 : // Calculate block offset in case we have spill file. Use predefined
248 : // block map otherwise.
249 :
250 115 : if (nDataSize != -1 && nGDALBlockSize > nDataSize)
251 : {
252 0 : CPLError(CE_Failure, CPLE_AppDefined, "Invalid block size: %d",
253 : nGDALBlockSize);
254 0 : return CE_Failure;
255 : }
256 :
257 : // Getting the row offsets to optimize access.
258 115 : if (FillRowOffsets() == false || m_aFileOffsets.empty())
259 : {
260 0 : CPLError(CE_Failure, CPLE_AppDefined,
261 : "Some error in offsets calculation");
262 0 : return CE_Failure;
263 : }
264 :
265 : // Read the block in the documented or deduced offset
266 115 : if (VSIFSeekL(m_pfIMG, m_aFileOffsets[iBlock], SEEK_SET))
267 : {
268 0 : CPLError(CE_Failure, CPLE_AppDefined,
269 : "Read from invalid offset for grid block.");
270 0 : return CE_Failure;
271 : }
272 :
273 : size_t nCompressedRawSize;
274 115 : if (iBlock == m_nHeight - 1)
275 35 : nCompressedRawSize = SIZE_MAX; // We don't know it
276 : else
277 160 : nCompressedRawSize = static_cast<size_t>(m_aFileOffsets[iBlock + 1] -
278 80 : m_aFileOffsets[iBlock]);
279 :
280 115 : return GetBlockData(pData, nCompressedRawSize);
281 : }
282 :
283 61 : void MMRBand::UpdateGeoTransform()
284 : {
285 61 : m_gt.xorig = GetBoundingBoxMinX();
286 61 : m_gt.xscale = (GetBoundingBoxMaxX() - m_gt.xorig) / GetWidth();
287 61 : m_gt.xrot = 0.0; // No rotation in MiraMon rasters
288 61 : m_gt.yorig = GetBoundingBoxMaxY();
289 61 : m_gt.yrot = 0.0;
290 61 : m_gt.yscale = (GetBoundingBoxMinY() - m_gt.yorig) / GetHeight();
291 61 : }
292 :
293 : /************************************************************************/
294 : /* Other functions */
295 : /************************************************************************/
296 :
297 : // [ATTRIBUTE_DATA:xxxx] or [OVERVIEW:ASPECTES_TECNICS]
298 215 : bool MMRBand::Get_ATTRIBUTE_DATA_or_OVERVIEW_ASPECTES_TECNICS_int(
299 : const CPLString &osSection, const char *pszKey, int *nValue,
300 : const char *pszErrorMessage)
301 : {
302 215 : if (osSection.empty() || !pszKey || !nValue)
303 0 : return false;
304 :
305 430 : CPLString osValue;
306 215 : if (!m_pfRel->GetMetadataValue(SECTION_ATTRIBUTE_DATA, osSection, pszKey,
307 217 : osValue) ||
308 2 : osValue.empty())
309 : {
310 213 : if (m_pfRel->GetMetadataValue(SECTION_OVERVIEW,
311 : SECTION_ASPECTES_TECNICS, pszKey,
312 424 : osValue) == false ||
313 211 : osValue.empty())
314 : {
315 2 : if (pszErrorMessage)
316 2 : CPLError(CE_Failure, CPLE_AppDefined, "%s", pszErrorMessage);
317 2 : return false;
318 : }
319 : }
320 :
321 213 : if (1 != sscanf(osValue, "%d", nValue))
322 : {
323 0 : if (pszErrorMessage)
324 0 : CPLError(CE_Failure, CPLE_AppDefined, "%s", pszErrorMessage);
325 0 : return false;
326 : }
327 213 : return true;
328 : }
329 :
330 104 : bool MMRBand::GetDataTypeAndBytesPerPixel(const char *pszCompType,
331 : MMDataType *nCompressionType,
332 : MMBytesPerPixel *nBytesPerPixel)
333 : {
334 104 : if (!nCompressionType || !nBytesPerPixel || !pszCompType)
335 0 : return false;
336 :
337 104 : if (EQUAL(pszCompType, "bit"))
338 : {
339 2 : *nCompressionType = MMDataType::DATATYPE_AND_COMPR_BIT;
340 2 : *nBytesPerPixel = MMBytesPerPixel::TYPE_BYTES_PER_PIXEL_BYTE_I_RLE;
341 2 : return true;
342 : }
343 102 : if (EQUAL(pszCompType, "byte"))
344 : {
345 35 : *nCompressionType = MMDataType::DATATYPE_AND_COMPR_BYTE;
346 35 : *nBytesPerPixel = MMBytesPerPixel::TYPE_BYTES_PER_PIXEL_BYTE_I_RLE;
347 35 : return true;
348 : }
349 67 : if (EQUAL(pszCompType, "byte-RLE"))
350 : {
351 25 : *nCompressionType = MMDataType::DATATYPE_AND_COMPR_BYTE_RLE;
352 25 : *nBytesPerPixel = MMBytesPerPixel::TYPE_BYTES_PER_PIXEL_BYTE_I_RLE;
353 25 : return true;
354 : }
355 42 : if (EQUAL(pszCompType, "integer"))
356 : {
357 3 : *nCompressionType = MMDataType::DATATYPE_AND_COMPR_INTEGER;
358 3 : *nBytesPerPixel = MMBytesPerPixel::TYPE_BYTES_PER_PIXEL_INTEGER_I_RLE;
359 3 : return true;
360 : }
361 39 : if (EQUAL(pszCompType, "integer-RLE"))
362 : {
363 16 : *nCompressionType = MMDataType::DATATYPE_AND_COMPR_INTEGER_RLE;
364 16 : *nBytesPerPixel = MMBytesPerPixel::TYPE_BYTES_PER_PIXEL_INTEGER_I_RLE;
365 16 : return true;
366 : }
367 23 : if (EQUAL(pszCompType, "uinteger"))
368 : {
369 4 : *nCompressionType = MMDataType::DATATYPE_AND_COMPR_UINTEGER;
370 4 : *nBytesPerPixel = MMBytesPerPixel::TYPE_BYTES_PER_PIXEL_INTEGER_I_RLE;
371 4 : return true;
372 : }
373 19 : if (EQUAL(pszCompType, "uinteger-RLE"))
374 : {
375 2 : *nCompressionType = MMDataType::DATATYPE_AND_COMPR_UINTEGER_RLE;
376 2 : *nBytesPerPixel = MMBytesPerPixel::TYPE_BYTES_PER_PIXEL_INTEGER_I_RLE;
377 2 : return true;
378 : }
379 17 : if (EQUAL(pszCompType, "long"))
380 : {
381 3 : *nCompressionType = MMDataType::DATATYPE_AND_COMPR_LONG;
382 3 : *nBytesPerPixel = MMBytesPerPixel::TYPE_BYTES_PER_PIXEL_LONG_REAL_I_RLE;
383 3 : return true;
384 : }
385 14 : if (EQUAL(pszCompType, "long-RLE"))
386 : {
387 2 : *nCompressionType = MMDataType::DATATYPE_AND_COMPR_LONG_RLE;
388 2 : *nBytesPerPixel = MMBytesPerPixel::TYPE_BYTES_PER_PIXEL_LONG_REAL_I_RLE;
389 2 : return true;
390 : }
391 12 : if (EQUAL(pszCompType, "real"))
392 : {
393 3 : *nCompressionType = MMDataType::DATATYPE_AND_COMPR_REAL;
394 3 : *nBytesPerPixel = MMBytesPerPixel::TYPE_BYTES_PER_PIXEL_LONG_REAL_I_RLE;
395 3 : return true;
396 : }
397 9 : if (EQUAL(pszCompType, "real-RLE"))
398 : {
399 2 : *nCompressionType = MMDataType::DATATYPE_AND_COMPR_REAL_RLE;
400 2 : *nBytesPerPixel = MMBytesPerPixel::TYPE_BYTES_PER_PIXEL_LONG_REAL_I_RLE;
401 2 : return true;
402 : }
403 7 : if (EQUAL(pszCompType, "double"))
404 : {
405 2 : *nCompressionType = MMDataType::DATATYPE_AND_COMPR_DOUBLE;
406 2 : *nBytesPerPixel = MMBytesPerPixel::TYPE_BYTES_PER_PIXEL_DOUBLE_I_RLE;
407 2 : return true;
408 : }
409 5 : if (EQUAL(pszCompType, "double-RLE"))
410 : {
411 4 : *nCompressionType = MMDataType::DATATYPE_AND_COMPR_DOUBLE_RLE;
412 4 : *nBytesPerPixel = MMBytesPerPixel::TYPE_BYTES_PER_PIXEL_DOUBLE_I_RLE;
413 4 : return true;
414 : }
415 :
416 1 : return false;
417 : }
418 :
419 : // Getting data type from metadata
420 105 : bool MMRBand::UpdateDataTypeFromREL(const CPLString osSection)
421 : {
422 105 : m_eMMDataType = MMDataType::DATATYPE_AND_COMPR_UNDEFINED;
423 105 : m_eMMBytesPerPixel = MMBytesPerPixel::TYPE_BYTES_PER_PIXEL_UNDEFINED;
424 :
425 210 : CPLString osValue;
426 105 : if (!m_pfRel->GetMetadataValue(SECTION_ATTRIBUTE_DATA, osSection,
427 210 : "TipusCompressio", osValue) ||
428 105 : osValue.empty())
429 : {
430 1 : m_nWidth = 0;
431 1 : m_nHeight = 0;
432 1 : CPLError(CE_Failure, CPLE_AppDefined,
433 : "MiraMonRaster: no nDataType documented");
434 1 : return false;
435 : }
436 :
437 104 : if (!GetDataTypeAndBytesPerPixel(osValue.c_str(), &m_eMMDataType,
438 : &m_eMMBytesPerPixel))
439 : {
440 1 : m_nWidth = 0;
441 1 : m_nHeight = 0;
442 1 : CPLError(CE_Failure, CPLE_AppDefined,
443 : "MiraMonRaster: data type unhandled");
444 1 : return false;
445 : }
446 :
447 103 : m_nDataTypeSizeBytes = std::max(1, static_cast<int>(m_eMMBytesPerPixel));
448 103 : return true;
449 : }
450 :
451 : // Getting number of columns from metadata
452 108 : bool MMRBand::UpdateColumnsNumberFromREL(const CPLString &osSection)
453 : {
454 108 : return Get_ATTRIBUTE_DATA_or_OVERVIEW_ASPECTES_TECNICS_int(
455 : osSection, "columns", &m_nWidth,
456 108 : "MMRBand::MMRBand : No number of columns documented");
457 : }
458 :
459 107 : bool MMRBand::UpdateRowsNumberFromREL(const CPLString &osSection)
460 : {
461 107 : return Get_ATTRIBUTE_DATA_or_OVERVIEW_ASPECTES_TECNICS_int(
462 : osSection, "rows", &m_nHeight,
463 107 : "MMRBand::MMRBand : No number of rows documented");
464 : }
465 :
466 : // Getting nodata value from metadata
467 103 : void MMRBand::UpdateNoDataValue(const CPLString &osSection)
468 : {
469 206 : CPLString osValue;
470 103 : if (!m_pfRel->GetMetadataValue(SECTION_ATTRIBUTE_DATA, osSection, "NODATA",
471 158 : osValue) ||
472 55 : osValue.empty())
473 : {
474 62 : m_dfNoData = 0; // No a valid value.
475 62 : m_bNoDataSet = false;
476 : }
477 : else
478 : {
479 41 : m_dfNoData = CPLAtof(osValue);
480 41 : m_bNoDataSet = true;
481 : }
482 103 : }
483 :
484 103 : void MMRBand::UpdateMinMaxValuesFromREL(const CPLString &osSection)
485 : {
486 103 : m_bMinSet = false;
487 :
488 206 : CPLString osValue;
489 :
490 206 : CPLString osAuxSection = SECTION_ATTRIBUTE_DATA;
491 103 : osAuxSection.append(":");
492 103 : osAuxSection.append(osSection);
493 206 : if (m_pfRel->GetMetadataValue(osAuxSection, "min", osValue) &&
494 103 : !osValue.empty())
495 : {
496 100 : if (1 == CPLsscanf(osValue, "%lf", &m_dfMin))
497 100 : m_bMinSet = true;
498 : }
499 :
500 103 : m_bMaxSet = false;
501 206 : if (m_pfRel->GetMetadataValue(osAuxSection, "max", osValue) &&
502 103 : !osValue.empty())
503 : {
504 100 : if (1 == CPLsscanf(osValue, "%lf", &m_dfMax))
505 100 : m_bMaxSet = true;
506 : }
507 :
508 : // Special case: dfMin > dfMax
509 103 : if (m_bMinSet && m_bMaxSet && m_dfMin > m_dfMax)
510 : {
511 0 : m_bMinSet = false;
512 0 : m_bMaxSet = false;
513 : }
514 103 : }
515 :
516 103 : void MMRBand::UpdateUnitTypeValueFromREL(const CPLString &osSection)
517 : {
518 206 : CPLString osValue;
519 :
520 206 : CPLString osAuxSection = SECTION_ATTRIBUTE_DATA;
521 103 : osAuxSection.append(":");
522 103 : osAuxSection.append(osSection);
523 109 : if (m_pfRel->GetMetadataValue(osAuxSection, "unitats", osValue) &&
524 6 : !osValue.empty())
525 : {
526 6 : m_osBandUnitType = osValue;
527 : }
528 103 : }
529 :
530 103 : void MMRBand::UpdateMinMaxVisuValuesFromREL(const CPLString &osSection)
531 : {
532 103 : m_bMinVisuSet = false;
533 103 : m_dfVisuMin = 1;
534 :
535 206 : CPLString osValue;
536 103 : if (m_pfRel->GetMetadataValue(SECTION_COLOR_TEXT, osSection,
537 108 : "Color_ValorColor_0", osValue) &&
538 5 : !osValue.empty())
539 : {
540 5 : if (1 == CPLsscanf(osValue, "%lf", &m_dfVisuMin))
541 5 : m_bMinVisuSet = true;
542 : }
543 :
544 103 : m_bMaxVisuSet = false;
545 103 : m_dfVisuMax = 1;
546 :
547 103 : if (m_pfRel->GetMetadataValue(SECTION_COLOR_TEXT, osSection,
548 108 : "Color_ValorColor_n_1", osValue) &&
549 5 : !osValue.empty())
550 : {
551 5 : if (1 == CPLsscanf(osValue, "%lf", &m_dfVisuMax))
552 5 : m_bMaxVisuSet = true;
553 : }
554 103 : }
555 :
556 103 : void MMRBand::UpdateFriendlyDescriptionFromREL(const CPLString &osSection)
557 : {
558 : // This "if" is due to CID 1620830 in Coverity Scan
559 103 : if (!m_pfRel->GetMetadataValue(SECTION_ATTRIBUTE_DATA, osSection,
560 103 : KEY_descriptor, m_osFriendlyDescription))
561 10 : m_osFriendlyDescription = "";
562 103 : }
563 :
564 103 : void MMRBand::UpdateReferenceSystemFromREL()
565 : {
566 : // This "if" is due to CID 1620842 in Coverity Scan
567 103 : if (!m_pfRel->GetMetadataValue("SPATIAL_REFERENCE_SYSTEM:HORIZONTAL",
568 103 : "HorizontalSystemIdentifier", m_osRefSystem))
569 0 : m_osRefSystem = "";
570 103 : }
571 :
572 103 : void MMRBand::UpdateBoundingBoxFromREL(const CPLString &osSection)
573 : {
574 : // Bounding box of the band
575 : // [ATTRIBUTE_DATA:xxxx:EXTENT] or [EXTENT]
576 206 : CPLString osValue;
577 103 : if (!m_pfRel->GetMetadataValue(SECTION_ATTRIBUTE_DATA, osSection,
578 196 : SECTION_EXTENT, "MinX", osValue) ||
579 93 : osValue.empty())
580 : {
581 10 : m_dfBBMinX = 0;
582 : }
583 : else
584 : {
585 93 : if (1 != CPLsscanf(osValue, "%lf", &m_dfBBMinX))
586 0 : m_dfBBMinX = 0;
587 : }
588 :
589 103 : if (!m_pfRel->GetMetadataValue(SECTION_ATTRIBUTE_DATA, osSection,
590 196 : SECTION_EXTENT, "MaxX", osValue) ||
591 93 : osValue.empty())
592 : {
593 10 : m_dfBBMaxX = m_nWidth;
594 : }
595 : else
596 : {
597 93 : if (1 != CPLsscanf(osValue, "%lf", &m_dfBBMaxX))
598 : {
599 : // If the value is something that cannot be scanned,
600 : // we silently continue as it was undefined.
601 0 : m_dfBBMaxX = m_nWidth;
602 : }
603 : }
604 :
605 103 : if (!m_pfRel->GetMetadataValue(SECTION_ATTRIBUTE_DATA, osSection,
606 196 : SECTION_EXTENT, "MinY", osValue) ||
607 93 : osValue.empty())
608 : {
609 10 : m_dfBBMinY = 0;
610 : }
611 : else
612 : {
613 93 : if (1 != CPLsscanf(osValue, "%lf", &m_dfBBMinY))
614 0 : m_dfBBMinY = 0;
615 : }
616 :
617 103 : if (!m_pfRel->GetMetadataValue(SECTION_ATTRIBUTE_DATA, osSection,
618 196 : SECTION_EXTENT, "MaxY", osValue) ||
619 93 : osValue.empty())
620 : {
621 10 : m_dfBBMaxY = m_nHeight;
622 : }
623 : else
624 : {
625 93 : if (1 != CPLsscanf(osValue, "%lf", &m_dfBBMaxY))
626 : {
627 : // If the value is something that cannot be scanned,
628 : // we silently continue as it was undefined.
629 0 : m_dfBBMaxY = m_nHeight;
630 : }
631 : }
632 103 : }
633 :
634 103 : void MMRBand::UpdateSimbolizationInfo(const CPLString &osSection)
635 : {
636 103 : m_pfRel->GetMetadataValue(SECTION_COLOR_TEXT, osSection, "Color_Const",
637 103 : m_osColor_Const);
638 :
639 103 : if (EQUAL(m_osColor_Const, "1"))
640 : {
641 1 : if (CE_None == m_pfRel->UpdateGDALColorEntryFromBand(
642 1 : osSection, m_sConstantColorRGB))
643 1 : m_osValidColorConst = true;
644 : }
645 :
646 103 : m_pfRel->GetMetadataValue(SECTION_COLOR_TEXT, osSection, "Color_Paleta",
647 103 : m_osColor_Paleta);
648 :
649 : // Treatment of the color variable
650 103 : m_pfRel->GetMetadataValue(SECTION_COLOR_TEXT, osSection,
651 : "Color_TractamentVariable",
652 103 : m_osColor_TractamentVariable);
653 :
654 103 : m_pfRel->GetMetadataValue(SECTION_ATTRIBUTE_DATA, osSection,
655 103 : KEY_TractamentVariable, m_osTractamentVariable);
656 :
657 : // Is categorical?
658 103 : if (m_osTractamentVariable.empty())
659 : {
660 8 : m_bIsCategorical = false;
661 : }
662 : else
663 : {
664 95 : if (EQUAL(m_osTractamentVariable, "Categoric"))
665 89 : m_bIsCategorical = true;
666 : else
667 6 : m_bIsCategorical = false;
668 : }
669 :
670 103 : m_pfRel->GetMetadataValue(SECTION_COLOR_TEXT, osSection,
671 103 : "Color_EscalatColor", m_osColor_EscalatColor);
672 :
673 103 : m_pfRel->GetMetadataValue(SECTION_COLOR_TEXT, osSection,
674 : "Color_N_SimbolsALaTaula",
675 103 : m_osColor_N_SimbolsALaTaula);
676 103 : }
677 :
678 103 : void MMRBand::UpdateRATInfo(const CPLString &osSection)
679 : {
680 103 : CPLString os_IndexJoin;
681 :
682 103 : if (!m_pfRel->GetMetadataValue(SECTION_ATTRIBUTE_DATA, osSection,
683 181 : "IndexsJoinTaula", os_IndexJoin) ||
684 78 : os_IndexJoin.empty())
685 : {
686 25 : return;
687 : }
688 :
689 : // Let's see if there is any table that can ve converted to RAT
690 78 : const CPLStringList aosTokens(CSLTokenizeString2(os_IndexJoin, ",", 0));
691 78 : const int nTokens = CSLCount(aosTokens);
692 78 : if (nTokens < 1)
693 0 : return;
694 :
695 78 : CPLString os_Join = "JoinTaula";
696 78 : os_Join.append("_");
697 78 : os_Join.append(aosTokens[0]);
698 :
699 78 : CPLString osTableNameSection_value;
700 78 : if (!m_pfRel->GetMetadataValue(SECTION_ATTRIBUTE_DATA, osSection, os_Join,
701 156 : osTableNameSection_value) ||
702 78 : osTableNameSection_value.empty())
703 0 : return;
704 :
705 78 : CPLString osTableNameSection = "TAULA_";
706 78 : osTableNameSection.append(osTableNameSection_value);
707 :
708 78 : if (!m_pfRel->GetMetadataValue(osTableNameSection, KEY_NomFitxer,
709 156 : m_osShortRATName) ||
710 78 : m_osShortRATName.empty())
711 : {
712 0 : m_osAssociateREL = "";
713 0 : return;
714 : }
715 :
716 78 : m_pfRel->GetMetadataValue(osTableNameSection, "AssociatRel",
717 78 : m_osAssociateREL);
718 : }
719 :
720 : /************************************************************************/
721 : /* Functions that read bytes from IMG file band */
722 : /************************************************************************/
723 : template <typename TYPE>
724 54 : CPLErr MMRBand::UncompressRow(void *rowBuffer, size_t nCompressedRawSize)
725 : {
726 54 : int nAccumulated = 0L, nIAccumulated = 0L;
727 : unsigned char cCounter;
728 54 : size_t nCompressedIndex = 0;
729 :
730 : TYPE RLEValue;
731 : TYPE *pDst;
732 54 : size_t sizeof_TYPE = sizeof(TYPE);
733 :
734 108 : std::vector<unsigned char> aCompressedRow;
735 :
736 54 : if (nCompressedRawSize != SIZE_MAX)
737 : {
738 32 : if (nCompressedRawSize > 1000 * 1000 &&
739 0 : GetFileSize() < nCompressedRawSize)
740 : {
741 0 : CPLError(CE_Failure, CPLE_AppDefined, "Too small file");
742 0 : return CE_Failure;
743 : }
744 : try
745 : {
746 32 : aCompressedRow.resize(nCompressedRawSize);
747 : }
748 0 : catch (const std::exception &)
749 : {
750 0 : CPLError(CE_Failure, CPLE_OutOfMemory,
751 : "Out of memory allocating working buffer");
752 0 : return CE_Failure;
753 : }
754 32 : if (VSIFReadL(aCompressedRow.data(), nCompressedRawSize, 1, m_pfIMG) !=
755 : 1)
756 0 : return CE_Failure;
757 : }
758 :
759 162 : while (nAccumulated < m_nWidth)
760 : {
761 108 : if (nCompressedRawSize == SIZE_MAX)
762 : {
763 44 : if (VSIFReadL(&cCounter, 1, 1, m_pfIMG) != 1)
764 0 : return CE_Failure;
765 : }
766 : else
767 : {
768 64 : if (nCompressedIndex >= aCompressedRow.size())
769 : {
770 0 : CPLError(CE_Failure, CPLE_AppDefined,
771 : "Invalid nCompressedIndex");
772 0 : return CE_Failure;
773 : }
774 64 : cCounter = aCompressedRow[nCompressedIndex];
775 64 : nCompressedIndex++;
776 : }
777 :
778 108 : if (cCounter == 0) /* Not compressed part */
779 : {
780 : /* The following counter read does not indicate
781 : "how many repeated values follow" but rather
782 : "how many are decompressed in standard raster format" */
783 0 : if (nCompressedRawSize == SIZE_MAX)
784 : {
785 0 : if (VSIFReadL(&cCounter, 1, 1, m_pfIMG) != 1)
786 0 : return CE_Failure;
787 : }
788 : else
789 : {
790 0 : if (nCompressedIndex >= aCompressedRow.size())
791 : {
792 0 : CPLError(CE_Failure, CPLE_AppDefined,
793 : "Invalid nCompressedIndex");
794 0 : return CE_Failure;
795 : }
796 0 : cCounter = aCompressedRow[nCompressedIndex];
797 0 : nCompressedIndex++;
798 : }
799 :
800 0 : nAccumulated += cCounter;
801 :
802 0 : if (nAccumulated > m_nWidth) /* This should not happen if the file
803 : is RLE and does not share counters across rows */
804 0 : return CE_Failure;
805 :
806 0 : for (; nIAccumulated < nAccumulated; nIAccumulated++)
807 : {
808 0 : if (nCompressedRawSize == SIZE_MAX)
809 : {
810 0 : VSIFReadL(&RLEValue, sizeof_TYPE, 1, m_pfIMG);
811 0 : memcpy((static_cast<TYPE *>(rowBuffer)) + nIAccumulated,
812 : &RLEValue, sizeof_TYPE);
813 : }
814 : else
815 : {
816 0 : if (nCompressedIndex + sizeof_TYPE > aCompressedRow.size())
817 : {
818 0 : CPLError(CE_Failure, CPLE_AppDefined,
819 : "Invalid nCompressedIndex");
820 0 : return CE_Failure;
821 : }
822 0 : memcpy((static_cast<TYPE *>(rowBuffer)) + nIAccumulated,
823 0 : &aCompressedRow[nCompressedIndex], sizeof_TYPE);
824 0 : nCompressedIndex += sizeof_TYPE;
825 : }
826 : }
827 : }
828 : else
829 : {
830 108 : nAccumulated += cCounter;
831 108 : if (nAccumulated > m_nWidth) /* This should not happen if the file
832 : is RLE and does not share counters across rows */
833 0 : return CE_Failure;
834 :
835 108 : if (nCompressedRawSize == SIZE_MAX)
836 : {
837 44 : if (VSIFReadL(&RLEValue, sizeof_TYPE, 1, m_pfIMG) != 1)
838 0 : return CE_Failure;
839 : }
840 : else
841 : {
842 64 : if (nCompressedIndex + sizeof(TYPE) > aCompressedRow.size())
843 : {
844 0 : CPLError(CE_Failure, CPLE_AppDefined,
845 : "Invalid nCompressedIndex");
846 0 : return CE_Failure;
847 : }
848 64 : memcpy(&RLEValue, &aCompressedRow[nCompressedIndex],
849 : sizeof(TYPE));
850 64 : nCompressedIndex += sizeof(TYPE);
851 : }
852 :
853 108 : const int nCount = nAccumulated - nIAccumulated;
854 108 : pDst = static_cast<TYPE *>(rowBuffer) + nIAccumulated;
855 :
856 108 : std::fill(pDst, pDst + nCount, RLEValue);
857 :
858 108 : nIAccumulated = nAccumulated;
859 : }
860 : }
861 :
862 54 : return CE_None;
863 : }
864 :
865 121 : CPLErr MMRBand::GetBlockData(void *rowBuffer, size_t nCompressedRawSize)
866 : {
867 121 : if (m_eMMDataType == MMDataType::DATATYPE_AND_COMPR_BIT)
868 : {
869 16 : const int nGDALBlockSize = DIV_ROUND_UP(m_nBlockXSize, 8);
870 :
871 16 : if (VSIFReadL(rowBuffer, nGDALBlockSize, 1, m_pfIMG) != 1)
872 : {
873 0 : CPLError(CE_Failure, CPLE_AppDefined, "Error while reading band");
874 0 : return CE_Failure;
875 : }
876 16 : return CE_None;
877 : }
878 :
879 105 : if (m_eMMDataType == MMDataType::DATATYPE_AND_COMPR_BYTE ||
880 84 : m_eMMDataType == MMDataType::DATATYPE_AND_COMPR_INTEGER ||
881 78 : m_eMMDataType == MMDataType::DATATYPE_AND_COMPR_UINTEGER ||
882 72 : m_eMMDataType == MMDataType::DATATYPE_AND_COMPR_LONG ||
883 66 : m_eMMDataType == MMDataType::DATATYPE_AND_COMPR_REAL ||
884 60 : m_eMMDataType == MMDataType::DATATYPE_AND_COMPR_DOUBLE)
885 : {
886 51 : if (VSIFReadL(rowBuffer, m_nDataTypeSizeBytes, m_nWidth, m_pfIMG) !=
887 51 : static_cast<size_t>(m_nWidth))
888 : {
889 0 : CPLError(CE_Failure, CPLE_AppDefined, "Error while reading band");
890 0 : return CE_Failure;
891 : }
892 51 : return CE_None;
893 : }
894 :
895 : CPLErr eErr;
896 54 : switch (m_eMMDataType)
897 : {
898 24 : case MMDataType::DATATYPE_AND_COMPR_BYTE_RLE:
899 24 : eErr = UncompressRow<GByte>(rowBuffer, nCompressedRawSize);
900 24 : break;
901 6 : case MMDataType::DATATYPE_AND_COMPR_INTEGER_RLE:
902 6 : eErr = UncompressRow<GInt16>(rowBuffer, nCompressedRawSize);
903 6 : break;
904 6 : case MMDataType::DATATYPE_AND_COMPR_UINTEGER_RLE:
905 6 : eErr = UncompressRow<GUInt16>(rowBuffer, nCompressedRawSize);
906 6 : break;
907 6 : case MMDataType::DATATYPE_AND_COMPR_LONG_RLE:
908 6 : eErr = UncompressRow<GInt32>(rowBuffer, nCompressedRawSize);
909 6 : break;
910 6 : case MMDataType::DATATYPE_AND_COMPR_REAL_RLE:
911 6 : eErr = UncompressRow<float>(rowBuffer, nCompressedRawSize);
912 6 : break;
913 6 : case MMDataType::DATATYPE_AND_COMPR_DOUBLE_RLE:
914 6 : eErr = UncompressRow<double>(rowBuffer, nCompressedRawSize);
915 6 : break;
916 :
917 0 : default:
918 0 : CPLError(CE_Failure, CPLE_AppDefined, "Error in datatype");
919 0 : eErr = CE_Failure;
920 : }
921 :
922 54 : return eErr;
923 : } // End of GetBlockData()
924 :
925 16 : int MMRBand::PositionAtStartOfRowOffsetsInFile()
926 : {
927 : vsi_l_offset nFileSize, nHeaderOffset;
928 : char szChain[16];
929 : GInt16 nVersion, nSubVersion;
930 : int nOffsetSize, nOffsetsSectionType;
931 :
932 16 : if (VSIFSeekL(m_pfIMG, 0, SEEK_END))
933 0 : return 0;
934 :
935 16 : nFileSize = VSIFTellL(m_pfIMG);
936 :
937 16 : if (nFileSize < 32) // Minimum required size
938 2 : return 0;
939 :
940 14 : if (m_nHeight)
941 : {
942 14 : if (nFileSize < static_cast<vsi_l_offset>(32) + m_nHeight + 32)
943 0 : return 0;
944 : }
945 :
946 14 : vsi_l_offset nHeadOffset = nFileSize - 32;
947 :
948 14 : if (VSIFSeekL(m_pfIMG, nHeadOffset, SEEK_SET)) // Reading final header.
949 0 : return 0;
950 14 : if (VSIFReadL(szChain, 16, 1, m_pfIMG) != 1)
951 0 : return 0;
952 238 : for (int nIndex = 0; nIndex < 16; nIndex++)
953 : {
954 224 : if (szChain[nIndex] != '\0')
955 0 : return 0; // Supposed 0's are not 0.
956 : }
957 :
958 14 : if (VSIFReadL(szChain, 8, 1, m_pfIMG) != 1)
959 0 : return 0;
960 :
961 14 : if (strncmp(szChain, "IMG ", 4) || szChain[5] != '.')
962 0 : return 0;
963 :
964 : // Some version checks
965 14 : szChain[7] = 0;
966 14 : if (sscanf(szChain + 6, "%hd", &nSubVersion) != 1 || nSubVersion < 0)
967 0 : return 0;
968 :
969 14 : szChain[5] = 0;
970 14 : if (sscanf(szChain + 4, "%hd", &nVersion) != 1 || nVersion != 1)
971 0 : return 0;
972 :
973 : // Next header to be read
974 14 : if (VSIFReadL(&nHeaderOffset, sizeof(vsi_l_offset), 1, m_pfIMG) != 1)
975 0 : return 0;
976 :
977 28 : std::set<vsi_l_offset> alreadyVisitedOffsets;
978 : bool bRepeat;
979 14 : do
980 : {
981 14 : bRepeat = FALSE;
982 :
983 14 : if (VSIFSeekL(m_pfIMG, nHeaderOffset, SEEK_SET))
984 0 : return 0;
985 :
986 14 : if (VSIFReadL(szChain, 8, 1, m_pfIMG) != 1)
987 0 : return 0;
988 :
989 14 : if (strncmp(szChain, "IMG ", 4) || szChain[5] != '.')
990 0 : return 0;
991 :
992 14 : if (VSIFReadL(&nOffsetsSectionType, 4, 1, m_pfIMG) != 1)
993 0 : return 0;
994 :
995 14 : if (nOffsetsSectionType != 2) // 2 = row offsets section
996 : {
997 : // This is not the section I am looking for
998 0 : if (VSIFSeekL(m_pfIMG, 8 + 4, SEEK_CUR))
999 0 : return 0;
1000 :
1001 0 : if (VSIFReadL(&nHeaderOffset, sizeof(vsi_l_offset), 1, m_pfIMG) !=
1002 : 1)
1003 0 : return 0;
1004 :
1005 0 : if (nHeaderOffset == 0)
1006 0 : return 0;
1007 :
1008 0 : if (cpl::contains(alreadyVisitedOffsets, nHeaderOffset))
1009 : {
1010 0 : CPLError(CE_Failure, CPLE_AssertionFailed,
1011 : "Error reading offsets. They will be ignored.");
1012 0 : return 0;
1013 : }
1014 :
1015 0 : alreadyVisitedOffsets.insert(nHeaderOffset);
1016 :
1017 0 : bRepeat = TRUE;
1018 : }
1019 :
1020 : } while (bRepeat);
1021 :
1022 14 : szChain[7] = 0;
1023 14 : if (sscanf(szChain + 6, "%hd", &nSubVersion) != 1 || nSubVersion < 0)
1024 0 : return 0;
1025 14 : szChain[5] = 0;
1026 14 : if (sscanf(szChain + 4, "%hd", &nVersion) != 1 || nVersion != 1)
1027 0 : return 0;
1028 :
1029 : /*
1030 : Now I'm in the correct section
1031 : -------------------------------
1032 : Info about this section:
1033 : RasterRLE: minimum size: nHeight*2
1034 : Offsets: minimum size: 32+nHeight*4
1035 : Final: size: 32
1036 : */
1037 :
1038 14 : if (m_nHeight)
1039 : {
1040 14 : if (nHeaderOffset < static_cast<vsi_l_offset>(m_nHeight) *
1041 14 : 2 || // Minimum size of an RLE
1042 14 : nFileSize - nHeaderOffset <
1043 14 : static_cast<vsi_l_offset>(32) + m_nHeight +
1044 : 32) // Minimum size of the section in version 1.0
1045 0 : return 0;
1046 : }
1047 :
1048 28 : if (VSIFReadL(&nOffsetSize, 4, 1, m_pfIMG) != 1 ||
1049 14 : (nOffsetSize != 8 && nOffsetSize != 4 && nOffsetSize != 2 &&
1050 14 : nOffsetSize != 1))
1051 0 : return 0;
1052 :
1053 14 : if (m_nHeight)
1054 : {
1055 14 : if (nFileSize - nHeaderOffset <
1056 14 : 32 + static_cast<vsi_l_offset>(nOffsetSize) * m_nHeight +
1057 : 32) // No space for this section in this file
1058 0 : return 0;
1059 :
1060 : // I leave the file prepared to read offsets
1061 14 : if (VSIFSeekL(m_pfIMG, 16, SEEK_CUR))
1062 0 : return 0;
1063 : }
1064 : else
1065 : {
1066 0 : if (VSIFSeekL(m_pfIMG, 4, SEEK_CUR))
1067 0 : return 0;
1068 :
1069 0 : if (VSIFSeekL(m_pfIMG, 4, SEEK_CUR))
1070 0 : return 0;
1071 :
1072 : // I leave the file prepared to read offsets
1073 0 : if (VSIFSeekL(m_pfIMG, 8, SEEK_CUR))
1074 0 : return 0;
1075 : }
1076 :
1077 : // There are offsets!
1078 14 : return nOffsetSize;
1079 : } // Fi de PositionAtStartOfRowOffsetsInFile()
1080 :
1081 : /************************************************************************/
1082 : /* GetFileSize() */
1083 : /************************************************************************/
1084 :
1085 0 : vsi_l_offset MMRBand::GetFileSize()
1086 : {
1087 0 : if (m_nFileSize == 0)
1088 : {
1089 0 : const auto nCurPos = VSIFTellL(m_pfIMG);
1090 0 : VSIFSeekL(m_pfIMG, 0, SEEK_END);
1091 0 : m_nFileSize = VSIFTellL(m_pfIMG);
1092 0 : VSIFSeekL(m_pfIMG, nCurPos, SEEK_SET);
1093 : }
1094 0 : return m_nFileSize;
1095 : }
1096 :
1097 : /************************************************************************/
1098 : /* FillRowOffsets() */
1099 : /************************************************************************/
1100 :
1101 115 : bool MMRBand::FillRowOffsets()
1102 : {
1103 : vsi_l_offset nStartOffset;
1104 : int nIRow;
1105 : vsi_l_offset nBytesPerPixelPerNCol;
1106 : int nSizeToRead; // nSizeToRead is not an offset, but the size of the offsets being read
1107 : // directly from the IMG file (can be 1, 2, 4, or 8).
1108 : vsi_l_offset nFileByte;
1109 : size_t nMaxBytesPerCompressedRow;
1110 115 : const int nGDALBlockSize = DIV_ROUND_UP(m_nBlockXSize, 8);
1111 :
1112 : // If it's filled, there is no need to fill it again
1113 115 : if (!m_aFileOffsets.empty())
1114 80 : return true;
1115 :
1116 : // Sanity check to avoid attempting huge memory allocation
1117 35 : if (m_nHeight > 1000 * 1000)
1118 : {
1119 0 : if (GetFileSize() < static_cast<vsi_l_offset>(m_nHeight))
1120 : {
1121 0 : CPLError(CE_Failure, CPLE_AppDefined, "Too small file");
1122 0 : return false;
1123 : }
1124 : }
1125 :
1126 : try
1127 : {
1128 35 : m_aFileOffsets.resize(static_cast<size_t>(m_nHeight) + 1);
1129 : }
1130 0 : catch (const std::bad_alloc &e)
1131 : {
1132 0 : CPLError(CE_Failure, CPLE_OutOfMemory, "%s", e.what());
1133 0 : return false;
1134 : }
1135 :
1136 35 : switch (m_eMMDataType)
1137 : {
1138 2 : case MMDataType::DATATYPE_AND_COMPR_BIT:
1139 :
1140 : // "<=" it's ok. There is space and it's to make easier the programming
1141 20 : for (nIRow = 0; nIRow <= m_nHeight; nIRow++)
1142 18 : m_aFileOffsets[nIRow] =
1143 18 : static_cast<vsi_l_offset>(nIRow) * nGDALBlockSize;
1144 2 : break;
1145 :
1146 17 : case MMDataType::DATATYPE_AND_COMPR_BYTE:
1147 : case MMDataType::DATATYPE_AND_COMPR_INTEGER:
1148 : case MMDataType::DATATYPE_AND_COMPR_UINTEGER:
1149 : case MMDataType::DATATYPE_AND_COMPR_LONG:
1150 : case MMDataType::DATATYPE_AND_COMPR_REAL:
1151 : case MMDataType::DATATYPE_AND_COMPR_DOUBLE:
1152 17 : nBytesPerPixelPerNCol =
1153 17 : m_nDataTypeSizeBytes * static_cast<vsi_l_offset>(m_nWidth);
1154 : // "<=" it's ok. There is space and it's to make easier the programming
1155 85 : for (nIRow = 0; nIRow <= m_nHeight; nIRow++)
1156 68 : m_aFileOffsets[nIRow] =
1157 68 : static_cast<vsi_l_offset>(nIRow) * nBytesPerPixelPerNCol;
1158 17 : break;
1159 :
1160 16 : case MMDataType::DATATYPE_AND_COMPR_BYTE_RLE:
1161 : case MMDataType::DATATYPE_AND_COMPR_INTEGER_RLE:
1162 : case MMDataType::DATATYPE_AND_COMPR_UINTEGER_RLE:
1163 : case MMDataType::DATATYPE_AND_COMPR_LONG_RLE:
1164 : case MMDataType::DATATYPE_AND_COMPR_REAL_RLE:
1165 : case MMDataType::DATATYPE_AND_COMPR_DOUBLE_RLE:
1166 :
1167 16 : nStartOffset = VSIFTellL(m_pfIMG);
1168 :
1169 : // Let's determine if are there offsets in the file
1170 16 : if (0 < (nSizeToRead = PositionAtStartOfRowOffsetsInFile()))
1171 : {
1172 : // I have offsets!!
1173 14 : nFileByte = 0L; // all bits to 0
1174 56 : for (nIRow = 0; nIRow < m_nHeight; nIRow++)
1175 : {
1176 42 : if (VSIFReadL(&nFileByte, nSizeToRead, 1, m_pfIMG) != 1)
1177 0 : return false;
1178 :
1179 42 : m_aFileOffsets[nIRow] = nFileByte;
1180 :
1181 : // Let's check that the difference between two offsets is in a int range
1182 42 : if (nIRow > 0)
1183 : {
1184 56 : if (m_aFileOffsets[nIRow] <=
1185 28 : m_aFileOffsets[static_cast<size_t>(nIRow) - 1])
1186 0 : return false;
1187 :
1188 28 : if (m_aFileOffsets[nIRow] -
1189 28 : m_aFileOffsets[static_cast<size_t>(nIRow) -
1190 28 : 1] >=
1191 : static_cast<vsi_l_offset>(SIZE_MAX))
1192 0 : return false;
1193 : }
1194 : }
1195 14 : m_aFileOffsets[nIRow] = 0; // Not reliable
1196 14 : VSIFSeekL(m_pfIMG, nStartOffset, SEEK_SET);
1197 14 : break;
1198 : }
1199 :
1200 : // Not indexed RLE. We create a dynamic indexation
1201 4 : if (m_nWidth >
1202 2 : INT_MAX /
1203 2 : (std::max(1, static_cast<int>(m_eMMBytesPerPixel)) + 1))
1204 : {
1205 0 : CPLError(CE_Failure, CPLE_AppDefined, "Too large row: %d",
1206 : m_nWidth);
1207 0 : VSIFSeekL(m_pfIMG, nStartOffset, SEEK_SET);
1208 0 : return false;
1209 : }
1210 :
1211 2 : nMaxBytesPerCompressedRow =
1212 2 : static_cast<int>(m_eMMBytesPerPixel)
1213 2 : ? (m_nWidth * (static_cast<int>(m_eMMBytesPerPixel) + 1))
1214 0 : : (m_nWidth * (1 + 1));
1215 : unsigned char *pBuffer;
1216 :
1217 2 : if (nullptr == (pBuffer = static_cast<unsigned char *>(
1218 2 : VSI_MALLOC_VERBOSE(nMaxBytesPerCompressedRow))))
1219 : {
1220 0 : VSIFSeekL(m_pfIMG, nStartOffset, SEEK_SET);
1221 0 : return false;
1222 : }
1223 :
1224 2 : VSIFSeekL(m_pfIMG, 0, SEEK_SET);
1225 2 : m_aFileOffsets[0] = 0;
1226 8 : for (nIRow = 0; nIRow < m_nHeight; nIRow++)
1227 : {
1228 6 : GetBlockData(pBuffer, SIZE_MAX);
1229 6 : m_aFileOffsets[static_cast<size_t>(nIRow) + 1] =
1230 6 : VSIFTellL(m_pfIMG);
1231 : }
1232 2 : VSIFree(pBuffer);
1233 2 : VSIFSeekL(m_pfIMG, nStartOffset, SEEK_SET);
1234 2 : break;
1235 :
1236 0 : default:
1237 0 : return false;
1238 : } // End of switch (eMMDataType)
1239 35 : return true;
1240 :
1241 : } // End of FillRowOffsets()
|