LCOV - code coverage report
Current view: top level - ogr/ogrsf_frmts/dxf - ogrdxfdatasource.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 383 480 79.8 %
Date: 2025-03-25 20:12:57 Functions: 21 22 95.5 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  DXF Translator
       4             :  * Purpose:  Implements OGRDXFDataSource class
       5             :  * Author:   Frank Warmerdam, warmerdam@pobox.com
       6             :  *
       7             :  ******************************************************************************
       8             :  * Copyright (c) 2009, Frank Warmerdam <warmerdam@pobox.com>
       9             :  * Copyright (c) 2010-2013, Even Rouault <even dot rouault at spatialys.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             : 
      18             : #include <algorithm>
      19             : 
      20             : /************************************************************************/
      21             : /*                          OGRDXFDataSource()                          */
      22             : /************************************************************************/
      23             : 
      24         185 : OGRDXFDataSource::OGRDXFDataSource()
      25             :     : fp(nullptr), iEntitiesOffset(0), iEntitiesLineNumber(0),
      26             :       bInlineBlocks(false), bMergeBlockGeometries(false),
      27             :       bTranslateEscapeSequences(false), bIncludeRawCodeValues(false),
      28         185 :       b3DExtensibleMode(false), bHaveReadSolidData(false)
      29             : {
      30         185 : }
      31             : 
      32             : /************************************************************************/
      33             : /*                         ~OGRDXFDataSource()                          */
      34             : /************************************************************************/
      35             : 
      36         498 : OGRDXFDataSource::~OGRDXFDataSource()
      37             : 
      38             : {
      39             :     /* -------------------------------------------------------------------- */
      40             :     /*      Destroy layers.                                                 */
      41             :     /* -------------------------------------------------------------------- */
      42         375 :     while (!apoLayers.empty())
      43             :     {
      44         190 :         delete apoLayers.back();
      45         190 :         apoLayers.pop_back();
      46             :     }
      47             : 
      48             :     /* -------------------------------------------------------------------- */
      49             :     /*      Close file.                                                     */
      50             :     /* -------------------------------------------------------------------- */
      51         185 :     if (fp != nullptr)
      52             :     {
      53         185 :         VSIFCloseL(fp);
      54         185 :         fp = nullptr;
      55             :     }
      56         313 : }
      57             : 
      58             : /************************************************************************/
      59             : /*                           TestCapability()                           */
      60             : /************************************************************************/
      61             : 
      62           0 : int OGRDXFDataSource::TestCapability(const char *pszCap)
      63             : {
      64           0 :     if (EQUAL(pszCap, ODsCZGeometries))
      65           0 :         return true;
      66             : 
      67           0 :     return false;
      68             : }
      69             : 
      70             : /************************************************************************/
      71             : /*                              GetLayer()                              */
      72             : /************************************************************************/
      73             : 
      74         413 : OGRLayer *OGRDXFDataSource::GetLayer(int iLayer)
      75             : 
      76             : {
      77         413 :     if (iLayer < 0 || iLayer >= (int)apoLayers.size())
      78           0 :         return nullptr;
      79             :     else
      80         413 :         return apoLayers[iLayer];
      81             : }
      82             : 
      83             : /************************************************************************/
      84             : /*                                Open()                                */
      85             : /************************************************************************/
      86             : 
      87         185 : int OGRDXFDataSource::Open(const char *pszFilename, bool bHeaderOnly,
      88             :                            CSLConstList papszOptionsIn)
      89             : 
      90             : {
      91         185 :     SetDescription(pszFilename);
      92             : 
      93         185 :     osEncoding = CPL_ENC_ISO8859_1;
      94             : 
      95         185 :     bInlineBlocks = CPLTestBool(
      96             :         CSLFetchNameValueDef(papszOptionsIn, "INLINE_BLOCKS",
      97             :                              CPLGetConfigOption("DXF_INLINE_BLOCKS", "TRUE")));
      98         185 :     bMergeBlockGeometries = CPLTestBool(CSLFetchNameValueDef(
      99             :         papszOptionsIn, "MERGE_BLOCK_GEOMETRIES",
     100             :         CPLGetConfigOption("DXF_MERGE_BLOCK_GEOMETRIES", "TRUE")));
     101             : 
     102         185 :     bTranslateEscapeSequences = CPLTestBool(CSLFetchNameValueDef(
     103             :         papszOptionsIn, "TRANSLATE_ESCAPE_SEQUENCES",
     104             :         CPLGetConfigOption("DXF_TRANSLATE_ESCAPE_SEQUENCES", "TRUE")));
     105             : 
     106         185 :     bIncludeRawCodeValues = CPLTestBool(CSLFetchNameValueDef(
     107             :         papszOptionsIn, "INCLUDE_RAW_CODE_VALUES",
     108             :         CPLGetConfigOption("DXF_INCLUDE_RAW_CODE_VALUES", "FALSE")));
     109             : 
     110         185 :     b3DExtensibleMode = CPLTestBool(CSLFetchNameValueDef(
     111             :         papszOptionsIn, "3D_EXTENSIBLE_MODE",
     112             :         CPLGetConfigOption("DXF_3D_EXTENSIBLE_MODE", "FALSE")));
     113             : 
     114         185 :     m_bClosedLineAsPolygon = CPLTestBool(CSLFetchNameValueDef(
     115             :         papszOptionsIn, "CLOSED_LINE_AS_POLYGON",
     116             :         CPLGetConfigOption("DXF_CLOSED_LINE_AS_POLYGON", "FALSE")));
     117             : 
     118         185 :     m_dfHatchTolerance = CPLAtof(
     119             :         CSLFetchNameValueDef(papszOptionsIn, "HATCH_TOLERANCE",
     120             :                              CPLGetConfigOption("DXF_HATCH_TOLERANCE", "-1")));
     121             : 
     122             :     // Only for debugging
     123         185 :     if (CPLTestBool(CPLGetConfigOption("DXF_HEADER_ONLY", "FALSE")))
     124           0 :         bHeaderOnly = true;
     125             : 
     126             :     /* -------------------------------------------------------------------- */
     127             :     /*      Open the file.                                                  */
     128             :     /* -------------------------------------------------------------------- */
     129         185 :     fp = VSIFOpenL(pszFilename, "r");
     130         185 :     if (fp == nullptr)
     131           0 :         return FALSE;
     132             : 
     133         185 :     oReader.Initialize(fp);
     134             : 
     135             :     /* -------------------------------------------------------------------- */
     136             :     /*      Confirm we have a header section.                               */
     137             :     /* -------------------------------------------------------------------- */
     138             :     char szLineBuf[257];
     139         185 :     bool bEntitiesOnly = false;
     140             : 
     141         185 :     if (ReadValue(szLineBuf) != 0 || !EQUAL(szLineBuf, "SECTION"))
     142           0 :         return FALSE;
     143             : 
     144         370 :     if (ReadValue(szLineBuf) != 2 ||
     145         185 :         (!EQUAL(szLineBuf, "HEADER") && !EQUAL(szLineBuf, "ENTITIES") &&
     146           9 :          !EQUAL(szLineBuf, "TABLES")))
     147           0 :         return FALSE;
     148             : 
     149         185 :     if (EQUAL(szLineBuf, "ENTITIES"))
     150          19 :         bEntitiesOnly = true;
     151             : 
     152             :     /* Some files might have no header but begin directly with a TABLES section
     153             :      */
     154         166 :     else if (EQUAL(szLineBuf, "TABLES"))
     155             :     {
     156             :         osEncoding = CSLFetchNameValueDef(
     157             :             papszOptionsIn, "ENCODING",
     158           9 :             CPLGetConfigOption("DXF_ENCODING", osEncoding));
     159             : 
     160           9 :         if (!ReadTablesSection())
     161           0 :             return FALSE;
     162           9 :         if (ReadValue(szLineBuf) < 0)
     163             :         {
     164           0 :             DXF_READER_ERROR();
     165           0 :             return FALSE;
     166             :         }
     167             :     }
     168             : 
     169             :     /* -------------------------------------------------------------------- */
     170             :     /*      Process the header, picking up a few useful pieces of           */
     171             :     /*      information.                                                    */
     172             :     /* -------------------------------------------------------------------- */
     173             :     else /* if( EQUAL(szLineBuf,"HEADER") ) */
     174             :     {
     175         157 :         if (!ReadHeaderSection())
     176           0 :             return FALSE;
     177         157 :         if (ReadValue(szLineBuf) < 0)
     178             :         {
     179           0 :             DXF_READER_ERROR();
     180           0 :             return FALSE;
     181             :         }
     182             : 
     183             :         /* --------------------------------------------------------------------
     184             :          */
     185             :         /*      Process the CLASSES section, if present. */
     186             :         /* --------------------------------------------------------------------
     187             :          */
     188         157 :         if (EQUAL(szLineBuf, "ENDSEC"))
     189             :         {
     190           0 :             if (ReadValue(szLineBuf) < 0)
     191             :             {
     192           0 :                 DXF_READER_ERROR();
     193           0 :                 return FALSE;
     194             :             }
     195             :         }
     196             : 
     197         157 :         if (EQUAL(szLineBuf, "SECTION"))
     198             :         {
     199         156 :             if (ReadValue(szLineBuf) < 0)
     200             :             {
     201           0 :                 DXF_READER_ERROR();
     202           0 :                 return FALSE;
     203             :             }
     204             :         }
     205             : 
     206         157 :         if (EQUAL(szLineBuf, "CLASSES"))
     207             :         {
     208             :             // int nCode = 0;
     209        1210 :             while ((/* nCode = */ ReadValue(szLineBuf, sizeof(szLineBuf))) >
     210        2420 :                        -1 &&
     211        1210 :                    !EQUAL(szLineBuf, "ENDSEC"))
     212             :             {
     213             :                 // printf("C:%d/%s\n", nCode, szLineBuf );
     214             :             }
     215             :         }
     216             : 
     217             :         /* --------------------------------------------------------------------
     218             :          */
     219             :         /*      Process the TABLES section, if present. */
     220             :         /* --------------------------------------------------------------------
     221             :          */
     222         157 :         if (EQUAL(szLineBuf, "ENDSEC"))
     223             :         {
     224         122 :             if (ReadValue(szLineBuf) < 0)
     225             :             {
     226           0 :                 DXF_READER_ERROR();
     227           0 :                 return FALSE;
     228             :             }
     229             :         }
     230             : 
     231         157 :         if (EQUAL(szLineBuf, "SECTION"))
     232             :         {
     233         122 :             if (ReadValue(szLineBuf) < 0)
     234             :             {
     235           0 :                 DXF_READER_ERROR();
     236           0 :                 return FALSE;
     237             :             }
     238             :         }
     239             : 
     240         157 :         if (EQUAL(szLineBuf, "TABLES"))
     241             :         {
     242         156 :             if (!ReadTablesSection())
     243           0 :                 return FALSE;
     244         156 :             if (ReadValue(szLineBuf) < 0)
     245             :             {
     246           0 :                 DXF_READER_ERROR();
     247           0 :                 return FALSE;
     248             :             }
     249             :         }
     250             :     }
     251             : 
     252             :     /* -------------------------------------------------------------------- */
     253             :     /*      Create a blocks layer if we are not in inlining mode.           */
     254             :     /* -------------------------------------------------------------------- */
     255         185 :     if (!bInlineBlocks)
     256           5 :         apoLayers.push_back(new OGRDXFBlocksLayer(this));
     257             : 
     258             :     /* -------------------------------------------------------------------- */
     259             :     /*      Create out layer object - we will need it when interpreting     */
     260             :     /*      blocks.                                                         */
     261             :     /* -------------------------------------------------------------------- */
     262         185 :     apoLayers.push_back(new OGRDXFLayer(this));
     263             : 
     264             :     /* -------------------------------------------------------------------- */
     265             :     /*      Process the BLOCKS section if present.                          */
     266             :     /* -------------------------------------------------------------------- */
     267         185 :     if (!bEntitiesOnly)
     268             :     {
     269         166 :         if (EQUAL(szLineBuf, "ENDSEC"))
     270             :         {
     271           0 :             if (ReadValue(szLineBuf) < 0)
     272             :             {
     273           0 :                 DXF_READER_ERROR();
     274           0 :                 return FALSE;
     275             :             }
     276             :         }
     277             : 
     278         166 :         if (EQUAL(szLineBuf, "SECTION"))
     279             :         {
     280         163 :             if (ReadValue(szLineBuf) < 0)
     281             :             {
     282           0 :                 DXF_READER_ERROR();
     283           0 :                 return FALSE;
     284             :             }
     285             :         }
     286             : 
     287         166 :         if (EQUAL(szLineBuf, "BLOCKS"))
     288             :         {
     289         163 :             if (!ReadBlocksSection())
     290           1 :                 return FALSE;
     291         162 :             if (ReadValue(szLineBuf) < 0)
     292             :             {
     293           0 :                 DXF_READER_ERROR();
     294           0 :                 return FALSE;
     295             :             }
     296             :         }
     297             :     }
     298             : 
     299         184 :     if (bHeaderOnly)
     300          57 :         return TRUE;
     301             : 
     302             :     /* -------------------------------------------------------------------- */
     303             :     /*      Now we are at the entities section, hopefully.  Confirm.        */
     304             :     /* -------------------------------------------------------------------- */
     305         127 :     if (EQUAL(szLineBuf, "SECTION"))
     306             :     {
     307         105 :         if (ReadValue(szLineBuf) < 0)
     308             :         {
     309           0 :             DXF_READER_ERROR();
     310           0 :             return FALSE;
     311             :         }
     312             :     }
     313             : 
     314         127 :     if (!EQUAL(szLineBuf, "ENTITIES"))
     315             :     {
     316           0 :         DXF_READER_ERROR();
     317           0 :         return FALSE;
     318             :     }
     319             : 
     320         127 :     iEntitiesOffset = oReader.iSrcBufferFileOffset + oReader.iSrcBufferOffset;
     321         127 :     iEntitiesLineNumber = oReader.nLineNumber;
     322         127 :     apoLayers[0]->ResetReading();
     323             : 
     324         127 :     return TRUE;
     325             : }
     326             : 
     327             : /************************************************************************/
     328             : /*                         ReadTablesSection()                          */
     329             : /************************************************************************/
     330             : 
     331         165 : bool OGRDXFDataSource::ReadTablesSection()
     332             : 
     333             : {
     334             :     char szLineBuf[257];
     335         165 :     int nCode = 0;
     336             : 
     337        3098 :     while ((nCode = ReadValue(szLineBuf, sizeof(szLineBuf))) > -1 &&
     338        1549 :            !EQUAL(szLineBuf, "ENDSEC"))
     339             :     {
     340             :         // We are only interested in extracting tables.
     341        1384 :         if (nCode != 0 || !EQUAL(szLineBuf, "TABLE"))
     342           0 :             continue;
     343             : 
     344        1384 :         nCode = ReadValue(szLineBuf, sizeof(szLineBuf));
     345        1384 :         if (nCode < 0)
     346             :         {
     347           0 :             DXF_READER_ERROR();
     348           0 :             return false;
     349             :         }
     350             : 
     351        1384 :         if (nCode != 2)
     352           0 :             continue;
     353             : 
     354             :         // CPLDebug( "DXF", "Found table %s.", szLineBuf );
     355             : 
     356       38362 :         while ((nCode = ReadValue(szLineBuf, sizeof(szLineBuf))) > -1 &&
     357       19181 :                !EQUAL(szLineBuf, "ENDTAB"))
     358             :         {
     359       17797 :             if (nCode == 0 && EQUAL(szLineBuf, "LAYER"))
     360             :             {
     361         174 :                 if (!ReadLayerDefinition())
     362           0 :                     return false;
     363             :             }
     364       17797 :             if (nCode == 0 && EQUAL(szLineBuf, "LTYPE"))
     365             :             {
     366         656 :                 if (!ReadLineTypeDefinition())
     367           0 :                     return false;
     368             :             }
     369       17797 :             if (nCode == 0 && EQUAL(szLineBuf, "STYLE"))
     370             :             {
     371         171 :                 if (!ReadTextStyleDefinition())
     372           0 :                     return false;
     373             :             }
     374       17797 :             if (nCode == 0 && EQUAL(szLineBuf, "DIMSTYLE"))
     375             :             {
     376         157 :                 if (!ReadDimStyleDefinition())
     377           0 :                     return false;
     378             :             }
     379             :         }
     380             :     }
     381         165 :     if (nCode < 0)
     382             :     {
     383           0 :         DXF_READER_ERROR();
     384           0 :         return false;
     385             :     }
     386             : 
     387         165 :     CPLDebug("DXF", "Read %d layer definitions.", (int)oLayerTable.size());
     388         165 :     return true;
     389             : }
     390             : 
     391             : /************************************************************************/
     392             : /*                        ReadLayerDefinition()                         */
     393             : /************************************************************************/
     394             : 
     395         174 : bool OGRDXFDataSource::ReadLayerDefinition()
     396             : 
     397             : {
     398             :     char szLineBuf[257];
     399         174 :     int nCode = 0;
     400         348 :     std::map<CPLString, CPLString> oLayerProperties;
     401         348 :     CPLString osLayerName = "";
     402             : 
     403         174 :     oLayerProperties["Hidden"] = "0";
     404             : 
     405        1844 :     while ((nCode = ReadValue(szLineBuf, sizeof(szLineBuf))) > 0)
     406             :     {
     407        1670 :         switch (nCode)
     408             :         {
     409         174 :             case 2:
     410             :                 osLayerName =
     411         174 :                     CPLString(szLineBuf).Recode(GetEncoding(), CPL_ENC_UTF8);
     412         174 :                 oLayerProperties["Exists"] = "1";
     413         174 :                 break;
     414             : 
     415         173 :             case 6:
     416         346 :                 oLayerProperties["Linetype"] =
     417         519 :                     CPLString(szLineBuf).Recode(GetEncoding(), CPL_ENC_UTF8);
     418         173 :                 break;
     419             : 
     420         174 :             case 62:
     421         174 :                 oLayerProperties["Color"] = szLineBuf;
     422             : 
     423             :                 // Is layer off?
     424         174 :                 if (atoi(szLineBuf) < 0 && oLayerProperties["Hidden"] != "2")
     425           2 :                     oLayerProperties["Hidden"] = "1";
     426         174 :                 break;
     427             : 
     428           1 :             case 420:
     429           1 :                 oLayerProperties["TrueColor"] = szLineBuf;
     430           1 :                 break;
     431             : 
     432         174 :             case 70:
     433         174 :                 oLayerProperties["Flags"] = szLineBuf;
     434             : 
     435             :                 // Is layer frozen?
     436         174 :                 if (atoi(szLineBuf) & 0x01)
     437           5 :                     oLayerProperties["Hidden"] = "2";
     438         174 :                 break;
     439             : 
     440         156 :             case 370:
     441             :             case 39:
     442         156 :                 oLayerProperties["LineWeight"] = szLineBuf;
     443         156 :                 break;
     444             : 
     445         818 :             default:
     446         818 :                 break;
     447             :         }
     448             :     }
     449         174 :     if (nCode < 0)
     450             :     {
     451           0 :         DXF_READER_ERROR();
     452           0 :         return false;
     453             :     }
     454             : 
     455         174 :     if (!oLayerProperties.empty())
     456         174 :         oLayerTable[osLayerName] = std::move(oLayerProperties);
     457             : 
     458         174 :     if (nCode == 0)
     459         174 :         UnreadValue();
     460         174 :     return true;
     461             : }
     462             : 
     463             : /************************************************************************/
     464             : /*                        LookupLayerProperty()                         */
     465             : /************************************************************************/
     466             : 
     467        5248 : const char *OGRDXFDataSource::LookupLayerProperty(const char *pszLayer,
     468             :                                                   const char *pszProperty)
     469             : 
     470             : {
     471        5248 :     if (pszLayer == nullptr)
     472           0 :         return nullptr;
     473             : 
     474             :     try
     475             :     {
     476        5248 :         return (oLayerTable[pszLayer])[pszProperty];
     477             :     }
     478           0 :     catch (...)
     479             :     {
     480           0 :         return nullptr;
     481             :     }
     482             : }
     483             : 
     484             : /************************************************************************/
     485             : /*                       ReadLineTypeDefinition()                       */
     486             : /************************************************************************/
     487             : 
     488         656 : bool OGRDXFDataSource::ReadLineTypeDefinition()
     489             : 
     490             : {
     491             :     char szLineBuf[257];
     492         656 :     int nCode = 0;
     493        1312 :     CPLString osLineTypeName;
     494        1312 :     std::vector<double> oLineTypeDef;
     495             :     double dfThisValue;
     496             : 
     497        8598 :     while ((nCode = ReadValue(szLineBuf, sizeof(szLineBuf))) > 0)
     498             :     {
     499        7942 :         switch (nCode)
     500             :         {
     501         656 :             case 2:
     502             :                 osLineTypeName =
     503         656 :                     CPLString(szLineBuf).Recode(GetEncoding(), CPL_ENC_UTF8);
     504         656 :                 break;
     505             : 
     506         834 :             case 49:
     507         834 :                 dfThisValue = CPLAtof(szLineBuf);
     508             : 
     509             :                 // Same sign as the previous entry? Continue the previous dash
     510             :                 // or gap by appending this length
     511        1452 :                 if (oLineTypeDef.size() > 0 &&
     512         618 :                     (dfThisValue < 0) == (oLineTypeDef.back() < 0))
     513             :                 {
     514           1 :                     oLineTypeDef.back() += dfThisValue;
     515             :                 }
     516             :                 // Otherwise, add a new entry
     517             :                 else
     518             :                 {
     519         833 :                     oLineTypeDef.push_back(dfThisValue);
     520             :                 }
     521             : 
     522         834 :                 break;
     523             : 
     524        6452 :             default:
     525        6452 :                 break;
     526             :         }
     527             :     }
     528         656 :     if (nCode < 0)
     529             :     {
     530           0 :         DXF_READER_ERROR();
     531           0 :         return false;
     532             :     }
     533             : 
     534             :     // Deal with an odd number of elements by adding the last element
     535             :     // onto the first
     536         656 :     if (oLineTypeDef.size() % 2 == 1)
     537             :     {
     538           1 :         oLineTypeDef.front() += oLineTypeDef.back();
     539           1 :         oLineTypeDef.pop_back();
     540             :     }
     541             : 
     542         656 :     if (oLineTypeDef.size())
     543             :     {
     544             :         // If the first element is a gap, rotate the elements so the first
     545             :         // element is a dash
     546         216 :         if (oLineTypeDef.front() < 0)
     547             :         {
     548           2 :             std::rotate(oLineTypeDef.begin(), oLineTypeDef.begin() + 1,
     549           2 :                         oLineTypeDef.end());
     550             :         }
     551             : 
     552         216 :         oLineTypeTable[osLineTypeName] = std::move(oLineTypeDef);
     553             :     }
     554             : 
     555         656 :     if (nCode == 0)
     556         656 :         UnreadValue();
     557         656 :     return true;
     558             : }
     559             : 
     560             : /************************************************************************/
     561             : /*                           LookupLineType()                           */
     562             : /************************************************************************/
     563             : 
     564        1152 : std::vector<double> OGRDXFDataSource::LookupLineType(const char *pszName)
     565             : 
     566             : {
     567        1152 :     if (pszName && oLineTypeTable.count(pszName) > 0)
     568          47 :         return oLineTypeTable[pszName];
     569             :     else
     570        1105 :         return std::vector<double>();  // empty, represents a continuous line
     571             : }
     572             : 
     573             : /************************************************************************/
     574             : /*                       ReadTextStyleDefinition()                      */
     575             : /************************************************************************/
     576             : 
     577         171 : bool OGRDXFDataSource::ReadTextStyleDefinition()
     578             : 
     579             : {
     580             :     char szLineBuf[257];
     581         171 :     int nCode = 0;
     582             : 
     583         342 :     CPLString osStyleHandle;
     584         342 :     CPLString osStyleName;
     585         171 :     bool bInsideAcadSection = false;
     586             : 
     587        2325 :     while ((nCode = ReadValue(szLineBuf, sizeof(szLineBuf))) > 0)
     588             :     {
     589        2154 :         switch (nCode)
     590             :         {
     591         154 :             case 5:
     592         154 :                 osStyleHandle = szLineBuf;
     593         154 :                 break;
     594             : 
     595         171 :             case 2:
     596         342 :                 osStyleName = CPLString(szLineBuf)
     597         171 :                                   .Recode(GetEncoding(), CPL_ENC_UTF8)
     598         171 :                                   .toupper();
     599         171 :                 break;
     600             : 
     601         169 :             case 70:
     602             :                 // If the LSB is set, this is not a text style
     603         169 :                 if (atoi(szLineBuf) & 1)
     604           0 :                     return true;
     605         169 :                 break;
     606             : 
     607             :                 // Note: 40 and 41 group codes do not propagate from a text
     608             :                 // style down to TEXT objects. However, 41 does propagate down
     609             :                 // for MTEXT.
     610             : 
     611         171 :             case 41:
     612         171 :                 oTextStyleTable[osStyleName]["Width"] = szLineBuf;
     613         171 :                 break;
     614             : 
     615          10 :             case 1001:
     616          10 :                 bInsideAcadSection = EQUAL(szLineBuf, "ACAD");
     617          10 :                 break;
     618             : 
     619          10 :             case 1000:
     620          10 :                 if (bInsideAcadSection)
     621          10 :                     oTextStyleTable[osStyleName]["Font"] = szLineBuf;
     622          10 :                 break;
     623             : 
     624          10 :             case 1071:
     625             :                 // bold and italic are kept in this undocumented bitfield
     626          10 :                 if (bInsideAcadSection)
     627             :                 {
     628          10 :                     const int nFontFlags = atoi(szLineBuf);
     629          20 :                     oTextStyleTable[osStyleName]["Bold"] =
     630          30 :                         (nFontFlags & 0x2000000) ? "1" : "0";
     631          20 :                     oTextStyleTable[osStyleName]["Italic"] =
     632          30 :                         (nFontFlags & 0x1000000) ? "1" : "0";
     633             :                 }
     634          10 :                 break;
     635             : 
     636        1459 :             default:
     637        1459 :                 break;
     638             :         }
     639             :     }
     640         171 :     if (nCode < 0)
     641             :     {
     642           0 :         DXF_READER_ERROR();
     643           0 :         return false;
     644             :     }
     645             : 
     646         171 :     if (nCode == 0)
     647         171 :         UnreadValue();
     648             : 
     649         171 :     if (osStyleHandle != "")
     650         154 :         oTextStyleHandles[osStyleHandle] = std::move(osStyleName);
     651             : 
     652         171 :     return true;
     653             : }
     654             : 
     655             : /************************************************************************/
     656             : /*                           TextStyleExists()                          */
     657             : /************************************************************************/
     658             : 
     659           1 : bool OGRDXFDataSource::TextStyleExists(const char *pszTextStyle)
     660             : 
     661             : {
     662           1 :     if (!pszTextStyle)
     663           0 :         return false;
     664             : 
     665           1 :     CPLString osTextStyleUpper = pszTextStyle;
     666           1 :     osTextStyleUpper.toupper();
     667             : 
     668           1 :     return oTextStyleTable.count(osTextStyleUpper) > 0;
     669             : }
     670             : 
     671             : /************************************************************************/
     672             : /*                       LookupTextStyleProperty()                      */
     673             : /************************************************************************/
     674             : 
     675         389 : const char *OGRDXFDataSource::LookupTextStyleProperty(const char *pszTextStyle,
     676             :                                                       const char *pszProperty,
     677             :                                                       const char *pszDefault)
     678             : 
     679             : {
     680         389 :     if (!pszTextStyle)
     681           0 :         return pszDefault;
     682             : 
     683         778 :     CPLString osTextStyleUpper = pszTextStyle;
     684         389 :     osTextStyleUpper.toupper();
     685             : 
     686         641 :     if (pszProperty && oTextStyleTable.count(osTextStyleUpper) > 0 &&
     687         641 :         oTextStyleTable[osTextStyleUpper].count(pszProperty) > 0)
     688             :     {
     689          54 :         return (oTextStyleTable[osTextStyleUpper])[pszProperty];
     690             :     }
     691             :     else
     692             :     {
     693         335 :         return pszDefault;
     694             :     }
     695             : }
     696             : 
     697             : /************************************************************************/
     698             : /*                      GetTextStyleNameByHandle()                      */
     699             : /*                                                                      */
     700             : /*      Find the name of the text style with the given STYLE table      */
     701             : /*      handle. If there is no such style, an empty string is returned. */
     702             : /************************************************************************/
     703             : 
     704          10 : CPLString OGRDXFDataSource::GetTextStyleNameByHandle(const char *pszID)
     705             : 
     706             : {
     707          20 :     CPLString l_osID = pszID;
     708             : 
     709          10 :     if (oTextStyleHandles.count(l_osID) == 0)
     710           6 :         return "";
     711             :     else
     712           4 :         return oTextStyleHandles[l_osID];
     713             : }
     714             : 
     715             : /************************************************************************/
     716             : /*                  PopulateDefaultDimStyleProperties()                 */
     717             : /************************************************************************/
     718             : 
     719         217 : void OGRDXFDataSource::PopulateDefaultDimStyleProperties(
     720             :     std::map<CPLString, CPLString> &oDimStyleProperties)
     721             : 
     722             : {
     723         217 :     const int *piCode = ACGetKnownDimStyleCodes();
     724        2604 :     do
     725             :     {
     726        2821 :         const char *pszProperty = ACGetDimStylePropertyName(*piCode);
     727        5642 :         oDimStyleProperties[pszProperty] =
     728        8463 :             ACGetDimStylePropertyDefault(*piCode);
     729        2821 :     } while (*(++piCode));
     730         217 : }
     731             : 
     732             : /************************************************************************/
     733             : /*                       ReadDimStyleDefinition()                       */
     734             : /************************************************************************/
     735             : 
     736         157 : bool OGRDXFDataSource::ReadDimStyleDefinition()
     737             : 
     738             : {
     739             :     char szLineBuf[257];
     740         157 :     int nCode = 0;
     741         314 :     std::map<CPLString, CPLString> oDimStyleProperties;
     742         314 :     CPLString osDimStyleName = "";
     743             : 
     744         157 :     PopulateDefaultDimStyleProperties(oDimStyleProperties);
     745             : 
     746        1723 :     while ((nCode = ReadValue(szLineBuf, sizeof(szLineBuf))) > 0)
     747             :     {
     748        1566 :         switch (nCode)
     749             :         {
     750         157 :             case 2:
     751             :                 osDimStyleName =
     752         157 :                     CPLString(szLineBuf).Recode(GetEncoding(), CPL_ENC_UTF8);
     753         157 :                 break;
     754             : 
     755        1409 :             default:
     756        1409 :                 const char *pszProperty = ACGetDimStylePropertyName(nCode);
     757        1409 :                 if (pszProperty)
     758         162 :                     oDimStyleProperties[pszProperty] = szLineBuf;
     759        1409 :                 break;
     760             :         }
     761             :     }
     762         157 :     if (nCode < 0)
     763             :     {
     764           0 :         DXF_READER_ERROR();
     765           0 :         return false;
     766             :     }
     767             : 
     768         157 :     if (!oDimStyleProperties.empty())
     769         157 :         oDimStyleTable[osDimStyleName] = std::move(oDimStyleProperties);
     770             : 
     771         157 :     if (nCode == 0)
     772         157 :         UnreadValue();
     773         157 :     return true;
     774             : }
     775             : 
     776             : /************************************************************************/
     777             : /*                           LookupDimStyle()                           */
     778             : /*                                                                      */
     779             : /*      If the specified DIMSTYLE does not exist, a default set of      */
     780             : /*      of style properties are copied into oDimStyleProperties and     */
     781             : /*      false is returned.  Otherwise true is returned.                 */
     782             : /************************************************************************/
     783             : 
     784          42 : bool OGRDXFDataSource::LookupDimStyle(
     785             :     const char *pszDimStyle,
     786             :     std::map<CPLString, CPLString> &oDimStyleProperties)
     787             : 
     788             : {
     789          42 :     if (pszDimStyle == nullptr || !oDimStyleTable.count(pszDimStyle))
     790             :     {
     791          16 :         PopulateDefaultDimStyleProperties(oDimStyleProperties);
     792          16 :         return false;
     793             :     }
     794             : 
     795             :     // make a copy of the DIMSTYLE properties, so no-one can mess around
     796             :     // with our original copy
     797          26 :     oDimStyleProperties = oDimStyleTable[pszDimStyle];
     798          26 :     return true;
     799             : }
     800             : 
     801             : /************************************************************************/
     802             : /*                         ReadHeaderSection()                          */
     803             : /************************************************************************/
     804             : 
     805         157 : bool OGRDXFDataSource::ReadHeaderSection()
     806             : 
     807             : {
     808             :     char szLineBuf[257];
     809         157 :     int nCode = 0;
     810             : 
     811       44332 :     while ((nCode = ReadValue(szLineBuf, sizeof(szLineBuf))) > -1 &&
     812       22166 :            !EQUAL(szLineBuf, "ENDSEC"))
     813             :     {
     814       22009 :         if (nCode != 9)
     815        6176 :             continue;
     816             : 
     817       15833 :         CPLString l_osName = szLineBuf;
     818             : 
     819       15833 :         if (ReadValue(szLineBuf, sizeof(szLineBuf)) < 0)
     820             :         {
     821           0 :             DXF_READER_ERROR();
     822           0 :             return false;
     823             :         }
     824             : 
     825       15833 :         oHeaderVariables[l_osName] = szLineBuf;
     826       15833 :         GDALDataset::SetMetadataItem(l_osName.c_str(), szLineBuf,
     827             :                                      "DXF_HEADER_VARIABLES");
     828             :     }
     829         157 :     if (nCode < 0)
     830             :     {
     831           0 :         DXF_READER_ERROR();
     832           0 :         return false;
     833             :     }
     834             : 
     835         157 :     nCode = ReadValue(szLineBuf, sizeof(szLineBuf));
     836         157 :     if (nCode < 0)
     837             :     {
     838           0 :         DXF_READER_ERROR();
     839           0 :         return false;
     840             :     }
     841         157 :     UnreadValue();
     842             : 
     843             :     /* Unusual DXF files produced by dxflib */
     844             :     /* such as http://www.ribbonsoft.com/library/architecture/plants/decd5.dxf
     845             :      */
     846             :     /* where there is a spurious ENDSEC in the middle of the header variables */
     847         157 :     if (nCode == 9 && STARTS_WITH_CI(szLineBuf, "$"))
     848             :     {
     849           0 :         while ((nCode = ReadValue(szLineBuf, sizeof(szLineBuf))) > -1 &&
     850           0 :                !EQUAL(szLineBuf, "ENDSEC"))
     851             :         {
     852           0 :             if (nCode != 9)
     853           0 :                 continue;
     854             : 
     855           0 :             CPLString l_osName = szLineBuf;
     856             : 
     857           0 :             if (ReadValue(szLineBuf, sizeof(szLineBuf)) < 0)
     858             :             {
     859           0 :                 DXF_READER_ERROR();
     860           0 :                 return false;
     861             :             }
     862             : 
     863           0 :             oHeaderVariables[l_osName] = szLineBuf;
     864           0 :             GDALDataset::SetMetadataItem(l_osName.c_str(), szLineBuf,
     865             :                                          "DXF_HEADER_VARIABLES");
     866             :         }
     867           0 :         if (nCode < 0)
     868             :         {
     869           0 :             DXF_READER_ERROR();
     870           0 :             return false;
     871             :         }
     872             :     }
     873             : 
     874         157 :     CPLDebug("DXF", "Read %d header variables.", (int)oHeaderVariables.size());
     875             : 
     876             :     /* -------------------------------------------------------------------- */
     877             :     /*      Decide on what CPLRecode() name to use for the files            */
     878             :     /*      encoding or allow the encoding to be overridden.                */
     879             :     /* -------------------------------------------------------------------- */
     880         157 :     CPLString osCodepage = GetVariable("$DWGCODEPAGE", "ANSI_1252");
     881             : 
     882             :     // not strictly accurate but works even without iconv.
     883         157 :     if (osCodepage == "ANSI_1252")
     884         157 :         osEncoding = CPL_ENC_ISO8859_1;
     885           0 :     else if (STARTS_WITH_CI(osCodepage, "ANSI_"))
     886             :     {
     887           0 :         osEncoding = "CP";
     888           0 :         osEncoding += osCodepage + 5;
     889             :     }
     890             :     else
     891             :     {
     892             :         // fallback to the default
     893           0 :         osEncoding = CPL_ENC_ISO8859_1;
     894             :     }
     895             : 
     896         157 :     const char *pszEncoding = CPLGetConfigOption("DXF_ENCODING", nullptr);
     897         157 :     if (pszEncoding != nullptr)
     898           0 :         osEncoding = pszEncoding;
     899             : 
     900         157 :     if (osEncoding != CPL_ENC_ISO8859_1)
     901           0 :         CPLDebug("DXF", "Treating DXF as encoding '%s', $DWGCODEPAGE='%s'",
     902             :                  osEncoding.c_str(), osCodepage.c_str());
     903         157 :     return true;
     904             : }
     905             : 
     906             : /************************************************************************/
     907             : /*                            GetVariable()                             */
     908             : /*                                                                      */
     909             : /*      Fetch a variable that came from the HEADER section.             */
     910             : /************************************************************************/
     911             : 
     912        1302 : const char *OGRDXFDataSource::GetVariable(const char *pszName,
     913             :                                           const char *pszDefault)
     914             : 
     915             : {
     916        1302 :     if (oHeaderVariables.count(pszName) == 0)
     917        1116 :         return pszDefault;
     918             :     else
     919         186 :         return oHeaderVariables[pszName];
     920             : }
     921             : 
     922             : /************************************************************************/
     923             : /*                         AddStandardFields()                          */
     924             : /************************************************************************/
     925             : 
     926         262 : void OGRDXFDataSource::AddStandardFields(OGRFeatureDefn *poFeatureDefn,
     927             :                                          const int nFieldModes)
     928             : {
     929         524 :     OGRFieldDefn oLayerField("Layer", OFTString);
     930         262 :     poFeatureDefn->AddFieldDefn(&oLayerField);
     931             : 
     932         524 :     OGRFieldDefn oPaperSpaceField("PaperSpace", OFTInteger);
     933         262 :     oPaperSpaceField.SetSubType(OFSTBoolean);
     934         262 :     poFeatureDefn->AddFieldDefn(&oPaperSpaceField);
     935             : 
     936         524 :     OGRFieldDefn oClassField("SubClasses", OFTString);
     937         262 :     poFeatureDefn->AddFieldDefn(&oClassField);
     938             : 
     939         262 :     if (nFieldModes & ODFM_IncludeRawCodeValues)
     940             :     {
     941           2 :         OGRFieldDefn oRawCodeField("RawCodeValues", OFTStringList);
     942           1 :         poFeatureDefn->AddFieldDefn(&oRawCodeField);
     943             :     }
     944             : 
     945         524 :     OGRFieldDefn oLinetypeField("Linetype", OFTString);
     946         262 :     poFeatureDefn->AddFieldDefn(&oLinetypeField);
     947             : 
     948         524 :     OGRFieldDefn oEntityHandleField("EntityHandle", OFTString);
     949         262 :     poFeatureDefn->AddFieldDefn(&oEntityHandleField);
     950             : 
     951         524 :     OGRFieldDefn oTextField("Text", OFTString);
     952         262 :     poFeatureDefn->AddFieldDefn(&oTextField);
     953             : 
     954         262 :     if (nFieldModes & ODFM_Include3DModeFields)
     955             :     {
     956           2 :         OGRFieldDefn oASMBinaryField("ASMData", OFTBinary);
     957           1 :         poFeatureDefn->AddFieldDefn(&oASMBinaryField);
     958             : 
     959           2 :         OGRFieldDefn oASMTransformField("ASMTransform", OFTRealList);
     960           1 :         poFeatureDefn->AddFieldDefn(&oASMTransformField);
     961             :     }
     962             : 
     963         262 :     if (nFieldModes & ODFM_IncludeBlockFields)
     964             :     {
     965         164 :         OGRFieldDefn oBlockNameField("BlockName", OFTString);
     966          82 :         poFeatureDefn->AddFieldDefn(&oBlockNameField);
     967             : 
     968         164 :         OGRFieldDefn oScaleField("BlockScale", OFTRealList);
     969          82 :         poFeatureDefn->AddFieldDefn(&oScaleField);
     970             : 
     971         164 :         OGRFieldDefn oBlockAngleField("BlockAngle", OFTReal);
     972          82 :         poFeatureDefn->AddFieldDefn(&oBlockAngleField);
     973             : 
     974         164 :         OGRFieldDefn oBlockOCSNormalField("BlockOCSNormal", OFTRealList);
     975          82 :         poFeatureDefn->AddFieldDefn(&oBlockOCSNormalField);
     976             : 
     977         164 :         OGRFieldDefn oBlockOCSCoordsField("BlockOCSCoords", OFTRealList);
     978          82 :         poFeatureDefn->AddFieldDefn(&oBlockOCSCoordsField);
     979             : 
     980         164 :         OGRFieldDefn oBlockAttribsField("BlockAttributes", OFTStringList);
     981          82 :         poFeatureDefn->AddFieldDefn(&oBlockAttribsField);
     982             : 
     983             :         // This field holds the name of the block on which the entity lies.
     984             :         // The BlockName field was previously used for this purpose; this
     985             :         // was changed because of the ambiguity with the BlockName field
     986             :         // used by INSERT entities.
     987         164 :         OGRFieldDefn oBlockField("Block", OFTString);
     988          82 :         poFeatureDefn->AddFieldDefn(&oBlockField);
     989             : 
     990             :         // Extra field to use with ATTDEF entities
     991         164 :         OGRFieldDefn oAttributeTagField("AttributeTag", OFTString);
     992          82 :         poFeatureDefn->AddFieldDefn(&oAttributeTagField);
     993             :     }
     994         262 : }
     995             : 
     996             : /************************************************************************/
     997             : /*                    GetEntryFromAcDsDataSection()                     */
     998             : /************************************************************************/
     999             : 
    1000             : size_t
    1001           2 : OGRDXFDataSource::GetEntryFromAcDsDataSection(const char *pszEntityHandle,
    1002             :                                               const GByte **pabyBuffer)
    1003             : 
    1004             : {
    1005           2 :     if (!pszEntityHandle || !pabyBuffer)
    1006           0 :         return 0;
    1007             : 
    1008           2 :     if (bHaveReadSolidData)
    1009             :     {
    1010           1 :         if (oSolidBinaryData.count(pszEntityHandle) > 0)
    1011             :         {
    1012           1 :             *pabyBuffer = oSolidBinaryData[pszEntityHandle].data();
    1013           1 :             return oSolidBinaryData[pszEntityHandle].size();
    1014             :         }
    1015           0 :         return 0;
    1016             :     }
    1017             : 
    1018             :     // Keep track of our current position and line number in the file so we can
    1019             :     // return here later
    1020           1 :     unsigned int iPrevOffset =
    1021           1 :         oReader.iSrcBufferFileOffset + oReader.iSrcBufferOffset;
    1022           1 :     int nPrevLineNumber = oReader.nLineNumber;
    1023             : 
    1024             :     char szLineBuf[4096];
    1025           1 :     int nCode = 0;
    1026           1 :     bool bFound = false;
    1027             : 
    1028             :     // Search for the ACDSDATA section
    1029         313 :     while ((nCode = ReadValue(szLineBuf, sizeof(szLineBuf))) >= 0)
    1030             :     {
    1031             :         // Check whether the ACDSDATA section starts here
    1032         313 :         if (nCode == 0 && EQUAL(szLineBuf, "SECTION"))
    1033             :         {
    1034           3 :             if ((nCode = ReadValue(szLineBuf, sizeof(szLineBuf))) < 0)
    1035             :             {
    1036           0 :                 break;
    1037             :             }
    1038             : 
    1039           3 :             if (nCode == 2 && EQUAL(szLineBuf, "ACDSDATA"))
    1040             :             {
    1041           1 :                 bFound = true;
    1042           1 :                 break;
    1043             :             }
    1044             :         }
    1045             :     }
    1046             : 
    1047           1 :     if (!bFound)
    1048             :     {
    1049           0 :         oReader.ResetReadPointer(iPrevOffset, nPrevLineNumber);
    1050           0 :         return 0;
    1051             :     }
    1052             : 
    1053           1 :     bool bInAcDsRecord = false;
    1054           1 :     bool bGotAsmData = false;
    1055           2 :     CPLString osThisHandle;
    1056             : 
    1057             :     // Search for the relevant ACDSRECORD and extract its binary data
    1058         129 :     while ((nCode = ReadValue(szLineBuf, sizeof(szLineBuf))) >= 0)
    1059             :     {
    1060         128 :         if (nCode == 0 && EQUAL(szLineBuf, "ENDSEC"))
    1061             :         {
    1062             :             // We've reached the end of the ACDSDATA section
    1063             :             break;
    1064             :         }
    1065         128 :         else if (nCode == 0)
    1066             :         {
    1067           9 :             bInAcDsRecord = EQUAL(szLineBuf, "ACDSRECORD");
    1068           9 :             bGotAsmData = false;
    1069           9 :             osThisHandle.clear();
    1070             :         }
    1071         119 :         else if (bInAcDsRecord && nCode == 320)
    1072             :         {
    1073           3 :             osThisHandle = szLineBuf;
    1074             :         }
    1075         116 :         else if (bInAcDsRecord && nCode == 2)
    1076             :         {
    1077           6 :             bGotAsmData = EQUAL(szLineBuf, "ASM_Data");
    1078             :         }
    1079         110 :         else if (bInAcDsRecord && bGotAsmData && nCode == 94)
    1080             :         {
    1081             :             // Group code 94 gives the length of the binary data that follows
    1082           2 :             int nLen = atoi(szLineBuf);
    1083             : 
    1084             :             // Enforce some limits (the upper limit is arbitrary)
    1085           2 :             if (nLen <= 0 || nLen > 1048576)
    1086             :             {
    1087           0 :                 CPLError(CE_Warning, CPLE_AppDefined,
    1088             :                          "ACDSRECORD data for entity %s is too long (more than "
    1089             :                          "1MB in size) and was skipped.",
    1090             :                          pszEntityHandle);
    1091           0 :                 continue;
    1092             :             }
    1093             : 
    1094           2 :             oSolidBinaryData[osThisHandle].resize(nLen);
    1095             : 
    1096             :             // Read the binary data into the buffer
    1097           2 :             int nPos = 0;
    1098          14 :             while (ReadValue(szLineBuf, sizeof(szLineBuf)) == 310)
    1099             :             {
    1100             :                 int nBytesRead;
    1101          12 :                 GByte *pabyHex = CPLHexToBinary(szLineBuf, &nBytesRead);
    1102             : 
    1103          12 :                 if (nPos + nBytesRead > nLen)
    1104             :                 {
    1105           0 :                     CPLError(CE_Warning, CPLE_AppDefined,
    1106             :                              "Too many bytes in ACDSRECORD data for entity %s. "
    1107             :                              "Is the length (group code 94) correct?",
    1108             :                              pszEntityHandle);
    1109           0 :                     break;
    1110             :                 }
    1111             :                 else
    1112             :                 {
    1113             :                     std::copy_n(pabyHex, nBytesRead,
    1114          12 :                                 oSolidBinaryData[osThisHandle].begin() + nPos);
    1115          12 :                     nPos += nBytesRead;
    1116             :                 }
    1117             : 
    1118          12 :                 CPLFree(pabyHex);
    1119             :             }
    1120             :         }
    1121             :     }
    1122             : 
    1123           1 :     oReader.ResetReadPointer(iPrevOffset, nPrevLineNumber);
    1124             : 
    1125           1 :     bHaveReadSolidData = true;
    1126             : 
    1127           1 :     if (oSolidBinaryData.count(pszEntityHandle) > 0)
    1128             :     {
    1129           1 :         *pabyBuffer = oSolidBinaryData[pszEntityHandle].data();
    1130           1 :         return oSolidBinaryData[pszEntityHandle].size();
    1131             :     }
    1132           0 :     return 0;
    1133             : }

Generated by: LCOV version 1.14