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

Generated by: LCOV version 1.14