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