Coverage Report

Created: 2026-03-30 09:00

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/gdal/frmts/rmf/rmfdataset.h
Line
Count
Source
1
/******************************************************************************
2
 *
3
 * Project:  Raster Matrix Format
4
 * Purpose:  Private class declarations for the RMF classes used to read/write
5
 *           GIS "Integratsia" raster files (also known as "Panorama" GIS).
6
 * Author:   Andrey Kiselev, dron@ak4719.spb.edu
7
 *
8
 ******************************************************************************
9
 * Copyright (c) 2007, Andrey Kiselev <dron@ak4719.spb.edu>
10
 * Copyright (c) 2023, NextGIS <info@nextgis.com>
11
 *
12
 * SPDX-License-Identifier: MIT
13
 ****************************************************************************/
14
15
#ifndef RMFDATASET_H_INCLUDED
16
#define RMFDATASET_H_INCLUDED
17
18
#include <array>
19
#include <list>
20
#include "gdal_priv.h"
21
#include "cpl_worker_thread_pool.h"
22
23
680
#define RMF_HEADER_SIZE 320
24
0
#define RMF_EXT_HEADER_SIZE 320
25
931
#define RMF_MIN_EXT_HEADER_SIZE (36 + 4)
26
866
#define RMF_MAX_EXT_HEADER_SIZE 1000000
27
28
906
#define RMF_COMPRESSION_NONE 0
29
557
#define RMF_COMPRESSION_LZW 1
30
264
#define RMF_COMPRESSION_JPEG 2
31
494
#define RMF_COMPRESSION_DEM 32
32
33
enum RMFType
34
{
35
    RMFT_RSW,  // Raster map
36
    RMFT_MTW   // Digital elevation model
37
};
38
39
enum RMFVersion
40
{
41
    RMF_VERSION = 0x0200,      // Version for "small" files less than 4 Gb
42
    RMF_VERSION_HUGE = 0x0201  // Version for "huge" files less than 4 Tb. Since
43
                               // GIS Panorama v11
44
};
45
46
class RMFDataset;
47
48
3.68k
#define RMF_HUGE_OFFSET_FACTOR 256
49
50
constexpr int RMF_JPEG_BAND_COUNT = 3;
51
constexpr int RMF_DEM_BAND_COUNT = 1;
52
53
/************************************************************************/
54
/*                              RMFHeader                               */
55
/************************************************************************/
56
57
typedef struct
58
{
59
1.17k
#define RMF_SIGNATURE_SIZE 4
60
    char bySignature[RMF_SIGNATURE_SIZE];  // "RSW" for raster
61
                                           // map or "MTW" for DEM
62
    GUInt32 iVersion;
63
    GUInt32 nSize;       // File size in bytes
64
    GUInt32 nOvrOffset;  // Offset to overview
65
    GUInt32 iUserID;
66
0
#define RMF_NAME_SIZE 32
67
    GByte byName[RMF_NAME_SIZE];
68
    GUInt32 nBitDepth;  // Number of bits per pixel
69
    GUInt32 nHeight;    // Image length
70
    GUInt32 nWidth;     // Image width
71
    GUInt32 nXTiles;    // Number of tiles in line
72
    GUInt32 nYTiles;    // Number of tiles in column
73
    GUInt32 nTileHeight;
74
    GUInt32 nTileWidth;
75
    GUInt32 nLastTileHeight;
76
    GUInt32 nLastTileWidth;
77
    GUInt32 nROIOffset;
78
    GUInt32 nROISize;
79
    GUInt32 nClrTblOffset;   // Position and size
80
    GUInt32 nClrTblSize;     // of the colour table
81
    GUInt32 nTileTblOffset;  // Position and size of the
82
    GUInt32 nTileTblSize;    // tile offsets/sizes table
83
    GInt32 iMapType;
84
    GInt32 iProjection;
85
    GInt32 iEPSGCode;
86
    double dfScale;
87
    double dfResolution;
88
    double dfPixelSize;
89
    double dfLLX;
90
    double dfLLY;
91
    double dfStdP1;
92
    double dfStdP2;
93
    double dfCenterLong;
94
    double dfCenterLat;
95
    GByte iCompression;
96
    GByte iMaskType;
97
    GByte iMaskStep;
98
    GByte iFrameFlag;
99
    GUInt32 nFlagsTblOffset;
100
    GUInt32 nFlagsTblSize;
101
    GUInt32 nFileSize0;
102
    GUInt32 nFileSize1;
103
    GByte iUnknown;
104
    GByte iGeorefFlag;
105
    GByte iInverse;
106
    GByte iJpegQuality;
107
#define RMF_INVISIBLE_COLORS_SIZE 32
108
    GByte abyInvisibleColors[RMF_INVISIBLE_COLORS_SIZE];
109
    double adfElevMinMax[2];
110
    double dfNoData;
111
    GUInt32 iElevationUnit;
112
    GByte iElevationType;
113
    GUInt32 nExtHdrOffset;
114
    GUInt32 nExtHdrSize;
115
} RMFHeader;
116
117
/************************************************************************/
118
/*                             RMFExtHeader                             */
119
/************************************************************************/
120
121
typedef struct
122
{
123
    GInt32 nEllipsoid;
124
    GInt32 nVertDatum;
125
    GInt32 nDatum;
126
    GInt32 nZone;
127
} RMFExtHeader;
128
129
/************************************************************************/
130
/*                               RSWFrame                               */
131
/************************************************************************/
132
133
typedef struct
134
{
135
    GInt32 nType;
136
    GInt32 nSize;
137
    GInt32 nSubCount;
138
    GInt32 nCoordsSize;
139
} RSWFrame;
140
141
typedef struct
142
{
143
    GInt32 nX, nY;
144
} RSWFrameCoord;
145
146
/************************************************************************/
147
/*                          RMFCompressionJob                           */
148
/************************************************************************/
149
150
struct RMFCompressionJob
151
{
152
    RMFDataset *poDS = nullptr;
153
    CPLErr eResult = CE_None;
154
    int nBlockXOff = -1;
155
    int nBlockYOff = -1;
156
    GByte *pabyUncompressedData = nullptr;
157
    size_t nUncompressedBytes = 0;
158
    GByte *pabyCompressedData = nullptr;
159
    size_t nCompressedBytes = 0;
160
    GUInt32 nXSize = 0;
161
    GUInt32 nYSize = 0;
162
163
0
    RMFCompressionJob() = default;
164
    RMFCompressionJob(const RMFCompressionJob &) = delete;
165
    RMFCompressionJob &operator=(const RMFCompressionJob &) = delete;
166
    RMFCompressionJob(RMFCompressionJob &&) = default;
167
    RMFCompressionJob &operator=(RMFCompressionJob &&) = default;
168
};
169
170
/************************************************************************/
171
/*                           RMFCompressData                            */
172
/************************************************************************/
173
174
struct RMFCompressData
175
{
176
    CPLWorkerThreadPool oThreadPool{};
177
    std::vector<RMFCompressionJob> asJobs{};
178
    std::list<RMFCompressionJob *> asReadyJobs{};
179
    GByte *pabyBuffers = nullptr;
180
    CPLMutex *hReadyJobMutex = nullptr;
181
    CPLMutex *hWriteTileMutex = nullptr;
182
183
    RMFCompressData(const RMFCompressData &) = delete;
184
    RMFCompressData &operator=(const RMFCompressData &) = delete;
185
186
    RMFCompressData();
187
    ~RMFCompressData();
188
};
189
190
/************************************************************************/
191
/*                             RMFTileData                              */
192
/************************************************************************/
193
194
struct RMFTileData
195
{
196
    std::vector<GByte> oData{};
197
    int nBandsWritten = 0;
198
};
199
200
/************************************************************************/
201
/*                              RMFDataset                              */
202
/************************************************************************/
203
204
class RMFDataset final : public GDALDataset
205
{
206
    friend class RMFRasterBand;
207
208
  private:
209
    RMFHeader sHeader{};
210
    RMFExtHeader sExtHeader{};
211
    RMFType eRMFType = RMFT_RSW;
212
    GUInt32 nXTiles = 0;
213
    GUInt32 nYTiles = 0;
214
    GUInt32 *paiTiles = nullptr;
215
    GByte *pabyDecompressBuffer = nullptr;
216
    GByte *pabyCurrentTile = nullptr;
217
    bool bCurrentTileIsNull = false;
218
    int nCurrentTileXOff = -1;
219
    int nCurrentTileYOff = -1;
220
    GUInt32 nCurrentTileBytes = 0;
221
    GUInt32 nColorTableSize = 0;
222
    GByte *pabyColorTable = nullptr;
223
    GDALColorTable *poColorTable = nullptr;
224
    GDALGeoTransform m_gt{};
225
    OGRSpatialReference m_oSRS{};
226
227
    char *pszUnitType = nullptr;
228
229
    bool bBigEndian = false;
230
    bool bHeaderDirty = false;
231
232
    VSILFILE *fp = nullptr;
233
234
    std::shared_ptr<RMFCompressData> poCompressData{};
235
    std::map<GUInt32, RMFTileData> oUnfinishedTiles{};
236
237
    CPLErr WriteHeader();
238
    static size_t LZWDecompress(const GByte *, GUInt32, GByte *, GUInt32,
239
                                GUInt32, GUInt32);
240
    static size_t LZWCompress(const GByte *, GUInt32, GByte *, GUInt32, GUInt32,
241
                              GUInt32, const RMFDataset *);
242
#ifdef HAVE_LIBJPEG
243
    static size_t JPEGDecompress(const GByte *, GUInt32, GByte *, GUInt32,
244
                                 GUInt32, GUInt32);
245
    static size_t JPEGCompress(const GByte *, GUInt32, GByte *, GUInt32,
246
                               GUInt32, GUInt32, const RMFDataset *);
247
#endif  // HAVE_LIBJPEG
248
    static size_t DEMDecompress(const GByte *, GUInt32, GByte *, GUInt32,
249
                                GUInt32, GUInt32);
250
    static size_t DEMCompress(const GByte *, GUInt32, GByte *, GUInt32, GUInt32,
251
                              GUInt32, const RMFDataset *);
252
253
    /*!
254
        Tile decompress callback
255
        pabyIn - input compressed data
256
        nSizeIn - input compressed data size (in bytes)
257
        pabyOut - pointer to uncompressed data
258
        nSizeOut - maximum uncompressed data size
259
        nTileSx - width of uncompressed tile (in pixels)
260
        nTileSy - height of uncompressed tile (in pixels)
261
262
        Returns: actual uncompressed data size or 0 on error (if nSizeOut is
263
                 small returns 0 too).
264
    */
265
    size_t (*Decompress)(const GByte *pabyIn, GUInt32 nSizeIn, GByte *pabyOut,
266
                         GUInt32 nSizeOut, GUInt32 nTileSx,
267
                         GUInt32 nTileSy) = nullptr;
268
269
    /*!
270
        Tile compress callback
271
        pabyIn - input uncompressed data
272
        nSizeIn - input uncompressed data size (in bytes)
273
        pabyOut - pointer to compressed data
274
        nSizeOut - maximum compressed data size
275
        nTileSx - width of uncompressed tile (in pixels)
276
        nTileSy - height of uncompressed tile (in pixels)
277
        poDS - pointer to parent dataset
278
279
        Returns: actual compressed data size or 0 on error (if nSizeOut is
280
                 small returns 0 too).
281
    */
282
    size_t (*Compress)(const GByte *pabyIn, GUInt32 nSizeIn, GByte *pabyOut,
283
                       GUInt32 nSizeOut, GUInt32 nTileSx, GUInt32 nTileSy,
284
                       const RMFDataset *poDS) = nullptr;
285
286
    std::vector<RMFDataset *> poOvrDatasets{};
287
    vsi_l_offset nHeaderOffset = 0;
288
    RMFDataset *poParentDS = nullptr;
289
290
    RMFDataset(const RMFDataset &) = delete;
291
    RMFDataset &operator=(const RMFDataset &) = delete;
292
293
  public:
294
    RMFDataset();
295
    ~RMFDataset() override;
296
297
    static int Identify(GDALOpenInfo *poOpenInfo);
298
    static GDALDataset *Open(GDALOpenInfo *);
299
    static RMFDataset *Open(GDALOpenInfo *, RMFDataset *poParentDS,
300
                            vsi_l_offset nNextHeaderOffset);
301
    static GDALDataset *Create(const char *, int, int, int, GDALDataType,
302
                               CSLConstList);
303
    static GDALDataset *Create(const char *, int, int, int, GDALDataType,
304
                               CSLConstList, RMFDataset *poParentDS,
305
                               double dfOvFactor);
306
    CPLErr FlushCache(bool bAtClosing) override;
307
308
    CPLErr GetGeoTransform(GDALGeoTransform &gt) const override;
309
    CPLErr SetGeoTransform(const GDALGeoTransform &gt) override;
310
    const OGRSpatialReference *GetSpatialRef() const override;
311
    CPLErr SetSpatialRef(const OGRSpatialReference *poSRS) override;
312
313
    CPLErr IBuildOverviews(const char *pszResampling, int nOverviews,
314
                           const int *panOverviewList, int nBandsIn,
315
                           const int *panBandList, GDALProgressFunc pfnProgress,
316
                           void *pProgressData,
317
                           CSLConstList papszOptions) override;
318
    CPLErr IRasterIO(GDALRWFlag eRWFlag, int nXOff, int nYOff, int nXSize,
319
                     int nYSize, void *pData, int nBufXSize, int nBufYSize,
320
                     GDALDataType eBufType, int nBandCount,
321
                     BANDMAP_TYPE panBandMap, GSpacing nPixelSpace,
322
                     GSpacing nLineSpace, GSpacing nBandSpace,
323
                     GDALRasterIOExtraArg *psExtraArg) override;
324
    CPLErr SetMetadataItem(const char *pszName, const char *pszValue,
325
                           const char *pszDomain = "") override;
326
    CPLErr SetMetadata(CSLConstList papszMetadata,
327
                       const char *pszDomain = "") override;
328
    // cppcheck-suppress functionStatic
329
    vsi_l_offset GetFileOffset(GUInt32 iRMFOffset) const;
330
    GUInt32 GetRMFOffset(vsi_l_offset iFileOffset,
331
                         vsi_l_offset *piNewFileOffset) const;
332
    RMFDataset *OpenOverview(RMFDataset *poParentDS, GDALOpenInfo *);
333
    vsi_l_offset GetLastOffset() const;
334
    CPLErr CleanOverviews();
335
    static GByte GetCompressionType(const char *pszCompressName);
336
    int SetupCompression(GDALDataType eType, const char *pszFilename);
337
    static void WriteTileJobFunc(void *pData);
338
    CPLErr InitCompressorData(CSLConstList papszParamList);
339
    CPLErr WriteTile(int nBlockXOff, int nBlockYOff, GByte *pabyData,
340
                     size_t nBytes, GUInt32 nRawXSize, GUInt32 nRawYSize);
341
    CPLErr WriteRawTile(int nBlockXOff, int nBlockYOff, GByte *pabyData,
342
                        size_t nBytes);
343
    CPLErr ReadTile(int nBlockXOff, int nBlockYOff, GByte *pabyData,
344
                    size_t nBytes, GUInt32 nRawXSize, GUInt32 nRawYSize,
345
                    bool &bNullTile);
346
    void SetupNBits();
347
};
348
349
/************************************************************************/
350
/*                            RMFRasterBand                             */
351
/************************************************************************/
352
353
class RMFRasterBand final : public GDALRasterBand
354
{
355
    friend class RMFDataset;
356
357
  private:
358
    GUInt32 nBlockSize = 0;
359
    GUInt32 nBlockBytes = 0;
360
    GUInt32 nLastTileWidth = 0;
361
    GUInt32 nLastTileHeight = 0;
362
    GUInt32 nDataSize = 0;
363
364
  public:
365
    RMFRasterBand(RMFDataset *, int, GDALDataType);
366
    ~RMFRasterBand() override;
367
368
    CPLErr IReadBlock(int, int, void *) override;
369
    CPLErr IWriteBlock(int, int, void *) override;
370
    virtual GDALSuggestedBlockAccessPattern
371
    GetSuggestedBlockAccessPattern() const override;
372
    double GetNoDataValue(int *pbSuccess = nullptr) override;
373
    CPLErr SetNoDataValue(double dfNoData) override;
374
    const char *GetUnitType() override;
375
    GDALColorInterp GetColorInterpretation() override;
376
    GDALColorTable *GetColorTable() override;
377
    CPLErr SetUnitType(const char *) override;
378
    CPLErr SetColorTable(GDALColorTable *) override;
379
    int GetOverviewCount() override;
380
    GDALRasterBand *GetOverview(int i) override;
381
    CPLErr IRasterIO(GDALRWFlag eRWFlag, int nXOff, int nYOff, int nXSize,
382
                     int nYSize, void *pData, int nBufXSize, int nBufYSize,
383
                     GDALDataType eBufType, GSpacing nPixelSpace,
384
                     GSpacing nLineSpace,
385
                     GDALRasterIOExtraArg *psExtraArg) override;
386
};
387
388
#endif