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-05-04 12:52:34 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             :  * Permission is hereby granted, free of charge, to any person obtaining a
      12             :  * copy of this software and associated documentation files (the "Software"),
      13             :  * to deal in the Software without restriction, including without limitation
      14             :  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
      15             :  * and/or sell copies of the Software, and to permit persons to whom the
      16             :  * Software is furnished to do so, subject to the following conditions:
      17             :  *
      18             :  * The above copyright notice and this permission notice shall be included
      19             :  * in all copies or substantial portions of the Software.
      20             :  *
      21             :  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
      22             :  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      23             :  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
      24             :  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
      25             :  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
      26             :  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
      27             :  * DEALINGS IN THE SOFTWARE.
      28             :  ****************************************************************************/
      29             : 
      30             : #include "ogr_dxf.h"
      31             : #include "cpl_conv.h"
      32             : #include "cpl_string.h"
      33             : #include "cpl_csv.h"
      34             : 
      35             : /************************************************************************/
      36             : /*                            OGRDXFReader()                            */
      37             : /************************************************************************/
      38             : 
      39         278 : OGRDXFReader::OGRDXFReader()
      40             :     : fp(nullptr), iSrcBufferOffset(0), nSrcBufferBytes(0),
      41         278 :       iSrcBufferFileOffset(0), achSrcBuffer{}, nLastValueSize(0), nLineNumber(0)
      42             : {
      43         278 : }
      44             : 
      45             : /************************************************************************/
      46             : /*                           ~OGRDXFReader()                            */
      47             : /************************************************************************/
      48             : 
      49         278 : OGRDXFReader::~OGRDXFReader()
      50             : 
      51             : {
      52         278 : }
      53             : 
      54             : /************************************************************************/
      55             : /*                             Initialize()                             */
      56             : /************************************************************************/
      57             : 
      58         278 : void OGRDXFReader::Initialize(VSILFILE *fpIn)
      59             : 
      60             : {
      61         278 :     fp = fpIn;
      62         278 : }
      63             : 
      64             : /************************************************************************/
      65             : /*                          ResetReadPointer()                          */
      66             : /************************************************************************/
      67             : 
      68         194 : void OGRDXFReader::ResetReadPointer(unsigned int iNewOffset,
      69             :                                     int nNewLineNumber /* = 0 */)
      70             : 
      71             : {
      72         194 :     nSrcBufferBytes = 0;
      73         194 :     iSrcBufferOffset = 0;
      74         194 :     iSrcBufferFileOffset = iNewOffset;
      75         194 :     nLastValueSize = 0;
      76         194 :     nLineNumber = nNewLineNumber;
      77             : 
      78         194 :     VSIFSeekL(fp, iNewOffset, SEEK_SET);
      79         194 : }
      80             : 
      81             : /************************************************************************/
      82             : /*                           LoadDiskChunk()                            */
      83             : /*                                                                      */
      84             : /*      Load another block (512 bytes) of input from the source         */
      85             : /*      file.                                                           */
      86             : /************************************************************************/
      87             : 
      88       16443 : void OGRDXFReader::LoadDiskChunk()
      89             : 
      90             : {
      91       16443 :     if (nSrcBufferBytes - iSrcBufferOffset > 511)
      92           0 :         return;
      93             : 
      94       16443 :     if (iSrcBufferOffset > 0)
      95             :     {
      96       15919 :         CPLAssert(nSrcBufferBytes <= 1024);
      97       15919 :         CPLAssert(iSrcBufferOffset <= nSrcBufferBytes);
      98             : 
      99       15919 :         memmove(achSrcBuffer, achSrcBuffer + iSrcBufferOffset,
     100       15919 :                 nSrcBufferBytes - iSrcBufferOffset);
     101       15919 :         iSrcBufferFileOffset += iSrcBufferOffset;
     102       15919 :         nSrcBufferBytes -= iSrcBufferOffset;
     103       15919 :         iSrcBufferOffset = 0;
     104             :     }
     105             : 
     106       16443 :     nSrcBufferBytes +=
     107       16443 :         static_cast<int>(VSIFReadL(achSrcBuffer + nSrcBufferBytes, 1, 512, fp));
     108       16443 :     achSrcBuffer[nSrcBufferBytes] = '\0';
     109             : 
     110       16443 :     CPLAssert(nSrcBufferBytes <= 1024);
     111       16443 :     CPLAssert(iSrcBufferOffset <= nSrcBufferBytes);
     112             : }
     113             : 
     114             : /************************************************************************/
     115             : /*                             ReadValue()                              */
     116             : /*                                                                      */
     117             : /*      Read one type code and value line pair from the DXF file.       */
     118             : /************************************************************************/
     119             : 
     120      153559 : int OGRDXFReader::ReadValueRaw(char *pszValueBuf, int nValueBufSize)
     121             : 
     122             : {
     123             :     /* -------------------------------------------------------------------- */
     124             :     /*      Make sure we have lots of data in our buffer for one value.     */
     125             :     /* -------------------------------------------------------------------- */
     126      153559 :     if (nSrcBufferBytes - iSrcBufferOffset < 512)
     127       16440 :         LoadDiskChunk();
     128             : 
     129             :     /* -------------------------------------------------------------------- */
     130             :     /*      Capture the value code, and skip past it.                       */
     131             :     /* -------------------------------------------------------------------- */
     132      153559 :     unsigned int iStartSrcBufferOffset = iSrcBufferOffset;
     133      153559 :     int nValueCode = atoi(achSrcBuffer + iSrcBufferOffset);
     134             : 
     135      153559 :     nLineNumber++;
     136             : 
     137             :     // proceed to newline.
     138     1540940 :     while (achSrcBuffer[iSrcBufferOffset] != '\n' &&
     139      614017 :            achSrcBuffer[iSrcBufferOffset] != '\r' &&
     140      460640 :            achSrcBuffer[iSrcBufferOffset] != '\0')
     141      460458 :         iSrcBufferOffset++;
     142             : 
     143      153559 :     if (achSrcBuffer[iSrcBufferOffset] == '\0')
     144         182 :         return -1;
     145             : 
     146             :     // skip past newline.  CR, CRLF, or LFCR
     147      153377 :     if ((achSrcBuffer[iSrcBufferOffset] == '\r' &&
     148        5820 :          achSrcBuffer[iSrcBufferOffset + 1] == '\n') ||
     149      147573 :         (achSrcBuffer[iSrcBufferOffset] == '\n' &&
     150      147557 :          achSrcBuffer[iSrcBufferOffset + 1] == '\r'))
     151        5805 :         iSrcBufferOffset += 2;
     152             :     else
     153      147572 :         iSrcBufferOffset += 1;
     154             : 
     155      153377 :     if (achSrcBuffer[iSrcBufferOffset] == '\0')
     156           0 :         return -1;
     157             : 
     158             :     /* -------------------------------------------------------------------- */
     159             :     /*      Capture the value string.                                       */
     160             :     /* -------------------------------------------------------------------- */
     161      153377 :     unsigned int iEOL = iSrcBufferOffset;
     162      306754 :     CPLString osValue;
     163             : 
     164      153377 :     nLineNumber++;
     165             : 
     166             :     // proceed to newline.
     167     1181890 :     while (achSrcBuffer[iEOL] != '\n' && achSrcBuffer[iEOL] != '\r' &&
     168     1028510 :            achSrcBuffer[iEOL] != '\0')
     169     1028510 :         iEOL++;
     170             : 
     171      153377 :     bool bLongLine = false;
     172      153379 :     while (achSrcBuffer[iEOL] == '\0' ||
     173      153376 :            (achSrcBuffer[iEOL] == '\r' && achSrcBuffer[iEOL + 1] == '\0'))
     174             :     {
     175             :         // The line is longer than the buffer (or the line ending is split at
     176             :         // end of buffer). Let's copy what we have so far into our string, and
     177             :         // read more
     178           3 :         const auto nValueLength = osValue.length();
     179             : 
     180           3 :         if (nValueLength + iEOL - iSrcBufferOffset > 1048576)
     181             :         {
     182           0 :             CPLError(CE_Failure, CPLE_AppDefined, "Line %d is too long",
     183             :                      nLineNumber);
     184           0 :             return -1;
     185             :         }
     186             : 
     187           3 :         osValue.resize(nValueLength + iEOL - iSrcBufferOffset, '\0');
     188           3 :         std::copy(achSrcBuffer + iSrcBufferOffset, achSrcBuffer + iEOL,
     189           3 :                   osValue.begin() + nValueLength);
     190             : 
     191           3 :         iSrcBufferOffset = iEOL;
     192           3 :         LoadDiskChunk();
     193           3 :         iEOL = iSrcBufferOffset;
     194           3 :         bLongLine = true;
     195             : 
     196             :         // Have we prematurely reached the end of the file?
     197           3 :         if (achSrcBuffer[iEOL] == '\0')
     198           1 :             return -1;
     199             : 
     200             :         // Proceed to newline again
     201         437 :         while (achSrcBuffer[iEOL] != '\n' && achSrcBuffer[iEOL] != '\r' &&
     202         435 :                achSrcBuffer[iEOL] != '\0')
     203         435 :             iEOL++;
     204             :     }
     205             : 
     206      153376 :     size_t nValueBufLen = 0;
     207             : 
     208             :     // If this was an extremely long line, copy from osValue into the buffer
     209      153376 :     if (!osValue.empty())
     210             :     {
     211           2 :         strncpy(pszValueBuf, osValue.c_str(), nValueBufSize - 1);
     212           2 :         pszValueBuf[nValueBufSize - 1] = '\0';
     213             : 
     214           2 :         nValueBufLen = strlen(pszValueBuf);
     215             : 
     216           2 :         if (static_cast<int>(osValue.length()) > nValueBufSize - 1)
     217             :         {
     218           2 :             CPLDebug("DXF", "Long line truncated to %d characters.\n%s...",
     219             :                      nValueBufSize - 1, pszValueBuf);
     220             :         }
     221             :     }
     222             : 
     223             :     // Copy the last (normally, the only) section of this line into the buffer
     224      153376 :     if (static_cast<int>(iEOL - iSrcBufferOffset) >
     225      153376 :         nValueBufSize - static_cast<int>(nValueBufLen) - 1)
     226             :     {
     227           2 :         strncpy(pszValueBuf + nValueBufLen, achSrcBuffer + iSrcBufferOffset,
     228           2 :                 nValueBufSize - static_cast<int>(nValueBufLen) - 1);
     229           2 :         pszValueBuf[nValueBufSize - 1] = '\0';
     230             : 
     231           2 :         CPLDebug("DXF", "Long line truncated to %d characters.\n%s...",
     232             :                  nValueBufSize - 1, pszValueBuf);
     233             :     }
     234             :     else
     235             :     {
     236      153374 :         strncpy(pszValueBuf + nValueBufLen, achSrcBuffer + iSrcBufferOffset,
     237      153374 :                 iEOL - iSrcBufferOffset);
     238      153374 :         pszValueBuf[nValueBufLen + iEOL - iSrcBufferOffset] = '\0';
     239             :     }
     240             : 
     241      153376 :     iSrcBufferOffset = iEOL;
     242             : 
     243             :     // skip past newline.  CR, CRLF, or LFCR
     244      153376 :     if ((achSrcBuffer[iSrcBufferOffset] == '\r' &&
     245        5816 :          achSrcBuffer[iSrcBufferOffset + 1] == '\n') ||
     246      147572 :         (achSrcBuffer[iSrcBufferOffset] == '\n' &&
     247      147560 :          achSrcBuffer[iSrcBufferOffset + 1] == '\r'))
     248        5804 :         iSrcBufferOffset += 2;
     249             :     else
     250      147572 :         iSrcBufferOffset += 1;
     251             : 
     252             :     /* -------------------------------------------------------------------- */
     253             :     /*      Record how big this value was, so it can be unread safely.      */
     254             :     /* -------------------------------------------------------------------- */
     255      153376 :     if (bLongLine)
     256           2 :         nLastValueSize = 0;
     257             :     else
     258             :     {
     259      153374 :         nLastValueSize = iSrcBufferOffset - iStartSrcBufferOffset;
     260      153374 :         CPLAssert(nLastValueSize > 0);
     261             :     }
     262             : 
     263      153376 :     return nValueCode;
     264             : }
     265             : 
     266      153559 : int OGRDXFReader::ReadValue(char *pszValueBuf, int nValueBufSize)
     267             : {
     268             :     int nValueCode;
     269             :     while (true)
     270             :     {
     271      153559 :         nValueCode = ReadValueRaw(pszValueBuf, nValueBufSize);
     272      153559 :         if (nValueCode == 999)
     273             :         {
     274             :             // Skip comments
     275          13 :             continue;
     276             :         }
     277      153546 :         break;
     278             :     }
     279      153546 :     return nValueCode;
     280             : }
     281             : 
     282             : /************************************************************************/
     283             : /*                            UnreadValue()                             */
     284             : /*                                                                      */
     285             : /*      Unread the last value read, accomplished by resetting the       */
     286             : /*      read pointer.                                                   */
     287             : /************************************************************************/
     288             : 
     289        1935 : void OGRDXFReader::UnreadValue()
     290             : 
     291             : {
     292        1935 :     if (nLastValueSize == 0)
     293             :     {
     294           1 :         CPLError(CE_Failure, CPLE_AppDefined,
     295             :                  "Cannot UnreadValue(), likely due to a previous long line");
     296           1 :         return;
     297             :     }
     298        1934 :     CPLAssert(iSrcBufferOffset >= nLastValueSize);
     299        1934 :     CPLAssert(nLastValueSize > 0);
     300             : 
     301        1934 :     iSrcBufferOffset -= nLastValueSize;
     302        1934 :     nLineNumber -= 2;
     303        1934 :     nLastValueSize = 0;
     304             : }

Generated by: LCOV version 1.14