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