Coverage Report

Created: 2025-07-23 09:13

/src/gdal/frmts/jpeg/jpegdrivercore.cpp
Line
Count
Source (jump to first uncovered line)
1
/******************************************************************************
2
 *
3
 * Project:  JPEG JFIF Driver
4
 * Purpose:  Implement GDAL JPEG Support based on IJG libjpeg.
5
 * Author:   Frank Warmerdam, warmerdam@pobox.com
6
 *
7
 ******************************************************************************
8
 * Copyright (c) 2000, Frank Warmerdam
9
 * Copyright (c) 2007-2014, Even Rouault <even dot rouault at spatialys.com>
10
 *
11
 * Portions Copyright (c) Her majesty the Queen in right of Canada as
12
 * represented by the Minister of National Defence, 2006.
13
 *
14
 * SPDX-License-Identifier: MIT
15
 ****************************************************************************/
16
17
#include "jpegdrivercore.h"
18
19
// So that D_LOSSLESS_SUPPORTED is visible if defined in jmorecfg of libjpeg-turbo >= 2.2
20
#define JPEG_INTERNAL_OPTIONS
21
#include "jpeglib.h"
22
23
/************************************************************************/
24
/*                    JPEGDatasetIsJPEGLS()                             */
25
/************************************************************************/
26
27
bool JPEGDatasetIsJPEGLS(GDALOpenInfo *poOpenInfo)
28
29
1.42k
{
30
1.42k
    GByte *pabyHeader = poOpenInfo->pabyHeader;
31
1.42k
    int nHeaderBytes = poOpenInfo->nHeaderBytes;
32
33
1.42k
    if (nHeaderBytes < 10)
34
0
        return false;
35
36
1.42k
    if (pabyHeader[0] != 0xff || pabyHeader[1] != 0xd8)
37
0
        return false;
38
39
4.08k
    for (int nOffset = 2; nOffset + 4 < nHeaderBytes;)
40
3.50k
    {
41
3.50k
        if (pabyHeader[nOffset] != 0xFF)
42
669
            return false;
43
44
2.83k
        int nMarker = pabyHeader[nOffset + 1];
45
2.83k
        if (nMarker == 0xDA)
46
156
            return false;
47
48
2.67k
        if (nMarker == 0xF7)  // JPEG Extension 7, JPEG-LS.
49
8
            return true;
50
2.67k
        if (nMarker == 0xF8)  // JPEG Extension 8, JPEG-LS Extension.
51
0
            return true;
52
2.67k
        if (nMarker == 0xC3)  // Start of Frame 3 (Lossless Huffman)
53
3
            return true;
54
2.66k
        if (nMarker ==
55
2.66k
            0xC7)  // Start of Frame 7 (Differential Lossless Huffman)
56
0
            return true;
57
2.66k
        if (nMarker == 0xCB)  // Start of Frame 11 (Lossless Arithmetic)
58
0
            return true;
59
2.66k
        if (nMarker ==
60
2.66k
            0xCF)  // Start of Frame 15 (Differential Lossless Arithmetic)
61
0
            return true;
62
63
2.66k
        nOffset += 2 + pabyHeader[nOffset + 2] * 256 + pabyHeader[nOffset + 3];
64
2.66k
    }
65
66
584
    return false;
67
1.42k
}
68
69
/************************************************************************/
70
/*                     JPEGDriverIdentify()                             */
71
/************************************************************************/
72
73
int JPEGDriverIdentify(GDALOpenInfo *poOpenInfo)
74
75
604k
{
76
    // If it is a subfile, read the JPEG header.
77
604k
    if (STARTS_WITH_CI(poOpenInfo->pszFilename, "JPEG_SUBFILE:"))
78
28
        return TRUE;
79
604k
    if (STARTS_WITH(poOpenInfo->pszFilename, "JPEG:"))
80
0
        return TRUE;
81
82
    // First we check to see if the file has the expected header bytes.
83
604k
    const int nHeaderBytes = poOpenInfo->nHeaderBytes;
84
85
604k
    if (nHeaderBytes < 10)
86
511k
        return FALSE;
87
88
93.4k
    GByte *const pabyHeader = poOpenInfo->pabyHeader;
89
93.4k
    if (pabyHeader[0] != 0xff || pabyHeader[1] != 0xd8 || pabyHeader[2] != 0xff)
90
92.0k
        return FALSE;
91
92
        // libjpeg-turbo >= 2.2 supports lossless mode
93
1.42k
#if !defined(D_LOSSLESS_SUPPORTED)
94
1.42k
    if (JPEGDatasetIsJPEGLS(poOpenInfo))
95
11
    {
96
11
        return FALSE;
97
11
    }
98
1.40k
#endif
99
100
    // Some files like
101
    // http://dionecanali.hd.free.fr/~mdione/mapzen/N65E039.hgt.gz could be
102
    // mis-identfied as JPEG
103
1.40k
    CPLString osFilenameLower = CPLString(poOpenInfo->pszFilename).tolower();
104
1.40k
    if (osFilenameLower.endsWith(".hgt") ||
105
1.40k
        osFilenameLower.endsWith(".hgt.gz") ||
106
1.40k
        osFilenameLower.endsWith(".hgt.zip"))
107
0
    {
108
0
        return FALSE;
109
0
    }
110
111
1.40k
    return TRUE;
112
1.40k
}
113
114
/************************************************************************/
115
/*                     JPEGDriverSetCommonMetadata()                    */
116
/************************************************************************/
117
118
void JPEGDriverSetCommonMetadata(GDALDriver *poDriver)
119
22
{
120
22
    poDriver->SetDescription(DRIVER_NAME);
121
22
    poDriver->SetMetadataItem(GDAL_DCAP_RASTER, "YES");
122
22
    poDriver->SetMetadataItem(GDAL_DMD_LONGNAME, "JPEG JFIF");
123
22
    poDriver->SetMetadataItem(GDAL_DMD_HELPTOPIC, "drivers/raster/jpeg.html");
124
22
    poDriver->SetMetadataItem(GDAL_DMD_EXTENSION, "jpg");
125
22
    poDriver->SetMetadataItem(GDAL_DMD_EXTENSIONS, "jpg jpeg");
126
22
    poDriver->SetMetadataItem(GDAL_DMD_MIMETYPE, "image/jpeg");
127
128
22
#if defined(JPEG_LIB_MK1_OR_12BIT) || defined(JPEG_DUAL_MODE_8_12)
129
22
    poDriver->SetMetadataItem(GDAL_DMD_CREATIONDATATYPES, "Byte UInt16");
130
#else
131
    poDriver->SetMetadataItem(GDAL_DMD_CREATIONDATATYPES, "Byte");
132
#endif
133
22
    poDriver->SetMetadataItem(GDAL_DCAP_VIRTUALIO, "YES");
134
135
22
    const char *pszOpenOptions =
136
22
        "<OpenOptionList>\n"
137
22
        "   <Option name='USE_INTERNAL_OVERVIEWS' type='boolean' "
138
22
        "description='whether to use implicit internal overviews' "
139
22
        "default='YES'/>\n"
140
22
        "   <Option name='APPLY_ORIENTATION' type='boolean' "
141
22
        "description='whether to take into account EXIF Orientation to "
142
22
        "rotate/flip the image' default='NO'/>\n"
143
22
        "</OpenOptionList>\n";
144
22
    poDriver->SetMetadataItem(GDAL_DMD_OPENOPTIONLIST, pszOpenOptions);
145
146
#ifdef D_LOSSLESS_SUPPORTED
147
    // For autotest purposes
148
    poDriver->SetMetadataItem("LOSSLESS_JPEG_SUPPORTED", "YES", "JPEG");
149
#endif
150
151
22
    poDriver->pfnIdentify = JPEGDriverIdentify;
152
22
    poDriver->SetMetadataItem(GDAL_DCAP_OPEN, "YES");
153
22
    poDriver->SetMetadataItem(GDAL_DCAP_CREATECOPY, "YES");
154
22
}
155
156
/************************************************************************/
157
/*                    DeclareDeferredJPEGPlugin()                       */
158
/************************************************************************/
159
160
#ifdef PLUGIN_FILENAME
161
void DeclareDeferredJPEGPlugin()
162
{
163
    if (GDALGetDriverByName(DRIVER_NAME) != nullptr)
164
    {
165
        return;
166
    }
167
    auto poDriver = new GDALPluginDriverProxy(PLUGIN_FILENAME);
168
#ifdef PLUGIN_INSTALLATION_MESSAGE
169
    poDriver->SetMetadataItem(GDAL_DMD_PLUGIN_INSTALLATION_MESSAGE,
170
                              PLUGIN_INSTALLATION_MESSAGE);
171
#endif
172
    JPEGDriverSetCommonMetadata(poDriver);
173
    GetGDALDriverManager()->DeclareDeferredPluginDriver(poDriver);
174
}
175
#endif