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 : * Permission is hereby granted, free of charge, to any person obtaining a
11 : * copy of this software and associated documentation files (the "Software"),
12 : * to deal in the Software without restriction, including without limitation
13 : * the rights to use, copy, modify, merge, publish, distribute, sublicense,
14 : * and/or sell copies of the Software, and to permit persons to whom the
15 : * Software is furnished to do so, subject to the following conditions:
16 : *
17 : * The above copyright notice and this permission notice shall be included
18 : * in all copies or substantial portions of the Software.
19 : *
20 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
21 : * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22 : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
23 : * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24 : * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
25 : * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
26 : * DEALINGS IN THE SOFTWARE.
27 : ****************************************************************************/
28 :
29 : #include "gdal_pdf.h"
30 :
31 : #ifdef HAVE_POPPLER
32 :
33 : #include "pdfio.h"
34 :
35 : #include "cpl_vsi.h"
36 :
37 189 : static vsi_l_offset VSIPDFFileStreamGetSize(VSILFILE *f)
38 : {
39 189 : VSIFSeekL(f, 0, SEEK_END);
40 189 : vsi_l_offset nSize = VSIFTellL(f);
41 189 : VSIFSeekL(f, 0, SEEK_SET);
42 189 : return nSize;
43 : }
44 :
45 : /************************************************************************/
46 : /* VSIPDFFileStream() */
47 : /************************************************************************/
48 :
49 189 : VSIPDFFileStream::VSIPDFFileStream(VSILFILE *fIn, const char *pszFilename,
50 189 : Object &&dictA)
51 378 : : BaseStream(std::move(dictA), (Goffset)VSIPDFFileStreamGetSize(fIn)),
52 189 : poParent(nullptr), poFilename(new GooString(pszFilename)), f(fIn),
53 : nStart(0), bLimited(false), nLength(0), nCurrentPos(VSI_L_OFFSET_MAX),
54 189 : bHasSavedPos(FALSE), nSavedPos(0), nPosInBuffer(-1), nBufferLength(-1)
55 : {
56 189 : }
57 :
58 : /************************************************************************/
59 : /* VSIPDFFileStream() */
60 : /************************************************************************/
61 :
62 7775 : VSIPDFFileStream::VSIPDFFileStream(VSIPDFFileStream *poParentIn,
63 : vsi_l_offset startA, bool limitedA,
64 7775 : vsi_l_offset lengthA, Object &&dictA)
65 7775 : : BaseStream(std::move(dictA), (Goffset)lengthA), poParent(poParentIn),
66 7775 : poFilename(poParentIn->poFilename), f(poParentIn->f), nStart(startA),
67 : bLimited(limitedA), nLength(lengthA), nCurrentPos(VSI_L_OFFSET_MAX),
68 7775 : bHasSavedPos(FALSE), nSavedPos(0), nPosInBuffer(-1), nBufferLength(-1)
69 : {
70 7775 : }
71 :
72 : /************************************************************************/
73 : /* ~VSIPDFFileStream() */
74 : /************************************************************************/
75 :
76 15928 : VSIPDFFileStream::~VSIPDFFileStream()
77 : {
78 7964 : close();
79 7964 : if (poParent == nullptr)
80 : {
81 189 : delete poFilename;
82 : }
83 15928 : }
84 :
85 : /************************************************************************/
86 : /* copy() */
87 : /************************************************************************/
88 :
89 0 : BaseStream *VSIPDFFileStream::copy()
90 : {
91 0 : return new VSIPDFFileStream(poParent, nStart, bLimited, nLength,
92 0 : dict.copy());
93 : }
94 :
95 : /************************************************************************/
96 : /* makeSubStream() */
97 : /************************************************************************/
98 7775 : Stream *VSIPDFFileStream::makeSubStream(Goffset startA, bool limitedA,
99 : Goffset lengthA, Object &&dictA)
100 : {
101 : return new VSIPDFFileStream(this, startA, limitedA, lengthA,
102 7775 : std::move(dictA));
103 : }
104 :
105 : /************************************************************************/
106 : /* getPos() */
107 : /************************************************************************/
108 :
109 1430 : Goffset VSIPDFFileStream::getPos()
110 : {
111 1430 : return static_cast<Goffset>(nCurrentPos);
112 : }
113 :
114 : /************************************************************************/
115 : /* getStart() */
116 : /************************************************************************/
117 :
118 378 : Goffset VSIPDFFileStream::getStart()
119 : {
120 378 : return (Goffset)nStart;
121 : }
122 :
123 : /************************************************************************/
124 : /* getKind() */
125 : /************************************************************************/
126 :
127 0 : StreamKind VSIPDFFileStream::getKind() const
128 : {
129 0 : return strFile;
130 : }
131 :
132 : /************************************************************************/
133 : /* getFileName() */
134 : /************************************************************************/
135 :
136 378 : GooString *VSIPDFFileStream::getFileName()
137 : {
138 378 : return poFilename;
139 : }
140 :
141 : /************************************************************************/
142 : /* FillBuffer() */
143 : /************************************************************************/
144 :
145 10905 : int VSIPDFFileStream::FillBuffer()
146 : {
147 10905 : if (nBufferLength == 0)
148 0 : return FALSE;
149 10905 : if (nBufferLength != -1 && nBufferLength < BUFFER_SIZE)
150 191 : return FALSE;
151 :
152 10714 : nPosInBuffer = 0;
153 : int nToRead;
154 10714 : if (!bLimited)
155 8178 : nToRead = BUFFER_SIZE;
156 2536 : else if (nCurrentPos + BUFFER_SIZE > nStart + nLength)
157 853 : nToRead = (int)(nStart + nLength - nCurrentPos);
158 : else
159 1683 : nToRead = BUFFER_SIZE;
160 10714 : if (nToRead < 0)
161 0 : return FALSE;
162 10714 : nBufferLength = (int)VSIFReadL(abyBuffer, 1, nToRead, f);
163 10714 : if (nBufferLength == 0)
164 9 : return FALSE;
165 :
166 : // Since we now report a non-zero length (as BaseStream::length member),
167 : // PDFDoc::getPage() can go to the linearized mode if the file is
168 : // linearized, and thus create a pageCache. If so, in PDFDoc::~PDFDoc(), if
169 : // pageCache is not null, it would try to access the stream (str) through
170 : // getPageCount(), but we have just freed and nullify str before in
171 : // PDFFreeDoc(). So make as if the file is not linearized to avoid those
172 : // issues... All this is due to our attempt of avoiding cross-heap issues
173 : // with allocation and liberation of VSIPDFFileStream as PDFDoc::str member.
174 10705 : if (nCurrentPos == 0 || nCurrentPos == VSI_L_OFFSET_MAX)
175 : {
176 400190 : for (int i = 0; i < nBufferLength - (int)strlen("/Linearized "); i++)
177 : {
178 399790 : if (memcmp(abyBuffer + i, "/Linearized ", strlen("/Linearized ")) ==
179 : 0)
180 : {
181 0 : bFoundLinearizedHint = true;
182 0 : memcpy(abyBuffer + i, "/XXXXXXXXXX ", strlen("/Linearized "));
183 0 : break;
184 : }
185 : }
186 : }
187 :
188 10705 : return TRUE;
189 : }
190 :
191 : /************************************************************************/
192 : /* getChar() */
193 : /************************************************************************/
194 :
195 : /* The unoptimized version performs a bit less since we must go through */
196 : /* the whole virtual I/O chain for each character reading. We save a few */
197 : /* percent with this extra internal caching */
198 :
199 2968280 : int VSIPDFFileStream::getChar()
200 : {
201 : #ifdef unoptimized_version
202 : GByte chRead;
203 : if (bLimited && nCurrentPos >= nStart + nLength)
204 : return EOF;
205 : if (VSIFReadL(&chRead, 1, 1, f) == 0)
206 : return EOF;
207 : #else
208 2968280 : if (nPosInBuffer == nBufferLength)
209 : {
210 10691 : if (!FillBuffer() || nPosInBuffer >= nBufferLength)
211 113 : return EOF;
212 : }
213 :
214 2968160 : GByte chRead = abyBuffer[nPosInBuffer];
215 2968160 : nPosInBuffer++;
216 : #endif
217 2968160 : nCurrentPos++;
218 2968160 : return chRead;
219 : }
220 :
221 : /************************************************************************/
222 : /* getUnfilteredChar() */
223 : /************************************************************************/
224 :
225 0 : int VSIPDFFileStream::getUnfilteredChar()
226 : {
227 0 : return getChar();
228 : }
229 :
230 : /************************************************************************/
231 : /* lookChar() */
232 : /************************************************************************/
233 :
234 0 : int VSIPDFFileStream::lookChar()
235 : {
236 : #ifdef unoptimized_version
237 : int nPosBefore = nCurrentPos;
238 : int chRead = getChar();
239 : if (chRead == EOF)
240 : return EOF;
241 : VSIFSeekL(f, nCurrentPos = nPosBefore, SEEK_SET);
242 : return chRead;
243 : #else
244 0 : int chRead = getChar();
245 0 : if (chRead == EOF)
246 0 : return EOF;
247 0 : nPosInBuffer--;
248 0 : nCurrentPos--;
249 0 : return chRead;
250 : #endif
251 : }
252 :
253 : /************************************************************************/
254 : /* reset() */
255 : /************************************************************************/
256 :
257 7777 : void VSIPDFFileStream::reset()
258 : {
259 7777 : nSavedPos = VSIFTellL(f);
260 7777 : bHasSavedPos = TRUE;
261 7777 : VSIFSeekL(f, nCurrentPos = nStart, SEEK_SET);
262 7777 : nPosInBuffer = -1;
263 7777 : nBufferLength = -1;
264 7777 : }
265 :
266 : /************************************************************************/
267 : /* unfilteredReset() */
268 : /************************************************************************/
269 :
270 0 : void VSIPDFFileStream::unfilteredReset()
271 : {
272 0 : reset();
273 0 : }
274 :
275 : /************************************************************************/
276 : /* close() */
277 : /************************************************************************/
278 :
279 14674 : void VSIPDFFileStream::close()
280 : {
281 14674 : if (bHasSavedPos)
282 7229 : VSIFSeekL(f, nCurrentPos = nSavedPos, SEEK_SET);
283 14674 : bHasSavedPos = FALSE;
284 14674 : nSavedPos = 0;
285 14674 : }
286 :
287 : /************************************************************************/
288 : /* setPos() */
289 : /************************************************************************/
290 :
291 1619 : void VSIPDFFileStream::setPos(Goffset pos, int dir)
292 : {
293 1619 : if (dir >= 0)
294 : {
295 1241 : VSIFSeekL(f, nCurrentPos = pos, SEEK_SET);
296 : }
297 : else
298 : {
299 378 : if (bLimited == false)
300 : {
301 378 : VSIFSeekL(f, 0, SEEK_END);
302 : }
303 : else
304 : {
305 0 : VSIFSeekL(f, nStart + nLength, SEEK_SET);
306 : }
307 378 : vsi_l_offset size = VSIFTellL(f);
308 378 : vsi_l_offset newpos = (vsi_l_offset)pos;
309 378 : if (newpos > size)
310 22 : newpos = size;
311 378 : VSIFSeekL(f, nCurrentPos = size - newpos, SEEK_SET);
312 : }
313 1619 : nPosInBuffer = -1;
314 1619 : nBufferLength = -1;
315 1619 : }
316 :
317 : /************************************************************************/
318 : /* moveStart() */
319 : /************************************************************************/
320 :
321 189 : void VSIPDFFileStream::moveStart(Goffset delta)
322 : {
323 189 : nStart += delta;
324 189 : VSIFSeekL(f, nCurrentPos = nStart, SEEK_SET);
325 189 : nPosInBuffer = -1;
326 189 : nBufferLength = -1;
327 189 : }
328 :
329 : /************************************************************************/
330 : /* hasGetChars() */
331 : /************************************************************************/
332 :
333 657 : bool VSIPDFFileStream::hasGetChars()
334 : {
335 657 : return true;
336 : }
337 :
338 : /************************************************************************/
339 : /* getChars() */
340 : /************************************************************************/
341 :
342 657 : int VSIPDFFileStream::getChars(int nChars, unsigned char *buffer)
343 : {
344 657 : int nRead = 0;
345 1332 : while (nRead < nChars)
346 : {
347 762 : int nToRead = nChars - nRead;
348 762 : if (nPosInBuffer == nBufferLength)
349 : {
350 214 : if (!bLimited && nToRead > BUFFER_SIZE)
351 : {
352 0 : int nJustRead = (int)VSIFReadL(buffer + nRead, 1, nToRead, f);
353 0 : nPosInBuffer = -1;
354 0 : nBufferLength = -1;
355 0 : nCurrentPos += nJustRead;
356 0 : nRead += nJustRead;
357 0 : break;
358 : }
359 214 : else if (!FillBuffer() || nPosInBuffer >= nBufferLength)
360 87 : break;
361 : }
362 675 : if (nToRead > nBufferLength - nPosInBuffer)
363 105 : nToRead = nBufferLength - nPosInBuffer;
364 :
365 675 : memcpy(buffer + nRead, abyBuffer + nPosInBuffer, nToRead);
366 675 : nPosInBuffer += nToRead;
367 675 : nCurrentPos += nToRead;
368 675 : nRead += nToRead;
369 : }
370 657 : return nRead;
371 : }
372 :
373 : #endif
|