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

Generated by: LCOV version 1.14