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 :
81 : #if POPPLER_MAJOR_VERSION > 25 || \
82 : (POPPLER_MAJOR_VERSION == 25 && POPPLER_MINOR_VERSION >= 5)
83 : std::unique_ptr<Stream> VSIPDFFileStream::makeSubStream(Goffset startA,
84 : bool limitedA,
85 : Goffset lengthA,
86 : Object &&dictA)
87 : {
88 : return std::make_unique<VSIPDFFileStream>(this, startA, limitedA, lengthA,
89 : std::move(dictA));
90 : }
91 : #else
92 7479 : Stream *VSIPDFFileStream::makeSubStream(Goffset startA, bool limitedA,
93 : Goffset lengthA, Object &&dictA)
94 : {
95 : return new VSIPDFFileStream(this, startA, limitedA, lengthA,
96 7479 : std::move(dictA));
97 : }
98 : #endif
99 :
100 : /************************************************************************/
101 : /* getPos() */
102 : /************************************************************************/
103 :
104 1406 : Goffset VSIPDFFileStream::getPos()
105 : {
106 1406 : return static_cast<Goffset>(nCurrentPos);
107 : }
108 :
109 : /************************************************************************/
110 : /* getStart() */
111 : /************************************************************************/
112 :
113 340 : Goffset VSIPDFFileStream::getStart()
114 : {
115 340 : return static_cast<Goffset>(nStart);
116 : }
117 :
118 : /************************************************************************/
119 : /* getKind() */
120 : /************************************************************************/
121 :
122 0 : StreamKind VSIPDFFileStream::getKind() const
123 : {
124 0 : return strFile;
125 : }
126 :
127 : /************************************************************************/
128 : /* getFileName() */
129 : /************************************************************************/
130 :
131 340 : GooString *VSIPDFFileStream::getFileName()
132 : {
133 340 : return poFilename;
134 : }
135 :
136 : /************************************************************************/
137 : /* FillBuffer() */
138 : /************************************************************************/
139 :
140 10633 : int VSIPDFFileStream::FillBuffer()
141 : {
142 10633 : if (nBufferLength == 0)
143 0 : return FALSE;
144 10633 : if (nBufferLength != -1 && nBufferLength < BUFFER_SIZE)
145 267 : return FALSE;
146 :
147 10366 : nPosInBuffer = 0;
148 : int nToRead;
149 10366 : if (!bLimited)
150 7839 : nToRead = BUFFER_SIZE;
151 2527 : else if (nCurrentPos + BUFFER_SIZE > nStart + nLength)
152 844 : nToRead = static_cast<int>(nStart + nLength - nCurrentPos);
153 : else
154 1683 : nToRead = BUFFER_SIZE;
155 10366 : if (nToRead < 0)
156 0 : return FALSE;
157 10366 : nBufferLength = static_cast<int>(VSIFReadL(abyBuffer, 1, nToRead, f));
158 10366 : if (nBufferLength == 0)
159 10 : return FALSE;
160 :
161 : // Since we now report a non-zero length (as BaseStream::length member),
162 : // PDFDoc::getPage() can go to the linearized mode if the file is
163 : // linearized, and thus create a pageCache. If so, in PDFDoc::~PDFDoc(), if
164 : // pageCache is not null, it would try to access the stream (str) through
165 : // getPageCount(), but we have just freed and nullify str before in
166 : // PDFFreeDoc(). So make as if the file is not linearized to avoid those
167 : // issues... All this is due to our attempt of avoiding cross-heap issues
168 : // with allocation and liberation of VSIPDFFileStream as PDFDoc::str member.
169 10356 : if (nCurrentPos == 0 || nCurrentPos == VSI_L_OFFSET_MAX)
170 : {
171 361696 : for (int i = 0;
172 361696 : i < nBufferLength - static_cast<int>(strlen("/Linearized ")); i++)
173 : {
174 361334 : if (memcmp(abyBuffer + i, "/Linearized ", strlen("/Linearized ")) ==
175 : 0)
176 : {
177 0 : bFoundLinearizedHint = true;
178 0 : memcpy(abyBuffer + i, "/XXXXXXXXXX ", strlen("/Linearized "));
179 0 : break;
180 : }
181 : }
182 : }
183 :
184 10356 : return TRUE;
185 : }
186 :
187 : /************************************************************************/
188 : /* getChar() */
189 : /************************************************************************/
190 :
191 : /* The unoptimized version performs a bit less since we must go through */
192 : /* the whole virtual I/O chain for each character reading. We save a few */
193 : /* percent with this extra internal caching */
194 :
195 2891400 : int VSIPDFFileStream::getChar()
196 : {
197 : #ifdef unoptimized_version
198 : GByte chRead;
199 : if (bLimited && nCurrentPos >= nStart + nLength)
200 : return EOF;
201 : if (VSIFReadL(&chRead, 1, 1, f) == 0)
202 : return EOF;
203 : #else
204 2891400 : if (nPosInBuffer == nBufferLength)
205 : {
206 10304 : if (!FillBuffer() || nPosInBuffer >= nBufferLength)
207 113 : return EOF;
208 : }
209 :
210 2891290 : GByte chRead = abyBuffer[nPosInBuffer];
211 2891290 : nPosInBuffer++;
212 : #endif
213 2891290 : nCurrentPos++;
214 2891290 : return chRead;
215 : }
216 :
217 : /************************************************************************/
218 : /* getUnfilteredChar() */
219 : /************************************************************************/
220 :
221 0 : int VSIPDFFileStream::getUnfilteredChar()
222 : {
223 0 : return getChar();
224 : }
225 :
226 : /************************************************************************/
227 : /* lookChar() */
228 : /************************************************************************/
229 :
230 0 : int VSIPDFFileStream::lookChar()
231 : {
232 : #ifdef unoptimized_version
233 : int nPosBefore = nCurrentPos;
234 : int chRead = getChar();
235 : if (chRead == EOF)
236 : return EOF;
237 : VSIFSeekL(f, nCurrentPos = nPosBefore, SEEK_SET);
238 : return chRead;
239 : #else
240 0 : int chRead = getChar();
241 0 : if (chRead == EOF)
242 0 : return EOF;
243 0 : nPosInBuffer--;
244 0 : nCurrentPos--;
245 0 : return chRead;
246 : #endif
247 : }
248 :
249 : /************************************************************************/
250 : /* reset() */
251 : /************************************************************************/
252 :
253 : #if POPPLER_MAJOR_VERSION > 25 || \
254 : (POPPLER_MAJOR_VERSION == 25 && POPPLER_MINOR_VERSION >= 2)
255 : bool VSIPDFFileStream::reset()
256 : #else
257 7439 : void VSIPDFFileStream::reset()
258 : #endif
259 : {
260 7439 : nSavedPos = VSIFTellL(f);
261 7439 : bHasSavedPos = TRUE;
262 7439 : VSIFSeekL(f, nCurrentPos = nStart, SEEK_SET);
263 7439 : nPosInBuffer = -1;
264 7439 : nBufferLength = -1;
265 : #if POPPLER_MAJOR_VERSION > 25 || \
266 : (POPPLER_MAJOR_VERSION == 25 && POPPLER_MINOR_VERSION >= 2)
267 : return true;
268 : #endif
269 7439 : }
270 :
271 : /************************************************************************/
272 : /* unfilteredReset() */
273 : /************************************************************************/
274 :
275 : #if POPPLER_MAJOR_VERSION > 25 || \
276 : (POPPLER_MAJOR_VERSION == 25 && POPPLER_MINOR_VERSION >= 3)
277 : bool VSIPDFFileStream::unfilteredReset()
278 : {
279 : return reset();
280 : }
281 : #else
282 0 : void VSIPDFFileStream::unfilteredReset()
283 : {
284 0 : reset();
285 0 : }
286 : #endif
287 :
288 : /************************************************************************/
289 : /* close() */
290 : /************************************************************************/
291 :
292 14060 : void VSIPDFFileStream::close()
293 : {
294 14060 : if (bHasSavedPos)
295 : {
296 6926 : nCurrentPos = nSavedPos;
297 6926 : VSIFSeekL(f, nCurrentPos, SEEK_SET);
298 : }
299 14060 : bHasSavedPos = FALSE;
300 14060 : nSavedPos = 0;
301 14060 : }
302 :
303 : /************************************************************************/
304 : /* setPos() */
305 : /************************************************************************/
306 :
307 1576 : void VSIPDFFileStream::setPos(Goffset pos, int dir)
308 : {
309 1576 : if (dir >= 0)
310 : {
311 1236 : VSIFSeekL(f, nCurrentPos = pos, SEEK_SET);
312 : }
313 : else
314 : {
315 340 : if (bLimited == false)
316 : {
317 340 : VSIFSeekL(f, 0, SEEK_END);
318 : }
319 : else
320 : {
321 0 : VSIFSeekL(f, nStart + nLength, SEEK_SET);
322 : }
323 340 : vsi_l_offset size = VSIFTellL(f);
324 340 : vsi_l_offset newpos = static_cast<vsi_l_offset>(pos);
325 340 : if (newpos > size)
326 22 : newpos = size;
327 340 : VSIFSeekL(f, nCurrentPos = size - newpos, SEEK_SET);
328 : }
329 1576 : nPosInBuffer = -1;
330 1576 : nBufferLength = -1;
331 1576 : }
332 :
333 : /************************************************************************/
334 : /* moveStart() */
335 : /************************************************************************/
336 :
337 170 : void VSIPDFFileStream::moveStart(Goffset delta)
338 : {
339 170 : nStart += delta;
340 170 : nCurrentPos = nStart;
341 170 : VSIFSeekL(f, nCurrentPos, SEEK_SET);
342 170 : nPosInBuffer = -1;
343 170 : nBufferLength = -1;
344 170 : }
345 :
346 : /************************************************************************/
347 : /* hasGetChars() */
348 : /************************************************************************/
349 :
350 734 : bool VSIPDFFileStream::hasGetChars()
351 : {
352 734 : return true;
353 : }
354 :
355 : /************************************************************************/
356 : /* getChars() */
357 : /************************************************************************/
358 :
359 734 : int VSIPDFFileStream::getChars(int nChars, unsigned char *buffer)
360 : {
361 734 : int nRead = 0;
362 1447 : while (nRead < nChars)
363 : {
364 877 : int nToRead = nChars - nRead;
365 877 : if (nPosInBuffer == nBufferLength)
366 : {
367 329 : if (!bLimited && nToRead > BUFFER_SIZE)
368 : {
369 : int nJustRead =
370 0 : static_cast<int>(VSIFReadL(buffer + nRead, 1, nToRead, f));
371 0 : nPosInBuffer = -1;
372 0 : nBufferLength = -1;
373 0 : nCurrentPos += nJustRead;
374 0 : nRead += nJustRead;
375 0 : break;
376 : }
377 329 : else if (!FillBuffer() || nPosInBuffer >= nBufferLength)
378 164 : break;
379 : }
380 713 : if (nToRead > nBufferLength - nPosInBuffer)
381 143 : nToRead = nBufferLength - nPosInBuffer;
382 :
383 713 : memcpy(buffer + nRead, abyBuffer + nPosInBuffer, nToRead);
384 713 : nPosInBuffer += nToRead;
385 713 : nCurrentPos += nToRead;
386 713 : nRead += nToRead;
387 : }
388 734 : return nRead;
389 : }
390 :
391 : #endif
|