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.

340 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 (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. #include "ki_exception.h"
  25. #include <string_utils.h>
  26. #include <locale_io.h>
  27. #include <gerbview.h>
  28. #include <gerbview_frame.h>
  29. #include <gerber_file_image.h>
  30. #include <gerber_file_image_list.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. // size of a single line of text from a gerber file.
  193. // warning: some files can have *very long* lines, so the buffer must be large.
  194. #define GERBER_BUFZ 1000000
  195. // A large buffer to store one line
  196. static char lineBuffer[GERBER_BUFZ+1];
  197. bool GERBER_FILE_IMAGE::LoadGerberFile( const wxString& aFullFileName )
  198. {
  199. int G_command = 0; // command number for G commands like G04
  200. int D_commande = 0; // command number for D commands like D02
  201. char* text;
  202. ClearMessageList( );
  203. ResetDefaultValues();
  204. // Read the gerber file */
  205. m_Current_File = wxFopen( aFullFileName, wxT( "rt" ) );
  206. if( m_Current_File == nullptr )
  207. return false;
  208. m_FileName = aFullFileName;
  209. LOCALE_IO toggleIo;
  210. wxString msg;
  211. while( true )
  212. {
  213. if( fgets( lineBuffer, GERBER_BUFZ, m_Current_File ) == nullptr )
  214. break;
  215. m_LineNum++;
  216. text = StrPurge( lineBuffer );
  217. while( text && *text )
  218. {
  219. switch( *text )
  220. {
  221. case ' ':
  222. case '\r':
  223. case '\n':
  224. text++;
  225. break;
  226. case '*': // End command
  227. m_CommandState = END_BLOCK;
  228. text++;
  229. break;
  230. case 'M': // End file
  231. m_CommandState = CMD_IDLE;
  232. while( *text )
  233. text++;
  234. break;
  235. case 'G': /* Line type Gxx : command */
  236. G_command = CodeNumber( text );
  237. Execute_G_Command( text, G_command );
  238. break;
  239. case 'D': /* Line type Dxx : Tool selection (xx > 0) or
  240. * command if xx = 0..9 */
  241. D_commande = CodeNumber( text );
  242. Execute_DCODE_Command( text, D_commande );
  243. break;
  244. case 'X':
  245. case 'Y': /* Move or draw command */
  246. m_CurrentPos = ReadXYCoord( text );
  247. if( *text == '*' ) // command like X12550Y19250*
  248. {
  249. Execute_DCODE_Command( text, m_Last_Pen_Command );
  250. }
  251. break;
  252. case 'I':
  253. case 'J': /* Auxiliary Move command */
  254. m_IJPos = ReadIJCoord( text );
  255. if( *text == '*' ) // command like X35142Y15945J504*
  256. {
  257. Execute_DCODE_Command( text, m_Last_Pen_Command );
  258. }
  259. break;
  260. case '%':
  261. if( m_CommandState != ENTER_RS274X_CMD )
  262. {
  263. m_CommandState = ENTER_RS274X_CMD;
  264. ReadRS274XCommand( lineBuffer, GERBER_BUFZ, text );
  265. }
  266. else //Error
  267. {
  268. AddMessageToList( wxT( "Expected RS274X Command" ) );
  269. m_CommandState = CMD_IDLE;
  270. text++;
  271. }
  272. break;
  273. default:
  274. msg.Printf( wxT( "Unexpected char 0x%2.2X" ), *text );
  275. AddMessageToList( msg );
  276. text++;
  277. break;
  278. }
  279. }
  280. }
  281. fclose( m_Current_File );
  282. m_InUse = true;
  283. return true;
  284. }