Coverage Report

Created: 2026-06-30 08:33

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