Coverage Report

Created: 2026-11-12 08:28

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
4.51k
    : m_pfRel(&fRel), m_nWidth(0), m_nHeight(0),
29
4.51k
      m_osBandSection(osBandSectionIn)
30
4.51k
{
31
    // Getting band and band file name from metadata.
32
4.51k
    CPLString osNomFitxer;
33
4.51k
    osNomFitxer = SECTION_ATTRIBUTE_DATA;
34
4.51k
    osNomFitxer.append(":");
35
4.51k
    osNomFitxer.append(osBandSectionIn);
36
4.51k
    if (!m_pfRel->GetMetadataValue(osNomFitxer, KEY_NomFitxer,
37
4.51k
                                   m_osRawBandFileName) ||
38
3.46k
        m_osRawBandFileName.empty())
39
1.05k
    {
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
1.05k
        if (m_pfRel->GetNBands() >= 1)
48
11
            m_osBandFileName = "";
49
1.03k
        else
50
1.03k
        {
51
1.03k
            m_osBandFileName = m_pfRel->MMRGetFileNameFromRelName(
52
1.03k
                m_pfRel->GetRELName(), pszExtRaster);
53
1.03k
        }
54
55
1.05k
        if (m_osBandFileName.empty())
56
11
        {
57
11
            m_nWidth = 0;
58
11
            m_nHeight = 0;
59
11
            CPLError(CE_Failure, CPLE_AssertionFailed,
60
11
                     "The REL file '%s' contains a documented \
61
11
                band with no explicit or wrong name. Section [%s] or [%s:%s].",
62
11
                     m_pfRel->GetRELNameChar(), SECTION_ATTRIBUTE_DATA,
63
11
                     SECTION_ATTRIBUTE_DATA, m_osBandSection.c_str());
64
11
            return;
65
11
        }
66
1.03k
        m_osBandName = CPLGetBasenameSafe(m_osBandFileName);
67
1.03k
        m_osRawBandFileName = m_osBandName;
68
1.03k
    }
69
3.46k
    else
70
3.46k
    {
71
3.46k
        m_osBandName = CPLGetBasenameSafe(m_osRawBandFileName);
72
3.46k
        CPLString osAux = CPLGetPathSafe(m_pfRel->GetRELNameChar());
73
3.46k
        m_osBandFileName =
74
3.46k
            CPLFormFilenameSafe(osAux.c_str(), m_osRawBandFileName.c_str(), "");
75
76
3.46k
        CPLString osExtension =
77
3.46k
            CPLString(CPLGetExtensionSafe(m_osBandFileName).c_str());
78
3.46k
        if (!EQUAL(osExtension, pszExtRaster + 1))
79
7
            return;
80
3.46k
    }
81
82
    // There is a band file documented?
83
4.49k
    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
4.49k
    if (!UpdateColumnsNumberFromREL(m_osBandSection))
100
7
    {
101
7
        m_nWidth = 0;
102
7
        m_nHeight = 0;
103
7
        return;
104
7
    }
105
106
4.49k
    if (!UpdateRowsNumberFromREL(m_osBandSection))
107
5
    {
108
5
        m_nWidth = 0;
109
5
        m_nHeight = 0;
110
5
        return;
111
5
    }
112
113
4.48k
    if (m_nWidth <= 0 || m_nHeight <= 0)
114
3
    {
115
3
        m_nWidth = 0;
116
3
        m_nHeight = 0;
117
3
        CPLError(CE_Failure, CPLE_AppDefined,
118
3
                 "MMRBand::MMRBand : (nWidth <= 0 || nHeight <= 0)");
119
3
        return;
120
3
    }
121
122
    // Getting data type and compression.
123
    // If error, message given inside.
124
4.48k
    if (!UpdateDataTypeFromREL(m_osBandSection))
125
47
        return;
126
127
    // Let's see if there is RLE compression
128
4.43k
    m_bIsCompressed =
129
4.43k
        (((m_eMMDataType >= MMDataType::DATATYPE_AND_COMPR_BYTE_RLE) &&
130
3.94k
          (m_eMMDataType <= MMDataType::DATATYPE_AND_COMPR_DOUBLE_RLE)) ||
131
489
         m_eMMDataType == MMDataType::DATATYPE_AND_COMPR_BIT);
132
133
    // Getting min and max values
134
4.43k
    UpdateMinMaxValuesFromREL(m_osBandSection);
135
136
    // Getting unit type
137
4.43k
    UpdateUnitTypeValueFromREL(m_osBandSection);
138
139
    // Getting min and max values for simbolization
140
4.43k
    UpdateMinMaxVisuValuesFromREL(m_osBandSection);
141
4.43k
    if (!m_bMinVisuSet)
142
4.43k
    {
143
4.43k
        if (m_bMinSet)
144
1.44k
        {
145
1.44k
            m_dfVisuMin = m_dfMin;
146
1.44k
            m_bMinVisuSet = true;
147
1.44k
        }
148
4.43k
    }
149
4.43k
    if (!m_bMaxVisuSet)
150
4.43k
    {
151
4.43k
        if (m_bMaxSet)
152
422
        {
153
422
            m_dfVisuMax = m_dfMax;
154
422
            m_bMaxVisuSet = true;
155
422
        }
156
4.43k
    }
157
158
    // Getting the friendly description of the band
159
4.43k
    UpdateFriendlyDescriptionFromREL(m_osBandSection);
160
161
    // Getting NoData value and definition
162
4.43k
    UpdateNoDataValue(m_osBandSection);
163
164
    // Getting reference system and coordinates of the geographic bounding box
165
4.43k
    UpdateReferenceSystemFromREL();
166
167
    // Getting the bounding box: coordinates in the terrain
168
4.43k
    UpdateBoundingBoxFromREL(m_osBandSection);
169
170
    // Getting all information about simbolization
171
4.43k
    UpdateSimbolizationInfo(m_osBandSection);
172
173
    // Getting all information about RAT
174
4.43k
    UpdateRATInfo(m_osBandSection);
175
176
    // MiraMon IMG files are efficient in going to an specified row.
177
    // So let's configure the blocks as line blocks.
178
4.43k
    m_nBlockXSize = m_nWidth;
179
4.43k
    m_nBlockYSize = 1;
180
4.43k
    m_nNRowsPerBlock = 1;
181
182
    // Can the binary file that contains all data for this band be opened?
183
4.43k
    m_pfIMG = VSIFOpenL(m_osBandFileName, "rb");
184
4.43k
    if (!m_pfIMG)
185
417
    {
186
417
        m_nWidth = 0;
187
417
        m_nHeight = 0;
188
417
        CPLError(CE_Failure, CPLE_OpenFailed,
189
417
                 "Failed to open MiraMon band file `%s' with access 'rb'.",
190
417
                 m_osBandFileName.c_str());
191
417
        return;
192
417
    }
193
194
    // We have a valid MMRBand.
195
4.01k
    m_bIsValid = true;
196
4.01k
}
197
198
MMRBand::MMRBand(GDALProgressFunc pfnProgress, void *pProgressData,
199
                 GDALDataset &oSrcDS, int nIBand, const CPLString &osDestPath,
200
                 GDALRasterBand &papoBand, bool bCompress, bool bCategorical,
201
                 const CPLString &osPattern, const CPLString &osBandSection,
202
                 bool bNeedOfNomFitxer)
203
0
    : m_pfnProgress(pfnProgress), m_pProgressData(pProgressData),
204
0
      m_nIBand(nIBand), m_osBandSection(osBandSection),
205
0
      m_osFriendlyDescription(papoBand.GetDescription()),
206
0
      m_bIsCompressed(bCompress), m_bIsCategorical(bCategorical)
207
0
{
208
    // Getting the binary filename
209
0
    if (bNeedOfNomFitxer)
210
0
        m_osBandName = osPattern + "_" + osBandSection;
211
0
    else
212
0
        m_osBandName = osPattern;
213
214
0
    m_osRawBandFileName = m_osBandName + pszExtRaster;
215
0
    m_osBandFileName =
216
0
        CPLFormFilenameSafe(osDestPath, m_osBandName, pszExtRaster);
217
218
    // Getting essential metadata documented at
219
    // https://www.miramon.cat/new_note/eng/notes/MiraMon_raster_file_format.pdf
220
221
    // Getting number of columns and rows
222
0
    m_nWidth = papoBand.GetXSize();
223
0
    m_nHeight = papoBand.GetYSize();
224
225
0
    if (m_nWidth <= 0 || m_nHeight <= 0)
226
0
    {
227
0
        m_nWidth = 0;
228
0
        m_nHeight = 0;
229
0
        CPLError(CE_Failure, CPLE_AppDefined,
230
0
                 "MMRBand::MMRBand : (nWidth <= 0 || nHeight <= 0)");
231
0
        return;
232
0
    }
233
234
    // Getting units
235
0
    m_osBandUnitType = papoBand.GetUnitType();
236
237
    // Getting data type and compression from papoBand.
238
    // If error, message given inside.
239
0
    if (!UpdateDataTypeAndBytesPerPixelFromRasterBand(papoBand))
240
0
    {
241
0
        CPLError(CE_Failure, CPLE_AppDefined,
242
0
                 "MMRBand::MMRBand : DataType not supported");
243
0
        return;
244
0
    }
245
0
    m_nDataTypeSizeBytes = std::max(1, static_cast<int>(m_eMMBytesPerPixel));
246
0
    m_bIsCompressed = bCompress;
247
248
    // Getting NoData value and definition
249
0
    UpdateNoDataValueFromRasterBand(papoBand);
250
251
0
    if (WriteColorTable(oSrcDS))
252
0
    {
253
0
        m_osCTName.clear();
254
0
        CPLError(CE_Warning, CPLE_AppDefined,
255
0
                 "MMRBand::MMRBand : Existent color table but not imported"
256
0
                 "due to some existent errors");
257
0
    }
258
259
0
    if (WriteAttributeTable(oSrcDS))
260
0
    {
261
0
        m_osRATDBFName.clear();
262
0
        m_osRATRELName.clear();
263
0
        CPLError(CE_Warning, CPLE_AppDefined,
264
0
                 "MMRBand::MMRBand : Existent attribute table but not imported "
265
0
                 "due to some existent errors");
266
0
    }
267
268
    // We have a valid MMRBand.
269
0
    m_bIsValid = true;
270
0
}
271
272
/************************************************************************/
273
/*                              ~MMRBand()                              */
274
/************************************************************************/
275
MMRBand::~MMRBand()
276
4.51k
{
277
4.51k
    if (m_pfIMG == nullptr)
278
497
        return;
279
280
4.01k
    CPL_IGNORE_RET_VAL(VSIFCloseL(m_pfIMG));
281
4.01k
    m_pfIMG = nullptr;
282
4.01k
}
283
284
const CPLString &MMRBand::GetRELFileName() const
285
307
{
286
307
    static const CPLString osEmpty;
287
307
    if (!m_pfRel)
288
0
        return osEmpty;
289
307
    return m_pfRel->GetRELName();
290
307
}
291
292
/************************************************************************/
293
/*                           GetRasterBlock()                           */
294
/************************************************************************/
295
CPLErr MMRBand::GetRasterBlock(int /*nXBlock*/, int nYBlock, void *pData,
296
                               int nDataSize)
297
298
29.3k
{
299
29.3k
    if (nYBlock > INT_MAX / (std::max(1, m_nNRowsPerBlock)))
300
0
    {
301
0
        CPLError(CE_Failure, CPLE_OutOfMemory, "Error in GetRasterBlock");
302
0
        return CE_Failure;
303
0
    }
304
29.3k
    const int iBlock = nYBlock * m_nNRowsPerBlock;
305
306
29.3k
    if (m_nBlockXSize > INT_MAX / (std::max(1, m_nDataTypeSizeBytes)))
307
0
    {
308
0
        CPLError(CE_Failure, CPLE_OutOfMemory, "Error in GetRasterBlock");
309
0
        return CE_Failure;
310
0
    }
311
312
29.3k
    if (m_nBlockYSize >
313
29.3k
        INT_MAX / (std::max(1, m_nDataTypeSizeBytes * m_nBlockXSize)))
314
0
    {
315
0
        CPLError(CE_Failure, CPLE_OutOfMemory, "Error in GetRasterBlock");
316
0
        return CE_Failure;
317
0
    }
318
319
29.3k
    const int nGDALBlockSize =
320
29.3k
        m_nDataTypeSizeBytes * m_nBlockXSize * m_nBlockYSize;
321
322
    // Calculate block offset in case we have spill file. Use predefined
323
    // block map otherwise.
324
325
29.3k
    if (nDataSize != -1 && nGDALBlockSize > nDataSize)
326
0
    {
327
0
        CPLError(CE_Failure, CPLE_AppDefined, "Invalid block size: %d",
328
0
                 nGDALBlockSize);
329
0
        return CE_Failure;
330
0
    }
331
332
    // Getting the row offsets to optimize access.
333
29.3k
    if (FillRowOffsets() == false || m_aFileOffsets.empty())
334
50
    {
335
50
        CPLError(CE_Failure, CPLE_AppDefined,
336
50
                 "Some error in offsets calculation");
337
50
        return CE_Failure;
338
50
    }
339
340
    // Read the block in the documented or deduced offset
341
29.3k
    if (VSIFSeekL(m_pfIMG, m_aFileOffsets[iBlock], SEEK_SET))
342
9
    {
343
9
        CPLError(CE_Failure, CPLE_AppDefined,
344
9
                 "Read from invalid offset for grid block.");
345
9
        return CE_Failure;
346
9
    }
347
348
29.3k
    size_t nCompressedRawSize;
349
29.3k
    if (iBlock == m_nHeight - 1)
350
551
        nCompressedRawSize = SIZE_MAX;  // We don't know it
351
28.7k
    else
352
28.7k
        nCompressedRawSize = static_cast<size_t>(m_aFileOffsets[iBlock + 1] -
353
28.7k
                                                 m_aFileOffsets[iBlock]);
354
355
29.3k
    return GetBlockData(pData, nCompressedRawSize);
356
29.3k
}
357
358
void MMRBand::UpdateGeoTransform()
359
3.48k
{
360
3.48k
    m_gt.xorig = GetBoundingBoxMinX();
361
3.48k
    m_gt.xscale = (GetBoundingBoxMaxX() - m_gt.xorig) / GetWidth();
362
3.48k
    m_gt.xrot = 0.0;  // No rotation in MiraMon rasters
363
3.48k
    m_gt.yorig = GetBoundingBoxMaxY();
364
3.48k
    m_gt.yrot = 0.0;
365
3.48k
    m_gt.yscale = (GetBoundingBoxMinY() - m_gt.yorig) / GetHeight();
366
3.48k
}
367
368
/************************************************************************/
369
/*                           Other functions                            */
370
/************************************************************************/
371
372
// [ATTRIBUTE_DATA:xxxx] or [OVERVIEW:ASPECTES_TECNICS]
373
bool MMRBand::Get_ATTRIBUTE_DATA_or_OVERVIEW_ASPECTES_TECNICS_int(
374
    const CPLString &osSection, const char *pszKey, int *nValue,
375
    const char *pszErrorMessage)
376
8.98k
{
377
8.98k
    if (osSection.empty() || !pszKey || !nValue)
378
0
        return false;
379
380
8.98k
    CPLString osValue;
381
8.98k
    if (!m_pfRel->GetMetadataValue(SECTION_ATTRIBUTE_DATA, osSection, pszKey,
382
8.98k
                                   osValue) ||
383
6.05k
        osValue.empty())
384
2.95k
    {
385
2.95k
        if (m_pfRel->GetMetadataValue(SECTION_OVERVIEW,
386
2.95k
                                      SECTION_ASPECTES_TECNICS, pszKey,
387
2.95k
                                      osValue) == false ||
388
2.94k
            osValue.empty())
389
11
        {
390
11
            if (pszErrorMessage)
391
11
                CPLError(CE_Failure, CPLE_AppDefined, "%s", pszErrorMessage);
392
11
            return false;
393
11
        }
394
2.95k
    }
395
396
8.97k
    if (1 != sscanf(osValue, "%d", nValue))
397
1
    {
398
1
        if (pszErrorMessage)
399
1
            CPLError(CE_Failure, CPLE_AppDefined, "%s", pszErrorMessage);
400
1
        return false;
401
1
    }
402
8.97k
    return true;
403
8.97k
}
404
405
bool MMRBand::GetDataTypeAndBytesPerPixel(const char *pszCompType,
406
                                          MMDataType *nCompressionType,
407
                                          MMBytesPerPixel *nBytesPerPixel)
