Coverage Report

Created: 2026-03-30 09:00

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/gdal/frmts/png/pngdataset.h
Line
Count
Source
1
/******************************************************************************
2
 *
3
 * Project:  PNG Driver
4
 * Purpose:  Implement GDAL PNG Support
5
 * Author:   Frank Warmerdam, warmerda@home.com
6
 *
7
 ******************************************************************************
8
 * Copyright (c) 2000, Frank Warmerdam
9
 * Copyright (c) 2007-2014, Even Rouault <even dot rouault at spatialys.com>
10
 *
11
 * SPDX-License-Identifier: MIT
12
 ******************************************************************************
13
 *
14
 * ISSUES:
15
 *  o CollectMetadata() will only capture TEXT chunks before the image
16
 *    data as the code is currently structured.
17
 *  o Interlaced images are read entirely into memory for use.  This is
18
 *    bad for large images.
19
 *  o Image reading is always strictly sequential.  Reading backwards will
20
 *    cause the file to be rewound, and access started again from the
21
 *    beginning.
22
 *  o 16 bit alpha values are not scaled by to eight bit.
23
 *
24
 */
25
26
#include "cpl_string.h"
27
#include "gdal_frmts.h"
28
#include "gdal_pam.h"
29
30
#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
31
// Disabled for now since currently this only works for libpng 1.2
32
// libpng 1.6 requires additional includes. See #6928
33
// #define DISABLE_CRC_CHECK
34
#endif
35
36
#ifdef DISABLE_CRC_CHECK
37
// Needs to be defined before including png.h
38
#define PNG_INTERNAL
39
#endif
40
41
#include "png.h"
42
43
#include <csetjmp>
44
45
#include <algorithm>
46
#include <array>
47
48
#ifdef _MSC_VER
49
#pragma warning(disable : 4611)
50
#endif
51
52
#ifdef USE_NEON_OPTIMIZATIONS
53
#define HAVE_SSE2
54
#include "include_sse2neon.h"
55
#elif defined(__SSE2__) || defined(_M_X64) ||                                  \
56
    (defined(_M_IX86_FP) && _M_IX86_FP >= 2)
