Coverage Report

Created: 2025-11-15 08:43

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/gdal/ogr/ogrsf_frmts/cad/libopencad/cadtables.cpp
Line
Count
Source
1
/*******************************************************************************
2
 *  Project: libopencad
3
 *  Purpose: OpenSource CAD formats support library
4
 *  Author: Alexandr Borzykh, mush3d at gmail.com
5
 *  Author: Dmitry Baryshnikov, bishop.dev@gmail.com
6
 *  Language: C++
7
 *******************************************************************************
8
 *  The MIT License (MIT)
9
 *
10
 *  Copyright (c) 2016 Alexandr Borzykh
11
 *  Copyright (c) 2016-2018 NextGIS, <info@nextgis.com>
12
 *
13
  * SPDX-License-Identifier: MIT
14
 *******************************************************************************/
15
#include "cadtables.h"
16
#include "opencad_api.h"
17
18
#include <cassert>
19
#include <iostream>
20
#include <memory>
21
#include <set>
22
23
using namespace std;
24
25
CADTables::CADTables()
26
6.66k
{
27
6.66k
}
28
29
void CADTables::AddTable( TableType eType, const CADHandle& hHandle )
30
116k
{
31
116k
    mapTables[eType] = hHandle;
32
116k
}
33
34
int CADTables::ReadTable( CADFile * const pCADFile, CADTables::TableType eType )
35
6.13k
{
36
6.13k
    auto iterAskedTable = mapTables.find( eType );
37
6.13k
    if( iterAskedTable == mapTables.end() )
38
0
        return CADErrorCodes::TABLE_READ_FAILED;
39
40
    // TODO: read different tables
41
6.13k
    switch( eType )
42
6.13k
    {
43
6.13k
        case LayersTable:
44
6.13k
            return ReadLayersTable( pCADFile, iterAskedTable->second.getAsLong() );
45
0
        default:
46
0
            std::cerr << "Unsupported table.";
47
0
            break;
48
6.13k
    }
49
50
0
    return CADErrorCodes::SUCCESS;
51
6.13k
}
52
53
size_t CADTables::GetLayerCount() const
54
13.9k
{
55
13.9k
    return aLayers.size();
56
13.9k
}
57
58
CADLayer& CADTables::GetLayer( size_t iIndex )
59
11.5k
{
60
11.5k
    return aLayers[iIndex];
61
11.5k
}
62
63
CADHandle CADTables::GetTableHandle( enum TableType eType )
64
1.49k
{
65
    // FIXME: need to add try/catch to prevent crashes on not found elem.
66
1.49k
    return mapTables[eType];
67
1.49k
}
68
69
int CADTables::ReadLayersTable( CADFile * const pCADFile, long dLayerControlHandle )
70
6.13k
{
71
    // Reading Layer Control obj, and aLayers.
72
6.13k
    unique_ptr<CADObject> pCADObject( pCADFile->GetObject( dLayerControlHandle ) );
73
74
6.13k
    CADLayerControlObject* spLayerControl =
75
6.13k
            dynamic_cast<CADLayerControlObject *>(pCADObject.get());
76
6.13k
    if( !spLayerControl )
77
2.73k
    {
78
2.73k
        return CADErrorCodes::TABLE_READ_FAILED;
79
2.73k
    }
80
81
795k
    for( size_t i = 0; i < spLayerControl->hLayers.size(); ++i )
82
792k
    {
83
792k
        if( !spLayerControl->hLayers[i].isNull() )
84
383k
        {
85
383k
            CADLayer oCADLayer( pCADFile );
86
87
            // Init CADLayer from CADLayerObject properties
88
383k
            CADObject* pCADLayerObject = pCADFile->GetObject(
89
383k
                        spLayerControl->hLayers[i].getAsLong() );
90
383k
            unique_ptr<CADLayerObject> oCADLayerObj(
91
383k
                    dynamic_cast<CADLayerObject *>( pCADLayerObject ) );
92
93
383k
            if(oCADLayerObj)
94
12.2k
            {
95
12.2k
                oCADLayer.setName( oCADLayerObj->sLayerName );
96
12.2k
                oCADLayer.setFrozen( oCADLayerObj->bFrozen );
97
12.2k
                oCADLayer.setOn( oCADLayerObj->bOn );
98
12.2k
                oCADLayer.setFrozenByDefault( oCADLayerObj->bFrozenInNewVPORT );
99
12.2k
                oCADLayer.setLocked( oCADLayerObj->bLocked );
100
12.2k
                oCADLayer.setLineWeight( oCADLayerObj->dLineWeight );
101
12.2k
                oCADLayer.setColor( oCADLayerObj->dCMColor );
102
12.2k
                oCADLayer.setId( aLayers.size() + 1 );
103
12.2k
                oCADLayer.setHandle( oCADLayerObj->hObjectHandle.getAsLong() );
104
105
12.2k
                aLayers.push_back( std::move(oCADLayer) );
106
12.2k
            }
107
371k
            else
108
371k
            {
109
371k
                delete pCADLayerObject;
110
371k
            }
111
383k
        }
112
792k
    }
113
114
3.39k
    auto iterBlockMS = mapTables.find( BlockRecordModelSpace );
115
3.39k
    if( iterBlockMS == mapTables.end() )
116
0
        return CADErrorCodes::TABLE_READ_FAILED;
117
118
3.39k
    CADObject* pCADBlockObject = pCADFile->GetObject(
119
3.39k
                iterBlockMS->second.getAsLong() );
120
3.39k
    unique_ptr<CADBlockHeaderObject> spModelSpace(
121
3.39k
            dynamic_cast<CADBlockHeaderObject *>( pCADBlockObject ) );
122
3.39k
    if(!spModelSpace)
123
1.90k
    {
124
1.90k
        delete pCADBlockObject;
125
1.90k
        return CADErrorCodes::TABLE_READ_FAILED;
126
1.90k
    }
127
128
1.49k
    if(spModelSpace->hEntities.size() < 2)
129
1
    {
130
1
        return CADErrorCodes::TABLE_READ_FAILED;
131
1
    }
132
133
1.49k
    auto dCurrentEntHandle = spModelSpace->hEntities[0].getAsLong();
134
1.49k
    auto dLastEntHandle    = spModelSpace->hEntities[1].getAsLong();
135
    // To avoid infinite loops
136
1.49k
    std::set<long> oVisitedHandles;
137
3.89k
    while( dCurrentEntHandle != 0 &&
138
3.29k
           oVisitedHandles.find(dCurrentEntHandle) == oVisitedHandles.end() )
139
3.24k
    {
140
3.24k
        oVisitedHandles.insert(dCurrentEntHandle);
141
142
3.24k
        CADObject* pCADEntityObject = pCADFile->GetObject( dCurrentEntHandle, true );
143
3.24k
        unique_ptr<CADEntityObject> spEntityObj(
144
3.24k
                    dynamic_cast<CADEntityObject *>( pCADEntityObject ) );
145
146
3.24k
        if( !spEntityObj )
147
687
        {
148
687
            delete pCADEntityObject;
149
687
            DebugMsg( "Entity object is null\n" );
150
687
            break;
151
687
        }
152
2.55k
        else if ( dCurrentEntHandle == dLastEntHandle )
153
154
        {
154
154
            FillLayer( spEntityObj.get() );
155
154
            break;
156
154
        }
157
158
2.40k
        FillLayer( spEntityObj.get() );
159
160
2.40k
        if( spEntityObj->stCed.bNoLinks )
161
1.27k
        {
162
1.27k
            ++dCurrentEntHandle;
163
1.27k
        }
164
1.12k
        else
165
1.12k
        {
166
1.12k
            dCurrentEntHandle = spEntityObj->stChed.hNextEntity.getAsLong( spEntityObj->stCed.hObjectHandle );
167
1.12k
        }
168
2.40k
    }
169
170
1.49k
    DebugMsg( "Read aLayers using LayerControl object count: %d\n",
171
1.49k
              static_cast<int>(aLayers.size()) );
172
173
1.49k
    return CADErrorCodes::SUCCESS;
174
1.49k
}
175
176
void CADTables::FillLayer( const CADEntityObject * pEntityObject )
177
2.55k
{
178
2.55k
    if(nullptr == pEntityObject)
179
0
    {
180
0
        return;
181
0
    }
182
183
2.55k
    for( CADLayer& oLayer : aLayers )
184
8.76k
    {
185
8.76k
        if( pEntityObject->stChed.hLayer.getAsLong(
186
8.76k
                    pEntityObject->stCed.hObjectHandle ) == oLayer.getHandle() )
187
2.14k
        {
188
2.14k
            DebugMsg( "Object with type: %s is attached to layer named: %s\n",
189
2.14k
                      getNameByType( pEntityObject->getType() ).c_str(),
190
2.14k
                      oLayer.getName().c_str() );
191
192
2.14k
            oLayer.addHandle( pEntityObject->stCed.hObjectHandle.getAsLong(),
193
2.14k
                              pEntityObject->getType() );
194
2.14k
            break;
195
2.14k
        }
196
8.76k
    }
197
2.55k
}