408
4.48k
{
409
4.48k
    if (!nCompressionType || !nBytesPerPixel || !pszCompType)
410
0
        return false;
411
412
4.48k
    if (EQUAL(pszCompType, "bit"))
413
46
    {
414
46
        *nCompressionType = MMDataType::DATATYPE_AND_COMPR_BIT;
415
46
        *nBytesPerPixel = MMBytesPerPixel::TYPE_BYTES_PER_PIXEL_BYTE_I_RLE;
416
46
        return true;
417
46
    }
418
4.43k
    if (EQUAL(pszCompType, "byte"))
419
231
    {
420
231
        *nCompressionType = MMDataType::DATATYPE_AND_COMPR_BYTE;
421
231
        *nBytesPerPixel = MMBytesPerPixel::TYPE_BYTES_PER_PIXEL_BYTE_I_RLE;
422
231
        return true;
423
231
    }
424
4.20k
    if (EQUAL(pszCompType, "byte-RLE"))
425
991
    {
426
991
        *nCompressionType = MMDataType::DATATYPE_AND_COMPR_BYTE_RLE;
427
991
        *nBytesPerPixel = MMBytesPerPixel::TYPE_BYTES_PER_PIXEL_BYTE_I_RLE;
428
991
        return true;
429
991
    }
430
3.21k
    if (EQUAL(pszCompType, "integer"))
431
25
    {
432
25
        *nCompressionType = MMDataType::DATATYPE_AND_COMPR_INTEGER;
433
25
        *nBytesPerPixel = MMBytesPerPixel::TYPE_BYTES_PER_PIXEL_INTEGER_I_RLE;
434
25
        return true;
435
25
    }
436
3.18k
    if (EQUAL(pszCompType, "integer-RLE"))
437
292
    {
438
292
        *nCompressionType = MMDataType::DATATYPE_AND_COMPR_INTEGER_RLE;
439
292
        *nBytesPerPixel = MMBytesPerPixel::TYPE_BYTES_PER_PIXEL_INTEGER_I_RLE;
440
292
        return true;
441
292
    }
442
2.89k
    if (EQUAL(pszCompType, "uinteger"))
443
54
    {
444
54
        *nCompressionType = MMDataType::DATATYPE_AND_COMPR_UINTEGER;
445
54
        *nBytesPerPixel = MMBytesPerPixel::TYPE_BYTES_PER_PIXEL_INTEGER_I_RLE;
446
54
        return true;
447
54
    }
448
2.84k
    if (EQUAL(pszCompType, "uinteger-RLE"))
449
376
    {
450
376
        *nCompressionType = MMDataType::DATATYPE_AND_COMPR_UINTEGER_RLE;
451
376
        *nBytesPerPixel = MMBytesPerPixel::TYPE_BYTES_PER_PIXEL_INTEGER_I_RLE;
452
376
        return true;
453
376
    }
454
2.46k
    if (EQUAL(pszCompType, "long"))
455
55
    {
456
55
        *nCompressionType = MMDataType::DATATYPE_AND_COMPR_LONG;
457
55
        *nBytesPerPixel = MMBytesPerPixel::TYPE_BYTES_PER_PIXEL_LONG_REAL_I_RLE;
458
55
        return true;
459
55
    }
460
2.41k
    if (EQUAL(pszCompType, "long-RLE"))
461
406
    {
462
406
        *nCompressionType = MMDataType::DATATYPE_AND_COMPR_LONG_RLE;
463
406
        *nBytesPerPixel = MMBytesPerPixel::TYPE_BYTES_PER_PIXEL_LONG_REAL_I_RLE;
464
406
        return true;
465
406
    }
466
2.00k
    if (EQUAL(pszCompType, "real"))
467
13
    {
468
13
        *nCompressionType = MMDataType::DATATYPE_AND_COMPR_REAL;
469
13
        *nBytesPerPixel = MMBytesPerPixel::TYPE_BYTES_PER_PIXEL_LONG_REAL_I_RLE;
470
13
        return true;
471
13
    }
472
1.99k
    if (EQUAL(pszCompType, "real-RLE"))
473
255
    {
474
255
        *nCompressionType = MMDataType::DATATYPE_AND_COMPR_REAL_RLE;
475
255
        *nBytesPerPixel = MMBytesPerPixel::TYPE_BYTES_PER_PIXEL_LONG_REAL_I_RLE;
476
255
        return true;
477
255
    }
478
1.73k
    if (EQUAL(pszCompType, "double"))
479
65
    {
480
65
        *nCompressionType = MMDataType::DATATYPE_AND_COMPR_DOUBLE;
481
65
        *nBytesPerPixel = MMBytesPerPixel::TYPE_BYTES_PER_PIXEL_DOUBLE_I_RLE;
482
65
        return true;
483
65
    }
484
1.67k
    if (EQUAL(pszCompType, "double-RLE"))
485
1.62k
    {
486
1.62k
        *nCompressionType = MMDataType::DATATYPE_AND_COMPR_DOUBLE_RLE;
487
1.62k
        *nBytesPerPixel = MMBytesPerPixel::TYPE_BYTES_PER_PIXEL_DOUBLE_I_RLE;
488
1.62k
        return true;
489
1.62k
    }
490
491
44
    return false;
492
1.67k
}
493
494
// Getting data type from metadata
495
bool MMRBand::UpdateDataTypeFromREL(const CPLString &osSection)
496
4.48k
{
497
4.48k
    m_eMMDataType = MMDataType::DATATYPE_AND_COMPR_UNDEFINED;
498
4.48k
    m_eMMBytesPerPixel = MMBytesPerPixel::TYPE_BYTES_PER_PIXEL_UNDEFINED;
499
500
4.48k
    CPLString osValue;
501
4.48k
    if (!m_pfRel->GetMetadataValue(SECTION_ATTRIBUTE_DATA, osSection,
502
4.48k
                                   "TipusCompressio", osValue) ||
503
4.48k
        osValue.empty())
504
3
    {
505
3
        m_nWidth = 0;
506
3
        m_nHeight = 0;
507
3
        CPLError(CE_Failure, CPLE_AppDefined,
508
3
                 "MiraMonRaster: no nDataType documented");
509
3
        return false;
510
3
    }
511
512
4.48k
    if (!GetDataTypeAndBytesPerPixel(osValue.c_str(), &m_eMMDataType,
513
4.48k
                                     &m_eMMBytesPerPixel))
514
44
    {
515
44
        m_nWidth = 0;
516
44
        m_nHeight = 0;
517
44
        CPLError(CE_Failure, CPLE_AppDefined,
518
44
                 "MiraMonRaster: data type unhandled");
519
44
        return false;
520
44
    }
521
522
4.43k
    m_nDataTypeSizeBytes = std::max(1, static_cast<int>(m_eMMBytesPerPixel));
523
4.43k
    return true;
524
4.48k
}
525
526
// Getting number of columns from metadata
527
bool MMRBand::UpdateColumnsNumberFromREL(const CPLString &osSection)
528
4.49k
{
529
4.49k
    return Get_ATTRIBUTE_DATA_or_OVERVIEW_ASPECTES_TECNICS_int(
530
4.49k
        osSection, "columns", &m_nWidth,
531
4.49k
        "MMRBand::MMRBand : No number of columns documented");
532
4.49k
}
533
534
bool MMRBand::UpdateRowsNumberFromREL(const CPLString &osSection)
535
4.49k
{
536
4.49k
    return Get_ATTRIBUTE_DATA_or_OVERVIEW_ASPECTES_TECNICS_int(
537
4.49k
        osSection, "rows", &m_nHeight,
538
4.49k
        "MMRBand::MMRBand : No number of rows documented");
539
4.49k
}
540
541
// Getting nodata value from metadata
542
void MMRBand::UpdateNoDataValue(const CPLString &osSection)
543
4.43k
{
544
4.43k
    CPLString osValue;
545
4.43k
    if (!m_pfRel->GetMetadataValue(SECTION_ATTRIBUTE_DATA, osSection, "NODATA",
546
4.43k
                                   osValue) ||
547
291
        osValue.empty())
548
4.17k
    {
549
4.17k
        m_dfNoData = 0;  // No a valid value.
550
4.17k
        m_bNoDataSet = false;
551
4.17k
    }
552
261
    else
553
261
    {
554
261
        m_dfNoData = CPLAtof(osValue);
555
261
        m_bNoDataSet = true;
556
261
    }
557
4.43k
}
558
559
void MMRBand::UpdateMinMaxValuesFromREL(const CPLString &osSection)
560
4.43k
{
561
4.43k
    m_bMinSet = false;
562
563
4.43k
    CPLString osValue;
564
565
4.43k
    if (m_pfRel->GetMetadataValue(SECTION_ATTRIBUTE_DATA, osSection, "min",
566
4.43k
                                  osValue) &&
567
1.86k
        !osValue.empty())
568
1.85k
    {
569
1.85k
        if (1 == CPLsscanf(osValue, "%lf", &m_dfMin))
570
1.58k
            m_bMinSet = true;
571
1.85k
    }
572
573
4.43k
    m_bMaxSet = false;
574
4.43k
    if (m_pfRel->GetMetadataValue(SECTION_ATTRIBUTE_DATA, osSection, "max",
575
4.43k
                                  osValue) &&
576
735
        !osValue.empty())
577
719
    {
578
719
        if (1 == CPLsscanf(osValue, "%lf", &m_dfMax))
579
559
            m_bMaxSet = true;
580
719
    }
581
582
    // Special case: dfMin > dfMax
583
4.43k
    if (m_bMinSet && m_bMaxSet && m_dfMin > m_dfMax)
584
137
    {
585
137
        m_bMinSet = false;
586
137
        m_bMaxSet = false;
587
137
    }
588
4.43k
}
589
590
void MMRBand::UpdateUnitTypeValueFromREL(const CPLString &osSection)
591
4.43k
{
592
4.43k
    CPLString osValue;
593
594
4.43k
    if (m_pfRel->GetMetadataValue(SECTION_ATTRIBUTE_DATA, osSection, "unitats",
595
4.43k
                                  osValue) &&
596
0
        !osValue.empty())
597
0
    {
598
0
        m_osBandUnitType = std::move(osValue);
599
0
    }
600
4.43k
}
601
602
void MMRBand::UpdateMinMaxVisuValuesFromREL(const CPLString &osSection)
603
4.43k
{
604
4.43k
    m_bMinVisuSet = false;
605
4.43k
    m_dfVisuMin = 1;
606
607
4.43k
    CPLString osValue;
608
4.43k
    if (m_pfRel->GetMetadataValue(SECTION_COLOR_TEXT, osSection,
609
4.43k
                                  "Color_ValorColor_0", osValue) &&
610
0
        !osValue.empty())
611
0
    {
612
0
        if (1 == CPLsscanf(osValue, "%lf", &m_dfVisuMin))
613
0
            m_bMinVisuSet = true;
614
0
    }
615
616
4.43k
    m_bMaxVisuSet = false;
617
4.43k
    m_dfVisuMax = 1;
618
619
4.43k
    if (m_pfRel->GetMetadataValue(SECTION_COLOR_TEXT, osSection,
620
4.43k
                                  "Color_ValorColor_n_1", osValue) &&
621
0
        !osValue.empty())
622
0
    {
623
0
        if (1 == CPLsscanf(osValue, "%lf", &m_dfVisuMax))
624
0
            m_bMaxVisuSet = true;
625
0
    }
626
4.43k
}
627
628
void MMRBand::UpdateFriendlyDescriptionFromREL(const CPLString &osSection)
629
4.43k
{
630
    // This "if" is due to CID 1620830 in Coverity Scan
631
4.43k
    if (!m_pfRel->GetMetadataValue(SECTION_ATTRIBUTE_DATA, osSection,
632
4.43k
                                   KEY_descriptor, m_osFriendlyDescription))
633
3.75k
        m_osFriendlyDescription = "";
634
4.43k
}
635
636
void MMRBand::UpdateReferenceSystemFromREL()
637
4.43k
{
638
    // This "if" is due to CID 1620842 in Coverity Scan
639
4.43k
    if (!m_pfRel->GetMetadataValue("SPATIAL_REFERENCE_SYSTEM:HORIZONTAL",
640
4.43k
                                   "HorizontalSystemIdentifier", m_osRefSystem))
641
4.36k
        m_osRefSystem = "";
642
4.43k
}
643
644
void MMRBand::UpdateBoundingBoxFromREL(const CPLString &osSection)
645
4.43k
{
646
    // Bounding box of the band
647
    // [ATTRIBUTE_DATA:xxxx:EXTENT] or [EXTENT]
648
4.43k
    CPLString osValue;
649
4.43k
    if (!m_pfRel->GetMetadataValue(SECTION_ATTRIBUTE_DATA, osSection,
650
4.43k
                                   SECTION_EXTENT, "MinX", osValue) ||
651
1.67k
        osValue.empty())
652
2.78k
    {
653
2.78k
        m_dfBBMinX = 0;
654
2.78k
    }
655
1.64k
    else
656
1.64k
    {
657
1.64k
        if (1 != CPLsscanf(osValue, "%lf", &m_dfBBMinX))
658
393
            m_dfBBMinX = 0;
659
1.64k
    }
660
661
4.43k
    if (!m_pfRel->GetMetadataValue(SECTION_ATTRIBUTE_DATA, osSection,
662
4.43k
                                   SECTION_EXTENT, "MaxX", osValue) ||
663
732
        osValue.empty())
664
3.70k
    {
665
3.70k
        m_dfBBMaxX = m_nWidth;
666
3.70k
    }
667
732
    else
668
732
    {
669
732
        if (1 != CPLsscanf(osValue, "%lf", &m_dfBBMaxX))
670
97
        {
671
            // If the value is something that cannot be scanned,
672
            // we silently continue as it was undefined.
673
97
            m_dfBBMaxX = m_nWidth;
674
97
        }
675
732
    }
676
677
4.43k
    if (!m_pfRel->GetMetadataValue(SECTION_ATTRIBUTE_DATA, osSection,
678
4.43k
                                   SECTION_EXTENT, "MinY", osValue) ||
679
1.67k
        osValue.empty())
680
2.77k
    {
681
2.77k
        m_dfBBMinY = 0;
682
2.77k
    }
683
1.65k
    else
684
1.65k
    {
685
1.65k
        if (1 != CPLsscanf(osValue, "%lf", &m_dfBBMinY))
686
130
            m_dfBBMinY = 0;
687
1.65k
    }
688
689
4.43k
    if (!m_pfRel->GetMetadataValue(SECTION_ATTRIBUTE_DATA, osSection,
690
4.43k
                                   SECTION_EXTENT, "MaxY", osValue) ||
691
1.25k
        osValue.empty())
692
3.18k
    {
693
3.18k
        m_dfBBMaxY = m_nHeight;
694
3.18k
    }
695
1.25k
    else
696
1.25k
    {
697
1.25k
        if (1 != CPLsscanf(osValue, "%lf", &m_dfBBMaxY))
698
112
        {
699
            // If the value is something that cannot be scanned,
700
            // we silently continue as it was undefined.
701
112
            m_dfBBMaxY = m_nHeight;
702
112
        }
703
1.25k
    }
704
4.43k
}
705
706
void MMRBand::UpdateSimbolizationInfo(const CPLString &osSection)
707
4.43k
{
708
4.43k
    m_pfRel->GetMetadataValue(SECTION_COLOR_TEXT, osSection, "Color_Const",
709
4.43k
                              m_osColor_Const);
710
711
4.43k
    if (EQUAL(m_osColor_Const, "1"))
712
79
    {
713
79
        if (CE_None == m_pfRel->UpdateGDALColorEntryFromBand(
714
79
                           osSection, m_sConstantColorRGB))
715
79
            m_osValidColorConst = true;
716
79
    }
717
718
4.43k
    m_pfRel->GetMetadataValue(SECTION_COLOR_TEXT, osSection, "Color_Paleta",
719
4.43k
                              m_osColor_Paleta);
720
721
    // Treatment of the color variable
722
4.43k
    m_pfRel->GetMetadataValue(SECTION_COLOR_TEXT, osSection,
723
4.43k
                              "Color_TractamentVariable",
724
4.43k
                              m_osColor_TractamentVariable);
725
726
4.43k
    m_pfRel->GetMetadataValue(SECTION_ATTRIBUTE_DATA, osSection,
727
4.43k
                              KEY_TractamentVariable, m_osTractamentVariable);
728
729
    // Is categorical?
730
4.43k
    if (m_osTractamentVariable.empty())
731
2.55k
    {
732
2.55k
        m_bIsCategorical = false;
733
2.55k
    }
734
1.88k
    else
735
1.88k
    {
736
1.88k
        if (EQUAL(m_osTractamentVariable, "Categoric"))
737
195
            m_bIsCategorical = true;
738
1.68k
        else
739
1.68k
            m_bIsCategorical = false;
740
1.88k
    }
741
742
4.43k
    m_pfRel->GetMetadataValue(SECTION_COLOR_TEXT, osSection,
743
4.43k
                              "Color_EscalatColor", m_osColor_EscalatColor);
744
745
4.43k
    m_pfRel->GetMetadataValue(SECTION_COLOR_TEXT, osSection,
746
4.43k
                              "Color_N_SimbolsALaTaula",
747
4.43k
                              m_osColor_N_SimbolsALaTaula);
748
4.43k
}
749
750
void MMRBand::UpdateRATInfo(const CPLString &osSection)
751
4.43k
{
752
4.43k
    CPLString os_IndexJoin;
753
754
4.43k
    if (!m_pfRel->GetMetadataValue(SECTION_ATTRIBUTE_DATA, osSection,
755
4.43k
                                   "IndexsJoinTaula", os_IndexJoin) ||
756
216
        os_IndexJoin.empty())
757
4.22k
    {
758
4.22k
        return;
759
4.22k
    }
760
761
    // Let's see if there is any table that can ve converted to RAT
762
216
    const CPLStringList aosTokens(CSLTokenizeString2(os_IndexJoin, ",", 0));
763
216
    const int nTokens = CSLCount(aosTokens);
764
216
    if (nTokens < 1)
765
0
        return;
766
767
216
    CPLString os_Join = "JoinTaula";
768
216
    os_Join.append("_");
769
216
    os_Join.append(aosTokens[0]);
770
771
216
    CPLString osTableNameSection_value;
772
216
    if (!m_pfRel->GetMetadataValue(SECTION_ATTRIBUTE_DATA, osSection, os_Join,
773
216
                                   osTableNameSection_value) ||
774
93
        osTableNameSection_value.empty())
775
123
        return;
776
777
93
    CPLString osTableNameSection = "TAULA_";
778
93
    osTableNameSection.append(osTableNameSection_value);
779
780
93
    if (!m_pfRel->GetMetadataValue(osTableNameSection, KEY_NomFitxer,
781
93
                                   m_osShortRATName) ||
782
53
        m_osShortRATName.empty())
783
40
    {
784
40
        m_osAssociateREL = "";
785
40
        return;
786
40
    }
787
788
53
    CPL_IGNORE_RET_VAL(m_pfRel->GetMetadataValue(
789
53
        osTableNameSection, "AssociatRel", m_osAssociateREL));
790
53
}
791
792
/************************************************************************/
793
/*             Functions that read bytes from IMG file band             */
794
/************************************************************************/
795
template <typename TYPE>
796
CPLErr MMRBand::UncompressRow(void *rowBuffer, size_t nCompressedRawSize)
797
34.0M
{
798
34.0M
    int nAccumulated = 0L, nIAccumulated = 0L;
799
34.0M
    unsigned char cCounter;
800
34.0M
    size_t nCompressedIndex = 0;
801
802
34.0M
    TYPE RLEValue;
803
34.0M
    TYPE *pDst;
804
34.0M
    size_t sizeof_TYPE = sizeof(TYPE);
805
806
34.0M
    std::vector<unsigned char> aCompressedRow;
807
808
34.0M
    if (nCompressedRawSize != SIZE_MAX)
809
3.43k
    {
810
3.43k
        if (nCompressedRawSize > 1000 * 1000 &&
811
660
            GetFileSize() < nCompressedRawSize)
812
564
        {
813
564
            CPLError(CE_Failure, CPLE_AppDefined, "Too small file");
814
564
            return CE_Failure;
815
564
        }
816
2.86k
        try
817
2.86k
        {
818
2.86k
            aCompressedRow.resize(nCompressedRawSize);
819
2.86k
        }
820
2.86k
        catch (const std::exception &)
821
2.86k
        {
822
0
            CPLError(CE_Failure, CPLE_OutOfMemory,
823
0
                     "Out of memory allocating working buffer");
824
0
            return CE_Failure;
825
0
        }
826
2.86k
        if (VSIFReadL(aCompressedRow.data(), nCompressedRawSize, 1, m_pfIMG) !=
827
2.86k
            1)
828
92
            return CE_Failure;
829
2.86k
    }
830
831
239M
    while (nAccumulated < m_nWidth)
832
239M
    {
833
239M
        if (nCompressedRawSize == SIZE_MAX)
834
137M
        {
835
137M
            if (VSIFReadL(&cCounter, 1, 1, m_pfIMG) != 1)
836
33.8M
                return CE_Failure;
837
137M
        }
838
102M
        else
839
102M
        {
840
102M
            if (nCompressedIndex >= aCompressedRow.size())
841
168
            {
842
168
                CPLError(CE_Failure, CPLE_AppDefined,
843
168
                         "Invalid nCompressedIndex");
844
168
                return CE_Failure;
845
168
            }
846
102M
            cCounter = aCompressedRow[nCompressedIndex];
847
102M
            nCompressedIndex++;
848
102M
        }
849
850
205M
        if (cCounter == 0) /* Not compressed part */
851
201M
        {
852
            /* The following counter read does not indicate
853
            "how many repeated values follow" but rather
854
            "how many are decompressed in standard raster format" */
855
201M
            if (nCompressedRawSize == SIZE_MAX)
856
100M
            {
857
100M
                if (VSIFReadL(&cCounter, 1, 1, m_pfIMG) != 1)
858
255
                    return CE_Failure;
859
100M
            }
860
100M
            else
861
100M
            {
862
100M
                if (nCompressedIndex >= aCompressedRow.size())
863
125
                {
864
125
                    CPLError(CE_Failure, CPLE_AppDefined,
865
125
                             "Invalid nCompressedIndex");
866
125
                    return CE_Failure;
867
125
                }
868
100M
                cCounter = aCompressedRow[nCompressedIndex];
869
100M
                nCompressedIndex++;
870
100M
            }
871
872
201M
            nAccumulated += cCounter;
873
874
201M
            if (nAccumulated > m_nWidth) /* This should not happen if the file
875
                                  is RLE and does not share counters across rows */
876
1.73k
                return CE_Failure;
877
878
211M
            for (; nIAccumulated < nAccumulated; nIAccumulated++)
879
9.98M
            {
880
9.98M
                if (nCompressedRawSize == SIZE_MAX)
881
5.11M
                {
882
5.11M
                    VSIFReadL(&RLEValue, sizeof_TYPE, 1, m_pfIMG);
883
5.11M
                    memcpy((static_cast<TYPE *>(rowBuffer)) + nIAccumulated,
884
5.11M
                           &RLEValue, sizeof_TYPE);
885
5.11M
                }
886
4.87M
                else
887
4.87M
                {
888
4.87M
                    if (nCompressedIndex + sizeof_TYPE > aCompressedRow.size())
889
385
                    {
890
385
                        CPLError(CE_Failure, CPLE_AppDefined,
891
385
                                 "Invalid nCompressedIndex");
892
385
                        return CE_Failure;
893
385
                    }
894
4.87M
                    memcpy((static_cast<TYPE *>(rowBuffer)) + nIAccumulated,
895
4.87M
                           &aCompressedRow[nCompressedIndex], sizeof_TYPE);
896
4.87M
                    nCompressedIndex += sizeof_TYPE;
897
4.87M
                }
898
9.98M
            }
899
201M
        }
900
4.45M
        else
901
4.45M
        {
902
4.45M
            nAccumulated += cCounter;
903
4.45M
            if (nAccumulated > m_nWidth) /* This should not happen if the file
904
                                  is RLE and does not share counters across rows */
905
166k
                return CE_Failure;
906
907
4.28M
            if (nCompressedRawSize == SIZE_MAX)
908
2.25M
            {
909
2.25M
                if (VSIFReadL(&RLEValue, sizeof_TYPE, 1, m_pfIMG) != 1)
910
479
                    return CE_Failure;
911
2.25M
            }
912
2.02M
            else
913
2.02M
            {
914
2.02M
                if (nCompressedIndex + sizeof(TYPE) > aCompressedRow.size())
915
257
                {
916
257
                    CPLError(CE_Failure, CPLE_AppDefined,
917
257
                             "Invalid nCompressedIndex");
918
257
                    return CE_Failure;
919
257
                }
920
2.02M
                memcpy(&RLEValue, &aCompressedRow[nCompressedIndex],
921
2.02M
                       sizeof(TYPE));
922
2.02M
                nCompressedIndex += sizeof(TYPE);
923
2.02M
            }
924
925
4.28M
            const int nCount = nAccumulated - nIAccumulated;
926
4.28M
            pDst = static_cast<TYPE *>(rowBuffer) + nIAccumulated;
927
928
4.28M
            std::fill(pDst, pDst + nCount, RLEValue);
929
930
4.28M
            nIAccumulated = nAccumulated;
931
4.28M
        }
932
205M
    }
933
934
5.11k
    return CE_None;
935
34.0M
}
CPLErr MMRBand::UncompressRow<unsigned char>(void*, unsigned long)
Line
Count
Source
797
10.6M
{
798
10.6M
    int nAccumulated = 0L, nIAccumulated = 0L;
799
10.6M
    unsigned char cCounter;
800
10.6M
    size_t nCompressedIndex = 0;
801
802
10.6M
    TYPE RLEValue;
803
10.6M
    TYPE *pDst;
804
10.6M
    size_t sizeof_TYPE = sizeof(TYPE);
805
806
10.6M
    std::vector<unsigned char> aCompressedRow;
807
808
10.6M
    if (nCompressedRawSize != SIZE_MAX)
809
580
    {
810
580
        if (nCompressedRawSize > 1000 * 1000 &&
811
124
            GetFileSize() < nCompressedRawSize)
812
102
        {
813
102
            CPLError(CE_Failure, CPLE_AppDefined, "Too small file");
814
102
            return CE_Failure;
815
102
        }
816
478
        try
817
478
        {
818
478
            aCompressedRow.resize(nCompressedRawSize);
819
478
        }
820
478
        catch (const std::exception &)
821
478
        {
822
0
            CPLError(CE_Failure, CPLE_OutOfMemory,
823
0
                     "Out of memory allocating working buffer");
824
0
            return CE_Failure;
825
0
        }
826
478
        if (VSIFReadL(aCompressedRow.data(), nCompressedRawSize, 1, m_pfIMG) !=
827
478
            1)
828
10
            return CE_Failure;
829
478
    }
830
831
53.2M
    while (nAccumulated < m_nWidth)
832
53.2M
    {
833
53.2M
        if (nCompressedRawSize == SIZE_MAX)
834
32.0M
        {
835
32.0M
            if (VSIFReadL(&cCounter, 1, 1, m_pfIMG) != 1)
836
10.5M
                return CE_Failure;
837
32.0M
        }
838
21.2M
        else
839
21.2M
        {
840
21.2M
            if (nCompressedIndex >= aCompressedRow.size())
841
56
            {
842
56
                CPLError(CE_Failure, CPLE_AppDefined,
843
56
                         "Invalid nCompressedIndex");
844
56
                return CE_Failure;
845
56
            }
846
21.2M
            cCounter = aCompressedRow[nCompressedIndex];
847
21.2M
            nCompressedIndex++;
848
21.2M
        }
849
850
42.7M
        if (cCounter == 0) /* Not compressed part */
851
41.5M
        {
852
            /* The following counter read does not indicate
853
            "how many repeated values follow" but rather
854
            "how many are decompressed in standard raster format" */
855
41.5M
            if (nCompressedRawSize == SIZE_MAX)
856
20.8M
            {
857
20.8M
                if (VSIFReadL(&cCounter, 1, 1, m_pfIMG) != 1)
858
45
                    return CE_Failure;
859
20.8M
            }
860
20.7M
            else
861
20.7M
            {
862
20.7M
                if (nCompressedIndex >= aCompressedRow.size())
863
20
                {
864
20
                    CPLError(CE_Failure, CPLE_AppDefined,
865
20
                             "Invalid nCompressedIndex");
866
20
                    return CE_Failure;
867
20
                }
868
20.7M
                cCounter = aCompressedRow[nCompressedIndex];
869
20.7M
                nCompressedIndex++;
870
20.7M
            }
871
872
41.5M
            nAccumulated += cCounter;
873
874
41.5M
            if (nAccumulated > m_nWidth) /* This should not happen if the file
875
                                  is RLE and does not share counters across rows */
876
192
                return CE_Failure;
877
878
43.6M
            for (; nIAccumulated < nAccumulated; nIAccumulated++)
879
2.07M
            {
880
2.07M
                if (nCompressedRawSize == SIZE_MAX)
881
1.07M
                {
882
1.07M
                    VSIFReadL(&RLEValue, sizeof_TYPE, 1, m_pfIMG);
883
1.07M
                    memcpy((static_cast<TYPE *>(rowBuffer)) + nIAccumulated,
884
1.07M
                           &RLEValue, sizeof_TYPE);
885
1.07M
                }
886
999k
                else
887
999k
                {
888
999k
                    if (nCompressedIndex + sizeof_TYPE > aCompressedRow.size())
889
26
                    {
890
26
                        CPLError(CE_Failure, CPLE_AppDefined,
891
26
                                 "Invalid nCompressedIndex");
892
26
                        return CE_Failure;
893
26
                    }
894
999k
                    memcpy((static_cast<TYPE *>(rowBuffer)) + nIAccumulated,
895
999k
                           &aCompressedRow[nCompressedIndex], sizeof_TYPE);
896
999k
                    nCompressedIndex += sizeof_TYPE;
897
999k
                }
898
2.07M
            }
899
41.5M
        }
900
1.13M
        else
901
1.13M
        {
902
1.13M
            nAccumulated += cCounter;
903
1.13M
            if (nAccumulated > m_nWidth) /* This should not happen if the file
904
                                  is RLE and does not share counters across rows */
905
36.4k
                return CE_Failure;
906
907
1.09M
            if (nCompressedRawSize == SIZE_MAX)
908
591k
            {
909
591k
                if (VSIFReadL(&RLEValue, sizeof_TYPE, 1, m_pfIMG) != 1)
910
70
                    return CE_Failure;
911
591k
            }
912
503k
            else
913
503k
            {
914
503k
                if (nCompressedIndex + sizeof(TYPE) > aCompressedRow.size())
915
41
                {
916
41
                    CPLError(CE_Failure, CPLE_AppDefined,
917
41
                             "Invalid nCompressedIndex");
918
41
                    return CE_Failure;
919
41
                }
920
503k
                memcpy(&RLEValue, &aCompressedRow[nCompressedIndex],
921
503k
                       sizeof(TYPE));
922
503k
                nCompressedIndex += sizeof(TYPE);
923
503k
            }
924
925
1.09M
            const int nCount = nAccumulated - nIAccumulated;
926
1.09M
            pDst = static_cast<TYPE *>(rowBuffer) + nIAccumulated;
927
928
1.09M
            std::fill(pDst, pDst + nCount, RLEValue);
929
930
1.09M
            nIAccumulated = nAccumulated;
931
1.09M
        }
932
42.7M
    }
933
934
552
    return CE_None;
935
10.6M
}
CPLErr MMRBand::UncompressRow<short>(void*, unsigned long)
Line
Count
Source
797
6.70k
{
798
6.70k
    int nAccumulated = 0L, nIAccumulated = 0L;
799
6.70k
    unsigned char cCounter;
800
6.70k
    size_t nCompressedIndex = 0;
801
802
6.70k
    TYPE RLEValue;
803
6.70k
    TYPE *pDst;
804
6.70k
    size_t sizeof_TYPE = sizeof(TYPE);
805
806
6.70k
    std::vector<unsigned char> aCompressedRow;
807
808
6.70k
    if (nCompressedRawSize != SIZE_MAX)
809
260
    {
810
260
        if (nCompressedRawSize > 1000 * 1000 &&
811
105
            GetFileSize() < nCompressedRawSize)
812
88
        {
813
88
            CPLError(CE_Failure, CPLE_AppDefined, "Too small file");
814
88
            return CE_Failure;
815
88
        }
816
172
        try
817
172
        {
818
172
            aCompressedRow.resize(nCompressedRawSize);
819
172
        }
820
172
        catch (const std::exception &)
821
172
        {
822
0
            CPLError(CE_Failure, CPLE_OutOfMemory,
823
0
                     "Out of memory allocating working buffer");
824
0
            return CE_Failure;
825
0
        }
826
172
        if (VSIFReadL(aCompressedRow.data(), nCompressedRawSize, 1, m_pfIMG) !=
827
172
            1)
828
9
            return CE_Failure;
829
172
    }
830
831
33.5M
    while (nAccumulated < m_nWidth)
832
33.5M
    {
833
33.5M
        if (nCompressedRawSize == SIZE_MAX)
834
16.7M
        {
835
16.7M
            if (VSIFReadL(&cCounter, 1, 1, m_pfIMG) != 1)
836
2.79k
                return CE_Failure;
837
16.7M
        }
838
16.7M
        else
839
16.7M
        {
840
16.7M
            if (nCompressedIndex >= aCompressedRow.size())
841
23
            {
842
23
                CPLError(CE_Failure, CPLE_AppDefined,
843
23
                         "Invalid nCompressedIndex");
844
23
                return CE_Failure;
845
23
            }
846
16.7M
            cCounter = aCompressedRow[nCompressedIndex];
847
16.7M
            nCompressedIndex++;
848
16.7M
        }
849
850
33.5M
        if (cCounter == 0) /* Not compressed part */
851
32.5M
        {
852
            /* The following counter read does not indicate
853
            "how many repeated values follow" but rather
854
            "how many are decompressed in standard raster format" */
855
32.5M
            if (nCompressedRawSize == SIZE_MAX)
856
16.2M
            {
857
16.2M
                if (VSIFReadL(&cCounter, 1, 1, m_pfIMG) != 1)
858
29
                    return CE_Failure;
859
16.2M
            }
860
16.2M
            else
861
16.2M
            {
862
16.2M
                if (nCompressedIndex >= aCompressedRow.size())
863
29
                {
864
29
                    CPLError(CE_Failure, CPLE_AppDefined,
865
29
                             "Invalid nCompressedIndex");
866
29
                    return CE_Failure;
867
29
                }
868
16.2M
                cCounter = aCompressedRow[nCompressedIndex];
869
16.2M
                nCompressedIndex++;
870
16.2M
            }
871
872
32.5M
            nAccumulated += cCounter;
873
874
32.5M
            if (nAccumulated > m_nWidth) /* This should not happen if the file
875
                                  is RLE and does not share counters across rows */
876
158
                return CE_Failure;
877
878
34.5M
            for (; nIAccumulated < nAccumulated; nIAccumulated++)
879
1.97M
            {
880
1.97M
                if (nCompressedRawSize == SIZE_MAX)
881
992k
                {
882
992k
                    VSIFReadL(&RLEValue, sizeof_TYPE, 1, m_pfIMG);
883
992k
                    memcpy((static_cast<TYPE *>(rowBuffer)) + nIAccumulated,
884
992k
                           &RLEValue, sizeof_TYPE);
885
992k
                }
886
984k
                else
887
984k
                {
888
984k
                    if (nCompressedIndex + sizeof_TYPE > aCompressedRow.size())
889
48
                    {
890
48
                        CPLError(CE_Failure, CPLE_AppDefined,
891
48
                                 "Invalid nCompressedIndex");
892
48
                        return CE_Failure;
893
48
                    }
894
984k
                    memcpy((static_cast<TYPE *>(rowBuffer)) + nIAccumulated,
895
984k
                           &aCompressedRow[nCompressedIndex], sizeof_TYPE);
896
984k
                    nCompressedIndex += sizeof_TYPE;
897
984k
                }
898
1.97M
            }
899
32.5M
        }
900
1.01M
        else
901
1.01M
        {
902
1.01M
            nAccumulated += cCounter;
903
1.01M
            if (nAccumulated > m_nWidth) /* This should not happen if the file
904
                                  is RLE and does not share counters across rows */
905
3.42k
                return CE_Failure;
906
907
1.00M
            if (nCompressedRawSize == SIZE_MAX)
908
511k
            {
909
511k
                if (VSIFReadL(&RLEValue, sizeof_TYPE, 1, m_pfIMG) != 1)
910
63
                    return CE_Failure;
911
511k
            }
912
497k
            else
913
497k
            {
914
497k
                if (nCompressedIndex + sizeof(TYPE) > aCompressedRow.size())
915
40
                {
916
40
                    CPLError(CE_Failure, CPLE_AppDefined,
917
40
                             "Invalid nCompressedIndex");
918
40
                    return CE_Failure;
919
40
                }
920
497k
                memcpy(&RLEValue, &aCompressedRow[nCompressedIndex],
921
497k
                       sizeof(TYPE));
922
497k
                nCompressedIndex += sizeof(TYPE);
923
497k
            }
924
925
1.00M
            const int nCount = nAccumulated - nIAccumulated;
926
1.00M
            pDst = static_cast<TYPE *>(rowBuffer) + nIAccumulated;
927
928
1.00M
            std::fill(pDst, pDst + nCount, RLEValue);
929
930
1.00M
            nIAccumulated = nAccumulated;
931
1.00M
        }
932
33.5M
    }
933
934
7
    return CE_None;
935
6.61k
}
CPLErr MMRBand::UncompressRow<unsigned short>(void*, unsigned long)
Line
Count
Source
797
2.76M
{
798
2.76M
    int nAccumulated = 0L, nIAccumulated = 0L;
799
2.76M
    unsigned char cCounter;
800
2.76M
    size_t nCompressedIndex = 0;
801
802
2.76M
    TYPE RLEValue;
803
2.76M
    TYPE *pDst;
804
2.76M
    size_t sizeof_TYPE = sizeof(TYPE);
805
806
2.76M
    std::vector<unsigned char> aCompressedRow;
807
808
2.76M
    if (nCompressedRawSize != SIZE_MAX)
809
351
    {
810
351
        if (nCompressedRawSize > 1000 * 1000 &&
811
90
            GetFileSize() < nCompressedRawSize)
812
79
        {
813
79
            CPLError(CE_Failure, CPLE_AppDefined, "Too small file");
814
79
            return CE_Failure;
815
79
        }
816
272
        try
817
272
        {
818
272
            aCompressedRow.resize(nCompressedRawSize);
819
272
        }
820
272
        catch (const std::exception &)
821
272
        {
822
0
            CPLError(CE_Failure, CPLE_OutOfMemory,
823
0
                     "Out of memory allocating working buffer");
824
0
            return CE_Failure;
825
0
        }
826
272
        if (VSIFReadL(aCompressedRow.data(), nCompressedRawSize, 1, m_pfIMG) !=
827
272
            1)
828
18
            return CE_Failure;
829
272
    }
830
831
46.5M
    while (nAccumulated < m_nWidth)
832
46.5M
    {
833
46.5M
        if (nCompressedRawSize == SIZE_MAX)
834
24.8M
        {
835
24.8M
            if (VSIFReadL(&cCounter, 1, 1, m_pfIMG) != 1)
836
2.74M
                return CE_Failure;
837
24.8M
        }
838
21.7M
        else
839
21.7M
        {
840
21.7M
            if (nCompressedIndex >= aCompressedRow.size())
841
27
            {
842
27
                CPLError(CE_Failure, CPLE_AppDefined,
843
27
                         "Invalid nCompressedIndex");
844
27
                return CE_Failure;
845
27
            }
846
21.7M
            cCounter = aCompressedRow[nCompressedIndex];
847
21.7M
            nCompressedIndex++;
848
21.7M
        }
849
850
43.8M
        if (cCounter == 0) /* Not compressed part */
851
42.5M
        {
852
            /* The following counter read does not indicate
853
            "how many repeated values follow" but rather
854
            "how many are decompressed in standard raster format" */
855
42.5M
            if (nCompressedRawSize == SIZE_MAX)
856
21.4M
            {
857
21.4M
                if (VSIFReadL(&cCounter, 1, 1, m_pfIMG) != 1)
858
22
                    return CE_Failure;
859
21.4M
            }
860
21.1M
            else
861
21.1M
            {
862
21.1M
                if (nCompressedIndex >= aCompressedRow.size())
863
20
                {
864
20
                    CPLError(CE_Failure, CPLE_AppDefined,
865
20
                             "Invalid nCompressedIndex");
866
20
                    return CE_Failure;
867
20
                }
868
21.1M
                cCounter = aCompressedRow[nCompressedIndex];
869
21.1M
                nCompressedIndex++;
870
21.1M
            }
871
872
42.5M
            nAccumulated += cCounter;
873
874
42.5M
            if (nAccumulated > m_nWidth) /* This should not happen if the file
875
                                  is RLE and does not share counters across rows */
876
199
                return CE_Failure;
877
878
45.2M
            for (; nIAccumulated < nAccumulated; nIAccumulated++)
879
2.68M
            {
880
2.68M
                if (nCompressedRawSize == SIZE_MAX)
881
1.37M
                {
882
1.37M
                    VSIFReadL(&RLEValue, sizeof_TYPE, 1, m_pfIMG);
883
1.37M
                    memcpy((static_cast<TYPE *>(rowBuffer)) + nIAccumulated,
884
1.37M
                           &RLEValue, sizeof_TYPE);
885
1.37M
                }
886
1.31M
                else
887
1.31M
                {
888
1.31M
                    if (nCompressedIndex + sizeof_TYPE > aCompressedRow.size())
889
54
                    {
890
54
                        CPLError(CE_Failure, CPLE_AppDefined,
891
54
                                 "Invalid nCompressedIndex");
892
54
                        return CE_Failure;
893
54
                    }
894
1.31M
                    memcpy((static_cast<TYPE *>(rowBuffer)) + nIAccumulated,
895
1.31M
                           &aCompressedRow[nCompressedIndex], sizeof_TYPE);
896
1.31M
                    nCompressedIndex += sizeof_TYPE;
897
1.31M
                }
898
2.68M
            }
899
42.5M
        }
900
1.23M
        else
901
1.23M
        {
902
1.23M
            nAccumulated += cCounter;
903
1.23M
            if (nAccumulated > m_nWidth) /* This should not happen if the file
904
                                  is RLE and does not share counters across rows */
905
18.9k
                return CE_Failure;
906
907
1.21M
            if (nCompressedRawSize == SIZE_MAX)
908
635k
            {
909
635k
                if (VSIFReadL(&RLEValue, sizeof_TYPE, 1, m_pfIMG) != 1)
910
56
                    return CE_Failure;
911
635k
            }
912
576k
            else
913
576k
            {
914
576k
                if (nCompressedIndex + sizeof(TYPE) > aCompressedRow.size())
915
34
                {
916
34
                    CPLError(CE_Failure, CPLE_AppDefined,
917
34
                             "Invalid nCompressedIndex");
918
34
                    return CE_Failure;
919
34
                }
920
576k
                memcpy(&RLEValue, &aCompressedRow[nCompressedIndex],
921
576k
                       sizeof(TYPE));
922
576k
                nCompressedIndex += sizeof(TYPE);
923
576k
            }
924
925
1.21M
            const int nCount = nAccumulated - nIAccumulated;
926
1.21M
            pDst = static_cast<TYPE *>(rowBuffer) + nIAccumulated;
927
928
1.21M
            std::fill(pDst, pDst + nCount, RLEValue);
929
930
1.21M
            nIAccumulated = nAccumulated;
931
1.21M
        }
932
43.8M
    }
933
934
165
    return CE_None;
935
2.76M
}
CPLErr MMRBand::UncompressRow<int>(void*, unsigned long)
Line
Count
Source
797
5.36M
{
798
5.36M
    int nAccumulated = 0L, nIAccumulated = 0L;
799
5.36M
    unsigned char cCounter;
800
5.36M
    size_t nCompressedIndex = 0;
801
802
5.36M
    TYPE RLEValue;
803
5.36M
    TYPE *pDst;
804
5.36M
    size_t sizeof_TYPE = sizeof(TYPE);
805
806
5.36M
    std::vector<unsigned char> aCompressedRow;
807
808
5.36M
    if (nCompressedRawSize != SIZE_MAX)
809
686
    {
810
686
        if (nCompressedRawSize > 1000 * 1000 &&
811
111
            GetFileSize() < nCompressedRawSize)
812
97
        {
813
97
            CPLError(CE_Failure, CPLE_AppDefined, "Too small file");
814
97
            return CE_Failure;
815
97
        }
816
589
        try
817
589
        {
818
589
            aCompressedRow.resize(nCompressedRawSize);
819
589
        }
820
589
        catch (const std::exception &)
821
589
        {
822
0
            CPLError(CE_Failure, CPLE_OutOfMemory,
823
0
                     "Out of memory allocating working buffer");
824
0
            return CE_Failure;
825
0
        }
826
589
        if (VSIFReadL(aCompressedRow.data(), nCompressedRawSize, 1, m_pfIMG) !=
827
589
            1)
828
26
            return CE_Failure;
829
589
    }
830
831
35.6M
    while (nAccumulated < m_nWidth)
832
35.6M
    {
833
35.6M
        if (nCompressedRawSize == SIZE_MAX)
834
20.4M
        {
835
20.4M
            if (VSIFReadL(&cCounter, 1, 1, m_pfIMG) != 1)
836
5.33M
                return CE_Failure;
837
20.4M
        }
838
15.1M
        else
839
15.1M
        {
840
15.1M
            if (nCompressedIndex >= aCompressedRow.size())
841
28
            {
842
28
                CPLError(CE_Failure, CPLE_AppDefined,
843
28
                         "Invalid nCompressedIndex");
844
28
                return CE_Failure;
845
28
            }
846
15.1M
            cCounter = aCompressedRow[nCompressedIndex];
847
15.1M
            nCompressedIndex++;
848
15.1M
        }
849
850
30.2M
        if (cCounter == 0) /* Not compressed part */
851
29.8M
        {
852
            /* The following counter read does not indicate
853
            "how many repeated values follow" but rather
854
            "how many are decompressed in standard raster format" */
855
29.8M
            if (nCompressedRawSize == SIZE_MAX)
856
14.9M
            {
857
14.9M
                if (VSIFReadL(&cCounter, 1, 1, m_pfIMG) != 1)
858
52
                    return CE_Failure;
859
14.9M
            }
860
14.9M
            else
861
14.9M
            {
862
14.9M
                if (nCompressedIndex >= aCompressedRow.size())
863
29
                {
864
29
                    CPLError(CE_Failure, CPLE_AppDefined,
865
29
                             "Invalid nCompressedIndex");
866
29
                    return CE_Failure;
867
29
                }
868
14.9M
                cCounter = aCompressedRow[nCompressedIndex];
869
14.9M
                nCompressedIndex++;
870
14.9M
            }
871
872
29.8M
            nAccumulated += cCounter;
873
874
29.8M
            if (nAccumulated > m_nWidth) /* This should not happen if the file
875
                                  is RLE and does not share counters across rows */
876
301
                return CE_Failure;
877
878
30.8M
            for (; nIAccumulated < nAccumulated; nIAccumulated++)
879
987k
            {
880
987k
                if (nCompressedRawSize == SIZE_MAX)
881
499k
                {
882
499k
                    VSIFReadL(&RLEValue, sizeof_TYPE, 1, m_pfIMG);
883
499k
                    memcpy((static_cast<TYPE *>(rowBuffer)) + nIAccumulated,
884
499k
                           &RLEValue, sizeof_TYPE);
885
499k
                }
886
488k
                else
887
488k
                {
888
488k
                    if (nCompressedIndex + sizeof_TYPE > aCompressedRow.size())
889
72
                    {
890
72
                        CPLError(CE_Failure, CPLE_AppDefined,
891
72
                                 "Invalid nCompressedIndex");
892
72
                        return CE_Failure;
893
72
                    }
894
488k
                    memcpy((static_cast<TYPE *>(rowBuffer)) + nIAccumulated,
895
488k
                           &aCompressedRow[nCompressedIndex], sizeof_TYPE);
896
488k
                    nCompressedIndex += sizeof_TYPE;
897
488k
                }
898
987k
            }
899
29.8M
        }
900
394k
        else
901
394k
        {
902
394k
            nAccumulated += cCounter;
903
394k
            if (nAccumulated > m_nWidth) /* This should not happen if the file
904
                                  is RLE and does not share counters across rows */
905
26.3k
                return CE_Failure;
906
907
367k
            if (nCompressedRawSize == SIZE_MAX)
908
187k
            {
909
187k
                if (VSIFReadL(&RLEValue, sizeof_TYPE, 1, m_pfIMG) != 1)
910
39
                    return CE_Failure;
911
187k
            }
912
180k
            else
913
180k
            {
914
180k
                if (nCompressedIndex + sizeof(TYPE) > aCompressedRow.size())
915
20
                {
916
20
                    CPLError(CE_Failure, CPLE_AppDefined,
917
20
                             "Invalid nCompressedIndex");
918
20
                    return CE_Failure;
919
20
                }
920
180k
                memcpy(&RLEValue, &aCompressedRow[nCompressedIndex],
921
180k
                       sizeof(TYPE));
922
180k
                nCompressedIndex += sizeof(TYPE);
923
180k
            }
924
925
367k
            const int nCount = nAccumulated - nIAccumulated;
926
367k
            pDst = static_cast<TYPE *>(rowBuffer) + nIAccumulated;
927
928
367k
            std::fill(pDst, pDst + nCount, RLEValue);
929
930
367k
            nIAccumulated = nAccumulated;
931
367k
        }
932
30.2M
    }
933
934
1.14k
    return CE_None;
935
5.36M
}
CPLErr MMRBand::UncompressRow<float>(void*, unsigned long)
Line
Count
Source
797
15.6k
{
798
15.6k
    int nAccumulated = 0L, nIAccumulated = 0L;
799
15.6k
    unsigned char cCounter;
800
15.6k
    size_t nCompressedIndex = 0;
801
802
15.6k
    TYPE RLEValue;
803
15.6k
    TYPE *pDst;
804
15.6k
    size_t sizeof_TYPE = sizeof(TYPE);
805
806
15.6k
    std::vector<unsigned char> aCompressedRow;
807
808
15.6k
    if (nCompressedRawSize != SIZE_MAX)
809
374
    {
810
374
        if (nCompressedRawSize > 1000 * 1000 &&
811
93
            GetFileSize() < nCompressedRawSize)
812
74
        {
813
74
            CPLError(CE_Failure, CPLE_AppDefined, "Too small file");
814
74
            return CE_Failure;
815
74
        }
816
300
        try
817
300
        {
818
300
            aCompressedRow.resize(nCompressedRawSize);
819
300
        }
820
300
        catch (const std::exception &)
821
300
        {
822
0
            CPLError(CE_Failure, CPLE_OutOfMemory,
823
0
                     "Out of memory allocating working buffer");
824
0
            return CE_Failure;
825
0
        }
826
300
        if (VSIFReadL(aCompressedRow.data(), nCompressedRawSize, 1, m_pfIMG) !=
827
300
            1)
828
18
            return CE_Failure;
829
300
    }
830
831
31.1M
    while (nAccumulated < m_nWidth)
832
31.1M
    {
833
31.1M
        if (nCompressedRawSize == SIZE_MAX)
834
15.5M
        {
835
15.5M
            if (VSIFReadL(&cCounter, 1, 1, m_pfIMG) != 1)
836
8.03k
                return CE_Failure;
837
15.5M
        }
838
15.5M
        else
839
15.5M
        {
840
15.5M
            if (nCompressedIndex >= aCompressedRow.size())
841
13
            {
842
13
                CPLError(CE_Failure, CPLE_AppDefined,
843
13
                         "Invalid nCompressedIndex");
844
13
                return CE_Failure;
845
13
            }
846
15.5M
            cCounter = aCompressedRow[nCompressedIndex];
847
15.5M
            nCompressedIndex++;
848
15.5M
        }
849
850
31.1M
        if (cCounter == 0) /* Not compressed part */
851
30.7M
        {
852
            /* The following counter read does not indicate
853
            "how many repeated values follow" but rather
854
            "how many are decompressed in standard raster format" */
855
30.7M
            if (nCompressedRawSize == SIZE_MAX)
856
15.3M
            {
857
15.3M
                if (VSIFReadL(&cCounter, 1, 1, m_pfIMG) != 1)
858
15
                    return CE_Failure;
859
15.3M
            }
860
15.3M
            else
861
15.3M
            {
862
15.3M
                if (nCompressedIndex >= aCompressedRow.size())
863
7
                {
864
7
                    CPLError(CE_Failure, CPLE_AppDefined,
865
7
                             "Invalid nCompressedIndex");
866
7
                    return CE_Failure;
867
7
                }
868
15.3M
                cCounter = aCompressedRow[nCompressedIndex];
869
15.3M
                nCompressedIndex++;
870
15.3M
            }
871
872
30.7M
            nAccumulated += cCounter;
873
874
30.7M
            if (nAccumulated > m_nWidth) /* This should not happen if the file
875
                                  is RLE and does not share counters across rows */
876
162
                return CE_Failure;
877
878
31.9M
            for (; nIAccumulated < nAccumulated; nIAccumulated++)
879
1.19M
            {
880
1.19M
                if (nCompressedRawSize == SIZE_MAX)
881
602k
                {
882
602k
                    VSIFReadL(&RLEValue, sizeof_TYPE, 1, m_pfIMG);
883
602k
                    memcpy((static_cast<TYPE *>(rowBuffer)) + nIAccumulated,
884
602k
                           &RLEValue, sizeof_TYPE);
885
602k
                }
886
588k
                else
887
588k
                {
888
588k
                    if (nCompressedIndex + sizeof_TYPE > aCompressedRow.size())
889
26
                    {
890
26
                        CPLError(CE_Failure, CPLE_AppDefined,
891
26
                                 "Invalid nCompressedIndex");
892
26
                        return CE_Failure;
893
26
                    }
894
588k
                    memcpy((static_cast<TYPE *>(rowBuffer)) + nIAccumulated,
895
588k
                           &aCompressedRow[nCompressedIndex], sizeof_TYPE);
896
588k
                    nCompressedIndex += sizeof_TYPE;
897
588k
                }
898
1.19M
            }
899
30.7M
        }
900
370k
        else
901
370k
        {
902
370k
            nAccumulated += cCounter;
903
370k
            if (nAccumulated > m_nWidth) /* This should not happen if the file
904
                                  is RLE and does not share counters across rows */
905
6.52k
                return CE_Failure;
906
907
364k
            if (nCompressedRawSize == SIZE_MAX)
908
187k
            {
909
187k
                if (VSIFReadL(&RLEValue, sizeof_TYPE, 1, m_pfIMG) != 1)
910
77
                    return CE_Failure;
911
187k
            }
912
176k
            else
913
176k
            {
914
176k
                if (nCompressedIndex + sizeof(TYPE) > aCompressedRow.size())
915
38
                {
916
38
                    CPLError(CE_Failure, CPLE_AppDefined,
917
38
                             "Invalid nCompressedIndex");
918
38
                    return CE_Failure;
919
38
                }
920
176k
                memcpy(&RLEValue, &aCompressedRow[nCompressedIndex],
921
176k
                       sizeof(TYPE));
922
176k
                nCompressedIndex += sizeof(TYPE);
923
176k
            }
924
925
364k
            const int nCount = nAccumulated - nIAccumulated;
926
364k
            pDst = static_cast<TYPE *>(rowBuffer) + nIAccumulated;
927
928
364k
            std::fill(pDst, pDst + nCount, RLEValue);
929
930
364k
            nIAccumulated = nAccumulated;
931
364k
        }
932
31.1M
    }
933
934
662
    return CE_None;
935
15.5k
}
CPLErr MMRBand::UncompressRow<double>(void*, unsigned long)
Line
Count
Source
797
15.2M
{
798
15.2M
    int nAccumulated = 0L, nIAccumulated = 0L;
799
15.2M
    unsigned char cCounter;
800
15.2M
    size_t nCompressedIndex = 0;
801
802
15.2M
    TYPE RLEValue;
803
15.2M
    TYPE *pDst;
804
15.2M
    size_t sizeof_TYPE = sizeof(TYPE);
805
806
15.2M
    std::vector<unsigned char> aCompressedRow;
807
808
15.2M
    if (nCompressedRawSize != SIZE_MAX)
809
1.18k
    {
810
1.18k
        if (nCompressedRawSize > 1000 * 1000 &&
811
137
            GetFileSize() < nCompressedRawSize)
812
124
        {
813
124
            CPLError(CE_Failure, CPLE_AppDefined, "Too small file");
814
124
            return CE_Failure;
815
124
        }
816
1.05k
        try
817
1.05k
        {
818
1.05k
            aCompressedRow.resize(nCompressedRawSize);
819
1.05k
        }
820
1.05k
        catch (const std::exception &)
821
1.05k
        {
822
0
            CPLError(CE_Failure, CPLE_OutOfMemory,
823
0
                     "Out of memory allocating working buffer");
824
0
            return CE_Failure;
825
0
        }
826
1.05k
        if (VSIFReadL(aCompressedRow.data(), nCompressedRawSize, 1, m_pfIMG) !=
827
1.05k
            1)
828
11
            return CE_Failure;
829
1.05k
    }
830
831
39.2M
    while (nAccumulated < m_nWidth)
832
39.2M
    {
833
39.2M
        if (nCompressedRawSize == SIZE_MAX)
834
27.3M
        {
835
27.3M
            if (VSIFReadL(&cCounter, 1, 1, m_pfIMG) != 1)
836
15.1M
                return CE_Failure;
837
27.3M
        }
838
11.8M
        else
839
11.8M
        {
840
11.8M
            if (nCompressedIndex >= aCompressedRow.size())
841
21
            {
842
21
                CPLError(CE_Failure, CPLE_AppDefined,
843
21
                         "Invalid nCompressedIndex");
844
21
                return CE_Failure;
845
21
            }
846
11.8M
            cCounter = aCompressedRow[nCompressedIndex];
847
11.8M
            nCompressedIndex++;
848
11.8M
        }
849
850
24.0M
        if (cCounter == 0) /* Not compressed part */
851
23.7M
        {
852
            /* The following counter read does not indicate
853
            "how many repeated values follow" but rather
854
            "how many are decompressed in standard raster format" */
855
23.7M
            if (nCompressedRawSize == SIZE_MAX)
856
11.9M
            {
857
11.9M
                if (VSIFReadL(&cCounter, 1, 1, m_pfIMG) != 1)
858
92
                    return CE_Failure;
859
11.9M
            }
860
11.7M
            else
861
11.7M
            {
862
11.7M
                if (nCompressedIndex >= aCompressedRow.size())
863
20
                {
864
20
                    CPLError(CE_Failure, CPLE_AppDefined,
865
20
                             "Invalid nCompressedIndex");
866
20
                    return CE_Failure;
867
20
                }
868
11.7M
                cCounter = aCompressedRow[nCompressedIndex];
869
11.7M
                nCompressedIndex++;
870
11.7M
            }
871
872
23.7M
            nAccumulated += cCounter;
873
874
23.7M
            if (nAccumulated > m_nWidth) /* This should not happen if the file
875
                                  is RLE and does not share counters across rows */
876
720
                return CE_Failure;
877
878
24.7M
            for (; nIAccumulated < nAccumulated; nIAccumulated++)
879
1.06M
            {
880
1.06M
                if (nCompressedRawSize == SIZE_MAX)
881
569k
                {
882
569k
                    VSIFReadL(&RLEValue, sizeof_TYPE, 1, m_pfIMG);
883
569k
                    memcpy((static_cast<TYPE *>(rowBuffer)) + nIAccumulated,
884
569k
                           &RLEValue, sizeof_TYPE);
885
569k
                }
886
493k
                else
887
493k
                {
888
493k
                    if (nCompressedIndex + sizeof_TYPE > aCompressedRow.size())
889
159
                    {
890
159
                        CPLError(CE_Failure, CPLE_AppDefined,
891
159
                                 "Invalid nCompressedIndex");
892
159
                        return CE_Failure;
893
159
                    }
894
493k
                    memcpy((static_cast<TYPE *>(rowBuffer)) + nIAccumulated,
895
493k
                           &aCompressedRow[nCompressedIndex], sizeof_TYPE);
896
493k
                    nCompressedIndex += sizeof_TYPE;
897
493k
                }
898
1.06M
            }
899
23.7M
        }
900
311k
        else
901
311k
        {
902
311k
            nAccumulated += cCounter;
903
311k
            if (nAccumulated > m_nWidth) /* This should not happen if the file
904
                                  is RLE and does not share counters across rows */
905
74.7k
                return CE_Failure;
906
907
236k
            if (nCompressedRawSize == SIZE_MAX)
908
142k
            {
909
142k
                if (VSIFReadL(&RLEValue, sizeof_TYPE, 1, m_pfIMG) != 1)
910
174
                    return CE_Failure;
911
142k
            }
912
94.0k
            else
913
94.0k
            {
914
94.0k
                if (nCompressedIndex + sizeof(TYPE) > aCompressedRow.size())
915
84
                {
916
84
                    CPLError(CE_Failure, CPLE_AppDefined,
917
84
                             "Invalid nCompressedIndex");
918
84
                    return CE_Failure;
919
84
                }
920
93.9k
                memcpy(&RLEValue, &aCompressedRow[nCompressedIndex],
921
93.9k
                       sizeof(TYPE));
922
93.9k
                nCompressedIndex += sizeof(TYPE);
923
93.9k
            }
924
925
236k
            const int nCount = nAccumulated - nIAccumulated;
926
236k
            pDst = static_cast<TYPE *>(rowBuffer) + nIAccumulated;
927
928
236k
            std::fill(pDst, pDst + nCount, RLEValue);
929
930
236k
            nIAccumulated = nAccumulated;
931
236k
        }
932
24.0M
    }
933
934
2.58k
    return CE_None;
935
15.2M
}
936
937
CPLErr MMRBand::GetBlockData(void *rowBuffer, size_t nCompressedRawSize)
938
34.0M
{
939
34.0M
    if (m_eMMDataType == MMDataType::DATATYPE_AND_COMPR_BIT)
940
96
    {
941
96
        const int nGDALBlockSize = DIV_ROUND_UP(m_nBlockXSize, 8);
942
943
96
        if (VSIFReadL(rowBuffer, nGDALBlockSize, 1, m_pfIMG) != 1)
944
28
        {
945
28
            CPLError(CE_Failure, CPLE_AppDefined, "Error while reading band");
946
28
            return CE_Failure;
947
28
        }
948
68
        return CE_None;
949
96
    }
950
951
34.0M
    if (m_eMMDataType == MMDataType::DATATYPE_AND_COMPR_BYTE ||
952
34.0M
        m_eMMDataType == MMDataType::DATATYPE_AND_COMPR_INTEGER ||
953
34.0M
        m_eMMDataType == MMDataType::DATATYPE_AND_COMPR_UINTEGER ||
954
34.0M
        m_eMMDataType == MMDataType::DATATYPE_AND_COMPR_LONG ||
955
34.0M
        m_eMMDataType == MMDataType::DATATYPE_AND_COMPR_REAL ||
956
34.0M
        m_eMMDataType == MMDataType::DATATYPE_AND_COMPR_DOUBLE)
957
25.3k
    {
958
25.3k
        if (VSIFReadL(rowBuffer, m_nDataTypeSizeBytes, m_nWidth, m_pfIMG) !=
959
25.3k
            static_cast<size_t>(m_nWidth))
960
200
        {
961
200
            CPLError(CE_Failure, CPLE_AppDefined, "Error while reading band");
962
200
            return CE_Failure;
963
200
        }
964
25.1k
        return CE_None;
965
25.3k
    }
966
967
34.0M
    CPLErr eErr;
968
34.0M
    switch (m_eMMDataType)
969
34.0M
    {
970
10.6M
        case MMDataType::DATATYPE_AND_COMPR_BYTE_RLE:
971
10.6M
            eErr = UncompressRow<GByte>(rowBuffer, nCompressedRawSize);
972
10.6M
            break;
973
6.70k
        case MMDataType::DATATYPE_AND_COMPR_INTEGER_RLE:
974
6.70k
            eErr = UncompressRow<GInt16>(rowBuffer, nCompressedRawSize);
975
6.70k
            break;
976
2.76M
        case MMDataType::DATATYPE_AND_COMPR_UINTEGER_RLE:
977
2.76M
            eErr = UncompressRow<GUInt16>(rowBuffer, nCompressedRawSize);
978
2.76M
            break;
979
5.36M
        case MMDataType::DATATYPE_AND_COMPR_LONG_RLE:
980
5.36M
            eErr = UncompressRow<GInt32>(rowBuffer, nCompressedRawSize);
981
5.36M
            break;
982
15.6k
        case MMDataType::DATATYPE_AND_COMPR_REAL_RLE:
983
15.6k
            eErr = UncompressRow<float>(rowBuffer, nCompressedRawSize);
984
15.6k
            break;
985
15.2M
        case MMDataType::DATATYPE_AND_COMPR_DOUBLE_RLE:
986
15.2M
            eErr = UncompressRow<double>(rowBuffer, nCompressedRawSize);
987
15.2M
            break;
988
989
0
        default:
990
0
            CPLError(CE_Failure, CPLE_AppDefined, "Error in datatype");
991
0
            eErr = CE_Failure;
992
34.0M
    }
993
994
34.0M
    return eErr;
995
34.0M
}  // End of GetBlockData()
996
997
int MMRBand::PositionAtStartOfRowOffsetsInFile()
998
2.86k
{
999
2.86k
    vsi_l_offset nFileSize, nHeaderOffset;
1000
2.86k
    char szChain[16];
1001
2.86k
    GInt16 nVersion, nSubVersion;
1002
2.86k
    int nOffsetSize, nOffsetsSectionType;
1003
1004
2.86k
    if (VSIFSeekL(m_pfIMG, 0, SEEK_END))
1005
0
        return 0;
1006
1007
2.86k
    nFileSize = VSIFTellL(m_pfIMG);
1008
1009
2.86k
    if (nFileSize < 32)  // Minimum required size
1010
129
        return 0;
1011
1012
2.74k
    if (m_nHeight)
1013
2.74k
    {
1014
2.74k
        if (nFileSize < static_cast<vsi_l_offset>(32) + m_nHeight + 32)
1015
146
            return 0;
1016
2.74k
    }
1017
1018
2.59k
    vsi_l_offset nHeadOffset = nFileSize - 32;
1019
1020
2.59k
    if (VSIFSeekL(m_pfIMG, nHeadOffset, SEEK_SET))  // Reading final header.
1021
0
        return 0;
1022
2.59k
    if (VSIFReadL(szChain, 16, 1, m_pfIMG) != 1)
1023
0
        return 0;
1024
25.3k
    for (int nIndex = 0; nIndex < 16; nIndex++)
1025
23.9k
    {
1026
23.9k
        if (szChain[nIndex] != '\0')
1027
1.25k
            return 0;  // Supposed 0's are not 0.
1028
23.9k
    }
1029
1030
1.34k
    if (VSIFReadL(szChain, 8, 1, m_pfIMG) != 1)
1031
0
        return 0;
1032
1033
1.34k
    if (strncmp(szChain, "IMG ", 4) || szChain[5] != '.')
1034
172
        return 0;
1035
1036
    // Some version checks
1037
1.16k
    szChain[7] = 0;
1038
1.16k
    if (sscanf(szChain + 6, "%hd", &nSubVersion) != 1 || nSubVersion < 0)
1039
18
        return 0;
1040
1041
1.15k
    szChain[5] = 0;
1042
1.15k
    if (sscanf(szChain + 4, "%hd", &nVersion) != 1 || nVersion != 1)
1043
33
        return 0;
1044
1045
    // Next header to be read
1046
1.11k
    if (VSIFReadL(&nHeaderOffset, sizeof(vsi_l_offset), 1, m_pfIMG) != 1)
1047
0
        return 0;
1048
1049
1.11k
    std::set<vsi_l_offset> alreadyVisitedOffsets;
1050
1.11k
    bool bRepeat;
1051
1.11k
    do
1052
1.57k
    {
1053
1.57k
        bRepeat = FALSE;
1054
1055
1.57k
        if (VSIFSeekL(m_pfIMG, nHeaderOffset, SEEK_SET))
1056
19
            return 0;
1057
1058
1.55k
        if (VSIFReadL(szChain, 8, 1, m_pfIMG) != 1)
1059
215
            return 0;
1060
1061
1.34k
        if (strncmp(szChain, "IMG ", 4) || szChain[5] != '.')
1062
61
            return 0;
1063
1064
1.28k
        if (VSIFReadL(&nOffsetsSectionType, 4, 1, m_pfIMG) != 1)
1065
0
            return 0;
1066
1067
1.28k
        if (nOffsetsSectionType != 2)  // 2 = row offsets section
1068
522
        {
1069
            // This is not the section I am looking for
1070
522
            if (VSIFSeekL(m_pfIMG, 8 + 4, SEEK_CUR))
1071
0
                return 0;
1072
1073
522
            if (VSIFReadL(&nHeaderOffset, sizeof(vsi_l_offset), 1, m_pfIMG) !=
1074
522
                1)
1075
25
                return 0;
1076
1077
497
            if (nHeaderOffset == 0)
1078
19
                return 0;
1079
1080
478
            if (cpl::contains(alreadyVisitedOffsets, nHeaderOffset))
1081
17
            {
1082
17
                CPLError(CE_Failure, CPLE_AssertionFailed,
1083
17
                         "Error reading offsets. They will be ignored.");
1084
17
                return 0;
1085
17
            }
1086
1087
461
            alreadyVisitedOffsets.insert(nHeaderOffset);
1088
1089
461
            bRepeat = TRUE;
1090
461
        }
1091
1092
1.28k
    } while (bRepeat);
1093
1094
761
    szChain[7] = 0;
1095
761
    if (sscanf(szChain + 6, "%hd", &nSubVersion) != 1 || nSubVersion < 0)
1096
11
        return 0;
1097
750
    szChain[5] = 0;
1098
750
    if (sscanf(szChain + 4, "%hd", &nVersion) != 1 || nVersion != 1)
1099
26
        return 0;
1100
1101
    /*
1102
        Now I'm in the correct section
1103
        -------------------------------
1104
        Info about this section:
1105
        RasterRLE: minimum size: nHeight*2
1106
        Offsets:   minimum size: 32+nHeight*4
1107
        Final:     size: 32
1108
    */
1109
1110
724
    if (m_nHeight)
1111
724
    {
1112
724
        if (nHeaderOffset < static_cast<vsi_l_offset>(m_nHeight) *
1113
724
                                2 ||  // Minimum size of an RLE
1114
706
            nFileSize - nHeaderOffset <
1115
706
                static_cast<vsi_l_offset>(32) + m_nHeight +
1116
706
                    32)  // Minimum size of the section in version 1.0
1117
28
            return 0;
1118
724
    }
1119
1120
696
    if (VSIFReadL(&nOffsetSize, 4, 1, m_pfIMG) != 1 ||
1121
696
        (nOffsetSize != 8 && nOffsetSize != 4 && nOffsetSize != 2 &&
1122
91
         nOffsetSize != 1))
1123
40
        return 0;
1124
1125
656
    if (m_nHeight)
1126
656
    {
1127
656
        if (nFileSize - nHeaderOffset <
1128
656
            32 + static_cast<vsi_l_offset>(nOffsetSize) * m_nHeight +
1129
656
                32)  // No space for this section in this file
1130
4
            return 0;
1131
1132
        // I leave the file prepared to read offsets
1133
652
        if (VSIFSeekL(m_pfIMG, 16, SEEK_CUR))
1134
0
            return 0;
1135
652
    }
1136
0
    else
1137
0
    {
1138
0
        if (VSIFSeekL(m_pfIMG, 4, SEEK_CUR))
1139
0
            return 0;
1140
1141
0
        if (VSIFSeekL(m_pfIMG, 4, SEEK_CUR))
1142
0
            return 0;
1143
1144
        // I leave the file prepared to read offsets
1145
0
        if (VSIFSeekL(m_pfIMG, 8, SEEK_CUR))
1146
0
            return 0;
1147
0
    }
1148
1149
    // There are offsets!
1150
652
    return nOffsetSize;
1151
656
}  // Fi de PositionAtStartOfRowOffsetsInFile()
1152
1153
/************************************************************************/
1154
/*                            GetFileSize()                             */
1155
/************************************************************************/
1156
1157
vsi_l_offset MMRBand::GetFileSize()
1158
682
{
1159
682
    if (m_nFileSize == 0)
1160
682
    {
1161
682
        const auto nCurPos = VSIFTellL(m_pfIMG);
1162
682
        VSIFSeekL(m_pfIMG, 0, SEEK_END);
1163
682
        m_nFileSize = VSIFTellL(m_pfIMG);
1164
682
        VSIFSeekL(m_pfIMG, nCurPos, SEEK_SET);
1165
682
    }
1166
682
    return m_nFileSize;
1167
682
}
1168
1169
/************************************************************************/
1170
/*                           FillRowOffsets()                           */
1171
/************************************************************************/
1172
1173
bool MMRBand::FillRowOffsets()
1174
29.3k
{
1175
29.3k
    vsi_l_offset nStartOffset;
1176
29.3k
    int nIRow;
1177
29.3k
    vsi_l_offset nBytesPerPixelPerNCol;
1178
29.3k
    int nSizeToRead;  // nSizeToRead is not an offset, but the size of the offsets being read
1179
                      // directly from the IMG file (can be 1, 2, 4, or 8).
1180
29.3k
    vsi_l_offset nFileByte;
1181
29.3k
    size_t nMaxBytesPerCompressedRow;
1182
29.3k
    const int nGDALBlockSize = DIV_ROUND_UP(m_nBlockXSize, 8);
1183
1184
    // If it's filled, there is no need to fill it again
1185
29.3k
    if (!m_aFileOffsets.empty())
1186
26.1k
        return true;
1187
1188
    // Sanity check to avoid attempting huge memory allocation
1189
3.21k
    if (m_nHeight > 1000 * 1000)
1190
22
    {
1191
22
        if (GetFileSize() < static_cast<vsi_l_offset>(m_nHeight))
1192
22
        {
1193
22
            CPLError(CE_Failure, CPLE_AppDefined, "Too small file");
1194
22
            return false;
1195
22
        }
1196
22
    }
1197
1198
3.19k
    try
1199
3.19k
    {
1200
3.19k
        m_aFileOffsets.resize(static_cast<size_t>(m_nHeight) + 1);
1201
3.19k
    }
1202
3.19k
    catch (const std::bad_alloc &e)
1203
3.19k
    {
1204
0
        CPLError(CE_Failure, CPLE_OutOfMemory, "%s", e.what());
1205
0
        return false;
1206
0
    }
1207
1208
3.19k
    switch (m_eMMDataType)
1209
3.19k
    {
1210
43
        case MMDataType::DATATYPE_AND_COMPR_BIT:
1211
1212
            // "<=" it's ok. There is space and it's to make easier the programming
1213
655k
            for (nIRow = 0; nIRow <= m_nHeight; nIRow++)
1214
655k
                m_aFileOffsets[nIRow] =
1215
655k
                    static_cast<vsi_l_offset>(nIRow) * nGDALBlockSize;
1216
43
            break;
1217
1218
135
        case MMDataType::DATATYPE_AND_COMPR_BYTE:
1219
156
        case MMDataType::DATATYPE_AND_COMPR_INTEGER:
1220
175
        case MMDataType::DATATYPE_AND_COMPR_UINTEGER:
1221
205
        case MMDataType::DATATYPE_AND_COMPR_LONG:
1222
218
        case MMDataType::DATATYPE_AND_COMPR_REAL:
1223
279
        case MMDataType::DATATYPE_AND_COMPR_DOUBLE:
1224
279
            nBytesPerPixelPerNCol =
1225
279
                m_nDataTypeSizeBytes * static_cast<vsi_l_offset>(m_nWidth);
1226
            // "<=" it's ok. There is space and it's to make easier the programming
1227
68.2M
            for (nIRow = 0; nIRow <= m_nHeight; nIRow++)
1228
68.2M
                m_aFileOffsets[nIRow] =
1229
68.2M
                    static_cast<vsi_l_offset>(nIRow) * nBytesPerPixelPerNCol;
1230
279
            break;
1231
1232
612
        case MMDataType::DATATYPE_AND_COMPR_BYTE_RLE:
1233
880
        case MMDataType::DATATYPE_AND_COMPR_INTEGER_RLE:
1234
1.19k
        case MMDataType::DATATYPE_AND_COMPR_UINTEGER_RLE:
1235
1.57k
        case MMDataType::DATATYPE_AND_COMPR_LONG_RLE:
1236
1.80k
        case MMDataType::DATATYPE_AND_COMPR_REAL_RLE:
1237
2.86k
        case MMDataType::DATATYPE_AND_COMPR_DOUBLE_RLE:
1238
1239
2.86k
            nStartOffset = VSIFTellL(m_pfIMG);
1240
1241
            // Let's determine if are there offsets in the file
1242
2.86k
            if (0 < (nSizeToRead = PositionAtStartOfRowOffsetsInFile()))
1243
652
            {
1244
                // I have offsets!!
1245
652
                nFileByte = 0L;  // all bits to 0
1246
2.42k
                for (nIRow = 0; nIRow < m_nHeight; nIRow++)
1247
1.80k
                {
1248
1.80k
                    if (VSIFReadL(&nFileByte, nSizeToRead, 1, m_pfIMG) != 1)
1249
0
                        return false;
1250
1251
1.80k
                    m_aFileOffsets[nIRow] = nFileByte;
1252
1253
                    // Let's check that the difference between two offsets is in a int range
1254
1.80k
                    if (nIRow > 0)
1255
1.15k
                    {
1256
1.15k
                        if (m_aFileOffsets[nIRow] <=
1257
1.15k
                            m_aFileOffsets[static_cast<size_t>(nIRow) - 1])
1258
28
                            return false;
1259
1260
1.12k
                        if (m_aFileOffsets[nIRow] -
1261
1.12k
                                m_aFileOffsets[static_cast<size_t>(nIRow) -
1262
1.12k
                                               1] >=
1263
1.12k
                            static_cast<vsi_l_offset>(SIZE_MAX))
1264
0
                            return false;
1265
1.12k
                    }
1266
1.80k
                }
1267
624
                m_aFileOffsets[nIRow] = 0;  // Not reliable
1268
624
                VSIFSeekL(m_pfIMG, nStartOffset, SEEK_SET);
1269
624
                break;
1270
652
            }
1271
1272
            // Not indexed RLE. We create a dynamic indexation
1273
2.21k
            if (m_nWidth >
1274
2.21k
                INT_MAX /
1275
2.21k
                    (std::max(1, static_cast<int>(m_eMMBytesPerPixel)) + 1))
1276
0
            {
1277
0
                CPLError(CE_Failure, CPLE_AppDefined, "Too large row: %d",
1278
0
                         m_nWidth);
1279
0
                VSIFSeekL(m_pfIMG, nStartOffset, SEEK_SET);
1280
0
                return false;
1281
0
            }
1282
1283
2.21k
            nMaxBytesPerCompressedRow =
1284
2.21k
                static_cast<int>(m_eMMBytesPerPixel)
1285
2.21k
                    ? (m_nWidth * (static_cast<int>(m_eMMBytesPerPixel) + 1))
1286
2.21k
                    : (m_nWidth * (1 + 1));
1287
2.21k
            unsigned char *pBuffer;
1288
1289
2.21k
            if (nullptr == (pBuffer = static_cast<unsigned char *>(
1290
2.21k
                                VSI_MALLOC_VERBOSE(nMaxBytesPerCompressedRow))))
1291
0
            {
1292
0
                VSIFSeekL(m_pfIMG, nStartOffset, SEEK_SET);
1293
0
                return false;
1294
0
            }
1295
1296
2.21k
            VSIFSeekL(m_pfIMG, 0, SEEK_SET);
1297
2.21k
            m_aFileOffsets[0] = 0;
1298
34.0M
            for (nIRow = 0; nIRow < m_nHeight; nIRow++)
1299
34.0M
            {
1300
34.0M
                GetBlockData(pBuffer, SIZE_MAX);
1301
34.0M
                m_aFileOffsets[static_cast<size_t>(nIRow) + 1] =
1302
34.0M
                    VSIFTellL(m_pfIMG);
1303
34.0M
            }
1304
2.21k
            VSIFree(pBuffer);
1305
2.21k
            VSIFSeekL(m_pfIMG, nStartOffset, SEEK_SET);
1306
2.21k
            break;
1307
1308
0
        default:
1309
0
            return false;
1310
3.19k
    }  // End of switch (eMMDataType)
1311
3.16k
    return true;
1312
1313
3.19k
}  // End of FillRowOffsets()
1314
1315
/************************************************************************/
1316
/*                              Writing part()                          */
1317
/* Indexing a compressed file increments the efficiency when reading it */
1318
/************************************************************************/
1319
bool MMRBand::WriteRowOffsets()
1320
0
{
1321
0
    if (m_aFileOffsets.empty() || m_nHeight == 0)
1322
0
        return true;
1323
1324
0
    VSIFSeekL(m_pfIMG, 0, SEEK_END);
1325
1326
0
    vsi_l_offset nStartOffset = VSIFTellL(m_pfIMG);
1327
0
    if (nStartOffset == 0)
1328
0
        return false;
1329
1330
0
    if (VSIFWriteL("IMG 1.0\0", sizeof("IMG 1.0"), 1, m_pfIMG) != 1)
1331
0
        return false;
1332
1333
    // Type of section
1334
0
    int nAux = 2;
1335
0
    if (VSIFWriteL(&nAux, 4, 1, m_pfIMG) != 1)
1336
0
        return false;
1337
1338
0
    size_t nIndexOffset = static_cast<size_t>(m_nHeight);
1339
0
    int nOffsetSize;
1340
1341
0
    if (m_aFileOffsets[nIndexOffset - 1] < static_cast<vsi_l_offset>(UCHAR_MAX))
1342
0
        nOffsetSize = 1;
1343
0
    else if (m_aFileOffsets[nIndexOffset - 1] <
1344
0
             static_cast<vsi_l_offset>(USHRT_MAX))
1345
0
        nOffsetSize = 2;
1346
0
    else if (m_aFileOffsets[nIndexOffset - 1] <
1347
0
             static_cast<vsi_l_offset>(UINT32_MAX))
1348
0
        nOffsetSize = 4;
1349
0
    else
1350
0
        nOffsetSize = 8;
1351
1352
0
    if (VSIFWriteL(&nOffsetSize, 4, 1, m_pfIMG) != 1)
1353
0
        return false;
1354
1355
0
    nAux = 0;
1356
0
    if (VSIFWriteL(&nAux, 4, 1, m_pfIMG) != 1)
1357
0
        return false;
1358
0
    if (VSIFWriteL(&nAux, 4, 1, m_pfIMG) != 1)
1359
0
        return false;
1360
1361
0
    vsi_l_offset nUselessOffset = 0;
1362
0
    if (VSIFWriteL(&nUselessOffset, sizeof(vsi_l_offset), 1, m_pfIMG) != 1)
1363
0
        return false;
1364
1365
    // The main part
1366
0
    size_t nSizeTOffsetSize = nOffsetSize;
1367
0
    if (nSizeTOffsetSize == sizeof(vsi_l_offset))
1368
0
    {
1369
0
        if (VSIFWriteL(&(m_aFileOffsets[0]), sizeof(vsi_l_offset), nIndexOffset,
1370
0
                       m_pfIMG) != nIndexOffset)
1371
0
            return false;
1372
0
    }
1373
0
    else
1374
0
    {
1375
0
        for (nIndexOffset = 0; nIndexOffset < m_aFileOffsets.size() - 1;
1376
0
             nIndexOffset++)
1377
0
        {
1378
0
            if (VSIFWriteL(&(m_aFileOffsets[nIndexOffset]), nSizeTOffsetSize, 1,
1379
0
                           m_pfIMG) != 1)
1380
0
                return false;
1381
0
        }
1382
0
    }
1383
1384
    // End part of file
1385
0
    nAux = 0;
1386
0
    for (int nIndex = 0; nIndex < 4; nIndex++)
1387
0
    {
1388
0
        if (VSIFWriteL(&nAux, 4, 1, m_pfIMG) != 1)
1389
0
            return false;
1390
0
    }
1391
0
    if (VSIFWriteL("IMG 1.0\0", sizeof("IMG 1.0"), 1, m_pfIMG) != 1)
1392
0
        return false;
1393
1394
0
    if (VSIFWriteL(&nStartOffset, sizeof(vsi_l_offset), 1, m_pfIMG) != 1)
1395
0
        return false;
1396
1397
0
    return true;
1398
1399
0
}  // End of WriteRowOffsets()
1400
1401
// Getting data type from dataset
1402
bool MMRBand::UpdateDataTypeAndBytesPerPixelFromRasterBand(
1403
    GDALRasterBand &papoBand)
