LCOV - code coverage report
Current view: top level - frmts/pdf - pdfio.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 108 137 78.8 %
Date: 2025-02-20 10:14:44 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             :  * 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        7479 : Stream *VSIPDFFileStream::makeSubStream(Goffset startA, bool limitedA,
      81             :                                         Goffset lengthA, Object &&dictA)
      82             : {
      83             :     return new VSIPDFFileStream(this, startA, limitedA, lengthA,
      84        7479 :                                 std::move(dictA));
      85             : }
      86             : 
      87             : /************************************************************************/
      88             : /*                                 getPos()                             */
      89             : /************************************************************************/
      90             : 
      91        1406 : Goffset VSIPDFFileStream::getPos()
      92             : {
      93        1406 :     return static_cast<Goffset>(nCurrentPos);
      94             : }
      95             : 
      96             : /************************************************************************/
      97             : /*                                getStart()                            */
      98             : /************************************************************************/
      99             : 
     100         340 : Goffset VSIPDFFileStream::getStart()
     101             : {
     102         340 :     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         340 : GooString *VSIPDFFileStream::getFileName()
     119             : {
     120         340 :     return poFilename;
     121             : }
     122             : 
     123             : /************************************************************************/
     124             : /*                             FillBuffer()                             */
     125             : /************************************************************************/
     126             : 
     127       10633 : int VSIPDFFileStream::FillBuffer()
     128             : {
     129       10633 :     if (nBufferLength == 0)
     130           0 :         return FALSE;
     131       10633 :     if (nBufferLength != -1 && nBufferLength < BUFFER_SIZE)
     132         267 :         return FALSE;
     133             : 
     134       10366 :     nPosInBuffer = 0;
     135             :     int nToRead;
     136       10366 :     if (!bLimited)
     137        7839 :         nToRead = BUFFER_SIZE;
     138        2527 :     else if (nCurrentPos + BUFFER_SIZE > nStart + nLength)
     139         844 :         nToRead = static_cast<int>(nStart + nLength - nCurrentPos);
     140             :     else
     141        1683 :         nToRead = BUFFER_SIZE;
     142       10366 :     if (nToRead < 0)
     143           0 :         return FALSE;
     144       10366 :     nBufferLength = static_cast<int>(VSIFReadL(abyBuffer, 1, nToRead, f));
     145       10366 :     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       10356 :     if (nCurrentPos == 0 || nCurrentPos == VSI_L_OFFSET_MAX)
     157             :     {
     158      361696 :         for (int i = 0;
     159      361696 :              i < nBufferLength - static_cast<int>(strlen("/Linearized ")); i++)
     160             :         {
     161      361334 :             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       10356 :     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     2891400 : 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     2891400 :     if (nPosInBuffer == nBufferLength)
     192             :     {
     193       10304 :         if (!FillBuffer() || nPosInBuffer >= nBufferLength)
     194         113 :             return EOF;
     195             :     }
     196             : 
     197     2891290 :     GByte chRead = abyBuffer[nPosInBuffer];
     198     2891290 :     nPosInBuffer++;
     199             : #endif
     200     2891290 :     nCurrentPos++;
     201     2891290 :     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             : #if POPPLER_MAJOR_VERSION > 25 ||                                              \
     241             :     (POPPLER_MAJOR_VERSION == 25 && POPPLER_MINOR_VERSION >= 2)
     242             : bool VSIPDFFileStream::reset()
     243             : #else
     244        7439 : void VSIPDFFileStream::reset()
     245             : #endif
     246             : {
     247        7439 :     nSavedPos = VSIFTellL(f);
     248        7439 :     bHasSavedPos = TRUE;
     249        7439 :     VSIFSeekL(f, nCurrentPos = nStart, SEEK_SET);
     250        7439 :     nPosInBuffer = -1;
     251        7439 :     nBufferLength = -1;
     252             : #if POPPLER_MAJOR_VERSION > 25 ||                                              \
     253             :     (POPPLER_MAJOR_VERSION == 25 && POPPLER_MINOR_VERSION >= 2)
     254             :     return true;
     255             : #endif
     256        7439 : }
     257             : 
     258             : /************************************************************************/
     259             : /*                         unfilteredReset()                            */
     260             : /************************************************************************/
     261             : 
     262             : #if POPPLER_MAJOR_VERSION > 25 ||                                              \
     263             :     (POPPLER_MAJOR_VERSION == 25 && POPPLER_MINOR_VERSION > 2)
     264             : bool VSIPDFFileStream::unfilteredReset()
     265             : {
     266             :     return reset();
     267             : }
     268             : #else
     269           0 : void VSIPDFFileStream::unfilteredReset()
     270             : {
     271           0 :     reset();
     272           0 : }
     273             : #endif
     274             : 
     275             : /************************************************************************/
     276             : /*                                close()                               */
     277             : /************************************************************************/
     278             : 
     279       14060 : void VSIPDFFileStream::close()
     280             : {
     281       14060 :     if (bHasSavedPos)
     282             :     {
     283        6926 :         nCurrentPos = nSavedPos;
     284        6926 :         VSIFSeekL(f, nCurrentPos, SEEK_SET);
     285             :     }
     286       14060 :     bHasSavedPos = FALSE;
     287       14060 :     nSavedPos = 0;
     288       14060 : }
     289             : 
     290             : /************************************************************************/
     291             : /*                               setPos()                               */
     292             : /************************************************************************/
     293             : 
     294        1576 : void VSIPDFFileStream::setPos(Goffset pos, int dir)
     295             : {
     296        1576 :     if (dir >= 0)
     297             :     {
     298        1236 :         VSIFSeekL(f, nCurrentPos = pos, SEEK_SET);
     299             :     }
     300             :     else
     301             :     {
     302         340 :         if (bLimited == false)
     303             :         {
     304         340 :             VSIFSeekL(f, 0, SEEK_END);
     305             :         }
     306             :         else
     307             :         {
     308           0 :             VSIFSeekL(f, nStart + nLength, SEEK_SET);
     309             :         }
     310         340 :         vsi_l_offset size = VSIFTellL(f);
     311         340 :         vsi_l_offset newpos = static_cast<vsi_l_offset>(pos);
     312         340 :         if (newpos > size)
     313          22 :             newpos = size;
     314         340 :         VSIFSeekL(f, nCurrentPos = size - newpos, SEEK_SET);
     315             :     }
     316        1576 :     nPosInBuffer = -1;
     317        1576 :     nBufferLength = -1;
     318        1576 : }
     319             : 
     320             : /************************************************************************/
     321             : /*                            moveStart()                               */
     322             : /************************************************************************/
     323             : 
     324         170 : void VSIPDFFileStream::moveStart(Goffset delta)
     325             : {
     326         170 :     nStart += delta;
     327         170 :     nCurrentPos = nStart;
     328         170 :     VSIFSeekL(f, nCurrentPos, SEEK_SET);
     329         170 :     nPosInBuffer = -1;
     330         170 :     nBufferLength = -1;
     331         170 : }
     332             : 
     333             : /************************************************************************/
     334             : /*                          hasGetChars()                               */
     335             : /************************************************************************/
     336             : 
     337         734 : bool VSIPDFFileStream::hasGetChars()
     338             : {
     339         734 :     return true;
     340             : }
     341             : 
     342             : /************************************************************************/
     343             : /*                            getChars()                                */
     344             : /************************************************************************/
     345             : 
     346         734 : int VSIPDFFileStream::getChars(int nChars, unsigned char *buffer)
     347             : {
     348         734 :     int nRead = 0;
     349        1447 :     while (nRead < nChars)
     350             :     {
     351         877 :         int nToRead = nChars - nRead;
     352         877 :         if (nPosInBuffer == nBufferLength)
     353             :         {
     354         329 :             if (!bLimited && nToRead > BUFFER_SIZE)
     355             :             {
     356             :                 int nJustRead =
     357           0 :                     static_cast<int>(VSIFReadL(buffer + nRead, 1, nToRead, f));
     358           0 :                 nPosInBuffer = -1;
     359           0 :                 nBufferLength = -1;
     360           0 :                 nCurrentPos += nJustRead;
     361           0 :                 nRead += nJustRead;
     362           0 :                 break;
     363             :             }
     364         329 :             else if (!FillBuffer() || nPosInBuffer >= nBufferLength)
     365         164 :                 break;
     366             :         }
     367         713 :         if (nToRead > nBufferLength - nPosInBuffer)
     368         143 :             nToRead = nBufferLength - nPosInBuffer;
     369             : 
     370         713 :         memcpy(buffer + nRead, abyBuffer + nPosInBuffer, nToRead);
     371         713 :         nPosInBuffer += nToRead;
     372         713 :         nCurrentPos += nToRead;
     373         713 :         nRead += nToRead;
     374             :     }
     375         734 :     return nRead;
     376             : }
     377             : 
     378             : #endif

Generated by: LCOV version 1.14