Altium schematic parser: Add fraction pin placement
In the schematic libaries, pin positions that are off 10mil spacing need fractional elements stored in a different location
This commit is contained in:
parent
35d60598d5
commit
439c25fca9
|
@ -26,6 +26,7 @@
|
||||||
#include "altium_parser_utils.h"
|
#include "altium_parser_utils.h"
|
||||||
|
|
||||||
#include <compoundfilereader.h>
|
#include <compoundfilereader.h>
|
||||||
|
#include <charconv>
|
||||||
#include <ki_exception.h>
|
#include <ki_exception.h>
|
||||||
#include <math/util.h>
|
#include <math/util.h>
|
||||||
#include <numeric>
|
#include <numeric>
|
||||||
|
@ -204,7 +205,7 @@ ALTIUM_COMPOUND_FILE::FindStreamSingleLevel( const CFB::COMPOUND_FILE_ENTRY* aEn
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
std::map<wxString, const CFB::COMPOUND_FILE_ENTRY*>
|
std::map<wxString, ALTIUM_SYMBOL_DATA>
|
||||||
ALTIUM_COMPOUND_FILE::GetLibSymbols( const CFB::COMPOUND_FILE_ENTRY* aStart ) const
|
ALTIUM_COMPOUND_FILE::GetLibSymbols( const CFB::COMPOUND_FILE_ENTRY* aStart ) const
|
||||||
{
|
{
|
||||||
const CFB::COMPOUND_FILE_ENTRY* root = aStart ? aStart : m_reader->GetRootEntry();
|
const CFB::COMPOUND_FILE_ENTRY* root = aStart ? aStart : m_reader->GetRootEntry();
|
||||||
|
@ -212,7 +213,7 @@ ALTIUM_COMPOUND_FILE::GetLibSymbols( const CFB::COMPOUND_FILE_ENTRY* aStart ) co
|
||||||
if( !root )
|
if( !root )
|
||||||
return {};
|
return {};
|
||||||
|
|
||||||
std::map<wxString, const CFB::COMPOUND_FILE_ENTRY*> folders;
|
std::map<wxString, ALTIUM_SYMBOL_DATA> folders;
|
||||||
|
|
||||||
m_reader->EnumFiles( root, 1, [&]( const CFB::COMPOUND_FILE_ENTRY* tentry, const CFB::utf16string&, int ) -> int
|
m_reader->EnumFiles( root, 1, [&]( const CFB::COMPOUND_FILE_ENTRY* tentry, const CFB::utf16string&, int ) -> int
|
||||||
{
|
{
|
||||||
|
@ -227,7 +228,16 @@ ALTIUM_COMPOUND_FILE::GetLibSymbols( const CFB::COMPOUND_FILE_ENTRY* aStart ) co
|
||||||
std::wstring fileName = UTF16ToWstring( entry->name, entry->nameLen );
|
std::wstring fileName = UTF16ToWstring( entry->name, entry->nameLen );
|
||||||
|
|
||||||
if( m_reader->IsStream( entry ) && fileName == L"Data" )
|
if( m_reader->IsStream( entry ) && fileName == L"Data" )
|
||||||
folders[dirName] = entry;
|
folders[dirName].m_symbol = entry;
|
||||||
|
|
||||||
|
if( m_reader->IsStream( entry ) && fileName == L"PinFrac" )
|
||||||
|
folders[dirName].m_pinsFrac = entry;
|
||||||
|
|
||||||
|
if( m_reader->IsStream( entry ) && fileName == L"PinWideText" )
|
||||||
|
folders[dirName].m_pinsWideText = entry;
|
||||||
|
|
||||||
|
if( m_reader->IsStream( entry ) && fileName == L"PinTextData" )
|
||||||
|
folders[dirName].m_pinsTextData = entry;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
} );
|
} );
|
||||||
|
@ -420,7 +430,7 @@ std::map<wxString, wxString> ALTIUM_BINARY_PARSER::ReadProperties(
|
||||||
// Both the 'l' and the null-byte are missing, which looks like Altium swallowed two bytes.
|
// Both the 'l' and the null-byte are missing, which looks like Altium swallowed two bytes.
|
||||||
bool hasNullByte = m_pos[length - 1] == '\0';
|
bool hasNullByte = m_pos[length - 1] == '\0';
|
||||||
|
|
||||||
if( !hasNullByte )
|
if( !hasNullByte && !isBinary )
|
||||||
{
|
{
|
||||||
wxLogError( _( "Missing null byte at end of property list. Imported data might be "
|
wxLogError( _( "Missing null byte at end of property list. Imported data might be "
|
||||||
"malformed or missing." ) );
|
"malformed or missing." ) );
|
||||||
|
@ -500,5 +510,4 @@ std::map<wxString, wxString> ALTIUM_BINARY_PARSER::ReadProperties(
|
||||||
}
|
}
|
||||||
|
|
||||||
return kv;
|
return kv;
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,17 +27,17 @@
|
||||||
|
|
||||||
#include "altium_props_utils.h"
|
#include "altium_props_utils.h"
|
||||||
|
|
||||||
|
#include <charconv>
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <numeric>
|
#include <numeric>
|
||||||
|
#include <string>
|
||||||
|
#include <stdexcept>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
#include <wx/mstream.h>
|
#include <wx/mstream.h>
|
||||||
#include <wx/zstream.h>
|
#include <wx/zstream.h>
|
||||||
#include <math/vector2d.h>
|
#include <math/vector2d.h>
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
#include <string>
|
|
||||||
#include <stdexcept>
|
|
||||||
|
|
||||||
namespace CFB
|
namespace CFB
|
||||||
{
|
{
|
||||||
|
@ -53,6 +53,16 @@ struct COMPOUND_FILE_ENTRY;
|
||||||
std::string FormatPath( const std::vector<std::string>& aVectorPath );
|
std::string FormatPath( const std::vector<std::string>& aVectorPath );
|
||||||
|
|
||||||
|
|
||||||
|
class ALTIUM_SYMBOL_DATA
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
const CFB::COMPOUND_FILE_ENTRY* m_symbol;
|
||||||
|
const CFB::COMPOUND_FILE_ENTRY* m_pinsFrac;
|
||||||
|
const CFB::COMPOUND_FILE_ENTRY* m_pinsWideText;
|
||||||
|
const CFB::COMPOUND_FILE_ENTRY* m_pinsTextData;
|
||||||
|
const CFB::COMPOUND_FILE_ENTRY* m_pinsSymbolLineWidth;
|
||||||
|
};
|
||||||
|
|
||||||
class ALTIUM_COMPOUND_FILE
|
class ALTIUM_COMPOUND_FILE
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
@ -94,7 +104,7 @@ public:
|
||||||
|
|
||||||
std::map<wxString, const CFB::COMPOUND_FILE_ENTRY*> EnumDir( const std::wstring& aDir ) const;
|
std::map<wxString, const CFB::COMPOUND_FILE_ENTRY*> EnumDir( const std::wstring& aDir ) const;
|
||||||
|
|
||||||
std::map<wxString, const CFB::COMPOUND_FILE_ENTRY*> GetLibSymbols( const CFB::COMPOUND_FILE_ENTRY* aStart ) const;
|
std::map<wxString, ALTIUM_SYMBOL_DATA> GetLibSymbols( const CFB::COMPOUND_FILE_ENTRY* aStart ) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
@ -359,7 +369,7 @@ public:
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string ReadPascalString()
|
std::string ReadShortPascalString()
|
||||||
{
|
{
|
||||||
uint8_t length = ReadByte();
|
uint8_t length = ReadByte();
|
||||||
|
|
||||||
|
@ -371,6 +381,18 @@ public:
|
||||||
return pascalString;
|
return pascalString;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string ReadFullPascalString()
|
||||||
|
{
|
||||||
|
uint32_t length = ReadInt32();
|
||||||
|
|
||||||
|
if( m_position + length > m_data.size() )
|
||||||
|
throw std::out_of_range( "ALTIUM_BINARY_READER: out of range" );
|
||||||
|
|
||||||
|
std::string pascalString( &m_data[m_position], &m_data[m_position + length] );
|
||||||
|
m_position += length;
|
||||||
|
return pascalString;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const std::string& m_data;
|
const std::string& m_data;
|
||||||
size_t m_position;
|
size_t m_position;
|
||||||
|
@ -382,31 +404,28 @@ public:
|
||||||
ALTIUM_COMPRESSED_READER( const std::string& aData ) : ALTIUM_BINARY_READER( aData )
|
ALTIUM_COMPRESSED_READER( const std::string& aData ) : ALTIUM_BINARY_READER( aData )
|
||||||
{}
|
{}
|
||||||
|
|
||||||
std::pair<int, std::string> ReadCompressedString()
|
std::pair<int, std::string*> ReadCompressedString()
|
||||||
{
|
{
|
||||||
std::string result;
|
std::string* result;
|
||||||
int id = -1;
|
int id = -1;
|
||||||
|
|
||||||
while( true )
|
uint8_t byte = ReadByte();
|
||||||
{
|
if( byte != 0xD0 )
|
||||||
uint8_t byte = ReadByte();
|
throw std::runtime_error( "ALTIUM_COMPRESSED_READER: invalid compressed string" );
|
||||||
if( byte != 0xD0 )
|
|
||||||
throw std::runtime_error( "ALTIUM_COMPRESSED_READER: invalid compressed string" );
|
|
||||||
|
|
||||||
std::string str = ReadPascalString();
|
std::string str = ReadShortPascalString();
|
||||||
|
std::from_chars( str.data(), str.data() + str.size(), id );
|
||||||
|
|
||||||
id = std::stoi( str );
|
std::string data = ReadFullPascalString();
|
||||||
|
result = decompressData( data );
|
||||||
std::string data = ReadPascalString();
|
|
||||||
|
|
||||||
result = decompressData( data );
|
|
||||||
}
|
|
||||||
|
|
||||||
return std::make_pair( id, result );
|
return std::make_pair( id, result );
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::string decompressData( std::string& aData )
|
std::string decompressedData;
|
||||||
|
|
||||||
|
std::string* decompressData( std::string& aData )
|
||||||
{
|
{
|
||||||
// Create a memory input stream with the buffer
|
// Create a memory input stream with the buffer
|
||||||
wxMemoryInputStream memStream( (void*) aData.data(), aData.length() );
|
wxMemoryInputStream memStream( (void*) aData.data(), aData.length() );
|
||||||
|
@ -414,9 +433,6 @@ private:
|
||||||
// Create a zlib input stream with the memory input stream
|
// Create a zlib input stream with the memory input stream
|
||||||
wxZlibInputStream zStream( memStream );
|
wxZlibInputStream zStream( memStream );
|
||||||
|
|
||||||
// Prepare a string to hold decompressed data
|
|
||||||
std::string decompressedData;
|
|
||||||
|
|
||||||
// Read decompressed data from the zlib input stream
|
// Read decompressed data from the zlib input stream
|
||||||
while( !zStream.Eof() )
|
while( !zStream.Eof() )
|
||||||
{
|
{
|
||||||
|
@ -426,7 +442,7 @@ private:
|
||||||
decompressedData.append( buffer, bytesRead );
|
decompressedData.append( buffer, bytesRead );
|
||||||
}
|
}
|
||||||
|
|
||||||
return decompressedData;
|
return &decompressedData;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -4278,15 +4278,54 @@ std::map<wxString,LIB_SYMBOL*> SCH_IO_ALTIUM::ParseLibFile( const ALTIUM_COMPOUN
|
||||||
{
|
{
|
||||||
std::map<wxString,LIB_SYMBOL*> ret;
|
std::map<wxString,LIB_SYMBOL*> ret;
|
||||||
std::vector<int> fontSizes;
|
std::vector<int> fontSizes;
|
||||||
|
struct SYMBOL_PIN_FRAC
|
||||||
|
{
|
||||||
|
int x_frac;
|
||||||
|
int y_frac;
|
||||||
|
int len_frac;
|
||||||
|
};
|
||||||
|
|
||||||
ParseLibHeader( aAltiumLibFile, fontSizes );
|
ParseLibHeader( aAltiumLibFile, fontSizes );
|
||||||
|
|
||||||
std::map<wxString, const CFB::COMPOUND_FILE_ENTRY*> syms = aAltiumLibFile.GetLibSymbols( nullptr );
|
std::map<wxString, ALTIUM_SYMBOL_DATA> syms = aAltiumLibFile.GetLibSymbols( nullptr );
|
||||||
|
|
||||||
for( auto& [name, entry] : syms )
|
for( auto& [name, entry] : syms )
|
||||||
{
|
{
|
||||||
ALTIUM_BINARY_PARSER reader( aAltiumLibFile, entry );
|
|
||||||
|
std::map<int, SYMBOL_PIN_FRAC> pinFracs;
|
||||||
|
|
||||||
|
if( entry.m_pinsFrac )
|
||||||
|
{
|
||||||
|
auto parse_binary_pin_frac =
|
||||||
|
[&]( const std::string& binaryData ) -> std::map<wxString, wxString>
|
||||||
|
{
|
||||||
|
std::map<wxString, wxString> result;
|
||||||
|
ALTIUM_COMPRESSED_READER cmpreader( binaryData );
|
||||||
|
|
||||||
|
std::pair<int, std::string*> pinFracData = cmpreader.ReadCompressedString();
|
||||||
|
|
||||||
|
ALTIUM_BINARY_READER binreader( *pinFracData.second );
|
||||||
|
SYMBOL_PIN_FRAC pinFrac;
|
||||||
|
|
||||||
|
pinFrac.x_frac = binreader.ReadInt32();
|
||||||
|
pinFrac.y_frac = binreader.ReadInt32();
|
||||||
|
pinFrac.len_frac = binreader.ReadInt32();
|
||||||
|
pinFracs.insert( { pinFracData.first, pinFrac } );
|
||||||
|
|
||||||
|
return result;
|
||||||
|
};
|
||||||
|
|
||||||
|
ALTIUM_BINARY_PARSER reader( aAltiumLibFile, entry.m_pinsFrac );
|
||||||
|
|
||||||
|
while( reader.GetRemainingBytes() > 0 )
|
||||||
|
{
|
||||||
|
reader.ReadProperties( parse_binary_pin_frac );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ALTIUM_BINARY_PARSER reader( aAltiumLibFile, entry.m_symbol );
|
||||||
std::vector<LIB_SYMBOL*> symbols;
|
std::vector<LIB_SYMBOL*> symbols;
|
||||||
|
int pin_index = 0;
|
||||||
|
|
||||||
if( reader.GetRemainingBytes() <= 0 )
|
if( reader.GetRemainingBytes() <= 0 )
|
||||||
{
|
{
|
||||||
|
@ -4304,10 +4343,9 @@ std::map<wxString,LIB_SYMBOL*> SCH_IO_ALTIUM::ParseLibFile( const ALTIUM_COMPOUN
|
||||||
symbols = ParseLibComponent( properties );
|
symbols = ParseLibComponent( properties );
|
||||||
}
|
}
|
||||||
|
|
||||||
auto handleBinaryDataLambda =
|
auto handleBinaryPinLambda =
|
||||||
[]( const std::string& binaryData ) -> std::map<wxString, wxString>
|
[&]( const std::string& binaryData ) -> std::map<wxString, wxString>
|
||||||
{
|
{
|
||||||
|
|
||||||
std::map<wxString, wxString> result;
|
std::map<wxString, wxString> result;
|
||||||
|
|
||||||
ALTIUM_BINARY_READER binreader( binaryData );
|
ALTIUM_BINARY_READER binreader( binaryData );
|
||||||
|
@ -4325,7 +4363,7 @@ std::map<wxString,LIB_SYMBOL*> SCH_IO_ALTIUM::ParseLibFile( const ALTIUM_COMPOUN
|
||||||
result["SYMBOL_OUTEREDGE"] = wxString::Format( "%d", binreader.ReadByte() );
|
result["SYMBOL_OUTEREDGE"] = wxString::Format( "%d", binreader.ReadByte() );
|
||||||
result["SYMBOL_INNER"] = wxString::Format( "%d", binreader.ReadByte() );
|
result["SYMBOL_INNER"] = wxString::Format( "%d", binreader.ReadByte() );
|
||||||
result["SYMBOL_OUTER"] = wxString::Format( "%d", binreader.ReadByte() );
|
result["SYMBOL_OUTER"] = wxString::Format( "%d", binreader.ReadByte() );
|
||||||
result["TEXT"] = binreader.ReadPascalString();
|
result["TEXT"] = binreader.ReadShortPascalString();
|
||||||
binreader.ReadByte(); // unknown
|
binreader.ReadByte(); // unknown
|
||||||
result["ELECTRICAL"] = wxString::Format( "%d", binreader.ReadByte() );
|
result["ELECTRICAL"] = wxString::Format( "%d", binreader.ReadByte() );
|
||||||
result["PINCONGLOMERATE"] = wxString::Format( "%d", binreader.ReadByte() );
|
result["PINCONGLOMERATE"] = wxString::Format( "%d", binreader.ReadByte() );
|
||||||
|
@ -4333,12 +4371,19 @@ std::map<wxString,LIB_SYMBOL*> SCH_IO_ALTIUM::ParseLibFile( const ALTIUM_COMPOUN
|
||||||
result["LOCATION.X"] = wxString::Format( "%d", binreader.ReadInt16() );
|
result["LOCATION.X"] = wxString::Format( "%d", binreader.ReadInt16() );
|
||||||
result["LOCATION.Y"] = wxString::Format( "%d", binreader.ReadInt16() );
|
result["LOCATION.Y"] = wxString::Format( "%d", binreader.ReadInt16() );
|
||||||
result["COLOR"] = wxString::Format( "%d", binreader.ReadInt32() );
|
result["COLOR"] = wxString::Format( "%d", binreader.ReadInt32() );
|
||||||
result["NAME"] = binreader.ReadPascalString();
|
result["NAME"] = binreader.ReadShortPascalString();
|
||||||
result["DESIGNATOR"] = binreader.ReadPascalString();
|
result["DESIGNATOR"] = binreader.ReadShortPascalString();
|
||||||
result["SWAPIDGROUP"] = binreader.ReadPascalString();
|
result["SWAPIDGROUP"] = binreader.ReadShortPascalString();
|
||||||
|
|
||||||
|
|
||||||
std::string partSeq = binreader.ReadPascalString(); // This is 'part|&|seq'
|
if( auto it = pinFracs.find( pin_index ); it != pinFracs.end() )
|
||||||
|
{
|
||||||
|
result["LOCATION.X_FRAC"] = wxString::Format( "%d", it->second.x_frac );
|
||||||
|
result["LOCATION.Y_FRAC"] = wxString::Format( "%d", it->second.y_frac );
|
||||||
|
result["PINLENGTH_FRAC"] = wxString::Format( "%d", it->second.len_frac );
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string partSeq = binreader.ReadShortPascalString(); // This is 'part|&|seq'
|
||||||
std::vector<std::string> partSeqSplit = split( partSeq, "|" );
|
std::vector<std::string> partSeqSplit = split( partSeq, "|" );
|
||||||
|
|
||||||
if( partSeqSplit.size() == 3 )
|
if( partSeqSplit.size() == 3 )
|
||||||
|
@ -4352,7 +4397,7 @@ std::map<wxString,LIB_SYMBOL*> SCH_IO_ALTIUM::ParseLibFile( const ALTIUM_COMPOUN
|
||||||
|
|
||||||
while( reader.GetRemainingBytes() > 0 )
|
while( reader.GetRemainingBytes() > 0 )
|
||||||
{
|
{
|
||||||
std::map<wxString, wxString> properties = reader.ReadProperties( handleBinaryDataLambda );
|
std::map<wxString, wxString> properties = reader.ReadProperties( handleBinaryPinLambda );
|
||||||
|
|
||||||
if( properties.empty() )
|
if( properties.empty() )
|
||||||
continue;
|
continue;
|
||||||
|
@ -4362,7 +4407,12 @@ std::map<wxString,LIB_SYMBOL*> SCH_IO_ALTIUM::ParseLibFile( const ALTIUM_COMPOUN
|
||||||
|
|
||||||
switch( record )
|
switch( record )
|
||||||
{
|
{
|
||||||
case ALTIUM_SCH_RECORD::PIN: ParsePin( properties, symbols ); break;
|
case ALTIUM_SCH_RECORD::PIN:
|
||||||
|
{
|
||||||
|
ParsePin( properties, symbols );
|
||||||
|
pin_index++;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case ALTIUM_SCH_RECORD::LABEL: ParseLabel( properties, symbols, fontSizes ); break;
|
case ALTIUM_SCH_RECORD::LABEL: ParseLabel( properties, symbols, fontSizes ); break;
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue