LCOV - code coverage report
Current view: top level - ogr/ogrsf_frmts/dxf - ogrdxfdatasource.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 402 491 81.9 %
Date: 2026-05-29 23:25:07 Functions: 22 22 100.0 %

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

Generated by: LCOV version 1.14