1 /******************************************************************************
2 **  libDXFrw - Library to read/write DXF files (ascii & binary)              **
3 **                                                                           **
4 **  Copyright (C) 2011-2015 José F. Soriano, rallazz@gmail.com               **
5 **                                                                           **
6 **  This library is free software, licensed under the terms of the GNU       **
7 **  General Public License as published by the Free Software Foundation,     **
8 **  either version 2 of the License, or (at your option) any later version.  **
9 **  You should have received a copy of the GNU General Public License        **
10 **  along with this program.  If not, see <http://www.gnu.org/licenses/>.    **
11 ******************************************************************************/
12 
13 
14 #include "libdwgr.h"
15 
16 #include <fstream>
17 #include <algorithm>
18 #include <sstream>
19 #include "intern/drw_dbg.h"
20 
21 #include "intern/drw_textcodec.h"
22 #include "intern/dwgreader.h"
23 #include "intern/dwgreader15.h"
24 #include "intern/dwgreader18.h"
25 #include "intern/dwgreader21.h"
26 #include "intern/dwgreader24.h"
27 #include "intern/dwgreader27.h"
28 
29 #define FIRSTHANDLE 48
30 
31 #if 0
32 enum sections
33 {
34   secUnknown,
35   secHeader,
36   secTables,
37   secBlocks,
38   secEntities,
39   secObjects
40 };
41 #endif
42 
dwgR(const char * name)43 dwgR::dwgR( const char *name )
44   : fileName{ name }
45 {
46   DRW_DBGSL( DRW_dbg::Level::None );
47 }
48 
49 dwgR::~dwgR() = default;
50 
setDebug(DRW::DebugLevel lvl)51 void dwgR::setDebug( DRW::DebugLevel lvl )
52 {
53   switch ( lvl )
54   {
55     case DRW::DebugLevel::Debug:
56       DRW_DBGSL( DRW_dbg::Level::Debug );
57       break;
58     case DRW::DebugLevel::None:
59       DRW_DBGSL( DRW_dbg::Level::None );
60   }
61 }
62 
63 /*reads metadata and loads image preview*/
getPreview()64 bool dwgR::getPreview()
65 {
66   std::ifstream filestr;
67 
68   bool isOk = openFile( &filestr );
69   if ( !isOk )
70     return false;
71 
72   isOk = reader->readMetaData();
73   if ( isOk )
74   {
75     isOk = reader->readPreview();
76   }
77   else
78     error = DRW::BAD_READ_METADATA;
79 
80   filestr.close();
81   if ( reader )
82   {
83     reader.reset();
84   }
85   return isOk;
86 }
87 
testReader()88 bool dwgR::testReader()
89 {
90   bool isOk = false;
91 
92   std::ifstream filestr;
93   filestr.open( fileName.c_str(), std::ios_base::in | std::ios::binary );
94   if ( !filestr.is_open() || !filestr.good() )
95   {
96     error = DRW::BAD_OPEN;
97     return isOk;
98   }
99 
100   dwgBuffer fileBuf( &filestr );
101   duint8 *tmpStrData = new duint8[fileBuf.size()];
102   fileBuf.getBytes( tmpStrData, fileBuf.size() );
103   dwgBuffer dataBuf( tmpStrData, fileBuf.size() );
104   fileBuf.setPosition( 0 );
105   DRW_DBG("\ndwgR::testReader filebuf size: ");DRW_DBG(fileBuf.size());
106   DRW_DBG("\ndwgR::testReader dataBuf size: ");DRW_DBG(dataBuf.size());
107   DRW_DBG("\n filebuf pos: ");DRW_DBG(fileBuf.getPosition());
108   DRW_DBG("\n dataBuf pos: ");DRW_DBG(dataBuf.getPosition());
109   DRW_DBG("\n filebuf bitpos: ");DRW_DBG(fileBuf.getBitPos());
110   DRW_DBG("\n dataBuf bitpos: ");DRW_DBG(dataBuf.getBitPos());
111   DRW_DBG("\n filebuf first byte : ");DRW_DBGH(fileBuf.getRawChar8());
112   DRW_DBG("\n dataBuf  first byte : ");DRW_DBGH(dataBuf.getRawChar8());
113   fileBuf.setBitPos( 4 );
114   dataBuf.setBitPos( 4 );
115   DRW_DBG("\n filebuf first byte : ");DRW_DBGH(fileBuf.getRawChar8());
116   DRW_DBG("\n dataBuf  first byte : ");DRW_DBGH(dataBuf.getRawChar8());
117   DRW_DBG("\n filebuf pos: ");DRW_DBG(fileBuf.getPosition());
118   DRW_DBG("\n dataBuf pos: ");DRW_DBG(dataBuf.getPosition());
119   DRW_DBG("\n filebuf bitpos: ");DRW_DBG(fileBuf.getBitPos());
120   DRW_DBG("\n dataBuf bitpos: ");DRW_DBG(dataBuf.getBitPos());
121   fileBuf.setBitPos( 6 );
122   dataBuf.setBitPos( 6 );
123   DRW_DBG("\n filebuf pos: ");DRW_DBG(fileBuf.getPosition());
124   DRW_DBG("\n dataBuf pos: ");DRW_DBG(dataBuf.getPosition());
125   DRW_DBG("\n filebuf bitpos: ");DRW_DBG(fileBuf.getBitPos());
126   DRW_DBG("\n dataBuf bitpos: ");DRW_DBG(dataBuf.getBitPos());
127   DRW_DBG("\n filebuf first byte : ");DRW_DBGH(fileBuf.getRawChar8());
128   DRW_DBG("\n dataBuf  first byte : ");DRW_DBGH(dataBuf.getRawChar8());
129   fileBuf.setBitPos( 0 );
130   dataBuf.setBitPos( 0 );
131   DRW_DBG("\n filebuf first byte : ");DRW_DBGH(fileBuf.getRawChar8());
132   DRW_DBG("\n dataBuf  first byte : ");DRW_DBGH(dataBuf.getRawChar8());
133   DRW_DBG("\n filebuf pos: ");DRW_DBG(fileBuf.getPosition());
134   DRW_DBG("\n dataBuf pos: ");DRW_DBG(dataBuf.getPosition());
135   DRW_DBG("\n filebuf bitpos: ");DRW_DBG(fileBuf.getBitPos());
136   DRW_DBG("\n dataBuf bitpos: ");DRW_DBG(dataBuf.getBitPos());
137   delete [] tmpStrData;
138   filestr.close();
139 
140   return isOk;
141 }
142 
143 /*start reading dwg file header and, if can read it, continue reading all*/
read(DRW_Interface * interface_,bool ext)144 bool dwgR::read( DRW_Interface *interface_, bool ext )
145 {
146   applyExt = ext;
147   iface = interface_;
148 
149 #if 0
150   testReader();
151   return false;
152 #endif
153 
154   std::ifstream filestr;
155   bool isOk = openFile( &filestr );
156   if ( !isOk )
157     return false;
158 
159   isOk = reader->readMetaData();
160   if ( isOk )
161   {
162     isOk = reader->readFileHeader();
163     if ( isOk )
164     {
165       isOk = processDwg();
166     }
167     else
168       error = DRW::BAD_READ_FILE_HEADER;
169   }
170   else
171     error = DRW::BAD_READ_METADATA;
172 
173   filestr.close();
174   if ( reader )
175   {
176     reader.reset();
177   }
178 
179   return isOk;
180 }
181 
182 std::unordered_map< const char *, DRW::Version > dwgR::DRW_dwgVersionStrings =
183 {
184   { "MC0.0", DRW::MC00 },
185   { "AC1.2", DRW::AC12 },
186   { "AC1.4", DRW::AC14 },
187   { "AC1.50", DRW::AC150 },
188   { "AC2.10", DRW::AC210 },
189   { "AC1002", DRW::AC1002 },
190   { "AC1003", DRW::AC1003 },
191   { "AC1004", DRW::AC1004 },
192   { "AC1006", DRW::AC1006 },
193   { "AC1009", DRW::AC1009 },
194   { "AC1012", DRW::AC1012 },
195   { "AC1014", DRW::AC1014 },
196   { "AC1015", DRW::AC1015 },
197   { "AC1018", DRW::AC1018 },
198   { "AC1021", DRW::AC1021 },
199   { "AC1024", DRW::AC1024 },
200   { "AC1027", DRW::AC1027 },
201   { "AC1032", DRW::AC1032 },
202 };
203 
204 /**
205  * Factory method which creates a reader for the specified DWG version.
206  *
207  * \returns nullptr if version is not supported.
208 */
createReaderForVersion(DRW::Version version,std::ifstream * stream,dwgR * p)209 std::unique_ptr<dwgReader> dwgR::createReaderForVersion( DRW::Version version, std::ifstream *stream, dwgR *p )
210 {
211   switch ( version )
212   {
213     // unsupported
214     case DRW::UNKNOWNV:
215     case DRW::MC00:
216     case DRW::AC12:
217     case DRW::AC14:
218     case DRW::AC150:
219     case DRW::AC210:
220     case DRW::AC1002:
221     case DRW::AC1003:
222     case DRW::AC1004:
223     case DRW::AC1006:
224     case DRW::AC1009:
225       break;
226 
227     case DRW::AC1012:
228     case DRW::AC1014:
229     case DRW::AC1015:
230       return std::unique_ptr< dwgReader >( new dwgReader15( stream, p ) );
231 
232     case DRW::AC1018:
233       return std::unique_ptr< dwgReader >( new dwgReader18( stream, p ) );
234 
235     case DRW::AC1021:
236       return std::unique_ptr< dwgReader >( new dwgReader21( stream, p ) );
237 
238     case DRW::AC1024:
239       return std::unique_ptr< dwgReader >( new dwgReader24( stream, p ) );
240 
241     case DRW::AC1027:
242       return std::unique_ptr< dwgReader >( new dwgReader27( stream, p ) );
243 
244     // unsupported
245     case DRW::AC1032:
246       break;
247   }
248   return nullptr;
249 }
250 
251 /* Open the file and stores it in filestr, install the correct reader version.
252  * If fail opening file, error are set as DRW::BAD_OPEN
253  * If not are DWG or are unsupported version, error are set as DRW::BAD_VERSION
254  * and closes filestr.
255  * Return true on succeed or false on fail
256 */
openFile(std::ifstream * filestr)257 bool dwgR::openFile( std::ifstream *filestr )
258 {
259   DRW_DBG("dwgR::read 1\n");
260   bool isOk = false;
261 
262   filestr->open( fileName.c_str(), std::ios_base::in | std::ios::binary );
263   if ( !filestr->is_open() || !filestr->good() )
264   {
265     error = DRW::BAD_OPEN;
266     return isOk;
267   }
268 
269   char line[7];
270   filestr->read( line, 6 );
271   line[6] = '\0';
272   DRW_DBG("dwgR::read 2\n");
273   DRW_DBG("dwgR::read line version: ");
274   DRW_DBG(line);
275   DRW_DBG("\n");
276 
277   // check version line against known version strings
278   version = DRW::UNKNOWNV;
279   for ( auto it = DRW_dwgVersionStrings.begin(); it != DRW_dwgVersionStrings.end(); ++it )
280   {
281     if ( strcmp( line, it->first ) == 0 )
282     {
283       version = it->second;
284       break;
285     }
286   }
287 
288   reader = createReaderForVersion( version, filestr, this );
289 
290   if ( !reader )
291   {
292     error = DRW::BAD_VERSION;
293     filestr->close();
294   }
295   else
296     isOk = true;
297 
298   return isOk;
299 }
300 
301 /********* Reader Process *********/
302 
processDwg()303 bool dwgR::processDwg()
304 {
305   DRW_DBG("dwgR::processDwg() start processing dwg\n");
306 
307   bool ret;
308   bool ret2;
309   DRW_Header hdr;
310   ret = reader->readDwgHeader( hdr );
311   if ( !ret )
312   {
313     error = DRW::BAD_READ_HEADER;
314   }
315 
316   ret2 = reader->readDwgClasses();
317   if ( ret && !ret2 )
318   {
319     error = DRW::BAD_READ_CLASSES;
320     ret = ret2;
321   }
322 
323   ret2 = reader->readDwgHandles();
324   if ( ret && !ret2 )
325   {
326     error = DRW::BAD_READ_HANDLES;
327     ret = ret2;
328   }
329 
330   ret2 = reader->readDwgTables( hdr );
331   if ( ret && !ret2 )
332   {
333     error = DRW::BAD_READ_TABLES;
334     ret = ret2;
335   }
336 
337   iface->addHeader( &hdr );
338 
339   for ( std::map<duint32, DRW_LType *>::iterator it = reader->ltypemap.begin(); it != reader->ltypemap.end(); ++it )
340   {
341     DRW_LType *lt = it->second;
342     iface->addLType( const_cast<DRW_LType &>( *lt ) );
343   }
344   for ( std::map<duint32, DRW_Layer *>::iterator it = reader->layermap.begin(); it != reader->layermap.end(); ++it )
345   {
346     DRW_Layer *ly = it->second;
347     iface->addLayer( const_cast<DRW_Layer &>( *ly ) );
348   }
349 
350   for ( std::map<duint32, DRW_Textstyle *>::iterator it = reader->stylemap.begin(); it != reader->stylemap.end(); ++it )
351   {
352     DRW_Textstyle *ly = it->second;
353     iface->addTextStyle( const_cast<DRW_Textstyle &>( *ly ) );
354   }
355 
356   for ( std::map<duint32, DRW_Dimstyle *>::iterator it = reader->dimstylemap.begin(); it != reader->dimstylemap.end(); ++it )
357   {
358     DRW_Dimstyle *ly = it->second;
359     iface->addDimStyle( const_cast<DRW_Dimstyle &>( *ly ) );
360   }
361 
362   for ( std::map<duint32, DRW_Vport *>::iterator it = reader->vportmap.begin(); it != reader->vportmap.end(); ++it )
363   {
364     DRW_Vport *ly = it->second;
365     iface->addVport( const_cast<DRW_Vport &>( *ly ) );
366   }
367 
368   for ( std::map<duint32, DRW_AppId *>::iterator it = reader->appIdmap.begin(); it != reader->appIdmap.end(); ++it )
369   {
370     DRW_AppId *ly = it->second;
371     iface->addAppId( const_cast<DRW_AppId &>( *ly ) );
372   }
373 
374   ret2 = reader->readDwgBlocks( *iface );
375   if ( ret && !ret2 )
376   {
377     error = DRW::BAD_READ_BLOCKS;
378     ret = ret2;
379   }
380 
381   ret2 = reader->readDwgEntities( *iface );
382   if ( ret && !ret2 )
383   {
384     error = DRW::BAD_READ_ENTITIES;
385     ret = ret2;
386   }
387 
388   ret2 = reader->readDwgObjects( *iface );
389   if ( ret && !ret2 )
390   {
391     error = DRW::BAD_READ_OBJECTS;
392     ret = ret2;
393   }
394 
395   return ret;
396 }
397