/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 |