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