1 /******************************************************************************
2 *
3 * Project: DWG Translator
4 * Purpose: Implements OGRDWGDataSource class
5 * Author: Frank Warmerdam, warmerdam@pobox.com
6 *
7 ******************************************************************************
8 * Copyright (c) 2011, Frank Warmerdam <warmerdam@pobox.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 "ogr_dwg.h"
30 #include "cpl_conv.h"
31 #include "cpl_string.h"
32
33 CPL_CVSID("$Id: ogrdwgdatasource.cpp 7e07230bbff24eb333608de4dbd460b7312839d0 2017-12-11 19:08:47Z Even Rouault $")
34
35 /************************************************************************/
36 /* OGRDWGDataSource() */
37 /************************************************************************/
38
OGRDWGDataSource()39 OGRDWGDataSource::OGRDWGDataSource() :
40 fp(nullptr),
41 iEntitiesSectionOffset(0),
42 bInlineBlocks(FALSE),
43 poServices(nullptr),
44 poDb(static_cast<const OdRxObject*>(nullptr))
45
46 {
47 }
48
49 /************************************************************************/
50 /* ~OGRDWGDataSource() */
51 /************************************************************************/
52
~OGRDWGDataSource()53 OGRDWGDataSource::~OGRDWGDataSource()
54
55 {
56 /* -------------------------------------------------------------------- */
57 /* Destroy layers. */
58 /* -------------------------------------------------------------------- */
59 while( !apoLayers.empty() )
60 {
61 delete apoLayers.back();
62 apoLayers.pop_back();
63 }
64 }
65
66 /************************************************************************/
67 /* TestCapability() */
68 /************************************************************************/
69
TestCapability(const char *)70 int OGRDWGDataSource::TestCapability( const char * /*pszCap*/ )
71
72 {
73 return FALSE;
74 }
75
76 /************************************************************************/
77 /* GetLayer() */
78 /************************************************************************/
79
GetLayer(int iLayer)80 OGRLayer *OGRDWGDataSource::GetLayer( int iLayer )
81
82 {
83 if( iLayer < 0 || iLayer >= (int) apoLayers.size() )
84 return nullptr;
85 else
86 return apoLayers[iLayer];
87 }
88
89 /************************************************************************/
90 /* Open() */
91 /************************************************************************/
92
Open(OGRDWGServices * poServicesIn,const char * pszFilename,int)93 int OGRDWGDataSource::Open( OGRDWGServices *poServicesIn,
94 const char * pszFilename, int /*bHeaderOnly*/ )
95
96 {
97 poServices = poServicesIn;
98
99 osEncoding = CPL_ENC_ISO8859_1;
100
101 m_osName = pszFilename;
102
103 bInlineBlocks = CPLTestBool(
104 CPLGetConfigOption( "DWG_INLINE_BLOCKS", "TRUE" ) );
105
106 /* -------------------------------------------------------------------- */
107 /* Open the file. */
108 /* -------------------------------------------------------------------- */
109 try
110 {
111 OdString f(pszFilename);
112 poDb = poServices->readFile(f.c_str(), true, false, Oda::kShareDenyNo);
113 }
114 catch( OdError& e )
115 {
116 CPLError( CE_Failure, CPLE_AppDefined,
117 "%s",
118 (const char *) poServices->getErrorDescription(e.code()) );
119 }
120 catch( ... )
121 {
122 CPLError( CE_Failure, CPLE_AppDefined,
123 "DWG readFile(%s) failed with generic exception.",
124 pszFilename );
125 }
126
127 if( poDb.isNull() )
128 return FALSE;
129
130 /* -------------------------------------------------------------------- */
131 /* Process the header, picking up a few useful pieces of */
132 /* information. */
133 /* -------------------------------------------------------------------- */
134 ReadHeaderSection();
135 ReadLineTypeDefinitions();
136 ReadLayerDefinitions();
137
138 /* -------------------------------------------------------------------- */
139 /* Create a blocks layer if we are not in inlining mode. */
140 /* -------------------------------------------------------------------- */
141 if( !bInlineBlocks )
142 apoLayers.push_back( new OGRDWGBlocksLayer( this ) );
143
144 /* -------------------------------------------------------------------- */
145 /* Create out layer object - we will need it when interpreting */
146 /* blocks. */
147 /* -------------------------------------------------------------------- */
148 apoLayers.push_back( new OGRDWGLayer( this ) );
149
150 ReadBlocksSection();
151
152 return TRUE;
153 }
154
155 /************************************************************************/
156 /* ReadLayerDefinitions() */
157 /************************************************************************/
158
ReadLayerDefinitions()159 void OGRDWGDataSource::ReadLayerDefinitions()
160
161 {
162 OdDbLayerTablePtr poLT = poDb->getLayerTableId().safeOpenObject();
163 OdDbSymbolTableIteratorPtr poIter = poLT->newIterator();
164
165 for (poIter->start(); !poIter->done(); poIter->step())
166 {
167 CPLString osValue;
168 OdDbLayerTableRecordPtr poLD = poIter->getRecordId().safeOpenObject();
169 std::map<CPLString,CPLString> oLayerProperties;
170
171 CPLString osLayerName = ACTextUnescape(poLD->getName(),GetEncoding(), false);
172
173 oLayerProperties["Exists"] = "1";
174
175 OdDbLinetypeTableRecordPtr poLinetypeTableRecord = poLD->linetypeObjectId().safeOpenObject();
176 oLayerProperties["Linetype"] =
177 ACTextUnescape(poLinetypeTableRecord->getName(),GetEncoding(), false);
178
179 osValue.Printf( "%d", poLD->colorIndex() );
180 oLayerProperties["Color"] = osValue;
181
182 osValue.Printf( "%d", (int) poLD->lineWeight() );
183 oLayerProperties["LineWeight"] = osValue;
184
185 if( poLD->isFrozen() || poLD->isHidden() || poLD->isOff() )
186 oLayerProperties["Hidden"] = "1";
187 else
188 oLayerProperties["Hidden"] = "0";
189
190 oLayerTable[osLayerName] = oLayerProperties;
191 }
192
193 CPLDebug( "DWG", "Read %d layer definitions.",
194 (int) oLayerTable.size() );
195 }
196
197 /************************************************************************/
198 /* LookupLayerProperty() */
199 /************************************************************************/
200
LookupLayerProperty(const char * pszLayer,const char * pszProperty)201 const char *OGRDWGDataSource::LookupLayerProperty( const char *pszLayer,
202 const char *pszProperty )
203
204 {
205 if( pszLayer == nullptr )
206 return nullptr;
207
208 try {
209 return (oLayerTable[pszLayer])[pszProperty];
210 } catch( ... ) {
211 return nullptr;
212 }
213 }
214
215 /************************************************************************/
216 /* ReadLineTypeDefinitions() */
217 /************************************************************************/
218
ReadLineTypeDefinitions()219 void OGRDWGDataSource::ReadLineTypeDefinitions()
220
221 {
222 OdDbLinetypeTablePtr poTable = poDb->getLinetypeTableId().safeOpenObject();
223 OdDbSymbolTableIteratorPtr poIter = poTable->newIterator();
224
225 for (poIter->start(); !poIter->done(); poIter->step())
226 {
227 CPLString osLineTypeName;
228 CPLString osLineTypeDef;
229 OdDbLinetypeTableRecordPtr poLT = poIter->getRecordId().safeOpenObject();
230
231 osLineTypeName = ACTextUnescape(poLT->getName(),GetEncoding(),false);
232
233 if (poLT->numDashes())
234 {
235 for (int i=0; i < poLT->numDashes(); i++)
236 {
237 if( i > 0 )
238 osLineTypeDef += " ";
239
240 CPLString osValue;
241 osValue.Printf( "%g", fabs(poLT->dashLengthAt(i)) );
242 osLineTypeDef += osValue;
243
244 osLineTypeDef += "g";
245 }
246
247 oLineTypeTable[osLineTypeName] = osLineTypeDef;
248 CPLDebug( "DWG", "LineType '%s' = '%s'",
249 osLineTypeName.c_str(),
250 osLineTypeDef.c_str() );
251 }
252 }
253 }
254
255 /************************************************************************/
256 /* LookupLineType() */
257 /************************************************************************/
258
LookupLineType(const char * pszName)259 const char *OGRDWGDataSource::LookupLineType( const char *pszName )
260
261 {
262 if( oLineTypeTable.count(pszName) > 0 )
263 return oLineTypeTable[pszName];
264 else
265 return nullptr;
266 }
267
268 /************************************************************************/
269 /* ReadHeaderSection() */
270 /************************************************************************/
271
ReadHeaderSection()272 void OGRDWGDataSource::ReadHeaderSection()
273
274 {
275 // using: DWGCODEPAGE, DIMTXT, LUPREC
276
277 CPLString osValue;
278
279 osValue.Printf( "%d", poDb->getLUPREC() );
280 oHeaderVariables["$LUPREC"] = osValue;
281
282 osValue.Printf( "%g", poDb->dimtxt() );
283 oHeaderVariables["$DIMTXT"] = osValue;
284
285 CPLDebug( "DWG", "Read %d header variables.",
286 (int) oHeaderVariables.size() );
287
288 /* -------------------------------------------------------------------- */
289 /* Decide on what CPLRecode() name to use for the files */
290 /* encoding or allow the encoding to be overridden. */
291 /* -------------------------------------------------------------------- */
292 CPLString osCodepage = GetVariable( "$DWGCODEPAGE", "ANSI_1252" );
293
294 // not strictly accurate but works even without iconv.
295 if( osCodepage == "ANSI_1252" )
296 osEncoding = CPL_ENC_ISO8859_1;
297 else if( STARTS_WITH_CI(osCodepage, "ANSI_") )
298 {
299 osEncoding = "CP";
300 osEncoding += osCodepage + 5;
301 }
302 else
303 {
304 // fallback to the default
305 osEncoding = CPL_ENC_ISO8859_1;
306 }
307
308 if( CPLGetConfigOption( "DWG_ENCODING", nullptr ) != nullptr )
309 osEncoding = CPLGetConfigOption( "DWG_ENCODING", nullptr );
310
311 if( osEncoding != CPL_ENC_ISO8859_1 )
312 CPLDebug( "DWG", "Treating DWG as encoding '%s', $DWGCODEPAGE='%s'",
313 osEncoding.c_str(), osCodepage.c_str() );
314 }
315
316 /************************************************************************/
317 /* GetVariable() */
318 /* */
319 /* Fetch a variable that came from the HEADER section. */
320 /************************************************************************/
321
GetVariable(const char * pszName,const char * pszDefault)322 const char *OGRDWGDataSource::GetVariable( const char *pszName,
323 const char *pszDefault )
324
325 {
326 if( oHeaderVariables.count(pszName) == 0 )
327 return pszDefault;
328 else
329 return oHeaderVariables[pszName];
330 }
331
332 /************************************************************************/
333 /* AddStandardFields() */
334 /************************************************************************/
335
AddStandardFields(OGRFeatureDefn * poFeatureDefn)336 void OGRDWGDataSource::AddStandardFields( OGRFeatureDefn *poFeatureDefn )
337
338 {
339 OGRFieldDefn oLayerField( "Layer", OFTString );
340 poFeatureDefn->AddFieldDefn( &oLayerField );
341
342 OGRFieldDefn oClassField( "SubClasses", OFTString );
343 poFeatureDefn->AddFieldDefn( &oClassField );
344
345 OGRFieldDefn oExtendedField( "ExtendedEntity", OFTString );
346 poFeatureDefn->AddFieldDefn( &oExtendedField );
347
348 OGRFieldDefn oLinetypeField( "Linetype", OFTString );
349 poFeatureDefn->AddFieldDefn( &oLinetypeField );
350
351 OGRFieldDefn oEntityHandleField( "EntityHandle", OFTString );
352 poFeatureDefn->AddFieldDefn( &oEntityHandleField );
353
354 OGRFieldDefn oTextField( "Text", OFTString );
355 poFeatureDefn->AddFieldDefn( &oTextField );
356
357 if( !bInlineBlocks )
358 {
359 OGRFieldDefn oBlockNameField( "BlockName", OFTString );
360 poFeatureDefn->AddFieldDefn( &oBlockNameField );
361 }
362 }
363