Coverage Report

Created: 2026-02-14 09:00

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
2.01k
        : nMaxScans(atoi(
135
2.01k
              CPLGetConfigOption("GDAL_JPEG_MAX_ALLOWED_SCAN_NUMBER", "100")))
136
2.01k
    {
137
2.01k
        memset(&setjmp_buffer, 0, sizeof(setjmp_buffer));
138
2.01k
    }
GDALJPEGUserData::GDALJPEGUserData()
Line
Count
Source
134
1.20k
        : nMaxScans(atoi(
135
1.20k
              CPLGetConfigOption("GDAL_JPEG_MAX_ALLOWED_SCAN_NUMBER", "100")))
136
1.20k
    {
137
1.20k
        memset(&setjmp_buffer, 0, sizeof(setjmp_buffer));
138
1.20k
    }
GDALJPEGUserData12::GDALJPEGUserData12()
Line
Count
Source
134
812
        : nMaxScans(atoi(
135
812
              CPLGetConfigOption("GDAL_JPEG_MAX_ALLOWED_SCAN_NUMBER", "100")))
136
812
    {
137
812
        memset(&setjmp_buffer, 0, sizeof(setjmp_buffer));
138
812
    }
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
    CPL_DISALLOW_COPY_ASSIGN(JPGDatasetCommon)
257
258
  public:
259
    JPGDatasetCommon();
260
    ~JPGDatasetCommon() override;
261
262
    CPLErr Close(GDALProgressFunc = nullptr, void * = nullptr) override;
263
264
    CPLErr IRasterIO(GDALRWFlag, int, int, int, int, void *, int, int,
265
                     GDALDataType, int, BANDMAP_TYPE, GSpacing nPixelSpace,
266
                     GSpacing nLineSpace, GSpacing nBandSpace,
267
                     GDALRasterIOExtraArg *psExtraArg) override;
268
269
    CPLErr GetGeoTransform(GDALGeoTransform &gt) const override;
270
271
    int GetGCPCount() override;
272
    const OGRSpatialReference *GetGCPSpatialRef() const override;
273
    const GDAL_GCP *GetGCPs() override;
274
275
    const OGRSpatialReference *GetSpatialRef() const override;
276
277
    char **GetMetadataDomainList() override;
278
    CSLConstList GetMetadata(const char *pszDomain = "") override;
279
    virtual const char *GetMetadataItem(const char *pszName,
280
                                        const char *pszDomain = "") override;
281
282
    char **GetFileList(void) override;
283
284
    CPLErr FlushCache(bool bAtClosing) override;
285
286
    CPLStringList GetCompressionFormats(int nXOff, int nYOff, int nXSize,
287
                                        int nYSize, int nBandCount,
288
                                        const int *panBandList) override;
289
    CPLErr ReadCompressedData(const char *pszFormat, int nXOff, int nYOff,
290
                              int nXSize, int nYSize, int nBandCount,
291
                              const int *panBandList, void **ppBuffer,
292
                              size_t *pnBufferSize,
293
                              char **ppszDetailedFormat) override;
294
295
    static GDALDataset *Open(GDALOpenInfo *);
