KiCad PCB EDA Suite
Loading...
Searching...
No Matches
easyedapro_import_utils.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) 2023 Alex Shvartzkop <[email protected]>
5 * Copyright (C) 2023 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
26#include "easyedapro_parser.h"
27
29
30#include <ki_exception.h>
31#include <string_utils.h>
32#include <json_common.h>
34
35#include <wx/log.h>
36#include <wx/stream.h>
37#include <wx/zipstrm.h>
38#include <wx/wfstream.h>
39#include <wx/mstream.h>
40#include <wx/txtstrm.h>
41
42
43wxString EASYEDAPRO::ShortenLibName( wxString aProjectName )
44{
45 wxString shortenedName = aProjectName;
46 shortenedName.Replace( wxS( "ProProject_" ), wxS( "" ) );
47 shortenedName.Replace( wxS( "ProDocument_" ), wxS( "" ) );
48 shortenedName = shortenedName.substr( 0, 10 );
49
50 return LIB_ID::FixIllegalChars( shortenedName + wxS( "-easyedapro" ), true );
51}
52
53
54LIB_ID EASYEDAPRO::ToKiCadLibID( const wxString& aLibName, const wxString& aLibReference )
55{
56 wxString libName = LIB_ID::FixIllegalChars( aLibName, true );
57 wxString libReference = EscapeString( aLibReference, CTX_LIBID );
58
59 wxString key = !aLibName.empty() ? ( aLibName + ':' + libReference ) : libReference;
60
61 LIB_ID libId;
62 libId.Parse( key, true );
63
64 return libId;
65}
66
67
68std::vector<IMPORT_PROJECT_DESC>
69EASYEDAPRO::ProjectToSelectorDialog( const nlohmann::json& aProject, bool aPcbOnly, bool aSchOnly )
70{
71 std::vector<IMPORT_PROJECT_DESC> result;
72
73 std::map<wxString, EASYEDAPRO::PRJ_SCHEMATIC> prjSchematics = aProject.at( "schematics" );
74 std::map<wxString, EASYEDAPRO::PRJ_BOARD> prjBoards = aProject.at( "boards" );
75 std::map<wxString, wxString> prjPcbNames = aProject.at( "pcbs" );
76
77 for( const auto& [prjName, board] : prjBoards )
78 {
80 desc.ComboName = desc.ComboId = prjName;
81 desc.PCBId = board.pcb;
82 desc.SchematicId = board.schematic;
83
84 auto pcbNameIt = prjPcbNames.find( desc.PCBId );
85 if( pcbNameIt != prjPcbNames.end() )
86 {
87 desc.PCBName = pcbNameIt->second;
88
89 if( desc.PCBName.empty() )
90 desc.PCBName = pcbNameIt->first;
91
92 prjPcbNames.erase( pcbNameIt );
93 }
94
95 auto schIt = prjSchematics.find( desc.SchematicId );
96 if( schIt != prjSchematics.end() )
97 {
98 desc.SchematicName = schIt->second.name;
99
100 if( desc.SchematicName.empty() )
101 desc.SchematicName = schIt->first;
102
103 prjSchematics.erase( schIt );
104 }
105
106 result.emplace_back( desc );
107 }
108
109 if( !aSchOnly )
110 {
111 for( const auto& [pcbId, pcbName] : prjPcbNames )
112 {
114 desc.PCBId = pcbId;
115 desc.PCBName = pcbName;
116
117 if( desc.PCBName.empty() )
118 desc.PCBName = pcbId;
119
120 result.emplace_back( desc );
121 }
122 }
123
124 if( !aPcbOnly )
125 {
126 for( const auto& [schId, schData] : prjSchematics )
127 {
129 desc.SchematicId = schId;
130 desc.SchematicName = schData.name;
131
132 if( desc.SchematicName.empty() )
133 desc.SchematicName = schId;
134
135 result.emplace_back( desc );
136 }
137 }
138
139 return result;
140}
141
142
143nlohmann::json EASYEDAPRO::ReadProjectOrDeviceFile( const wxString& aZipFileName )
144{
145 std::shared_ptr<wxZipEntry> entry;
146 wxFFileInputStream in( aZipFileName );
147 wxZipInputStream zip( in );
148
149 while( entry.reset( zip.GetNextEntry() ), entry.get() != NULL )
150 {
151 wxString name = entry->GetName();
152
153 try
154 {
155 if( name == wxS( "project.json" ) || name == wxS( "device.json" ) )
156 {
157 wxMemoryOutputStream memos;
158 memos << zip;
159 wxStreamBuffer* buf = memos.GetOutputStreamBuffer();
160
161 wxString str =
162 wxString::FromUTF8( (char*) buf->GetBufferStart(), buf->GetBufferSize() );
163
164 return nlohmann::json::parse( str );
165 }
166 }
167 catch( nlohmann::json::exception& e )
168 {
170 wxString::Format( _( "JSON error reading '%s': %s" ), name, e.what() ) );
171 }
172 catch( std::exception& e )
173 {
174 THROW_IO_ERROR( wxString::Format( _( "Error reading '%s': %s" ), name, e.what() ) );
175 }
176 }
177
178 THROW_IO_ERROR( wxString::Format(
179 _( "'%s' does not appear to be a valid EasyEDA (JLCEDA) Pro "
180 "project or library file. Cannot find project.json or device.json." ),
181 aZipFileName ) );
182}
183
184
186 const wxString& aFileName,
187 std::function<bool( const wxString&, const wxString&, wxInputStream& )> aCallback )
188{
189 std::shared_ptr<wxZipEntry> entry;
190 wxFFileInputStream in( aFileName );
191 wxZipInputStream zip( in );
192
193 if( !zip.IsOk() )
194 {
195 THROW_IO_ERROR( wxString::Format( _( "Cannot read ZIP archive '%s'" ), aFileName ) );
196 }
197
198 while( entry.reset( zip.GetNextEntry() ), entry.get() != NULL )
199 {
200 wxString name = entry->GetName();
201 wxString baseName = name.AfterLast( '\\' ).AfterLast( '/' ).BeforeFirst( '.' );
202
203 try
204 {
205 if( aCallback( name, baseName, zip ) )
206 break;
207 }
208 catch( nlohmann::json::exception& e )
209 {
211 wxString::Format( _( "JSON error reading '%s': %s" ), name, e.what() ) );
212 }
213 catch( std::exception& e )
214 {
215 THROW_IO_ERROR( wxString::Format( _( "Error reading '%s': %s" ), name, e.what() ) );
216 }
217 }
218}
219
220
221std::vector<nlohmann::json> EASYEDAPRO::ParseJsonLines( wxInputStream& aInput,
222 const wxString& aSource )
223{
224 wxTextInputStream txt( aInput, wxS( " " ), wxConvUTF8 );
225
226 int currentLine = 1;
227
228 std::vector<nlohmann::json> lines;
229 while( aInput.CanRead() )
230 {
231 try
232 {
233 nlohmann::json js = nlohmann::json::parse( txt.ReadLine() );
234 lines.emplace_back( js );
235 }
236 catch( nlohmann::json::exception& e )
237 {
238 wxLogWarning( wxString::Format( _( "Cannot parse JSON line %d in '%s': %s" ),
239 currentLine, aSource, e.what() ) );
240 }
241
242 currentLine++;
243 }
244
245 return lines;
246}
const char * name
Definition: DXF_plotter.cpp:57
A logical library item identifier and consists of various portions much like a URI.
Definition: lib_id.h:49
int Parse(const UTF8 &aId, bool aFix=false)
Parse LIB_ID with the information from aId.
Definition: lib_id.cpp:51
static UTF8 FixIllegalChars(const UTF8 &aLibItemName, bool aLib)
Replace illegal LIB_ID item name characters with underscores '_'.
Definition: lib_id.cpp:191
#define _(s)
#define THROW_IO_ERROR(msg)
Definition: ki_exception.h:39
LIB_ID ToKiCadLibID(const wxString &aLibName, const wxString &aLibReference)
void IterateZipFiles(const wxString &aFileName, std::function< bool(const wxString &, const wxString &, wxInputStream &)> aCallback)
std::vector< nlohmann::json > ParseJsonLines(wxInputStream &aInput, const wxString &aSource)
std::vector< IMPORT_PROJECT_DESC > ProjectToSelectorDialog(const nlohmann::json &aProject, bool aPcbOnly=false, bool aSchOnly=false)
nlohmann::json ReadProjectOrDeviceFile(const wxString &aZipFileName)
wxString ShortenLibName(wxString aProjectName)
wxString EscapeString(const wxString &aSource, ESCAPE_CONTEXT aContext)
The Escape/Unescape routines use HTML-entity-reference-style encoding to handle characters which are:...
@ CTX_LIBID
Definition: string_utils.h:54
Describes how non-KiCad boards and schematics should be imported as KiCad projects.