1 /******************************************************************************
2 * $Id: ogrdxfdatasource.cpp 27745 2014-09-27 16:38:57Z goatbar $
3 *
4 * Project: DXF Translator
5 * Purpose: Implements OGRDXFDataSource class
6 * Author: Frank Warmerdam, warmerdam@pobox.com
7 *
8 ******************************************************************************
9 * Copyright (c) 2009, Frank Warmerdam <warmerdam@pobox.com>
10 * Copyright (c) 2010-2013, Even Rouault <even dot rouault at mines-paris dot org>
11 *
12 * Permission is hereby granted, free of charge, to any person obtaining a
13 * copy of this software and associated documentation files (the "Software"),
14 * to deal in the Software without restriction, including without limitation
15 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
16 * and/or sell copies of the Software, and to permit persons to whom the
17 * Software is furnished to do so, subject to the following conditions:
18 *
19 * The above copyright notice and this permission notice shall be included
20 * in all copies or substantial portions of the Software.
21 *
22 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
23 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
25 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
27 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
28 * DEALINGS IN THE SOFTWARE.
29 ****************************************************************************/
30
31 #include "ogr_dxf.h"
32 #include "cpl_conv.h"
33 #include "cpl_string.h"
34
35 CPL_CVSID("$Id: ogrdxfdatasource.cpp 27745 2014-09-27 16:38:57Z goatbar $");
36
37 /************************************************************************/
38 /* OGRDXFDataSource() */
39 /************************************************************************/
40
OGRDXFDataSource()41 OGRDXFDataSource::OGRDXFDataSource()
42
43 {
44 fp = NULL;
45 }
46
47 /************************************************************************/
48 /* ~OGRDXFDataSource() */
49 /************************************************************************/
50
~OGRDXFDataSource()51 OGRDXFDataSource::~OGRDXFDataSource()
52
53 {
54 /* -------------------------------------------------------------------- */
55 /* Destroy layers. */
56 /* -------------------------------------------------------------------- */
57 while( apoLayers.size() > 0 )
58 {
59 delete apoLayers.back();
60 apoLayers.pop_back();
61 }
62
63 /* -------------------------------------------------------------------- */
64 /* Close file. */
65 /* -------------------------------------------------------------------- */
66 if( fp != NULL )
67 {
68 VSIFCloseL( fp );
69 fp = NULL;
70 }
71 }
72
73 /************************************************************************/
74 /* TestCapability() */
75 /************************************************************************/
76
TestCapability(CPL_UNUSED const char * pszCap)77 int OGRDXFDataSource::TestCapability( CPL_UNUSED const char * pszCap )
78 {
79 return FALSE;
80 }
81
82 /************************************************************************/
83 /* GetLayer() */
84 /************************************************************************/
85
86
GetLayer(int iLayer)87 OGRLayer *OGRDXFDataSource::GetLayer( int iLayer )
88
89 {
90 if( iLayer < 0 || iLayer >= (int) apoLayers.size() )
91 return NULL;
92 else
93 return apoLayers[iLayer];
94 }
95
96 /************************************************************************/
97 /* Open() */
98 /************************************************************************/
99
Open(const char * pszFilename,int bHeaderOnly)100 int OGRDXFDataSource::Open( const char * pszFilename, int bHeaderOnly )
101
102 {
103 osEncoding = CPL_ENC_ISO8859_1;
104
105 osName = pszFilename;
106
107 bInlineBlocks = CSLTestBoolean(
108 CPLGetConfigOption( "DXF_INLINE_BLOCKS", "TRUE" ) );
109
110 if( CSLTestBoolean(
111 CPLGetConfigOption( "DXF_HEADER_ONLY", "FALSE" ) ) )
112 bHeaderOnly = TRUE;
113
114 /* -------------------------------------------------------------------- */
115 /* Open the file. */
116 /* -------------------------------------------------------------------- */
117 fp = VSIFOpenL( pszFilename, "r" );
118 if( fp == NULL )
119 return FALSE;
120
121 oReader.Initialize( fp );
122
123 /* -------------------------------------------------------------------- */
124 /* Confirm we have a header section. */
125 /* -------------------------------------------------------------------- */
126 char szLineBuf[257];
127 int nCode;
128 int bEntitiesOnly = FALSE;
129
130 if( ReadValue( szLineBuf ) != 0 || !EQUAL(szLineBuf,"SECTION") )
131 return FALSE;
132
133 if( ReadValue( szLineBuf ) != 2
134 || (!EQUAL(szLineBuf,"HEADER") && !EQUAL(szLineBuf,"ENTITIES") && !EQUAL(szLineBuf,"TABLES")) )
135 return FALSE;
136
137 if( EQUAL(szLineBuf,"ENTITIES") )
138 bEntitiesOnly = TRUE;
139
140 /* Some files might have no header but begin directly with a TABLES section */
141 else if( EQUAL(szLineBuf,"TABLES") )
142 {
143 if( CPLGetConfigOption( "DXF_ENCODING", NULL ) != NULL )
144 osEncoding = CPLGetConfigOption( "DXF_ENCODING", NULL );
145
146 ReadTablesSection();
147 ReadValue(szLineBuf);
148 }
149
150 /* -------------------------------------------------------------------- */
151 /* Process the header, picking up a few useful pieces of */
152 /* information. */
153 /* -------------------------------------------------------------------- */
154 else /* if( EQUAL(szLineBuf,"HEADER") ) */
155 {
156 ReadHeaderSection();
157 ReadValue(szLineBuf);
158
159 /* -------------------------------------------------------------------- */
160 /* Process the CLASSES section, if present. */
161 /* -------------------------------------------------------------------- */
162 if( EQUAL(szLineBuf,"ENDSEC") )
163 ReadValue(szLineBuf);
164
165 if( EQUAL(szLineBuf,"SECTION") )
166 ReadValue(szLineBuf);
167
168 if( EQUAL(szLineBuf,"CLASSES") )
169 {
170 while( (nCode = ReadValue( szLineBuf,sizeof(szLineBuf) )) > -1
171 && !EQUAL(szLineBuf,"ENDSEC") )
172 {
173 //printf("C:%d/%s\n", nCode, szLineBuf );
174 }
175 }
176
177 /* -------------------------------------------------------------------- */
178 /* Process the TABLES section, if present. */
179 /* -------------------------------------------------------------------- */
180 if( EQUAL(szLineBuf,"ENDSEC") )
181 ReadValue(szLineBuf);
182
183 if( EQUAL(szLineBuf,"SECTION") )
184 ReadValue(szLineBuf);
185
186 if( EQUAL(szLineBuf,"TABLES") )
187 {
188 ReadTablesSection();
189 ReadValue(szLineBuf);
190 }
191 }
192
193 /* -------------------------------------------------------------------- */
194 /* Create a blocks layer if we are not in inlining mode. */
195 /* -------------------------------------------------------------------- */
196 if( !bInlineBlocks )
197 apoLayers.push_back( new OGRDXFBlocksLayer( this ) );
198
199 /* -------------------------------------------------------------------- */
200 /* Create out layer object - we will need it when interpreting */
201 /* blocks. */
202 /* -------------------------------------------------------------------- */
203 apoLayers.push_back( new OGRDXFLayer( this ) );
204
205 /* -------------------------------------------------------------------- */
206 /* Process the BLOCKS section if present. */
207 /* -------------------------------------------------------------------- */
208 if( !bEntitiesOnly )
209 {
210 if( EQUAL(szLineBuf,"ENDSEC") )
211 ReadValue(szLineBuf);
212
213 if( EQUAL(szLineBuf,"SECTION") )
214 ReadValue(szLineBuf);
215
216 if( EQUAL(szLineBuf,"BLOCKS") )
217 {
218 ReadBlocksSection();
219 ReadValue(szLineBuf);
220 }
221 }
222
223 if( bHeaderOnly )
224 return TRUE;
225
226 /* -------------------------------------------------------------------- */
227 /* Now we are at the entities section, hopefully. Confirm. */
228 /* -------------------------------------------------------------------- */
229 if( EQUAL(szLineBuf,"SECTION") )
230 ReadValue(szLineBuf);
231
232 if( !EQUAL(szLineBuf,"ENTITIES") )
233 return FALSE;
234
235 iEntitiesSectionOffset = oReader.iSrcBufferFileOffset + oReader.iSrcBufferOffset;
236 apoLayers[0]->ResetReading();
237
238 return TRUE;
239 }
240
241 /************************************************************************/
242 /* ReadTablesSection() */
243 /************************************************************************/
244
ReadTablesSection()245 void OGRDXFDataSource::ReadTablesSection()
246
247 {
248 char szLineBuf[257];
249 int nCode;
250
251 while( (nCode = ReadValue( szLineBuf, sizeof(szLineBuf) )) > -1
252 && !EQUAL(szLineBuf,"ENDSEC") )
253 {
254 // We are only interested in extracting tables.
255 if( nCode != 0 || !EQUAL(szLineBuf,"TABLE") )
256 continue;
257
258 // Currently we are only interested in the LAYER table.
259 nCode = ReadValue( szLineBuf, sizeof(szLineBuf) );
260
261 if( nCode != 2 )
262 continue;
263
264 //CPLDebug( "DXF", "Found table %s.", szLineBuf );
265
266 while( (nCode = ReadValue( szLineBuf, sizeof(szLineBuf) )) > -1
267 && !EQUAL(szLineBuf,"ENDTAB") )
268 {
269 if( nCode == 0 && EQUAL(szLineBuf,"LAYER") )
270 ReadLayerDefinition();
271 if( nCode == 0 && EQUAL(szLineBuf,"LTYPE") )
272 ReadLineTypeDefinition();
273 }
274 }
275
276 CPLDebug( "DXF", "Read %d layer definitions.", (int) oLayerTable.size() );
277 }
278
279 /************************************************************************/
280 /* ReadLayerDefinition() */
281 /************************************************************************/
282
ReadLayerDefinition()283 void OGRDXFDataSource::ReadLayerDefinition()
284
285 {
286 char szLineBuf[257];
287 int nCode;
288 std::map<CPLString,CPLString> oLayerProperties;
289 CPLString osLayerName = "";
290
291 oLayerProperties["Hidden"] = "0";
292
293 while( (nCode = ReadValue( szLineBuf, sizeof(szLineBuf) )) > 0 )
294 {
295 switch( nCode )
296 {
297 case 2:
298 osLayerName = ACTextUnescape(szLineBuf,GetEncoding());
299 oLayerProperties["Exists"] = "1";
300 break;
301
302 case 6:
303 oLayerProperties["Linetype"] = ACTextUnescape(szLineBuf,
304 GetEncoding());
305 break;
306
307 case 62:
308 oLayerProperties["Color"] = szLineBuf;
309
310 if( atoi(szLineBuf) < 0 ) // Is layer off?
311 oLayerProperties["Hidden"] = "1";
312 break;
313
314 case 70:
315 oLayerProperties["Flags"] = szLineBuf;
316 if( atoi(szLineBuf) & 0x01 ) // Is layer frozen?
317 oLayerProperties["Hidden"] = "1";
318 break;
319
320 case 370:
321 case 39:
322 oLayerProperties["LineWeight"] = szLineBuf;
323 break;
324
325 default:
326 break;
327 }
328 }
329
330 if( oLayerProperties.size() > 0 )
331 oLayerTable[osLayerName] = oLayerProperties;
332
333 if( nCode == 0 )
334 UnreadValue();
335 }
336
337 /************************************************************************/
338 /* LookupLayerProperty() */
339 /************************************************************************/
340
LookupLayerProperty(const char * pszLayer,const char * pszProperty)341 const char *OGRDXFDataSource::LookupLayerProperty( const char *pszLayer,
342 const char *pszProperty )
343
344 {
345 if( pszLayer == NULL )
346 return NULL;
347
348 try {
349 return (oLayerTable[pszLayer])[pszProperty];
350 } catch( ... ) {
351 return NULL;
352 }
353 }
354
355 /************************************************************************/
356 /* ReadLineTypeDefinition() */
357 /************************************************************************/
358
ReadLineTypeDefinition()359 void OGRDXFDataSource::ReadLineTypeDefinition()
360
361 {
362 char szLineBuf[257];
363 int nCode;
364 CPLString osLineTypeName;
365 CPLString osLineTypeDef;
366
367 while( (nCode = ReadValue( szLineBuf, sizeof(szLineBuf) )) > 0 )
368 {
369 switch( nCode )
370 {
371 case 2:
372 osLineTypeName = ACTextUnescape(szLineBuf,GetEncoding());
373 break;
374
375 case 49:
376 {
377 if( osLineTypeDef != "" )
378 osLineTypeDef += " ";
379
380 if( szLineBuf[0] == '-' )
381 osLineTypeDef += szLineBuf+1;
382 else
383 osLineTypeDef += szLineBuf;
384
385 osLineTypeDef += "g";
386 }
387 break;
388
389 default:
390 break;
391 }
392 }
393
394 if( osLineTypeDef != "" )
395 oLineTypeTable[osLineTypeName] = osLineTypeDef;
396
397 if( nCode == 0 )
398 UnreadValue();
399 }
400
401 /************************************************************************/
402 /* LookupLineType() */
403 /************************************************************************/
404
LookupLineType(const char * pszName)405 const char *OGRDXFDataSource::LookupLineType( const char *pszName )
406
407 {
408 if( oLineTypeTable.count(pszName) > 0 )
409 return oLineTypeTable[pszName];
410 else
411 return NULL;
412 }
413
414 /************************************************************************/
415 /* ReadHeaderSection() */
416 /************************************************************************/
417
ReadHeaderSection()418 void OGRDXFDataSource::ReadHeaderSection()
419
420 {
421 char szLineBuf[257];
422 int nCode;
423
424 while( (nCode = ReadValue( szLineBuf, sizeof(szLineBuf) )) > -1
425 && !EQUAL(szLineBuf,"ENDSEC") )
426 {
427 if( nCode != 9 )
428 continue;
429
430 CPLString osName = szLineBuf;
431
432 ReadValue( szLineBuf, sizeof(szLineBuf) );
433
434 CPLString osValue = szLineBuf;
435
436 oHeaderVariables[osName] = osValue;
437 }
438
439 if (nCode != -1)
440 {
441 nCode = ReadValue( szLineBuf, sizeof(szLineBuf) );
442 UnreadValue();
443 }
444
445 /* Unusual DXF files produced by dxflib */
446 /* such as http://www.ribbonsoft.com/library/architecture/plants/decd5.dxf */
447 /* where there is a spurious ENDSEC in the middle of the header variables */
448 if (nCode == 9 && EQUALN(szLineBuf,"$", 1) )
449 {
450 while( (nCode = ReadValue( szLineBuf, sizeof(szLineBuf) )) > -1
451 && !EQUAL(szLineBuf,"ENDSEC") )
452 {
453 if( nCode != 9 )
454 continue;
455
456 CPLString osName = szLineBuf;
457
458 ReadValue( szLineBuf, sizeof(szLineBuf) );
459
460 CPLString osValue = szLineBuf;
461
462 oHeaderVariables[osName] = osValue;
463 }
464 }
465
466 CPLDebug( "DXF", "Read %d header variables.",
467 (int) oHeaderVariables.size() );
468
469 /* -------------------------------------------------------------------- */
470 /* Decide on what CPLRecode() name to use for the files */
471 /* encoding or allow the encoding to be overridden. */
472 /* -------------------------------------------------------------------- */
473 CPLString osCodepage = GetVariable( "$DWGCODEPAGE", "ANSI_1252" );
474
475 // not strictly accurate but works even without iconv.
476 if( osCodepage == "ANSI_1252" )
477 osEncoding = CPL_ENC_ISO8859_1;
478 else if( EQUALN(osCodepage,"ANSI_",5) )
479 {
480 osEncoding = "CP";
481 osEncoding += osCodepage + 5;
482 }
483 else
484 {
485 // fallback to the default
486 osEncoding = CPL_ENC_ISO8859_1;
487 }
488
489 if( CPLGetConfigOption( "DXF_ENCODING", NULL ) != NULL )
490 osEncoding = CPLGetConfigOption( "DXF_ENCODING", NULL );
491
492 if( osEncoding != CPL_ENC_ISO8859_1 )
493 CPLDebug( "DXF", "Treating DXF as encoding '%s', $DWGCODEPAGE='%s'",
494 osEncoding.c_str(), osCodepage.c_str() );
495 }
496
497 /************************************************************************/
498 /* GetVariable() */
499 /* */
500 /* Fetch a variable that came from the HEADER section. */
501 /************************************************************************/
502
GetVariable(const char * pszName,const char * pszDefault)503 const char *OGRDXFDataSource::GetVariable( const char *pszName,
504 const char *pszDefault )
505
506 {
507 if( oHeaderVariables.count(pszName) == 0 )
508 return pszDefault;
509 else
510 return oHeaderVariables[pszName];
511 }
512
513 /************************************************************************/
514 /* AddStandardFields() */
515 /************************************************************************/
516
AddStandardFields(OGRFeatureDefn * poFeatureDefn)517 void OGRDXFDataSource::AddStandardFields( OGRFeatureDefn *poFeatureDefn )
518
519 {
520 OGRFieldDefn oLayerField( "Layer", OFTString );
521 poFeatureDefn->AddFieldDefn( &oLayerField );
522
523 OGRFieldDefn oClassField( "SubClasses", OFTString );
524 poFeatureDefn->AddFieldDefn( &oClassField );
525
526 OGRFieldDefn oExtendedField( "ExtendedEntity", OFTString );
527 poFeatureDefn->AddFieldDefn( &oExtendedField );
528
529 OGRFieldDefn oLinetypeField( "Linetype", OFTString );
530 poFeatureDefn->AddFieldDefn( &oLinetypeField );
531
532 OGRFieldDefn oEntityHandleField( "EntityHandle", OFTString );
533 poFeatureDefn->AddFieldDefn( &oEntityHandleField );
534
535 OGRFieldDefn oTextField( "Text", OFTString );
536 poFeatureDefn->AddFieldDefn( &oTextField );
537
538 if( !bInlineBlocks )
539 {
540 OGRFieldDefn oTextField( "BlockName", OFTString );
541 poFeatureDefn->AddFieldDefn( &oTextField );
542 }
543 }
544