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.

247 lines
6.9 KiB

  1. /*
  2. * This program source code file is part of KiCad, a free EDA CAD application.
  3. *
  4. * Copyright (C) 2007-2019 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. /**
  25. * @file job_file_reader.cpp
  26. */
  27. #include <nlohmann/json.hpp>
  28. #include <wx/filename.h>
  29. #include <wildcards_and_files_ext.h>
  30. #include <gerbview.h>
  31. #include <richio.h>
  32. #include <locale_io.h>
  33. #include <string_utils.h>
  34. #include <gerber_file_image.h>
  35. #include <gerber_file_image_list.h>
  36. #include <gerbview_frame.h>
  37. #include <reporter.h>
  38. #include <gbr_metadata.h>
  39. #include <dialogs/html_message_box.h>
  40. #include <view/view.h>
  41. #include <wx/filedlg.h>
  42. using json = nlohmann::json;
  43. /**
  44. * this class read and parse a Gerber job file to extract useful info
  45. * for GerbView
  46. *
  47. * In a gerber job file, old (deprecated) format, data lines start by
  48. * %TF. (usual Gerber X2 info)
  49. * %TJ.B. (board info)
  50. * %TJ.D. (design info)
  51. * %TJ.L. (layers info)
  52. * some others are not yet handled by Kicad
  53. * M02* is the last line
  54. * In a gerber job file, JSON format, first lines are
  55. * {
  56. * "Header":
  57. * and the block ( a JSON array) containing the filename of files to load is
  58. * "FilesAttributes":
  59. * [
  60. * {
  61. * "Path": "interf_u-Composant.gbr",
  62. * "FileFunction": "Copper,L1,Top",
  63. * "FilePolarity": "Positive"
  64. * },
  65. * {
  66. * "Path": "interf_u-In1.Cu.gbr",
  67. * "FileFunction": "Copper,L2,Inr",
  68. * "FilePolarity": "Positive"
  69. * },
  70. * ],
  71. */
  72. class GERBER_JOBFILE_READER
  73. {
  74. public:
  75. GERBER_JOBFILE_READER( const wxString& aFileName, REPORTER* aReporter )
  76. {
  77. m_filename = aFileName;
  78. m_reporter = aReporter;
  79. }
  80. ~GERBER_JOBFILE_READER() {}
  81. bool ReadGerberJobFile(); /// read a .gbrjob file
  82. wxArrayString& GetGerberFiles() { return m_GerberFiles; }
  83. private:
  84. REPORTER* m_reporter;
  85. wxFileName m_filename;
  86. wxArrayString m_GerberFiles; // List of gerber files in job
  87. // Convert a JSON string, that uses escaped sequence of 4 hexadecimal digits
  88. // to encode unicode chars when not ASCII7 codes
  89. // json11 converts this sequence to UTF8 string
  90. wxString formatStringFromJSON( const std::string& name );
  91. };
  92. bool GERBER_JOBFILE_READER::ReadGerberJobFile()
  93. {
  94. // Read the gerber file */
  95. FILE* jobFile = wxFopen( m_filename.GetFullPath(), wxT( "rt" ) );
  96. if( jobFile == nullptr )
  97. return false;
  98. LOCALE_IO toggleIo;
  99. FILE_LINE_READER jobfileReader( jobFile, m_filename.GetFullPath() ); // Will close jobFile
  100. wxString data;
  101. // detect the file format: old (deprecated) gerber format of official JSON format
  102. bool json_format = false;
  103. char* line = jobfileReader.ReadLine();
  104. if( !line ) // end of file
  105. return false;
  106. data = line;
  107. if( data.Contains( wxT( "{" ) ) )
  108. json_format = true;
  109. if( json_format )
  110. {
  111. while( ( line = jobfileReader.ReadLine() ) != nullptr )
  112. data << '\n' << line;
  113. try
  114. {
  115. json js = json::parse( TO_UTF8( data ) );
  116. for( json& entry : js["FilesAttributes"] )
  117. {
  118. std::string name = entry["Path"].get<std::string>();
  119. m_GerberFiles.Add( formatStringFromJSON( name ) );
  120. }
  121. }
  122. catch( ... )
  123. {
  124. return false;
  125. }
  126. }
  127. else
  128. {
  129. if( m_reporter )
  130. m_reporter->ReportTail( _( "This job file uses an outdated format. Please recreate it." ),
  131. RPT_SEVERITY_WARNING );
  132. return false;
  133. }
  134. return true;
  135. }
  136. wxString GERBER_JOBFILE_READER::formatStringFromJSON( const std::string& name )
  137. {
  138. // Convert a JSON string, that uses a escaped sequence of 4 hexadecimal digits
  139. // to encode unicode chars
  140. // Our json11 library returns in this case a UTF8 sequence. Just convert it to
  141. // a wxString.
  142. wxString wstr = From_UTF8( name.c_str() );
  143. return wstr;
  144. }
  145. bool GERBVIEW_FRAME::LoadGerberJobFile( const wxString& aFullFileName )
  146. {
  147. wxFileName filename = aFullFileName;
  148. wxString currentPath;
  149. bool success = true;
  150. if( !filename.IsOk() )
  151. {
  152. // Use the current working directory if the file name path does not exist.
  153. if( filename.DirExists() )
  154. currentPath = filename.GetPath();
  155. else
  156. currentPath = m_mruPath;
  157. wxFileDialog dlg( this, _( "Open Gerber Job File" ),
  158. currentPath,
  159. filename.GetFullName(),
  160. FILEEXT::GerberJobFileWildcard(),
  161. wxFD_OPEN | wxFD_FILE_MUST_EXIST | wxFD_CHANGE_DIR );
  162. if( dlg.ShowModal() == wxID_CANCEL )
  163. return false;
  164. filename = dlg.GetPath();
  165. currentPath = filename.GetPath();
  166. m_mruPath = currentPath;
  167. }
  168. else
  169. {
  170. currentPath = filename.GetPath();
  171. m_mruPath = currentPath;
  172. }
  173. WX_STRING_REPORTER reporter;
  174. if( filename.IsOk() )
  175. {
  176. GERBER_JOBFILE_READER gbjReader( filename.GetFullPath(), &reporter );
  177. if( gbjReader.ReadGerberJobFile() )
  178. {
  179. // Update the list of recent drill files.
  180. UpdateFileHistory( filename.GetFullPath(), &m_jobFileHistory );
  181. Clear_DrawLayers( false );
  182. ClearMsgPanel();
  183. wxArrayString& gbrfiles = gbjReader.GetGerberFiles();
  184. // 0 = Gerber file type
  185. std::vector<int> fileTypesVec( gbrfiles.Count(), 0 );
  186. success = LoadListOfGerberAndDrillFiles( currentPath, gbrfiles, &fileTypesVec );
  187. Zoom_Automatique( false );
  188. }
  189. }
  190. SortLayersByX2Attributes();
  191. if( reporter.HasMessage() )
  192. {
  193. wxSafeYield(); // Allows slice of time to redraw the screen
  194. // to refresh widgets, before displaying messages
  195. HTML_MESSAGE_BOX mbox( this, _( "Messages" ) );
  196. mbox.ListSet( reporter.GetMessages() );
  197. mbox.ShowModal();
  198. }
  199. return success;
  200. }