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