57
#define HAVE_SSE2
58
#include <emmintrin.h>
59
#endif
60
61
#ifdef HAVE_SSE2
62
#define ENABLE_WHOLE_IMAGE_OPTIMIZATION
63
#endif
64
65
/************************************************************************/
66
/* ==================================================================== */
67
/*                              PNGDataset                              */
68
/* ==================================================================== */
69
/************************************************************************/
70
71
class PNGRasterBand;
72
73
#ifdef _MSC_VER
74
#pragma warning(push)
75
// 'PNGDataset': structure was padded due to __declspec(align()) at line where
76
// we use `jmp_buf`.
77
#pragma warning(disable : 4324)
78
#endif
79
80
class PNGDataset final : public GDALPamDataset
81
{
82
    friend class PNGRasterBand;
83
84
    VSILFILE *fpImage{};
85
    png_structp hPNG{};
86
    png_infop psPNGInfo{};
87
    int nBitDepth{8};
88
    int nColorType{};  // PNG_COLOR_TYPE_*
89
    int bInterlaced{};
90
91
    int nBufferStartLine{};
92
    int nBufferLines{};
93
    int nLastLineRead{-1};
94
    GByte *pabyBuffer{};
95
96
    std::unique_ptr<GDALColorTable> poColorTable{};
97
98
    int bGeoTransformValid{};
99
    GDALGeoTransform m_gt{};
100
101
    void CollectMetadata();
102
103
    int bHasReadXMPMetadata{};
104
    void CollectXMPMetadata();
105
106
    CPLErr LoadScanline(int);
107
    CPLErr LoadInterlacedChunk(int);
108
    void Restart();
109
110
    int bHasTriedLoadWorldFile{};
111
    void LoadWorldFile();
112
    CPLString osWldFilename{};
113
114
    int bHasReadICCMetadata{};
115
    void LoadICCProfile();
116
117
    bool m_bByteOrderIsLittleEndian = false;
118
    bool m_bHasRewind = false;
119
120
    static void WriteMetadataAsText(jmp_buf sSetJmpContext, png_structp hPNG,
121
                                    png_infop psPNGInfo, const char *pszKey,
122
                                    const char *pszValue);
123
    static GDALDataset *OpenStage2(GDALOpenInfo *, PNGDataset *&);
124
125
    CPL_DISALLOW_COPY_ASSIGN(PNGDataset)
126
127
  public:
128
    PNGDataset();
129
    ~PNGDataset() override;
130
131
    CPLErr Close(GDALProgressFunc = nullptr, void * = nullptr) override;
132
133
    static GDALDataset *Open(GDALOpenInfo *);
134
    static GDALDataset *CreateCopy(const char *pszFilename,
135
                                   GDALDataset *poSrcDS, int bStrict,
136
                                   CSLConstList papszOptions,
137
                                   GDALProgressFunc pfnProgress,
138
                                   void *pProgressData);
139
140
    char **GetFileList(void) override;
141
142
    CPLErr GetGeoTransform(GDALGeoTransform &gt) const override;
143
    CPLErr FlushCache(bool bAtClosing) override;
144
145
    char **GetMetadataDomainList() override;
146
147
    CSLConstList GetMetadata(const char *pszDomain = "") override;
148
    virtual const char *
149
    GetMetadataItem(const char *pszName,
150
                    const char *pszDomain = nullptr) override;
151
152
    CPLErr IRasterIO(GDALRWFlag, int, int, int, int, void *, int, int,
153
                     GDALDataType, int, BANDMAP_TYPE, GSpacing, GSpacing,
154
                     GSpacing, GDALRasterIOExtraArg *psExtraArg) override;
155
156
#ifdef ENABLE_WHOLE_IMAGE_OPTIMIZATION
157
    bool IsCompatibleOfSingleBlock() const;
158
    CPLErr LoadWholeImage(void *pSingleBuffer, GSpacing nPixelSpace,
159
                          GSpacing nLineSpace, GSpacing nBandSpace,
160
                          void *apabyBuffers[4]);
161
#endif
162
163
    jmp_buf sSetJmpContext{};  // Semi-private.
164
};
165
166
#ifdef _MSC_VER
167
#pragma warning(pop)
168
#endif
169
170
/************************************************************************/
171
/* ==================================================================== */
172
/*                            PNGRasterBand                             */
173
/* ==================================================================== */
174
/************************************************************************/
175
176
class PNGRasterBand final : public GDALPamRasterBand
177
{
178
    friend class PNGDataset;
179
180
  public:
181
    PNGRasterBand(PNGDataset *, int);
182
183
    CPLErr IReadBlock(int, int, void *) override;
184
185
    virtual GDALSuggestedBlockAccessPattern
186
    GetSuggestedBlockAccessPattern() const override
187
0
    {
188
0
        return GSBAP_TOP_TO_BOTTOM;
189
0
    }
190
191
    GDALColorInterp GetColorInterpretation() override;
192
    GDALColorTable *GetColorTable() override;
193
    CPLErr SetNoDataValue(double dfNewValue) override;
194
    double GetNoDataValue(int *pbSuccess = nullptr) override;
195
196
    CPLErr IRasterIO(GDALRWFlag, int, int, int, int, void *, int, int,
197
                     GDALDataType, GSpacing, GSpacing,
198
                     GDALRasterIOExtraArg *psExtraArg) override;
199
200
    int bHaveNoData;
201
    double dfNoDataValue;
202
203
#ifdef SUPPORT_CREATE
204
    virtual CPLErr SetColorTable(GDALColorTable *);
205
    CPLErr IWriteBlock(int, int, void *) override;
206
207
  protected:
208
    int m_bBandProvided[5];
209
210
    void reset_band_provision_flags()
211
    {
212
        PNGDataset &ds = *reinterpret_cast<PNGDataset *>(poDS);
213
214
        for (size_t i = 0; i < static_cast<size_t>(ds.nBands); i++)
215
            m_bBandProvided[i] = FALSE;
216
    }
217
#endif
218
};