LCOV - code coverage report
Current view: top level - ogr/ogrsf_frmts/dxf - ogrdxfwriterds.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 357 428 83.4 %
Date: 2024-11-21 22:18:42 Functions: 20 22 90.9 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  DXF Translator
       4             :  * Purpose:  Implements OGRDXFWriterDS - the OGRDataSource class used for
       5             :  *           writing a DXF file.
       6             :  * Author:   Frank Warmerdam, warmerdam@pobox.com
       7             :  *
       8             :  ******************************************************************************
       9             :  * Copyright (c) 2009, Frank Warmerdam <warmerdam@pobox.com>
      10             :  * Copyright (c) 2010-2012, Even Rouault <even dot rouault at spatialys.com>
      11             :  *
      12             :  * SPDX-License-Identifier: MIT
      13             :  ****************************************************************************/
      14             : 
      15             : #include "cpl_port.h"
      16             : 
      17             : #include <cmath>
      18             : #include <cstdlib>
      19             : #include <limits>
      20             : 
      21             : #include "ogr_dxf.h"
      22             : #include "cpl_conv.h"
      23             : #include "cpl_string.h"
      24             : #include "cpl_vsi_error.h"
      25             : 
      26             : #ifdef EMBED_RESOURCE_FILES
      27             : #include "embedded_resources.h"
      28             : #endif
      29             : 
      30             : /************************************************************************/
      31             : /*                          OGRDXFWriterDS()                          */
      32             : /************************************************************************/
      33             : 
      34          45 : OGRDXFWriterDS::OGRDXFWriterDS()
      35             :     : nNextFID(80), poLayer(nullptr), poBlocksLayer(nullptr), fp(nullptr),
      36          45 :       fpTemp(nullptr), papszLayersToCreate(nullptr), nHANDSEEDOffset(0)
      37             : {
      38          45 : }
      39             : 
      40             : /************************************************************************/
      41             : /*                         ~OGRDXFWriterDS()                          */
      42             : /************************************************************************/
      43             : 
      44          90 : OGRDXFWriterDS::~OGRDXFWriterDS()
      45             : 
      46             : {
      47          45 :     if (fp != nullptr)
      48             :     {
      49             :         /* --------------------------------------------------------------------
      50             :          */
      51             :         /*      Transfer over the header into the destination file with any */
      52             :         /*      adjustments or insertions needed. */
      53             :         /* --------------------------------------------------------------------
      54             :          */
      55          44 :         CPLDebug("DXF", "Compose final DXF file from components.");
      56             : 
      57          44 :         if (IsMarkedSuppressOnClose() && fpTemp != nullptr)
      58             :         {
      59           1 :             CPLDebug("DXF", "Do not copy final DXF when 'suppress on close'.");
      60           1 :             VSIFCloseL(fpTemp);
      61           1 :             VSIUnlink(osTempFilename);
      62           1 :             fpTemp = nullptr;
      63             :         }
      64             : 
      65          44 :         TransferUpdateHeader(fp);
      66             : 
      67          44 :         if (fpTemp != nullptr)
      68             :         {
      69             :             /* --------------------------------------------------------------------
      70             :              */
      71             :             /*      Copy in the temporary file contents. */
      72             :             /* --------------------------------------------------------------------
      73             :              */
      74          43 :             VSIFCloseL(fpTemp);
      75          43 :             fpTemp = VSIFOpenL(osTempFilename, "r");
      76             : 
      77          43 :             const char *pszLine = nullptr;
      78        2059 :             while ((pszLine = CPLReadLineL(fpTemp)) != nullptr)
      79             :             {
      80        2016 :                 VSIFWriteL(pszLine, 1, strlen(pszLine), fp);
      81        2016 :                 VSIFWriteL("\n", 1, 1, fp);
      82             :             }
      83             : 
      84             :             /* --------------------------------------------------------------------
      85             :              */
      86             :             /*      Cleanup temporary file. */
      87             :             /* --------------------------------------------------------------------
      88             :              */
      89          43 :             VSIFCloseL(fpTemp);
      90          43 :             VSIUnlink(osTempFilename);
      91             :         }
      92             : 
      93             :         /* --------------------------------------------------------------------
      94             :          */
      95             :         /*      Write trailer. */
      96             :         /* --------------------------------------------------------------------
      97             :          */
      98          44 :         if (osTrailerFile != "")
      99          44 :             TransferUpdateTrailer(fp);
     100             : 
     101             :         /* --------------------------------------------------------------------
     102             :          */
     103             :         /*      Fixup the HANDSEED value now that we know all the entity ids */
     104             :         /*      created. */
     105             :         /* --------------------------------------------------------------------
     106             :          */
     107          44 :         FixupHANDSEED(fp);
     108             : 
     109             :         /* --------------------------------------------------------------------
     110             :          */
     111             :         /*      Close file. */
     112             :         /* --------------------------------------------------------------------
     113             :          */
     114             : 
     115          44 :         VSIFCloseL(fp);
     116          44 :         fp = nullptr;
     117             :     }
     118             : 
     119             :     /* -------------------------------------------------------------------- */
     120             :     /*      Destroy layers.                                                 */
     121             :     /* -------------------------------------------------------------------- */
     122          45 :     delete poLayer;
     123          45 :     delete poBlocksLayer;
     124             : 
     125          45 :     CSLDestroy(papszLayersToCreate);
     126             : 
     127          45 :     if (m_bHeaderFileIsTemp)
     128           0 :         VSIUnlink(osHeaderFile.c_str());
     129          45 :     if (m_bTrailerFileIsTemp)
     130           0 :         VSIUnlink(osTrailerFile.c_str());
     131          90 : }
     132             : 
     133             : /************************************************************************/
     134             : /*                           TestCapability()                           */
     135             : /************************************************************************/
     136             : 
     137          48 : int OGRDXFWriterDS::TestCapability(const char *pszCap)
     138             : 
     139             : {
     140          48 :     if (EQUAL(pszCap, ODsCCreateLayer))
     141             :         // Unable to have more than one OGR entities layer in a DXF file, with
     142             :         // one options blocks layer.
     143          32 :         return poBlocksLayer == nullptr || poLayer == nullptr;
     144             :     else
     145          16 :         return FALSE;
     146             : }
     147             : 
     148             : /************************************************************************/
     149             : /*                              GetLayer()                              */
     150             : /************************************************************************/
     151             : 
     152           0 : OGRLayer *OGRDXFWriterDS::GetLayer(int iLayer)
     153             : 
     154             : {
     155           0 :     if (iLayer == 0)
     156           0 :         return poLayer;
     157             :     else
     158           0 :         return nullptr;
     159             : }
     160             : 
     161             : /************************************************************************/
     162             : /*                           GetLayerCount()                            */
     163             : /************************************************************************/
     164             : 
     165           0 : int OGRDXFWriterDS::GetLayerCount()
     166             : 
     167             : {
     168           0 :     if (poLayer)
     169           0 :         return 1;
     170             :     else
     171           0 :         return 0;
     172             : }
     173             : 
     174             : /************************************************************************/
     175             : /*                                Open()                                */
     176             : /************************************************************************/
     177             : 
     178          45 : int OGRDXFWriterDS::Open(const char *pszFilename, char **papszOptions)
     179             : 
     180             : {
     181             :     /* -------------------------------------------------------------------- */
     182             :     /*      Open the standard header, or a user provided header.            */
     183             :     /* -------------------------------------------------------------------- */
     184          45 :     if (CSLFetchNameValue(papszOptions, "HEADER") != nullptr)
     185           3 :         osHeaderFile = CSLFetchNameValue(papszOptions, "HEADER");
     186             :     else
     187             :     {
     188             : #ifdef EMBED_RESOURCE_FILES
     189             :         CPLErrorStateBackuper oErrorStateBackuper(CPLQuietErrorHandler);
     190             : #endif
     191             : #ifdef USE_ONLY_EMBEDDED_RESOURCE_FILES
     192             :         const char *pszValue = nullptr;
     193             : #else
     194          42 :         const char *pszValue = CPLFindFile("gdal", "header.dxf");
     195          42 :         if (pszValue == nullptr)
     196             : #endif
     197             :         {
     198             : #ifdef EMBED_RESOURCE_FILES
     199             :             static const bool bOnce [[maybe_unused]] = []()
     200             :             {
     201             :                 CPLDebug("DXF", "Using embedded header.dxf");
     202             :                 return true;
     203             :             }();
     204             :             pszValue = VSIMemGenerateHiddenFilename("header.dxf");
     205             :             VSIFCloseL(VSIFileFromMemBuffer(
     206             :                 pszValue,
     207             :                 const_cast<GByte *>(
     208             :                     reinterpret_cast<const GByte *>(OGRDXFGetHEADER())),
     209             :                 static_cast<int>(strlen(OGRDXFGetHEADER())),
     210             :                 /* bTakeOwnership = */ false));
     211             :             m_bHeaderFileIsTemp = true;
     212             : #else
     213           0 :             CPLError(CE_Failure, CPLE_OpenFailed,
     214             :                      "Failed to find template header file header.dxf for "
     215             :                      "reading,\nis GDAL_DATA set properly?");
     216           0 :             return FALSE;
     217             : #endif
     218             :         }
     219          42 :         osHeaderFile = pszValue;
     220             :     }
     221             : 
     222             :     /* -------------------------------------------------------------------- */
     223             :     /*      Establish the name for our trailer file.                        */
     224             :     /* -------------------------------------------------------------------- */
     225          45 :     if (CSLFetchNameValue(papszOptions, "TRAILER") != nullptr)
     226           0 :         osTrailerFile = CSLFetchNameValue(papszOptions, "TRAILER");
     227             :     else
     228             :     {
     229             : #ifdef EMBED_RESOURCE_FILES
     230             :         CPLErrorStateBackuper oErrorStateBackuper(CPLQuietErrorHandler);
     231             : #endif
     232             : #ifdef USE_ONLY_EMBEDDED_RESOURCE_FILES
     233             :         const char *pszValue = nullptr;
     234             : #else
     235          45 :         const char *pszValue = CPLFindFile("gdal", "trailer.dxf");
     236          45 :         if (pszValue != nullptr)
     237          45 :             osTrailerFile = pszValue;
     238             : #endif
     239             : #ifdef EMBED_RESOURCE_FILES
     240             :         if (!pszValue)
     241             :         {
     242             :             static const bool bOnce [[maybe_unused]] = []()
     243             :             {
     244             :                 CPLDebug("DXF", "Using embedded trailer.dxf");
     245             :                 return true;
     246             :             }();
     247             :             osTrailerFile = VSIMemGenerateHiddenFilename("trailer.dxf");
     248             :             m_bTrailerFileIsTemp = false;
     249             :             VSIFCloseL(VSIFileFromMemBuffer(
     250             :                 osTrailerFile.c_str(),
     251             :                 const_cast<GByte *>(
     252             :                     reinterpret_cast<const GByte *>(OGRDXFGetTRAILER())),
     253             :                 static_cast<int>(strlen(OGRDXFGetTRAILER())),
     254             :                 /* bTakeOwnership = */ false));
     255             :         }
     256             : #endif
     257             :     }
     258             : 
     259             : /* -------------------------------------------------------------------- */
     260             : /*      What entity id do we want to start with when writing?  Small    */
     261             : /*      values run a risk of overlapping some undetected entity in      */
     262             : /*      the header or trailer despite the prescanning we do.            */
     263             : /* -------------------------------------------------------------------- */
     264             : #ifdef DEBUG
     265          45 :     nNextFID = 80;
     266             : #else
     267             :     nNextFID = 131072;
     268             : #endif
     269             : 
     270          45 :     if (CSLFetchNameValue(papszOptions, "FIRST_ENTITY") != nullptr)
     271           1 :         nNextFID = atoi(CSLFetchNameValue(papszOptions, "FIRST_ENTITY"));
     272             : 
     273             :     /* -------------------------------------------------------------------- */
     274             :     /*      Prescan the header and trailer for entity codes.                */
     275             :     /* -------------------------------------------------------------------- */
     276          45 :     ScanForEntities(osHeaderFile, "HEADER");
     277          45 :     ScanForEntities(osTrailerFile, "TRAILER");
     278             : 
     279             :     /* -------------------------------------------------------------------- */
     280             :     /*      Attempt to read the template header file so we have a list      */
     281             :     /*      of layers, linestyles and blocks.                               */
     282             :     /* -------------------------------------------------------------------- */
     283          45 :     if (!oHeaderDS.Open(osHeaderFile, true, nullptr))
     284           0 :         return FALSE;
     285             : 
     286             :     /* -------------------------------------------------------------------- */
     287             :     /*      Create the output file.                                         */
     288             :     /* -------------------------------------------------------------------- */
     289          45 :     fp = VSIFOpenExL(pszFilename, "w+", true);
     290             : 
     291          45 :     if (fp == nullptr)
     292             :     {
     293           1 :         CPLError(CE_Failure, CPLE_OpenFailed,
     294             :                  "Failed to open '%s' for writing: %s", pszFilename,
     295             :                  VSIGetLastErrorMsg());
     296           1 :         return FALSE;
     297             :     }
     298             : 
     299             :     /* -------------------------------------------------------------------- */
     300             :     /*      Establish the temporary file.                                   */
     301             :     /* -------------------------------------------------------------------- */
     302          44 :     osTempFilename = pszFilename;
     303          44 :     osTempFilename += ".tmp";
     304             : 
     305          44 :     fpTemp = VSIFOpenL(osTempFilename, "w");
     306          44 :     if (fpTemp == nullptr)
     307             :     {
     308           0 :         CPLError(CE_Failure, CPLE_OpenFailed,
     309             :                  "Failed to open '%s' for writing.", osTempFilename.c_str());
     310           0 :         return FALSE;
     311             :     }
     312             : 
     313          44 :     return TRUE;
     314             : }
     315             : 
     316             : /************************************************************************/
     317             : /*                           ICreateLayer()                             */
     318             : /************************************************************************/
     319             : 
     320             : OGRLayer *
     321          61 : OGRDXFWriterDS::ICreateLayer(const char *pszName,
     322             :                              const OGRGeomFieldDefn * /*poGeomFieldDefn*/,
     323             :                              CSLConstList /*papszOptions*/)
     324             : 
     325             : {
     326          61 :     if (EQUAL(pszName, "blocks") && poBlocksLayer == nullptr)
     327             :     {
     328           2 :         poBlocksLayer = new OGRDXFBlocksWriterLayer(this);
     329           2 :         return poBlocksLayer;
     330             :     }
     331          59 :     else if (poLayer == nullptr)
     332             :     {
     333          43 :         poLayer = new OGRDXFWriterLayer(this, fpTemp);
     334          43 :         return poLayer;
     335             :     }
     336             :     else
     337             :     {
     338          16 :         CPLError(CE_Failure, CPLE_AppDefined,
     339             :                  "Unable to have more than one OGR entities layer in a DXF "
     340             :                  "file, with one options blocks layer.");
     341          16 :         return nullptr;
     342             :     }
     343             : }
     344             : 
     345             : /************************************************************************/
     346             : /*                             WriteValue()                             */
     347             : /************************************************************************/
     348             : 
     349       35376 : static bool WriteValue(VSILFILE *fp, int nCode, const char *pszLine)
     350             : 
     351             : {
     352             :     char szLinePair[300];
     353             : 
     354       35376 :     snprintf(szLinePair, sizeof(szLinePair), "%3d\n%s\n", nCode, pszLine);
     355       35376 :     size_t nLen = strlen(szLinePair);
     356       35376 :     if (VSIFWriteL(szLinePair, 1, nLen, fp) != nLen)
     357             :     {
     358           0 :         CPLError(CE_Failure, CPLE_FileIO,
     359             :                  "Attempt to write line to DXF file failed, disk full?.");
     360           0 :         return false;
     361             :     }
     362             : 
     363       35376 :     return true;
     364             : }
     365             : 
     366             : /************************************************************************/
     367             : /*                             WriteValue()                             */
     368             : /************************************************************************/
     369             : 
     370         184 : static bool WriteValue(VSILFILE *fp, int nCode, double dfValue)
     371             : 
     372             : {
     373             :     char szLinePair[64];
     374             : 
     375         184 :     CPLsnprintf(szLinePair, sizeof(szLinePair), "%3d\n%.15g\n", nCode, dfValue);
     376         184 :     size_t nLen = strlen(szLinePair);
     377         184 :     if (VSIFWriteL(szLinePair, 1, nLen, fp) != nLen)
     378             :     {
     379           0 :         CPLError(CE_Failure, CPLE_FileIO,
     380             :                  "Attempt to write line to DXF file failed, disk full?.");
     381           0 :         return false;
     382             :     }
     383             : 
     384         184 :     return true;
     385             : }
     386             : 
     387             : /************************************************************************/
     388             : /*                        TransferUpdateHeader()                        */
     389             : /************************************************************************/
     390             : 
     391          44 : bool OGRDXFWriterDS::TransferUpdateHeader(VSILFILE *fpOut)
     392             : 
     393             : {
     394          44 :     oHeaderDS.ResetReadPointer(0);
     395             : 
     396             :     // We don't like non-finite extents. In this case, just write a generic
     397             :     // bounding box. Most CAD programs probably ignore this anyway.
     398          44 :     if (!std::isfinite(oGlobalEnvelope.MinX) ||
     399          26 :         !std::isfinite(oGlobalEnvelope.MinY) ||
     400          96 :         !std::isfinite(oGlobalEnvelope.MaxX) ||
     401          26 :         !std::isfinite(oGlobalEnvelope.MaxY))
     402             :     {
     403          18 :         oGlobalEnvelope.MinX = 0.0;
     404          18 :         oGlobalEnvelope.MinY = 0.0;
     405          18 :         oGlobalEnvelope.MaxX = 10.0;
     406          18 :         oGlobalEnvelope.MaxY = 10.0;
     407             :     }
     408             : 
     409             :     /* -------------------------------------------------------------------- */
     410             :     /*      Copy header, inserting in new objects as needed.                */
     411             :     /* -------------------------------------------------------------------- */
     412             :     char szLineBuf[257];
     413          44 :     int nCode = 0;
     414          88 :     CPLString osSection;
     415          88 :     CPLString osTable;
     416          88 :     CPLString osEntity;
     417             : 
     418       48850 :     while ((nCode = oHeaderDS.ReadValue(szLineBuf, sizeof(szLineBuf))) != -1 &&
     419       24403 :            osSection != "ENTITIES")
     420             :     {
     421       24403 :         if (nCode == 0 && EQUAL(szLineBuf, "ENDTAB"))
     422             :         {
     423             :             // If we are at the end of the LAYER TABLE consider inserting
     424             :             // missing definitions.
     425         396 :             if (osTable == "LAYER")
     426             :             {
     427          44 :                 if (!WriteNewLayerDefinitions(fp))
     428           0 :                     return false;
     429             :             }
     430             : 
     431             :             // If at the end of the BLOCK_RECORD TABLE consider inserting
     432             :             // missing definitions.
     433         396 :             if (osTable == "BLOCK_RECORD" && poBlocksLayer)
     434             :             {
     435           2 :                 if (!WriteNewBlockRecords(fp))
     436           0 :                     return false;
     437             :             }
     438             : 
     439             :             // If at the end of the LTYPE TABLE consider inserting
     440             :             // missing layer type definitions.
     441         396 :             if (osTable == "LTYPE")
     442             :             {
     443          44 :                 if (!WriteNewLineTypeRecords(fp))
     444           0 :                     return false;
     445             :             }
     446             : 
     447             :             // If at the end of the STYLE TABLE consider inserting
     448             :             // missing layer type definitions.
     449         396 :             if (osTable == "STYLE")
     450             :             {
     451          44 :                 if (!WriteNewTextStyleRecords(fp))
     452           0 :                     return false;
     453             :             }
     454             : 
     455         396 :             osTable = "";
     456             :         }
     457             : 
     458             :         // If we are at the end of the BLOCKS section, consider inserting
     459             :         // supplementary blocks.
     460       24447 :         if (nCode == 0 && osSection == "BLOCKS" && EQUAL(szLineBuf, "ENDSEC") &&
     461          44 :             poBlocksLayer != nullptr)
     462             :         {
     463           2 :             if (!WriteNewBlockDefinitions(fp))
     464           0 :                 return false;
     465             :         }
     466             : 
     467             :         // We need to keep track of where $HANDSEED is so that we can
     468             :         // come back and fix it up when we have generated all entity ids.
     469       24403 :         if (nCode == 9 && EQUAL(szLineBuf, "$HANDSEED"))
     470             :         {
     471          44 :             if (!WriteValue(fpOut, nCode, szLineBuf))
     472           0 :                 return false;
     473             : 
     474          44 :             nCode = oHeaderDS.ReadValue(szLineBuf, sizeof(szLineBuf));
     475             : 
     476             :             // ensure we have room to overwrite with a longer value.
     477         308 :             while (strlen(szLineBuf) < 8)
     478             :             {
     479         264 :                 memmove(szLineBuf + 1, szLineBuf, strlen(szLineBuf) + 1);
     480         264 :                 szLineBuf[0] = '0';
     481             :             }
     482             : 
     483          44 :             nHANDSEEDOffset = VSIFTellL(fpOut);
     484             :         }
     485             : 
     486             :         // Patch EXTMIN with minx and miny
     487       24403 :         if (nCode == 9 && EQUAL(szLineBuf, "$EXTMIN"))
     488             :         {
     489          44 :             if (!WriteValue(fpOut, nCode, szLineBuf))
     490           0 :                 return false;
     491             : 
     492          44 :             nCode = oHeaderDS.ReadValue(szLineBuf, sizeof(szLineBuf));
     493          44 :             if (nCode == 10)
     494             :             {
     495          44 :                 if (!WriteValue(fpOut, nCode, oGlobalEnvelope.MinX))
     496           0 :                     return false;
     497             : 
     498          44 :                 nCode = oHeaderDS.ReadValue(szLineBuf, sizeof(szLineBuf));
     499          44 :                 if (nCode == 20)
     500             :                 {
     501          44 :                     if (!WriteValue(fpOut, nCode, oGlobalEnvelope.MinY))
     502           0 :                         return false;
     503             : 
     504          44 :                     continue;
     505             :                 }
     506             :             }
     507             :         }
     508             : 
     509             :         // Patch EXTMAX with maxx and maxy
     510       24359 :         if (nCode == 9 && EQUAL(szLineBuf, "$EXTMAX"))
     511             :         {
     512          44 :             if (!WriteValue(fpOut, nCode, szLineBuf))
     513           0 :                 return false;
     514             : 
     515          44 :             nCode = oHeaderDS.ReadValue(szLineBuf, sizeof(szLineBuf));
     516          44 :             if (nCode == 10)
     517             :             {
     518          44 :                 if (!WriteValue(fpOut, nCode, oGlobalEnvelope.MaxX))
     519           0 :                     return false;
     520             : 
     521          44 :                 nCode = oHeaderDS.ReadValue(szLineBuf, sizeof(szLineBuf));
     522          44 :                 if (nCode == 20)
     523             :                 {
     524          44 :                     if (!WriteValue(fpOut, nCode, oGlobalEnvelope.MaxY))
     525           0 :                         return false;
     526             : 
     527          44 :                     continue;
     528             :                 }
     529             :             }
     530             :         }
     531             : 
     532             :         // Copy over the source line.
     533       24315 :         if (!WriteValue(fpOut, nCode, szLineBuf))
     534           0 :             return false;
     535             : 
     536             :         // Track what entity we are in - that is the last "code 0" object.
     537       24315 :         if (nCode == 0)
     538        1887 :             osEntity = szLineBuf;
     539             : 
     540             :         // Track what section we are in.
     541       24315 :         if (nCode == 0 && EQUAL(szLineBuf, "SECTION"))
     542             :         {
     543         220 :             nCode = oHeaderDS.ReadValue(szLineBuf);
     544         220 :             if (nCode == -1)
     545           0 :                 break;
     546             : 
     547         220 :             if (!WriteValue(fpOut, nCode, szLineBuf))
     548           0 :                 return false;
     549             : 
     550         220 :             osSection = szLineBuf;
     551             :         }
     552             : 
     553             :         // Track what TABLE we are in.
     554       24315 :         if (nCode == 0 && EQUAL(szLineBuf, "TABLE"))
     555             :         {
     556         396 :             nCode = oHeaderDS.ReadValue(szLineBuf);
     557         396 :             if (!WriteValue(fpOut, nCode, szLineBuf))
     558           0 :                 return false;
     559             : 
     560         396 :             osTable = szLineBuf;
     561             :         }
     562             : 
     563             :         // If we are starting the first layer, then capture
     564             :         // the layer contents while copying so we can duplicate
     565             :         // it for any new layer definitions.
     566       24359 :         if (nCode == 0 && EQUAL(szLineBuf, "LAYER") && osTable == "LAYER" &&
     567          44 :             aosDefaultLayerText.empty())
     568             :         {
     569         440 :             do
     570             :             {
     571         484 :                 anDefaultLayerCode.push_back(nCode);
     572         484 :                 aosDefaultLayerText.push_back(szLineBuf);
     573             : 
     574         484 :                 if (nCode != 0 && !WriteValue(fpOut, nCode, szLineBuf))
     575           0 :                     return false;
     576             : 
     577         484 :                 nCode = oHeaderDS.ReadValue(szLineBuf);
     578             : 
     579         484 :                 if (nCode == 2 && !EQUAL(szLineBuf, "0"))
     580             :                 {
     581           0 :                     anDefaultLayerCode.resize(0);
     582           0 :                     aosDefaultLayerText.resize(0);
     583           0 :                     break;
     584             :                 }
     585         484 :             } while (nCode != 0);
     586             : 
     587          44 :             oHeaderDS.UnreadValue();
     588             :         }
     589             :     }
     590             : 
     591          44 :     return true;
     592             : }
     593             : 
     594             : /************************************************************************/
     595             : /*                       TransferUpdateTrailer()                        */
     596             : /************************************************************************/
     597             : 
     598          44 : bool OGRDXFWriterDS::TransferUpdateTrailer(VSILFILE *fpOut)
     599             : {
     600             :     /* -------------------------------------------------------------------- */
     601             :     /*      Open the file and setup a reader.                               */
     602             :     /* -------------------------------------------------------------------- */
     603          44 :     VSILFILE *l_fp = VSIFOpenL(osTrailerFile, "r");
     604             : 
     605          44 :     if (l_fp == nullptr)
     606           0 :         return false;
     607             : 
     608          88 :     OGRDXFReader oReader;
     609          44 :     oReader.Initialize(l_fp);
     610             : 
     611             :     /* -------------------------------------------------------------------- */
     612             :     /*      Scan ahead to find the OBJECTS section.                         */
     613             :     /* -------------------------------------------------------------------- */
     614             :     char szLineBuf[257];
     615          44 :     int nCode = 0;
     616             : 
     617          88 :     while ((nCode = oReader.ReadValue(szLineBuf, sizeof(szLineBuf))) != -1)
     618             :     {
     619          88 :         if (nCode == 0 && EQUAL(szLineBuf, "SECTION"))
     620             :         {
     621          44 :             nCode = oReader.ReadValue(szLineBuf, sizeof(szLineBuf));
     622          44 :             if (nCode == 2 && EQUAL(szLineBuf, "OBJECTS"))
     623          44 :                 break;
     624             :         }
     625             :     }
     626             : 
     627          44 :     if (nCode == -1)
     628             :     {
     629           0 :         CPLError(CE_Failure, CPLE_AppDefined,
     630             :                  "Failed to find OBJECTS section in trailer file '%s'.",
     631             :                  osTrailerFile.c_str());
     632           0 :         return false;
     633             :     }
     634             : 
     635             :     /* -------------------------------------------------------------------- */
     636             :     /*      Insert the "end of section" for ENTITIES, and the start of      */
     637             :     /*      the OBJECTS section.                                            */
     638             :     /* -------------------------------------------------------------------- */
     639          44 :     WriteValue(fpOut, 0, "ENDSEC");
     640          44 :     WriteValue(fpOut, 0, "SECTION");
     641          44 :     WriteValue(fpOut, 2, "OBJECTS");
     642             : 
     643             :     /* -------------------------------------------------------------------- */
     644             :     /*      Copy the remainder of the file.                                 */
     645             :     /* -------------------------------------------------------------------- */
     646          44 :     bool ret = true;
     647        9460 :     while ((nCode = oReader.ReadValue(szLineBuf, sizeof(szLineBuf))) != -1)
     648             :     {
     649        9416 :         if (!WriteValue(fpOut, nCode, szLineBuf))
     650             :         {
     651           0 :             ret = false;
     652           0 :             break;
     653             :         }
     654             :     }
     655             : 
     656          44 :     VSIFCloseL(l_fp);
     657             : 
     658          44 :     return ret;
     659             : }
     660             : 
     661             : /************************************************************************/
     662             : /*                           FixupHANDSEED()                            */
     663             : /*                                                                      */
     664             : /*      Fixup the next entity id information in the $HANDSEED header    */
     665             : /*      variable.                                                       */
     666             : /************************************************************************/
     667             : 
     668          44 : bool OGRDXFWriterDS::FixupHANDSEED(VSILFILE *fpIn)
     669             : 
     670             : {
     671             :     /* -------------------------------------------------------------------- */
     672             :     /*      What is a good next handle seed?  Scan existing values.         */
     673             :     /* -------------------------------------------------------------------- */
     674          44 :     unsigned int nHighestHandle = 0;
     675          44 :     std::set<CPLString>::iterator it;
     676             : 
     677        1755 :     for (it = aosUsedEntities.begin(); it != aosUsedEntities.end(); ++it)
     678             :     {
     679        1711 :         unsigned int nHandle = 0;
     680        1711 :         if (sscanf((*it).c_str(), "%x", &nHandle) == 1)
     681             :         {
     682        1711 :             if (nHandle > nHighestHandle)
     683        1125 :                 nHighestHandle = nHandle;
     684             :         }
     685             :     }
     686             : 
     687             :     /* -------------------------------------------------------------------- */
     688             :     /*      Read the existing handseed value, replace it, and write back.   */
     689             :     /* -------------------------------------------------------------------- */
     690          44 :     if (nHANDSEEDOffset == 0)
     691           0 :         return false;
     692             : 
     693             :     char szWorkBuf[30];
     694          44 :     VSIFSeekL(fpIn, nHANDSEEDOffset, SEEK_SET);
     695          44 :     VSIFReadL(szWorkBuf, 1, sizeof(szWorkBuf), fpIn);
     696             : 
     697          44 :     int i = 0;
     698         176 :     while (szWorkBuf[i] != '\n')
     699         132 :         i++;
     700             : 
     701          44 :     i++;
     702          44 :     if (szWorkBuf[i] == '\r')
     703           0 :         i++;
     704             : 
     705          44 :     CPLString osNewValue;
     706             : 
     707          44 :     osNewValue.Printf("%08X", nHighestHandle + 1);
     708          44 :     strncpy(szWorkBuf + i, osNewValue.c_str(), osNewValue.size());
     709             : 
     710          44 :     VSIFSeekL(fpIn, nHANDSEEDOffset, SEEK_SET);
     711          44 :     VSIFWriteL(szWorkBuf, 1, sizeof(szWorkBuf), fp);
     712             : 
     713          44 :     return true;
     714             : }
     715             : 
     716             : /************************************************************************/
     717             : /*                      WriteNewLayerDefinitions()                      */
     718             : /************************************************************************/
     719             : 
     720          44 : bool OGRDXFWriterDS::WriteNewLayerDefinitions(VSILFILE *fpOut)
     721             : 
     722             : {
     723          44 :     const int nNewLayers = CSLCount(papszLayersToCreate);
     724             : 
     725          47 :     for (int iLayer = 0; iLayer < nNewLayers; iLayer++)
     726             :     {
     727           3 :         bool bIsDefPoints = false;
     728           3 :         bool bWrote290 = false;
     729          36 :         for (unsigned i = 0; i < aosDefaultLayerText.size(); i++)
     730             :         {
     731          33 :             if (anDefaultLayerCode[i] == 2)
     732             :             {
     733           3 :                 if (EQUAL(papszLayersToCreate[iLayer], "DEFPOINTS"))
     734           0 :                     bIsDefPoints = true;
     735             : 
     736           3 :                 if (!WriteValue(fpOut, 2, papszLayersToCreate[iLayer]))
     737           0 :                     return false;
     738             :             }
     739          30 :             else if (anDefaultLayerCode[i] == 5)
     740             :             {
     741             :                 unsigned int nIgnored;
     742           3 :                 if (!WriteEntityID(fpOut, nIgnored))
     743           0 :                     return false;
     744             :             }
     745             :             else
     746             :             {
     747          27 :                 if (anDefaultLayerCode[i] == 290)
     748           0 :                     bWrote290 = true;
     749             : 
     750          27 :                 if (!WriteValue(fpOut, anDefaultLayerCode[i],
     751          27 :                                 aosDefaultLayerText[i]))
     752           0 :                     return false;
     753             :             }
     754             :         }
     755           3 :         if (bIsDefPoints && !bWrote290)
     756             :         {
     757             :             // The Defpoints layer must be explicitly set to not plotted to
     758             :             // please Autocad. See https://trac.osgeo.org/gdal/ticket/7078
     759           0 :             if (!WriteValue(fpOut, 290, "0"))
     760           0 :                 return false;
     761             :         }
     762             :     }
     763             : 
     764          44 :     return true;
     765             : }
     766             : 
     767             : /************************************************************************/
     768             : /*                      WriteNewLineTypeRecords()                       */
     769             : /************************************************************************/
     770             : 
     771          44 : bool OGRDXFWriterDS::WriteNewLineTypeRecords(VSILFILE *fpIn)
     772             : 
     773             : {
     774          44 :     if (poLayer == nullptr)
     775           1 :         return true;
     776             : 
     777             :     const std::map<CPLString, std::vector<double>> &oNewLineTypes =
     778          43 :         poLayer->GetNewLineTypeMap();
     779             : 
     780          43 :     bool bRet = true;
     781          45 :     for (const auto &oPair : oNewLineTypes)
     782             :     {
     783           2 :         bRet &= WriteValue(fpIn, 0, "LTYPE");
     784             :         unsigned int nIgnored;
     785           2 :         bRet &= WriteEntityID(fpIn, nIgnored);
     786           2 :         bRet &= WriteValue(fpIn, 100, "AcDbSymbolTableRecord");
     787           2 :         bRet &= WriteValue(fpIn, 100, "AcDbLinetypeTableRecord");
     788           2 :         bRet &= WriteValue(fpIn, 2, oPair.first);
     789           2 :         bRet &= WriteValue(fpIn, 70, "0");
     790           2 :         bRet &= WriteValue(fpIn, 3, "");
     791           2 :         bRet &= WriteValue(fpIn, 72, "65");
     792           2 :         bRet &= WriteValue(fpIn, 73, static_cast<int>(oPair.second.size()));
     793             : 
     794           2 :         double dfTotalLength = 0.0;
     795           6 :         for (const double &dfSegment : oPair.second)
     796           4 :             dfTotalLength += fabs(dfSegment);
     797           2 :         bRet &= WriteValue(fpIn, 40, dfTotalLength);
     798             : 
     799           6 :         for (const double &dfSegment : oPair.second)
     800             :         {
     801           4 :             bRet &= WriteValue(fpIn, 49, dfSegment);
     802           4 :             bRet &= WriteValue(fpIn, 74, "0");
     803             :         }
     804             :     }
     805             : 
     806          43 :     return bRet;
     807             : }
     808             : 
     809             : /************************************************************************/
     810             : /*                      WriteNewTextStyleRecords()                      */
     811             : /************************************************************************/
     812             : 
     813          44 : bool OGRDXFWriterDS::WriteNewTextStyleRecords(VSILFILE *fpIn)
     814             : 
     815             : {
     816          44 :     if (poLayer == nullptr)
     817           1 :         return true;
     818             : 
     819          43 :     auto &oNewTextStyles = poLayer->GetNewTextStyleMap();
     820             : 
     821          43 :     bool bRet = true;
     822          44 :     for (auto &oPair : oNewTextStyles)
     823             :     {
     824           1 :         bRet &= WriteValue(fpIn, 0, "STYLE");
     825             :         unsigned int nIgnored;
     826           1 :         bRet &= WriteEntityID(fpIn, nIgnored);
     827           1 :         bRet &= WriteValue(fpIn, 100, "AcDbSymbolTableRecord");
     828           1 :         bRet &= WriteValue(fpIn, 100, "AcDbTextStyleTableRecord");
     829           1 :         bRet &= WriteValue(fpIn, 2, oPair.first);
     830           1 :         bRet &= WriteValue(fpIn, 70, "0");
     831           1 :         bRet &= WriteValue(fpIn, 40, "0.0");
     832             : 
     833           1 :         if (oPair.second.count("Width"))
     834           1 :             bRet &= WriteValue(fpIn, 41, oPair.second["Width"]);
     835             :         else
     836           0 :             bRet &= WriteValue(fpIn, 41, "1.0");
     837             : 
     838           1 :         bRet &= WriteValue(fpIn, 50, "0.0");
     839           1 :         bRet &= WriteValue(fpIn, 71, "0");
     840           1 :         bRet &= WriteValue(fpIn, 1001, "ACAD");
     841             : 
     842           1 :         if (oPair.second.count("Font"))
     843           1 :             bRet &= WriteValue(fpIn, 1000, oPair.second["Font"]);
     844             : 
     845           1 :         int nStyleValue = 0;
     846           1 :         if (oPair.second.count("Italic") && oPair.second["Italic"] == "1")
     847           0 :             nStyleValue |= 0x1000000;
     848           1 :         if (oPair.second.count("Bold") && oPair.second["Bold"] == "1")
     849           1 :             nStyleValue |= 0x2000000;
     850           1 :         bRet &= WriteValue(fpIn, 1071,
     851           2 :                            CPLString().Printf("%d", nStyleValue).c_str());
     852             :     }
     853             : 
     854          43 :     return bRet;
     855             : }
     856             : 
     857             : /************************************************************************/
     858             : /*                        WriteNewBlockRecords()                        */
     859             : /************************************************************************/
     860             : 
     861           2 : bool OGRDXFWriterDS::WriteNewBlockRecords(VSILFILE *fpIn)
     862             : 
     863             : {
     864           2 :     std::set<CPLString> aosAlreadyHandled;
     865             : 
     866             :     /* ==================================================================== */
     867             :     /*      Loop over all block objects written via the blocks layer.       */
     868             :     /* ==================================================================== */
     869           2 :     bool bRet = true;
     870           6 :     for (size_t iBlock = 0; iBlock < poBlocksLayer->apoBlocks.size(); iBlock++)
     871             :     {
     872           4 :         OGRFeature *poThisBlockFeat = poBlocksLayer->apoBlocks[iBlock];
     873             : 
     874             :         /* --------------------------------------------------------------------
     875             :          */
     876             :         /*      Is this block already defined in the template header? */
     877             :         /* --------------------------------------------------------------------
     878             :          */
     879           4 :         CPLString osBlockName = poThisBlockFeat->GetFieldAsString("Block");
     880             : 
     881           4 :         if (oHeaderDS.LookupBlock(osBlockName) != nullptr)
     882           0 :             continue;
     883             : 
     884             :         /* --------------------------------------------------------------------
     885             :          */
     886             :         /*      Have we already written a BLOCK_RECORD for this block? */
     887             :         /* --------------------------------------------------------------------
     888             :          */
     889           4 :         if (aosAlreadyHandled.find(osBlockName) != aosAlreadyHandled.end())
     890           0 :             continue;
     891             : 
     892           4 :         aosAlreadyHandled.insert(osBlockName);
     893             : 
     894             :         /* --------------------------------------------------------------------
     895             :          */
     896             :         /*      Write the block record. */
     897             :         /* --------------------------------------------------------------------
     898             :          */
     899           4 :         bRet &= WriteValue(fpIn, 0, "BLOCK_RECORD");
     900             :         unsigned int nIgnored;
     901           4 :         bRet &= WriteEntityID(fpIn, nIgnored);
     902           4 :         bRet &= WriteValue(fpIn, 100, "AcDbSymbolTableRecord");
     903           4 :         bRet &= WriteValue(fpIn, 100, "AcDbBlockTableRecord");
     904           4 :         bRet &= WriteValue(fpIn, 2, poThisBlockFeat->GetFieldAsString("Block"));
     905           4 :         bRet &= WriteValue(fpIn, 340, "0");
     906             :     }
     907             : 
     908           4 :     return bRet;
     909             : }
     910             : 
     911             : /************************************************************************/
     912             : /*                      WriteNewBlockDefinitions()                      */
     913             : /************************************************************************/
     914             : 
     915           2 : bool OGRDXFWriterDS::WriteNewBlockDefinitions(VSILFILE *fpIn)
     916             : 
     917             : {
     918           2 :     if (poLayer == nullptr)
     919           1 :         poLayer = new OGRDXFWriterLayer(this, fpTemp);
     920           2 :     poLayer->ResetFP(fpIn);
     921             : 
     922             :     /* ==================================================================== */
     923             :     /*      Loop over all block objects written via the blocks layer.       */
     924             :     /* ==================================================================== */
     925           2 :     bool bRet = true;
     926           6 :     for (size_t iBlock = 0; iBlock < poBlocksLayer->apoBlocks.size(); iBlock++)
     927             :     {
     928           4 :         OGRFeature *poThisBlockFeat = poBlocksLayer->apoBlocks[iBlock];
     929             : 
     930             :         /* --------------------------------------------------------------------
     931             :          */
     932             :         /*      Is this block already defined in the template header? */
     933             :         /* --------------------------------------------------------------------
     934             :          */
     935           4 :         CPLString osBlockName = poThisBlockFeat->GetFieldAsString("Block");
     936             : 
     937           4 :         if (oHeaderDS.LookupBlock(osBlockName) != nullptr)
     938           0 :             continue;
     939             : 
     940             :         /* --------------------------------------------------------------------
     941             :          */
     942             :         /*      Write the block definition preamble. */
     943             :         /* --------------------------------------------------------------------
     944             :          */
     945           4 :         CPLDebug("DXF", "Writing BLOCK definition for '%s'.",
     946             :                  poThisBlockFeat->GetFieldAsString("Block"));
     947             : 
     948           4 :         bRet &= WriteValue(fpIn, 0, "BLOCK");
     949             :         unsigned int nIgnored;
     950           4 :         bRet &= WriteEntityID(fpIn, nIgnored);
     951           4 :         bRet &= WriteValue(fpIn, 100, "AcDbEntity");
     952           4 :         if (strlen(poThisBlockFeat->GetFieldAsString("Layer")) > 0)
     953           0 :             bRet &=
     954           0 :                 WriteValue(fpIn, 8, poThisBlockFeat->GetFieldAsString("Layer"));
     955             :         else
     956           4 :             bRet &= WriteValue(fpIn, 8, "0");
     957           4 :         bRet &= WriteValue(fpIn, 100, "AcDbBlockBegin");
     958           4 :         bRet &= WriteValue(fpIn, 2, poThisBlockFeat->GetFieldAsString("Block"));
     959           4 :         bRet &= WriteValue(fpIn, 70, "0");
     960             : 
     961             :         // Origin
     962           4 :         bRet &= WriteValue(fpIn, 10, "0.0");
     963           4 :         bRet &= WriteValue(fpIn, 20, "0.0");
     964           4 :         bRet &= WriteValue(fpIn, 30, "0.0");
     965             : 
     966           4 :         bRet &= WriteValue(fpIn, 3, poThisBlockFeat->GetFieldAsString("Block"));
     967           4 :         bRet &= WriteValue(fpIn, 1, "");
     968             : 
     969             :         /* --------------------------------------------------------------------
     970             :          */
     971             :         /*      Write out the feature entities. */
     972             :         /* --------------------------------------------------------------------
     973             :          */
     974           4 :         if (poLayer->CreateFeature(poThisBlockFeat) != OGRERR_NONE)
     975           0 :             return false;
     976             : 
     977             :         /* --------------------------------------------------------------------
     978             :          */
     979             :         /*      Write out following features if they are the same block. */
     980             :         /* --------------------------------------------------------------------
     981             :          */
     982           6 :         while (iBlock < poBlocksLayer->apoBlocks.size() - 1 &&
     983           2 :                EQUAL(poBlocksLayer->apoBlocks[iBlock + 1]->GetFieldAsString(
     984             :                          "Block"),
     985             :                      osBlockName))
     986             :         {
     987           0 :             iBlock++;
     988             : 
     989           0 :             if (poLayer->CreateFeature(poBlocksLayer->apoBlocks[iBlock]) !=
     990             :                 OGRERR_NONE)
     991           0 :                 return false;
     992             :         }
     993             : 
     994             :         /* --------------------------------------------------------------------
     995             :          */
     996             :         /*      Write out the block definition postamble. */
     997             :         /* --------------------------------------------------------------------
     998             :          */
     999           4 :         bRet &= WriteValue(fpIn, 0, "ENDBLK");
    1000           4 :         bRet &= WriteEntityID(fpIn, nIgnored);
    1001           4 :         bRet &= WriteValue(fpIn, 100, "AcDbEntity");
    1002           4 :         if (strlen(poThisBlockFeat->GetFieldAsString("Layer")) > 0)
    1003           0 :             bRet &=
    1004           0 :                 WriteValue(fpIn, 8, poThisBlockFeat->GetFieldAsString("Layer"));
    1005             :         else
    1006           4 :             bRet &= WriteValue(fpIn, 8, "0");
    1007           4 :         bRet &= WriteValue(fpIn, 100, "AcDbBlockEnd");
    1008             :     }
    1009             : 
    1010           2 :     return bRet;
    1011             : }
    1012             : 
    1013             : /************************************************************************/
    1014             : /*                          ScanForEntities()                           */
    1015             : /*                                                                      */
    1016             : /*      Scan the indicated file for entity ids ("5" records) and        */
    1017             : /*      build them up as a set so we can be careful to avoid            */
    1018             : /*      creating new entities with conflicting ids.                     */
    1019             : /************************************************************************/
    1020             : 
    1021          90 : void OGRDXFWriterDS::ScanForEntities(const char *pszFilename,
    1022             :                                      const char *pszTarget)
    1023             : 
    1024             : {
    1025             :     /* -------------------------------------------------------------------- */
    1026             :     /*      Open the file and setup a reader.                               */
    1027             :     /* -------------------------------------------------------------------- */
    1028          90 :     VSILFILE *l_fp = VSIFOpenL(pszFilename, "r");
    1029             : 
    1030          90 :     if (l_fp == nullptr)
    1031           0 :         return;
    1032             : 
    1033         180 :     OGRDXFReader oReader;
    1034          90 :     oReader.Initialize(l_fp);
    1035             : 
    1036             :     /* -------------------------------------------------------------------- */
    1037             :     /*      Add every code "5" line to our entities list.                   */
    1038             :     /* -------------------------------------------------------------------- */
    1039             :     char szLineBuf[257];
    1040          90 :     int nCode = 0;
    1041          90 :     const char *pszPortion = "HEADER";
    1042             : 
    1043       35826 :     while ((nCode = oReader.ReadValue(szLineBuf, sizeof(szLineBuf))) != -1)
    1044             :     {
    1045       35736 :         if ((nCode == 5 || nCode == 105) && EQUAL(pszTarget, pszPortion))
    1046             :         {
    1047        3132 :             CPLString osEntity(szLineBuf);
    1048             : 
    1049        1566 :             if (CheckEntityID(osEntity))
    1050           6 :                 CPLDebug("DXF", "Encountered entity '%s' multiple times.",
    1051             :                          osEntity.c_str());
    1052             :             else
    1053        1560 :                 aosUsedEntities.insert(osEntity);
    1054             :         }
    1055             : 
    1056       35736 :         if (nCode == 0 && EQUAL(szLineBuf, "SECTION"))
    1057             :         {
    1058         270 :             nCode = oReader.ReadValue(szLineBuf, sizeof(szLineBuf));
    1059         270 :             if (nCode == 2 && EQUAL(szLineBuf, "ENTITIES"))
    1060          45 :                 pszPortion = "BODY";
    1061         270 :             if (nCode == 2 && EQUAL(szLineBuf, "OBJECTS"))
    1062          45 :                 pszPortion = "TRAILER";
    1063             :         }
    1064             :     }
    1065             : 
    1066          90 :     VSIFCloseL(l_fp);
    1067             : }
    1068             : 
    1069             : /************************************************************************/
    1070             : /*                           CheckEntityID()                            */
    1071             : /*                                                                      */
    1072             : /*      Does the mentioned entity already exist?                        */
    1073             : /************************************************************************/
    1074             : 
    1075        1766 : bool OGRDXFWriterDS::CheckEntityID(const char *pszEntityID)
    1076             : 
    1077             : {
    1078        1766 :     std::set<CPLString>::iterator it;
    1079             : 
    1080        1766 :     it = aosUsedEntities.find(pszEntityID);
    1081        1766 :     return it != aosUsedEntities.end();
    1082             : }
    1083             : 
    1084             : /************************************************************************/
    1085             : /*                           WriteEntityID()                            */
    1086             : /************************************************************************/
    1087             : 
    1088         185 : bool OGRDXFWriterDS::WriteEntityID(VSILFILE *fpIn, unsigned int &nAssignedFID,
    1089             :                                    GIntBig nPreferredFID)
    1090             : 
    1091             : {
    1092         370 :     CPLString osEntityID;
    1093             : 
    1094             :     // From https://github.com/OSGeo/gdal/issues/11299 it seems that 0 is an
    1095             :     // invalid handle value.
    1096         201 :     if (nPreferredFID > 0 &&
    1097             :         nPreferredFID <=
    1098          16 :             static_cast<GIntBig>(std::numeric_limits<unsigned int>::max()))
    1099             :     {
    1100             : 
    1101          16 :         osEntityID.Printf("%X", static_cast<unsigned int>(nPreferredFID));
    1102          16 :         if (!CheckEntityID(osEntityID))
    1103             :         {
    1104           1 :             aosUsedEntities.insert(osEntityID);
    1105           1 :             if (!WriteValue(fpIn, 5, osEntityID))
    1106           0 :                 return false;
    1107           1 :             nAssignedFID = static_cast<unsigned int>(nPreferredFID);
    1108           1 :             return true;
    1109             :         }
    1110             :     }
    1111             : 
    1112           0 :     do
    1113             :     {
    1114         184 :         osEntityID.Printf("%X", nNextFID++);
    1115         184 :     } while (CheckEntityID(osEntityID));
    1116             : 
    1117         184 :     aosUsedEntities.insert(osEntityID);
    1118         184 :     if (!WriteValue(fpIn, 5, osEntityID))
    1119           0 :         return false;
    1120             : 
    1121         184 :     nAssignedFID = nNextFID - 1;
    1122         184 :     return true;
    1123             : }
    1124             : 
    1125             : /************************************************************************/
    1126             : /*                           UpdateExtent()                             */
    1127             : /************************************************************************/
    1128             : 
    1129         175 : void OGRDXFWriterDS::UpdateExtent(OGREnvelope *psEnvelope)
    1130             : {
    1131         175 :     oGlobalEnvelope.Merge(*psEnvelope);
    1132         175 : }

Generated by: LCOV version 1.14