33#include <wx/filename.h>
42 const uint64_t FNV_PRIME = 0x00000100000001B3ULL;
43 const uint64_t FNV_OFFSET = 0xcbf29ce484222325ULL;
46 uint64_t hash1 = FNV_OFFSET;
47 uint64_t hash2 = FNV_OFFSET;
49 std::string salt1 =
"PADS1:" + aIdentifier;
53 hash1 ^=
static_cast<uint8_t
>( c );
57 std::string salt2 =
"PADS2:" + aIdentifier;
61 hash2 ^=
static_cast<uint8_t
>( c );
66 std::ostringstream ss;
67 ss << std::hex << std::setfill(
'0' );
69 ss << std::setw( 8 ) << ( hash1 >> 32 );
72 ss << std::setw( 4 ) << ( ( hash1 >> 16 ) & 0xFFFF );
76 uint16_t version = ( ( hash1 & 0xFFFF ) & 0x0FFF ) | 0x4000;
77 ss << std::setw( 4 ) << version;
81 uint16_t variant = ( ( hash2 >> 48 ) & 0x3FFF ) | 0x8000;
82 ss << std::setw( 4 ) << variant;
85 ss << std::setw( 12 ) << ( hash2 & 0xFFFFFFFFFFFFULL );
87 return KIID( ss.str() );
93 std::ifstream file( aFilePath.fn_str() );
100 if( !std::getline( file, line ) )
105 if( line.rfind(
"*PADS-POWERPCB", 0 ) == 0
106 || line.rfind(
"!PADS-POWERPCB", 0 ) == 0 )
109 if( line.rfind(
"*PADS2000", 0 ) == 0
110 || line.rfind(
"!PADS2000", 0 ) == 0 )
113 if( line.rfind(
"*PADS-POWERLOGIC", 0 ) == 0
114 || line.rfind(
"!PADS-POWERLOGIC", 0 ) == 0 )
117 if( line.rfind(
"*PADS-LOGIC", 0 ) == 0
118 || line.rfind(
"!PADS-LOGIC", 0 ) == 0 )
129 wxFileName sourceFn( aFilePath );
131 if( !sourceFn.IsOk() || !sourceFn.FileExists() )
140 result.pcbFile = aFilePath;
142 result.schematicFile = aFilePath;
144 wxString sourceDir = sourceFn.GetPath();
145 wxString sourceBase = sourceFn.GetName();
147 wxDir dir( sourceDir );
149 if( !dir.IsOpened() )
152 static const std::vector<wxString> extensions = { wxS(
"asc" ), wxS(
"ASC" ), wxS(
"txt" ),
156 bool cont = dir.GetFirst( &filename );
160 wxFileName candidateFn( sourceDir, filename );
161 wxString candidatePath = candidateFn.GetFullPath();
163 if( candidatePath == aFilePath )
165 cont = dir.GetNext( &filename );
169 wxString ext = candidateFn.GetExt().Lower();
170 bool validExt =
false;
172 for(
const wxString& validExtension : extensions )
174 if( ext == validExtension.Lower() )
183 cont = dir.GetNext( &filename );
187 bool matchingBase = ( candidateFn.GetName() == sourceBase );
194 if( matchingBase ||
result.schematicFile.IsEmpty() )
196 result.schematicFile = candidatePath;
201 cont = dir.GetNext( &filename );
209 if( matchingBase ||
result.pcbFile.IsEmpty() )
211 result.pcbFile = candidatePath;
216 cont = dir.GetNext( &filename );
222 cont = dir.GetNext( &filename );
228int ParseInt(
const std::string& aStr,
int aDefault,
const std::string& aContext )
232 return std::stoi( aStr );
234 catch(
const std::exception& )
236 if( !aContext.empty() )
238 wxLogTrace( wxT(
"PADS" ), wxT(
"Parse error in %s: '%s' is not a valid integer" ),
239 wxString::FromUTF8( aContext ), wxString::FromUTF8( aStr ) );
247double ParseDouble(
const std::string& aStr,
double aDefault,
const std::string& aContext )
251 return std::stod( aStr );
253 catch(
const std::exception& )
255 if( !aContext.empty() )
257 wxLogTrace( wxT(
"PADS" ), wxT(
"Parse error in %s: '%s' is not a valid number" ),
258 wxString::FromUTF8( aContext ), wxString::FromUTF8( aStr ) );
268 if( aNetName.empty() )
271 if( aNetName[0] ==
'/' )
272 return wxT(
"~{" ) +
ConvertText( aNetName.substr( 1 ) ) + wxT(
"}" );
285 wxString
result = wxString::FromUTF8( aText.data(), aText.size() );
289 wxCSConv cp1252( wxFONTENCODING_CP1252 );
290 result = wxString( aText.data(), cp1252, aText.size() );
294 result = wxString( aText.data(), wxConvISO8859_1, aText.size() );
303 int8_t s =
static_cast<int8_t
>( aPadsStyle & 0xFF );
325 if( aJustification >= 8 )
328 hCode = aJustification - 8;
330 else if( aJustification >= 2 )
333 hCode = aJustification - 2;
338 hCode = aJustification;
359int PadsScaleCoord(
double aVal,
bool aIsX,
double aOriginX,
double aOriginY,
double aScaleFactor )
361 double origin = aIsX ? aOriginX : aOriginY;
363 long long origin_nm =
static_cast<long long>( std::round( origin * aScaleFactor ) );
364 long long val_nm =
static_cast<long long>( std::round( aVal * aScaleFactor ) );
366 long long result = aIsX ? ( val_nm - origin_nm ) : ( origin_nm - val_nm );
368 return static_cast<int>( std::clamp<long long>(
result, std::numeric_limits<int>::min(),
369 std::numeric_limits<int>::max() ) );
Common utilities and types for parsing PADS file formats, shared by the PCB and schematic importers.
void DecodeJustification(int aJustification, GR_TEXT_H_ALIGN_T &aHJustify, GR_TEXT_V_ALIGN_T &aVJustify)
Decode a PADS text justification code into KiCad horizontal and vertical alignment.
int PadsScaleCoord(double aVal, bool aIsX, double aOriginX, double aOriginY, double aScaleFactor)
Map a PADS board coordinate to a KiCad internal coordinate.
RELATED_FILES FindRelatedPadsFiles(const wxString &aFilePath)
Find the related PADS project file (schematic for a PCB source, or vice versa) in the same directory,...
int ParseInt(const std::string &aStr, int aDefault, const std::string &aContext)
Parse integer from string with error context.
wxString ConvertText(const std::string &aText)
Decode text from a PADS file, which uses an 8-bit codepage rather than UTF-8.
PADS_FILE_TYPE DetectPadsFileType(const wxString &aFilePath)
Detect the type of a PADS file by examining its header.
wxString ConvertInvertedNetName(const std::string &aNetName)
Convert a PADS net name to KiCad notation.
LINE_STYLE PadsLineStyleToKiCad(int aPadsStyle)
Convert a PADS line style integer to a KiCad LINE_STYLE enum value.
KIID GenerateDeterministicUuid(const std::string &aIdentifier)
Generate a deterministic KIID from a PADS component identifier.
double ParseDouble(const std::string &aStr, double aDefault, const std::string &aContext)
Parse double from string with error context.
LINE_STYLE
Dashed line types.
wxString result
Test unit parsing edge cases and error handling.
GR_TEXT_H_ALIGN_T
This is API surface mapped to common.types.HorizontalAlignment.
GR_TEXT_V_ALIGN_T
This is API surface mapped to common.types.VertialAlignment.