1404
0
{
1405
0
    switch (papoBand.GetRasterDataType())
1406
0
    {
1407
0
        case GDT_Byte:
1408
0
            if (m_bIsCompressed)
1409
0
                m_eMMDataType = MMDataType::DATATYPE_AND_COMPR_BYTE_RLE;
1410
0
            else
1411
0
                m_eMMDataType = MMDataType::DATATYPE_AND_COMPR_BYTE;
1412
1413
0
            m_eMMBytesPerPixel =
1414
0
                MMBytesPerPixel::TYPE_BYTES_PER_PIXEL_BYTE_I_RLE;
1415
0
            break;
1416
1417
0
        case GDT_UInt16:
1418
0
            if (m_bIsCompressed)
1419
0
                m_eMMDataType = MMDataType::DATATYPE_AND_COMPR_UINTEGER_RLE;
1420
0
            else
1421
0
                m_eMMDataType = MMDataType::DATATYPE_AND_COMPR_UINTEGER;
1422
1423
0
            m_eMMBytesPerPixel =
1424
0
                MMBytesPerPixel::TYPE_BYTES_PER_PIXEL_INTEGER_I_RLE;
1425
0
            break;
1426
1427
0
        case GDT_Int16:
1428
0
            if (m_bIsCompressed)
1429
0
                m_eMMDataType = MMDataType::DATATYPE_AND_COMPR_INTEGER_RLE;
1430
0
            else
1431
0
                m_eMMDataType = MMDataType::DATATYPE_AND_COMPR_INTEGER;
1432
1433
0
            m_eMMBytesPerPixel =
1434
0
                MMBytesPerPixel::TYPE_BYTES_PER_PIXEL_INTEGER_I_RLE;
1435
0
            break;
1436
1437
0
        case GDT_Int32:
1438
0
            if (m_bIsCompressed)
1439
0
                m_eMMDataType = MMDataType::DATATYPE_AND_COMPR_LONG_RLE;
1440
0
            else
1441
0
                m_eMMDataType = MMDataType::DATATYPE_AND_COMPR_LONG;
1442
1443
0
            m_eMMBytesPerPixel =
1444
0
                MMBytesPerPixel::TYPE_BYTES_PER_PIXEL_LONG_REAL_I_RLE;
1445
0
            break;
1446
1447
0
        case GDT_Float32:
1448
0
            if (m_bIsCompressed)
1449
0
                m_eMMDataType = MMDataType::DATATYPE_AND_COMPR_REAL_RLE;
1450
0
            else
1451
0
                m_eMMDataType = MMDataType::DATATYPE_AND_COMPR_REAL;
1452
1453
0
            m_eMMBytesPerPixel =
1454
0
                MMBytesPerPixel::TYPE_BYTES_PER_PIXEL_LONG_REAL_I_RLE;
1455
0
            break;
1456
1457
0
        case GDT_Float64:
1458
0
            if (m_bIsCompressed)
1459
0
                m_eMMDataType = MMDataType::DATATYPE_AND_COMPR_DOUBLE_RLE;
1460
0
            else
1461
0
                m_eMMDataType = MMDataType::DATATYPE_AND_COMPR_DOUBLE;
1462
1463
0
            m_eMMBytesPerPixel =
1464
0
                MMBytesPerPixel::TYPE_BYTES_PER_PIXEL_DOUBLE_I_RLE;
1465
0
            break;
1466
1467
0
        default:
1468
0
            m_eMMDataType = MMDataType::DATATYPE_AND_COMPR_UNDEFINED;
1469
0
            m_eMMBytesPerPixel =
1470
0
                MMBytesPerPixel::TYPE_BYTES_PER_PIXEL_UNDEFINED;
1471
0
            m_nDataTypeSizeBytes = 0;
1472
0
            m_nWidth = 0;
1473
0
            m_nHeight = 0;
1474
0
            CPLError(CE_Failure, CPLE_AppDefined,
1475
0
                     "MiraMonRaster: data type unhandled");
1476
0
            return false;
1477
0
    }
1478
0
    return true;
1479
0
}
1480
1481
// Getting nodata value from metadata
1482
void MMRBand::UpdateNoDataValueFromRasterBand(GDALRasterBand &papoBand)
1483
0
{
1484
0
    int pbSuccess;
1485
0
    m_dfNoData = papoBand.GetNoDataValue(&pbSuccess);
1486
0
    m_bNoDataSet = pbSuccess == 1 ? true : false;
1487
0
}
1488
1489
CPLString MMRBand::GetRELDataType() const
1490
0
{
1491
0
    if (m_eMMDataType == MMDataType::DATATYPE_AND_COMPR_BIT)
1492
0
        return "bit";
1493
0
    if (m_eMMDataType == MMDataType::DATATYPE_AND_COMPR_BYTE ||
1494
0
        m_eMMDataType == MMDataType::DATATYPE_AND_COMPR_BYTE_RLE)
1495
0
    {
1496
0
        if (m_bIsCompressed)
1497
0
            return "byte-RLE";
1498
0
        return "byte";
1499
0
    }
1500
0
    if (m_eMMDataType == MMDataType::DATATYPE_AND_COMPR_INTEGER ||
1501
0
        m_eMMDataType == MMDataType::DATATYPE_AND_COMPR_INTEGER_RLE)
1502
0
    {
1503
0
        if (m_bIsCompressed)
1504
0
            return "integer-RLE";
1505
0
        return "integer";
1506
0
    }
1507
1508
0
    if (m_eMMDataType == MMDataType::DATATYPE_AND_COMPR_UINTEGER ||
1509
0
        m_eMMDataType == MMDataType::DATATYPE_AND_COMPR_UINTEGER_RLE)
1510
0
    {
1511
0
        if (m_bIsCompressed)
1512
0
            return "uinteger-RLE";
1513
0
        return "uinteger";
1514
0
    }
1515
1516
0
    if (m_eMMDataType == MMDataType::DATATYPE_AND_COMPR_LONG ||
1517
0
        m_eMMDataType == MMDataType::DATATYPE_AND_COMPR_LONG_RLE)
1518
0
    {
1519
0
        if (m_bIsCompressed)
1520
0
            return "long-RLE";
1521
0
        return "long";
1522
0
    }
1523
1524
0
    if (m_eMMDataType == MMDataType::DATATYPE_AND_COMPR_REAL ||
1525
0
        m_eMMDataType == MMDataType::DATATYPE_AND_COMPR_REAL_RLE)
1526
0
    {
1527
0
        if (m_bIsCompressed)
1528
0
            return "real-RLE";
1529
0
        return "real";
1530
0
    }
1531
1532
0
    if (m_eMMDataType == MMDataType::DATATYPE_AND_COMPR_DOUBLE ||
1533
0
        m_eMMDataType == MMDataType::DATATYPE_AND_COMPR_DOUBLE_RLE)
1534
0
    {
1535
0
        if (m_bIsCompressed)
1536
0
            return "double-RLE";
1537
0
        return "double";
1538
0
    }
1539
1540
0
    return "";
1541
0
}
1542
1543
void MMRBand::UpdateRowMinMax(const void *pBuffer)
1544
0
{
1545
0
    switch (m_eMMDataType)
1546
0
    {
1547
0
        case MMDataType::DATATYPE_AND_COMPR_BIT:
1548
0
        case MMDataType::DATATYPE_AND_COMPR_BYTE:
1549
0
        case MMDataType::DATATYPE_AND_COMPR_BYTE_RLE:
1550
0
            UpdateRowMinMax<unsigned char>(pBuffer);
1551
0
            break;
1552
1553
0
        case MMDataType::DATATYPE_AND_COMPR_UINTEGER:
1554
0
        case MMDataType::DATATYPE_AND_COMPR_UINTEGER_RLE:
1555
0
            UpdateRowMinMax<GUInt16>(pBuffer);
1556
0
            break;
1557
1558
0
        case MMDataType::DATATYPE_AND_COMPR_INTEGER:
1559
0
        case MMDataType::DATATYPE_AND_COMPR_INTEGER_RLE:
1560
0
        case MMDataType::DATATYPE_AND_COMPR_INTEGER_ASCII:
1561
0
            UpdateRowMinMax<GInt16>(pBuffer);
1562
0
            break;
1563
1564
0
        case MMDataType::DATATYPE_AND_COMPR_LONG:
1565
0
        case MMDataType::DATATYPE_AND_COMPR_LONG_RLE:
1566
0
            UpdateRowMinMax<int>(pBuffer);
1567
0
            break;
1568
1569
0
        case MMDataType::DATATYPE_AND_COMPR_REAL:
1570
0
        case MMDataType::DATATYPE_AND_COMPR_REAL_RLE:
1571
0
        case MMDataType::DATATYPE_AND_COMPR_REAL_ASCII:
1572
0
            UpdateRowMinMax<float>(pBuffer);
1573
0
            break;
1574
1575
0
        case MMDataType::DATATYPE_AND_COMPR_DOUBLE:
1576
0
        case MMDataType::DATATYPE_AND_COMPR_DOUBLE_RLE:
1577
0
            UpdateRowMinMax<double>(pBuffer);
1578
0
            break;
1579
1580
0
        default:
1581
0
            break;
1582
0
    }
1583
0
}
1584
1585
bool MMRBand::WriteBandFile(GDALDataset &oSrcDS, int nNBands, int nIBand)
1586
0
{
1587
1588
0
    GDALRasterBand *pRasterBand = oSrcDS.GetRasterBand(nIBand + 1);
1589
0
    if (!pRasterBand)
1590
0
        return false;
1591
1592
    // Updating variable to suitable values
1593
0
    m_nBlockXSize = m_nWidth;
1594
0
    m_nBlockYSize = 1;
1595
0
    m_nNRowsPerBlock = 1;
1596
1597
    // Opening the RAW file
1598
0
    m_pfIMG = VSIFOpenL(m_osBandFileName, "wb");
1599
0
    if (!m_pfIMG)
1600
0
    {
1601
0
        CPLError(CE_Failure, CPLE_OpenFailed,
1602
0
                 "Failed to create MiraMon band file `%s' with access 'wb'.",
1603
0
                 m_osBandFileName.c_str());
1604
0
        return false;
1605
0
    }
1606
1607
    // Creating index information
1608
0
    if (m_bIsCompressed)
1609
0
    {
1610
0
        try
1611
0
        {
1612
0
            m_aFileOffsets.resize(static_cast<size_t>(m_nHeight) + 1);
1613
0
        }
1614
0
        catch (const std::bad_alloc &e)
1615
0
        {
1616
0
            CPLError(CE_Failure, CPLE_OutOfMemory, "%s", e.what());
1617
0
            return false;
1618
0
        }
1619
0
    }
1620
1621
0
    GDALDataType eDT = pRasterBand->GetRasterDataType();
1622
1623
    // Temporary buffer for one scanline
1624
0
    void *pBuffer =
1625
0
        VSI_MALLOC2_VERBOSE(m_nWidth, GDALGetDataTypeSizeBytes(eDT));
1626
0
    if (pBuffer == nullptr)
1627
0
        return false;
1628
1629
0
    void *pRow =
1630
0
        VSI_MALLOC2_VERBOSE(m_nWidth, (GDALGetDataTypeSizeBytes(eDT) + 1));
1631
0
    if (pRow == nullptr)
1632
0
    {
1633
0
        VSIFree(pBuffer);
1634
0
        return false;
1635
0
    }
1636
1637
    // Loop over each line
1638
0
    double dfComplete = nIBand * 1.0 / nNBands;
1639
0
    double dfIncr = 1.0 / (nNBands * m_nHeight);
1640
0
    if (!m_pfnProgress(dfComplete, nullptr, m_pProgressData))
1641
0
    {
1642
0
        VSIFree(pBuffer);
1643
0
        VSIFree(pRow);
1644
0
        return false;
1645
0
    }
1646
1647
0
    m_bMinSet = false;
1648
0
    m_dfMin = std::numeric_limits<double>::max();
1649
0
    m_bMaxSet = false;
1650
0
    m_dfMax = -std::numeric_limits<double>::max();
1651
1652
0
    for (int iLine = 0; iLine < m_nHeight; ++iLine)
1653
0
    {
1654
        // Read one line from the raster band
1655
0
        CPLErr err =
1656
0
            pRasterBand->RasterIO(GF_Read, 0, iLine, m_nWidth, 1, pBuffer,
1657
0
                                  m_nWidth, 1, eDT, 0, 0, nullptr);
1658
1659
0
        if (err != CE_None)
1660
0
        {
1661
0
            CPLError(CE_Failure, CPLE_AppDefined,
1662
0
                     "Error reading line %d from raster band", iLine);
1663
0
            VSIFree(pBuffer);
1664
0
            VSIFree(pRow);
1665
0
            return false;
1666
0
        }
1667
1668
        // MinMax calculation
1669
0
        UpdateRowMinMax(pBuffer);
1670
1671
0
        if (m_bIsCompressed)
1672
0
            m_aFileOffsets[iLine] = VSIFTellL(m_pfIMG);
1673
1674
        // Write the line to the MiraMon band file
1675
0
        size_t nWritten, nCompressed;
1676
0
        if (m_bIsCompressed)
1677
0
        {
1678
0
            nCompressed =
1679
0
                CompressRowType(m_eMMDataType, pBuffer, m_nWidth, pRow);
1680
0
            nWritten = VSIFWriteL(pRow, 1, nCompressed, m_pfIMG);
1681
0
            if (nWritten != nCompressed)
1682
0
            {
1683
0
                CPLError(CE_Failure, CPLE_AppDefined,
1684
0
                         "Failed to write line %d to MiraMon band file", iLine);
1685
0
                VSIFree(pBuffer);
1686
0
                VSIFree(pRow);
1687
0
                return false;
1688
0
            }
1689
0
        }
1690
0
        else
1691
0
        {
1692
0
            nWritten = VSIFWriteL(pBuffer, GDALGetDataTypeSizeBytes(eDT),
1693
0
                                  m_nWidth, m_pfIMG);
1694
0
            if (nWritten != static_cast<size_t>(m_nWidth))
1695
0
            {
1696
0
                CPLError(CE_Failure, CPLE_AppDefined,
1697
0
                         "Failed to write line %d to MiraMon band file", iLine);
1698
0
                VSIFree(pBuffer);
1699
0
                VSIFree(pRow);
1700
0
                return false;
1701
0
            }
1702
0
        }
1703
1704
0
        dfComplete += dfIncr;
1705
0
        if (!m_pfnProgress(dfComplete, nullptr, m_pProgressData))
1706
0
        {
1707
0
            VSIFree(pBuffer);
1708
0
            VSIFree(pRow);
1709
0
            return false;
1710
0
        }
1711
0
    }
1712
0
    VSIFree(pBuffer);
1713
0
    VSIFree(pRow);
1714
1715
    // Updating min and max values for simbolization
1716
0
    m_dfVisuMin = m_dfMin;
1717
0
    m_bMinVisuSet = m_bMinSet;
1718
0
    m_dfVisuMax = m_dfMax;
1719
0
    m_bMaxVisuSet = m_bMaxSet;
1720
1721
    // There is a final part that contain the indexes to every row
1722
0
    if (m_bIsCompressed)
1723
0
    {
1724
0
        if (WriteRowOffsets() == false)
1725
0
            return false;
1726
0
    }
1727
1728
0
    dfComplete = (nIBand + 1.0) / nNBands;
1729
0
    if (!m_pfnProgress(dfComplete, nullptr, m_pProgressData))
1730
0
        return false;
1731
1732
0
    return true;
1733
0
}
1734
1735
constexpr uint8_t LIMIT = 255;
1736
1737
template <typename T>
1738
size_t MMRBand::CompressRowTypeTpl(const T *pRow, int nNCol, void *pBufferVoid)
1739
0
{
1740
0
    uint8_t *pBuffer = static_cast<uint8_t *>(pBufferVoid);
1741
1742
0
    T tPreviousValue = pRow[0];
1743
0
    uint8_t nByteCounter = 0;
1744
0
    size_t nRowBytes = 0;
1745
1746
0
    for (int i = 0; i < nNCol; i++)
1747
0
    {
1748
0
        if (tPreviousValue == pRow[i] && nByteCounter < LIMIT)
1749
0
            nByteCounter++;
1750
0
        else  // I have found a different value or I have reached the limit of the counter
1751
0
        {
1752
0
            if (nByteCounter == 1)
1753
0
            {
1754
                //In cas of three consecutive different values, it's more efficient
1755
                // to write them as uncompressed values than as three RLE
1756
0
                if (i + 2 < nNCol && pRow[i] != pRow[i + 1] &&
1757
0
                    pRow[i + 1] != pRow[i + 2])
1758
0
                {
1759
                    // Indicates that the following values are
1760
                    // uncompressed, and how many of them are there
1761
0
                    *pBuffer++ = 0;
1762
0
                    uint8_t *pHowManyUncompressed = pBuffer++;
1763
0
                    nRowBytes += 2;
1764
1765
                    // Writing first three
1766
0
                    memcpy(pBuffer, &tPreviousValue, sizeof(T));
1767
0
                    pBuffer += sizeof(T);
1768
1769
0
                    tPreviousValue = pRow[i];
1770
0
                    memcpy(pBuffer, &tPreviousValue, sizeof(T));
1771
0
                    pBuffer += sizeof(T);
1772
0
                    i++;
1773
1774
0
                    tPreviousValue = pRow[i];
1775
0
                    memcpy(pBuffer, &tPreviousValue, sizeof(T));
1776
0
                    pBuffer += sizeof(T);
1777
1778
0
                    nRowBytes += 3 * sizeof(T);
1779
1780
                    // nByteCounter is now the number of bytes of the three uncompressed values
1781
0
                    nByteCounter = 3;
1782
1783
0
                    for (i++; i + 1 < nNCol && nByteCounter < LIMIT;
1784
0
                         i++, nByteCounter++)
1785
0
                    {
1786
0
                        if (pRow[i] == pRow[i + 1])
1787
0
                            break;
1788
1789
0
                        memcpy(pBuffer, pRow + i, sizeof(T));
1790
0
                        pBuffer += sizeof(T);
1791
0
                        nRowBytes += sizeof(T);
1792
0
                    }
1793
1794
0
                    if (i + 1 == nNCol && nByteCounter < LIMIT)
1795
0
                    {
1796
0
                        *pHowManyUncompressed = ++nByteCounter;
1797
0
                        memcpy(pBuffer, pRow + i, sizeof(T));
1798
0
                        nRowBytes += sizeof(T);
1799
0
                        return nRowBytes;
1800
0
                    }
1801
1802
0
                    *pHowManyUncompressed = nByteCounter;
1803
0
                    tPreviousValue = pRow[i];
1804
0
                    nByteCounter = 1;
1805
0
                    continue;
1806
0
                }
1807
0
            }
1808
1809
            // Normal RLE
1810
0
            *pBuffer++ = nByteCounter;
1811
0
            memcpy(pBuffer, &tPreviousValue, sizeof(T));
1812
0
            pBuffer += sizeof(T);
1813
0
            nRowBytes += 1 + sizeof(T);
1814
1815
0
            tPreviousValue = pRow[i];
1816
0
            nByteCounter = 1;
1817
0
        }
1818
0
    }
1819
1820
    // Last element
1821
0
    *pBuffer++ = nByteCounter;
1822
1823
0
    memcpy(pBuffer, &tPreviousValue, sizeof(T));
1824
0
    nRowBytes += 1 + sizeof(T);
1825
1826
0
    return nRowBytes;
1827
0
}
Unexecuted instantiation: unsigned long MMRBand::CompressRowTypeTpl<unsigned char>(unsigned char const*, int, void*)
Unexecuted instantiation: unsigned long MMRBand::CompressRowTypeTpl<short>(short const*, int, void*)
Unexecuted instantiation: unsigned long MMRBand::CompressRowTypeTpl<unsigned short>(unsigned short const*, int, void*)
Unexecuted instantiation: unsigned long MMRBand::CompressRowTypeTpl<int>(int const*, int, void*)
Unexecuted instantiation: unsigned long MMRBand::CompressRowTypeTpl<float>(float const*, int, void*)
Unexecuted instantiation: unsigned long MMRBand::CompressRowTypeTpl<double>(double const*, int, void*)
1828
1829
size_t MMRBand::CompressRowType(MMDataType nDataType, const void *pRow,
1830
                                int nNCol, void *pBuffer)
