Coverage Report

Created: 2026-09-26 08:22

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