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 190 : OGRDXFDataSource::OGRDXFDataSource()
41 :
42 : {
43 190 : fp = NULL;
44 190 : }
45 :
46 : /************************************************************************/
47 : /* ~OGRDXFDataSource() */
48 : /************************************************************************/
49 :
50 190 : OGRDXFDataSource::~OGRDXFDataSource()
51 :
52 : {
53 : /* -------------------------------------------------------------------- */
54 : /* Destroy layers. */
55 : /* -------------------------------------------------------------------- */
56 404 : while( apoLayers.size() > 0 )
57 : {
58 24 : delete apoLayers.back();
59 24 : apoLayers.pop_back();
60 : }
61 :
62 : /* -------------------------------------------------------------------- */
63 : /* Close file. */
64 : /* -------------------------------------------------------------------- */
65 190 : if( fp != NULL )
66 : {
67 23 : VSIFCloseL( fp );
68 23 : fp = NULL;
69 : }
70 190 : }
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 190 : int OGRDXFDataSource::Open( const char * pszFilename, int bHeaderOnly )
101 :
102 : {
103 190 : if( !EQUAL(CPLGetExtension(pszFilename),"dxf") )
104 167 : 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 : UnreadValue();
327 20 : }
328 :
329 : /************************************************************************/
330 : /* LookupLayerProperty() */
331 : /************************************************************************/
332 :
333 263 : const char *OGRDXFDataSource::LookupLayerProperty( const char *pszLayer,
334 : const char *pszProperty )
335 :
336 : {
337 263 : if( pszLayer == NULL )
338 0 : return NULL;
339 :
340 : try {
341 263 : return (oLayerTable[pszLayer])[pszProperty];
342 0 : } catch( ... ) {
343 0 : return NULL;
344 : }
345 : }
346 :
347 : /************************************************************************/
348 : /* ReadLineTypeDefinition() */
349 : /************************************************************************/
350 :
351 113 : void OGRDXFDataSource::ReadLineTypeDefinition()
352 :
353 : {
354 : char szLineBuf[257];
355 : int nCode;
356 113 : CPLString osLineTypeName;
357 113 : CPLString osLineTypeDef;
358 :
359 1749 : while( (nCode = ReadValue( szLineBuf, sizeof(szLineBuf) )) > 0 )
360 : {
361 1523 : switch( nCode )
362 : {
363 : case 2:
364 113 : osLineTypeName = ACTextUnescape(szLineBuf,GetEncoding());
365 113 : break;
366 :
367 : case 49:
368 : {
369 232 : if( osLineTypeDef != "" )
370 170 : osLineTypeDef += " ";
371 :
372 232 : if( szLineBuf[0] == '-' )
373 116 : osLineTypeDef += szLineBuf+1;
374 : else
375 116 : osLineTypeDef += szLineBuf;
376 :
377 232 : osLineTypeDef += "g";
378 : }
379 : break;
380 :
381 : default:
382 : break;
383 : }
384 : }
385 :
386 113 : if( osLineTypeDef != "" )
387 62 : oLineTypeTable[osLineTypeName] = osLineTypeDef;
388 :
389 113 : UnreadValue();
390 113 : }
391 :
392 : /************************************************************************/
393 : /* LookupLineType() */
394 : /************************************************************************/
395 :
396 87 : const char *OGRDXFDataSource::LookupLineType( const char *pszName )
397 :
398 : {
399 87 : if( oLineTypeTable.count(pszName) > 0 )
400 4 : return oLineTypeTable[pszName];
401 : else
402 83 : return NULL;
403 : }
404 :
405 : /************************************************************************/
406 : /* ReadHeaderSection() */
407 : /************************************************************************/
408 :
409 18 : void OGRDXFDataSource::ReadHeaderSection()
410 :
411 : {
412 : char szLineBuf[257];
413 : int nCode;
414 :
415 3242 : while( (nCode = ReadValue( szLineBuf, sizeof(szLineBuf) )) > -1
416 : && !EQUAL(szLineBuf,"ENDSEC") )
417 : {
418 4010 : if( nCode != 9 )
419 786 : continue;
420 :
421 3224 : CPLString osName = szLineBuf;
422 :
423 3224 : ReadValue( szLineBuf, sizeof(szLineBuf) );
424 :
425 3224 : CPLString osValue = szLineBuf;
426 :
427 3224 : oHeaderVariables[osName] = osValue;
428 : }
429 :
430 18 : if (nCode != -1)
431 : {
432 18 : nCode = ReadValue( szLineBuf, sizeof(szLineBuf) );
433 18 : 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 18 : 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 18 : (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 18 : CPLString osCodepage = GetVariable( "$DWGCODEPAGE", "ANSI_1252" );
465 :
466 : // not strictly accurate but works even without iconv.
467 18 : if( osCodepage == "ANSI_1252" )
468 18 : 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 18 : if( CPLGetConfigOption( "DXF_ENCODING", NULL ) != NULL )
481 0 : osEncoding = CPLGetConfigOption( "DXF_ENCODING", NULL );
482 :
483 18 : 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 18 : }
487 :
488 : /************************************************************************/
489 : /* GetVariable() */
490 : /* */
491 : /* Fetch a variable that came from the HEADER section. */
492 : /************************************************************************/
493 :
494 36 : const char *OGRDXFDataSource::GetVariable( const char *pszName,
495 : const char *pszDefault )
496 :
497 : {
498 36 : if( oHeaderVariables.count(pszName) == 0 )
499 12 : return pszDefault;
500 : else
501 24 : return oHeaderVariables[pszName];
502 : }
503 :
504 : /************************************************************************/
505 : /* AddStandardFields() */
506 : /************************************************************************/
507 :
508 24 : void OGRDXFDataSource::AddStandardFields( OGRFeatureDefn *poFeatureDefn )
509 :
510 : {
511 24 : OGRFieldDefn oLayerField( "Layer", OFTString );
512 24 : poFeatureDefn->AddFieldDefn( &oLayerField );
513 :
514 24 : OGRFieldDefn oClassField( "SubClasses", OFTString );
515 24 : poFeatureDefn->AddFieldDefn( &oClassField );
516 :
517 24 : OGRFieldDefn oExtendedField( "ExtendedEntity", OFTString );
518 24 : poFeatureDefn->AddFieldDefn( &oExtendedField );
519 :
520 24 : OGRFieldDefn oLinetypeField( "Linetype", OFTString );
521 24 : poFeatureDefn->AddFieldDefn( &oLinetypeField );
522 :
523 24 : OGRFieldDefn oEntityHandleField( "EntityHandle", OFTString );
524 24 : poFeatureDefn->AddFieldDefn( &oEntityHandleField );
525 :
526 24 : OGRFieldDefn oTextField( "Text", OFTString );
527 24 : poFeatureDefn->AddFieldDefn( &oTextField );
528 :
529 24 : if( !bInlineBlocks )
530 : {
531 2 : OGRFieldDefn oTextField( "BlockName", OFTString );
532 2 : poFeatureDefn->AddFieldDefn( &oTextField );
533 24 : }
534 24 : }
|