Coverage Report

Created: 2025-06-09 07:42

/src/gdal/frmts/jpeg/jpgdataset.h
Line
Count
Source (jump to first uncovered line)
1
/******************************************************************************
2
 * $Id: jpgdataset.cpp 37340 2017-02-11 18:28:02Z goatbar
3
 *
4
 * Project:  JPEG JFIF Driver
5
 * Purpose:  Implement GDAL JPEG Support based on IJG libjpeg.
6
 * Author:   Frank Warmerdam, warmerdam@pobox.com
7
 *
8
 ******************************************************************************
9
 * Copyright (c) 2000, Frank Warmerdam
10
 * Copyright (c) 2007-2014, Even Rouault <even dot rouault at spatialys.com>
11
 *
12
 * Portions Copyright (c) Her majesty the Queen in right of Canada as
13
 * represented by the Minister of National Defence, 2006.
14
 *
15
 * SPDX-License-Identifier: MIT
16
 ****************************************************************************/
17
18
#include "cpl_port.h"
19
20
// TODO(schwehr): Run IWYU.
21
#include <cerrno>
22
#include <climits>
23
#include <cstddef>
24
#include <cstdio>
25
#include <cstdlib>
26
#include <cstring>
27
#if HAVE_FCNTL_H
28
#include <fcntl.h>
29
#endif
30
#include <setjmp.h>
31
32
#include <algorithm>
33
#include <mutex>
34
#include <string>
35
36
#include "cpl_conv.h"
37
#include "cpl_error.h"
38
#include "cpl_progress.h"
39
#include "cpl_string.h"
40
#include "cpl_vsi.h"
41
#include "gdal.h"
42
#include "gdal_frmts.h"
43
#include "gdal_pam.h"
44
#include "gdal_priv.h"
45
46
CPL_C_START
47
48
// So that D_LOSSLESS_SUPPORTED is visible if defined in jmorecfg of libjpeg-turbo >= 2.2
49
#define JPEG_INTERNAL_OPTIONS
50
51
#ifdef LIBJPEG_12_PATH
52
#include LIBJPEG_12_PATH
53
#else
54
#include "jpeglib.h"
55
#endif
56
CPL_C_END
57
#include "memdataset.h"
58
#include "vsidataio.h"
59
60
// TIFF header.
61
typedef struct
62
{
63
    GUInt16 tiff_magic;    // Magic number (defines byte order).
64
    GUInt16 tiff_version;  // TIFF version number.
65
    GUInt32 tiff_diroff;   // byte offset to first directory.
66
} TIFFHeader;
67
68
// Ok to use setjmp().
69
#ifdef _MSC_VER
70
#pragma warning(disable : 4611)
71
#endif
72
73
struct JPGDatasetOpenArgs
74
{
75
    const char *pszFilename = nullptr;
76
    VSILFILE *fpLin = nullptr;
77
    CSLConstList papszSiblingFiles = nullptr;
78
    int nScaleFactor = 1;
79
    bool bDoPAMInitialize = false;
80
    bool bUseInternalOverviews = false;
81
    bool bIsLossless = false;
82
};
83
84
class JPGDatasetCommon;
85
86
#if defined(JPEG_DUAL_MODE_8_12) && !defined(JPGDataset)
87
JPGDatasetCommon *JPEGDataset12Open(JPGDatasetOpenArgs *psArgs);
88
GDALDataset *JPEGDataset12CreateCopy(const char *pszFilename,
89
                                     GDALDataset *poSrcDS, int bStrict,
90
                                     char **papszOptions,
91
                                     GDALProgressFunc pfnProgress,
92
                                     void *pProgressData);
93
#endif
94
95
GDALRasterBand *JPGCreateBand(JPGDatasetCommon *poDS, int nBand);
96
97
typedef void (*my_jpeg_write_m_header)(void *cinfo, int marker,
98
                                       unsigned int datalen);
99
typedef void (*my_jpeg_write_m_byte)(void *cinfo, int val);
100
101
CPLErr JPGAppendMask(const char *pszJPGFilename, GDALRasterBand *poMask,
102
                     GDALProgressFunc pfnProgress, void *pProgressData);
