Coverage Report

Created: 2026-02-14 09:00

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