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