LCOV - code coverage report
Current view: top level - ogr/ogrsf_frmts/dgn - dgnopen.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 71 79 89.9 %
Date: 2024-11-25 13:07:18 Functions: 7 7 100.0 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  Microstation DGN Access Library
       4             :  * Purpose:  DGN Access Library file open code.
       5             :  * Author:   Frank Warmerdam, warmerdam@pobox.com
       6             :  *
       7             :  ******************************************************************************
       8             :  * Copyright (c) 2000, Avenza Systems Inc, http://www.avenza.com/
       9             :  *
      10             :  * SPDX-License-Identifier: MIT
      11             :  ****************************************************************************/
      12             : 
      13             : #include "dgnlibp.h"
      14             : 
      15             : /************************************************************************/
      16             : /*                            DGNTestOpen()                             */
      17             : /************************************************************************/
      18             : 
      19             : /**
      20             :  * Test if header is DGN.
      21             :  *
      22             :  * @param pabyHeader block of header data from beginning of file.
      23             :  * @param nByteCount number of bytes in pabyHeader.
      24             :  *
      25             :  * @return TRUE if the header appears to be from a DGN file, otherwise FALSE.
      26             :  */
      27             : 
      28        3928 : int DGNTestOpen(GByte *pabyHeader, int nByteCount)
      29             : 
      30             : {
      31        3928 :     if (nByteCount < 4)
      32           0 :         return FALSE;
      33             : 
      34             :     // Is it a cell library?
      35        3928 :     if (pabyHeader[0] == 0x08 && pabyHeader[1] == 0x05 &&
      36           0 :         pabyHeader[2] == 0x17 && pabyHeader[3] == 0x00)
      37           0 :         return TRUE;
      38             : 
      39             :     // Is it not a regular 2D or 3D file?
      40        3928 :     if ((pabyHeader[0] != 0x08 && pabyHeader[0] != 0xC8) ||
      41         194 :         pabyHeader[1] != 0x09 || pabyHeader[2] != 0xFE || pabyHeader[3] != 0x02)
      42        3734 :         return FALSE;
      43             : 
      44         194 :     return TRUE;
      45             : }
      46             : 
      47             : /************************************************************************/
      48             : /*                              DGNOpen()                               */
      49             : /************************************************************************/
      50             : 
      51             : /**
      52             :  * Open a DGN file.
      53             :  *
      54             :  * The file is opened, and minimally verified to ensure it is a DGN (ISFF)
      55             :  * file.  If the file cannot be opened for read access an error with code
      56             :  * CPLE_OpenFailed with be reported via CPLError() and NULL returned.
      57             :  * If the file header does
      58             :  * not appear to be a DGN file, an error with code CPLE_AppDefined will be
      59             :  * reported via CPLError(), and NULL returned.
      60             :  *
      61             :  * If successful a handle for further access is returned.  This should be
      62             :  * closed with DGNClose() when no longer needed.
      63             :  *
      64             :  * DGNOpen() does not scan the file on open, and should be very fast even for
      65             :  * large files.
      66             :  *
      67             :  * @param pszFilename name of file to try opening.
      68             :  * @param bUpdate should the file be opened with read+update (r+) mode?
      69             :  *
      70             :  * @return handle to use for further access to file using DGN API, or NULL
      71             :  * if open fails.
      72             :  */
      73             : 
      74         110 : DGNHandle DGNOpen(const char *pszFilename, int bUpdate)
      75             : 
      76             : {
      77             :     /* -------------------------------------------------------------------- */
      78             :     /*      Open the file.                                                  */
      79             :     /* -------------------------------------------------------------------- */
      80         110 :     VSILFILE *fp = VSIFOpenL(pszFilename, bUpdate ? "rb+" : "rb");
      81         110 :     if (fp == nullptr)
      82             :     {
      83           0 :         CPLError(CE_Failure, CPLE_OpenFailed,
      84             :                  "Unable to open `%s' for read access.\n", pszFilename);
      85           0 :         return nullptr;
      86             :     }
      87             : 
      88             :     /* -------------------------------------------------------------------- */
      89             :     /*      Verify the format ... add later.                                */
      90             :     /* -------------------------------------------------------------------- */
      91             :     GByte abyHeader[512];
      92             :     const int nHeaderBytes =
      93         110 :         static_cast<int>(VSIFReadL(abyHeader, 1, sizeof(abyHeader), fp));
      94         110 :     if (!DGNTestOpen(abyHeader, nHeaderBytes))
      95             :     {
      96           0 :         CPLError(CE_Failure, CPLE_AppDefined,
      97             :                  "File `%s' does not have expected DGN header.\n", pszFilename);
      98           0 :         VSIFCloseL(fp);
      99           0 :         return nullptr;
     100             :     }
     101             : 
     102         110 :     VSIRewindL(fp);
     103             : 
     104             :     /* -------------------------------------------------------------------- */
     105             :     /*      Create the info structure.                                      */
     106             :     /* -------------------------------------------------------------------- */
     107         110 :     DGNInfo *psDGN = static_cast<DGNInfo *>(CPLCalloc(sizeof(DGNInfo), 1));
     108         110 :     psDGN->fp = fp;
     109         110 :     psDGN->next_element_id = 0;
     110             : 
     111         110 :     psDGN->got_tcb = false;
     112         110 :     psDGN->scale = 1.0;
     113         110 :     psDGN->origin_x = 0.0;
     114         110 :     psDGN->origin_y = 0.0;
     115         110 :     psDGN->origin_z = 0.0;
     116             : 
     117         110 :     psDGN->index_built = false;
     118         110 :     psDGN->element_count = 0;
     119         110 :     psDGN->element_index = nullptr;
     120             : 
     121         110 :     psDGN->got_bounds = false;
     122             : 
     123         110 :     if (abyHeader[0] == 0xC8)
     124          42 :         psDGN->dimension = 3;
     125             :     else
     126          68 :         psDGN->dimension = 2;
     127             : 
     128         110 :     psDGN->has_spatial_filter = false;
     129         110 :     psDGN->sf_converted_to_uor = false;
     130         110 :     psDGN->select_complex_group = false;
     131         110 :     psDGN->in_complex_group = false;
     132             : 
     133         110 :     return (DGNHandle)psDGN;
     134             : }
     135             : 
     136             : /************************************************************************/
     137             : /*                           DGNSetOptions()                            */
     138             : /************************************************************************/
     139             : 
     140             : /**
     141             :  * Set file access options.
     142             :  *
     143             :  * Sets a flag affecting how the file is accessed.  Currently
     144             :  * there is only one support flag:
     145             :  *
     146             :  * DGNO_CAPTURE_RAW_DATA: If this is enabled (it is off by default),
     147             :  * then the raw binary data associated with elements will be kept in
     148             :  * the raw_data field within the DGNElemCore when they are read.  This
     149             :  * is required if the application needs to interpret the raw data itself.
     150             :  * It is also necessary if the element is to be written back to this file,
     151             :  * or another file using DGNWriteElement().  Off by default (to conserve
     152             :  * memory).
     153             :  *
     154             :  * @param hDGN handle to file returned by DGNOpen().
     155             :  * @param nOptions ORed option flags.
     156             :  */
     157             : 
     158          34 : void DGNSetOptions(DGNHandle hDGN, int nOptions)
     159             : 
     160             : {
     161          34 :     DGNInfo *psDGN = (DGNInfo *)hDGN;
     162             : 
     163          34 :     psDGN->options = nOptions;
     164          34 : }
     165             : 
     166             : /************************************************************************/
     167             : /*                        DGNSetSpatialFilter()                         */
     168             : /************************************************************************/
     169             : 
     170             : /**
     171             :  * Set rectangle for which features are desired.
     172             :  *
     173             :  * If a spatial filter is set with this function, DGNReadElement() will
     174             :  * only return spatial elements (elements with a known bounding box) and
     175             :  * only those elements for which this bounding box overlaps the requested
     176             :  * region.
     177             :  *
     178             :  * If all four values (dfXMin, dfXMax, dfYMin and dfYMax) are zero, the
     179             :  * spatial filter is disabled.   Note that installing a spatial filter
     180             :  * won't reduce the amount of data read from disk.  All elements are still
     181             :  * scanned, but the amount of processing work for elements outside the
     182             :  * spatial filter is minimized.
     183             :  *
     184             :  * @param hDGN Handle from DGNOpen() for file to update.
     185             :  * @param dfXMin minimum x coordinate for extents (georeferenced coordinates).
     186             :  * @param dfYMin minimum y coordinate for extents (georeferenced coordinates).
     187             :  * @param dfXMax maximum x coordinate for extents (georeferenced coordinates).
     188             :  * @param dfYMax maximum y coordinate for extents (georeferenced coordinates).
     189             :  */
     190             : 
     191           2 : void DGNSetSpatialFilter(DGNHandle hDGN, double dfXMin, double dfYMin,
     192             :                          double dfXMax, double dfYMax)
     193             : 
     194             : {
     195           2 :     DGNInfo *psDGN = (DGNInfo *)hDGN;
     196             : 
     197           2 :     if (dfXMin == 0.0 && dfXMax == 0.0 && dfYMin == 0.0 && dfYMax == 0.0)
     198             :     {
     199           1 :         psDGN->has_spatial_filter = false;
     200           1 :         return;
     201             :     }
     202             : 
     203           1 :     psDGN->has_spatial_filter = true;
     204           1 :     psDGN->sf_converted_to_uor = false;
     205             : 
     206           1 :     psDGN->sf_min_x_geo = dfXMin;
     207           1 :     psDGN->sf_min_y_geo = dfYMin;
     208           1 :     psDGN->sf_max_x_geo = dfXMax;
     209           1 :     psDGN->sf_max_y_geo = dfYMax;
     210             : 
     211           1 :     DGNSpatialFilterToUOR(psDGN);
     212             : }
     213             : 
     214             : /************************************************************************/
     215             : /*                       DGNSpatialFilterToUOR()                        */
     216             : /************************************************************************/
     217             : 
     218           2 : void DGNSpatialFilterToUOR(DGNInfo *psDGN)
     219             : 
     220             : {
     221           2 :     if (psDGN->sf_converted_to_uor || !psDGN->has_spatial_filter ||
     222           2 :         !psDGN->got_tcb)
     223           1 :         return;
     224             : 
     225           1 :     DGNPoint sMin = {psDGN->sf_min_x_geo, psDGN->sf_min_y_geo, 0};
     226             : 
     227           1 :     DGNPoint sMax = {psDGN->sf_max_x_geo, psDGN->sf_max_y_geo, 0};
     228             : 
     229           1 :     DGNInverseTransformPoint(psDGN, &sMin);
     230           1 :     DGNInverseTransformPoint(psDGN, &sMax);
     231             : 
     232           1 :     psDGN->sf_min_x = (GUInt32)(sMin.x + 2147483648.0);
     233           1 :     psDGN->sf_min_y = (GUInt32)(sMin.y + 2147483648.0);
     234           1 :     psDGN->sf_max_x = (GUInt32)(sMax.x + 2147483648.0);
     235           1 :     psDGN->sf_max_y = (GUInt32)(sMax.y + 2147483648.0);
     236             : 
     237           1 :     psDGN->sf_converted_to_uor = true;
     238             : }
     239             : 
     240             : /************************************************************************/
     241             : /*                              DGNClose()                              */
     242             : /************************************************************************/
     243             : 
     244             : /**
     245             :  * Close DGN file.
     246             :  *
     247             :  * @param hDGN Handle from DGNOpen() for file to close.
     248             :  */
     249             : 
     250         110 : void DGNClose(DGNHandle hDGN)
     251             : 
     252             : {
     253         110 :     DGNInfo *psDGN = (DGNInfo *)hDGN;
     254             : 
     255         110 :     VSIFCloseL(psDGN->fp);
     256         110 :     CPLFree(psDGN->element_index);
     257         110 :     CPLFree(psDGN);
     258         110 : }
     259             : 
     260             : /************************************************************************/
     261             : /*                          DGNGetDimension()                           */
     262             : /************************************************************************/
     263             : 
     264             : /**
     265             :  * Return 2D/3D dimension of file.
     266             :  *
     267             :  * Return 2 or 3 depending on the dimension value of the provided file.
     268             :  */
     269             : 
     270          42 : int DGNGetDimension(DGNHandle hDGN)
     271             : 
     272             : {
     273          42 :     DGNInfo *psDGN = (DGNInfo *)hDGN;
     274             : 
     275          42 :     return psDGN->dimension;
     276             : }

Generated by: LCOV version 1.14