LCOV - code coverage report
Current view: top level - ogr/ogrsf_frmts/dgn - dgnread.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 450 977 46.1 %
Date: 2024-05-08 14:54:11 Functions: 17 21 81.0 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  Microstation DGN Access Library
       4             :  * Purpose:  DGN Access Library element reading code.
       5             :  * Author:   Frank Warmerdam, warmerdam@pobox.com
       6             :  *
       7             :  ******************************************************************************
       8             :  * Copyright (c) 2000, Avenza Systems Inc, http://www.avenza.com/
       9             :  *
      10             :  * Permission is hereby granted, free of charge, to any person obtaining a
      11             :  * copy of this software and associated documentation files (the "Software"),
      12             :  * to deal in the Software without restriction, including without limitation
      13             :  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
      14             :  * and/or sell copies of the Software, and to permit persons to whom the
      15             :  * Software is furnished to do so, subject to the following conditions:
      16             :  *
      17             :  * The above copyright notice and this permission notice shall be included
      18             :  * in all copies or substantial portions of the Software.
      19             :  *
      20             :  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
      21             :  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      22             :  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
      23             :  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
      24             :  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
      25             :  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
      26             :  * DEALINGS IN THE SOFTWARE.
      27             :  ****************************************************************************/
      28             : 
      29             : #include "dgnlibp.h"
      30             : 
      31             : #include <algorithm>
      32             : 
      33             : static DGNElemCore *DGNParseTCB(DGNInfo *);
      34             : static DGNElemCore *DGNParseColorTable(DGNInfo *);
      35             : static DGNElemCore *DGNParseTagSet(DGNInfo *);
      36             : 
      37             : /************************************************************************/
      38             : /*                             DGN_INT16()                              */
      39             : /************************************************************************/
      40             : 
      41           0 : static short int DGN_INT16(const GByte *p)
      42             : {
      43           0 :     return static_cast<short>(p[0] | (p[1] << 8));
      44             : }
      45             : 
      46             : /************************************************************************/
      47             : /*                           DGNGotoElement()                           */
      48             : /************************************************************************/
      49             : 
      50             : /**
      51             :  * Seek to indicated element.
      52             :  *
      53             :  * Changes what element will be read on the next call to DGNReadElement().
      54             :  * Note that this function requires and index, and one will be built if
      55             :  * not already available.
      56             :  *
      57             :  * @param hDGN the file to affect.
      58             :  * @param element_id the element to seek to.  These values are sequentially
      59             :  * ordered starting at zero for the first element.
      60             :  *
      61             :  * @return returns TRUE on success or FALSE on failure.
      62             :  */
      63             : 
      64         283 : int DGNGotoElement(DGNHandle hDGN, int element_id)
      65             : 
      66             : {
      67         283 :     DGNInfo *psDGN = (DGNInfo *)hDGN;
      68             : 
      69         283 :     DGNBuildIndex(psDGN);
      70             : 
      71         283 :     if (element_id < 0 || element_id >= psDGN->element_count)
      72           0 :         return FALSE;
      73             : 
      74         283 :     if (VSIFSeekL(psDGN->fp, psDGN->element_index[element_id].offset,
      75         283 :                   SEEK_SET) != 0)
      76           0 :         return FALSE;
      77             : 
      78         283 :     psDGN->next_element_id = element_id;
      79         283 :     psDGN->in_complex_group = false;
      80             : 
      81         283 :     return TRUE;
      82             : }
      83             : 
      84             : /************************************************************************/
      85             : /*                         DGNLoadRawElement()                          */
      86             : /************************************************************************/
      87             : 
      88        1081 : int DGNLoadRawElement(DGNInfo *psDGN, int *pnType, int *pnLevel)
      89             : 
      90             : {
      91             :     /* -------------------------------------------------------------------- */
      92             :     /*      Read the first four bytes to get the level, type, and word      */
      93             :     /*      count.                                                          */
      94             :     /* -------------------------------------------------------------------- */
      95        1081 :     if (VSIFReadL(psDGN->abyElem, 1, 4, psDGN->fp) != 4)
      96          48 :         return FALSE;
      97             : 
      98             :     /* Is this an 0xFFFF endof file marker? */
      99        1033 :     if (psDGN->abyElem[0] == 0xff && psDGN->abyElem[1] == 0xff)
     100          29 :         return FALSE;
     101             : 
     102        1004 :     int nWords = psDGN->abyElem[2] + psDGN->abyElem[3] * 256;
     103        1004 :     int nType = psDGN->abyElem[1] & 0x7f;
     104        1004 :     int nLevel = psDGN->abyElem[0] & 0x3f;
     105             : 
     106             :     /* -------------------------------------------------------------------- */
     107             :     /*      Read the rest of the element data into the working buffer.      */
     108             :     /* -------------------------------------------------------------------- */
     109        1004 :     if (nWords * 2 + 4 >= (int)sizeof(psDGN->abyElem))
     110           0 :         return FALSE;
     111             : 
     112             :     /* coverity[tainted_data] */
     113        1004 :     if ((int)VSIFReadL(psDGN->abyElem + 4, 2, nWords, psDGN->fp) != nWords)
     114           0 :         return FALSE;
     115        1004 :     psDGN->abyElem[4 + 2 * nWords] = 0;
     116        1004 :     psDGN->abyElem[sizeof(psDGN->abyElem) - 1] = 0;
     117             : 
     118        1004 :     psDGN->nElemBytes = nWords * 2 + 4;
     119             : 
     120        1004 :     psDGN->next_element_id++;
     121             : 
     122             :     /* -------------------------------------------------------------------- */
     123             :     /*      Return requested info.                                          */
     124             :     /* -------------------------------------------------------------------- */
     125        1004 :     if (pnType != nullptr)
     126        1004 :         *pnType = nType;
     127             : 
     128        1004 :     if (pnLevel != nullptr)
     129        1004 :         *pnLevel = nLevel;
     130             : 
     131        1004 :     return TRUE;
     132             : }
     133             : 
     134             : /************************************************************************/
     135             : /*                          DGNGetRawExtents()                          */
     136             : /*                                                                      */
     137             : /*      Returns false if the element type does not have recognizable    */
     138             : /*      element extents, other true and the extents will be updated.    */
     139             : /*                                                                      */
     140             : /*      It is assumed the raw element data has been loaded into the     */
     141             : /*      working area by DGNLoadRawElement().                            */
     142             : /************************************************************************/
     143             : 
     144         157 : static bool DGNGetRawExtents(DGNInfo *psDGN, int nType,
     145             :                              unsigned char *pabyRawData, GUInt32 *pnXMin,
     146             :                              GUInt32 *pnYMin, GUInt32 *pnZMin, GUInt32 *pnXMax,
     147             :                              GUInt32 *pnYMax, GUInt32 *pnZMax)
     148             : 
     149             : {
     150         157 :     if (pabyRawData == nullptr)
     151         155 :         pabyRawData = psDGN->abyElem + 0;
     152             : 
     153         157 :     switch (nType)
     154             :     {
     155          38 :         case DGNT_LINE:
     156             :         case DGNT_LINE_STRING:
     157             :         case DGNT_SHAPE:
     158             :         case DGNT_CURVE:
     159             :         case DGNT_BSPLINE_POLE:
     160             :         case DGNT_BSPLINE_SURFACE_HEADER:
     161             :         case DGNT_BSPLINE_CURVE_HEADER:
     162             :         case DGNT_ELLIPSE:
     163             :         case DGNT_ARC:
     164             :         case DGNT_TEXT:
     165             :         case DGNT_TEXT_NODE:
     166             :         case DGNT_COMPLEX_CHAIN_HEADER:
     167             :         case DGNT_COMPLEX_SHAPE_HEADER:
     168             :         case DGNT_CONE:
     169             :         case DGNT_3DSURFACE_HEADER:
     170             :         case DGNT_3DSOLID_HEADER:
     171          38 :             *pnXMin = DGN_INT32(pabyRawData + 4);
     172          38 :             *pnYMin = DGN_INT32(pabyRawData + 8);
     173          38 :             if (pnZMin != nullptr)
     174          34 :                 *pnZMin = DGN_INT32(pabyRawData + 12);
     175             : 
     176          38 :             *pnXMax = DGN_INT32(pabyRawData + 16);
     177          38 :             *pnYMax = DGN_INT32(pabyRawData + 20);
     178          38 :             if (pnZMax != nullptr)
     179          34 :                 *pnZMax = DGN_INT32(pabyRawData + 24);
     180          38 :             return true;
     181             : 
     182         119 :         default:
     183         119 :             return false;
     184             :     }
     185             : }
     186             : 
     187             : /************************************************************************/
     188             : /*                        DGNGetElementExtents()                        */
     189             : /************************************************************************/
     190             : 
     191             : /**
     192             :  * Fetch extents of an element.
     193             :  *
     194             :  * This function will return the extents of the passed element if possible.
     195             :  * The extents are extracted from the element header if it contains them,
     196             :  * and transformed into master georeferenced format.  Some element types
     197             :  * do not have extents at all and will fail.
     198             :  *
     199             :  * This call will also fail if the extents raw data for the element is not
     200             :  * available.  This will occur if it was not the most recently read element,
     201             :  * and if the raw_data field is not loaded.
     202             :  *
     203             :  * @param hDGN the handle of the file to read from.
     204             :  *
     205             :  * @param psElement the element to extract extents from.
     206             :  *
     207             :  * @param psMin structure loaded with X, Y and Z minimum values for the
     208             :  * extent.
     209             :  *
     210             :  * @param psMax structure loaded with X, Y and Z maximum values for the
     211             :  * extent.
     212             :  *
     213             :  * @return TRUE on success of FALSE if extracting extents fails.
     214             :  */
     215             : 
     216           2 : int DGNGetElementExtents(DGNHandle hDGN, DGNElemCore *psElement,
     217             :                          DGNPoint *psMin, DGNPoint *psMax)
     218             : 
     219             : {
     220           2 :     DGNInfo *psDGN = (DGNInfo *)hDGN;
     221           2 :     bool bResult = false;
     222             : 
     223           2 :     GUInt32 anMin[3] = {0, 0, 0};
     224           2 :     GUInt32 anMax[3] = {0, 0, 0};
     225             : 
     226             :     /* -------------------------------------------------------------------- */
     227             :     /*      Get the extents if we have raw data in the element, or          */
     228             :     /*      loaded in the file buffer.                                      */
     229             :     /* -------------------------------------------------------------------- */
     230           2 :     if (psElement->raw_data != nullptr)
     231           2 :         bResult = DGNGetRawExtents(psDGN, psElement->type, psElement->raw_data,
     232             :                                    anMin + 0, anMin + 1, anMin + 2, anMax + 0,
     233             :                                    anMax + 1, anMax + 2);
     234           0 :     else if (psElement->element_id == psDGN->next_element_id - 1)
     235           0 :         bResult = DGNGetRawExtents(psDGN, psElement->type, psDGN->abyElem + 0,
     236             :                                    anMin + 0, anMin + 1, anMin + 2, anMax + 0,
     237             :                                    anMax + 1, anMax + 2);
     238             :     else
     239             :     {
     240           0 :         CPLError(CE_Warning, CPLE_AppDefined,
     241             :                  "DGNGetElementExtents() fails because the requested element "
     242             :                  "does not have raw data available.");
     243           0 :         return FALSE;
     244             :     }
     245             : 
     246           2 :     if (!bResult)
     247           0 :         return FALSE;
     248             : 
     249             :     /* -------------------------------------------------------------------- */
     250             :     /*      Transform to user coordinate system and return.  The offset     */
     251             :     /*      is to convert from "binary offset" form to twos complement.     */
     252             :     /* -------------------------------------------------------------------- */
     253           2 :     psMin->x = anMin[0] - 2147483648.0;
     254           2 :     psMin->y = anMin[1] - 2147483648.0;
     255           2 :     psMin->z = anMin[2] - 2147483648.0;
     256             : 
     257           2 :     psMax->x = anMax[0] - 2147483648.0;
     258           2 :     psMax->y = anMax[1] - 2147483648.0;
     259           2 :     psMax->z = anMax[2] - 2147483648.0;
     260             : 
     261           2 :     DGNTransformPoint(psDGN, psMin);
     262           2 :     DGNTransformPoint(psDGN, psMax);
     263             : 
     264           2 :     return TRUE;
     265             : }
     266             : 
     267             : /************************************************************************/
     268             : /*                         DGNProcessElement()                          */
     269             : /*                                                                      */
     270             : /*      Assumes the raw element data has already been loaded, and       */
     271             : /*      tries to convert it into an element structure.                  */
     272             : /************************************************************************/
     273             : 
     274         561 : static DGNElemCore *DGNProcessElement(DGNInfo *psDGN, int nType, int nLevel)
     275             : 
     276             : {
     277         561 :     DGNElemCore *psElement = nullptr;
     278             : 
     279             :     /* -------------------------------------------------------------------- */
     280             :     /*      Handle based on element type.                                   */
     281             :     /* -------------------------------------------------------------------- */
     282         561 :     switch (nType)
     283             :     {
     284           0 :         case DGNT_CELL_HEADER:
     285             :         {
     286             :             DGNElemCellHeader *psCell = static_cast<DGNElemCellHeader *>(
     287           0 :                 CPLCalloc(sizeof(DGNElemCellHeader), 1));
     288           0 :             psElement = (DGNElemCore *)psCell;
     289           0 :             psElement->stype = DGNST_CELL_HEADER;
     290           0 :             DGNParseCore(psDGN, psElement);
     291             : 
     292           0 :             psCell->totlength = psDGN->abyElem[36] + psDGN->abyElem[37] * 256;
     293             : 
     294           0 :             DGNRad50ToAscii(psDGN->abyElem[38] + psDGN->abyElem[39] * 256,
     295           0 :                             psCell->name + 0);
     296           0 :             DGNRad50ToAscii(psDGN->abyElem[40] + psDGN->abyElem[41] * 256,
     297           0 :                             psCell->name + 3);
     298             : 
     299           0 :             psCell->cclass = psDGN->abyElem[42] + psDGN->abyElem[43] * 256;
     300           0 :             psCell->levels[0] = psDGN->abyElem[44] + psDGN->abyElem[45] * 256;
     301           0 :             psCell->levels[1] = psDGN->abyElem[46] + psDGN->abyElem[47] * 256;
     302           0 :             psCell->levels[2] = psDGN->abyElem[48] + psDGN->abyElem[49] * 256;
     303           0 :             psCell->levels[3] = psDGN->abyElem[50] + psDGN->abyElem[51] * 256;
     304             : 
     305           0 :             if (psDGN->dimension == 2)
     306             :             {
     307           0 :                 psCell->rnglow.x = DGN_INT32(psDGN->abyElem + 52);
     308           0 :                 psCell->rnglow.y = DGN_INT32(psDGN->abyElem + 56);
     309           0 :                 psCell->rnghigh.x = DGN_INT32(psDGN->abyElem + 60);
     310           0 :                 psCell->rnghigh.y = DGN_INT32(psDGN->abyElem + 64);
     311             : 
     312           0 :                 psCell->trans[0] =
     313           0 :                     1.0 * DGN_INT32(psDGN->abyElem + 68) / (1U << 31);
     314           0 :                 psCell->trans[1] =
     315           0 :                     1.0 * DGN_INT32(psDGN->abyElem + 72) / (1U << 31);
     316           0 :                 psCell->trans[2] =
     317           0 :                     1.0 * DGN_INT32(psDGN->abyElem + 76) / (1U << 31);
     318           0 :                 psCell->trans[3] =
     319           0 :                     1.0 * DGN_INT32(psDGN->abyElem + 80) / (1U << 31);
     320             : 
     321           0 :                 psCell->origin.x = DGN_INT32(psDGN->abyElem + 84);
     322           0 :                 psCell->origin.y = DGN_INT32(psDGN->abyElem + 88);
     323             : 
     324             :                 {
     325           0 :                     const double a = DGN_INT32(psDGN->abyElem + 68);
     326           0 :                     const double b = DGN_INT32(psDGN->abyElem + 72);
     327           0 :                     const double c = DGN_INT32(psDGN->abyElem + 76);
     328           0 :                     const double d = DGN_INT32(psDGN->abyElem + 80);
     329           0 :                     const double a2 = a * a;
     330           0 :                     const double c2 = c * c;
     331             : 
     332           0 :                     psCell->xscale = sqrt(a2 + c2) / 214748;
     333           0 :                     psCell->yscale = sqrt(b * b + d * d) / 214748;
     334           0 :                     if ((a2 + c2) <= 0.0)
     335           0 :                         psCell->rotation = 0.0;
     336             :                     else
     337           0 :                         psCell->rotation = acos(a / sqrt(a2 + c2));
     338             : 
     339           0 :                     if (b <= 0)
     340           0 :                         psCell->rotation = psCell->rotation * 180 / M_PI;
     341             :                     else
     342           0 :                         psCell->rotation = 360 - psCell->rotation * 180 / M_PI;
     343             :                 }
     344             :             }
     345             :             else
     346             :             {
     347           0 :                 psCell->rnglow.x = DGN_INT32(psDGN->abyElem + 52);
     348           0 :                 psCell->rnglow.y = DGN_INT32(psDGN->abyElem + 56);
     349           0 :                 psCell->rnglow.z = DGN_INT32(psDGN->abyElem + 60);
     350           0 :                 psCell->rnghigh.x = DGN_INT32(psDGN->abyElem + 64);
     351           0 :                 psCell->rnghigh.y = DGN_INT32(psDGN->abyElem + 68);
     352           0 :                 psCell->rnghigh.z = DGN_INT32(psDGN->abyElem + 72);
     353             : 
     354           0 :                 psCell->trans[0] =
     355           0 :                     1.0 * DGN_INT32(psDGN->abyElem + 76) / (1U << 31);
     356           0 :                 psCell->trans[1] =
     357           0 :                     1.0 * DGN_INT32(psDGN->abyElem + 80) / (1U << 31);
     358           0 :                 psCell->trans[2] =
     359           0 :                     1.0 * DGN_INT32(psDGN->abyElem + 84) / (1U << 31);
     360           0 :                 psCell->trans[3] =
     361           0 :                     1.0 * DGN_INT32(psDGN->abyElem + 88) / (1U << 31);
     362           0 :                 psCell->trans[4] =
     363           0 :                     1.0 * DGN_INT32(psDGN->abyElem + 92) / (1U << 31);
     364           0 :                 psCell->trans[5] =
     365           0 :                     1.0 * DGN_INT32(psDGN->abyElem + 96) / (1U << 31);
     366           0 :                 psCell->trans[6] =
     367           0 :                     1.0 * DGN_INT32(psDGN->abyElem + 100) / (1U << 31);
     368           0 :                 psCell->trans[7] =
     369           0 :                     1.0 * DGN_INT32(psDGN->abyElem + 104) / (1U << 31);
     370           0 :                 psCell->trans[8] =
     371           0 :                     1.0 * DGN_INT32(psDGN->abyElem + 108) / (1U << 31);
     372             : 
     373           0 :                 psCell->origin.x = DGN_INT32(psDGN->abyElem + 112);
     374           0 :                 psCell->origin.y = DGN_INT32(psDGN->abyElem + 116);
     375           0 :                 psCell->origin.z = DGN_INT32(psDGN->abyElem + 120);
     376             :             }
     377             : 
     378           0 :             DGNTransformPoint(psDGN, &(psCell->rnglow));
     379           0 :             DGNTransformPoint(psDGN, &(psCell->rnghigh));
     380           0 :             DGNTransformPoint(psDGN, &(psCell->origin));
     381             :         }
     382           0 :         break;
     383             : 
     384           0 :         case DGNT_CELL_LIBRARY:
     385             :         {
     386             :             DGNElemCellLibrary *psCell = static_cast<DGNElemCellLibrary *>(
     387           0 :                 CPLCalloc(sizeof(DGNElemCellLibrary), 1));
     388           0 :             psElement = (DGNElemCore *)psCell;
     389           0 :             psElement->stype = DGNST_CELL_LIBRARY;
     390           0 :             DGNParseCore(psDGN, psElement);
     391             : 
     392           0 :             DGNRad50ToAscii(psDGN->abyElem[32] + psDGN->abyElem[33] * 256,
     393           0 :                             psCell->name + 0);
     394           0 :             DGNRad50ToAscii(psDGN->abyElem[34] + psDGN->abyElem[35] * 256,
     395           0 :                             psCell->name + 3);
     396             : 
     397           0 :             psElement->properties =
     398           0 :                 psDGN->abyElem[38] + psDGN->abyElem[39] * 256;
     399             : 
     400           0 :             psCell->dispsymb = psDGN->abyElem[40] + psDGN->abyElem[41] * 256;
     401             : 
     402           0 :             psCell->cclass = psDGN->abyElem[42] + psDGN->abyElem[43] * 256;
     403           0 :             psCell->levels[0] = psDGN->abyElem[44] + psDGN->abyElem[45] * 256;
     404           0 :             psCell->levels[1] = psDGN->abyElem[46] + psDGN->abyElem[47] * 256;
     405           0 :             psCell->levels[2] = psDGN->abyElem[48] + psDGN->abyElem[49] * 256;
     406           0 :             psCell->levels[3] = psDGN->abyElem[50] + psDGN->abyElem[51] * 256;
     407             : 
     408           0 :             psCell->numwords = psDGN->abyElem[36] + psDGN->abyElem[37] * 256;
     409             : 
     410           0 :             memset(psCell->description, 0, sizeof(psCell->description));
     411             : 
     412           0 :             for (int iWord = 0; iWord < 9; iWord++)
     413             :             {
     414           0 :                 int iOffset = 52 + iWord * 2;
     415             : 
     416           0 :                 DGNRad50ToAscii(psDGN->abyElem[iOffset] +
     417           0 :                                     psDGN->abyElem[iOffset + 1] * 256,
     418           0 :                                 psCell->description + iWord * 3);
     419             :             }
     420             :         }
     421           0 :         break;
     422             : 
     423          10 :         case DGNT_LINE:
     424             :         {
     425             :             DGNElemMultiPoint *psLine = static_cast<DGNElemMultiPoint *>(
     426          10 :                 CPLCalloc(sizeof(DGNElemMultiPoint) + sizeof(DGNPoint), 1));
     427          10 :             psElement = (DGNElemCore *)psLine;
     428          10 :             psElement->stype = DGNST_MULTIPOINT;
     429          10 :             DGNParseCore(psDGN, psElement);
     430             : 
     431          10 :             int deltaLength = 0, deltaStart = 0;
     432          10 :             if (psLine->core.properties & DGNPF_ATTRIBUTES)
     433             :             {
     434          98 :                 for (int iAttr = 0; iAttr < psLine->core.attr_bytes - 3;
     435             :                      iAttr++)
     436             :                 {
     437          91 :                     if (psLine->core.attr_data[iAttr] == 0xA9 &&
     438           0 :                         psLine->core.attr_data[iAttr + 1] == 0x51)
     439             :                     {
     440           0 :                         deltaLength =
     441           0 :                             (psLine->core.attr_data[iAttr + 2] +
     442           0 :                              psLine->core.attr_data[iAttr + 3] * 256) *
     443             :                             2;
     444           0 :                         deltaStart = iAttr + 6;
     445           0 :                         break;
     446             :                     }
     447             :                 }
     448             :             }
     449             : 
     450          10 :             psLine->num_vertices = 2;
     451          10 :             if (psDGN->dimension == 2)
     452             :             {
     453           7 :                 psLine->vertices[0].x = DGN_INT32(psDGN->abyElem + 36);
     454           7 :                 psLine->vertices[0].y = DGN_INT32(psDGN->abyElem + 40);
     455           7 :                 psLine->vertices[1].x = DGN_INT32(psDGN->abyElem + 44);
     456           7 :                 psLine->vertices[1].y = DGN_INT32(psDGN->abyElem + 48);
     457             :             }
     458             :             else
     459             :             {
     460           3 :                 psLine->vertices[0].x = DGN_INT32(psDGN->abyElem + 36);
     461           3 :                 psLine->vertices[0].y = DGN_INT32(psDGN->abyElem + 40);
     462           3 :                 psLine->vertices[0].z = DGN_INT32(psDGN->abyElem + 44);
     463           3 :                 psLine->vertices[1].x = DGN_INT32(psDGN->abyElem + 48);
     464           3 :                 psLine->vertices[1].y = DGN_INT32(psDGN->abyElem + 52);
     465           3 :                 psLine->vertices[1].z = DGN_INT32(psDGN->abyElem + 56);
     466             :             }
     467             : 
     468          10 :             if (deltaStart && deltaLength &&
     469           0 :                 deltaStart + 1 * 4 + 2 + 2 <= psLine->core.attr_bytes)
     470             :             {
     471           0 :                 for (int i = 0; i < 2; i++)
     472             :                 {
     473             :                     int dx =
     474           0 :                         DGN_INT16(psLine->core.attr_data + deltaStart + i * 4);
     475           0 :                     int dy = DGN_INT16(psLine->core.attr_data + deltaStart +
     476           0 :                                        i * 4 + 2);
     477           0 :                     psLine->vertices[i].x += dx / 32767.0;
     478           0 :                     psLine->vertices[i].y += dy / 32767.0;
     479             :                 }
     480             :             }
     481             : 
     482          10 :             DGNTransformPoint(psDGN, psLine->vertices + 0);
     483          10 :             DGNTransformPoint(psDGN, psLine->vertices + 1);
     484             :         }
     485          10 :         break;
     486             : 
     487          16 :         case DGNT_LINE_STRING:
     488             :         case DGNT_SHAPE:
     489             :         case DGNT_CURVE:
     490             :         case DGNT_BSPLINE_POLE:
     491             :         {
     492          16 :             int pntsize = psDGN->dimension * 4;
     493             : 
     494          16 :             int count = psDGN->abyElem[36] + psDGN->abyElem[37] * 256;
     495          16 :             if (count < 2)
     496             :             {
     497           0 :                 CPLError(CE_Failure, CPLE_AssertionFailed, "count < 2");
     498           0 :                 return nullptr;
     499             :             }
     500             :             DGNElemMultiPoint *psLine =
     501          16 :                 static_cast<DGNElemMultiPoint *>(VSI_CALLOC_VERBOSE(
     502             :                     sizeof(DGNElemMultiPoint) + (count - 1) * sizeof(DGNPoint),
     503             :                     1));
     504          16 :             if (psLine == nullptr)
     505           0 :                 return nullptr;
     506          16 :             psElement = (DGNElemCore *)psLine;
     507          16 :             psElement->stype = DGNST_MULTIPOINT;
     508          16 :             DGNParseCore(psDGN, psElement);
     509             : 
     510          16 :             if (psDGN->nElemBytes < 38 + count * pntsize)
     511             :             {
     512           0 :                 int new_count = (psDGN->nElemBytes - 38) / pntsize;
     513           0 :                 if (new_count < 0)
     514             :                 {
     515           0 :                     CPLError(CE_Failure, CPLE_AssertionFailed, "new_count < 2");
     516           0 :                     DGNFreeElement(psDGN, psElement);
     517           0 :                     return nullptr;
     518             :                 }
     519           0 :                 CPLError(CE_Warning, CPLE_AppDefined,
     520             :                          "Trimming multipoint vertices to %d from %d because\n"
     521             :                          "element is short.\n",
     522             :                          new_count, count);
     523           0 :                 count = new_count;
     524             :             }
     525          16 :             int deltaLength = 0, deltaStart = 0;
     526          16 :             if (psLine->core.properties & DGNPF_ATTRIBUTES)
     527             :             {
     528         196 :                 for (int iAttr = 0; iAttr < psLine->core.attr_bytes - 3;
     529             :                      iAttr++)
     530             :                 {
     531         182 :                     if (psLine->core.attr_data[iAttr] == 0xA9 &&
     532           0 :                         psLine->core.attr_data[iAttr + 1] == 0x51)
     533             :                     {
     534           0 :                         deltaLength =
     535           0 :                             (psLine->core.attr_data[iAttr + 2] +
     536           0 :                              psLine->core.attr_data[iAttr + 3] * 256) *
     537             :                             2;
     538           0 :                         deltaStart = iAttr + 6;
     539           0 :                         break;
     540             :                     }
     541             :                 }
     542             :             }
     543         145 :             for (int i = 0; i < count && ((psDGN->dimension == 3) ? 46 : 42) +
     544         129 :                                                  i * pntsize + 4 <=
     545         129 :                                              psDGN->nElemBytes;
     546             :                  i++)
     547             :             {
     548         129 :                 psLine->vertices[i].x =
     549         129 :                     DGN_INT32(psDGN->abyElem + 38 + i * pntsize);
     550         129 :                 psLine->vertices[i].y =
     551         129 :                     DGN_INT32(psDGN->abyElem + 42 + i * pntsize);
     552         129 :                 if (psDGN->dimension == 3)
     553          14 :                     psLine->vertices[i].z =
     554          14 :                         DGN_INT32(psDGN->abyElem + 46 + i * pntsize);
     555         129 :                 if (deltaStart && deltaLength &&
     556           0 :                     deltaStart + i * 4 + 2 + 2 <= psLine->core.attr_bytes)
     557             :                 {
     558             :                     int dx =
     559           0 :                         DGN_INT16(psLine->core.attr_data + deltaStart + i * 4);
     560           0 :                     int dy = DGN_INT16(psLine->core.attr_data + deltaStart +
     561           0 :                                        i * 4 + 2);
     562           0 :                     psLine->vertices[i].x += dx / 32767.0;
     563           0 :                     psLine->vertices[i].y += dy / 32767.0;
     564             :                 }
     565         129 :                 DGNTransformPoint(psDGN, psLine->vertices + i);
     566         129 :                 psLine->num_vertices = i + 1;
     567             :             }
     568             :         }
     569          16 :         break;
     570             : 
     571           0 :         case DGNT_TEXT_NODE:
     572             :         {
     573             :             DGNElemTextNode *psNode = static_cast<DGNElemTextNode *>(
     574           0 :                 CPLCalloc(sizeof(DGNElemTextNode), 1));
     575           0 :             psElement = (DGNElemCore *)psNode;
     576           0 :             psElement->stype = DGNST_TEXT_NODE;
     577           0 :             DGNParseCore(psDGN, psElement);
     578             : 
     579           0 :             psNode->totlength = psDGN->abyElem[36] + psDGN->abyElem[37] * 256;
     580           0 :             psNode->numelems = psDGN->abyElem[38] + psDGN->abyElem[39] * 256;
     581             : 
     582           0 :             psNode->node_number = psDGN->abyElem[40] + psDGN->abyElem[41] * 256;
     583           0 :             psNode->max_length = psDGN->abyElem[42];
     584           0 :             psNode->max_used = psDGN->abyElem[43];
     585           0 :             psNode->font_id = psDGN->abyElem[44];
     586           0 :             psNode->justification = psDGN->abyElem[45];
     587           0 :             psNode->length_mult =
     588           0 :                 (DGN_INT32(psDGN->abyElem + 50)) * psDGN->scale * 6.0 / 1000.0;
     589           0 :             psNode->height_mult =
     590           0 :                 (DGN_INT32(psDGN->abyElem + 54)) * psDGN->scale * 6.0 / 1000.0;
     591             : 
     592           0 :             if (psDGN->dimension == 2)
     593             :             {
     594           0 :                 psNode->rotation = DGN_INT32(psDGN->abyElem + 58) / 360000.0;
     595             : 
     596           0 :                 psNode->origin.x = DGN_INT32(psDGN->abyElem + 62);
     597           0 :                 psNode->origin.y = DGN_INT32(psDGN->abyElem + 66);
     598             :             }
     599             :             else
     600             :             {
     601             :                 /* leave quaternion for later */
     602             : 
     603           0 :                 psNode->origin.x = DGN_INT32(psDGN->abyElem + 74);
     604           0 :                 psNode->origin.y = DGN_INT32(psDGN->abyElem + 78);
     605           0 :                 psNode->origin.z = DGN_INT32(psDGN->abyElem + 82);
     606             :             }
     607           0 :             DGNTransformPoint(psDGN, &(psNode->origin));
     608             :         }
     609           0 :         break;
     610             : 
     611           7 :         case DGNT_GROUP_DATA:
     612           7 :             if (nLevel == DGN_GDL_COLOR_TABLE)
     613             :             {
     614           0 :                 psElement = DGNParseColorTable(psDGN);
     615             :             }
     616             :             else
     617             :             {
     618             :                 psElement = static_cast<DGNElemCore *>(
     619           7 :                     CPLCalloc(sizeof(DGNElemCore), 1));
     620           7 :                 psElement->stype = DGNST_CORE;
     621           7 :                 DGNParseCore(psDGN, psElement);
     622             :             }
     623           7 :             break;
     624             : 
     625           6 :         case DGNT_ELLIPSE:
     626             :         {
     627             :             DGNElemArc *psEllipse =
     628           6 :                 static_cast<DGNElemArc *>(CPLCalloc(sizeof(DGNElemArc), 1));
     629           6 :             psElement = (DGNElemCore *)psEllipse;
     630           6 :             psElement->stype = DGNST_ARC;
     631           6 :             DGNParseCore(psDGN, psElement);
     632             : 
     633           6 :             memcpy(&(psEllipse->primary_axis), psDGN->abyElem + 36, 8);
     634           6 :             DGN2IEEEDouble(&(psEllipse->primary_axis));
     635           6 :             psEllipse->primary_axis *= psDGN->scale;
     636             : 
     637           6 :             memcpy(&(psEllipse->secondary_axis), psDGN->abyElem + 44, 8);
     638           6 :             DGN2IEEEDouble(&(psEllipse->secondary_axis));
     639           6 :             psEllipse->secondary_axis *= psDGN->scale;
     640             : 
     641           6 :             if (psDGN->dimension == 2)
     642             :             {
     643           6 :                 psEllipse->rotation = DGN_INT32(psDGN->abyElem + 52);
     644           6 :                 psEllipse->rotation = psEllipse->rotation / 360000.0;
     645             : 
     646           6 :                 memcpy(&(psEllipse->origin.x), psDGN->abyElem + 56, 8);
     647           6 :                 DGN2IEEEDouble(&(psEllipse->origin.x));
     648             : 
     649           6 :                 memcpy(&(psEllipse->origin.y), psDGN->abyElem + 64, 8);
     650           6 :                 DGN2IEEEDouble(&(psEllipse->origin.y));
     651             :             }
     652             :             else
     653             :             {
     654             :                 /* leave quaternion for later */
     655             : 
     656           0 :                 memcpy(&(psEllipse->origin.x), psDGN->abyElem + 68, 8);
     657           0 :                 DGN2IEEEDouble(&(psEllipse->origin.x));
     658             : 
     659           0 :                 memcpy(&(psEllipse->origin.y), psDGN->abyElem + 76, 8);
     660           0 :                 DGN2IEEEDouble(&(psEllipse->origin.y));
     661             : 
     662           0 :                 memcpy(&(psEllipse->origin.z), psDGN->abyElem + 84, 8);
     663           0 :                 DGN2IEEEDouble(&(psEllipse->origin.z));
     664             : 
     665           0 :                 psEllipse->quat[0] = DGN_INT32(psDGN->abyElem + 52);
     666           0 :                 psEllipse->quat[1] = DGN_INT32(psDGN->abyElem + 56);
     667           0 :                 psEllipse->quat[2] = DGN_INT32(psDGN->abyElem + 60);
     668           0 :                 psEllipse->quat[3] = DGN_INT32(psDGN->abyElem + 64);
     669             :             }
     670             : 
     671           6 :             DGNTransformPoint(psDGN, &(psEllipse->origin));
     672             : 
     673           6 :             psEllipse->startang = 0.0;
     674           6 :             psEllipse->sweepang = 360.0;
     675             :         }
     676           6 :         break;
     677             : 
     678           0 :         case DGNT_ARC:
     679             :         {
     680           0 :             GInt32 nSweepVal = 0;
     681             : 
     682             :             DGNElemArc *psEllipse =
     683           0 :                 static_cast<DGNElemArc *>(CPLCalloc(sizeof(DGNElemArc), 1));
     684           0 :             psElement = (DGNElemCore *)psEllipse;
     685           0 :             psElement->stype = DGNST_ARC;
     686           0 :             DGNParseCore(psDGN, psElement);
     687             : 
     688           0 :             psEllipse->startang = DGN_INT32(psDGN->abyElem + 36);
     689           0 :             psEllipse->startang = psEllipse->startang / 360000.0;
     690           0 :             if (psDGN->abyElem[41] & 0x80)
     691             :             {
     692           0 :                 psDGN->abyElem[41] &= 0x7f;
     693           0 :                 nSweepVal = -1 * DGN_INT32(psDGN->abyElem + 40);
     694             :             }
     695             :             else
     696           0 :                 nSweepVal = DGN_INT32(psDGN->abyElem + 40);
     697             : 
     698           0 :             if (nSweepVal == 0)
     699           0 :                 psEllipse->sweepang = 360.0;
     700             :             else
     701           0 :                 psEllipse->sweepang = nSweepVal / 360000.0;
     702             : 
     703           0 :             memcpy(&(psEllipse->primary_axis), psDGN->abyElem + 44, 8);
     704           0 :             DGN2IEEEDouble(&(psEllipse->primary_axis));
     705           0 :             psEllipse->primary_axis *= psDGN->scale;
     706             : 
     707           0 :             memcpy(&(psEllipse->secondary_axis), psDGN->abyElem + 52, 8);
     708           0 :             DGN2IEEEDouble(&(psEllipse->secondary_axis));
     709           0 :             psEllipse->secondary_axis *= psDGN->scale;
     710             : 
     711           0 :             if (psDGN->dimension == 2)
     712             :             {
     713           0 :                 psEllipse->rotation = DGN_INT32(psDGN->abyElem + 60);
     714           0 :                 psEllipse->rotation = psEllipse->rotation / 360000.0;
     715             : 
     716           0 :                 memcpy(&(psEllipse->origin.x), psDGN->abyElem + 64, 8);
     717           0 :                 DGN2IEEEDouble(&(psEllipse->origin.x));
     718             : 
     719           0 :                 memcpy(&(psEllipse->origin.y), psDGN->abyElem + 72, 8);
     720           0 :                 DGN2IEEEDouble(&(psEllipse->origin.y));
     721             :             }
     722             :             else
     723             :             {
     724             :                 /* for now we don't try to handle quaternion */
     725           0 :                 psEllipse->rotation = 0;
     726             : 
     727           0 :                 memcpy(&(psEllipse->origin.x), psDGN->abyElem + 76, 8);
     728           0 :                 DGN2IEEEDouble(&(psEllipse->origin.x));
     729             : 
     730           0 :                 memcpy(&(psEllipse->origin.y), psDGN->abyElem + 84, 8);
     731           0 :                 DGN2IEEEDouble(&(psEllipse->origin.y));
     732             : 
     733           0 :                 memcpy(&(psEllipse->origin.z), psDGN->abyElem + 92, 8);
     734           0 :                 DGN2IEEEDouble(&(psEllipse->origin.z));
     735             : 
     736           0 :                 psEllipse->quat[0] = DGN_INT32(psDGN->abyElem + 60);
     737           0 :                 psEllipse->quat[1] = DGN_INT32(psDGN->abyElem + 64);
     738           0 :                 psEllipse->quat[2] = DGN_INT32(psDGN->abyElem + 68);
     739           0 :                 psEllipse->quat[3] = DGN_INT32(psDGN->abyElem + 72);
     740             :             }
     741             : 
     742           0 :             DGNTransformPoint(psDGN, &(psEllipse->origin));
     743             :         }
     744           0 :         break;
     745             : 
     746           7 :         case DGNT_TEXT:
     747             :         {
     748           7 :             int num_chars = 0;
     749           7 :             int text_off = 0;
     750             : 
     751           7 :             if (psDGN->dimension == 2)
     752           7 :                 num_chars = psDGN->abyElem[58];
     753             :             else
     754           0 :                 num_chars = psDGN->abyElem[74];
     755             : 
     756             :             DGNElemText *psText = static_cast<DGNElemText *>(
     757           7 :                 CPLCalloc(sizeof(DGNElemText) + num_chars, 1));
     758           7 :             psElement = (DGNElemCore *)psText;
     759           7 :             psElement->stype = DGNST_TEXT;
     760           7 :             DGNParseCore(psDGN, psElement);
     761             : 
     762           7 :             psText->font_id = psDGN->abyElem[36];
     763           7 :             psText->justification = psDGN->abyElem[37];
     764           7 :             psText->length_mult =
     765           7 :                 (DGN_INT32(psDGN->abyElem + 38)) * psDGN->scale * 6.0 / 1000.0;
     766           7 :             psText->height_mult =
     767           7 :                 (DGN_INT32(psDGN->abyElem + 42)) * psDGN->scale * 6.0 / 1000.0;
     768             : 
     769           7 :             if (psDGN->dimension == 2)
     770             :             {
     771           7 :                 psText->rotation = DGN_INT32(psDGN->abyElem + 46);
     772           7 :                 psText->rotation = psText->rotation / 360000.0;
     773             : 
     774           7 :                 psText->origin.x = DGN_INT32(psDGN->abyElem + 50);
     775           7 :                 psText->origin.y = DGN_INT32(psDGN->abyElem + 54);
     776           7 :                 text_off = 60;
     777             :             }
     778             :             else
     779             :             {
     780             :                 /* leave quaternion for later */
     781             : 
     782           0 :                 psText->origin.x = DGN_INT32(psDGN->abyElem + 62);
     783           0 :                 psText->origin.y = DGN_INT32(psDGN->abyElem + 66);
     784           0 :                 psText->origin.z = DGN_INT32(psDGN->abyElem + 70);
     785           0 :                 text_off = 76;
     786             :             }
     787             : 
     788           7 :             DGNTransformPoint(psDGN, &(psText->origin));
     789             : 
     790             :             /* experimental multibyte support from Ason Kang
     791             :              * (hiska@netian.com)*/
     792           7 :             if (*(psDGN->abyElem + text_off) == 0xFF &&
     793           0 :                 *(psDGN->abyElem + text_off + 1) == 0xFD)
     794             :             {
     795           0 :                 int n = 0;
     796           0 :                 for (int i = 0; i < num_chars / 2 - 1; i++)
     797             :                 {
     798           0 :                     unsigned short w = 0;
     799           0 :                     memcpy(&w, psDGN->abyElem + text_off + 2 + i * 2, 2);
     800           0 :                     CPL_LSBPTR16(&w);
     801           0 :                     if (w < 256)
     802             :                     {  // if alpa-numeric code area : Normal character
     803           0 :                         *(psText->string + n) = (char)(w & 0xFF);
     804           0 :                         n++;  // skip 1 byte;
     805             :                     }
     806             :                     else
     807             :                     {  // if extend code area : 2 byte Korean character
     808           0 :                         *(psText->string + n) = (char)(w >> 8);        // hi
     809           0 :                         *(psText->string + n + 1) = (char)(w & 0xFF);  // lo
     810           0 :                         n += 2;                                        // 2 byte
     811             :                     }
     812             :                 }
     813           0 :                 psText->string[n] = '\0';  // terminate C string
     814             :             }
     815             :             else
     816             :             {
     817           7 :                 memcpy(psText->string, psDGN->abyElem + text_off, num_chars);
     818           7 :                 psText->string[num_chars] = '\0';
     819             :             }
     820             :         }
     821           7 :         break;
     822             : 
     823          97 :         case DGNT_TCB:
     824          97 :             psElement = DGNParseTCB(psDGN);
     825          97 :             break;
     826             : 
     827           1 :         case DGNT_COMPLEX_CHAIN_HEADER:
     828             :         case DGNT_COMPLEX_SHAPE_HEADER:
     829             :         {
     830             :             DGNElemComplexHeader *psHdr = static_cast<DGNElemComplexHeader *>(
     831           1 :                 CPLCalloc(sizeof(DGNElemComplexHeader), 1));
     832           1 :             psElement = (DGNElemCore *)psHdr;
     833           1 :             psElement->stype = DGNST_COMPLEX_HEADER;
     834           1 :             DGNParseCore(psDGN, psElement);
     835             : 
     836           1 :             psHdr->totlength = psDGN->abyElem[36] + psDGN->abyElem[37] * 256;
     837           1 :             psHdr->numelems = psDGN->abyElem[38] + psDGN->abyElem[39] * 256;
     838             :         }
     839           1 :         break;
     840             : 
     841           0 :         case DGNT_TAG_VALUE:
     842             :         {
     843             :             DGNElemTagValue *psTag = static_cast<DGNElemTagValue *>(
     844           0 :                 CPLCalloc(sizeof(DGNElemTagValue), 1));
     845           0 :             psElement = (DGNElemCore *)psTag;
     846           0 :             psElement->stype = DGNST_TAG_VALUE;
     847           0 :             DGNParseCore(psDGN, psElement);
     848             : 
     849           0 :             psTag->tagType = psDGN->abyElem[74] + psDGN->abyElem[75] * 256;
     850           0 :             memcpy(&(psTag->tagSet), psDGN->abyElem + 68, 4);
     851           0 :             CPL_LSBPTR32(&(psTag->tagSet));
     852           0 :             psTag->tagIndex = psDGN->abyElem[72] + psDGN->abyElem[73] * 256;
     853           0 :             psTag->tagLength = psDGN->abyElem[150] + psDGN->abyElem[151] * 256;
     854             : 
     855           0 :             if (psTag->tagType == 1)
     856             :             {
     857           0 :                 psTag->tagValue.string =
     858           0 :                     CPLStrdup((char *)psDGN->abyElem + 154);
     859             :             }
     860           0 :             else if (psTag->tagType == 3)
     861             :             {
     862           0 :                 memcpy(&(psTag->tagValue.integer), psDGN->abyElem + 154, 4);
     863           0 :                 CPL_LSBPTR32(&(psTag->tagValue.integer));
     864             :             }
     865           0 :             else if (psTag->tagType == 4)
     866             :             {
     867           0 :                 memcpy(&(psTag->tagValue.real), psDGN->abyElem + 154, 8);
     868           0 :                 DGN2IEEEDouble(&(psTag->tagValue.real));
     869             :             }
     870             :         }
     871           0 :         break;
     872             : 
     873         303 :         case DGNT_APPLICATION_ELEM:
     874         303 :             if (nLevel == 24)
     875             :             {
     876           0 :                 psElement = DGNParseTagSet(psDGN);
     877           0 :                 if (psElement == nullptr)
     878           0 :                     return nullptr;
     879             :             }
     880             :             else
     881             :             {
     882             :                 psElement = static_cast<DGNElemCore *>(
     883         303 :                     CPLCalloc(sizeof(DGNElemCore), 1));
     884         303 :                 psElement->stype = DGNST_CORE;
     885         303 :                 DGNParseCore(psDGN, psElement);
     886             :             }
     887         303 :             break;
     888             : 
     889           0 :         case DGNT_CONE:
     890             :         {
     891           0 :             if (psDGN->dimension != 3)
     892             :             {
     893           0 :                 CPLError(CE_Failure, CPLE_AssertionFailed,
     894             :                          "psDGN->dimension != 3");
     895           0 :                 return nullptr;
     896             :             }
     897             : 
     898             :             DGNElemCone *psCone =
     899           0 :                 static_cast<DGNElemCone *>(CPLCalloc(sizeof(DGNElemCone), 1));
     900           0 :             psElement = (DGNElemCore *)psCone;
     901           0 :             psElement->stype = DGNST_CONE;
     902           0 :             DGNParseCore(psDGN, psElement);
     903             : 
     904           0 :             psCone->unknown = psDGN->abyElem[36] + psDGN->abyElem[37] * 256;
     905           0 :             psCone->quat[0] = DGN_INT32(psDGN->abyElem + 38);
     906           0 :             psCone->quat[1] = DGN_INT32(psDGN->abyElem + 42);
     907           0 :             psCone->quat[2] = DGN_INT32(psDGN->abyElem + 46);
     908           0 :             psCone->quat[3] = DGN_INT32(psDGN->abyElem + 50);
     909             : 
     910           0 :             memcpy(&(psCone->center_1.x), psDGN->abyElem + 54, 8);
     911           0 :             DGN2IEEEDouble(&(psCone->center_1.x));
     912           0 :             memcpy(&(psCone->center_1.y), psDGN->abyElem + 62, 8);
     913           0 :             DGN2IEEEDouble(&(psCone->center_1.y));
     914           0 :             memcpy(&(psCone->center_1.z), psDGN->abyElem + 70, 8);
     915           0 :             DGN2IEEEDouble(&(psCone->center_1.z));
     916           0 :             memcpy(&(psCone->radius_1), psDGN->abyElem + 78, 8);
     917           0 :             DGN2IEEEDouble(&(psCone->radius_1));
     918             : 
     919           0 :             memcpy(&(psCone->center_2.x), psDGN->abyElem + 86, 8);
     920           0 :             DGN2IEEEDouble(&(psCone->center_2.x));
     921           0 :             memcpy(&(psCone->center_2.y), psDGN->abyElem + 94, 8);
     922           0 :             DGN2IEEEDouble(&(psCone->center_2.y));
     923           0 :             memcpy(&(psCone->center_2.z), psDGN->abyElem + 102, 8);
     924           0 :             DGN2IEEEDouble(&(psCone->center_2.z));
     925           0 :             memcpy(&(psCone->radius_2), psDGN->abyElem + 110, 8);
     926           0 :             DGN2IEEEDouble(&(psCone->radius_2));
     927             : 
     928           0 :             psCone->radius_1 *= psDGN->scale;
     929           0 :             psCone->radius_2 *= psDGN->scale;
     930           0 :             DGNTransformPoint(psDGN, &psCone->center_1);
     931           0 :             DGNTransformPoint(psDGN, &psCone->center_2);
     932             :         }
     933           0 :         break;
     934             : 
     935           0 :         case DGNT_3DSURFACE_HEADER:
     936             :         case DGNT_3DSOLID_HEADER:
     937             :         {
     938             :             DGNElemComplexHeader *psShape = static_cast<DGNElemComplexHeader *>(
     939           0 :                 CPLCalloc(sizeof(DGNElemComplexHeader), 1));
     940           0 :             psElement = (DGNElemCore *)psShape;
     941           0 :             psElement->stype = DGNST_COMPLEX_HEADER;
     942           0 :             DGNParseCore(psDGN, psElement);
     943             : 
     944             :             // Read complex header
     945           0 :             psShape->totlength = psDGN->abyElem[36] + psDGN->abyElem[37] * 256;
     946           0 :             psShape->numelems = psDGN->abyElem[38] + psDGN->abyElem[39] * 256;
     947           0 :             psShape->surftype = psDGN->abyElem[40];
     948           0 :             psShape->boundelms = psDGN->abyElem[41] + 1;
     949             :         }
     950           0 :         break;
     951           0 :         case DGNT_BSPLINE_SURFACE_HEADER:
     952             :         {
     953             :             DGNElemBSplineSurfaceHeader *psSpline =
     954             :                 static_cast<DGNElemBSplineSurfaceHeader *>(
     955           0 :                     CPLCalloc(sizeof(DGNElemBSplineSurfaceHeader), 1));
     956           0 :             psElement = (DGNElemCore *)psSpline;
     957           0 :             psElement->stype = DGNST_BSPLINE_SURFACE_HEADER;
     958           0 :             DGNParseCore(psDGN, psElement);
     959             : 
     960             :             // Read B-Spline surface header
     961           0 :             psSpline->desc_words =
     962           0 :                 static_cast<long>(DGN_INT32(psDGN->abyElem + 36));
     963           0 :             psSpline->curve_type = psDGN->abyElem[41];
     964             : 
     965             :             // U
     966           0 :             psSpline->u_order = (psDGN->abyElem[40] & 0x0f) + 2;
     967           0 :             psSpline->u_properties = psDGN->abyElem[40] & 0xf0;
     968           0 :             psSpline->num_poles_u =
     969           0 :                 psDGN->abyElem[42] + psDGN->abyElem[43] * 256;
     970           0 :             psSpline->num_knots_u =
     971           0 :                 psDGN->abyElem[44] + psDGN->abyElem[45] * 256;
     972           0 :             psSpline->rule_lines_u =
     973           0 :                 psDGN->abyElem[46] + psDGN->abyElem[47] * 256;
     974             : 
     975             :             // V
     976           0 :             psSpline->v_order = (psDGN->abyElem[48] & 0x0f) + 2;
     977           0 :             psSpline->v_properties = psDGN->abyElem[48] & 0xf0;
     978           0 :             psSpline->num_poles_v =
     979           0 :                 psDGN->abyElem[50] + psDGN->abyElem[51] * 256;
     980           0 :             psSpline->num_knots_v =
     981           0 :                 psDGN->abyElem[52] + psDGN->abyElem[53] * 256;
     982           0 :             psSpline->rule_lines_v =
     983           0 :                 psDGN->abyElem[54] + psDGN->abyElem[55] * 256;
     984             : 
     985           0 :             psSpline->num_bounds =
     986           0 :                 psDGN->abyElem[56] + psDGN->abyElem[57] * 556;
     987             :         }
     988           0 :         break;
     989           0 :         case DGNT_BSPLINE_CURVE_HEADER:
     990             :         {
     991             :             DGNElemBSplineCurveHeader *psSpline =
     992             :                 static_cast<DGNElemBSplineCurveHeader *>(
     993           0 :                     CPLCalloc(sizeof(DGNElemBSplineCurveHeader), 1));
     994           0 :             psElement = (DGNElemCore *)psSpline;
     995           0 :             psElement->stype = DGNST_BSPLINE_CURVE_HEADER;
     996           0 :             DGNParseCore(psDGN, psElement);
     997             : 
     998             :             // Read B-Spline curve header
     999           0 :             psSpline->desc_words =
    1000           0 :                 static_cast<long>(DGN_INT32(psDGN->abyElem + 36));
    1001             : 
    1002             :             // flags
    1003           0 :             psSpline->order = (psDGN->abyElem[40] & 0x0f) + 2;
    1004           0 :             psSpline->properties = psDGN->abyElem[40] & 0xf0;
    1005           0 :             psSpline->curve_type = psDGN->abyElem[41];
    1006             : 
    1007           0 :             psSpline->num_poles = psDGN->abyElem[42] + psDGN->abyElem[43] * 256;
    1008           0 :             psSpline->num_knots = psDGN->abyElem[44] + psDGN->abyElem[45] * 256;
    1009             :         }
    1010           0 :         break;
    1011           0 :         case DGNT_BSPLINE_SURFACE_BOUNDARY:
    1012             :         {
    1013           0 :             short numverts = psDGN->abyElem[38] + psDGN->abyElem[39] * 256;
    1014           0 :             if (numverts <= 0)
    1015             :             {
    1016           0 :                 CPLError(CE_Failure, CPLE_AssertionFailed, "numverts <= 0");
    1017           0 :                 return nullptr;
    1018             :             }
    1019             : 
    1020             :             DGNElemBSplineSurfaceBoundary *psBounds =
    1021             :                 static_cast<DGNElemBSplineSurfaceBoundary *>(
    1022           0 :                     CPLCalloc(sizeof(DGNElemBSplineSurfaceBoundary) +
    1023           0 :                                   (numverts - 1) * sizeof(DGNPoint),
    1024             :                               1));
    1025           0 :             psElement = (DGNElemCore *)psBounds;
    1026           0 :             psElement->stype = DGNST_BSPLINE_SURFACE_BOUNDARY;
    1027           0 :             DGNParseCore(psDGN, psElement);
    1028             : 
    1029           0 :             int deltaLength = 0, deltaStart = 0;
    1030           0 :             if (psBounds->core.properties & DGNPF_ATTRIBUTES)
    1031             :             {
    1032           0 :                 for (int iAttr = 0; iAttr < psBounds->core.attr_bytes - 3;
    1033             :                      iAttr++)
    1034             :                 {
    1035           0 :                     if (psBounds->core.attr_data[iAttr] == 0xA9 &&
    1036           0 :                         psBounds->core.attr_data[iAttr + 1] == 0x51)
    1037             :                     {
    1038           0 :                         deltaLength =
    1039           0 :                             (psBounds->core.attr_data[iAttr + 2] +
    1040           0 :                              psBounds->core.attr_data[iAttr + 3] * 256) *
    1041             :                             2;
    1042           0 :                         deltaStart = iAttr + 6;
    1043           0 :                         break;
    1044             :                     }
    1045             :                 }
    1046             :             }
    1047             :             // Read B-Spline surface boundary
    1048           0 :             psBounds->number = psDGN->abyElem[36] + psDGN->abyElem[37] * 256;
    1049             : 
    1050           0 :             for (int i = 0; i < numverts && 44 + i * 8 + 4 <= psDGN->nElemBytes;
    1051             :                  i++)
    1052             :             {
    1053           0 :                 psBounds->vertices[i].x =
    1054           0 :                     DGN_INT32(psDGN->abyElem + 40 + i * 8);
    1055           0 :                 psBounds->vertices[i].y =
    1056           0 :                     DGN_INT32(psDGN->abyElem + 44 + i * 8);
    1057           0 :                 psBounds->vertices[i].z = 0;
    1058           0 :                 if (deltaStart && deltaLength &&
    1059           0 :                     deltaStart + i * 4 + 2 + 2 <= psBounds->core.attr_bytes)
    1060             :                 {
    1061           0 :                     int dx = DGN_INT16(psBounds->core.attr_data + deltaStart +
    1062           0 :                                        i * 4);
    1063           0 :                     int dy = DGN_INT16(psBounds->core.attr_data + deltaStart +
    1064           0 :                                        i * 4 + 2);
    1065           0 :                     psBounds->vertices[i].x += dx / 32767.0;
    1066           0 :                     psBounds->vertices[i].y += dy / 32767.0;
    1067             :                 }
    1068           0 :                 psBounds->numverts = static_cast<short>(i + 1);
    1069             :             }
    1070             :         }
    1071           0 :         break;
    1072           0 :         case DGNT_BSPLINE_KNOT:
    1073             :         case DGNT_BSPLINE_WEIGHT_FACTOR:
    1074             :         {
    1075             :             // FIXME: Is it OK to assume that the # of elements corresponds
    1076             :             // directly to the element size? kintel 20051215.
    1077           0 :             int attr_bytes =
    1078           0 :                 psDGN->nElemBytes -
    1079           0 :                 (psDGN->abyElem[30] + psDGN->abyElem[31] * 256) * 2 - 32;
    1080           0 :             int numelems = (psDGN->nElemBytes - 36 - attr_bytes) / 4;
    1081           0 :             if (numelems < 1)
    1082             :             {
    1083           0 :                 CPLError(CE_Failure, CPLE_AssertionFailed, "numelems < 1");
    1084           0 :                 return nullptr;
    1085             :             }
    1086             :             DGNElemKnotWeight *psArray =
    1087           0 :                 static_cast<DGNElemKnotWeight *>(CPLCalloc(
    1088           0 :                     sizeof(DGNElemKnotWeight) + (numelems - 1) * sizeof(float),
    1089             :                     1));
    1090             : 
    1091           0 :             psElement = (DGNElemCore *)psArray;
    1092           0 :             psElement->stype = DGNST_KNOT_WEIGHT;
    1093           0 :             DGNParseCore(psDGN, psElement);
    1094             : 
    1095             :             // Read array
    1096           0 :             for (int i = 0; i < numelems; i++)
    1097             :             {
    1098           0 :                 psArray->array[i] = static_cast<float>(
    1099           0 :                     1.0 * DGN_INT32(psDGN->abyElem + 36 + i * 4) /
    1100             :                     ((1UL << 31) - 1));
    1101             :             }
    1102             :         }
    1103           0 :         break;
    1104           0 :         case DGNT_SHARED_CELL_DEFN:
    1105             :         {
    1106             :             DGNElemSharedCellDefn *psShared =
    1107             :                 static_cast<DGNElemSharedCellDefn *>(
    1108           0 :                     CPLCalloc(sizeof(DGNElemSharedCellDefn), 1));
    1109           0 :             psElement = (DGNElemCore *)psShared;
    1110           0 :             psElement->stype = DGNST_SHARED_CELL_DEFN;
    1111           0 :             DGNParseCore(psDGN, psElement);
    1112             : 
    1113           0 :             psShared->totlength = psDGN->abyElem[36] + psDGN->abyElem[37] * 256;
    1114             :         }
    1115           0 :         break;
    1116         114 :         default:
    1117             :         {
    1118             :             psElement =
    1119         114 :                 static_cast<DGNElemCore *>(CPLCalloc(sizeof(DGNElemCore), 1));
    1120         114 :             psElement->stype = DGNST_CORE;
    1121         114 :             DGNParseCore(psDGN, psElement);
    1122             :         }
    1123         114 :         break;
    1124             :     }
    1125             : 
    1126             :     /* -------------------------------------------------------------------- */
    1127             :     /*      If the element structure type is "core" or if we are running    */
    1128             :     /*      in "capture all" mode, record the complete binary image of      */
    1129             :     /*      the element.                                                    */
    1130             :     /* -------------------------------------------------------------------- */
    1131         561 :     if (psElement->stype == DGNST_CORE ||
    1132         137 :         (psDGN->options & DGNO_CAPTURE_RAW_DATA))
    1133             :     {
    1134         457 :         psElement->raw_bytes = psDGN->nElemBytes;
    1135         457 :         psElement->raw_data =
    1136         457 :             static_cast<unsigned char *>(CPLMalloc(psElement->raw_bytes));
    1137             : 
    1138         457 :         memcpy(psElement->raw_data, psDGN->abyElem, psElement->raw_bytes);
    1139             :     }
    1140             : 
    1141             :     /* -------------------------------------------------------------------- */
    1142             :     /*      Collect some additional generic information.                    */
    1143             :     /* -------------------------------------------------------------------- */
    1144         561 :     psElement->element_id = psDGN->next_element_id - 1;
    1145             : 
    1146         561 :     psElement->offset =
    1147         561 :         static_cast<int>(VSIFTellL(psDGN->fp)) - psDGN->nElemBytes;
    1148         561 :     psElement->size = psDGN->nElemBytes;
    1149             : 
    1150         561 :     return psElement;
    1151             : }
    1152             : 
    1153             : /************************************************************************/
    1154             : /*                           DGNReadElement()                           */
    1155             : /************************************************************************/
    1156             : 
    1157             : /**
    1158             :  * Read a DGN element.
    1159             :  *
    1160             :  * This function will return the next element in the file, starting with the
    1161             :  * first.  It is affected by DGNGotoElement() calls.
    1162             :  *
    1163             :  * The element is read into a structure which includes the DGNElemCore
    1164             :  * structure.  It is expected that applications will inspect the stype
    1165             :  * field of the returned DGNElemCore and use it to cast the pointer to the
    1166             :  * appropriate element structure type such as DGNElemMultiPoint.
    1167             :  *
    1168             :  * @param hDGN the handle of the file to read from.
    1169             :  *
    1170             :  * @return pointer to element structure, or NULL on EOF or processing error.
    1171             :  * The structure should be freed with DGNFreeElement() when no longer needed.
    1172             :  */
    1173             : 
    1174         597 : DGNElemCore *DGNReadElement(DGNHandle hDGN)
    1175             : 
    1176             : {
    1177         597 :     DGNInfo *psDGN = (DGNInfo *)hDGN;
    1178         597 :     int nType = 0;
    1179         597 :     int nLevel = 0;
    1180         597 :     bool bInsideFilter = false;
    1181             : 
    1182             :     /* -------------------------------------------------------------------- */
    1183             :     /*      Load the element data into the current buffer.  If a spatial    */
    1184             :     /*      filter is in effect, loop until we get something within our     */
    1185             :     /*      spatial constraints.                                            */
    1186             :     /* -------------------------------------------------------------------- */
    1187           3 :     do
    1188             :     {
    1189         600 :         bInsideFilter = true;
    1190             : 
    1191         600 :         if (!DGNLoadRawElement(psDGN, &nType, &nLevel))
    1192          36 :             return nullptr;
    1193             : 
    1194         564 :         if (psDGN->has_spatial_filter)
    1195             :         {
    1196          15 :             if (!psDGN->sf_converted_to_uor)
    1197           1 :                 DGNSpatialFilterToUOR(psDGN);
    1198             : 
    1199          15 :             GUInt32 nXMin = 0;
    1200          15 :             GUInt32 nXMax = 0;
    1201          15 :             GUInt32 nYMin = 0;
    1202          15 :             GUInt32 nYMax = 0;
    1203          15 :             if (!DGNGetRawExtents(psDGN, nType, nullptr, &nXMin, &nYMin,
    1204             :                                   nullptr, &nXMax, &nYMax, nullptr))
    1205             :             {
    1206             :                 /* If we don't have spatial characteristics for the element
    1207             :                    we will pass it through. */
    1208          11 :                 bInsideFilter = true;
    1209             :             }
    1210           4 :             else if (nXMin > psDGN->sf_max_x || nYMin > psDGN->sf_max_y ||
    1211           2 :                      nXMax < psDGN->sf_min_x || nYMax < psDGN->sf_min_y)
    1212             :             {
    1213           3 :                 bInsideFilter = false;
    1214             :             }
    1215             : 
    1216             :             /*
    1217             :             ** We want to select complex elements based on the extents of
    1218             :             ** the header, not the individual elements.
    1219             :             */
    1220          15 :             if (nType == DGNT_COMPLEX_CHAIN_HEADER ||
    1221          15 :                 nType == DGNT_COMPLEX_SHAPE_HEADER)
    1222             :             {
    1223           0 :                 psDGN->in_complex_group = true;
    1224           0 :                 psDGN->select_complex_group = bInsideFilter;
    1225             :             }
    1226          15 :             else if (psDGN->abyElem[0] & 0x80 /* complex flag set */)
    1227             :             {
    1228           0 :                 if (psDGN->in_complex_group)
    1229           0 :                     bInsideFilter = psDGN->select_complex_group;
    1230             :             }
    1231             :             else
    1232             :             {
    1233          15 :                 psDGN->in_complex_group = false;
    1234             :             }
    1235             :         }
    1236         564 :     } while (!bInsideFilter);
    1237             : 
    1238             :     /* -------------------------------------------------------------------- */
    1239             :     /*      Convert into an element structure.                              */
    1240             :     /* -------------------------------------------------------------------- */
    1241         561 :     DGNElemCore *psElement = DGNProcessElement(psDGN, nType, nLevel);
    1242             : 
    1243         561 :     return psElement;
    1244             : }
    1245             : 
    1246             : /************************************************************************/
    1247             : /*                       DGNElemTypeHasDispHdr()                        */
    1248             : /************************************************************************/
    1249             : 
    1250             : /**
    1251             :  * Does element type have display header.
    1252             :  *
    1253             :  * @param nElemType element type (0-63) to test.
    1254             :  *
    1255             :  * @return TRUE if elements of passed in type have a display header after the
    1256             :  * core element header, or FALSE otherwise.
    1257             :  */
    1258             : 
    1259         745 : int DGNElemTypeHasDispHdr(int nElemType)
    1260             : 
    1261             : {
    1262         745 :     switch (nElemType)
    1263             :     {
    1264         202 :         case 0:
    1265             :         case DGNT_TCB:
    1266             :         case DGNT_CELL_LIBRARY:
    1267             :         case DGNT_LEVEL_SYMBOLOGY:
    1268             :         case 32:
    1269             :         case 44:
    1270             :         case 48:
    1271             :         case 49:
    1272             :         case 50:
    1273             :         case 51:
    1274             :         case 57:
    1275             :         case 60:
    1276             :         case 61:
    1277             :         case 62:
    1278             :         case 63:
    1279         202 :             return FALSE;
    1280             : 
    1281         543 :         default:
    1282         543 :             return TRUE;
    1283             :     }
    1284             : }
    1285             : 
    1286             : /************************************************************************/
    1287             : /*                            DGNParseCore()                            */
    1288             : /************************************************************************/
    1289             : 
    1290         609 : int DGNParseCore(DGNInfo *psDGN, DGNElemCore *psElement)
    1291             : 
    1292             : {
    1293         609 :     GByte *psData = psDGN->abyElem + 0;
    1294             : 
    1295         609 :     psElement->level = psData[0] & 0x3f;
    1296         609 :     psElement->complex = psData[0] & 0x80;
    1297         609 :     psElement->deleted = psData[1] & 0x80;
    1298         609 :     psElement->type = psData[1] & 0x7f;
    1299             : 
    1300         609 :     if (psDGN->nElemBytes >= 36 && DGNElemTypeHasDispHdr(psElement->type))
    1301             :     {
    1302         407 :         psElement->graphic_group = psData[28] + psData[29] * 256;
    1303         407 :         psElement->properties = psData[32] + psData[33] * 256;
    1304         407 :         psElement->style = psData[34] & 0x7;
    1305         407 :         psElement->weight = (psData[34] & 0xf8) >> 3;
    1306         407 :         psElement->color = psData[35];
    1307             :     }
    1308             :     else
    1309             :     {
    1310         202 :         psElement->graphic_group = 0;
    1311         202 :         psElement->properties = 0;
    1312         202 :         psElement->style = 0;
    1313         202 :         psElement->weight = 0;
    1314         202 :         psElement->color = 0;
    1315             :     }
    1316             : 
    1317         609 :     if (psElement->properties & DGNPF_ATTRIBUTES)
    1318             :     {
    1319          23 :         const int nAttIndex = psData[30] + psData[31] * 256;
    1320             : 
    1321          23 :         psElement->attr_bytes = psDGN->nElemBytes - nAttIndex * 2 - 32;
    1322          23 :         if (psElement->attr_bytes > 0)
    1323             :         {
    1324          23 :             psElement->attr_data =
    1325          23 :                 static_cast<unsigned char *>(CPLMalloc(psElement->attr_bytes));
    1326          23 :             memcpy(psElement->attr_data, psData + nAttIndex * 2 + 32,
    1327          23 :                    psElement->attr_bytes);
    1328             :         }
    1329             :         else
    1330             :         {
    1331           0 :             CPLError(CE_Warning, CPLE_AppDefined,
    1332             :                      "Computed %d bytes for attribute info on element,\n"
    1333             :                      "perhaps this element type doesn't really have a disphdr?",
    1334             :                      psElement->attr_bytes);
    1335           0 :             psElement->attr_bytes = 0;
    1336             :         }
    1337             :     }
    1338             : 
    1339         609 :     return TRUE;
    1340             : }
    1341             : 
    1342             : /************************************************************************/
    1343             : /*                         DGNParseColorTable()                         */
    1344             : /************************************************************************/
    1345             : 
    1346           0 : static DGNElemCore *DGNParseColorTable(DGNInfo *psDGN)
    1347             : 
    1348             : {
    1349             :     DGNElemColorTable *psColorTable = static_cast<DGNElemColorTable *>(
    1350           0 :         CPLCalloc(sizeof(DGNElemColorTable), 1));
    1351           0 :     DGNElemCore *psElement = (DGNElemCore *)psColorTable;
    1352           0 :     psElement->stype = DGNST_COLORTABLE;
    1353             : 
    1354           0 :     DGNParseCore(psDGN, psElement);
    1355             : 
    1356           0 :     psColorTable->screen_flag = psDGN->abyElem[36] + psDGN->abyElem[37] * 256;
    1357             : 
    1358           0 :     memcpy(psColorTable->color_info[255], psDGN->abyElem + 38, 3);
    1359           0 :     memcpy(psColorTable->color_info, psDGN->abyElem + 41, 765);
    1360             : 
    1361             :     // We used to only install a color table as the default color
    1362             :     // table if it was the first in the file.  But apparently we should
    1363             :     // really be using the last one.  This doesn't necessarily accomplish
    1364             :     // that either if the elements are being read out of order but it will
    1365             :     // usually do better at least.
    1366           0 :     memcpy(psDGN->color_table, psColorTable->color_info, 768);
    1367           0 :     psDGN->got_color_table = 1;
    1368             : 
    1369           0 :     return psElement;
    1370             : }
    1371             : 
    1372             : /************************************************************************/
    1373             : /*                           DGNParseTagSet()                           */
    1374             : /************************************************************************/
    1375             : 
    1376           0 : static DGNElemCore *DGNParseTagSet(DGNInfo *psDGN)
    1377             : 
    1378             : {
    1379             :     DGNElemTagSet *psTagSet =
    1380           0 :         static_cast<DGNElemTagSet *>(CPLCalloc(sizeof(DGNElemTagSet), 1));
    1381           0 :     DGNElemCore *psElement = (DGNElemCore *)psTagSet;
    1382           0 :     psElement->stype = DGNST_TAG_SET;
    1383             : 
    1384           0 :     DGNParseCore(psDGN, psElement);
    1385             : 
    1386             :     /* -------------------------------------------------------------------- */
    1387             :     /*      Parse the overall information.                                  */
    1388             :     /* -------------------------------------------------------------------- */
    1389           0 :     psTagSet->tagCount = psDGN->abyElem[44] + psDGN->abyElem[45] * 256;
    1390           0 :     psTagSet->flags = psDGN->abyElem[46] + psDGN->abyElem[47] * 256;
    1391           0 :     psTagSet->tagSetName = CPLStrdup((const char *)(psDGN->abyElem + 48));
    1392             : 
    1393             :     /* -------------------------------------------------------------------- */
    1394             :     /*      Get the tag set number out of the attributes, if available.     */
    1395             :     /* -------------------------------------------------------------------- */
    1396           0 :     psTagSet->tagSet = -1;
    1397             : 
    1398           0 :     if (psElement->attr_bytes >= 8 && psElement->attr_data[0] == 0x03 &&
    1399           0 :         psElement->attr_data[1] == 0x10 && psElement->attr_data[2] == 0x2f &&
    1400           0 :         psElement->attr_data[3] == 0x7d)
    1401           0 :         psTagSet->tagSet =
    1402           0 :             psElement->attr_data[4] + psElement->attr_data[5] * 256;
    1403             : 
    1404             :     /* -------------------------------------------------------------------- */
    1405             :     /*      Parse each of the tag definitions.                              */
    1406             :     /* -------------------------------------------------------------------- */
    1407           0 :     psTagSet->tagList = static_cast<DGNTagDef *>(
    1408           0 :         CPLCalloc(sizeof(DGNTagDef), psTagSet->tagCount));
    1409             : 
    1410           0 :     size_t nDataOffset = 48 + strlen(psTagSet->tagSetName) + 1 + 1;
    1411             : 
    1412           0 :     for (int iTag = 0; iTag < psTagSet->tagCount; iTag++)
    1413             :     {
    1414           0 :         DGNTagDef *tagDef = psTagSet->tagList + iTag;
    1415             : 
    1416             :         // Check the buffer is large enough to read all tagDef components
    1417           0 :         size_t nDataOffsetEnd = nDataOffset;
    1418           0 :         if (nDataOffsetEnd <= static_cast<size_t>(psDGN->nElemBytes))
    1419             :         {
    1420           0 :             nDataOffsetEnd +=
    1421           0 :                 strlen((char *)psDGN->abyElem + nDataOffsetEnd) + 1 + 2;
    1422             :         }
    1423           0 :         if (nDataOffsetEnd <= static_cast<size_t>(psDGN->nElemBytes))
    1424             :         {
    1425           0 :             nDataOffsetEnd +=
    1426           0 :                 strlen((char *)psDGN->abyElem + nDataOffsetEnd) + 1 + 2 + 5;
    1427           0 :             if (tagDef->type == 1)
    1428             :             {
    1429           0 :                 nDataOffsetEnd += strlen(tagDef->defaultValue.string) + 1;
    1430             :             }
    1431           0 :             else if (tagDef->type == 3 || tagDef->type == 5)
    1432             :             {
    1433           0 :                 nDataOffsetEnd += 4;
    1434             :             }
    1435           0 :             else if (tagDef->type == 4)
    1436             :             {
    1437           0 :                 nDataOffsetEnd += 8;
    1438             :             }
    1439             :             else
    1440             :             {
    1441           0 :                 nDataOffsetEnd += 4;
    1442             :             }
    1443             :         }
    1444           0 :         if (nDataOffsetEnd > static_cast<size_t>(psDGN->nElemBytes))
    1445             :         {
    1446           0 :             CPLError(CE_Failure, CPLE_AssertionFailed,
    1447             :                      "nDataOffset >= static_cast<size_t>(psDGN->nElemBytes)");
    1448           0 :             DGNFreeElement(psDGN, psElement);
    1449           0 :             return nullptr;
    1450             :         }
    1451             : 
    1452             :         /* collect tag name. */
    1453           0 :         tagDef->name = CPLStrdup((char *)psDGN->abyElem + nDataOffset);
    1454           0 :         nDataOffset += strlen(tagDef->name) + 1;
    1455             : 
    1456             :         /* Get tag id */
    1457           0 :         tagDef->id =
    1458           0 :             psDGN->abyElem[nDataOffset] + psDGN->abyElem[nDataOffset + 1] * 256;
    1459           0 :         nDataOffset += 2;
    1460             : 
    1461             :         /* Get User Prompt */
    1462           0 :         tagDef->prompt = CPLStrdup((char *)psDGN->abyElem + nDataOffset);
    1463           0 :         nDataOffset += strlen(tagDef->prompt) + 1;
    1464             : 
    1465             :         /* Get type */
    1466           0 :         tagDef->type =
    1467           0 :             psDGN->abyElem[nDataOffset] + psDGN->abyElem[nDataOffset + 1] * 256;
    1468           0 :         nDataOffset += 2;
    1469             : 
    1470             :         /* skip five zeros */
    1471           0 :         nDataOffset += 5;
    1472             : 
    1473             :         /* Get the default */
    1474           0 :         if (tagDef->type == 1)
    1475             :         {
    1476           0 :             tagDef->defaultValue.string =
    1477           0 :                 CPLStrdup((char *)psDGN->abyElem + nDataOffset);
    1478           0 :             nDataOffset += strlen(tagDef->defaultValue.string) + 1;
    1479             :         }
    1480           0 :         else if (tagDef->type == 3 || tagDef->type == 5)
    1481             :         {
    1482           0 :             memcpy(&(tagDef->defaultValue.integer),
    1483           0 :                    psDGN->abyElem + nDataOffset, 4);
    1484           0 :             CPL_LSBPTR32(&(tagDef->defaultValue.integer));
    1485           0 :             nDataOffset += 4;
    1486             :         }
    1487           0 :         else if (tagDef->type == 4)
    1488             :         {
    1489           0 :             memcpy(&(tagDef->defaultValue.real), psDGN->abyElem + nDataOffset,
    1490             :                    8);
    1491           0 :             DGN2IEEEDouble(&(tagDef->defaultValue.real));
    1492           0 :             nDataOffset += 8;
    1493             :         }
    1494             :         else
    1495           0 :             nDataOffset += 4;
    1496             :     }
    1497           0 :     return psElement;
    1498             : }
    1499             : 
    1500             : /************************************************************************/
    1501             : /*                            DGNParseTCB()                             */
    1502             : /************************************************************************/
    1503             : 
    1504         145 : static DGNElemCore *DGNParseTCB(DGNInfo *psDGN)
    1505             : 
    1506             : {
    1507             :     DGNElemTCB *psTCB =
    1508         145 :         static_cast<DGNElemTCB *>(CPLCalloc(sizeof(DGNElemTCB), 1));
    1509         145 :     DGNElemCore *psElement = (DGNElemCore *)psTCB;
    1510         145 :     psElement->stype = DGNST_TCB;
    1511         145 :     DGNParseCore(psDGN, psElement);
    1512             : 
    1513         145 :     if (psDGN->abyElem[1214] & 0x40)
    1514          49 :         psTCB->dimension = 3;
    1515             :     else
    1516          96 :         psTCB->dimension = 2;
    1517             : 
    1518         145 :     psTCB->subunits_per_master =
    1519         145 :         static_cast<long>(DGN_INT32(psDGN->abyElem + 1112));
    1520             : 
    1521         145 :     psTCB->master_units[0] = (char)psDGN->abyElem[1120];
    1522         145 :     psTCB->master_units[1] = (char)psDGN->abyElem[1121];
    1523         145 :     psTCB->master_units[2] = '\0';
    1524             : 
    1525         145 :     psTCB->uor_per_subunit =
    1526         145 :         static_cast<long>(DGN_INT32(psDGN->abyElem + 1116));
    1527             : 
    1528         145 :     psTCB->sub_units[0] = (char)psDGN->abyElem[1122];
    1529         145 :     psTCB->sub_units[1] = (char)psDGN->abyElem[1123];
    1530         145 :     psTCB->sub_units[2] = '\0';
    1531             : 
    1532             :     /* Get global origin */
    1533         145 :     memcpy(&(psTCB->origin_x), psDGN->abyElem + 1240, 8);
    1534         145 :     memcpy(&(psTCB->origin_y), psDGN->abyElem + 1248, 8);
    1535         145 :     memcpy(&(psTCB->origin_z), psDGN->abyElem + 1256, 8);
    1536             : 
    1537             :     /* Transform to IEEE */
    1538         145 :     DGN2IEEEDouble(&(psTCB->origin_x));
    1539         145 :     DGN2IEEEDouble(&(psTCB->origin_y));
    1540         145 :     DGN2IEEEDouble(&(psTCB->origin_z));
    1541             : 
    1542             :     /* Convert from UORs to master units. */
    1543         145 :     if (psTCB->uor_per_subunit != 0 && psTCB->subunits_per_master != 0)
    1544             :     {
    1545         131 :         psTCB->origin_x = psTCB->origin_x /
    1546         131 :                           (psTCB->uor_per_subunit * psTCB->subunits_per_master);
    1547         131 :         psTCB->origin_y = psTCB->origin_y /
    1548         131 :                           (psTCB->uor_per_subunit * psTCB->subunits_per_master);
    1549         131 :         psTCB->origin_z = psTCB->origin_z /
    1550         131 :                           (psTCB->uor_per_subunit * psTCB->subunits_per_master);
    1551             :     }
    1552             : 
    1553         145 :     if (!psDGN->got_tcb)
    1554             :     {
    1555          74 :         psDGN->got_tcb = true;
    1556          74 :         psDGN->dimension = psTCB->dimension;
    1557          74 :         psDGN->origin_x = psTCB->origin_x;
    1558          74 :         psDGN->origin_y = psTCB->origin_y;
    1559          74 :         psDGN->origin_z = psTCB->origin_z;
    1560             : 
    1561          74 :         if (psTCB->uor_per_subunit != 0 && psTCB->subunits_per_master != 0)
    1562          74 :             psDGN->scale =
    1563          74 :                 1.0 / (psTCB->uor_per_subunit * psTCB->subunits_per_master);
    1564             :     }
    1565             : 
    1566             :     /* Collect views */
    1567        1305 :     for (int iView = 0; iView < 8; iView++)
    1568             :     {
    1569        1160 :         unsigned char *pabyRawView = psDGN->abyElem + 46 + iView * 118;
    1570        1160 :         DGNViewInfo *psView = psTCB->views + iView;
    1571             : 
    1572        1160 :         psView->flags = pabyRawView[0] + pabyRawView[1] * 256;
    1573        1160 :         memcpy(psView->levels, pabyRawView + 2, 8);
    1574             : 
    1575        1160 :         psView->origin.x = DGN_INT32(pabyRawView + 10);
    1576        1160 :         psView->origin.y = DGN_INT32(pabyRawView + 14);
    1577        1160 :         psView->origin.z = DGN_INT32(pabyRawView + 18);
    1578             : 
    1579        1160 :         DGNTransformPoint(psDGN, &(psView->origin));
    1580             : 
    1581        1160 :         psView->delta.x = DGN_INT32(pabyRawView + 22);
    1582        1160 :         psView->delta.y = DGN_INT32(pabyRawView + 26);
    1583        1160 :         psView->delta.z = DGN_INT32(pabyRawView + 30);
    1584             : 
    1585        1160 :         psView->delta.x *= psDGN->scale;
    1586        1160 :         psView->delta.y *= psDGN->scale;
    1587        1160 :         psView->delta.z *= psDGN->scale;
    1588             : 
    1589        1160 :         memcpy(psView->transmatrx, pabyRawView + 34, sizeof(double) * 9);
    1590       11600 :         for (int i = 0; i < 9; i++)
    1591       10440 :             DGN2IEEEDouble(psView->transmatrx + i);
    1592             : 
    1593        1160 :         memcpy(&(psView->conversion), pabyRawView + 106, sizeof(double));
    1594        1160 :         DGN2IEEEDouble(&(psView->conversion));
    1595             : 
    1596        1160 :         psView->activez =
    1597        1160 :             static_cast<unsigned long>(DGN_INT32(pabyRawView + 114));
    1598             :     }
    1599             : 
    1600         145 :     return psElement;
    1601             : }
    1602             : 
    1603             : /************************************************************************/
    1604             : /*                           DGNFreeElement()                           */
    1605             : /************************************************************************/
    1606             : 
    1607             : /**
    1608             :  * Free an element structure.
    1609             :  *
    1610             :  * This function will deallocate all resources associated with any element
    1611             :  * structure returned by DGNReadElement().
    1612             :  *
    1613             :  * @param hDGN handle to file from which the element was read.
    1614             :  * @param psElement the element structure returned by DGNReadElement().
    1615             :  */
    1616             : 
    1617         892 : void DGNFreeElement(CPL_UNUSED DGNHandle hDGN, DGNElemCore *psElement)
    1618             : {
    1619         892 :     if (psElement->attr_data != nullptr)
    1620          67 :         VSIFree(psElement->attr_data);
    1621             : 
    1622         892 :     if (psElement->raw_data != nullptr)
    1623         740 :         VSIFree(psElement->raw_data);
    1624             : 
    1625         892 :     if (psElement->stype == DGNST_TAG_SET)
    1626             :     {
    1627           0 :         DGNElemTagSet *psTagSet = (DGNElemTagSet *)psElement;
    1628           0 :         CPLFree(psTagSet->tagSetName);
    1629             : 
    1630           0 :         for (int iTag = 0; iTag < psTagSet->tagCount; iTag++)
    1631             :         {
    1632           0 :             CPLFree(psTagSet->tagList[iTag].name);
    1633           0 :             CPLFree(psTagSet->tagList[iTag].prompt);
    1634             : 
    1635           0 :             if (psTagSet->tagList[iTag].type == 1)
    1636           0 :                 CPLFree(psTagSet->tagList[iTag].defaultValue.string);
    1637             :         }
    1638           0 :         CPLFree(psTagSet->tagList);
    1639             :     }
    1640         892 :     else if (psElement->stype == DGNST_TAG_VALUE)
    1641             :     {
    1642           0 :         if (((DGNElemTagValue *)psElement)->tagType == 1)
    1643           0 :             CPLFree(((DGNElemTagValue *)psElement)->tagValue.string);
    1644             :     }
    1645             : 
    1646         892 :     CPLFree(psElement);
    1647         892 : }
    1648             : 
    1649             : /************************************************************************/
    1650             : /*                             DGNRewind()                              */
    1651             : /************************************************************************/
    1652             : 
    1653             : /**
    1654             :  * Rewind element reading.
    1655             :  *
    1656             :  * Rewind the indicated DGN file, so the next element read with
    1657             :  * DGNReadElement() will be the first.  Does not require indexing like
    1658             :  * the more general DGNReadElement() function.
    1659             :  *
    1660             :  * @param hDGN handle to file.
    1661             :  */
    1662             : 
    1663         106 : void DGNRewind(DGNHandle hDGN)
    1664             : 
    1665             : {
    1666         106 :     DGNInfo *psDGN = (DGNInfo *)hDGN;
    1667             : 
    1668         106 :     VSIRewindL(psDGN->fp);
    1669             : 
    1670         106 :     psDGN->next_element_id = 0;
    1671         106 :     psDGN->in_complex_group = false;
    1672         106 : }
    1673             : 
    1674             : /************************************************************************/
    1675             : /*                         DGNTransformPoint()                          */
    1676             : /************************************************************************/
    1677             : 
    1678        1326 : void DGNTransformPoint(DGNInfo *psDGN, DGNPoint *psPoint)
    1679             : 
    1680             : {
    1681        1326 :     psPoint->x = psPoint->x * psDGN->scale - psDGN->origin_x;
    1682        1326 :     psPoint->y = psPoint->y * psDGN->scale - psDGN->origin_y;
    1683        1326 :     psPoint->z = psPoint->z * psDGN->scale - psDGN->origin_z;
    1684        1326 : }
    1685             : 
    1686             : /************************************************************************/
    1687             : /*                      DGNInverseTransformPoint()                      */
    1688             : /************************************************************************/
    1689             : 
    1690           2 : void DGNInverseTransformPoint(DGNInfo *psDGN, DGNPoint *psPoint)
    1691             : 
    1692             : {
    1693           2 :     psPoint->x = (psPoint->x + psDGN->origin_x) / psDGN->scale;
    1694           2 :     psPoint->y = (psPoint->y + psDGN->origin_y) / psDGN->scale;
    1695           2 :     psPoint->z = (psPoint->z + psDGN->origin_z) / psDGN->scale;
    1696             : 
    1697           2 :     psPoint->x = std::max(-2147483647.0, std::min(2147483647.0, psPoint->x));
    1698           2 :     psPoint->y = std::max(-2147483647.0, std::min(2147483647.0, psPoint->y));
    1699           2 :     psPoint->z = std::max(-2147483647.0, std::min(2147483647.0, psPoint->z));
    1700           2 : }
    1701             : 
    1702             : /************************************************************************/
    1703             : /*                   DGNInverseTransformPointToInt()                    */
    1704             : /************************************************************************/
    1705             : 
    1706         290 : void DGNInverseTransformPointToInt(DGNInfo *psDGN, DGNPoint *psPoint,
    1707             :                                    unsigned char *pabyTarget)
    1708             : 
    1709             : {
    1710         290 :     double adfCT[3] = {(psPoint->x + psDGN->origin_x) / psDGN->scale,
    1711         290 :                        (psPoint->y + psDGN->origin_y) / psDGN->scale,
    1712         290 :                        (psPoint->z + psDGN->origin_z) / psDGN->scale};
    1713             : 
    1714         290 :     const int nIter = std::min(3, psDGN->dimension);
    1715         960 :     for (int i = 0; i < nIter; i++)
    1716             :     {
    1717         670 :         GInt32 nCTI = static_cast<GInt32>(
    1718         670 :             std::max(-2147483647.0, std::min(2147483647.0, adfCT[i])));
    1719             :         unsigned char abyCTI[4];
    1720         670 :         memcpy(abyCTI, &nCTI, sizeof(GInt32));
    1721             : 
    1722             : #ifdef WORDS_BIGENDIAN
    1723             :         pabyTarget[i * 4 + 0] = abyCTI[1];
    1724             :         pabyTarget[i * 4 + 1] = abyCTI[0];
    1725             :         pabyTarget[i * 4 + 2] = abyCTI[3];
    1726             :         pabyTarget[i * 4 + 3] = abyCTI[2];
    1727             : #else
    1728         670 :         pabyTarget[i * 4 + 3] = abyCTI[1];
    1729         670 :         pabyTarget[i * 4 + 2] = abyCTI[0];
    1730         670 :         pabyTarget[i * 4 + 1] = abyCTI[3];
    1731         670 :         pabyTarget[i * 4 + 0] = abyCTI[2];
    1732             : #endif
    1733             :     }
    1734         290 : }
    1735             : 
    1736             : /************************************************************************/
    1737             : /*                             DGNLoadTCB()                             */
    1738             : /************************************************************************/
    1739             : 
    1740             : /**
    1741             :  * Load TCB if not already loaded.
    1742             :  *
    1743             :  * This function will load the TCB element if it is not already loaded.
    1744             :  * It is used primarily to ensure the TCB is loaded before doing any operations
    1745             :  * that require TCB values (like creating new elements).
    1746             :  *
    1747             :  * @return FALSE on failure or TRUE on success.
    1748             :  */
    1749             : 
    1750         284 : int DGNLoadTCB(DGNHandle hDGN)
    1751             : 
    1752             : {
    1753         284 :     DGNInfo *psDGN = (DGNInfo *)hDGN;
    1754             : 
    1755         284 :     if (psDGN->got_tcb)
    1756         251 :         return TRUE;
    1757             : 
    1758          66 :     while (!psDGN->got_tcb)
    1759             :     {
    1760          33 :         DGNElemCore *psElem = DGNReadElement(hDGN);
    1761          33 :         if (psElem == nullptr)
    1762             :         {
    1763           0 :             CPLError(CE_Failure, CPLE_AppDefined,
    1764             :                      "DGNLoadTCB() - unable to find TCB in file.");
    1765           0 :             return FALSE;
    1766             :         }
    1767          33 :         DGNFreeElement(hDGN, psElem);
    1768             :     }
    1769             : 
    1770          33 :     return TRUE;
    1771             : }
    1772             : 
    1773             : /************************************************************************/
    1774             : /*                         DGNGetElementIndex()                         */
    1775             : /************************************************************************/
    1776             : 
    1777             : /**
    1778             :  * Fetch element index.
    1779             :  *
    1780             :  * This function will return an array with brief information about every
    1781             :  * element in a DGN file.  It requires one pass through the entire file to
    1782             :  * generate (this is not repeated on subsequent calls).
    1783             :  *
    1784             :  * The returned array of DGNElementInfo structures contain the level, type,
    1785             :  * stype, and other flags for each element in the file.  This can facilitate
    1786             :  * application level code representing the number of elements of various types
    1787             :  * efficiently.
    1788             :  *
    1789             :  * Note that while building the index requires one pass through the whole file,
    1790             :  * it does not generally request much processing for each element.
    1791             :  *
    1792             :  * @param hDGN the file to get an index for.
    1793             :  * @param pnElementCount the integer to put the total element count into.
    1794             :  *
    1795             :  * @return a pointer to an internal array of DGNElementInfo structures (there
    1796             :  * will be *pnElementCount entries in the array), or NULL on failure.  The
    1797             :  * returned array should not be modified or freed, and will last only as long
    1798             :  * as the DGN file remains open.
    1799             :  */
    1800             : 
    1801          35 : const DGNElementInfo *DGNGetElementIndex(DGNHandle hDGN, int *pnElementCount)
    1802             : 
    1803             : {
    1804          35 :     DGNInfo *psDGN = (DGNInfo *)hDGN;
    1805             : 
    1806          35 :     DGNBuildIndex(psDGN);
    1807             : 
    1808          35 :     if (pnElementCount != nullptr)
    1809           0 :         *pnElementCount = psDGN->element_count;
    1810             : 
    1811          35 :     return psDGN->element_index;
    1812             : }
    1813             : 
    1814             : /************************************************************************/
    1815             : /*                           DGNGetExtents()                            */
    1816             : /************************************************************************/
    1817             : 
    1818             : /**
    1819             :  * Fetch overall file extents.
    1820             :  *
    1821             :  * The extents are collected for each element while building an index, so
    1822             :  * if an index has not already been built, it will be built when
    1823             :  * DGNGetExtents() is called.
    1824             :  *
    1825             :  * The Z min/max values are generally meaningless (0 and 0xffffffff in uor
    1826             :  * space).
    1827             :  *
    1828             :  * @param hDGN the file to get extents for.
    1829             :  * @param padfExtents pointer to an array of six doubles into which are loaded
    1830             :  * the values xmin, ymin, zmin, xmax, ymax, and zmax.
    1831             :  *
    1832             :  * @return TRUE on success or FALSE on failure.
    1833             :  */
    1834             : 
    1835           0 : int DGNGetExtents(DGNHandle hDGN, double *padfExtents)
    1836             : 
    1837             : {
    1838           0 :     DGNInfo *psDGN = (DGNInfo *)hDGN;
    1839             : 
    1840           0 :     DGNBuildIndex(psDGN);
    1841             : 
    1842           0 :     if (!psDGN->got_bounds)
    1843           0 :         return FALSE;
    1844             : 
    1845           0 :     DGNPoint sMin = {psDGN->min_x - 2147483648.0, psDGN->min_y - 2147483648.0,
    1846           0 :                      psDGN->min_z - 2147483648.0};
    1847             : 
    1848           0 :     DGNTransformPoint(psDGN, &sMin);
    1849             : 
    1850           0 :     padfExtents[0] = sMin.x;
    1851           0 :     padfExtents[1] = sMin.y;
    1852           0 :     padfExtents[2] = sMin.z;
    1853             : 
    1854           0 :     DGNPoint sMax = {psDGN->max_x - 2147483648.0, psDGN->max_y - 2147483648.0,
    1855           0 :                      psDGN->max_z - 2147483648.0};
    1856             : 
    1857           0 :     DGNTransformPoint(psDGN, &sMax);
    1858             : 
    1859           0 :     padfExtents[3] = sMax.x;
    1860           0 :     padfExtents[4] = sMax.y;
    1861           0 :     padfExtents[5] = sMax.z;
    1862             : 
    1863           0 :     return TRUE;
    1864             : }
    1865             : 
    1866             : /************************************************************************/
    1867             : /*                           DGNBuildIndex()                            */
    1868             : /************************************************************************/
    1869             : 
    1870         351 : void DGNBuildIndex(DGNInfo *psDGN)
    1871             : 
    1872             : {
    1873         351 :     if (psDGN->index_built)
    1874         310 :         return;
    1875             : 
    1876          41 :     int nType = 0;
    1877          41 :     int nLevel = 0;
    1878          41 :     GUInt32 anRegion[6] = {};
    1879             : 
    1880          41 :     psDGN->index_built = true;
    1881             : 
    1882          41 :     DGNRewind(psDGN);
    1883             : 
    1884          41 :     int nMaxElements = 0;
    1885             : 
    1886          41 :     vsi_l_offset nLastOffset = VSIFTellL(psDGN->fp);
    1887         198 :     while (DGNLoadRawElement(psDGN, &nType, &nLevel))
    1888             :     {
    1889         157 :         if (psDGN->element_count == nMaxElements)
    1890             :         {
    1891          41 :             nMaxElements = (int)(nMaxElements * 1.5) + 500;
    1892             : 
    1893          41 :             psDGN->element_index = (DGNElementInfo *)CPLRealloc(
    1894          41 :                 psDGN->element_index, nMaxElements * sizeof(DGNElementInfo));
    1895             :         }
    1896             : 
    1897         157 :         DGNElementInfo *psEI = psDGN->element_index + psDGN->element_count;
    1898         157 :         psEI->level = (unsigned char)nLevel;
    1899         157 :         psEI->type = (unsigned char)nType;
    1900         157 :         psEI->flags = 0;
    1901         157 :         psEI->offset = nLastOffset;
    1902             : 
    1903         157 :         if (psDGN->abyElem[0] & 0x80)
    1904          17 :             psEI->flags |= DGNEIF_COMPLEX;
    1905             : 
    1906         157 :         if (psDGN->abyElem[1] & 0x80)
    1907           0 :             psEI->flags |= DGNEIF_DELETED;
    1908             : 
    1909         157 :         if (nType == DGNT_LINE || nType == DGNT_LINE_STRING ||
    1910         146 :             nType == DGNT_SHAPE || nType == DGNT_CURVE ||
    1911         138 :             nType == DGNT_BSPLINE_POLE)
    1912          19 :             psEI->stype = DGNST_MULTIPOINT;
    1913             : 
    1914         138 :         else if (nType == DGNT_GROUP_DATA && nLevel == DGN_GDL_COLOR_TABLE)
    1915             :         {
    1916           0 :             DGNElemCore *psCT = DGNParseColorTable(psDGN);
    1917           0 :             DGNFreeElement((DGNHandle)psDGN, psCT);
    1918           0 :             psEI->stype = DGNST_COLORTABLE;
    1919             :         }
    1920         138 :         else if (nType == DGNT_ELLIPSE || nType == DGNT_ARC)
    1921           7 :             psEI->stype = DGNST_ARC;
    1922             : 
    1923         131 :         else if (nType == DGNT_COMPLEX_SHAPE_HEADER ||
    1924         131 :                  nType == DGNT_COMPLEX_CHAIN_HEADER ||
    1925         130 :                  nType == DGNT_3DSURFACE_HEADER || nType == DGNT_3DSOLID_HEADER)
    1926           1 :             psEI->stype = DGNST_COMPLEX_HEADER;
    1927             : 
    1928         130 :         else if (nType == DGNT_TEXT)
    1929           8 :             psEI->stype = DGNST_TEXT;
    1930             : 
    1931         122 :         else if (nType == DGNT_TAG_VALUE)
    1932           0 :             psEI->stype = DGNST_TAG_VALUE;
    1933             : 
    1934         122 :         else if (nType == DGNT_APPLICATION_ELEM)
    1935             :         {
    1936          51 :             if (nLevel == 24)
    1937           0 :                 psEI->stype = DGNST_TAG_SET;
    1938             :             else
    1939          51 :                 psEI->stype = DGNST_CORE;
    1940             :         }
    1941          71 :         else if (nType == DGNT_TCB)
    1942             :         {
    1943          48 :             DGNElemCore *psTCB = DGNParseTCB(psDGN);
    1944          48 :             DGNFreeElement((DGNHandle)psDGN, psTCB);
    1945          48 :             psEI->stype = DGNST_TCB;
    1946             :         }
    1947          23 :         else if (nType == DGNT_CONE)
    1948           0 :             psEI->stype = DGNST_CONE;
    1949             :         else
    1950          23 :             psEI->stype = DGNST_CORE;
    1951             : 
    1952         471 :         if (!(psEI->flags & DGNEIF_DELETED) &&
    1953         297 :             !(psEI->flags & DGNEIF_COMPLEX) &&
    1954         140 :             DGNGetRawExtents(psDGN, nType, nullptr, anRegion + 0, anRegion + 1,
    1955             :                              anRegion + 2, anRegion + 3, anRegion + 4,
    1956             :                              anRegion + 5))
    1957             :         {
    1958             : #ifdef notdef
    1959             :             printf("panRegion[%d]=%.1f,%.1f,%.1f,%.1f,%.1f,%.1f\n", /*ok*/
    1960             :                    psDGN->element_count, anRegion[0] - 2147483648.0,
    1961             :                    anRegion[1] - 2147483648.0, anRegion[2] - 2147483648.0,
    1962             :                    anRegion[3] - 2147483648.0, anRegion[4] - 2147483648.0,
    1963             :                    anRegion[5] - 2147483648.0);
    1964             : #endif
    1965          32 :             if (psDGN->got_bounds)
    1966             :             {
    1967          24 :                 psDGN->min_x = std::min(psDGN->min_x, anRegion[0]);
    1968          24 :                 psDGN->min_y = std::min(psDGN->min_y, anRegion[1]);
    1969          24 :                 psDGN->min_z = std::min(psDGN->min_z, anRegion[2]);
    1970          24 :                 psDGN->max_x = std::max(psDGN->max_x, anRegion[3]);
    1971          24 :                 psDGN->max_y = std::max(psDGN->max_y, anRegion[4]);
    1972          24 :                 psDGN->max_z = std::max(psDGN->max_z, anRegion[5]);
    1973             :             }
    1974             :             else
    1975             :             {
    1976           8 :                 psDGN->min_x = anRegion[0];
    1977           8 :                 psDGN->min_y = anRegion[1];
    1978           8 :                 psDGN->min_z = anRegion[2];
    1979           8 :                 psDGN->max_x = anRegion[3];
    1980           8 :                 psDGN->max_y = anRegion[4];
    1981           8 :                 psDGN->max_z = anRegion[5];
    1982           8 :                 psDGN->got_bounds = true;
    1983             :             }
    1984             :         }
    1985             : 
    1986         157 :         psDGN->element_count++;
    1987             : 
    1988         157 :         nLastOffset = VSIFTellL(psDGN->fp);
    1989             :     }
    1990             : 
    1991          41 :     DGNRewind(psDGN);
    1992             : 
    1993          41 :     psDGN->max_element_count = nMaxElements;
    1994             : }

Generated by: LCOV version 1.14