1831
0
{
1832
0
    switch (nDataType)
1833
0
    {
1834
0
        case MMDataType::DATATYPE_AND_COMPR_BYTE_RLE:
1835
0
        case MMDataType::DATATYPE_AND_COMPR_BYTE:
1836
0
            return CompressRowTypeTpl<uint8_t>(
1837
0
                reinterpret_cast<const uint8_t *>(pRow), nNCol, pBuffer);
1838
1839
0
        case MMDataType::DATATYPE_AND_COMPR_INTEGER_RLE:
1840
0
        case MMDataType::DATATYPE_AND_COMPR_INTEGER:
1841
0
            return CompressRowTypeTpl<GInt16>(
1842
0
                reinterpret_cast<const GInt16 *>(pRow), nNCol, pBuffer);
1843
1844
0
        case MMDataType::DATATYPE_AND_COMPR_UINTEGER_RLE:
1845
0
        case MMDataType::DATATYPE_AND_COMPR_UINTEGER:
1846
0
            return CompressRowTypeTpl<GUInt16>(
1847
0
                reinterpret_cast<const GUInt16 *>(pRow), nNCol, pBuffer);
1848
1849
0
        case MMDataType::DATATYPE_AND_COMPR_LONG_RLE:
1850
0
        case MMDataType::DATATYPE_AND_COMPR_LONG:
1851
0
            return CompressRowTypeTpl<GInt32>(
1852
0
                reinterpret_cast<const GInt32 *>(pRow), nNCol, pBuffer);
1853
1854
0
        case MMDataType::DATATYPE_AND_COMPR_REAL_RLE:
1855
0
        case MMDataType::DATATYPE_AND_COMPR_REAL:
1856
0
            return CompressRowTypeTpl<float>(
1857
0
                reinterpret_cast<const float *>(pRow), nNCol, pBuffer);
1858
1859
0
        case MMDataType::DATATYPE_AND_COMPR_DOUBLE_RLE:
1860
0
        case MMDataType::DATATYPE_AND_COMPR_DOUBLE:
1861
0
            return CompressRowTypeTpl<double>(
1862
0
                reinterpret_cast<const double *>(pRow), nNCol, pBuffer);
1863
1864
0
        default:
1865
            // same treatment than the original
1866
0
            return 0;
1867
0
    }
1868
0
}
1869
1870
int MMRBand::WriteColorTable(GDALDataset &oSrcDS)
1871
0
{
1872
0
    GDALRasterBand *pRasterBand = oSrcDS.GetRasterBand(m_nIBand + 1);
1873
0
    if (!pRasterBand)
1874
0
        return 0;
1875
1876
0
    m_poCT = pRasterBand->GetColorTable();
1877
0
    if (!m_poCT)
1878
0
    {
1879
        // Perhaps the RAT contains colors and MiraMon can use them as a palette
1880
0
        return WriteColorTableFromRAT(oSrcDS);
1881
0
    }
1882
1883
0
    if (!m_poCT->GetColorEntryCount())
1884
0
        return 0;
1885
1886
    // Creating DBF table name
1887
0
    if (!cpl::ends_with(m_osBandFileName, pszExtRaster))
1888
0
        return 1;
1889
1890
    // Extract .img
1891
0
    m_osCTName = m_osBandFileName;
1892
0
    m_osCTName.resize(m_osCTName.size() - strlen(".img"));
1893
0
    m_osCTName.append("_CT.dbf");
1894
1895
    // Creating DBF
1896
0
    struct MM_DATA_BASE_XP *pBD_XP =
1897
0
        MM_CreateDBFHeader(4, MM_JOC_CARAC_UTF8_DBF);
1898
0
    if (!pBD_XP)
1899
0
        return 1;
1900
1901
    // Assigning DBF table name
1902
0
    CPLStrlcpy(pBD_XP->szFileName, m_osCTName, sizeof(pBD_XP->szFileName));
1903
1904
    // Initializing the table
1905
0
    MM_EXT_DBF_N_RECORDS nPaletteColors =
1906
0
        static_cast<MM_EXT_DBF_N_RECORDS>(m_poCT->GetColorEntryCount());
1907
0
    pBD_XP->nFields = 4;
1908
0
    pBD_XP->nRecords = nPaletteColors;
1909
0
    pBD_XP->FirstRecordOffset =
1910
0
        static_cast<MM_FIRST_RECORD_OFFSET_TYPE>(33 + (pBD_XP->nFields * 32));
1911
0
    pBD_XP->CharSet = MM_JOC_CARAC_ANSI_DBASE;
1912
0
    pBD_XP->dbf_version = MM_MARCA_DBASE4;
1913
0
    pBD_XP->BytesPerRecord = 1;
1914
1915
0
    MM_ACCUMULATED_BYTES_TYPE_DBF nClauSimbolNBytes = 0;
1916
0
    do
1917
0
    {
1918
0
        nClauSimbolNBytes++;
1919
0
        nPaletteColors /= 10;
1920
0
    } while (nPaletteColors > 0);
1921
0
    nClauSimbolNBytes++;
1922
1923
    // Fields of the DBF table
1924
0
    struct MM_FIELD MMField;
1925
0
    MM_InitializeField(&MMField);
1926
0
    MMField.FieldType = 'N';
1927
0
    CPLStrlcpy(MMField.FieldName, "CLAUSIMBOL", MM_MAX_LON_FIELD_NAME_DBF);
1928
0
    MMField.BytesPerField = nClauSimbolNBytes;
1929
0
    MM_DuplicateFieldDBXP(pBD_XP->pField, &MMField);
1930
1931
0
    CPLStrlcpy(MMField.FieldName, "R_COLOR", MM_MAX_LON_FIELD_NAME_DBF);
1932
0
    MMField.BytesPerField = 3;
1933
0
    MM_DuplicateFieldDBXP(pBD_XP->pField + 1, &MMField);
1934
1935
0
    CPLStrlcpy(MMField.FieldName, "G_COLOR", MM_MAX_LON_FIELD_NAME_DBF);
1936
0
    MMField.BytesPerField = 3;
1937
0
    MM_DuplicateFieldDBXP(pBD_XP->pField + 2, &MMField);
1938
1939
0
    CPLStrlcpy(MMField.FieldName, "B_COLOR", MM_MAX_LON_FIELD_NAME_DBF);
1940
0
    MMField.BytesPerField = 3;
1941
0
    MM_DuplicateFieldDBXP(pBD_XP->pField + 3, &MMField);
1942
1943
    // Opening the table
1944
0
    if (!MM_CreateAndOpenDBFFile(pBD_XP, pBD_XP->szFileName))
1945
0
    {
1946
0
        MM_ReleaseDBFHeader(&pBD_XP);
1947
0
        return 1;
1948
0
    }
1949
1950
    // Writing records to the table
1951
0
    if (0 != VSIFSeekL(pBD_XP->pfDataBase,
1952
0
                       static_cast<vsi_l_offset>(pBD_XP->FirstRecordOffset),
1953
0
                       SEEK_SET))
1954
0
    {
1955
0
        MM_ReleaseDBFHeader(&pBD_XP);
1956
0
        return 1;
1957
0
    }
1958
1959
0
    GDALColorEntry colorEntry;
1960
0
    int nIColor;
1961
0
    for (nIColor = 0; nIColor < static_cast<int>(pBD_XP->nRecords); nIColor++)
1962
0
    {
1963
0
        m_poCT->GetColorEntryAsRGB(nIColor, &colorEntry);
1964
1965
        // Deletion flag
1966
0
        if (!VSIFPrintfL(pBD_XP->pfDataBase, " "))
1967
0
        {
1968
0
            MM_ReleaseDBFHeader(&pBD_XP);
1969
0
            return 1;
1970
0
        }
1971
1972
0
        if (!VSIFPrintfL(pBD_XP->pfDataBase, "%*d",
1973
0
                         static_cast<int>(nClauSimbolNBytes), nIColor))
1974
0
        {
1975
0
            MM_ReleaseDBFHeader(&pBD_XP);
1976
0
            return 1;
1977
0
        }
1978
0
        if (colorEntry.c4 == 0)
1979
0
        {
1980
0
            if (!VSIFPrintfL(pBD_XP->pfDataBase, "%3d%3d%3d", -1, -1, -1))
1981
0
            {
1982
0
                MM_ReleaseDBFHeader(&pBD_XP);
1983
0
                return 1;
1984
0
            }
1985
0
        }
1986
0
        else
1987
0
        {
1988
0
            if (!VSIFPrintfL(pBD_XP->pfDataBase, "%3d%3d%3d",
1989
0
                             static_cast<int>(colorEntry.c1),
1990
0
                             static_cast<int>(colorEntry.c2),
1991
0
                             static_cast<int>(colorEntry.c3)))
1992
0
            {
1993
0
                MM_ReleaseDBFHeader(&pBD_XP);
1994
0
                return 1;
1995
0
            }
1996
0
        }
1997
0
    }
1998
1999
0
    fclose_and_nullify(&pBD_XP->pfDataBase);
2000
0
    MM_ReleaseDBFHeader(&pBD_XP);
2001
0
    return 0;
2002
0
}
2003
2004
// Writes DBF and REL attribute table in MiraMon format
2005
int MMRBand::WriteColorTableFromRAT(GDALDataset &oSrcDS)
2006
0
{
2007
0
    GDALRasterBand *pRasterBand = oSrcDS.GetRasterBand(m_nIBand + 1);
2008
0
    if (!pRasterBand)
2009
0
        return 0;
2010
2011
0
    m_poRAT = pRasterBand->GetDefaultRAT();
2012
0
    if (!m_poRAT)
2013
0
        return 0;
2014
2015
    // At least a value and RGB columns are required
2016
0
    if (m_poRAT->GetColumnCount() < 4)
2017
0
        return 0;
2018
2019
0
    if (!m_poRAT->GetRowCount())
2020
0
        return 0;
2021
2022
    // Getting the columns that can be converted to a MiraMon palette
2023
0
    int nIValueMinMax = m_poRAT->GetColOfUsage(GFU_MinMax);
2024
0
    int nIValueMin = m_poRAT->GetColOfUsage(GFU_Min);
2025
0
    int nIValueMax = m_poRAT->GetColOfUsage(GFU_Max);
2026
0
    int nIRed = m_poRAT->GetColOfUsage(GFU_Red);
2027
0
    int nIGreen = m_poRAT->GetColOfUsage(GFU_Green);
2028
0
    int nIBlue = m_poRAT->GetColOfUsage(GFU_Blue);
2029
0
    int nIAlpha = m_poRAT->GetColOfUsage(GFU_Alpha);
2030
2031
    // If the RAT has no value type nor RGB colors, MiraMon can't handle that
2032
    // as a color table. MinMax or Min and Max are accepted as values.
2033
0
    if (!(nIValueMinMax != -1 || (nIValueMin != -1 && nIValueMax != -1) ||
2034
0
          nIRed == -1 || nIGreen == -1 || nIBlue == -1))
2035
0
        return 0;
2036
2037
    // Creating DBF table name
2038
0
    if (!cpl::ends_with(m_osBandFileName, pszExtRaster))
2039
0
        return 1;
2040
2041
    // Extract .img
2042
0
    m_osCTName = m_osBandFileName;
2043
0
    m_osCTName.resize(m_osCTName.size() - strlen(".img"));
2044
0
    m_osCTName.append("_CT.dbf");
2045
2046
    // Creating DBF
2047
0
    struct MM_DATA_BASE_XP *pBD_XP =
2048
0
        MM_CreateDBFHeader(4, MM_JOC_CARAC_UTF8_DBF);
2049
0
    if (!pBD_XP)
2050
0
        return 1;
2051
2052
    // Assigning DBF table name
2053
0
    CPLStrlcpy(pBD_XP->szFileName, m_osCTName, sizeof(pBD_XP->szFileName));
2054
2055
    // Initializing the table
2056
0
    MM_EXT_DBF_N_RECORDS nPaletteColors =
2057
0
        static_cast<MM_EXT_DBF_N_RECORDS>(m_poRAT->GetRowCount());
2058
0
    pBD_XP->nFields = 4;
2059
0
    pBD_XP->nRecords = nPaletteColors;
2060
0
    pBD_XP->FirstRecordOffset =
2061
0
        static_cast<MM_FIRST_RECORD_OFFSET_TYPE>(33 + (pBD_XP->nFields * 32));
2062
0
    pBD_XP->CharSet = MM_JOC_CARAC_ANSI_DBASE;
2063
0
    pBD_XP->dbf_version = MM_MARCA_DBASE4;
2064
0
    pBD_XP->BytesPerRecord = 1;
2065
2066
0
    MM_ACCUMULATED_BYTES_TYPE_DBF nClauSimbolNBytes = 0;
2067
0
    do
2068
0
    {
2069
0
        nClauSimbolNBytes++;
2070
0
        nPaletteColors /= 10;
2071
0
    } while (nPaletteColors > 0);
2072
0
    nClauSimbolNBytes++;
2073
2074
    // Fields of the DBF table
2075
0
    struct MM_FIELD MMField;
2076
0
    MM_InitializeField(&MMField);
2077
0
    MMField.FieldType = 'N';
2078
0
    CPLStrlcpy(MMField.FieldName, "CLAUSIMBOL", MM_MAX_LON_FIELD_NAME_DBF);
2079
0
    MMField.BytesPerField = nClauSimbolNBytes;
2080
0
    MM_DuplicateFieldDBXP(pBD_XP->pField, &MMField);
2081
2082
0
    CPLStrlcpy(MMField.FieldName, "R_COLOR", MM_MAX_LON_FIELD_NAME_DBF);
2083
0
    MMField.BytesPerField = 3;
2084
0
    MM_DuplicateFieldDBXP(pBD_XP->pField + 1, &MMField);
2085
2086
0
    CPLStrlcpy(MMField.FieldName, "G_COLOR", MM_MAX_LON_FIELD_NAME_DBF);
2087
0
    MMField.BytesPerField = 3;
2088
0
    MM_DuplicateFieldDBXP(pBD_XP->pField + 2, &MMField);
2089
2090
0
    CPLStrlcpy(MMField.FieldName, "B_COLOR", MM_MAX_LON_FIELD_NAME_DBF);
2091
0
    MMField.BytesPerField = 3;
2092
0
    MM_DuplicateFieldDBXP(pBD_XP->pField + 3, &MMField);
2093
2094
    // Opening the table
2095
0
    if (!MM_CreateAndOpenDBFFile(pBD_XP, pBD_XP->szFileName))
2096
0
    {
2097
0
        MM_ReleaseDBFHeader(&pBD_XP);
2098
0
        return 1;
2099
0
    }
2100
2101
    // Writing records to the table
2102
0
    if (0 != VSIFSeekL(pBD_XP->pfDataBase,
2103
0
                       static_cast<vsi_l_offset>(pBD_XP->FirstRecordOffset),
2104
0
                       SEEK_SET))
2105
0
    {
2106
0
        MM_ReleaseDBFHeader(&pBD_XP);
2107
0
        return 1;
2108
0
    }
2109
2110
0
    int nIRow;
2111
0
    for (nIRow = 0; nIRow < static_cast<int>(pBD_XP->nRecords); nIRow++)
2112
0
    {
2113
0
        if (nIRow > 0 && nIValueMin != -1 && nIValueMax != -1)
2114
0
        {
2115
0
            if (m_poRAT->GetValueAsInt(nIRow, nIValueMin) ==
2116
0
                m_poRAT->GetValueAsInt(nIRow, nIValueMax))
2117
0
                break;
2118
0
        }
2119
        // Deletion flag
2120
0
        if (!VSIFPrintfL(pBD_XP->pfDataBase, " "))
2121
0
        {
2122
0
            MM_ReleaseDBFHeader(&pBD_XP);
2123
0
            return 1;
2124
0
        }
2125
2126
0
        if (!VSIFPrintfL(pBD_XP->pfDataBase, "%*d",
2127
0
                         static_cast<int>(nClauSimbolNBytes), nIRow))
2128
0
        {
2129
0
            MM_ReleaseDBFHeader(&pBD_XP);
2130
0
            return 1;
2131
0
        }
2132
0
        if (nIAlpha != -1 && m_poRAT->GetValueAsInt(nIRow, nIAlpha) == 0)
2133
0
        {
2134
0
            if (!VSIFPrintfL(pBD_XP->pfDataBase, "%3d%3d%3d", -1, -1, -1))
2135
0
            {
2136
0
                MM_ReleaseDBFHeader(&pBD_XP);
2137
0
                return 1;
2138
0
            }
2139
0
        }
2140
0
        else
2141
0
        {
2142
0
            if (!VSIFPrintfL(pBD_XP->pfDataBase, "%3d%3d%3d",
2143
0
                             m_poRAT->GetValueAsInt(nIRow, nIRed),
2144
0
                             m_poRAT->GetValueAsInt(nIRow, nIGreen),
2145
0
                             m_poRAT->GetValueAsInt(nIRow, nIBlue)))
2146
0
            {
2147
0
                MM_ReleaseDBFHeader(&pBD_XP);
2148
0
                return 1;
2149
0
            }
2150
0
        }
2151
0
    }
2152
2153
    // Nodata color
2154
0
    if (!VSIFPrintfL(pBD_XP->pfDataBase, " "))
2155
0
    {
2156
0
        MM_ReleaseDBFHeader(&pBD_XP);
2157
0
        return 1;
2158
0
    }
2159
0
    if (!VSIFPrintfL(pBD_XP->pfDataBase, "%*s",
2160
0
                     static_cast<int>(nClauSimbolNBytes), ""))
2161
0
    {
2162
0
        MM_ReleaseDBFHeader(&pBD_XP);
2163
0
        return 1;
2164
0
    }
2165
0
    if (!VSIFPrintfL(pBD_XP->pfDataBase, "%3d%3d%3d", -1, -1, -1))
2166
0
    {
2167
0
        MM_ReleaseDBFHeader(&pBD_XP);
2168
0
        return 1;
2169
0
    }
2170
0
    nIRow++;
2171
2172
0
    if (nIRow != static_cast<int>(pBD_XP->nRecords))
2173
0
    {
2174
0
        pBD_XP->nRecords = nIRow;
2175
0
        MM_WriteNRecordsMMBD_XPFile(pBD_XP);
2176
0
    }
2177
2178
0
    fclose_and_nullify(&pBD_XP->pfDataBase);
2179
0
    MM_ReleaseDBFHeader(&pBD_XP);
2180
0
    return 0;
2181
0
}
2182
2183
// Writes DBF and REL attribute table in MiraMon format
2184
int MMRBand::WriteAttributeTable(GDALDataset &oSrcDS)
2185
0
{
2186
0
    GDALRasterBand *pRasterBand = oSrcDS.GetRasterBand(m_nIBand + 1);
2187
0
    if (!pRasterBand)
2188
0
        return 0;
2189
2190
0
    m_poRAT = pRasterBand->GetDefaultRAT();
2191
0
    if (!m_poRAT)
2192
0
        return 0;
2193
2194
0
    if (!m_poRAT->GetColumnCount())
2195
0
        return 0;
2196
2197
0
    if (!m_poRAT->GetRowCount())
2198
0
        return 0;
2199
2200
    // Getting the Value column
2201
0
    int nIField;
2202
0
    m_osValue = "";
2203
0
    int nIValue = m_poRAT->GetColOfUsage(GFU_MinMax);
2204
    // If the RAT has no value type, MiraMon can't handle that
2205
    // as a RAT
2206
0
    if (nIValue == -1)
2207
0
    {
2208
0
        nIValue = m_poRAT->GetColOfUsage(GFU_Min);
2209
0
        if (nIValue == -1)
2210
0
        {
2211
0
            GDALRATFieldType nType = m_poRAT->GetTypeOfCol(0);
2212
0
            if (nType == GFT_Integer)
2213
0
                nIValue = 0;
2214
0
            else
2215
0
                return 1;
2216
0
        }
2217
0
    }
2218
2219
0
    m_osValue = m_poRAT->GetNameOfCol(nIValue);
2220
2221
    // Creating DBF table name
2222
0
    if (!cpl::ends_with(m_osBandFileName, pszExtRaster))
2223
0
        return 1;
2224
2225
    // Extract .img and create DBF file name
2226
0
    m_osRATDBFName = m_osBandFileName;
2227
0
    m_osRATDBFName.resize(m_osRATDBFName.size() - strlen(".img"));
2228
0
    m_osRATDBFName.append("_RAT.dbf");
2229
2230
    // Extract .img and create REL file name
2231
0
    m_osRATRELName = m_osBandFileName;
2232
0
    m_osRATRELName.resize(m_osRATRELName.size() - strlen(".img"));
2233
0
    m_osRATRELName.append("_RAT.rel");
2234
2235
    // Creating DBF
2236
0
    int nFields = m_poRAT->GetColumnCount();
2237
0
    struct MM_DATA_BASE_XP *pBD_XP =
2238
0
        MM_CreateDBFHeader(nFields, MM_JOC_CARAC_UTF8_DBF);
2239
0
    if (!pBD_XP)
2240
0
        return 1;
2241
2242
    // Creating a simple REL that allows MiraMon user to
2243
    // document this RAT in case of need.
2244
0
    auto pRATRel = std::make_unique<MMRRel>(m_osRATRELName);
2245
0
    if (!pRATRel->OpenRELFile("wb"))
2246
0
    {
2247
0
        MM_ReleaseDBFHeader(&pBD_XP);
2248
0
        return 1;
2249
0
    }
2250
2251
0
    pRATRel->AddSectionStart(SECTION_VERSIO);
2252
0
    pRATRel->AddKeyValue(KEY_Vers, "4");
2253
0
    pRATRel->AddKeyValue(KEY_SubVers, "3");
2254
0
    pRATRel->AddSectionEnd();
2255
2256
0
    pRATRel->AddSectionStart(SECTION_TAULA_PRINCIPAL);
2257
    // Get path relative to REL file
2258
0
    pRATRel->AddKeyValue(KEY_NomFitxer, CPLGetFilename(m_osRATDBFName));
2259
0
    pRATRel->AddKeyValue(KEY_TipusRelacio, "RELACIO_N_1");
2260
0
    pRATRel->AddKeyValue("AssociatRel", m_osValue);
2261
0
    pRATRel->AddSectionEnd();
2262
2263
    // Assigning DBF table name
2264
0
    CPLStrlcpy(pBD_XP->szFileName, m_osRATDBFName, sizeof(pBD_XP->szFileName));
2265
2266
    // Initializing the table
2267
0
    MM_EXT_DBF_N_RECORDS nRecords =
2268
0
        static_cast<MM_EXT_DBF_N_RECORDS>(m_poRAT->GetRowCount());
2269
0
    pBD_XP->nFields = nFields;
2270
0
    pBD_XP->nRecords = nRecords;
2271
0
    pBD_XP->FirstRecordOffset =
2272
0
        static_cast<MM_FIRST_RECORD_OFFSET_TYPE>(33 + (pBD_XP->nFields * 32));
2273
0
    pBD_XP->CharSet = MM_JOC_CARAC_ANSI_DBASE;
2274
0
    pBD_XP->dbf_version = MM_MARCA_DBASE4;
2275
0
    pBD_XP->BytesPerRecord = 1;
2276
2277
    // Fields of the DBF table
2278
0
    struct MM_FIELD MMField;
2279
0
    for (nIField = 0; nIField < m_poRAT->GetColumnCount(); nIField++)
2280
0
    {
2281
        // DBF part
2282
0
        MM_InitializeField(&MMField);
2283
0
        CPLStrlcpy(MMField.FieldName, m_poRAT->GetNameOfCol(nIField),
2284
0
                   sizeof(MMField.FieldName));
2285
2286
0
        MMField.BytesPerField = 0;
2287
0
        for (int nIRow = 0; nIRow < m_poRAT->GetRowCount(); nIRow++)
2288
0
        {
2289
0
            if (m_poRAT->GetTypeOfCol(nIField) == GFT_DateTime)
2290
0
            {
2291
0
                MMField.FieldType = 'D';
2292
0
                MMField.DecimalsIfFloat = 0;
2293
0
                MMField.BytesPerField = MM_MAX_AMPLADA_CAMP_D_DBF;
2294
0
                break;
2295
0
            }
2296
0
            else if (m_poRAT->GetTypeOfCol(nIField) == GFT_Boolean)
2297
0
            {
2298
0
                MMField.FieldType = 'L';
2299
0
                MMField.DecimalsIfFloat = 0;
2300
0
                MMField.BytesPerField = 1;
2301
0
                break;
2302
0
            }
2303
0
            else
2304
0
            {
2305
0
                if (m_poRAT->GetTypeOfCol(nIField) == GFT_String ||
2306
0
                    m_poRAT->GetTypeOfCol(nIField) == GFT_WKBGeometry)
2307
0
                {
2308
0
                    MMField.FieldType = 'C';
2309
0
                    MMField.DecimalsIfFloat = 0;
2310
0
                }
2311
0
                else
2312
0
                {
2313
0
                    MMField.FieldType = 'N';
2314
0
                    if (m_poRAT->GetTypeOfCol(nIField) == GFT_Real)
2315
0
                    {
2316
0
                        MMField.BytesPerField = 20;
2317
0
                        MMField.DecimalsIfFloat = MAX_RELIABLE_SF_DOUBLE;
2318
0
                    }
2319
0
                    else
2320
0
                        MMField.DecimalsIfFloat = 0;
2321
0
                }
2322
0
                char *pszString =
2323
0
                    CPLRecode(m_poRAT->GetValueAsString(nIRow, nIField),
2324
0
                              CPL_ENC_UTF8, "CP1252");
2325
2326
0
                if (strlen(pszString) > MMField.BytesPerField)
2327
0
                    MMField.BytesPerField =
2328
0
                        static_cast<MM_BYTES_PER_FIELD_TYPE_DBF>(
2329
0
                            strlen(pszString));
2330
2331
0
                CPLFree(pszString);
2332
0
            }
2333
0
        }
2334
0
        MM_DuplicateFieldDBXP(pBD_XP->pField + nIField, &MMField);
2335
2336
        // REL part
2337
0
        CPLString osSection = SECTION_TAULA_PRINCIPAL;
2338
0
        osSection.append(":");
2339
0
        osSection.append(MMField.FieldName);
2340
0
        pRATRel->AddSectionStart(osSection);
2341
2342
0
        if (EQUAL(MMField.FieldName, m_osValue))
2343
0
        {
2344
0
            pRATRel->AddKeyValue("visible", "0");
2345
0
            pRATRel->AddKeyValue(KEY_TractamentVariable, "Categoric");
2346
0
        }
2347
0
        pRATRel->AddKeyValue(KEY_descriptor, "");
2348
0
        pRATRel->AddSectionEnd();
2349
0
    }
2350
2351
    // Closing the REL
2352
0
    pRATRel->CloseRELFile();
2353
2354
    // Opening the table
2355
0
    if (!MM_CreateAndOpenDBFFile(pBD_XP, pBD_XP->szFileName))
2356
0
    {
2357
0
        MM_ReleaseDBFHeader(&pBD_XP);
2358
0
        return 1;
2359
0
    }
2360
2361
    // Writing records to the table
2362
0
    if (0 != VSIFSeekL(pBD_XP->pfDataBase,
2363
0
                       static_cast<vsi_l_offset>(pBD_XP->FirstRecordOffset),
2364
0
                       SEEK_SET))
2365
0
    {
2366
0
        MM_ReleaseDBFHeader(&pBD_XP);
2367
0
        return 1;
2368
0
    }
2369
2370
0
    for (int nIRow = 0; nIRow < static_cast<int>(pBD_XP->nRecords); nIRow++)
2371
0
    {
2372
        // Deletion flag
2373
0
        if (!VSIFPrintfL(pBD_XP->pfDataBase, " "))
2374
0
        {
2375
0
            MM_ReleaseDBFHeader(&pBD_XP);
2376
0
            return 1;
2377
0
        }
2378
0
        for (nIField = 0; nIField < static_cast<int>(pBD_XP->nFields);
2379
0
             nIField++)
2380
0
        {
2381
0
            if (m_poRAT->GetTypeOfCol(nIRow) == GFT_DateTime)
2382
0
            {
2383
0
                char szDate[15];
2384
0
                const GDALRATDateTime osDT =
2385
0
                    m_poRAT->GetValueAsDateTime(nIRow, nIField);
2386
0
                if (osDT.nYear >= 0)
2387
0
                    snprintf(szDate, sizeof(szDate), "%04d%02d%02d", osDT.nYear,
2388
0
                             osDT.nMonth, osDT.nDay);
2389
0
                else
2390
0
                    snprintf(szDate, sizeof(szDate), "%04d%02d%02d", 0, 0, 0);
2391
2392
0
                if (pBD_XP->pField[nIField].BytesPerField !=
2393
0
                    VSIFWriteL(szDate, 1, pBD_XP->pField[nIField].BytesPerField,
2394
0
                               pBD_XP->pfDataBase))
2395
0
                {
2396
0
                    MM_ReleaseDBFHeader(&pBD_XP);
2397
0
                    return 1;
2398
0
                }
2399
0
            }
2400
0
            else if (m_poRAT->GetTypeOfCol(nIRow) == GFT_Boolean)
2401
0
            {
2402
0
                if (pBD_XP->pField[nIField].BytesPerField !=
2403
0
                    VSIFWriteL(m_poRAT->GetValueAsBoolean(nIRow, nIField) ? "T"
2404
0
                                                                          : "F",
2405
0
                               1, pBD_XP->pField[nIField].BytesPerField,
2406
0
                               pBD_XP->pfDataBase))
2407
0
                {
2408
0
                    MM_ReleaseDBFHeader(&pBD_XP);
2409
0
                    return 1;
2410
0
                }
2411
0
            }
2412
0
            else if (m_poRAT->GetTypeOfCol(nIRow) == GFT_WKBGeometry)
2413
0
            {
2414
0
                if (pBD_XP->pField[nIField].BytesPerField !=
2415
0
                    VSIFWriteL(m_poRAT->GetValueAsString(nIRow, nIField), 1,
2416
0
                               pBD_XP->pField[nIField].BytesPerField,
2417
0
                               pBD_XP->pfDataBase))
2418
0
                {
2419
0
                    MM_ReleaseDBFHeader(&pBD_XP);
2420
0
                    return 1;
2421
0
                }
2422
0
            }
2423
0
            else
2424
0
            {
2425
0
                char *pszString =
2426
0
                    CPLRecode(m_poRAT->GetValueAsString(nIRow, nIField),
2427
0
                              CPL_ENC_UTF8, "CP1252");
2428
2429
0
                if (pBD_XP->pField[nIField].BytesPerField !=
2430
0
                    VSIFWriteL(pszString, 1,
2431
0
                               pBD_XP->pField[nIField].BytesPerField,
2432
0
                               pBD_XP->pfDataBase))
2433
0
                {
2434
0
                    MM_ReleaseDBFHeader(&pBD_XP);
2435
0
                    return 1;
2436
0
                }
2437
0
                CPLFree(pszString);
2438
0
            }
2439
0
        }
2440
0
    }
2441
2442
0
    fclose_and_nullify(&pBD_XP->pfDataBase);
2443
0
    MM_ReleaseDBFHeader(&pBD_XP);
2444
0
    return 0;
2445
0
}