LCOV - code coverage report
Current view: top level - frmts/pdf - pdfio.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 105 134 78.4 %
Date: 2024-05-04 12:52:34 Functions: 17 22 77.3 %

          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

Generated by: LCOV version 1.14