LCOV - code coverage report
Current view: top level - ogr/ogrsf_frmts/dxf - ogrdxfreader.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 116 120 96.7 %
Date: 2024-11-21 22:18:42 Functions: 8 8 100.0 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  DXF Translator
       4             :  * Purpose:  Implements low level DXF reading with caching and parsing of
       5             :  *           of the code/value pairs.
       6             :  * Author:   Frank Warmerdam, warmerdam@pobox.com
       7             :  *
       8             :  ******************************************************************************
       9             :  * Copyright (c) 2009, Frank Warmerdam <warmerdam@pobox.com>
      10             :  *
      11             :  * SPDX-License-Identifier: MIT
      12             :  ****************************************************************************/
      13             : 
      14             : #include "ogr_dxf.h"
      15             : #include "cpl_conv.h"
      16             : #include "cpl_string.h"
      17             : #include "cpl_csv.h"
      18             : 
      19             : /************************************************************************/
      20             : /*                            OGRDXFReader()                            */
      21             : /************************************************************************/
      22             : 
      23         281 : OGRDXFReader::OGRDXFReader()
      24             :     : fp(nullptr), iSrcBufferOffset(0), nSrcBufferBytes(0),
      25         281 :       iSrcBufferFileOffset(0), achSrcBuffer{}, nLastValueSize(0), nLineNumber(0)
      26             : {
      27         281 : }
      28             : 
      29             : /************************************************************************/
      30             : /*                           ~OGRDXFReader()                            */
      31             : /************************************************************************/
      32             : 
      33         281 : OGRDXFReader::~OGRDXFReader()
      34             : 
      35             : {
      36         281 : }
      37             : 
      38             : /************************************************************************/
      39             : /*                             Initialize()                             */
      40             : /************************************************************************/
      41             : 
      42         281 : void OGRDXFReader::Initialize(VSILFILE *fpIn)
      43             : 
      44             : {
      45         281 :     fp = fpIn;
      46         281 : }
      47             : 
      48             : /************************************************************************/
      49             : /*                          ResetReadPointer()                          */
      50             : /************************************************************************/
      51             : 
      52         202 : void OGRDXFReader::ResetReadPointer(unsigned int iNewOffset,
      53             :                                     int nNewLineNumber /* = 0 */)
      54             : 
      55             : {
      56         202 :     nSrcBufferBytes = 0;
      57         202 :     iSrcBufferOffset = 0;
      58         202 :     iSrcBufferFileOffset = iNewOffset;
      59         202 :     nLastValueSize = 0;
      60         202 :     nLineNumber = nNewLineNumber;
      61             : 
      62         202 :     VSIFSeekL(fp, iNewOffset, SEEK_SET);
      63         202 : }
      64             : 
      65             : /************************************************************************/
      66             : /*                           LoadDiskChunk()                            */
      67             : /*                                                                      */
      68             : /*      Load another block (512 bytes) of input from the source         */
      69             : /*      file.                                                           */
      70             : /************************************************************************/
      71             : 
      72       16599 : void OGRDXFReader::LoadDiskChunk()
      73             : 
      74             : {
      75       16599 :     if (nSrcBufferBytes - iSrcBufferOffset > 511)
      76           0 :         return;
      77             : 
      78       16599 :     if (iSrcBufferOffset > 0)
      79             :     {
      80       16055 :         CPLAssert(nSrcBufferBytes <= 1024);
      81       16055 :         CPLAssert(iSrcBufferOffset <= nSrcBufferBytes);
      82             : 
      83       16055 :         memmove(achSrcBuffer, achSrcBuffer + iSrcBufferOffset,
      84       16055 :                 nSrcBufferBytes - iSrcBufferOffset);
      85       16055 :         iSrcBufferFileOffset += iSrcBufferOffset;
      86       16055 :         nSrcBufferBytes -= iSrcBufferOffset;
      87       16055 :         iSrcBufferOffset = 0;
      88             :     }
      89             : 
      90       16599 :     nSrcBufferBytes +=
      91       16599 :         static_cast<int>(VSIFReadL(achSrcBuffer + nSrcBufferBytes, 1, 512, fp));
      92       16599 :     achSrcBuffer[nSrcBufferBytes] = '\0';
      93             : 
      94       16599 :     CPLAssert(nSrcBufferBytes <= 1024);
      95       16599 :     CPLAssert(iSrcBufferOffset <= nSrcBufferBytes);
      96             : }
      97             : 
      98             : /************************************************************************/
      99             : /*                             ReadValue()                              */
     100             : /*                                                                      */
     101             : /*      Read one type code and value line pair from the DXF file.       */
     102             : /************************************************************************/
     103             : 
     104      153895 : int OGRDXFReader::ReadValueRaw(char *pszValueBuf, int nValueBufSize)
     105             : 
     106             : {
     107             :     /* -------------------------------------------------------------------- */
     108             :     /*      Make sure we have lots of data in our buffer for one value.     */
     109             :     /* -------------------------------------------------------------------- */
     110      153895 :     if (nSrcBufferBytes - iSrcBufferOffset < 512)
     111       16596 :         LoadDiskChunk();
     112             : 
     113             :     /* -------------------------------------------------------------------- */
     114             :     /*      Capture the value code, and skip past it.                       */
     115             :     /* -------------------------------------------------------------------- */
     116      153895 :     unsigned int iStartSrcBufferOffset = iSrcBufferOffset;
     117      153895 :     int nValueCode = atoi(achSrcBuffer + iSrcBufferOffset);
     118             : 
     119      153895 :     nLineNumber++;
     120             : 
     121             :     // proceed to newline.
     122     1544300 :     while (achSrcBuffer[iSrcBufferOffset] != '\n' &&
     123      615361 :            achSrcBuffer[iSrcBufferOffset] != '\r' &&
     124      461648 :            achSrcBuffer[iSrcBufferOffset] != '\0')
     125      461466 :         iSrcBufferOffset++;
     126             : 
     127      153895 :     if (achSrcBuffer[iSrcBufferOffset] == '\0')
     128         182 :         return -1;
     129             : 
     130             :     // skip past newline.  CR, CRLF, or LFCR
     131      153713 :     if ((achSrcBuffer[iSrcBufferOffset] == '\r' &&
     132        5820 :          achSrcBuffer[iSrcBufferOffset + 1] == '\n') ||
     133      147909 :         (achSrcBuffer[iSrcBufferOffset] == '\n' &&
     134      147893 :          achSrcBuffer[iSrcBufferOffset + 1] == '\r'))
     135        5805 :         iSrcBufferOffset += 2;
     136             :     else
     137      147908 :         iSrcBufferOffset += 1;
     138             : 
     139      153713 :     if (achSrcBuffer[iSrcBufferOffset] == '\0')
     140           0 :         return -1;
     141             : 
     142             :     /* -------------------------------------------------------------------- */
     143             :     /*      Capture the value string.                                       */
     144             :     /* -------------------------------------------------------------------- */
     145      153713 :     unsigned int iEOL = iSrcBufferOffset;
     146      307426 :     CPLString osValue;
     147             : 
     148      153713 :     nLineNumber++;
     149             : 
     150             :     // proceed to newline.
     151     1184440 :     while (achSrcBuffer[iEOL] != '\n' && achSrcBuffer[iEOL] != '\r' &&
     152     1030730 :            achSrcBuffer[iEOL] != '\0')
     153     1030720 :         iEOL++;
     154             : 
     155      153713 :     bool bLongLine = false;
     156      153715 :     while (achSrcBuffer[iEOL] == '\0' ||
     157      153712 :            (achSrcBuffer[iEOL] == '\r' && achSrcBuffer[iEOL + 1] == '\0'))
     158             :     {
     159             :         // The line is longer than the buffer (or the line ending is split at
     160             :         // end of buffer). Let's copy what we have so far into our string, and
     161             :         // read more
     162           3 :         const auto nValueLength = osValue.length();
     163             : 
     164           3 :         if (nValueLength + iEOL - iSrcBufferOffset > 1048576)
     165             :         {
     166           0 :             CPLError(CE_Failure, CPLE_AppDefined, "Line %d is too long",
     167             :                      nLineNumber);
     168           0 :             return -1;
     169             :         }
     170             : 
     171           3 :         osValue.resize(nValueLength + iEOL - iSrcBufferOffset, '\0');
     172           3 :         std::copy(achSrcBuffer + iSrcBufferOffset, achSrcBuffer + iEOL,
     173           3 :                   osValue.begin() + nValueLength);
     174             : 
     175           3 :         iSrcBufferOffset = iEOL;
     176           3 :         LoadDiskChunk();
     177           3 :         iEOL = iSrcBufferOffset;
     178           3 :         bLongLine = true;
     179             : 
     180             :         // Have we prematurely reached the end of the file?
     181           3 :         if (achSrcBuffer[iEOL] == '\0')
     182           1 :             return -1;
     183             : 
     184             :         // Proceed to newline again
     185         437 :         while (achSrcBuffer[iEOL] != '\n' && achSrcBuffer[iEOL] != '\r' &&
     186         435 :                achSrcBuffer[iEOL] != '\0')
     187         435 :             iEOL++;
     188             :     }
     189             : 
     190      153712 :     size_t nValueBufLen = 0;
     191             : 
     192             :     // If this was an extremely long line, copy from osValue into the buffer
     193      153712 :     if (!osValue.empty())
     194             :     {
     195           2 :         strncpy(pszValueBuf, osValue.c_str(), nValueBufSize - 1);
     196           2 :         pszValueBuf[nValueBufSize - 1] = '\0';
     197             : 
     198           2 :         nValueBufLen = strlen(pszValueBuf);
     199             : 
     200           2 :         if (static_cast<int>(osValue.length()) > nValueBufSize - 1)
     201             :         {
     202           2 :             CPLDebug("DXF", "Long line truncated to %d characters.\n%s...",
     203             :                      nValueBufSize - 1, pszValueBuf);
     204             :         }
     205             :     }
     206             : 
     207             :     // Copy the last (normally, the only) section of this line into the buffer
     208      153712 :     if (static_cast<int>(iEOL - iSrcBufferOffset) >
     209      153712 :         nValueBufSize - static_cast<int>(nValueBufLen) - 1)
     210             :     {
     211           2 :         strncpy(pszValueBuf + nValueBufLen, achSrcBuffer + iSrcBufferOffset,
     212           2 :                 nValueBufSize - static_cast<int>(nValueBufLen) - 1);
     213           2 :         pszValueBuf[nValueBufSize - 1] = '\0';
     214             : 
     215           2 :         CPLDebug("DXF", "Long line truncated to %d characters.\n%s...",
     216             :                  nValueBufSize - 1, pszValueBuf);
     217             :     }
     218             :     else
     219             :     {
     220      153710 :         strncpy(pszValueBuf + nValueBufLen, achSrcBuffer + iSrcBufferOffset,
     221      153710 :                 iEOL - iSrcBufferOffset);
     222      153710 :         pszValueBuf[nValueBufLen + iEOL - iSrcBufferOffset] = '\0';
     223             :     }
     224             : 
     225      153712 :     iSrcBufferOffset = iEOL;
     226             : 
     227             :     // skip past newline.  CR, CRLF, or LFCR
     228      153712 :     if ((achSrcBuffer[iSrcBufferOffset] == '\r' &&
     229        5816 :          achSrcBuffer[iSrcBufferOffset + 1] == '\n') ||
     230      147908 :         (achSrcBuffer[iSrcBufferOffset] == '\n' &&
     231      147896 :          achSrcBuffer[iSrcBufferOffset + 1] == '\r'))
     232        5804 :         iSrcBufferOffset += 2;
     233             :     else
     234      147908 :         iSrcBufferOffset += 1;
     235             : 
     236             :     /* -------------------------------------------------------------------- */
     237             :     /*      Record how big this value was, so it can be unread safely.      */
     238             :     /* -------------------------------------------------------------------- */
     239      153712 :     if (bLongLine)
     240           2 :         nLastValueSize = 0;
     241             :     else
     242             :     {
     243      153710 :         nLastValueSize = iSrcBufferOffset - iStartSrcBufferOffset;
     244      153710 :         CPLAssert(nLastValueSize > 0);
     245             :     }
     246             : 
     247      153712 :     return nValueCode;
     248             : }
     249             : 
     250      153895 : int OGRDXFReader::ReadValue(char *pszValueBuf, int nValueBufSize)
     251             : {
     252             :     int nValueCode;
     253             :     while (true)
     254             :     {
     255      153895 :         nValueCode = ReadValueRaw(pszValueBuf, nValueBufSize);
     256      153895 :         if (nValueCode == 999)
     257             :         {
     258             :             // Skip comments
     259          13 :             continue;
     260             :         }
     261      153882 :         break;
     262             :     }
     263      153882 :     return nValueCode;
     264             : }
     265             : 
     266             : /************************************************************************/
     267             : /*                            UnreadValue()                             */
     268             : /*                                                                      */
     269             : /*      Unread the last value read, accomplished by resetting the       */
     270             : /*      read pointer.                                                   */
     271             : /************************************************************************/
     272             : 
     273        1958 : void OGRDXFReader::UnreadValue()
     274             : 
     275             : {
     276        1958 :     if (nLastValueSize == 0)
     277             :     {
     278           1 :         CPLError(CE_Failure, CPLE_AppDefined,
     279             :                  "Cannot UnreadValue(), likely due to a previous long line");
     280           1 :         return;
     281             :     }
     282        1957 :     CPLAssert(iSrcBufferOffset >= nLastValueSize);
     283        1957 :     CPLAssert(nLastValueSize > 0);
     284             : 
     285        1957 :     iSrcBufferOffset -= nLastValueSize;
     286        1957 :     nLineNumber -= 2;
     287        1957 :     nLastValueSize = 0;
     288             : }

Generated by: LCOV version 1.14