You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

336 lines
10 KiB

  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 The 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. #include "ki_exception.h"
  25. #include <string_utils.h>
  26. #include <gerbview.h>
  27. #include <gerbview_frame.h>
  28. #include <gerber_file_image.h>
  29. #include <gerber_file_image_list.h>
  30. #include <richio.h>
  31. #include <view/view.h>
  32. #include <dialogs/html_message_box.h>
  33. #include <macros.h>
  34. #include <wx/msgdlg.h>
  35. /* Read a gerber file, RS274D, RS274X or RS274X2 format.
  36. */
  37. bool GERBVIEW_FRAME::Read_GERBER_File( const wxString& GERBER_FullFileName )
  38. {
  39. wxString msg;
  40. int layer = GetActiveLayer();
  41. GERBER_FILE_IMAGE_LIST* images = GetImagesList();
  42. GERBER_FILE_IMAGE* gerber = GetGbrImage( layer );
  43. if( gerber != nullptr )
  44. {
  45. Erase_Current_DrawLayer( false );
  46. }
  47. // use an unique ptr while we load to free on exception properly
  48. std::unique_ptr<GERBER_FILE_IMAGE> gerber_uptr = std::make_unique<GERBER_FILE_IMAGE>( layer );
  49. // Read the gerber file. The image will be added only if it can be read
  50. // to avoid broken data.
  51. bool success = gerber_uptr->LoadGerberFile( GERBER_FullFileName );
  52. if( !success )
  53. {
  54. gerber_uptr.reset();
  55. msg.Printf( _( "File '%s' not found" ), GERBER_FullFileName );
  56. ShowInfoBarError( msg );
  57. return false;
  58. }
  59. gerber = gerber_uptr.release();
  60. wxASSERT( gerber != nullptr );
  61. images->AddGbrImage( gerber, layer );
  62. // Display errors list
  63. if( gerber->GetMessages().size() > 0 )
  64. {
  65. HTML_MESSAGE_BOX dlg( this, _( "Errors" ) );
  66. dlg.ListSet( gerber->GetMessages() );
  67. dlg.ShowModal();
  68. }
  69. /* if the gerber file has items using D codes but missing D codes definitions,
  70. * it can be a deprecated RS274D file (i.e. without any aperture information),
  71. * or has missing definitions,
  72. * warn the user:
  73. */
  74. if( gerber->GetItemsCount() && gerber->m_Has_MissingDCode )
  75. {
  76. if( !gerber->m_Has_DCode )
  77. msg = _("Warning: this file has no D-Code definition\n"
  78. "Therefore the size of some items is undefined");
  79. else
  80. msg = _("Warning: this file has some missing D-Code definitions\n"
  81. "Therefore the size of some items is undefined");
  82. wxMessageBox( msg );
  83. }
  84. if( GetCanvas() )
  85. {
  86. if( gerber->m_ImageNegative )
  87. {
  88. // TODO: find a way to handle negative images
  89. // (maybe convert geometry into positives?)
  90. }
  91. for( GERBER_DRAW_ITEM* item : gerber->GetItems() )
  92. GetCanvas()->GetView()->Add( (KIGFX::VIEW_ITEM*) item );
  93. }
  94. return true;
  95. }
  96. /*
  97. * Original function derived from gerber_is_rs274x_p() of gerbv 2.7.0.
  98. * Copyright of the source file readgerb.cpp included below:
  99. */
  100. /* gEDA - GNU Electronic Design Automation
  101. * This is a part of gerbv
  102. *
  103. * Copyright (C) 2000-2003 Stefan Petersen (spe@stacken.kth.se)
  104. *
  105. * $Id$
  106. *
  107. * This program is free software; you can redistribute it and/or modify
  108. * it under the terms of the GNU General Public License as published by
  109. * the Free Software Foundation; either version 2 of the License, or
  110. * (at your option) any later version.
  111. *
  112. * This program is distributed in the hope that it will be useful,
  113. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  114. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  115. * GNU General Public License for more details.
  116. *
  117. * You should have received a copy of the GNU General Public License
  118. * along with this program; if not, write to the Free Software
  119. * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA
  120. */
  121. bool GERBER_FILE_IMAGE::TestFileIsRS274( const wxString& aFullFileName )
  122. {
  123. char* letter = nullptr;
  124. bool foundADD = false;
  125. bool foundD0 = false;
  126. bool foundD2 = false;
  127. bool foundM0 = false;
  128. bool foundM2 = false;
  129. bool foundStar = false;
  130. bool foundX = false;
  131. bool foundY = false;
  132. try
  133. {
  134. FILE_LINE_READER gerberReader( aFullFileName );
  135. while( gerberReader.ReadLine() )
  136. {
  137. // Remove all whitespace from the beginning and end
  138. char* line = StrPurge( gerberReader.Line() );
  139. // Skip empty lines
  140. if( *line == 0 )
  141. continue;
  142. // Check that file is not binary (non-printing chars)
  143. for( size_t i = 0; i < strlen( line ); i++ )
  144. {
  145. if( !isascii( line[i] ) )
  146. return false;
  147. }
  148. if( strstr( line, "%ADD" ) )
  149. foundADD = true;
  150. if( strstr( line, "D00" ) || strstr( line, "D0" ) )
  151. foundD0 = true;
  152. if( strstr( line, "D02" ) || strstr( line, "D2" ) )
  153. foundD2 = true;
  154. if( strstr( line, "M00" ) || strstr( line, "M0" ) )
  155. foundM0 = true;
  156. if( strstr( line, "M02" ) || strstr( line, "M2" ) )
  157. foundM2 = true;
  158. if( strstr( line, "*" ) )
  159. foundStar = true;
  160. /* look for X<number> or Y<number> */
  161. if( ( letter = strstr( line, "X" ) ) != nullptr )
  162. {
  163. if( isdigit( letter[1] ) )
  164. foundX = true;
  165. }
  166. if( ( letter = strstr( line, "Y" ) ) != nullptr )
  167. {
  168. if( isdigit( letter[1] ) )
  169. foundY = true;
  170. }
  171. }
  172. }
  173. catch( IO_ERROR& )
  174. {
  175. return false;
  176. }
  177. // RS-274X
  178. if( ( foundD0 || foundD2 || foundM0 || foundM2 ) && foundADD && foundStar
  179. && ( foundX || foundY ) )
  180. {
  181. return true;
  182. }
  183. // RS-274D. Could be folded into the expression above, but someday
  184. // we might want to test for them separately.
  185. else if( ( foundD0 || foundD2 || foundM0 || foundM2 ) && !foundADD && foundStar
  186. && ( foundX || foundY ) )
  187. {
  188. return true;
  189. }
  190. return false;
  191. }
  192. // A large buffer to store one line
  193. char GERBER_FILE_IMAGE::m_LineBuffer[GERBER_BUFZ+1];
  194. bool GERBER_FILE_IMAGE::LoadGerberFile( const wxString& aFullFileName )
  195. {
  196. int G_command = 0; // command number for G commands like G04
  197. int D_commande = 0; // command number for D commands like D02
  198. char* text;
  199. ClearMessageList( );
  200. ResetDefaultValues();
  201. // Read the gerber file */
  202. m_Current_File = wxFopen( aFullFileName, wxT( "rt" ) );
  203. if( m_Current_File == nullptr )
  204. return false;
  205. m_FileName = aFullFileName;
  206. wxString msg;
  207. while( true )
  208. {
  209. if( fgets( m_LineBuffer, GERBER_BUFZ, m_Current_File ) == nullptr )
  210. break;
  211. m_LineNum++;
  212. text = StrPurge( m_LineBuffer );
  213. while( text && *text )
  214. {
  215. switch( *text )
  216. {
  217. case ' ':
  218. case '\r':
  219. case '\n':
  220. text++;
  221. break;
  222. case '*': // End command
  223. m_CommandState = END_BLOCK;
  224. text++;
  225. break;
  226. case 'M': // End file
  227. m_CommandState = CMD_IDLE;
  228. while( *text )
  229. text++;
  230. break;
  231. case 'G': /* Line type Gxx : command */
  232. G_command = CodeNumber( text );
  233. Execute_G_Command( text, G_command );
  234. break;
  235. case 'D': /* Line type Dxx : Tool selection (xx > 0) or
  236. * command if xx = 0..9 */
  237. D_commande = CodeNumber( text );
  238. Execute_DCODE_Command( text, D_commande );
  239. break;
  240. case 'X':
  241. case 'Y': /* Move or draw command */
  242. m_CurrentPos = ReadXYCoord( text );
  243. if( *text == '*' ) // command like X12550Y19250*
  244. {
  245. Execute_DCODE_Command( text, m_Last_Pen_Command );
  246. }
  247. break;
  248. case 'I':
  249. case 'J': /* Auxiliary Move command */
  250. m_IJPos = ReadIJCoord( text );
  251. if( *text == '*' ) // command like X35142Y15945J504*
  252. {
  253. Execute_DCODE_Command( text, m_Last_Pen_Command );
  254. }
  255. break;
  256. case '%':
  257. if( m_CommandState != ENTER_RS274X_CMD )
  258. {
  259. m_CommandState = ENTER_RS274X_CMD;
  260. ReadRS274XCommand( m_LineBuffer, GERBER_BUFZ, text );
  261. }
  262. else //Error
  263. {
  264. AddMessageToList( wxT( "Expected RS274X Command" ) );
  265. m_CommandState = CMD_IDLE;
  266. text++;
  267. }
  268. break;
  269. default:
  270. msg.Printf( wxT( "Unexpected char 0x%2.2X (%c)" ), *text, *text );
  271. AddMessageToList( msg );
  272. text++;
  273. break;
  274. }
  275. }
  276. }
  277. fclose( m_Current_File );
  278. m_InUse = true;
  279. return true;
  280. }