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 192 : static vsi_l_offset VSIPDFFileStreamGetSize(VSILFILE *f)
22 : {
23 192 : VSIFSeekL(f, 0, SEEK_END);
24 192 : vsi_l_offset nSize = VSIFTellL(f);
25 192 : VSIFSeekL(f, 0, SEEK_SET);
26 192 : return nSize;
27 : }
28 :
29 : /************************************************************************/
30 : /* VSIPDFFileStream() */
31 : /************************************************************************/
32 :
33 192 : VSIPDFFileStream::VSIPDFFileStream(VSILFILE *fIn, const char *pszFilename,
34 192 : Object &&dictA)
35 192 : : BaseStream(std::move(dictA),
36 384 : static_cast<Goffset>(VSIPDFFileStreamGetSize(fIn))),
37 192 : poParent(nullptr), poFilename(new GooString(pszFilename)), f(fIn)
38 : {
39 192 : }
40 :
41 : /************************************************************************/
42 : /* VSIPDFFileStream() */
43 : /************************************************************************/
44 :
45 8075 : VSIPDFFileStream::VSIPDFFileStream(VSIPDFFileStream *poParentIn,
46 : vsi_l_offset startA, bool limitedA,
47 8075 : vsi_l_offset lengthA, Object &&dictA)
48 8075 : : BaseStream(std::move(dictA), static_cast<Goffset>(lengthA)),
49 8075 : poParent(poParentIn), poFilename(poParentIn->poFilename),
50 8075 : f(poParentIn->f), nStart(startA), bLimited(limitedA), nLength(lengthA)
51 : {
52 8075 : }
53 :
54 : /************************************************************************/
55 : /* ~VSIPDFFileStream() */
56 : /************************************************************************/
57 :
58 16534 : VSIPDFFileStream::~VSIPDFFileStream()
59 : {
60 8267 : close();
61 8267 : if (poParent == nullptr)
62 : {
63 192 : delete poFilename;
64 : }
65 16534 : }
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 8075 : Stream *VSIPDFFileStream::makeSubStream(Goffset startA, bool limitedA,
81 : Goffset lengthA, Object &&dictA)
82 : {
83 : return new VSIPDFFileStream(this, startA, limitedA, lengthA,
84 8075 : std::move(dictA));
85 : }
86 :
87 : /************************************************************************/
88 : /* getPos() */
89 : /************************************************************************/
90 :
91 1502 : Goffset VSIPDFFileStream::getPos()
92 : {
93 1502 : return static_cast<Goffset>(nCurrentPos);
94 : }
95 :
96 : /************************************************************************/
97 : /* getStart() */
98 : /************************************************************************/
99 :
100 384 : Goffset VSIPDFFileStream::getStart()
101 : {
102 384 : 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 384 : GooString *VSIPDFFileStream::getFileName()
119 : {
120 384 : return poFilename;
121 : }
122 :
123 : /************************************************************************/
124 : /* FillBuffer() */
125 : /************************************************************************/
126 :
127 11339 : int VSIPDFFileStream::FillBuffer()
128 : {
129 11339 : if (nBufferLength == 0)
130 0 : return FALSE;
131 11339 : if (nBufferLength != -1 && nBufferLength < BUFFER_SIZE)
132 275 : return FALSE;
133 :
134 11064 : nPosInBuffer = 0;
135 : int nToRead;
136 11064 : if (!bLimited)
137 8485 : nToRead = BUFFER_SIZE;
138 2579 : else if (nCurrentPos + BUFFER_SIZE > nStart + nLength)
139 896 : nToRead = static_cast<int>(nStart + nLength - nCurrentPos);
140 : else
141 1683 : nToRead = BUFFER_SIZE;
142 11064 : if (nToRead < 0)
143 0 : return FALSE;
144 11064 : nBufferLength = static_cast<int>(VSIFReadL(abyBuffer, 1, nToRead, f));
145 11064 : 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 11054 : if (nCurrentPos == 0 || nCurrentPos == VSI_L_OFFSET_MAX)
157 : {
158 406268 : for (int i = 0;
159 406268 : i < nBufferLength - static_cast<int>(strlen("/Linearized ")); i++)
160 : {
161 405862 : 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 11054 : 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 3005350 : 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 3005350 : if (nPosInBuffer == nBufferLength)
192 : {
193 10998 : if (!FillBuffer() || nPosInBuffer >= nBufferLength)
194 113 : return EOF;
195 : }
196 :
197 3005230 : GByte chRead = abyBuffer[nPosInBuffer];
198 3005230 : nPosInBuffer++;
199 : #endif
200 3005230 : nCurrentPos++;
201 3005230 : 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 8057 : void VSIPDFFileStream::reset()
241 : {
242 8057 : nSavedPos = VSIFTellL(f);
243 8057 : bHasSavedPos = TRUE;
244 8057 : VSIFSeekL(f, nCurrentPos = nStart, SEEK_SET);
245 8057 : nPosInBuffer = -1;
246 8057 : nBufferLength = -1;
247 8057 : }
248 :
249 : /************************************************************************/
250 : /* unfilteredReset() */
251 : /************************************************************************/
252 :
253 0 : void VSIPDFFileStream::unfilteredReset()
254 : {
255 0 : reset();
256 0 : }
257 :
258 : /************************************************************************/
259 : /* close() */
260 : /************************************************************************/
261 :
262 15208 : void VSIPDFFileStream::close()
263 : {
264 15208 : if (bHasSavedPos)
265 : {
266 7500 : nCurrentPos = nSavedPos;
267 7500 : VSIFSeekL(f, nCurrentPos, SEEK_SET);
268 : }
269 15208 : bHasSavedPos = FALSE;
270 15208 : nSavedPos = 0;
271 15208 : }
272 :
273 : /************************************************************************/
274 : /* setPos() */
275 : /************************************************************************/
276 :
277 1694 : void VSIPDFFileStream::setPos(Goffset pos, int dir)
278 : {
279 1694 : if (dir >= 0)
280 : {
281 1310 : VSIFSeekL(f, nCurrentPos = pos, SEEK_SET);
282 : }
283 : else
284 : {
285 384 : if (bLimited == false)
286 : {
287 384 : VSIFSeekL(f, 0, SEEK_END);
288 : }
289 : else
290 : {
291 0 : VSIFSeekL(f, nStart + nLength, SEEK_SET);
292 : }
293 384 : vsi_l_offset size = VSIFTellL(f);
294 384 : vsi_l_offset newpos = static_cast<vsi_l_offset>(pos);
295 384 : if (newpos > size)
296 22 : newpos = size;
297 384 : VSIFSeekL(f, nCurrentPos = size - newpos, SEEK_SET);
298 : }
299 1694 : nPosInBuffer = -1;
300 1694 : nBufferLength = -1;
301 1694 : }
302 :
303 : /************************************************************************/
304 : /* moveStart() */
305 : /************************************************************************/
306 :
307 192 : void VSIPDFFileStream::moveStart(Goffset delta)
308 : {
309 192 : nStart += delta;
310 192 : nCurrentPos = nStart;
311 192 : VSIFSeekL(f, nCurrentPos, SEEK_SET);
312 192 : nPosInBuffer = -1;
313 192 : nBufferLength = -1;
314 192 : }
315 :
316 : /************************************************************************/
317 : /* hasGetChars() */
318 : /************************************************************************/
319 :
320 742 : bool VSIPDFFileStream::hasGetChars()
321 : {
322 742 : return true;
323 : }
324 :
325 : /************************************************************************/
326 : /* getChars() */
327 : /************************************************************************/
328 :
329 742 : int VSIPDFFileStream::getChars(int nChars, unsigned char *buffer)
330 : {
331 742 : int nRead = 0;
332 1459 : while (nRead < nChars)
333 : {
334 889 : int nToRead = nChars - nRead;
335 889 : if (nPosInBuffer == nBufferLength)
336 : {
337 341 : if (!bLimited && nToRead > BUFFER_SIZE)
338 : {
339 : int nJustRead =
340 0 : static_cast<int>(VSIFReadL(buffer + nRead, 1, nToRead, f));
341 0 : nPosInBuffer = -1;
342 0 : nBufferLength = -1;
343 0 : nCurrentPos += nJustRead;
344 0 : nRead += nJustRead;
345 0 : break;
346 : }
347 341 : else if (!FillBuffer() || nPosInBuffer >= nBufferLength)
348 172 : break;
349 : }
350 717 : if (nToRead > nBufferLength - nPosInBuffer)
351 147 : nToRead = nBufferLength - nPosInBuffer;
352 :
353 717 : memcpy(buffer + nRead, abyBuffer + nPosInBuffer, nToRead);
354 717 : nPosInBuffer += nToRead;
355 717 : nCurrentPos += nToRead;
356 717 : nRead += nToRead;
357 : }
358 742 : return nRead;
359 : }
360 :
361 : #endif
|