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

Generated by: LCOV version 1.14