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: 2024-11-21 22:18:42 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         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

Generated by: LCOV version 1.14