KiCad PCB EDA Suite
readgerb.cpp
Go to the documentation of this file.
1/*
2 * This program source code file is part of KiCad, a free EDA CAD application.
3 *
4 * Copyright (C) 2007-2016 Jean-Pierre Charras jp.charras at wanadoo.fr
5 * Copyright (C) 1992-2016 KiCad Developers, see AUTHORS.txt for contributors.
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, you may find one here:
19 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
20 * or you may search the http://www.gnu.org website for the version 2 license,
21 * or you may write to the Free Software Foundation, Inc.,
22 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
23 */
24
25#include "ki_exception.h"
26#include <string_utils.h>
27#include <locale_io.h>
28#include <gerbview.h>
29#include <gerbview_frame.h>
30#include <gerber_file_image.h>
32#include <view/view.h>
33
35#include <macros.h>
36
37#include <wx/msgdlg.h>
38
39/* Read a gerber file, RS274D, RS274X or RS274X2 format.
40 */
41bool GERBVIEW_FRAME::Read_GERBER_File( const wxString& GERBER_FullFileName )
42{
43 wxString msg;
44
45 int layer = GetActiveLayer();
47 GERBER_FILE_IMAGE* gerber = GetGbrImage( layer );
48
49 if( gerber != nullptr )
50 {
52 }
53
54 // use an unique ptr while we load to free on exception properly
55 std::unique_ptr<GERBER_FILE_IMAGE> gerber_uptr = std::make_unique<GERBER_FILE_IMAGE>( layer );
56
57 // Read the gerber file. The image will be added only if it can be read
58 // to avoid broken data.
59 bool success = gerber_uptr->LoadGerberFile( GERBER_FullFileName );
60
61 if( !success )
62 {
63 gerber_uptr.reset();
64 msg.Printf( _( "File '%s' not found" ), GERBER_FullFileName );
65 ShowInfoBarError( msg );
66 return false;
67 }
68
69 gerber = gerber_uptr.release();
70 wxASSERT( gerber != nullptr );
71 images->AddGbrImage( gerber, layer );
72
73 // Display errors list
74 if( gerber->GetMessages().size() > 0 )
75 {
76 HTML_MESSAGE_BOX dlg( this, _( "Errors" ) );
77 dlg.ListSet( gerber->GetMessages() );
78 dlg.ShowModal();
79 }
80
81 /* if the gerber file has items using D codes but missing D codes definitions,
82 * it can be a deprecated RS274D file (i.e. without any aperture information),
83 * or has missing definitions,
84 * warn the user:
85 */
86 if( gerber->GetItemsCount() && gerber->m_Has_MissingDCode )
87 {
88 if( !gerber->m_Has_DCode )
89 msg = _("Warning: this file has no D-Code definition\n"
90 "Therefore the size of some items is undefined");
91 else
92 msg = _("Warning: this file has some missing D-Code definitions\n"
93 "Therefore the size of some items is undefined");
94
95 wxMessageBox( msg );
96 }
97
98 if( GetCanvas() )
99 {
100 if( gerber->m_ImageNegative )
101 {
102 // TODO: find a way to handle negative images
103 // (maybe convert geometry into positives?)
104 }
105
106 for( GERBER_DRAW_ITEM* item : gerber->GetItems() )
107 GetCanvas()->GetView()->Add( (KIGFX::VIEW_ITEM*) item );
108 }
109
110 return true;
111}
112
113
114/*
115 * Original function derived from gerber_is_rs274x_p() of gerbv 2.7.0.
116 * Copyright of the source file readgerb.cpp included below:
117 */
118/* gEDA - GNU Electronic Design Automation
119 * This is a part of gerbv
120 *
121 * Copyright (C) 2000-2003 Stefan Petersen ([email protected])
122 *
123 * $Id$
124 *
125 * This program is free software; you can redistribute it and/or modify
126 * it under the terms of the GNU General Public License as published by
127 * the Free Software Foundation; either version 2 of the License, or
128 * (at your option) any later version.
129 *
130 * This program is distributed in the hope that it will be useful,
131 * but WITHOUT ANY WARRANTY; without even the implied warranty of
132 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
133 * GNU General Public License for more details.
134 *
135 * You should have received a copy of the GNU General Public License
136 * along with this program; if not, write to the Free Software
137 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA
138 */
139bool GERBER_FILE_IMAGE::TestFileIsRS274( const wxString& aFullFileName )
140{
141 char* letter = nullptr;
142 bool foundADD = false;
143 bool foundD0 = false;
144 bool foundD2 = false;
145 bool foundM0 = false;
146 bool foundM2 = false;
147 bool foundStar = false;
148 bool foundX = false;
149 bool foundY = false;
150
151 try
152 {
153 FILE_LINE_READER gerberReader( aFullFileName );
154
155 while( gerberReader.ReadLine() )
156 {
157 // Remove all whitespace from the beginning and end
158 char* line = StrPurge( gerberReader.Line() );
159
160 // Skip empty lines
161 if( *line == 0 )
162 continue;
163
164 // Check that file is not binary (non-printing chars)
165 for( size_t i = 0; i < strlen( line ); i++ )
166 {
167 if( !isascii( line[i] ) )
168 return false;
169 }
170
171 if( strstr( line, "%ADD" ) )
172 foundADD = true;
173
174 if( strstr( line, "D00" ) || strstr( line, "D0" ) )
175 foundD0 = true;
176
177 if( strstr( line, "D02" ) || strstr( line, "D2" ) )
178 foundD2 = true;
179
180 if( strstr( line, "M00" ) || strstr( line, "M0" ) )
181 foundM0 = true;
182
183 if( strstr( line, "M02" ) || strstr( line, "M2" ) )
184 foundM2 = true;
185
186 if( strstr( line, "*" ) )
187 foundStar = true;
188
189 /* look for X<number> or Y<number> */
190 if( ( letter = strstr( line, "X" ) ) != nullptr )
191 {
192 if( isdigit( letter[1] ) )
193 foundX = true;
194 }
195
196 if( ( letter = strstr( line, "Y" ) ) != nullptr )
197 {
198 if( isdigit( letter[1] ) )
199 foundY = true;
200 }
201 }
202 }
203 catch( IO_ERROR& )
204 {
205 return false;
206 }
207
208 // RS-274X
209 if( ( foundD0 || foundD2 || foundM0 || foundM2 ) && foundADD && foundStar
210 && ( foundX || foundY ) )
211 {
212 return true;
213 }
214 // RS-274D. Could be folded into the expression above, but someday
215 // we might want to test for them separately.
216 else if( ( foundD0 || foundD2 || foundM0 || foundM2 ) && !foundADD && foundStar
217 && ( foundX || foundY ) )
218 {
219 return true;
220 }
221
222
223 return false;
224}
225
226// size of a single line of text from a gerber file.
227// warning: some files can have *very long* lines, so the buffer must be large.
228#define GERBER_BUFZ 1000000
229// A large buffer to store one line
230static char lineBuffer[GERBER_BUFZ+1];
231
232bool GERBER_FILE_IMAGE::LoadGerberFile( const wxString& aFullFileName )
233{
234 int G_command = 0; // command number for G commands like G04
235 int D_commande = 0; // command number for D commands like D02
236 char* text;
237
240
241 // Read the gerber file */
242 m_Current_File = wxFopen( aFullFileName, wxT( "rt" ) );
243
244 if( m_Current_File == nullptr )
245 return false;
246
247 m_FileName = aFullFileName;
248
249 LOCALE_IO toggleIo;
250
251 wxString msg;
252
253 while( true )
254 {
255 if( fgets( lineBuffer, GERBER_BUFZ, m_Current_File ) == nullptr )
256 break;
257
258 m_LineNum++;
260
261 while( text && *text )
262 {
263 switch( *text )
264 {
265 case ' ':
266 case '\r':
267 case '\n':
268 text++;
269 break;
270
271 case '*': // End command
273 text++;
274 break;
275
276 case 'M': // End file
278 while( *text )
279 text++;
280 break;
281
282 case 'G': /* Line type Gxx : command */
283 G_command = CodeNumber( text );
284 Execute_G_Command( text, G_command );
285 break;
286
287 case 'D': /* Line type Dxx : Tool selection (xx > 0) or
288 * command if xx = 0..9 */
289 D_commande = CodeNumber( text );
290 Execute_DCODE_Command( text, D_commande );
291 break;
292
293 case 'X':
294 case 'Y': /* Move or draw command */
296 if( *text == '*' ) // command like X12550Y19250*
297 {
299 }
300 break;
301
302 case 'I':
303 case 'J': /* Auxiliary Move command */
305
306 if( *text == '*' ) // command like X35142Y15945J504*
307 {
309 }
310 break;
311
312 case '%':
314 {
317 }
318 else //Error
319 {
320 AddMessageToList( wxT( "Expected RS274X Command" ) );
322 text++;
323 }
324 break;
325
326 default:
327 msg.Printf( wxT( "Unexpected char 0x%2.2X" ), *text );
328 AddMessageToList( msg );
329 text++;
330 break;
331 }
332 }
333 }
334
335 fclose( m_Current_File );
336
337 m_InUse = true;
338
339 return true;
340}
void ShowInfoBarError(const wxString &aErrorMsg, bool aShowCloseButton=false, WX_INFOBAR::MESSAGE_TYPE aType=WX_INFOBAR::MESSAGE_TYPE::GENERIC)
Show the WX_INFOBAR displayed on the top of the canvas with a message and an error icon on the left o...
virtual EDA_DRAW_PANEL_GAL * GetCanvas() const
Return a pointer to GAL-based canvas of given EDA draw frame.
virtual KIGFX::VIEW * GetView() const
Return a pointer to the #VIEW instance used in the panel.
A LINE_READER that reads from an open file.
Definition: richio.h:173
char * ReadLine() override
Read a line of text into the buffer and increments the line number counter.
Definition: richio.cpp:219
GERBER_FILE_IMAGE_LIST is a helper class to handle a list of GERBER_FILE_IMAGE files which are loaded...
int AddGbrImage(GERBER_FILE_IMAGE *aGbrImage, int aIdx)
Add a GERBER_FILE_IMAGE* at index aIdx or at the first free location if aIdx < 0.
Hold the image data and parameters for one gerber file and layer parameters.
bool Execute_G_Command(char *&text, int G_command)
Definition: rs274d.cpp:421
bool LoadGerberFile(const wxString &aFullFileName)
Read and load a gerber file.
Definition: readgerb.cpp:232
int m_Last_Pen_Command
Current or last pen state (0..9, set by Dn option with n < 10.
VECTOR2I ReadIJCoord(char *&Text)
Return the current coordinate type pointed to by InnJnn Text (InnnnJmmmm)
virtual void ResetDefaultValues()
Set all parameters to a default value, before reading a file.
const wxArrayString & GetMessages() const
void ClearMessageList()
Clear the message list.
wxString m_FileName
Full File Name for this layer.
bool m_InUse
true if this image is currently in use (a file is loaded in it) false if it must be not drawn
bool m_ImageNegative
true = Negative image
void AddMessageToList(const wxString &aMessage)
Add a message to the message list.
int m_LineNum
Line number of the gerber file while reading.
VECTOR2I m_IJPos
IJ coord (for arcs & circles )
bool Execute_DCODE_Command(char *&text, int D_command)
Definition: rs274d.cpp:557
static bool TestFileIsRS274(const wxString &aFullFileName)
Performs a heuristics-based check of whether the file is an RS274 gerber file.
Definition: readgerb.cpp:139
bool ReadRS274XCommand(char *aBuff, unsigned int aBuffSize, char *&aText)
Read a single RS274X command terminated with a %.
Definition: rs274x.cpp:144
bool m_Has_DCode
< True if has DCodes in file or false if no DCodes found. Perhaps deprecated RS274D file.
VECTOR2I ReadXYCoord(char *&aText, bool aExcellonMode=false)
Return the current coordinate type pointed to by XnnYnn Text (XnnnnYmmmm).
int m_CommandState
state of gerber analysis command
VECTOR2I m_CurrentPos
current specified coord for plot
GERBER_DRAW_ITEMS & GetItems()
int CodeNumber(char *&aText)
Reads the next number and returns the value.
Definition: rs274d.cpp:401
GERBER_FILE_IMAGE_LIST * GetImagesList() const
Accessors to GERBER_FILE_IMAGE_LIST and GERBER_FILE_IMAGE data.
int GetActiveLayer() const
Return the active layer.
bool Read_GERBER_File(const wxString &GERBER_FullFileName)
Definition: readgerb.cpp:41
GERBER_FILE_IMAGE * GetGbrImage(int aIdx) const
void Erase_Current_DrawLayer(bool query)
void ListSet(const wxString &aList)
Add a list of items.
Hold an error message and may be used when throwing exceptions containing meaningful error messages.
Definition: ki_exception.h:76
An abstract base class for deriving all objects that can be added to a VIEW.
Definition: view_item.h:77
virtual void Add(VIEW_ITEM *aItem, int aDrawPriority=-1)
Add a VIEW_ITEM to the view.
Definition: view.cpp:316
char * Line() const
Return a pointer to the last line that was read in.
Definition: richio.h:117
Instantiate the current locale within a scope in which you are expecting exceptions to be thrown.
Definition: locale_io.h:41
#define _(s)
@ END_BLOCK
Definition: gerbview.h:65
@ ENTER_RS274X_CMD
Definition: gerbview.h:66
@ CMD_IDLE
Definition: gerbview.h:64
This file contains miscellaneous commonly used macros and functions.
#define GERBER_BUFZ
Definition: readgerb.cpp:228
static char lineBuffer[GERBER_BUFZ+1]
Definition: readgerb.cpp:230
char * StrPurge(char *text)
Remove leading and training spaces, tabs and end of line chars in text.