296
};
297
298
/************************************************************************/
299
/* ==================================================================== */
300
/*                              JPGDataset                              */
301
/* ==================================================================== */
302
/************************************************************************/
303
304
class JPGDataset final : public JPGDatasetCommon
305
{
306
    GDALJPEGUserData sUserData{};
307
308
    bool ErrorOutOnNonFatalError();
309
310
    static void EmitMessage(j_common_ptr cinfo, int msg_level);
311
    static void ProgressMonitor(j_common_ptr cinfo);
312
313
    struct jpeg_decompress_struct sDInfo{};
314
315
    struct jpeg_error_mgr sJErr{};
316
317
    struct jpeg_progress_mgr sJProgress{};
318
319
    CPLErr LoadScanline(int, GByte *outBuffer) override;
320
    CPLErr StartDecompress();
321
    void StopDecompress() override;
322
    CPLErr Restart() override;
323
324
    int GetDataPrecision() override
325
1.11k
    {
326
1.11k
        return sDInfo.data_precision;
327
1.11k
    }
JPGDataset::GetDataPrecision()
Line
Count
Source
325
780
    {
326
780
        return sDInfo.data_precision;
327
780
    }
JPGDataset12::GetDataPrecision()
Line
Count
Source
325
330
    {
326
330
        return sDInfo.data_precision;
327
330
    }
328
329
    int GetOutColorSpace() override
330
83.1k
    {
331
83.1k
        return sDInfo.out_color_space;
332
83.1k
    }
JPGDataset::GetOutColorSpace()
Line
Count
Source
330
65.3k
    {
331
65.3k
        return sDInfo.out_color_space;
332
65.3k
    }
JPGDataset12::GetOutColorSpace()
Line
Count
Source
330
17.7k
    {
331
17.7k
        return sDInfo.out_color_space;
332
17.7k
    }
333
334
    int GetJPEGColorSpace() override
335
0
    {
336
0
        return sDInfo.jpeg_color_space;
337
0
    }
Unexecuted instantiation: JPGDataset::GetJPEGColorSpace()
Unexecuted instantiation: JPGDataset12::GetJPEGColorSpace()
338
339
    int nQLevel = 0;
340
#if !defined(JPGDataset)
341
    void LoadDefaultTables(int);
342
#endif
343
    void SetScaleNumAndDenom();
344
345
    static JPGDatasetCommon *OpenStage2(JPGDatasetOpenArgs *psArgs,
346
                                        JPGDataset *&poDS);
347
348
  public:
349
    JPGDataset();
350
    ~JPGDataset() override;
351
352
    static JPGDatasetCommon *Open(JPGDatasetOpenArgs *psArgs);
353
    static GDALDataset *CreateCopy(const char *pszFilename,
354
                                   GDALDataset *poSrcDS, int bStrict,
355
                                   CSLConstList papszOptions,
356
                                   GDALProgressFunc pfnProgress,
357
                                   void *pProgressData);
358
    static GDALDataset *
359
    CreateCopyStage2(const char *pszFilename, GDALDataset *poSrcDS,
360
                     CSLConstList papszOptions, GDALProgressFunc pfnProgress,
361
                     void *pProgressData, VSIVirtualHandleUniquePtr fpImage,
362
                     GDALDataType eDT, int nQuality, bool bAppendMask,
363
                     GDALJPEGUserData &sUserData,
364
                     struct jpeg_compress_struct &sCInfo,
365
                     struct jpeg_error_mgr &sJErr, GByte *&pabyScanline);
366
    static void ErrorExit(j_common_ptr cinfo);
367
    static void OutputMessage(j_common_ptr cinfo);
368
};
369
370
/************************************************************************/
371
/* ==================================================================== */
372
/*                            JPGRasterBand                             */
373
/* ==================================================================== */
374
/************************************************************************/
375
376
class JPGRasterBand final : public GDALPamRasterBand
377
{
378
    friend class JPGDatasetCommon;
379
380
    // We have to keep a pointer to the JPGDataset that this JPGRasterBand
381
    // belongs to. In some case, we may have this->poGDS != this->poDS
382
    // For example for a JPGRasterBand that is set to a NITFDataset.
383
    // In other words, this->poDS doesn't necessary point to a JPGDataset
384
    // See ticket #1807.
385
    JPGDatasetCommon *poGDS{};
386
387
    CPL_DISALLOW_COPY_ASSIGN(JPGRasterBand)
388
389
  public:
390
    JPGRasterBand(JPGDatasetCommon *, int);
391
392
    CPLErr IReadBlock(int, int, void *) override;
393
    GDALColorInterp GetColorInterpretation() override;
394
395
    virtual GDALSuggestedBlockAccessPattern
396
    GetSuggestedBlockAccessPattern() const override
397
0
    {
398
0
        return GSBAP_TOP_TO_BOTTOM;
399
0
    }
400
401
    GDALRasterBand *GetMaskBand() override;
402
    int GetMaskFlags() override;
403
404
    GDALRasterBand *GetOverview(int i) override;
405
    int GetOverviewCount() override;
406
};
407
408
#if !defined(JPGDataset)
409
410
/************************************************************************/
411
/* ==================================================================== */
412
/*                             JPGMaskBand                              */
413
/* ==================================================================== */
414
/************************************************************************/
415
416
class JPGMaskBand final : public GDALRasterBand
417
{
418
  protected:
419
    CPLErr IReadBlock(int, int, void *) override;
420
421
  public:
422
    explicit JPGMaskBand(JPGDatasetCommon *poDS);
423
};
424
425
/************************************************************************/
426
/*                         GDALRegister_JPEG()                          */
427
/************************************************************************/
428
429
class GDALJPGDriver final : public GDALDriver
430
{
431
  public:
432
22
    GDALJPGDriver() = default;
433
434
    CSLConstList GetMetadata(const char *pszDomain = "") override;
435
    const char *GetMetadataItem(const char *pszName,
436
                                const char *pszDomain = "") override;
437
438
  private:
439
    std::recursive_mutex m_oMutex{};
440
    bool m_bMetadataInitialized = false;
441
    void InitializeMetadata();
442
};
443
444
#endif  // !defined(JPGDataset)