103
void JPGAddEXIF(GDALDataType eWorkDT, GDALDataset *poSrcDS, char **papszOptions,
104
                void *cinfo, my_jpeg_write_m_header p_jpeg_write_m_header,
105
                my_jpeg_write_m_byte p_jpeg_write_m_byte,
106
                GDALDataset *(pCreateCopy)(const char *, GDALDataset *, int,
107
                                           char **,
108
                                           GDALProgressFunc pfnProgress,
109
                                           void *pProgressData));
110
void JPGAddICCProfile(void *pInfo, const char *pszICCProfile,
111
                      my_jpeg_write_m_header p_jpeg_write_m_header,
112
                      my_jpeg_write_m_byte p_jpeg_write_m_byte);
113
114
class GDALJPEGUserData
115
{
116
  public:
117
    jmp_buf setjmp_buffer;
118
    bool bNonFatalErrorEncountered = false;
119
    void (*p_previous_emit_message)(j_common_ptr cinfo,
120
                                    int msg_level) = nullptr;
121
    int nMaxScans;
122
123
    GDALJPEGUserData()
124
0
        : nMaxScans(atoi(
125
0
              CPLGetConfigOption("GDAL_JPEG_MAX_ALLOWED_SCAN_NUMBER", "100")))
126
0
    {
127
0
        memset(&setjmp_buffer, 0, sizeof(setjmp_buffer));
128
0
    }
Unexecuted instantiation: GDALJPEGUserData::GDALJPEGUserData()
Unexecuted instantiation: GDALJPEGUserData12::GDALJPEGUserData12()
129
};
130
131
/************************************************************************/
132
/* ==================================================================== */
133
/*                         JPGDatasetCommon                             */
134
/* ==================================================================== */
135
/************************************************************************/
136
137
class JPGRasterBand;
138
class JPGMaskBand;
139
140
class JPGDatasetCommon CPL_NON_FINAL : public GDALPamDataset
141
{
142
  protected:
143
    friend class JPGDataset;
144
    friend class JPGRasterBand;
145
    friend class JPGMaskBand;
146
147
    int nScaleFactor;
148
    bool bHasInitInternalOverviews;
149
    int nInternalOverviewsCurrent;
150
    int nInternalOverviewsToFree;
151
    GDALDataset **papoInternalOverviews;
152
    JPGDatasetCommon *poActiveDS = nullptr; /* only valid in parent DS */
153
    JPGDatasetCommon **ppoActiveDS =
154
        nullptr; /* &poActiveDS of poActiveDS from parentDS */
155
    void InitInternalOverviews();
156
    GDALDataset *InitEXIFOverview();
157
158
    mutable OGRSpatialReference m_oSRS{};
159
    bool bGeoTransformValid;
160
    double adfGeoTransform[6];
161
    std::vector<gdal::GCP> m_aoGCPs{};
162
163
    VSILFILE *m_fpImage;
164
    GUIntBig nSubfileOffset;
165
166
    int nLoadedScanline;
167
    GByte *m_pabyScanline;
168
169
    bool bHasReadEXIFMetadata;
170
    bool bHasReadXMPMetadata;
171
    bool bHasReadICCMetadata;
172
    bool bHasReadFLIRMetadata = false;
173
    bool bHasReadImageStructureMetadata = false;
174
    char **papszMetadata;
175
    int nExifOffset;
176
    int nInterOffset;
177
    int nGPSOffset;
178
    bool bSwabflag;
179
    int nTiffDirStart;
180
    int nTIFFHEADER;
181
    bool bHasDoneJpegCreateDecompress;
182
    bool bHasDoneJpegStartDecompress;
183
184
    int m_nSubdatasetCount = 0;
185
186
    // FLIR raw thermal image
187
    bool m_bRawThermalLittleEndian = false;
188
    int m_nRawThermalImageWidth = 0;
189
    int m_nRawThermalImageHeight = 0;
190
    std::vector<GByte> m_abyRawThermalImage{};
191
192
    virtual CPLErr LoadScanline(int, GByte *outBuffer = nullptr) = 0;
193
    virtual void StopDecompress() = 0;
194
    virtual CPLErr Restart() = 0;
195
196
    virtual int GetDataPrecision() = 0;
197
    virtual int GetOutColorSpace() = 0;
198
    virtual int GetJPEGColorSpace() = 0;
199
200
    bool EXIFInit(VSILFILE *);
201
    void ReadICCProfile();
202
203
    void CheckForMask();
204
    void DecompressMask();
205
206
    void LoadForMetadataDomain(const char *pszDomain);
207
208
    void ReadImageStructureMetadata();
209
    void ReadEXIFMetadata();
210
    void ReadXMPMetadata();
211
    void ReadFLIRMetadata();
212
    GDALDataset *OpenFLIRRawThermalImage();
213
214
    bool bHasCheckedForMask;
215
    JPGMaskBand *poMaskBand;
216
    GByte *pabyBitMask;
217
    bool bMaskLSBOrder;
218
219
    GByte *pabyCMask;
220
    int nCMaskSize;
221
222
    // Color space exposed by GDAL.  Not necessarily the in_color_space nor
223
    // the out_color_space of JPEG library.
224
    /*J_COLOR_SPACE*/ int eGDALColorSpace;
225
226
    bool bIsSubfile;
227
    bool bHasTriedLoadWorldFileOrTab;
228
    void LoadWorldFileOrTab();
229
    CPLString osWldFilename;
230
231
    virtual int CloseDependentDatasets() override;
232
233
    virtual CPLErr IBuildOverviews(const char *, int, const int *, int,
234
                                   const int *, GDALProgressFunc, void *,
235
                                   CSLConstList papszOptions) override;
236
237
  public:
238
    JPGDatasetCommon();
239
    virtual ~JPGDatasetCommon();
240
241
    virtual CPLErr IRasterIO(GDALRWFlag, int, int, int, int, void *, int, int,
242
                             GDALDataType, int, BANDMAP_TYPE,
243
                             GSpacing nPixelSpace, GSpacing nLineSpace,
244
                             GSpacing nBandSpace,
245
                             GDALRasterIOExtraArg *psExtraArg) override;
246
247
    virtual CPLErr GetGeoTransform(double *) override;
248
249
    virtual int GetGCPCount() override;
250
    const OGRSpatialReference *GetGCPSpatialRef() const override;
251
    virtual const GDAL_GCP *GetGCPs() override;
252
253
    const OGRSpatialReference *GetSpatialRef() const override;
254
255
    virtual char **GetMetadataDomainList() override;
256
    virtual char **GetMetadata(const char *pszDomain = "") override;
257
    virtual const char *GetMetadataItem(const char *pszName,
258
                                        const char *pszDomain = "") override;
259
260
    virtual char **GetFileList(void) override;
261
262
    virtual CPLErr FlushCache(bool bAtClosing) override;
263
264
    CPLStringList GetCompressionFormats(int nXOff, int nYOff, int nXSize,
265
                                        int nYSize, int nBandCount,
266
                                        const int *panBandList) override;
267
    CPLErr ReadCompressedData(const char *pszFormat, int nXOff, int nYOff,
268
                              int nXSize, int nYSize, int nBandCount,
269
                              const int *panBandList, void **ppBuffer,
270
                              size_t *pnBufferSize,
271
                              char **ppszDetailedFormat) override;
272
273
    static GDALDataset *Open(GDALOpenInfo *);
274
};
275
276
/************************************************************************/
277
/* ==================================================================== */
278
/*                              JPGDataset                              */
279
/* ==================================================================== */
280
/************************************************************************/
281
282
class JPGDataset final : public JPGDatasetCommon
283
{
284
    GDALJPEGUserData sUserData;
285
286
    bool ErrorOutOnNonFatalError();
287
288
    static void EmitMessage(j_common_ptr cinfo, int msg_level);
289
    static void ProgressMonitor(j_common_ptr cinfo);
290
291
    struct jpeg_decompress_struct sDInfo;
292
    struct jpeg_error_mgr sJErr;
293
    struct jpeg_progress_mgr sJProgress;
294
295
    virtual CPLErr LoadScanline(int, GByte *outBuffer) override;
296
    CPLErr StartDecompress();
297
    virtual void StopDecompress() override;
298
    virtual CPLErr Restart() override;
299
300
    virtual int GetDataPrecision() override
301
0
    {
302
0
        return sDInfo.data_precision;
303
0
    }
Unexecuted instantiation: JPGDataset::GetDataPrecision()
Unexecuted instantiation: JPGDataset12::GetDataPrecision()
304
305
    virtual int GetOutColorSpace() override
306
0
    {
307
0
        return sDInfo.out_color_space;
308
0
    }
Unexecuted instantiation: JPGDataset::GetOutColorSpace()
Unexecuted instantiation: JPGDataset12::GetOutColorSpace()
309
310
    virtual int GetJPEGColorSpace() override
311
0
    {
312
0
        return sDInfo.jpeg_color_space;
313
0
    }
Unexecuted instantiation: JPGDataset::GetJPEGColorSpace()
Unexecuted instantiation: JPGDataset12::GetJPEGColorSpace()
314
315
    int nQLevel;
316
#if !defined(JPGDataset)
317
    void LoadDefaultTables(int);
318
#endif
319
    void SetScaleNumAndDenom();
320
321
    static JPGDatasetCommon *OpenStage2(JPGDatasetOpenArgs *psArgs,
322
                                        JPGDataset *&poDS);
323
324
  public:
325
    JPGDataset();
326
    virtual ~JPGDataset();
327
328
    static JPGDatasetCommon *Open(JPGDatasetOpenArgs *psArgs);
329
    static GDALDataset *CreateCopy(const char *pszFilename,
330
                                   GDALDataset *poSrcDS, int bStrict,
331
                                   char **papszOptions,
332
                                   GDALProgressFunc pfnProgress,
333
                                   void *pProgressData);
334
    static GDALDataset *CreateCopyStage2(
335
        const char *pszFilename, GDALDataset *poSrcDS, char **papszOptions,
336
        GDALProgressFunc pfnProgress, void *pProgressData, VSILFILE *fpImage,
337
        GDALDataType eDT, int nQuality, bool bAppendMask,
338
        GDALJPEGUserData &sUserData, struct jpeg_compress_struct &sCInfo,
339
        struct jpeg_error_mgr &sJErr, GByte *&pabyScanline);
340
    static void ErrorExit(j_common_ptr cinfo);
341
    static void OutputMessage(j_common_ptr cinfo);
342
};
343
344
/************************************************************************/
345
/* ==================================================================== */
346
/*                            JPGRasterBand                             */
347
/* ==================================================================== */
348
/************************************************************************/
349
350
class JPGRasterBand final : public GDALPamRasterBand
351
{
352
    friend class JPGDatasetCommon;
353
354
    // We have to keep a pointer to the JPGDataset that this JPGRasterBand
355
    // belongs to. In some case, we may have this->poGDS != this->poDS
356
    // For example for a JPGRasterBand that is set to a NITFDataset.
357
    // In other words, this->poDS doesn't necessary point to a JPGDataset
358
    // See ticket #1807.
359
    JPGDatasetCommon *poGDS;
360
361
  public:
362
    JPGRasterBand(JPGDatasetCommon *, int);
363
364
    virtual ~JPGRasterBand()
365
0
    {
366
0
    }
367
368
    virtual CPLErr IReadBlock(int, int, void *) override;
369
    virtual GDALColorInterp GetColorInterpretation() override;
370
371
    virtual GDALSuggestedBlockAccessPattern
372
    GetSuggestedBlockAccessPattern() const override
373
0
    {
374
0
        return GSBAP_TOP_TO_BOTTOM;
375
0
    }
376
377
    virtual GDALRasterBand *GetMaskBand() override;
378
    virtual int GetMaskFlags() override;
379
380
    virtual GDALRasterBand *GetOverview(int i) override;
381
    virtual int GetOverviewCount() override;
382
};
383
384
#if !defined(JPGDataset)
385
386
/************************************************************************/
387
/* ==================================================================== */
388
/*                             JPGMaskBand                              */
389
/* ==================================================================== */
390
/************************************************************************/
391
392
class JPGMaskBand final : public GDALRasterBand
393
{
394
  protected:
395
    virtual CPLErr IReadBlock(int, int, void *) override;
396
397
  public:
398
    explicit JPGMaskBand(JPGDatasetCommon *poDS);
399
400
    virtual ~JPGMaskBand()
401
0
    {
402
0
    }
403
};
404
405
/************************************************************************/
406
/*                         GDALRegister_JPEG()                          */
407
/************************************************************************/
408
409
class GDALJPGDriver final : public GDALDriver
410
{
411
  public:
412
2
    GDALJPGDriver() = default;
413
414
    char **GetMetadata(const char *pszDomain = "") override;
415
    const char *GetMetadataItem(const char *pszName,
416
                                const char *pszDomain = "") override;
417
418
  private:
419
    std::mutex m_oMutex{};
420
    bool m_bMetadataInitialized = false;
421
    void InitializeMetadata();
422
};
423
424
#endif  // !defined(JPGDataset)