LCOV - code coverage report
Current view: top level - ogr/ogrsf_frmts/dgn - dgnhelp.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 69 468 14.7 %
Date: 2024-05-08 12:15:28 Functions: 4 11 36.4 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  Microstation DGN Access Library
       4             :  * Purpose:  Application visible helper functions for parsing DGN information.
       5             :  * Author:   Frank Warmerdam, warmerdam@pobox.com
       6             :  *
       7             :  ******************************************************************************
       8             :  * Copyright (c) 2002, 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             : static const unsigned char abyDefaultPCT[256][3] = {
      32             :     {255, 255, 255}, {0, 0, 255},     {0, 255, 0},     {255, 0, 0},
      33             :     {255, 255, 0},   {255, 0, 255},   {255, 127, 0},   {0, 255, 255},
      34             :     {64, 64, 64},    {192, 192, 192}, {254, 0, 96},    {160, 224, 0},
      35             :     {0, 254, 160},   {128, 0, 160},   {176, 176, 176}, {0, 240, 240},
      36             :     {240, 240, 240}, {0, 0, 240},     {0, 240, 0},     {240, 0, 0},
      37             :     {240, 240, 0},   {240, 0, 240},   {240, 122, 0},   {0, 240, 240},
      38             :     {240, 240, 240}, {0, 0, 240},     {0, 240, 0},     {240, 0, 0},
      39             :     {240, 240, 0},   {240, 0, 240},   {240, 122, 0},   {0, 225, 225},
      40             :     {225, 225, 225}, {0, 0, 225},     {0, 225, 0},     {225, 0, 0},
      41             :     {225, 225, 0},   {225, 0, 225},   {225, 117, 0},   {0, 225, 225},
      42             :     {225, 225, 225}, {0, 0, 225},     {0, 225, 0},     {225, 0, 0},
      43             :     {225, 225, 0},   {225, 0, 225},   {225, 117, 0},   {0, 210, 210},
      44             :     {210, 210, 210}, {0, 0, 210},     {0, 210, 0},     {210, 0, 0},
      45             :     {210, 210, 0},   {210, 0, 210},   {210, 112, 0},   {0, 210, 210},
      46             :     {210, 210, 210}, {0, 0, 210},     {0, 210, 0},     {210, 0, 0},
      47             :     {210, 210, 0},   {210, 0, 210},   {210, 112, 0},   {0, 195, 195},
      48             :     {195, 195, 195}, {0, 0, 195},     {0, 195, 0},     {195, 0, 0},
      49             :     {195, 195, 0},   {195, 0, 195},   {195, 107, 0},   {0, 195, 195},
      50             :     {195, 195, 195}, {0, 0, 195},     {0, 195, 0},     {195, 0, 0},
      51             :     {195, 195, 0},   {195, 0, 195},   {195, 107, 0},   {0, 180, 180},
      52             :     {180, 180, 180}, {0, 0, 180},     {0, 180, 0},     {180, 0, 0},
      53             :     {180, 180, 0},   {180, 0, 180},   {180, 102, 0},   {0, 180, 180},
      54             :     {180, 180, 180}, {0, 0, 180},     {0, 180, 0},     {180, 0, 0},
      55             :     {180, 180, 0},   {180, 0, 180},   {180, 102, 0},   {0, 165, 165},
      56             :     {165, 165, 165}, {0, 0, 165},     {0, 165, 0},     {165, 0, 0},
      57             :     {165, 165, 0},   {165, 0, 165},   {165, 97, 0},    {0, 165, 165},
      58             :     {165, 165, 165}, {0, 0, 165},     {0, 165, 0},     {165, 0, 0},
      59             :     {165, 165, 0},   {165, 0, 165},   {165, 97, 0},    {0, 150, 150},
      60             :     {150, 150, 150}, {0, 0, 150},     {0, 150, 0},     {150, 0, 0},
      61             :     {150, 150, 0},   {150, 0, 150},   {150, 92, 0},    {0, 150, 150},
      62             :     {150, 150, 150}, {0, 0, 150},     {0, 150, 0},     {150, 0, 0},
      63             :     {150, 150, 0},   {150, 0, 150},   {150, 92, 0},    {0, 135, 135},
      64             :     {135, 135, 135}, {0, 0, 135},     {0, 135, 0},     {135, 0, 0},
      65             :     {135, 135, 0},   {135, 0, 135},   {135, 87, 0},    {0, 135, 135},
      66             :     {135, 135, 135}, {0, 0, 135},     {0, 135, 0},     {135, 0, 0},
      67             :     {135, 135, 0},   {135, 0, 135},   {135, 87, 0},    {0, 120, 120},
      68             :     {120, 120, 120}, {0, 0, 120},     {0, 120, 0},     {120, 0, 0},
      69             :     {120, 120, 0},   {120, 0, 120},   {120, 82, 0},    {0, 120, 120},
      70             :     {120, 120, 120}, {0, 0, 120},     {0, 120, 0},     {120, 0, 0},
      71             :     {120, 120, 0},   {120, 0, 120},   {120, 82, 0},    {0, 105, 105},
      72             :     {105, 105, 105}, {0, 0, 105},     {0, 105, 0},     {105, 0, 0},
      73             :     {105, 105, 0},   {105, 0, 105},   {105, 77, 0},    {0, 105, 105},
      74             :     {105, 105, 105}, {0, 0, 105},     {0, 105, 0},     {105, 0, 0},
      75             :     {105, 105, 0},   {105, 0, 105},   {105, 77, 0},    {0, 90, 90},
      76             :     {90, 90, 90},    {0, 0, 90},      {0, 90, 0},      {90, 0, 0},
      77             :     {90, 90, 0},     {90, 0, 90},     {90, 72, 0},     {0, 90, 90},
      78             :     {90, 90, 90},    {0, 0, 90},      {0, 90, 0},      {90, 0, 0},
      79             :     {90, 90, 0},     {90, 0, 90},     {90, 72, 0},     {0, 75, 75},
      80             :     {75, 75, 75},    {0, 0, 75},      {0, 75, 0},      {75, 0, 0},
      81             :     {75, 75, 0},     {75, 0, 75},     {75, 67, 0},     {0, 75, 75},
      82             :     {75, 75, 75},    {0, 0, 75},      {0, 75, 0},      {75, 0, 0},
      83             :     {75, 75, 0},     {75, 0, 75},     {75, 67, 0},     {0, 60, 60},
      84             :     {60, 60, 60},    {0, 0, 60},      {0, 60, 0},      {60, 0, 0},
      85             :     {60, 60, 0},     {60, 0, 60},     {60, 62, 0},     {0, 60, 60},
      86             :     {60, 60, 60},    {0, 0, 60},      {0, 60, 0},      {60, 0, 0},
      87             :     {60, 60, 0},     {60, 0, 60},     {60, 62, 0},     {0, 45, 45},
      88             :     {45, 45, 45},    {0, 0, 45},      {0, 45, 0},      {45, 0, 0},
      89             :     {45, 45, 0},     {45, 0, 45},     {45, 57, 0},     {0, 45, 45},
      90             :     {45, 45, 45},    {0, 0, 45},      {0, 45, 0},      {45, 0, 0},
      91             :     {45, 45, 0},     {45, 0, 45},     {45, 57, 0},     {0, 30, 30},
      92             :     {30, 30, 30},    {0, 0, 30},      {0, 30, 0},      {30, 0, 0},
      93             :     {30, 30, 0},     {30, 0, 30},     {30, 52, 0},     {0, 30, 30},
      94             :     {30, 30, 30},    {0, 0, 30},      {0, 30, 0},      {30, 0, 0},
      95             :     {30, 30, 0},     {30, 0, 30},     {192, 192, 192}, {28, 0, 100}};
      96             : 
      97             : /************************************************************************/
      98             : /*                           DGNLookupColor()                           */
      99             : /************************************************************************/
     100             : 
     101             : /**
     102             :  * Translate color index into RGB values.
     103             :  *
     104             :  * If no color table has yet been encountered in the file a hard-coded
     105             :  * "default" color table will be used.  This seems to be what Microstation
     106             :  * uses as a color table when there isn't one in a DGN file but I am not
     107             :  * absolutely convinced it is appropriate.
     108             :  *
     109             :  * @param hDGN the file.
     110             :  * @param color_index the color index to lookup.
     111             :  * @param red location to put red component.
     112             :  * @param green location to put green component.
     113             :  * @param blue location to put blue component.
     114             :  *
     115             :  * @return TRUE on success or FALSE on failure.  May fail if color_index is
     116             :  * out of range.
     117             :  */
     118             : 
     119         262 : int DGNLookupColor(DGNHandle hDGN, int color_index, int *red, int *green,
     120             :                    int *blue)
     121             : 
     122             : {
     123         262 :     if (color_index < 0 || color_index > 255)
     124           0 :         return FALSE;
     125             : 
     126         262 :     DGNInfo *psDGN = (DGNInfo *)hDGN;
     127             : 
     128         262 :     if (!psDGN->got_color_table)
     129             :     {
     130         262 :         *red = abyDefaultPCT[color_index][0];
     131         262 :         *green = abyDefaultPCT[color_index][1];
     132         262 :         *blue = abyDefaultPCT[color_index][2];
     133             :     }
     134             :     else
     135             :     {
     136           0 :         *red = psDGN->color_table[color_index][0];
     137           0 :         *green = psDGN->color_table[color_index][1];
     138           0 :         *blue = psDGN->color_table[color_index][2];
     139             :     }
     140             : 
     141         262 :     return TRUE;
     142             : }
     143             : 
     144             : /************************************************************************/
     145             : /*                        DGNGetShapeFillInfo()                         */
     146             : /************************************************************************/
     147             : 
     148             : /**
     149             :  * Fetch fill color for a shape.
     150             :  *
     151             :  * This method will check for a 0x0041 user attribute linkaged with fill
     152             :  * color information for the element.  If found the function returns TRUE,
     153             :  * and places the fill color in *pnColor, otherwise FALSE is returned and
     154             :  * *pnColor is not updated.
     155             :  *
     156             :  * @param hDGN the file.
     157             :  * @param psElem the element.
     158             :  * @param pnColor the location to return the fill color.
     159             :  *
     160             :  * @return TRUE on success or FALSE on failure.
     161             :  */
     162             : 
     163          10 : int DGNGetShapeFillInfo(DGNHandle hDGN, DGNElemCore *psElem, int *pnColor)
     164             : 
     165             : {
     166          10 :     for (int iLink = 0; true; iLink++)
     167             :     {
     168          17 :         int nLinkType = 0;
     169          17 :         int nLinkSize = 0;
     170          17 :         unsigned char *pabyData = DGNGetLinkage(hDGN, psElem, iLink, &nLinkType,
     171             :                                                 nullptr, nullptr, &nLinkSize);
     172          17 :         if (pabyData == nullptr)
     173          10 :             return FALSE;
     174             : 
     175          11 :         if (nLinkType == DGNLT_SHAPE_FILL && nLinkSize >= 9)
     176             :         {
     177           4 :             *pnColor = pabyData[8];
     178           4 :             return TRUE;
     179             :         }
     180           7 :     }
     181             : }
     182             : 
     183             : /************************************************************************/
     184             : /*                        DGNGetAssocID()                               */
     185             : /************************************************************************/
     186             : 
     187             : /**
     188             :  * Fetch association id for an element.
     189             :  *
     190             :  * This method will check if an element has an association id, and if so
     191             :  * returns it, otherwise returning -1.  Association ids are kept as a
     192             :  * user attribute linkage where present.
     193             :  *
     194             :  * @param hDGN the file.
     195             :  * @param psElem the element.
     196             :  *
     197             :  * @return The id or -1 on failure.
     198             :  */
     199             : 
     200           0 : int DGNGetAssocID(DGNHandle hDGN, DGNElemCore *psElem)
     201             : 
     202             : {
     203           0 :     for (int iLink = 0; true; iLink++)
     204             :     {
     205           0 :         int nLinkType = 0;
     206           0 :         int nLinkSize = 0;
     207           0 :         unsigned char *pabyData = DGNGetLinkage(hDGN, psElem, iLink, &nLinkType,
     208             :                                                 nullptr, nullptr, &nLinkSize);
     209           0 :         if (pabyData == nullptr)
     210           0 :             return -1;
     211             : 
     212           0 :         if (nLinkType == DGNLT_ASSOC_ID && nLinkSize >= 8)
     213             :         {
     214           0 :             return pabyData[4] + pabyData[5] * 256 + pabyData[6] * 256 * 256 +
     215           0 :                    pabyData[7] * 256 * 256 * 256;
     216             :         }
     217           0 :     }
     218             : }
     219             : 
     220             : /************************************************************************/
     221             : /*                          DGNRad50ToAscii()                           */
     222             : /*                                                                      */
     223             : /*      Convert one 16-bits Radix-50 to ASCII (3 chars).                */
     224             : /************************************************************************/
     225             : 
     226           0 : void DGNRad50ToAscii(unsigned short sRad50, char *str)
     227             : {
     228           0 :     char ch = '\0';
     229           0 :     unsigned short saQuots[3] = {1600, 40, 1};
     230             : 
     231           0 :     for (int i = 0; i < 3; i++)
     232             :     {
     233           0 :         unsigned short sValue = sRad50;
     234           0 :         sValue /= saQuots[i];
     235             :         /* Map 0..39 to ASCII */
     236           0 :         if (sValue == 0)
     237           0 :             ch = ' '; /* space */
     238           0 :         else if (/*sValue >= 1 &&*/ sValue <= 26)
     239           0 :             ch = (char)(sValue - 1 + 'A'); /* printable alpha A..Z */
     240           0 :         else if (sValue == 27)
     241           0 :             ch = '$'; /* dollar */
     242           0 :         else if (sValue == 28)
     243           0 :             ch = '.'; /* period */
     244           0 :         else if (sValue == 29)
     245           0 :             ch = ' '; /* unused char, emit a space instead */
     246           0 :         else if (/*sValue >= 30 &&*/ sValue <= 39)
     247           0 :             ch = (char)(sValue - 30 + '0'); /* digit 0..9 */
     248           0 :         *str = ch;
     249           0 :         str++;
     250             : 
     251           0 :         sRad50 -= (sValue * saQuots[i]);
     252             :     }
     253             : 
     254             :     /* Do zero-terminate */
     255           0 :     *str = '\0';
     256           0 : }
     257             : 
     258             : /************************************************************************/
     259             : /*                          DGNAsciiToRad50()                           */
     260             : /************************************************************************/
     261             : 
     262           0 : void DGNAsciiToRad50(const char *str, unsigned short *pRad50)
     263             : 
     264             : {
     265           0 :     unsigned short rad50 = 0;
     266             : 
     267           0 :     for (int i = 0; i < 3; i++)
     268             :     {
     269           0 :         if (i >= (int)strlen(str))
     270             :         {
     271           0 :             rad50 = rad50 * 40;
     272           0 :             continue;
     273             :         }
     274             : 
     275           0 :         unsigned short value = 0;
     276             : 
     277           0 :         if (str[i] == '$')
     278           0 :             value = 27;
     279           0 :         else if (str[i] == '.')
     280           0 :             value = 28;
     281           0 :         else if (str[i] == ' ')
     282           0 :             value = 29;
     283           0 :         else if (str[i] >= '0' && str[i] <= '9')
     284           0 :             value = str[i] - '0' + 30;
     285           0 :         else if (str[i] >= 'a' && str[i] <= 'z')
     286           0 :             value = str[i] - 'a' + 1;
     287           0 :         else if (str[i] >= 'A' && str[i] <= 'Z')
     288           0 :             value = str[i] - 'A' + 1;
     289             :         else
     290           0 :             value = 0;
     291             : 
     292           0 :         rad50 = rad50 * 40 + value;
     293             :     }
     294             : 
     295           0 :     *pRad50 = rad50;
     296           0 : }
     297             : 
     298             : /************************************************************************/
     299             : /*                        DGNGetLineStyleName()                         */
     300             : /*                                                                      */
     301             : /*      Read the line style name from symbol table.                     */
     302             : /*      The got name is stored in psLine.                               */
     303             : /************************************************************************/
     304             : #ifdef unused
     305             : int DGNGetLineStyleName(CPL_UNUSED DGNInfo *psDGN, DGNElemMultiPoint *psLine,
     306             :                         char szLineStyle[65])
     307             : {
     308             :     if (psLine->core.attr_bytes > 0 && psLine->core.attr_data[1] == 0x10 &&
     309             :         psLine->core.attr_data[2] == 0xf9 && psLine->core.attr_data[3] == 0x79)
     310             :     {
     311             : #ifdef notdef
     312             :         for (int i = 0; i < SYMBOL_TABLE_SIZE; i++)
     313             :         {
     314             :             if (*((unsigned char *)psDGN->buffer + 0x21e5 + i) ==
     315             :                     psLine->core.attr_data[4] &&
     316             :                 *((unsigned char *)psDGN->buffer + 0x21e6 + i) ==
     317             :                     psLine->core.attr_data[5] &&
     318             :                 *((unsigned char *)psDGN->buffer + 0x21e7 + i) ==
     319             :                     psLine->core.attr_data[6] &&
     320             :                 *((unsigned char *)psDGN->buffer + 0x21e8 + i) ==
     321             :                     psLine->core.attr_data[7])
     322             :             {
     323             :                 memcpy(szLineStyle, (unsigned char *)psDGN->buffer + 0x21e9 + i,
     324             :                        64);
     325             :                 szLineStyle[64] = '\0';
     326             :                 return TRUE;
     327             :             }
     328             :         }
     329             : #endif
     330             :         return FALSE;
     331             :     }
     332             :     else
     333             :     {
     334             :         szLineStyle[0] = '\0';
     335             :         return FALSE;
     336             :     }
     337             : }
     338             : #endif
     339             : 
     340             : /************************************************************************/
     341             : /*                           DGNDumpElement()                           */
     342             : /************************************************************************/
     343             : 
     344             : /**
     345             :  * Emit textual report of an element.
     346             :  *
     347             :  * This function exists primarily for debugging, and will produce a textual
     348             :  * report about any element type to the designated file.
     349             :  *
     350             :  * @param hDGN the file from which the element originated.
     351             :  * @param psElement the element to report on.
     352             :  * @param fp the file (such as stdout) to report the element information to.
     353             :  */
     354             : 
     355           0 : void DGNDumpElement(DGNHandle hDGN, DGNElemCore *psElement, FILE *fp)
     356             : 
     357             : {
     358           0 :     DGNInfo *psInfo = (DGNInfo *)hDGN;
     359             : 
     360           0 :     fprintf(fp, "\n");
     361           0 :     fprintf(fp, "Element:%-12s Level:%2d id:%-6d ",
     362             :             DGNTypeToName(psElement->type), psElement->level,
     363             :             psElement->element_id);
     364             : 
     365           0 :     if (psElement->complex)
     366           0 :         fprintf(fp, "(Complex) ");
     367             : 
     368           0 :     if (psElement->deleted)
     369           0 :         fprintf(fp, "(DELETED) ");
     370             : 
     371           0 :     fprintf(fp, "\n");
     372             : 
     373           0 :     fprintf(fp, "  offset=%d  size=%d bytes\n", psElement->offset,
     374             :             psElement->size);
     375             : 
     376           0 :     fprintf(fp, "  graphic_group:%-3d color:%d weight:%d style:%d\n",
     377             :             psElement->graphic_group, psElement->color, psElement->weight,
     378             :             psElement->style);
     379             : 
     380           0 :     if (psElement->properties != 0)
     381             :     {
     382           0 :         fprintf(fp, "  properties=%d", psElement->properties);
     383           0 :         if (psElement->properties & DGNPF_HOLE)
     384           0 :             fprintf(fp, ",HOLE");
     385           0 :         if (psElement->properties & DGNPF_SNAPPABLE)
     386           0 :             fprintf(fp, ",SNAPPABLE");
     387           0 :         if (psElement->properties & DGNPF_PLANAR)
     388           0 :             fprintf(fp, ",PLANAR");
     389           0 :         if (psElement->properties & DGNPF_ORIENTATION)
     390           0 :             fprintf(fp, ",ORIENTATION");
     391           0 :         if (psElement->properties & DGNPF_ATTRIBUTES)
     392           0 :             fprintf(fp, ",ATTRIBUTES");
     393           0 :         if (psElement->properties & DGNPF_MODIFIED)
     394           0 :             fprintf(fp, ",MODIFIED");
     395           0 :         if (psElement->properties & DGNPF_NEW)
     396           0 :             fprintf(fp, ",NEW");
     397           0 :         if (psElement->properties & DGNPF_LOCKED)
     398           0 :             fprintf(fp, ",LOCKED");
     399             : 
     400           0 :         int nClass = psElement->properties & DGNPF_CLASS;
     401           0 :         if (nClass == DGNC_PATTERN_COMPONENT)
     402           0 :             fprintf(fp, ",PATTERN_COMPONENT");
     403           0 :         else if (nClass == DGNC_CONSTRUCTION_ELEMENT)
     404           0 :             fprintf(fp, ",CONSTRUCTION ELEMENT");
     405           0 :         else if (nClass == DGNC_DIMENSION_ELEMENT)
     406           0 :             fprintf(fp, ",DIMENSION ELEMENT");
     407           0 :         else if (nClass == DGNC_PRIMARY_RULE_ELEMENT)
     408           0 :             fprintf(fp, ",PRIMARY RULE ELEMENT");
     409           0 :         else if (nClass == DGNC_LINEAR_PATTERNED_ELEMENT)
     410           0 :             fprintf(fp, ",LINEAR PATTERNED ELEMENT");
     411           0 :         else if (nClass == DGNC_CONSTRUCTION_RULE_ELEMENT)
     412           0 :             fprintf(fp, ",CONSTRUCTION_RULE_ELEMENT");
     413             : 
     414           0 :         fprintf(fp, "\n");
     415             :     }
     416             : 
     417           0 :     switch (psElement->stype)
     418             :     {
     419           0 :         case DGNST_MULTIPOINT:
     420             :         {
     421           0 :             DGNElemMultiPoint *psLine = (DGNElemMultiPoint *)psElement;
     422             : 
     423           0 :             for (int i = 0; i < psLine->num_vertices; i++)
     424           0 :                 fprintf(fp, "  (%.6f,%.6f,%.6f)\n", psLine->vertices[i].x,
     425             :                         psLine->vertices[i].y, psLine->vertices[i].z);
     426             :         }
     427           0 :         break;
     428             : 
     429           0 :         case DGNST_CELL_HEADER:
     430             :         {
     431           0 :             DGNElemCellHeader *psCell = (DGNElemCellHeader *)psElement;
     432             : 
     433           0 :             fprintf(
     434             :                 fp,
     435             :                 "  totlength=%d, name=%s, class=%x, levels=%02x%02x%02x%02x\n",
     436           0 :                 psCell->totlength, psCell->name, psCell->cclass,
     437           0 :                 psCell->levels[0], psCell->levels[1], psCell->levels[2],
     438           0 :                 psCell->levels[3]);
     439           0 :             fprintf(fp,
     440             :                     "  rnglow=(%.5f,%.5f,%.5f)\n"
     441             :                     "  rnghigh=(%.5f,%.5f,%.5f)\n",
     442             :                     psCell->rnglow.x, psCell->rnglow.y, psCell->rnglow.z,
     443             :                     psCell->rnghigh.x, psCell->rnghigh.y, psCell->rnghigh.z);
     444           0 :             fprintf(fp, "  origin=(%.5f,%.5f,%.5f)\n", psCell->origin.x,
     445             :                     psCell->origin.y, psCell->origin.z);
     446             : 
     447           0 :             if (psInfo->dimension == 2)
     448           0 :                 fprintf(fp, "  xscale=%g, yscale=%g, rotation=%g\n",
     449             :                         psCell->xscale, psCell->yscale, psCell->rotation);
     450             :             else
     451           0 :                 fprintf(fp, "  trans=%g,%g,%g,%g,%g,%g,%g,%g,%g\n",
     452             :                         psCell->trans[0], psCell->trans[1], psCell->trans[2],
     453             :                         psCell->trans[3], psCell->trans[4], psCell->trans[5],
     454             :                         psCell->trans[6], psCell->trans[7], psCell->trans[8]);
     455             :         }
     456           0 :         break;
     457             : 
     458           0 :         case DGNST_CELL_LIBRARY:
     459             :         {
     460           0 :             DGNElemCellLibrary *psCell = (DGNElemCellLibrary *)psElement;
     461             : 
     462           0 :             fprintf(
     463             :                 fp,
     464             :                 "  name=%s, class=%x, levels=%02x%02x%02x%02x, numwords=%d\n",
     465           0 :                 psCell->name, psCell->cclass, psCell->levels[0],
     466           0 :                 psCell->levels[1], psCell->levels[2], psCell->levels[3],
     467             :                 psCell->numwords);
     468           0 :             fprintf(fp, "  dispsymb=%d, description=%s\n", psCell->dispsymb,
     469           0 :                     psCell->description);
     470             :         }
     471           0 :         break;
     472             : 
     473           0 :         case DGNST_SHARED_CELL_DEFN:
     474             :         {
     475           0 :             DGNElemSharedCellDefn *psShared =
     476             :                 (DGNElemSharedCellDefn *)psElement;
     477             : 
     478           0 :             fprintf(fp, "  totlength=%d\n", psShared->totlength);
     479             :         }
     480           0 :         break;
     481             : 
     482           0 :         case DGNST_ARC:
     483             :         {
     484           0 :             DGNElemArc *psArc = (DGNElemArc *)psElement;
     485             : 
     486           0 :             if (psInfo->dimension == 2)
     487           0 :                 fprintf(fp, "  origin=(%.5f,%.5f), rotation=%f\n",
     488             :                         psArc->origin.x, psArc->origin.y, psArc->rotation);
     489             :             else
     490           0 :                 fprintf(fp, "  origin=(%.5f,%.5f,%.5f), quat=%d,%d,%d,%d\n",
     491             :                         psArc->origin.x, psArc->origin.y, psArc->origin.z,
     492             :                         psArc->quat[0], psArc->quat[1], psArc->quat[2],
     493             :                         psArc->quat[3]);
     494           0 :             fprintf(fp, "  axes=(%.5f,%.5f), start angle=%f, sweep=%f\n",
     495             :                     psArc->primary_axis, psArc->secondary_axis, psArc->startang,
     496             :                     psArc->sweepang);
     497             :         }
     498           0 :         break;
     499             : 
     500           0 :         case DGNST_TEXT:
     501             :         {
     502           0 :             DGNElemText *psText = (DGNElemText *)psElement;
     503             : 
     504           0 :             fprintf(fp,
     505             :                     "  origin=(%.5f,%.5f), rotation=%f\n"
     506             :                     "  font=%d, just=%d, length_mult=%g, height_mult=%g\n"
     507             :                     "  string = \"%s\"\n",
     508             :                     psText->origin.x, psText->origin.y, psText->rotation,
     509             :                     psText->font_id, psText->justification, psText->length_mult,
     510           0 :                     psText->height_mult, psText->string);
     511             :         }
     512           0 :         break;
     513             : 
     514           0 :         case DGNST_TEXT_NODE:
     515             :         {
     516           0 :             DGNElemTextNode *psNode = (DGNElemTextNode *)psElement;
     517             : 
     518           0 :             fprintf(fp, "  totlength=%d, num_texts=%d\n", psNode->totlength,
     519             :                     psNode->numelems);
     520           0 :             fprintf(fp,
     521             :                     "  origin=(%.5f,%.5f), rotation=%f\n"
     522             :                     "  font=%d, just=%d, length_mult=%g, height_mult=%g\n",
     523             :                     psNode->origin.x, psNode->origin.y, psNode->rotation,
     524           0 :                     psNode->font_id, psNode->justification, psNode->length_mult,
     525             :                     psNode->height_mult);
     526           0 :             fprintf(fp, "  max_length=%d, used=%d,", psNode->max_length,
     527           0 :                     psNode->max_used);
     528           0 :             fprintf(fp, "  node_number=%d\n", psNode->node_number);
     529             :         }
     530           0 :         break;
     531             : 
     532           0 :         case DGNST_COMPLEX_HEADER:
     533             :         {
     534           0 :             DGNElemComplexHeader *psHdr = (DGNElemComplexHeader *)psElement;
     535             : 
     536           0 :             fprintf(fp, "  totlength=%d, numelems=%d\n", psHdr->totlength,
     537             :                     psHdr->numelems);
     538           0 :             if (psElement->type == DGNT_3DSOLID_HEADER ||
     539           0 :                 psElement->type == DGNT_3DSURFACE_HEADER)
     540             :             {
     541           0 :                 fprintf(fp, "  surftype=%d, boundelms=%d\n", psHdr->surftype,
     542             :                         psHdr->boundelms);
     543             :             }
     544             :         }
     545           0 :         break;
     546             : 
     547           0 :         case DGNST_COLORTABLE:
     548             :         {
     549           0 :             DGNElemColorTable *psCT = (DGNElemColorTable *)psElement;
     550             : 
     551           0 :             fprintf(fp, "  screen_flag: %d\n", psCT->screen_flag);
     552           0 :             for (int i = 0; i < 256; i++)
     553             :             {
     554           0 :                 fprintf(fp, "  %3d: (%3u,%3u,%3u)\n", i, psCT->color_info[i][0],
     555           0 :                         psCT->color_info[i][1], psCT->color_info[i][2]);
     556             :             }
     557             :         }
     558           0 :         break;
     559             : 
     560           0 :         case DGNST_TCB:
     561             :         {
     562           0 :             DGNElemTCB *psTCB = (DGNElemTCB *)psElement;
     563             : 
     564           0 :             fprintf(fp, "  dimension = %d\n", psTCB->dimension);
     565           0 :             fprintf(fp, "  uor_per_subunit = %ld, subunits = `%s'\n",
     566           0 :                     psTCB->uor_per_subunit, psTCB->sub_units);
     567           0 :             fprintf(fp, "  subunits_per_master = %ld, master units = `%s'\n",
     568           0 :                     psTCB->subunits_per_master, psTCB->master_units);
     569           0 :             fprintf(fp, "  origin = (%.5f,%.5f,%.5f)\n", psTCB->origin_x,
     570             :                     psTCB->origin_y, psTCB->origin_z);
     571             : 
     572           0 :             for (int iView = 0; iView < 8; iView++)
     573             :             {
     574           0 :                 DGNViewInfo *psView = psTCB->views + iView;
     575             : 
     576           0 :                 fprintf(fp,
     577             :                         "  View%d: flags=%04X, "
     578             :                         "levels=%02X%02X%02X%02X%02X%02X%02X%02X\n",
     579           0 :                         iView, psView->flags, psView->levels[0],
     580           0 :                         psView->levels[1], psView->levels[2], psView->levels[3],
     581           0 :                         psView->levels[4], psView->levels[5], psView->levels[6],
     582           0 :                         psView->levels[7]);
     583           0 :                 fprintf(fp,
     584             :                         "        origin=(%g,%g,%g)\n        delta=(%g,%g,%g)\n",
     585             :                         psView->origin.x, psView->origin.y, psView->origin.z,
     586             :                         psView->delta.x, psView->delta.y, psView->delta.z);
     587           0 :                 fprintf(fp, "       trans=(%g,%g,%g,%g,%g,%g,%g,%g,%g)\n",
     588             :                         psView->transmatrx[0], psView->transmatrx[1],
     589             :                         psView->transmatrx[2], psView->transmatrx[3],
     590             :                         psView->transmatrx[4], psView->transmatrx[5],
     591             :                         psView->transmatrx[6], psView->transmatrx[7],
     592             :                         psView->transmatrx[8]);
     593             :             }
     594             :         }
     595           0 :         break;
     596             : 
     597           0 :         case DGNST_TAG_SET:
     598             :         {
     599           0 :             DGNElemTagSet *psTagSet = (DGNElemTagSet *)psElement;
     600             : 
     601           0 :             fprintf(fp, "  tagSetName=%s, tagSet=%d, tagCount=%d, flags=%d\n",
     602             :                     psTagSet->tagSetName, psTagSet->tagSet, psTagSet->tagCount,
     603             :                     psTagSet->flags);
     604           0 :             for (int iTag = 0; iTag < psTagSet->tagCount; iTag++)
     605             :             {
     606           0 :                 DGNTagDef *psTagDef = psTagSet->tagList + iTag;
     607             : 
     608           0 :                 fprintf(fp, "    %d: name=%s, type=%d, prompt=%s", psTagDef->id,
     609             :                         psTagDef->name, psTagDef->type, psTagDef->prompt);
     610           0 :                 if (psTagDef->type == 1)
     611           0 :                     fprintf(fp, ", default=%s\n",
     612             :                             psTagDef->defaultValue.string);
     613           0 :                 else if (psTagDef->type == 3 || psTagDef->type == 5)
     614           0 :                     fprintf(fp, ", default=%d\n",
     615             :                             psTagDef->defaultValue.integer);
     616           0 :                 else if (psTagDef->type == 4)
     617           0 :                     fprintf(fp, ", default=%g\n", psTagDef->defaultValue.real);
     618             :                 else
     619           0 :                     fprintf(fp, ", default=<unknown>\n");
     620             :             }
     621             :         }
     622           0 :         break;
     623             : 
     624           0 :         case DGNST_TAG_VALUE:
     625             :         {
     626           0 :             DGNElemTagValue *psTag = (DGNElemTagValue *)psElement;
     627             : 
     628           0 :             fprintf(fp, "  tagType=%d, tagSet=%d, tagIndex=%d, tagLength=%d\n",
     629             :                     psTag->tagType, psTag->tagSet, psTag->tagIndex,
     630             :                     psTag->tagLength);
     631           0 :             if (psTag->tagType == 1)
     632           0 :                 fprintf(fp, "  value=%s\n", psTag->tagValue.string);
     633           0 :             else if (psTag->tagType == 3)
     634           0 :                 fprintf(fp, "  value=%d\n", psTag->tagValue.integer);
     635           0 :             else if (psTag->tagType == 4)
     636           0 :                 fprintf(fp, "  value=%g\n", psTag->tagValue.real);
     637             :         }
     638           0 :         break;
     639             : 
     640           0 :         case DGNST_CONE:
     641             :         {
     642           0 :             DGNElemCone *psCone = (DGNElemCone *)psElement;
     643             : 
     644           0 :             fprintf(fp,
     645             :                     "  center_1=(%g,%g,%g) radius=%g\n"
     646             :                     "  center_2=(%g,%g,%g) radius=%g\n"
     647             :                     "  quat=%d,%d,%d,%d unknown=%d\n",
     648             :                     psCone->center_1.x, psCone->center_1.y, psCone->center_1.z,
     649             :                     psCone->radius_1, psCone->center_2.x, psCone->center_2.y,
     650             :                     psCone->center_2.z, psCone->radius_2, psCone->quat[0],
     651             :                     psCone->quat[1], psCone->quat[2], psCone->quat[3],
     652           0 :                     psCone->unknown);
     653             :         }
     654           0 :         break;
     655             : 
     656           0 :         case DGNST_BSPLINE_SURFACE_HEADER:
     657             :         {
     658           0 :             DGNElemBSplineSurfaceHeader *psSpline =
     659             :                 (DGNElemBSplineSurfaceHeader *)psElement;
     660             : 
     661           0 :             fprintf(fp, "  desc_words=%ld, curve type=%u\n",
     662           0 :                     psSpline->desc_words, psSpline->curve_type);
     663             : 
     664           0 :             fprintf(fp, "  U: properties=%02x", psSpline->u_properties);
     665           0 :             if (psSpline->u_properties != 0)
     666             :             {
     667           0 :                 if (psSpline->u_properties & DGNBSC_CURVE_DISPLAY)
     668             :                 {
     669           0 :                     fprintf(fp, ",CURVE_DISPLAY");
     670             :                 }
     671           0 :                 if (psSpline->u_properties & DGNBSC_POLY_DISPLAY)
     672             :                 {
     673           0 :                     fprintf(fp, ",POLY_DISPLAY");
     674             :                 }
     675           0 :                 if (psSpline->u_properties & DGNBSC_RATIONAL)
     676             :                 {
     677           0 :                     fprintf(fp, ",RATIONAL");
     678             :                 }
     679           0 :                 if (psSpline->u_properties & DGNBSC_CLOSED)
     680             :                 {
     681           0 :                     fprintf(fp, ",CLOSED");
     682             :                 }
     683             :             }
     684           0 :             fprintf(fp, "\n");
     685           0 :             fprintf(fp, "     order=%u\n  %d poles, %d knots, %d rule lines\n",
     686           0 :                     psSpline->u_order, psSpline->num_poles_u,
     687           0 :                     psSpline->num_knots_u, psSpline->rule_lines_u);
     688             : 
     689           0 :             fprintf(fp, "  V: properties=%02x", psSpline->v_properties);
     690           0 :             if (psSpline->v_properties != 0)
     691             :             {
     692           0 :                 if (psSpline->v_properties & DGNBSS_ARC_SPACING)
     693             :                 {
     694           0 :                     fprintf(fp, ",ARC_SPACING");
     695             :                 }
     696           0 :                 if (psSpline->v_properties & DGNBSS_CLOSED)
     697             :                 {
     698           0 :                     fprintf(fp, ",CLOSED");
     699             :                 }
     700             :             }
     701           0 :             fprintf(fp, "\n");
     702           0 :             fprintf(fp, "     order=%u\n  %d poles, %d knots, %d rule lines\n",
     703           0 :                     psSpline->v_order, psSpline->num_poles_v,
     704           0 :                     psSpline->num_knots_v, psSpline->rule_lines_v);
     705             :         }
     706           0 :         break;
     707             : 
     708           0 :         case DGNST_BSPLINE_CURVE_HEADER:
     709             :         {
     710           0 :             DGNElemBSplineCurveHeader *psSpline =
     711             :                 (DGNElemBSplineCurveHeader *)psElement;
     712             : 
     713           0 :             fprintf(fp,
     714             :                     "  desc_words=%ld, curve type=%u\n"
     715             :                     "  properties=%02x",
     716           0 :                     psSpline->desc_words, psSpline->curve_type,
     717           0 :                     psSpline->properties);
     718           0 :             if (psSpline->properties != 0)
     719             :             {
     720           0 :                 if (psSpline->properties & DGNBSC_CURVE_DISPLAY)
     721             :                 {
     722           0 :                     fprintf(fp, ",CURVE_DISPLAY");
     723             :                 }
     724           0 :                 if (psSpline->properties & DGNBSC_POLY_DISPLAY)
     725             :                 {
     726           0 :                     fprintf(fp, ",POLY_DISPLAY");
     727             :                 }
     728           0 :                 if (psSpline->properties & DGNBSC_RATIONAL)
     729             :                 {
     730           0 :                     fprintf(fp, ",RATIONAL");
     731             :                 }
     732           0 :                 if (psSpline->properties & DGNBSC_CLOSED)
     733             :                 {
     734           0 :                     fprintf(fp, ",CLOSED");
     735             :                 }
     736             :             }
     737           0 :             fprintf(fp, "\n");
     738           0 :             fprintf(fp, "  order=%u\n  %d poles, %d knots\n", psSpline->order,
     739           0 :                     psSpline->num_poles, psSpline->num_knots);
     740             :         }
     741           0 :         break;
     742             : 
     743           0 :         case DGNST_BSPLINE_SURFACE_BOUNDARY:
     744             :         {
     745           0 :             DGNElemBSplineSurfaceBoundary *psBounds =
     746             :                 (DGNElemBSplineSurfaceBoundary *)psElement;
     747             : 
     748           0 :             fprintf(fp, "  boundary number=%d, # vertices=%d\n",
     749           0 :                     psBounds->number, psBounds->numverts);
     750           0 :             for (int i = 0; i < psBounds->numverts; i++)
     751             :             {
     752           0 :                 fprintf(fp, "  (%.6f,%.6f)\n", psBounds->vertices[i].x,
     753             :                         psBounds->vertices[i].y);
     754             :             }
     755             :         }
     756           0 :         break;
     757             : 
     758           0 :         case DGNST_KNOT_WEIGHT:
     759             :         {
     760           0 :             DGNElemKnotWeight *psArray = (DGNElemKnotWeight *)psElement;
     761           0 :             int numelems = (psArray->core.size - 36) / 4;
     762           0 :             for (int i = 0; i < numelems; i++)
     763             :             {
     764           0 :                 fprintf(fp, "  %.6f\n", psArray->array[i]);
     765             :             }
     766             :         }
     767           0 :         break;
     768             : 
     769           0 :         default:
     770           0 :             break;
     771             :     }
     772             : 
     773           0 :     if (psElement->attr_bytes > 0)
     774             :     {
     775           0 :         fprintf(fp, "Attributes (%d bytes):\n", psElement->attr_bytes);
     776             : 
     777           0 :         for (int iLink = 0; true; iLink++)
     778             :         {
     779           0 :             int nLinkType = 0;
     780           0 :             int nEntityNum = 0;
     781           0 :             int nMSLink = 0;
     782           0 :             int nLinkSize = 0;
     783             :             // coverity[tained_data]
     784             :             unsigned char *pabyData =
     785           0 :                 DGNGetLinkage(hDGN, psElement, iLink, &nLinkType, &nEntityNum,
     786             :                               &nMSLink, &nLinkSize);
     787           0 :             if (pabyData == nullptr)
     788           0 :                 break;
     789             : 
     790           0 :             fprintf(fp, "Type=0x%04x", nLinkType);
     791           0 :             if (nMSLink != 0 || nEntityNum != 0)
     792           0 :                 fprintf(fp, ", EntityNum=%d, MSLink=%d", nEntityNum, nMSLink);
     793             : 
     794           0 :             int nBytes = static_cast<int>(psElement->attr_data +
     795           0 :                                           psElement->attr_bytes - pabyData);
     796           0 :             if (nBytes < nLinkSize)
     797             :             {
     798           0 :                 CPLError(CE_Failure, CPLE_AppDefined,
     799             :                          "Corrupt linkage, element id:%d, link:%d",
     800             :                          psElement->element_id, iLink);
     801           0 :                 fprintf(fp, " (Corrupt, declared size: %d, assuming size: %d)",
     802             :                         nLinkSize, nBytes);
     803           0 :                 nLinkSize = nBytes;
     804             :             }
     805           0 :             fprintf(fp, "\n  0x");
     806             : 
     807           0 :             for (int i = 0; i < nLinkSize; i++)
     808           0 :                 fprintf(fp, "%02x", pabyData[i]);
     809           0 :             fprintf(fp, "\n");
     810           0 :         }
     811             :     }
     812           0 : }
     813             : 
     814             : /************************************************************************/
     815             : /*                           DGNTypeToName()                            */
     816             : /************************************************************************/
     817             : 
     818             : /**
     819             :  * Convert type to name.
     820             :  *
     821             :  * Returns a human readable name for an element type such as DGNT_LINE.
     822             :  *
     823             :  * @param nType the DGNT_* type code to translate.
     824             :  *
     825             :  * @return a pointer to an internal string with the translation.  This string
     826             :  * should not be modified or freed.
     827             :  */
     828             : 
     829           0 : const char *DGNTypeToName(int nType)
     830             : 
     831             : {
     832             :     static char szNumericResult[16] = {};
     833             : 
     834           0 :     switch (nType)
     835             :     {
     836           0 :         case DGNT_CELL_LIBRARY:
     837           0 :             return "Cell Library";
     838             : 
     839           0 :         case DGNT_CELL_HEADER:
     840           0 :             return "Cell Header";
     841             : 
     842           0 :         case DGNT_LINE:
     843           0 :             return "Line";
     844             : 
     845           0 :         case DGNT_LINE_STRING:
     846           0 :             return "Line String";
     847             : 
     848           0 :         case DGNT_POINT_STRING:
     849           0 :             return "Point String";
     850             : 
     851           0 :         case DGNT_GROUP_DATA:
     852           0 :             return "Group Data";
     853             : 
     854           0 :         case DGNT_SHAPE:
     855           0 :             return "Shape";
     856             : 
     857           0 :         case DGNT_TEXT_NODE:
     858           0 :             return "Text Node";
     859             : 
     860           0 :         case DGNT_DIGITIZER_SETUP:
     861           0 :             return "Digitizer Setup";
     862             : 
     863           0 :         case DGNT_TCB:
     864           0 :             return "TCB";
     865             : 
     866           0 :         case DGNT_LEVEL_SYMBOLOGY:
     867           0 :             return "Level Symbology";
     868             : 
     869           0 :         case DGNT_CURVE:
     870           0 :             return "Curve";
     871             : 
     872           0 :         case DGNT_COMPLEX_CHAIN_HEADER:
     873           0 :             return "Complex Chain Header";
     874             : 
     875           0 :         case DGNT_COMPLEX_SHAPE_HEADER:
     876           0 :             return "Complex Shape Header";
     877             : 
     878           0 :         case DGNT_ELLIPSE:
     879           0 :             return "Ellipse";
     880             : 
     881           0 :         case DGNT_ARC:
     882           0 :             return "Arc";
     883             : 
     884           0 :         case DGNT_TEXT:
     885           0 :             return "Text";
     886             : 
     887           0 :         case DGNT_BSPLINE_POLE:
     888           0 :             return "B-Spline Pole";
     889             : 
     890           0 :         case DGNT_BSPLINE_SURFACE_HEADER:
     891           0 :             return "B-Spline Surface Header";
     892             : 
     893           0 :         case DGNT_BSPLINE_SURFACE_BOUNDARY:
     894           0 :             return "B-Spline Surface Boundary";
     895             : 
     896           0 :         case DGNT_BSPLINE_KNOT:
     897           0 :             return "B-Spline Knot";
     898             : 
     899           0 :         case DGNT_BSPLINE_CURVE_HEADER:
     900           0 :             return "B-Spline Curve Header";
     901             : 
     902           0 :         case DGNT_BSPLINE_WEIGHT_FACTOR:
     903           0 :             return "B-Spline Weight Factor";
     904             : 
     905           0 :         case DGNT_APPLICATION_ELEM:
     906           0 :             return "Application Element";
     907             : 
     908           0 :         case DGNT_SHARED_CELL_DEFN:
     909           0 :             return "Shared Cell Definition";
     910             : 
     911           0 :         case DGNT_SHARED_CELL_ELEM:
     912           0 :             return "Shared Cell Element";
     913             : 
     914           0 :         case DGNT_TAG_VALUE:
     915           0 :             return "Tag Value";
     916             : 
     917           0 :         case DGNT_CONE:
     918           0 :             return "Cone";
     919             : 
     920           0 :         case DGNT_3DSURFACE_HEADER:
     921           0 :             return "3D Surface Header";
     922             : 
     923           0 :         case DGNT_3DSOLID_HEADER:
     924           0 :             return "3D Solid Header";
     925             : 
     926           0 :         default:
     927           0 :             snprintf(szNumericResult, sizeof(szNumericResult), "%d", nType);
     928           0 :             return szNumericResult;
     929             :     }
     930             : }
     931             : 
     932             : /************************************************************************/
     933             : /*                         DGNGetAttrLinkSize()                         */
     934             : /************************************************************************/
     935             : 
     936             : /**
     937             :  * Get attribute linkage size.
     938             :  *
     939             :  * Returns the size, in bytes, of the attribute linkage starting at byte
     940             :  * offset nOffset.  On failure a value of 0 is returned.
     941             :  *
     942             :  * @param hDGN the file from which the element originated.
     943             :  * @param psElement the element to report on.
     944             :  * @param nOffset byte offset within attribute data of linkage to check.
     945             :  *
     946             :  * @return size of linkage in bytes, or zero.
     947             :  */
     948             : 
     949         470 : int DGNGetAttrLinkSize(CPL_UNUSED DGNHandle hDGN, DGNElemCore *psElement,
     950             :                        int nOffset)
     951             : {
     952         470 :     if (psElement->attr_bytes < nOffset + 4)
     953         309 :         return 0;
     954             : 
     955             :     /* DMRS Linkage */
     956         161 :     if ((psElement->attr_data[nOffset + 0] == 0 &&
     957          11 :          psElement->attr_data[nOffset + 1] == 0) ||
     958         150 :         (psElement->attr_data[nOffset + 0] == 0 &&
     959           0 :          psElement->attr_data[nOffset + 1] == 0x80))
     960          11 :         return 8;
     961             : 
     962             :     /* If low order bit of second byte is set, first byte is length */
     963         150 :     if (psElement->attr_data[nOffset + 1] & 0x10)
     964         150 :         return psElement->attr_data[nOffset + 0] * 2 + 2;
     965             : 
     966             :     /* unknown */
     967           0 :     return 0;
     968             : }
     969             : 
     970             : /************************************************************************/
     971             : /*                           DGNGetLinkage()                            */
     972             : /************************************************************************/
     973             : 
     974             : /**
     975             :  * Returns requested linkage raw data.
     976             :  *
     977             :  * A pointer to the raw data for the requested attribute linkage is returned
     978             :  * as well as (potentially) various information about the linkage including
     979             :  * the linkage type, database entity number and MSLink value, and the length
     980             :  * of the raw linkage data in bytes.
     981             :  *
     982             :  * If the requested linkage (iIndex) does not exist a value of zero is
     983             :  * returned.
     984             :  *
     985             :  * The entity number is (loosely speaking) the index of the table within
     986             :  * the current database to which the MSLINK value will refer.  The entity
     987             :  * number should be used to lookup the table name in the MSCATALOG table.
     988             :  * The MSLINK value is the key value for the record in the target table.
     989             :  *
     990             :  * @param hDGN the file from which the element originated.
     991             :  * @param psElement the element to report on.
     992             :  * @param iIndex the zero based index of the linkage to fetch.
     993             :  * @param pnLinkageType variable to return linkage type.  This may be one of
     994             :  * the predefined DGNLT_ values or a different value. This pointer may be NULL.
     995             :  * @param pnEntityNum variable to return the entity number in or NULL if not
     996             :  * required.
     997             :  * @param pnMSLink variable to return the MSLINK value in, or NULL if not
     998             :  * required.
     999             :  * @param pnLength variable to returned the linkage size in bytes or NULL.
    1000             :  *
    1001             :  * @return pointer to raw internal linkage data.  This data should not be
    1002             :  * altered or freed.  NULL returned on failure.
    1003             :  */
    1004             : 
    1005         390 : unsigned char *DGNGetLinkage(DGNHandle hDGN, DGNElemCore *psElement, int iIndex,
    1006             :                              int *pnLinkageType, int *pnEntityNum,
    1007             :                              int *pnMSLink, int *pnLength)
    1008             : 
    1009             : {
    1010         390 :     int nLinkSize = 0;
    1011             : 
    1012         390 :     for (int iLinkage = 0, nAttrOffset = 0;
    1013         470 :          (nLinkSize = DGNGetAttrLinkSize(hDGN, psElement, nAttrOffset)) != 0;
    1014          80 :          iLinkage++, nAttrOffset += nLinkSize)
    1015             :     {
    1016         161 :         if (iLinkage == iIndex)
    1017             :         {
    1018          81 :             if (nLinkSize <= 4)
    1019             :             {
    1020           0 :                 CPLError(CE_Failure, CPLE_AssertionFailed, "nLinkSize <= 4");
    1021           0 :                 return nullptr;
    1022             :             }
    1023          81 :             if (nLinkSize + nAttrOffset > psElement->attr_bytes)
    1024             :             {
    1025           0 :                 CPLError(CE_Failure, CPLE_AssertionFailed,
    1026             :                          "nLinkSize + nAttrOffset > psElement->attr_bytes");
    1027           0 :                 return nullptr;
    1028             :             }
    1029             : 
    1030          81 :             int nLinkageType = 0;
    1031          81 :             int nEntityNum = 0;
    1032          81 :             int nMSLink = 0;
    1033          81 :             if (psElement->attr_bytes >= nAttrOffset + 7 &&
    1034          81 :                 psElement->attr_data[nAttrOffset + 0] == 0x00 &&
    1035           4 :                 (psElement->attr_data[nAttrOffset + 1] == 0x00 ||
    1036           0 :                  psElement->attr_data[nAttrOffset + 1] == 0x80))
    1037             :             {
    1038           4 :                 nLinkageType = DGNLT_DMRS;
    1039           4 :                 nEntityNum = psElement->attr_data[nAttrOffset + 2] +
    1040           4 :                              psElement->attr_data[nAttrOffset + 3] * 256;
    1041           4 :                 nMSLink = psElement->attr_data[nAttrOffset + 4] +
    1042           4 :                           psElement->attr_data[nAttrOffset + 5] * 256 +
    1043           4 :                           psElement->attr_data[nAttrOffset + 6] * 65536;
    1044             :             }
    1045          77 :             else if (psElement->attr_bytes >= nAttrOffset + 4)
    1046          77 :                 nLinkageType = psElement->attr_data[nAttrOffset + 2] +
    1047          77 :                                psElement->attr_data[nAttrOffset + 3] * 256;
    1048             : 
    1049             :             // Possibly an external database linkage?
    1050          81 :             if (nLinkSize == 16 && nLinkageType != DGNLT_SHAPE_FILL &&
    1051          69 :                 psElement->attr_bytes >= nAttrOffset + 12)
    1052             :             {
    1053          69 :                 nEntityNum = psElement->attr_data[nAttrOffset + 6] +
    1054          69 :                              psElement->attr_data[nAttrOffset + 7] * 256;
    1055          69 :                 nMSLink = psElement->attr_data[nAttrOffset + 8] |
    1056          69 :                           (psElement->attr_data[nAttrOffset + 9] << 8) |
    1057          69 :                           (psElement->attr_data[nAttrOffset + 10] << 16) |
    1058          69 :                           (psElement->attr_data[nAttrOffset + 11] << 24);
    1059             :             }
    1060             : 
    1061          81 :             if (pnLinkageType != nullptr)
    1062          35 :                 *pnLinkageType = nLinkageType;
    1063          81 :             if (pnEntityNum != nullptr)
    1064          24 :                 *pnEntityNum = nEntityNum;
    1065          81 :             if (pnMSLink != nullptr)
    1066          24 :                 *pnMSLink = nMSLink;
    1067          81 :             if (pnLength != nullptr)
    1068          35 :                 *pnLength = nLinkSize;
    1069             : 
    1070          81 :             return psElement->attr_data + nAttrOffset;
    1071             :         }
    1072             :     }
    1073             : 
    1074         309 :     return nullptr;
    1075             : }
    1076             : 
    1077             : /************************************************************************/
    1078             : /*                         DGNRotationToQuat()                          */
    1079             : /*                                                                      */
    1080             : /*      Compute a quaternion for a given Z rotation.                    */
    1081             : /************************************************************************/
    1082             : 
    1083           0 : void DGNRotationToQuaternion(double dfRotation, int *panQuaternion)
    1084             : 
    1085             : {
    1086           0 :     const double dfRadianRot = (dfRotation / 180.0) * M_PI;
    1087             : 
    1088           0 :     panQuaternion[0] = (int)(cos(-dfRadianRot / 2.0) * 2147483647);
    1089           0 :     panQuaternion[1] = 0;
    1090           0 :     panQuaternion[2] = 0;
    1091           0 :     panQuaternion[3] = (int)(sin(-dfRadianRot / 2.0) * 2147483647);
    1092           0 : }
    1093             : 
    1094             : /************************************************************************/
    1095             : /*                         DGNQuaternionToMatrix()                      */
    1096             : /*                                                                      */
    1097             : /*      Compute a rotation matrix for a given quaternion                */
    1098             : /* FIXME: Write documentation on how to use this matrix                 */
    1099             : /* (i.e. things like row/column major, OpenGL style or not)             */
    1100             : /* kintel 20030819                                                      */
    1101             : /************************************************************************/
    1102             : 
    1103           0 : void DGNQuaternionToMatrix(int *quat, float *mat)
    1104             : {
    1105           0 :     const double q[4] = {1.0 * quat[1] / (1U << 31), 1.0 * quat[2] / (1U << 31),
    1106           0 :                          1.0 * quat[3] / (1U << 31),
    1107           0 :                          1.0 * quat[0] / (1U << 31)};
    1108             : 
    1109           0 :     mat[0 * 3 + 0] =
    1110           0 :         (float)(q[0] * q[0] - q[1] * q[1] - q[2] * q[2] + q[3] * q[3]);
    1111           0 :     mat[0 * 3 + 1] = (float)(2 * (q[2] * q[3] + q[0] * q[1]));
    1112           0 :     mat[0 * 3 + 2] = (float)(2 * (q[0] * q[2] - q[1] * q[3]));
    1113           0 :     mat[1 * 3 + 0] = (float)(2 * (q[0] * q[1] - q[2] * q[3]));
    1114           0 :     mat[1 * 3 + 1] =
    1115           0 :         (float)(-q[0] * q[0] + q[1] * q[1] - q[2] * q[2] + q[3] * q[3]);
    1116           0 :     mat[1 * 3 + 2] = (float)(2 * (q[0] * q[3] + q[1] * q[2]));
    1117           0 :     mat[2 * 3 + 0] = (float)(2 * (q[0] * q[2] + q[1] * q[3]));
    1118           0 :     mat[2 * 3 + 1] = (float)(2 * (q[1] * q[2] - q[0] * q[3]));
    1119           0 :     mat[2 * 3 + 2] =
    1120           0 :         (float)(-q[0] * q[0] - q[1] * q[1] + q[2] * q[2] + q[3] * q[3]);
    1121           0 : }
    1122             : 
    1123             : /************************************************************************/
    1124             : /*                  DGNTransformPointWithQuaternion()                   */
    1125             : /************************************************************************/
    1126             : 
    1127             : #ifdef unused
    1128             : void DGNTransformPointWithQuaternionVertex(CPL_UNUSED int *quat,
    1129             :                                            CPL_UNUSED DGNPoint *v1,
    1130             :                                            CPL_UNUSED DGNPoint *v2)
    1131             : {
    1132             :     /* ==================================================================== */
    1133             :     /*      Original code provided by kintel 20030819, but assumed to be    */
    1134             :     /*      incomplete.                                                     */
    1135             :     /* ==================================================================== */
    1136             : 
    1137             : #ifdef notdef
    1138             :     See below for sketched implementation. kintel 20030819.
    1139             :                                float x,y,z,w;
    1140             :     // FIXME: Convert quat to x,y,z,w
    1141             :     v2.x = w * w * v1.x + 2 * y * w * v1.z - 2 * z * w * v1.y + x * x * v1.x +
    1142             :            2 * y * x * v1.y + 2 * z * x * v1.z - z * z * v1.x - y * y * v1.x;
    1143             :     v2.y = 2 * x * y * v1.x + y * y * v1.y + 2 * z * y * v1.z +
    1144             :            2 * w * z * v1.x - z * z * v1.y + w * w * v1.y - 2 * x * w * v1.z -
    1145             :            x * x * v1.y;
    1146             :     v2.z = 2 * x * z * v1.x + 2 * y * z * v1.y + z * z * v1.z -
    1147             :            2 * w * y * v1.x - y * y * v1.z + 2 * w * x * v1.y - x * x * v1.z +
    1148             :            w * w * v1.z;
    1149             : #endif
    1150             : 
    1151             :     /* ==================================================================== */
    1152             :     /*      Implementation provided by Peggy Jung - 2004/03/05.            */
    1153             :     /*      peggy.jung at moskito-gis dot de.  I haven't tested it.         */
    1154             :     /* ==================================================================== */
    1155             : 
    1156             :     /*  Version: 0.1                                 Datum: 26.01.2004
    1157             : 
    1158             :     IN:
    1159             :     x,y,z               // DGNPoint &v1
    1160             :     quat[]              //
    1161             : 
    1162             :     OUT:
    1163             :     newX, newY, newZ    // DGNPoint &v2
    1164             : 
    1165             :     Author: Peggy Jung
    1166             :     */
    1167             :     /*
    1168             :         double ROT[12];  //rotation matrix for a given quaternion
    1169             :         double xx, xy, xz, xw, yy, yz, yw, zz, zw;
    1170             :         double a, b, c, d, n, x, y, z;
    1171             : 
    1172             :         x = v1->x;
    1173             :         y = v1->y;
    1174             :         z = v1->z;
    1175             : 
    1176             :         n =
    1177             :        sqrt((double)PDP2PC_long(quat[0])*(double)PDP2PC_long(quat[0])+(double)PDP2PC_long(quat[1])*(double)PDP2PC_long(quat[1])+
    1178             :                  (double)PDP2PC_long(quat[2])*(double)PDP2PC_long(quat[2])+(double)PDP2PC_long(quat[3])*(double)PDP2PC_long(quat[3]));
    1179             : 
    1180             :         a = (double)PDP2PC_long(quat[0])/n; //w
    1181             :         b = (double)PDP2PC_long(quat[1])/n; //x
    1182             :         c = (double)PDP2PC_long(quat[2])/n; //y
    1183             :         d = (double)PDP2PC_long(quat[3])/n; //z
    1184             : 
    1185             :         xx      = b*b;
    1186             :         xy      = b*c;
    1187             :         xz      = b*d;
    1188             :         xw      = b*a;
    1189             : 
    1190             :         yy      = c*c;
    1191             :         yz      = c*d;
    1192             :         yw      = c*a;
    1193             : 
    1194             :         zz      = d*d;
    1195             :         zw      = d+a;
    1196             : 
    1197             :         ROT[0] = 1 - 2 * yy - 2 * zz ;
    1198             :         ROT[1] =     2 * xy - 2 * zw ;
    1199             :         ROT[2] =     2 * xz + 2 * yw ;
    1200             : 
    1201             :         ROT[4] =     2 * xy + 2 * zw ;
    1202             :         ROT[5] = 1 - 2 * xx - 2 * zz ;
    1203             :         ROT[6] =     2 * yz - 2 * xw ;
    1204             : 
    1205             :         ROT[8] =     2 * xz - 2 * yw ;
    1206             :         ROT[9] =     2 * yz + 2 * xw ;
    1207             :         ROT[10] = 1 - 2 * xx - 2 * yy ;
    1208             : 
    1209             :         v2->x = ROT[0]*x + ROT[1]*y + ROT[2]*z;
    1210             :         v2->y = ROT[4]*x + ROT[5]*y + ROT[6]*z;
    1211             :         v2->z = ROT[8]*x + ROT[9]*y + ROT[10]*z;
    1212             :     */
    1213             : }
    1214             : #endif

Generated by: LCOV version 1.14