1 /*
2 * For reading and slight parsing of dxf files
3 *
4 * Author:
5 * Matt Squires <squiresm@colorado.edu>
6 *
7 * Copyright (C) 2005 Matt Squires
8 *
9 * Released under GNU GPL and LGPL, read the file 'GPL.txt' and 'LGPL.txt' for details
10 */
14 #include <fstream>
15 #include <string>
16 #include "read_dxf.h"
18 #include <iostream>
19 #include <string.h>
20 #include <stdlib.h>
21 using namespace std;
24 int MAX_STR_LN = 10000;
26 int section(char* value){
27 if ( strncmp(value,"HEADER",6) == 0 ) return 0;
28 if ( strncmp(value,"CLASSES",7) == 0 ) return 1;
29 if ( strncmp(value,"TABLES",6) == 0 ) return 2;
30 if ( strncmp(value,"BLOCKS",6) == 0 ) return 3;
31 if ( strncmp(value,"ENTITIES",8) == 0 ) return 4;
32 if ( strncmp(value,"OBJECTS",7) == 0 ) return 5;
33 if ( strncmp(value,"THUMBNAILIMAGE",14) == 0 ) return 6;
34 }
37 dxfpair::dxfpair(int gcode, char val[10000]){
38 group_code = gcode;
39 // Dynamically save the strings, otherwise the memory uses is bad
41 for (int i = 0; i < strlen(val); i++){
42 value.push_back(val[i]);
43 }
44 }
47 dxfpair::~dxfpair(){
48 //delete [] value;
49 }
51 char * dxfpair::value_char(char *string){
52 int size = value.size();
53 while( ( size > 0 ) && int(value[size-1]) < 33){
54 // Strip off any control characters and spaces off the end of the string
55 size--;
56 }
57 for(int i = 0; i < size; i++){
58 string[i] = value[i];
59 }
60 string[size]=0;
61 }
63 std::vector< std::vector< dxfpair > > dxf_get_sections(char* filename){
64 // In the dxf format information is paired into group codes that indicate the information that follows on the next line. The information on the next line is called the value
66 int n =0;
68 int group_code;
69 char value[MAX_STR_LN];
71 int section_num;
76 std::vector< std::vector< dxfpair > > out;
78 std::vector< dxfpair > header;
79 std::vector< dxfpair > classes;
80 std::vector< dxfpair > tables;
81 std::vector< dxfpair > blocks;
82 std::vector< dxfpair > entities;
83 std::vector< dxfpair > objects;
84 std::vector< dxfpair > thumbnailimage;
86 header.clear();
87 classes.clear();
88 tables.clear();
89 blocks.clear();
90 entities.clear();
91 objects.clear();
92 thumbnailimage.clear();
95 // Open dxf file for reading
96 std::ifstream file(filename);
98 if (!file.is_open()){
99 exit (1); // Change this to an exception
100 }
102 // Find the first SECTION header
104 while ( (!file.eof()) ){
105 n++;
107 // get the first group code and value
108 file.getline(value,MAX_STR_LN);
109 group_code = atoi(value);
110 file.getline(value,MAX_STR_LN);
112 do{
114 // TO DO set all the chars to be caps for later comparison
116 // Find the SECTION codes
117 if ( (group_code == 0 ) && ( strncmp(value,"SECTION",7) == 0 ) ){
118 // Directly after a section value is the type of section ( e.g. HEADER, TABLES )
119 file.getline(value,MAX_STR_LN);
120 group_code = atoi(value);
121 file.getline(value,MAX_STR_LN);
122 section_num = section( value );
123 if ( group_code == 2 ){
124 // Make sure the the group code is 2 for the SECTION name
125 // This is a big block of mostly repetitive code, it will result in larger code, but would be faster than putting the switch in another while loop. If I still live in a time when file size mattered alot I would change it
126 //std::cout << "section_num = " << section_num << std::endl;
127 switch ( section_num ){
128 case 0:
129 file.getline(value,MAX_STR_LN);
130 group_code = atoi(value);
131 file.getline(value,MAX_STR_LN);
132 do{
133 header.push_back( dxfpair( group_code, value ) );
134 file.getline(value,MAX_STR_LN);
135 group_code = atoi(value);
136 file.getline(value,MAX_STR_LN);
137 }while( ( (group_code != 0) || strncmp(value,"ENDSEC",6) != 0 ) && (!file.eof()) ); // I put in the (group_code != 0) in the hope that it will be a faster bool compare than the string compare. Test this later
138 break;
139 case 1:
140 file.getline(value,MAX_STR_LN);
141 group_code = atoi(value);
142 file.getline(value,MAX_STR_LN);
143 if ( (group_code != 0) || (strncmp(value,"ENDSEC",6) != 0) ){
144 // Some dxf files have blank sections. These are not handled by the do/while loop so break about if needed
145 do{
146 classes.push_back( dxfpair( group_code, value ) );
147 file.getline(value,MAX_STR_LN);
148 group_code = atoi(value);
149 file.getline(value,MAX_STR_LN);
150 }while( ( (group_code != 0) || strncmp(value,"ENDSEC",6) != 0 ) && (!file.eof()) ); // I put in the (group_code != 0) in the hope that it will be a faster bool compare than the string compare. Test this later
151 }
152 break;
153 case 2:
154 file.getline(value,MAX_STR_LN);
155 group_code = atoi(value);
156 file.getline(value,MAX_STR_LN);
157 do{
158 tables.push_back( dxfpair( group_code, value ) );
159 file.getline(value,MAX_STR_LN);
160 group_code = atoi(value);
161 file.getline(value,MAX_STR_LN);
162 }while( ( (group_code != 0) || strncmp(value,"ENDSEC",6) != 0 ) && (!file.eof()) );
163 break;
164 case 3:
165 file.getline(value,MAX_STR_LN);
166 group_code = atoi(value);
167 file.getline(value,MAX_STR_LN);
168 do{
169 blocks.push_back( dxfpair( group_code, value ) );
170 file.getline(value,MAX_STR_LN);
171 group_code = atoi(value);
172 file.getline(value,MAX_STR_LN);
173 }while( ( (group_code != 0) || strncmp(value,"ENDSEC",6) != 0 ) && (!file.eof()) ); // I put in the (group_code != 0) in the hope that it will be a faster bool compare than the string compare. Test this later
174 break;
175 case 4:
176 file.getline(value,MAX_STR_LN);
177 group_code = atoi(value);
178 file.getline(value,MAX_STR_LN);
179 do{
180 entities.push_back( dxfpair( group_code, value ) );
181 file.getline(value,MAX_STR_LN);
182 group_code = atoi(value);
183 file.getline(value,MAX_STR_LN);
184 }while( ( (group_code != 0) || strncmp(value,"ENDSEC",6) != 0 ) && (!file.eof()) ); // I put in the (group_code != 0) in the hope that it will be a faster bool compare than the string compare. Test this later
185 break;
186 case 5:
187 file.getline(value,MAX_STR_LN);
188 group_code = atoi(value);
189 file.getline(value,MAX_STR_LN);
190 do{
191 objects.push_back( dxfpair( group_code, value ) );
192 file.getline(value,MAX_STR_LN);
193 group_code = atoi(value);
194 file.getline(value,MAX_STR_LN);
195 }while( ( (group_code != 0) || strncmp(value,"ENDSEC",6) != 0 ) && (!file.eof()) ); // I put in the (group_code != 0) in the hope that it will be a faster bool compare than the string compare. Test this later
196 break;
197 case 6:
198 file.getline(value,MAX_STR_LN);
199 group_code = atoi(value);
200 file.getline(value,MAX_STR_LN);
201 do{
202 thumbnailimage.push_back( dxfpair( group_code, value ) );
203 file.getline(value,MAX_STR_LN);
204 group_code = atoi(value);
205 file.getline(value,MAX_STR_LN);
206 }while( ( (group_code != 0) || strncmp(value,"ENDSEC",6) != 0 ) && (!file.eof()) ); // I put in the (group_code != 0) in the hope that it will be a faster bool compare than the string compare. Test this later
207 break;
208 default:
209 file.getline(value,MAX_STR_LN);
210 group_code = atoi(value);
211 file.getline(value,MAX_STR_LN);
212 }
213 }
214 }
215 file.getline(value,MAX_STR_LN);
216 group_code = atoi(value);
217 file.getline(value,MAX_STR_LN);
219 n++;
220 }while( ( strncmp(value,"EOF",3) != 0 ) && (!file.eof()) );
221 }
223 out.push_back(header);
224 out.push_back(classes);
225 out.push_back(tables);
226 out.push_back(blocks);
227 out.push_back(entities);
228 out.push_back(objects);
229 out.push_back(thumbnailimage);
231 return out;
232 }
235 std::vector< std::vector< dxfpair > > separate_parts( std::vector< dxfpair > section){
236 //std::cout << "1" << std::endl;
237 //std::cout << "section.size() = " << section.size() << std::endl;
238 // Find where the major sections are and break into smaller parts
239 // Major section is defined as anything beween group_code 0 to 0
240 std::vector< dxfpair > inner;
241 std::vector< std::vector< dxfpair > > outer;
242 //std::cout << "2" << std::endl;
243 for (int i = 0; i < section.size(); i++){
244 //std::cout << "i = " << i << std::endl;
245 //std::cout << "section[i].value.size() = " << section[i].value.size() << std::endl;
247 // Make sure no control codes like LF or CR are making it past this section
248 if ( (section[i].value.size() > 0) && int(section[i].value.back()) < 32 ){
249 section[i].value.pop_back();
250 }
251 //for(int j = 0;j < section[i].value.size();j++ ) std::cout << section[i].value[j];
252 //std::cout << std::endl;
254 inner.push_back( section[i] );
256 // If the next group code is 0 then push the previously found info on outer and start looking for data again
257 if (section[i+1].group_code == 0){
258 //std::cout << "inner.push_back" << std::endl;
259 outer.push_back( inner );
260 inner.clear();
261 }
262 }
263 // Because putting the data on outer depends on find a GC=0 the last bit of data may be left behind so it inner has data in it put it on outer
264 if ( inner.size() > 0 ){
265 outer.push_back( inner );
266 inner.clear();
267 }
268 //std::cout << "3" << std::endl;
269 if (section.back().group_code == 0){
270 //outer.push_back( inner ); // Put the last part on if there is information, but I don't think it needs to.
271 }
273 return outer;
274 }