Coverage Report

Created: 2025-06-09 07:02

/src/gdal/frmts/rmf/rmfdataset.h
Line
Count
Source (jump to first uncovered line)
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
426
#define RMF_HEADER_SIZE 320
24
0
#define RMF_EXT_HEADER_SIZE 320
25
305
#define RMF_MIN_EXT_HEADER_SIZE (36 + 4)
26
238
#define RMF_MAX_EXT_HEADER_SIZE 1000000
27
28
455
#define RMF_COMPRESSION_NONE 0
29
149
#define RMF_COMPRESSION_LZW 1
30
6
#define RMF_COMPRESSION_JPEG 2
31
8
#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
12.5k
#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
492
#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
    std::array<double, 6> adfGeoTransform = {0, 1, 0, 0, 0, 1};
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
    virtual ~RMFDataset();
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
                               char **);
303
    static GDALDataset *Create(const char *, int, int, int, GDALDataType,
304
                               char **, RMFDataset *poParentDS,
305
                               double dfOvFactor);
306
    virtual CPLErr FlushCache(bool bAtClosing) override;
307
308
    virtual CPLErr GetGeoTransform(double *padfTransform) override;
309
    virtual CPLErr SetGeoTransform(double *) override;
310
    const OGRSpatialReference *GetSpatialRef() const override;
311
    CPLErr SetSpatialRef(const OGRSpatialReference *poSRS) override;
312
313
    virtual CPLErr IBuildOverviews(const char *pszResampling, int nOverviews,
314
                                   const int *panOverviewList, int nBandsIn,
315
                                   const int *panBandList,
316
                                   GDALProgressFunc pfnProgress,
317
                                   void *pProgressData,
318
                                   CSLConstList papszOptions) override;
319
    virtual CPLErr IRasterIO(GDALRWFlag eRWFlag, int nXOff, int nYOff,
320
                             int nXSize, int nYSize, void *pData, int nBufXSize,
321
                             int nBufYSize, GDALDataType eBufType,
322
                             int nBandCount, BANDMAP_TYPE panBandMap,
323
                             GSpacing nPixelSpace, GSpacing nLineSpace,
324
                             GSpacing nBandSpace,
325
                             GDALRasterIOExtraArg *psExtraArg) override;
326
    virtual CPLErr SetMetadataItem(const char *pszName, const char *pszValue,
327
                                   const char *pszDomain = "") override;
328
    virtual CPLErr SetMetadata(char **papszMetadata,
329
                               const char *pszDomain = "") override;
330
    // cppcheck-suppress functionStatic
331
    vsi_l_offset GetFileOffset(GUInt32 iRMFOffset) const;
332
    GUInt32 GetRMFOffset(vsi_l_offset iFileOffset,
333
                         vsi_l_offset *piNewFileOffset) const;
334
    RMFDataset *OpenOverview(RMFDataset *poParentDS, GDALOpenInfo *);
335
    vsi_l_offset GetLastOffset() const;
336
    CPLErr CleanOverviews();
337
    static GByte GetCompressionType(const char *pszCompressName);
338
    int SetupCompression(GDALDataType eType, const char *pszFilename);
339
    static void WriteTileJobFunc(void *pData);
340
    CPLErr InitCompressorData(char **papszParamList);
341
    CPLErr WriteTile(int nBlockXOff, int nBlockYOff, GByte *pabyData,
342
                     size_t nBytes, GUInt32 nRawXSize, GUInt32 nRawYSize);
343
    CPLErr WriteRawTile(int nBlockXOff, int nBlockYOff, GByte *pabyData,
344
                        size_t nBytes);
345
    CPLErr ReadTile(int nBlockXOff, int nBlockYOff, GByte *pabyData,
346
                    size_t nBytes, GUInt32 nRawXSize, GUInt32 nRawYSize,
347
                    bool &bNullTile);
348
    void SetupNBits();
349
};
350
351
/************************************************************************/
352
/*                            RMFRasterBand                             */
353
/************************************************************************/
354
355
class RMFRasterBand final : public GDALRasterBand
356
{
357
    friend class RMFDataset;
358
359
  private:
360
    GUInt32 nBlockSize = 0;
361
    GUInt32 nBlockBytes = 0;
362
    GUInt32 nLastTileWidth = 0;
363
    GUInt32 nLastTileHeight = 0;
364
    GUInt32 nDataSize = 0;
365
366
  public:
367
    RMFRasterBand(RMFDataset *, int, GDALDataType);
368
    virtual ~RMFRasterBand();
369
370
    virtual CPLErr IReadBlock(int, int, void *) override;
371
    virtual CPLErr IWriteBlock(int, int, void *) override;
372
    virtual GDALSuggestedBlockAccessPattern
373
    GetSuggestedBlockAccessPattern() const override;
374
    virtual double GetNoDataValue(int *pbSuccess = nullptr) override;
375
    virtual CPLErr SetNoDataValue(double dfNoData) override;
376
    virtual const char *GetUnitType() override;
377
    virtual GDALColorInterp GetColorInterpretation() override;
378
    virtual GDALColorTable *GetColorTable() override;
379
    virtual CPLErr SetUnitType(const char *) override;
380
    virtual CPLErr SetColorTable(GDALColorTable *) override;
381
    virtual int GetOverviewCount() override;
382
    virtual GDALRasterBand *GetOverview(int i) override;
383
    virtual CPLErr IRasterIO(GDALRWFlag eRWFlag, int nXOff, int nYOff,
384
                             int nXSize, int nYSize, void *pData, int nBufXSize,
385
                             int nBufYSize, GDALDataType eBufType,
386
                             GSpacing nPixelSpace, GSpacing nLineSpace,
387
                             GDALRasterIOExtraArg *psExtraArg) override;
388
};
389
390
#endif