1 /******************************************************************************
2  *
3  * Project:  DWG Translator
4  * Purpose:  Implements OGRDWGDataSource class
5  * Author:   Frank Warmerdam, warmerdam@pobox.com
6  *
7  ******************************************************************************
8  * Copyright (c) 2011, Frank Warmerdam <warmerdam@pobox.com>
9  *
10  * Permission is hereby granted, free of charge, to any person obtaining a
11  * copy of this software and associated documentation files (the "Software"),
12  * to deal in the Software without restriction, including without limitation
13  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
14  * and/or sell copies of the Software, and to permit persons to whom the
15  * Software is furnished to do so, subject to the following conditions:
16  *
17  * The above copyright notice and this permission notice shall be included
18  * in all copies or substantial portions of the Software.
19  *
20  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
21  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
23  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
25  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
26  * DEALINGS IN THE SOFTWARE.
27  ****************************************************************************/
28 
29 #include "ogr_dwg.h"
30 #include "cpl_conv.h"
31 #include "cpl_string.h"
32 
33 CPL_CVSID("$Id: ogrdwgdatasource.cpp 7e07230bbff24eb333608de4dbd460b7312839d0 2017-12-11 19:08:47Z Even Rouault $")
34 
35 /************************************************************************/
36 /*                          OGRDWGDataSource()                          */
37 /************************************************************************/
38 
OGRDWGDataSource()39 OGRDWGDataSource::OGRDWGDataSource() :
40   fp(nullptr),
41   iEntitiesSectionOffset(0),
42   bInlineBlocks(FALSE),
43   poServices(nullptr),
44   poDb(static_cast<const OdRxObject*>(nullptr))
45 
46 {
47 }
48 
49 /************************************************************************/
50 /*                         ~OGRDWGDataSource()                          */
51 /************************************************************************/
52 
~OGRDWGDataSource()53 OGRDWGDataSource::~OGRDWGDataSource()
54 
55 {
56 /* -------------------------------------------------------------------- */
57 /*      Destroy layers.                                                 */
58 /* -------------------------------------------------------------------- */
59     while( !apoLayers.empty() )
60     {
61         delete apoLayers.back();
62         apoLayers.pop_back();
63     }
64 }
65 
66 /************************************************************************/
67 /*                           TestCapability()                           */
68 /************************************************************************/
69 
TestCapability(const char *)70 int OGRDWGDataSource::TestCapability( const char * /*pszCap*/ )
71 
72 {
73     return FALSE;
74 }
75 
76 /************************************************************************/
77 /*                              GetLayer()                              */
78 /************************************************************************/
79 
GetLayer(int iLayer)80 OGRLayer *OGRDWGDataSource::GetLayer( int iLayer )
81 
82 {
83     if( iLayer < 0 || iLayer >= (int) apoLayers.size() )
84         return nullptr;
85     else
86         return apoLayers[iLayer];
87 }
88 
89 /************************************************************************/
90 /*                                Open()                                */
91 /************************************************************************/
92 
Open(OGRDWGServices * poServicesIn,const char * pszFilename,int)93 int OGRDWGDataSource::Open( OGRDWGServices *poServicesIn,
94                             const char * pszFilename, int /*bHeaderOnly*/ )
95 
96 {
97     poServices = poServicesIn;
98 
99     osEncoding = CPL_ENC_ISO8859_1;
100 
101     m_osName = pszFilename;
102 
103     bInlineBlocks = CPLTestBool(
104         CPLGetConfigOption( "DWG_INLINE_BLOCKS", "TRUE" ) );
105 
106 /* -------------------------------------------------------------------- */
107 /*      Open the file.                                                  */
108 /* -------------------------------------------------------------------- */
109     try
110     {
111         OdString f(pszFilename);
112         poDb = poServices->readFile(f.c_str(), true, false, Oda::kShareDenyNo);
113     }
114     catch( OdError& e )
115     {
116         CPLError( CE_Failure, CPLE_AppDefined,
117                   "%s",
118                   (const char *) poServices->getErrorDescription(e.code()) );
119     }
120     catch( ... )
121     {
122         CPLError( CE_Failure, CPLE_AppDefined,
123                   "DWG readFile(%s) failed with generic exception.",
124                   pszFilename );
125     }
126 
127     if( poDb.isNull() )
128         return FALSE;
129 
130 /* -------------------------------------------------------------------- */
131 /*      Process the header, picking up a few useful pieces of           */
132 /*      information.                                                    */
133 /* -------------------------------------------------------------------- */
134     ReadHeaderSection();
135     ReadLineTypeDefinitions();
136     ReadLayerDefinitions();
137 
138 /* -------------------------------------------------------------------- */
139 /*      Create a blocks layer if we are not in inlining mode.           */
140 /* -------------------------------------------------------------------- */
141     if( !bInlineBlocks )
142         apoLayers.push_back( new OGRDWGBlocksLayer( this ) );
143 
144 /* -------------------------------------------------------------------- */
145 /*      Create out layer object - we will need it when interpreting     */
146 /*      blocks.                                                         */
147 /* -------------------------------------------------------------------- */
148     apoLayers.push_back( new OGRDWGLayer( this ) );
149 
150     ReadBlocksSection();
151 
152     return TRUE;
153 }
154 
155 /************************************************************************/
156 /*                        ReadLayerDefinitions()                        */
157 /************************************************************************/
158 
ReadLayerDefinitions()159 void OGRDWGDataSource::ReadLayerDefinitions()
160 
161 {
162     OdDbLayerTablePtr poLT = poDb->getLayerTableId().safeOpenObject();
163     OdDbSymbolTableIteratorPtr poIter = poLT->newIterator();
164 
165     for (poIter->start(); !poIter->done(); poIter->step())
166     {
167         CPLString osValue;
168         OdDbLayerTableRecordPtr poLD = poIter->getRecordId().safeOpenObject();
169         std::map<CPLString,CPLString> oLayerProperties;
170 
171         CPLString osLayerName = ACTextUnescape(poLD->getName(),GetEncoding(), false);
172 
173         oLayerProperties["Exists"] = "1";
174 
175         OdDbLinetypeTableRecordPtr poLinetypeTableRecord = poLD->linetypeObjectId().safeOpenObject();
176         oLayerProperties["Linetype"] =
177             ACTextUnescape(poLinetypeTableRecord->getName(),GetEncoding(), false);
178 
179         osValue.Printf( "%d", poLD->colorIndex() );
180         oLayerProperties["Color"] = osValue;
181 
182         osValue.Printf( "%d", (int) poLD->lineWeight() );
183         oLayerProperties["LineWeight"] = osValue;
184 
185         if( poLD->isFrozen() || poLD->isHidden() || poLD->isOff() )
186             oLayerProperties["Hidden"] = "1";
187         else
188             oLayerProperties["Hidden"] = "0";
189 
190         oLayerTable[osLayerName] = oLayerProperties;
191     }
192 
193     CPLDebug( "DWG", "Read %d layer definitions.",
194               (int) oLayerTable.size() );
195 }
196 
197 /************************************************************************/
198 /*                        LookupLayerProperty()                         */
199 /************************************************************************/
200 
LookupLayerProperty(const char * pszLayer,const char * pszProperty)201 const char *OGRDWGDataSource::LookupLayerProperty( const char *pszLayer,
202                                                    const char *pszProperty )
203 
204 {
205     if( pszLayer == nullptr )
206         return nullptr;
207 
208     try {
209         return (oLayerTable[pszLayer])[pszProperty];
210     } catch( ... ) {
211         return nullptr;
212     }
213 }
214 
215 /************************************************************************/
216 /*                       ReadLineTypeDefinitions()                      */
217 /************************************************************************/
218 
ReadLineTypeDefinitions()219 void OGRDWGDataSource::ReadLineTypeDefinitions()
220 
221 {
222     OdDbLinetypeTablePtr poTable = poDb->getLinetypeTableId().safeOpenObject();
223     OdDbSymbolTableIteratorPtr poIter = poTable->newIterator();
224 
225     for (poIter->start(); !poIter->done(); poIter->step())
226     {
227         CPLString osLineTypeName;
228         CPLString osLineTypeDef;
229         OdDbLinetypeTableRecordPtr poLT = poIter->getRecordId().safeOpenObject();
230 
231         osLineTypeName = ACTextUnescape(poLT->getName(),GetEncoding(),false);
232 
233         if (poLT->numDashes())
234         {
235             for (int i=0; i < poLT->numDashes(); i++)
236             {
237                 if( i > 0 )
238                     osLineTypeDef += " ";
239 
240                 CPLString osValue;
241                 osValue.Printf( "%g", fabs(poLT->dashLengthAt(i)) );
242                 osLineTypeDef += osValue;
243 
244                 osLineTypeDef += "g";
245             }
246 
247             oLineTypeTable[osLineTypeName] = osLineTypeDef;
248             CPLDebug( "DWG", "LineType '%s' = '%s'",
249                        osLineTypeName.c_str(),
250                        osLineTypeDef.c_str() );
251         }
252     }
253 }
254 
255 /************************************************************************/
256 /*                           LookupLineType()                           */
257 /************************************************************************/
258 
LookupLineType(const char * pszName)259 const char *OGRDWGDataSource::LookupLineType( const char *pszName )
260 
261 {
262     if( oLineTypeTable.count(pszName) > 0 )
263         return oLineTypeTable[pszName];
264     else
265         return nullptr;
266 }
267 
268 /************************************************************************/
269 /*                         ReadHeaderSection()                          */
270 /************************************************************************/
271 
ReadHeaderSection()272 void OGRDWGDataSource::ReadHeaderSection()
273 
274 {
275     // using: DWGCODEPAGE, DIMTXT, LUPREC
276 
277     CPLString osValue;
278 
279     osValue.Printf( "%d", poDb->getLUPREC() );
280     oHeaderVariables["$LUPREC"] = osValue;
281 
282     osValue.Printf( "%g", poDb->dimtxt() );
283     oHeaderVariables["$DIMTXT"] = osValue;
284 
285     CPLDebug( "DWG", "Read %d header variables.",
286               (int) oHeaderVariables.size() );
287 
288 /* -------------------------------------------------------------------- */
289 /*      Decide on what CPLRecode() name to use for the files            */
290 /*      encoding or allow the encoding to be overridden.                */
291 /* -------------------------------------------------------------------- */
292     CPLString osCodepage = GetVariable( "$DWGCODEPAGE", "ANSI_1252" );
293 
294     // not strictly accurate but works even without iconv.
295     if( osCodepage == "ANSI_1252" )
296         osEncoding = CPL_ENC_ISO8859_1;
297     else if( STARTS_WITH_CI(osCodepage, "ANSI_") )
298     {
299         osEncoding = "CP";
300         osEncoding += osCodepage + 5;
301     }
302     else
303     {
304         // fallback to the default
305         osEncoding = CPL_ENC_ISO8859_1;
306     }
307 
308     if( CPLGetConfigOption( "DWG_ENCODING", nullptr ) != nullptr )
309         osEncoding = CPLGetConfigOption( "DWG_ENCODING", nullptr );
310 
311     if( osEncoding != CPL_ENC_ISO8859_1 )
312         CPLDebug( "DWG", "Treating DWG as encoding '%s', $DWGCODEPAGE='%s'",
313                   osEncoding.c_str(), osCodepage.c_str() );
314 }
315 
316 /************************************************************************/
317 /*                            GetVariable()                             */
318 /*                                                                      */
319 /*      Fetch a variable that came from the HEADER section.             */
320 /************************************************************************/
321 
GetVariable(const char * pszName,const char * pszDefault)322 const char *OGRDWGDataSource::GetVariable( const char *pszName,
323                                            const char *pszDefault )
324 
325 {
326     if( oHeaderVariables.count(pszName) == 0 )
327         return pszDefault;
328     else
329         return oHeaderVariables[pszName];
330 }
331 
332 /************************************************************************/
333 /*                         AddStandardFields()                          */
334 /************************************************************************/
335 
AddStandardFields(OGRFeatureDefn * poFeatureDefn)336 void OGRDWGDataSource::AddStandardFields( OGRFeatureDefn *poFeatureDefn )
337 
338 {
339     OGRFieldDefn  oLayerField( "Layer", OFTString );
340     poFeatureDefn->AddFieldDefn( &oLayerField );
341 
342     OGRFieldDefn  oClassField( "SubClasses", OFTString );
343     poFeatureDefn->AddFieldDefn( &oClassField );
344 
345     OGRFieldDefn  oExtendedField( "ExtendedEntity", OFTString );
346     poFeatureDefn->AddFieldDefn( &oExtendedField );
347 
348     OGRFieldDefn  oLinetypeField( "Linetype", OFTString );
349     poFeatureDefn->AddFieldDefn( &oLinetypeField );
350 
351     OGRFieldDefn  oEntityHandleField( "EntityHandle", OFTString );
352     poFeatureDefn->AddFieldDefn( &oEntityHandleField );
353 
354     OGRFieldDefn  oTextField( "Text", OFTString );
355     poFeatureDefn->AddFieldDefn( &oTextField );
356 
357     if( !bInlineBlocks )
358     {
359         OGRFieldDefn  oBlockNameField( "BlockName", OFTString );
360         poFeatureDefn->AddFieldDefn( &oBlockNameField );
361     }
362 }
363