LCOV - code coverage report
Current view: top level - ogr/ogrsf_frmts/dxf - ogrdxf_blockmap.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 85 95 89.5 %
Date: 2024-05-04 12:52:34 Functions: 5 5 100.0 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  DXF Translator
       4             :  * Purpose:  Implements BlockMap reading and management portion of
       5             :  *           OGRDXFDataSource class
       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             : #include <algorithm>
      36             : 
      37             : /************************************************************************/
      38             : /*                          ReadBlockSection()                          */
      39             : /************************************************************************/
      40             : 
      41         124 : bool OGRDXFDataSource::ReadBlocksSection()
      42             : 
      43             : {
      44             :     // Force inlining of blocks to false, for when OGRDXFLayer processes
      45             :     // INSERT entities
      46         124 :     const bool bOldInlineBlocks = bInlineBlocks;
      47         124 :     bInlineBlocks = false;
      48             : 
      49             :     OGRDXFLayer *poReaderLayer =
      50         124 :         static_cast<OGRDXFLayer *>(GetLayerByName("Entities"));
      51             : 
      52         124 :     iEntitiesOffset = oReader.iSrcBufferFileOffset + oReader.iSrcBufferOffset;
      53         124 :     iEntitiesLineNumber = oReader.nLineNumber;
      54             : 
      55             :     char szLineBuf[257];
      56         124 :     int nCode = 0;
      57        4271 :     while ((nCode = ReadValue(szLineBuf, sizeof(szLineBuf))) > -1 &&
      58        2135 :            !EQUAL(szLineBuf, "ENDSEC"))
      59             :     {
      60             :         // We are only interested in extracting blocks.
      61        2012 :         if (nCode != 0 || !EQUAL(szLineBuf, "BLOCK"))
      62        1939 :             continue;
      63             : 
      64             :         // Process contents of BLOCK definition till we find the
      65             :         // first entity.
      66         333 :         CPLString osBlockName;
      67         333 :         CPLString osBlockRecordHandle;
      68         333 :         OGRDXFInsertTransformer oBasePointTransformer;
      69             : 
      70        4220 :         while ((nCode = ReadValue(szLineBuf, sizeof(szLineBuf))) > 0)
      71             :         {
      72        3887 :             switch (nCode)
      73             :             {
      74         332 :                 case 2:
      75         332 :                     osBlockName = szLineBuf;
      76         332 :                     break;
      77             : 
      78         238 :                 case 330:
      79             :                     // get the block record handle as well, for arrowheads
      80         238 :                     osBlockRecordHandle = szLineBuf;
      81         238 :                     break;
      82             : 
      83         330 :                 case 10:
      84         330 :                     oBasePointTransformer.dfXOffset = -CPLAtof(szLineBuf);
      85         330 :                     break;
      86             : 
      87         330 :                 case 20:
      88         330 :                     oBasePointTransformer.dfYOffset = -CPLAtof(szLineBuf);
      89         330 :                     break;
      90             : 
      91         330 :                 case 30:
      92         330 :                     oBasePointTransformer.dfZOffset = -CPLAtof(szLineBuf);
      93         330 :                     break;
      94             :             }
      95             :         }
      96         333 :         if (nCode < 0)
      97             :         {
      98           0 :             bInlineBlocks = bOldInlineBlocks;
      99           0 :             DXF_READER_ERROR();
     100           0 :             return false;
     101             :         }
     102             : 
     103             :         // store the block record handle mapping even if the block is empty
     104         333 :         oBlockRecordHandles[osBlockRecordHandle] = osBlockName;
     105             : 
     106         333 :         if (EQUAL(szLineBuf, "ENDBLK"))
     107         260 :             continue;
     108             : 
     109          73 :         UnreadValue();
     110             : 
     111          73 :         if (oBlockMap.find(osBlockName) != oBlockMap.end())
     112             :         {
     113           0 :             bInlineBlocks = bOldInlineBlocks;
     114           0 :             DXF_READER_ERROR();
     115           0 :             return false;
     116             :         }
     117             : 
     118             :         // Now we will process entities till we run out at the ENDBLK code.
     119             : 
     120          73 :         PushBlockInsertion(osBlockName);
     121             : 
     122          73 :         OGRDXFFeature *poFeature = nullptr;
     123          73 :         int nIters = 0;
     124             :         const int nMaxIters =
     125          73 :             atoi(CPLGetConfigOption("DXF_FEATURE_LIMIT_PER_BLOCK", "10000"));
     126        1075 :         while ((poFeature = poReaderLayer->GetNextUnfilteredFeature()) !=
     127             :                nullptr)
     128             :         {
     129        1002 :             if (nMaxIters >= 0 && nIters == nMaxIters)
     130             :             {
     131           0 :                 delete poFeature;
     132           0 :                 CPLError(CE_Warning, CPLE_AppDefined,
     133             :                          "Limit of %d features for block %s reached. "
     134             :                          "If you need more, set the "
     135             :                          "DXF_FEATURE_LIMIT_PER_BLOCK configuration "
     136             :                          "option to the maximum value (or -1 for no limit)",
     137             :                          nMaxIters, osBlockName.c_str());
     138           0 :                 break;
     139             :             }
     140             : 
     141             :             // Apply the base point translation
     142        1002 :             OGRGeometry *poFeatureGeom = poFeature->GetGeometryRef();
     143        1002 :             if (poFeatureGeom)
     144        1001 :                 poFeatureGeom->transform(&oBasePointTransformer);
     145             : 
     146             :             // Also apply the base point translation to the original
     147             :             // coordinates of block references
     148        1002 :             if (poFeature->IsBlockReference())
     149             :             {
     150         791 :                 DXFTriple oTriple = poFeature->GetInsertOCSCoords();
     151         791 :                 OGRPoint oPoint(oTriple.dfX, oTriple.dfY, oTriple.dfZ);
     152         791 :                 oPoint.transform(&oBasePointTransformer);
     153         791 :                 poFeature->SetInsertOCSCoords(
     154        1582 :                     DXFTriple(oPoint.getX(), oPoint.getY(), oPoint.getZ()));
     155             :             }
     156             : 
     157        1002 :             oBlockMap[osBlockName].apoFeatures.push_back(poFeature);
     158        1002 :             nIters++;
     159             :         }
     160             : 
     161          73 :         PopBlockInsertion();
     162             :     }
     163         124 :     if (nCode < 0)
     164             :     {
     165           1 :         bInlineBlocks = bOldInlineBlocks;
     166           1 :         DXF_READER_ERROR();
     167           1 :         return false;
     168             :     }
     169             : 
     170         123 :     CPLDebug("DXF", "Read %d blocks with meaningful geometry.",
     171         123 :              (int)oBlockMap.size());
     172             : 
     173             :     // Restore old inline blocks setting
     174         123 :     bInlineBlocks = bOldInlineBlocks;
     175             : 
     176         123 :     return true;
     177             : }
     178             : 
     179             : /************************************************************************/
     180             : /*                            LookupBlock()                             */
     181             : /*                                                                      */
     182             : /*      Find the geometry collection corresponding to a name if it      */
     183             : /*      exists.  Note that the returned geometry pointer is to a        */
     184             : /*      geometry that continues to be owned by the datasource.  It      */
     185             : /*      should be cloned for use.                                       */
     186             : /************************************************************************/
     187             : 
     188         342 : DXFBlockDefinition *OGRDXFDataSource::LookupBlock(const char *pszName)
     189             : 
     190             : {
     191         684 :     CPLString l_osName = pszName;
     192             : 
     193         342 :     if (oBlockMap.count(l_osName) == 0)
     194         134 :         return nullptr;
     195             :     else
     196         208 :         return &(oBlockMap[l_osName]);
     197             : }
     198             : 
     199             : /************************************************************************/
     200             : /*                     GetBlockNameByRecordHandle()                     */
     201             : /*                                                                      */
     202             : /*      Find the name of the block with the given BLOCK_RECORD handle.  */
     203             : /*      If there is no such block, an empty string is returned.         */
     204             : /************************************************************************/
     205             : 
     206          18 : CPLString OGRDXFDataSource::GetBlockNameByRecordHandle(const char *pszID)
     207             : 
     208             : {
     209          36 :     CPLString l_osID = pszID;
     210             : 
     211          18 :     if (oBlockRecordHandles.count(l_osID) == 0)
     212           2 :         return "";
     213             :     else
     214          16 :         return oBlockRecordHandles[l_osID];
     215             : }
     216             : 
     217             : /************************************************************************/
     218             : /*                         PushBlockInsertion()                         */
     219             : /*                                                                      */
     220             : /*      Add a block name to the stack of blocks being inserted.         */
     221             : /*      Returns false if we are already inserting this block.           */
     222             : /************************************************************************/
     223             : 
     224        1285 : bool OGRDXFDataSource::PushBlockInsertion(const CPLString &osBlockName)
     225             : 
     226             : {
     227             :     // Make sure we are not recursing too deeply (avoid stack overflows) or
     228             :     // inserting a block within itself (avoid billion-laughs type issues).
     229             :     // 128 is a totally arbitrary limit
     230        2570 :     if (aosBlockInsertionStack.size() > 128 ||
     231           0 :         std::find(aosBlockInsertionStack.begin(), aosBlockInsertionStack.end(),
     232        2570 :                   osBlockName) != aosBlockInsertionStack.end())
     233             :     {
     234        1003 :         CPLError(CE_Warning, CPLE_AppDefined,
     235             :                  "Dangerous block recursion detected. "
     236             :                  "Some blocks have not been inserted.");
     237        1003 :         return false;
     238             :     }
     239             : 
     240         282 :     aosBlockInsertionStack.push_back(osBlockName);
     241         282 :     return true;
     242             : }
     243             : 
     244             : /************************************************************************/
     245             : /*                        ~DXFBlockDefinition()                         */
     246             : /*                                                                      */
     247             : /*      Safe cleanup of a block definition.                             */
     248             : /************************************************************************/
     249             : 
     250          73 : DXFBlockDefinition::~DXFBlockDefinition()
     251             : {
     252        1075 :     while (!apoFeatures.empty())
     253             :     {
     254        1002 :         delete apoFeatures.back();
     255        1002 :         apoFeatures.pop_back();
     256             :     }
     257          73 : }

Generated by: LCOV version 1.14