Line data Source code
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() override;
132 :
133 : static GDALDataset *Open(GDALOpenInfo *);
134 : static GDALDataset *CreateCopy(const char *pszFilename,
135 : GDALDataset *poSrcDS, int bStrict,
136 : char **papszOptions,
137 : GDALProgressFunc pfnProgress,
138 : void *pProgressData);
139 :
140 : char **GetFileList(void) override;
141 :
142 : CPLErr GetGeoTransform(GDALGeoTransform >) const override;
143 : CPLErr FlushCache(bool bAtClosing) override;
144 :
145 : char **GetMetadataDomainList() override;
146 :
147 : char **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 : #ifdef SUPPORT_CREATE
166 : int m_nBitDepth;
167 : GByte *m_pabyBuffer;
168 : png_byte *m_pabyAlpha;
169 : png_structp m_hPNG;
170 : png_infop m_psPNGInfo;
171 : png_color *m_pasPNGColors;
172 : VSILFILE *m_fpImage;
173 : int m_bGeoTransformValid;
174 : double m_adfGeoTransform[6];
175 : char *m_pszFilename;
176 : int m_nColorType; // PNG_COLOR_TYPE_*
177 :
178 : virtual CPLErr SetGeoTransform(double *);
179 : static GDALDataset *Create(const char *pszFilename, int nXSize, int nYSize,
180 : int nBands, GDALDataType, char **papszParamList);
181 :
182 : protected:
183 : CPLErr write_png_header();
184 :
185 : #endif
186 : };
187 :
188 : #ifdef _MSC_VER
189 : #pragma warning(pop)
190 : #endif
191 :
192 : /************************************************************************/
193 : /* ==================================================================== */
194 : /* PNGRasterBand */
195 : /* ==================================================================== */
196 : /************************************************************************/
197 :
198 : class PNGRasterBand final : public GDALPamRasterBand
199 : {
200 : friend class PNGDataset;
201 :
202 : public:
203 : PNGRasterBand(PNGDataset *, int);
204 :
205 : CPLErr IReadBlock(int, int, void *) override;
206 :
207 : virtual GDALSuggestedBlockAccessPattern
208 0 : GetSuggestedBlockAccessPattern() const override
209 : {
210 0 : return GSBAP_TOP_TO_BOTTOM;
211 : }
212 :
213 : GDALColorInterp GetColorInterpretation() override;
214 : GDALColorTable *GetColorTable() override;
215 : CPLErr SetNoDataValue(double dfNewValue) override;
216 : double GetNoDataValue(int *pbSuccess = nullptr) override;
217 :
218 : CPLErr IRasterIO(GDALRWFlag, int, int, int, int, void *, int, int,
219 : GDALDataType, GSpacing, GSpacing,
220 : GDALRasterIOExtraArg *psExtraArg) override;
221 :
222 : int bHaveNoData;
223 : double dfNoDataValue;
224 :
225 : #ifdef SUPPORT_CREATE
226 : virtual CPLErr SetColorTable(GDALColorTable *);
227 : CPLErr IWriteBlock(int, int, void *) override;
228 :
229 : protected:
230 : int m_bBandProvided[5];
231 :
232 : void reset_band_provision_flags()
233 : {
234 : PNGDataset &ds = *reinterpret_cast<PNGDataset *>(poDS);
235 :
236 : for (size_t i = 0; i < static_cast<size_t>(ds.nBands); i++)
237 : m_bBandProvided[i] = FALSE;
238 : }
239 : #endif
240 : };
|