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-06-08 21:14:40 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             : 
      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

Generated by: LCOV version 1.14