Line data Source code
1 : /******************************************************************************
2 : *
3 : * Project: PDF driver
4 : * Purpose: GDALDataset driver for PDF dataset.
5 : * Author: Even Rouault, <even dot rouault at spatialys.com>
6 : *
7 : ******************************************************************************
8 : * Copyright (c) 2010-2013, Even Rouault <even dot rouault at spatialys.com>
9 : *
10 : * SPDX-License-Identifier: MIT
11 : ****************************************************************************/
12 :
13 : #include "gdal_pdf.h"
14 :
15 : #ifdef HAVE_POPPLER
16 :
17 : #include "pdfio.h"
18 :
19 : #include "cpl_vsi.h"
20 :
21 170 : static vsi_l_offset VSIPDFFileStreamGetSize(VSILFILE *f)
22 : {
23 170 : VSIFSeekL(f, 0, SEEK_END);
24 170 : vsi_l_offset nSize = VSIFTellL(f);
25 170 : VSIFSeekL(f, 0, SEEK_SET);
26 170 : return nSize;
27 : }
28 :
29 : /************************************************************************/
30 : /* VSIPDFFileStream() */
31 : /************************************************************************/
32 :
33 170 : VSIPDFFileStream::VSIPDFFileStream(VSILFILE *fIn, const char *pszFilename,
34 170 : Object &&dictA)
35 170 : : BaseStream(std::move(dictA),
36 340 : static_cast<Goffset>(VSIPDFFileStreamGetSize(fIn))),
37 170 : poParent(nullptr), poFilename(new GooString(pszFilename)), f(fIn)
38 : {
39 170 : }
40 :
41 : /************************************************************************/
42 : /* VSIPDFFileStream() */
43 : /************************************************************************/
44 :
45 7479 : VSIPDFFileStream::VSIPDFFileStream(VSIPDFFileStream *poParentIn,
46 : vsi_l_offset startA, bool limitedA,
47 7479 : vsi_l_offset lengthA, Object &&dictA)
48 7479 : : BaseStream(std::move(dictA), static_cast<Goffset>(lengthA)),
49 7479 : poParent(poParentIn), poFilename(poParentIn->poFilename),
50 7479 : f(poParentIn->f), nStart(startA), bLimited(limitedA), nLength(lengthA)
51 : {
52 7479 : }
53 :
54 : /************************************************************************/
55 : /* ~VSIPDFFileStream() */
56 : /************************************************************************/
57 :
58 15298 : VSIPDFFileStream::~VSIPDFFileStream()
59 : {
60 7649 : close();
61 7649 : if (poParent == nullptr)
62 : {
63 170 : delete poFilename;
64 : }
65 15298 : }
66 :
67 : /************************************************************************/
68 : /* copy() */
69 : /************************************************************************/
70 :
71 0 : BaseStream *VSIPDFFileStream::copy()
72 : {
73 0 : return new VSIPDFFileStream(poParent, nStart, bLimited, nLength,
74 0 : dict.copy());
75 : }
76 :
77 : /************************************************************************/
78 : /* makeSubStream() */
79 : /************************************************************************/
80 7479 : Stream *VSIPDFFileStream::makeSubStream(Goffset startA, bool limitedA,
81 : Goffset lengthA, Object &&dictA)
82 : {
83 : return new VSIPDFFileStream(this, startA, limitedA, lengthA,
84 7479 : std::move(dictA));
85 : }
86 :
87 : /************************************************************************/
88 : /* getPos() */
89 : /************************************************************************/
90 :
91 1406 : Goffset VSIPDFFileStream::getPos()
92 : {
93 1406 : return static_cast<Goffset>(nCurrentPos);
94 : }
95 :
96 : /************************************************************************/
97 : /* getStart() */
98 : /************************************************************************/
99 :
100 340 : Goffset VSIPDFFileStream::getStart()
101 : {
102 340 : return static_cast<Goffset>(nStart);
103 : }
104 :
105 : /************************************************************************/
106 : /* getKind() */
107 : /************************************************************************/
108 :
109 0 : StreamKind VSIPDFFileStream::getKind() const
110 : {
111 0 : return strFile;
112 : }
113 :
114 : /************************************************************************/
115 : /* getFileName() */
116 : /************************************************************************/
117 :
118 340 : GooString *VSIPDFFileStream::getFileName()
119 : {
120 340 : return poFilename;
121 : }
122 :
123 : /************************************************************************/
124 : /* FillBuffer() */
125 : /************************************************************************/
126 :
127 10633 : int VSIPDFFileStream::FillBuffer()
128 : {
129 10633 : if (nBufferLength == 0)
130 0 : return FALSE;
131 10633 : if (nBufferLength != -1 && nBufferLength < BUFFER_SIZE)
132 267 : return FALSE;
133 :
134 10366 : nPosInBuffer = 0;
135 : int nToRead;
136 10366 : if (!bLimited)
137 7839 : nToRead = BUFFER_SIZE;
138 2527 : else if (nCurrentPos + BUFFER_SIZE > nStart + nLength)
139 844 : nToRead = static_cast<int>(nStart + nLength - nCurrentPos);
140 : else
141 1683 : nToRead = BUFFER_SIZE;
142 10366 : if (nToRead < 0)
143 0 : return FALSE;
144 10366 : nBufferLength = static_cast<int>(VSIFReadL(abyBuffer, 1, nToRead, f));
145 10366 : if (nBufferLength == 0)
146 10 : return FALSE;
147 :
148 : // Since we now report a non-zero length (as BaseStream::length member),
149 : // PDFDoc::getPage() can go to the linearized mode if the file is
150 : // linearized, and thus create a pageCache. If so, in PDFDoc::~PDFDoc(), if
151 : // pageCache is not null, it would try to access the stream (str) through
152 : // getPageCount(), but we have just freed and nullify str before in
153 : // PDFFreeDoc(). So make as if the file is not linearized to avoid those
154 : // issues... All this is due to our attempt of avoiding cross-heap issues
155 : // with allocation and liberation of VSIPDFFileStream as PDFDoc::str member.
156 10356 : if (nCurrentPos == 0 || nCurrentPos == VSI_L_OFFSET_MAX)
157 : {
158 361696 : for (int i = 0;
159 361696 : i < nBufferLength - static_cast<int>(strlen("/Linearized ")); i++)
160 : {
161 361334 : if (memcmp(abyBuffer + i, "/Linearized ", strlen("/Linearized ")) ==
162 : 0)
163 : {
164 0 : bFoundLinearizedHint = true;
165 0 : memcpy(abyBuffer + i, "/XXXXXXXXXX ", strlen("/Linearized "));
166 0 : break;
167 : }
168 : }
169 : }
170 :
171 10356 : return TRUE;
172 : }
173 :
174 : /************************************************************************/
175 : /* getChar() */
176 : /************************************************************************/
177 :
178 : /* The unoptimized version performs a bit less since we must go through */
179 : /* the whole virtual I/O chain for each character reading. We save a few */
180 : /* percent with this extra internal caching */
181 :
182 2891400 : int VSIPDFFileStream::getChar()
183 : {
184 : #ifdef unoptimized_version
185 : GByte chRead;
186 : if (bLimited && nCurrentPos >= nStart + nLength)
187 : return EOF;
188 : if (VSIFReadL(&chRead, 1, 1, f) == 0)
189 : return EOF;
190 : #else
191 2891400 : if (nPosInBuffer == nBufferLength)
192 : {
193 10304 : if (!FillBuffer() || nPosInBuffer >= nBufferLength)
194 113 : return EOF;
195 : }
196 :
197 2891290 : GByte chRead = abyBuffer[nPosInBuffer];
198 2891290 : nPosInBuffer++;
199 : #endif
200 2891290 : nCurrentPos++;
201 2891290 : return chRead;
202 : }
203 :
204 : /************************************************************************/
205 : /* getUnfilteredChar() */
206 : /************************************************************************/
207 :
208 0 : int VSIPDFFileStream::getUnfilteredChar()
209 : {
210 0 : return getChar();
211 : }
212 :
213 : /************************************************************************/
214 : /* lookChar() */
215 : /************************************************************************/
216 :
217 0 : int VSIPDFFileStream::lookChar()
218 : {
219 : #ifdef unoptimized_version
220 : int nPosBefore = nCurrentPos;
221 : int chRead = getChar();
222 : if (chRead == EOF)
223 : return EOF;
224 : VSIFSeekL(f, nCurrentPos = nPosBefore, SEEK_SET);
225 : return chRead;
226 : #else
227 0 : int chRead = getChar();
228 0 : if (chRead == EOF)
229 0 : return EOF;
230 0 : nPosInBuffer--;
231 0 : nCurrentPos--;
232 0 : return chRead;
233 : #endif
234 : }
235 :
236 : /************************************************************************/
237 : /* reset() */
238 : /************************************************************************/
239 :
240 : #if POPPLER_MAJOR_VERSION > 25 || \
241 : (POPPLER_MAJOR_VERSION == 25 && POPPLER_MINOR_VERSION >= 2)
242 : bool VSIPDFFileStream::reset()
243 : #else
244 7439 : void VSIPDFFileStream::reset()
245 : #endif
246 : {
247 7439 : nSavedPos = VSIFTellL(f);
248 7439 : bHasSavedPos = TRUE;
249 7439 : VSIFSeekL(f, nCurrentPos = nStart, SEEK_SET);
250 7439 : nPosInBuffer = -1;
251 7439 : nBufferLength = -1;
252 : #if POPPLER_MAJOR_VERSION > 25 || \
253 : (POPPLER_MAJOR_VERSION == 25 && POPPLER_MINOR_VERSION >= 2)
254 : return true;
255 : #endif
256 7439 : }
257 :
258 : /************************************************************************/
259 : /* unfilteredReset() */
260 : /************************************************************************/
261 :
262 : #if POPPLER_MAJOR_VERSION > 25 || \
263 : (POPPLER_MAJOR_VERSION == 25 && POPPLER_MINOR_VERSION > 2)
264 : bool VSIPDFFileStream::unfilteredReset()
265 : {
266 : return reset();
267 : }
268 : #else
269 0 : void VSIPDFFileStream::unfilteredReset()
270 : {
271 0 : reset();
272 0 : }
273 : #endif
274 :
275 : /************************************************************************/
276 : /* close() */
277 : /************************************************************************/
278 :
279 14060 : void VSIPDFFileStream::close()
280 : {
281 14060 : if (bHasSavedPos)
282 : {
283 6926 : nCurrentPos = nSavedPos;
284 6926 : VSIFSeekL(f, nCurrentPos, SEEK_SET);
285 : }
286 14060 : bHasSavedPos = FALSE;
287 14060 : nSavedPos = 0;
288 14060 : }
289 :
290 : /************************************************************************/
291 : /* setPos() */
292 : /************************************************************************/
293 :
294 1576 : void VSIPDFFileStream::setPos(Goffset pos, int dir)
295 : {
296 1576 : if (dir >= 0)
297 : {
298 1236 : VSIFSeekL(f, nCurrentPos = pos, SEEK_SET);
299 : }
300 : else
301 : {
302 340 : if (bLimited == false)
303 : {
304 340 : VSIFSeekL(f, 0, SEEK_END);
305 : }
306 : else
307 : {
308 0 : VSIFSeekL(f, nStart + nLength, SEEK_SET);
309 : }
310 340 : vsi_l_offset size = VSIFTellL(f);
311 340 : vsi_l_offset newpos = static_cast<vsi_l_offset>(pos);
312 340 : if (newpos > size)
313 22 : newpos = size;
314 340 : VSIFSeekL(f, nCurrentPos = size - newpos, SEEK_SET);
315 : }
316 1576 : nPosInBuffer = -1;
317 1576 : nBufferLength = -1;
318 1576 : }
319 :
320 : /************************************************************************/
321 : /* moveStart() */
322 : /************************************************************************/
323 :
324 170 : void VSIPDFFileStream::moveStart(Goffset delta)
325 : {
326 170 : nStart += delta;
327 170 : nCurrentPos = nStart;
328 170 : VSIFSeekL(f, nCurrentPos, SEEK_SET);
329 170 : nPosInBuffer = -1;
330 170 : nBufferLength = -1;
331 170 : }
332 :
333 : /************************************************************************/
334 : /* hasGetChars() */
335 : /************************************************************************/
336 :
337 734 : bool VSIPDFFileStream::hasGetChars()
338 : {
339 734 : return true;
340 : }
341 :
342 : /************************************************************************/
343 : /* getChars() */
344 : /************************************************************************/
345 :
346 734 : int VSIPDFFileStream::getChars(int nChars, unsigned char *buffer)
347 : {
348 734 : int nRead = 0;
349 1447 : while (nRead < nChars)
350 : {
351 877 : int nToRead = nChars - nRead;
352 877 : if (nPosInBuffer == nBufferLength)
353 : {
354 329 : if (!bLimited && nToRead > BUFFER_SIZE)
355 : {
356 : int nJustRead =
357 0 : static_cast<int>(VSIFReadL(buffer + nRead, 1, nToRead, f));
358 0 : nPosInBuffer = -1;
359 0 : nBufferLength = -1;
360 0 : nCurrentPos += nJustRead;
361 0 : nRead += nJustRead;
362 0 : break;
363 : }
364 329 : else if (!FillBuffer() || nPosInBuffer >= nBufferLength)
365 164 : break;
366 : }
367 713 : if (nToRead > nBufferLength - nPosInBuffer)
368 143 : nToRead = nBufferLength - nPosInBuffer;
369 :
370 713 : memcpy(buffer + nRead, abyBuffer + nPosInBuffer, nToRead);
371 713 : nPosInBuffer += nToRead;
372 713 : nCurrentPos += nToRead;
373 713 : nRead += nToRead;
374 : }
375 734 : return nRead;
376 : }
377 :
378 : #endif
|