33#include <wx/filename.h>
77static int ReadInt4At(
const uint8_t* aData,
size_t aPos )
79 uint32_t raw = (
static_cast<uint32_t
>( aData[aPos] ) << 24 )
80 | (
static_cast<uint32_t
>( aData[aPos + 1] ) << 16 )
81 | (
static_cast<uint32_t
>( aData[aPos + 2] ) << 8 )
82 |
static_cast<uint32_t
>( aData[aPos + 3] );
83 return static_cast<int>(
static_cast<int64_t
>( raw ) -
INT4_BIAS );
112 return static_cast<int>(
static_cast<int64_t
>( aDipTraceCoord ) / 3 );
122 return static_cast<int>(
static_cast<int64_t
>( aDipTraceCoord ) / 3 );
128 return static_cast<int>(
static_cast<int64_t
>(
std::abs( aDipTraceCoord ) ) / 3 );
137 const uint8_t* data =
m_reader.GetData();
138 size_t fileSize =
m_reader.GetFileSize();
140 auto rdInt4 = [&](
size_t o ) ->
int
142 uint32_t raw = (
static_cast<uint32_t
>( data[o] ) << 24 ) | (
static_cast<uint32_t
>( data[o + 1] ) << 16 )
143 | (
static_cast<uint32_t
>( data[o + 2] ) << 8 ) |
static_cast<uint32_t
>( data[o + 3] );
144 return static_cast<int>(
static_cast<int64_t
>( raw ) -
INT4_BIAS );
150 static constexpr int UNITS_PER_MM = 30000;
152 for(
size_t o = 0; o + 24 <= fileSize; o++ )
155 int h = rdInt4( o + 4 );
157 if( w <= 0 || h <= 0 || ( w % UNITS_PER_MM ) != 0 || ( h % UNITS_PER_MM ) != 0 )
160 int wmm = w / UNITS_PER_MM;
161 int hmm = h / UNITS_PER_MM;
163 if( wmm < 50 || wmm > 2000 || hmm < 50 || hmm > 2000 )
166 int margins[4] = { rdInt4( o + 8 ), rdInt4( o + 12 ), rdInt4( o + 16 ), rdInt4( o + 20 ) };
167 bool sane = margins[0] > 0;
169 for(
int m : margins )
171 if( m < 0 || ( m % UNITS_PER_MM ) != 0 || m / UNITS_PER_MM > 100 )
201 wxString libName =
m_schematic->Project().GetProjectName();
203 if( libName.IsEmpty() )
206 libName = fn.GetName();
209 if( libName.IsEmpty() )
210 libName = wxT(
"noname" );
212 libName += wxT(
"-diptrace-import" );
244 size_t compSectionStart =
m_reader.GetOffset();
246 bool hasBusSection =
false;
278 catch(
const std::exception& e )
280 THROW_IO_ERRORF(
_(
"DipTrace import: unexpected error at offset 0x%06zX: %s" ),
281 m_reader.GetOffset(), wxString::FromUTF8( e.what() ) );
290 uint8_t magicLen =
m_reader.ReadByte();
292 if( magicLen != 7 && magicLen != 11 )
293 THROW_IO_ERRORF(
_(
"Invalid DipTrace schematic magic length: %d (expected 7 or 11)." ), (
int) magicLen );
295 std::vector<uint8_t> magicBuf( magicLen );
296 m_reader.ReadBytes( magicBuf.data(), magicLen );
298 if( memcmp( magicBuf.data(),
"DTSCHEM", 7 ) != 0 )
299 THROW_IO_ERROR(
_(
"Invalid DipTrace schematic file: bad magic header." ) );
309 const uint8_t* suffix = magicBuf.data() + 7;
311 if( !std::isdigit( suffix[0] ) || suffix[1] !=
'.' || !std::isdigit( suffix[2] ) || !std::isdigit( suffix[3] ) )
313 THROW_IO_ERROR(
_(
"Invalid DipTrace schematic file: bad legacy version suffix." ) );
317 m_version = ( suffix[2] -
'0' ) * 10 + ( suffix[3] -
'0' );
345 for(
int i = 0; i < 5; i++ )
359 uint8_t extraHdr[4] = {};
362 uint32_t extraChars = (
static_cast<uint32_t
>( extraHdr[0] ) << 24 )
363 | (
static_cast<uint32_t
>( extraHdr[1] ) << 16 )
364 | (
static_cast<uint32_t
>( extraHdr[2] ) << 8 ) | extraHdr[3];
368 if( extraChars > 0 && extraChars < 1000 )
369 m_reader.Skip(
static_cast<size_t>( extraChars ) * 2 );
384 int numStyles =
m_reader.ReadInt3();
386 if( numStyles < 0 || numStyles > 2000 )
389 for(
int i = 0; i < numStyles; i++ )
416 for(
int i = 0; i < 5; i++ )
435 for(
int i = 0; i < 5; i++ )
449 const uint8_t* data =
m_reader.GetData();
450 size_t fileSize =
m_reader.GetFileSize();
452 static const uint8_t marker[] = { 0x3B, 0x9A, 0xF1, 0x10, 0x3B, 0x9A, 0xF1, 0x10, 0x00, 0x00 };
453 static constexpr size_t markerLen =
sizeof( marker );
455 if( aSearchStart + markerLen + 3 >= fileSize )
458 for(
size_t off = aSearchStart; off < fileSize - markerLen - 3; off++ )
460 if( memcmp( data + off, marker, markerLen ) == 0 )
462 int count = ( ( data[off + 10] << 16 ) | ( data[off + 11] << 8 ) | data[off + 12] ) -
INT3_BIAS;
464 if( count >= 0 && count <= 1000 )
467 if( count > 1000 && count <= 10000 )
478 const uint8_t* data =
m_reader.GetData();
479 size_t fileSize =
m_reader.GetFileSize();
484 size_t off = fileSize - 3;
488 if( data[off] == 0x0F && data[off + 1] == 0x42 && data[off + 2] == 0x40 )
494 size_t tailStart = off + 3;
495 size_t tailCount = ( fileSize - tailStart ) / 3;
497 return ( tailCount > 1 ) ? tailStart : fileSize;
508 std::vector<size_t> boundaries;
510 size_t off = aFirstComp;
511 size_t end = ( aBusSectionOffset > 20 ) ? aBusSectionOffset - 20 : 0;
517 boundaries.push_back( off );
532 const uint8_t* data =
m_reader.GetData();
533 size_t fileSize =
m_reader.GetFileSize();
537 if( aOffset + 19 > fileSize )
540 int z1 = ( ( data[aOffset + 6] << 16 ) | ( data[aOffset + 7] << 8 ) | data[aOffset + 8] ) -
INT3_BIAS;
541 int z2 = ( ( data[aOffset + 9] << 16 ) | ( data[aOffset + 10] << 8 ) | data[aOffset + 11] ) -
INT3_BIAS;
543 if( z1 != 0 || z2 != 0 )
548 if( w < 0 || w > 200000 )
551 int npts = ( ( data[aOffset + 16] << 16 ) | ( data[aOffset + 17] << 8 ) | data[aOffset + 18] ) -
INT3_BIAS;
553 return npts >= 1 && npts <= 100;
557 if( aOffset + 17 > fileSize )
560 if( data[aOffset + 6] != 0 || data[aOffset + 7] != 0 || data[aOffset + 8] != 0 || data[aOffset + 9] != 0 )
567 if( w < 0 || w > 200000 )
570 int npts = ( ( data[aOffset + 14] << 16 ) | ( data[aOffset + 15] << 8 ) | data[aOffset + 16] ) -
INT3_BIAS;
572 return npts >= 1 && npts <= 100;
582 const uint8_t* data =
m_reader.GetData();
583 size_t fileSize =
m_reader.GetFileSize();
585 static constexpr uint8_t
TAHOMA_FONT_PATTERN[] = { 0x00, 0x06, 0x00, 0x54, 0x00, 0x61, 0x00,
586 0x68, 0x00, 0x6f, 0x00, 0x6d, 0x00, 0x61 };
588 if( aOffset + 29 > fileSize )
591 int sentinel = ( ( data[aOffset] << 16 ) | ( data[aOffset + 1] << 8 ) | data[aOffset + 2] ) -
INT3_BIAS;
592 int shapeField = ( ( data[aOffset + 3] << 16 ) | ( data[aOffset + 4] << 8 ) | data[aOffset + 5] ) -
INT3_BIAS;
594 if( sentinel != 1000000 || shapeField != 0 )
602 if( data[aOffset + 20] != 0 || data[aOffset + 21] != 0 )
605 int lineWidth =
ReadInt4At( data, aOffset + 22 );
607 if( lineWidth < 0 || lineWidth > 200000 )
610 int numPoints = ( ( data[aOffset + 26] << 16 ) | ( data[aOffset + 27] << 8 ) | data[aOffset + 28] ) -
INT3_BIAS;
612 return numPoints >= 1 && numPoints <= 100;
618 size_t compSectionStart =
m_reader.GetOffset();
629 bool desynced =
false;
633 size_t compStart =
m_reader.GetOffset();
640 catch(
const std::exception& )
646 if(
m_reader.GetOffset() <= compStart )
657 m_reader.SetOffset( compSectionStart );
667 for(
size_t ci = 0; ci < compStarts.size(); ci++ )
669 size_t compEnd = ( ci + 1 < compStarts.size() ) ? compStarts[ci + 1] : aBusSectionOffset;
673 m_reader.SetOffset( compStarts[ci] );
680 catch(
const std::exception& e )
682 THROW_IO_ERRORF(
_(
"DipTrace import: failed to parse component %zu at offset 0x%06zX: %s" ),
683 ci, compStarts[ci], wxString::FromUTF8( e.what() ) );
689 THROW_IO_ERRORF(
_(
"DipTrace import: found %zu components, but the file header declares %d." ),
697 static bool s_dumpComponents = std::getenv(
"KICAD_DIPTRACE_DUMP_COMPONENTS" ) !=
nullptr;
698 static bool s_dumpComponentDetail = std::getenv(
"KICAD_DIPTRACE_DUMP_COMPONENT_DETAIL" ) !=
nullptr;
710 size_t componentCeiling = aCompEnd > 0 ? aCompEnd :
m_reader.GetFileSize();
714 for(
size_t p =
comp.fileOffset + 16; p < componentCeiling; p++ )
718 componentCeiling = p;
724 auto dumpDetail = [&](
const wxString& aMsg )
728 m_reporter->Report( wxString::Format( wxT(
"DipTrace SCH detail @0x%06zX: %s" ),
comp.fileOffset, aMsg ),
743 dumpDetail( wxString::Format( wxT(
"hdr end=0x%06zX name='%s' ref='%s' value='%s' prefix='%s'" ),
752 if( s_dumpComponentDetail )
754 dumpDetail( wxString::Format( wxT(
"post-hdr end=0x%06zX postA=%d postB=%d flag1=%d "
755 "postC=%d postD=%d" ),
756 m_reader.GetOffset(), postA, postB, flag1, postC, postD ) );
763 comp.isMultiPart = ( pb1 == 1 );
766 int partFieldB =
m_reader.ReadInt3();
767 int partFieldC =
m_reader.ReadInt3();
768 int partBboxX1 =
m_reader.ReadInt4();
769 int partBboxY1 =
m_reader.ReadInt4();
770 int partBboxX2 =
m_reader.ReadInt4();
771 int partBboxY2 =
m_reader.ReadInt4();
774 wxString partTailStr;
776 if(
comp.isMultiPart )
779 partTailStr =
comp.partId;
785 size_t partTailStart =
m_reader.GetOffset();
791 if( partTailInt > 0 && partTailInt < 256 )
793 size_t strStart = partTailStart + 3;
794 size_t strEnd = strStart +
static_cast<size_t>( partTailInt );
795 const uint8_t* data =
m_reader.GetData();
796 size_t fileSize =
m_reader.GetFileSize();
798 if( strEnd + 3 <= fileSize )
800 bool asciiPayload =
true;
802 for(
size_t i = strStart; i < strEnd; i++ )
806 if( c < 0x20 || c > 0x7E )
808 asciiPayload =
false;
816 ( ( data[strEnd] << 16 ) | ( data[strEnd + 1] << 8 ) | data[strEnd + 2] ) -
INT3_BIAS;
818 if( nextInt3 >= -1 && nextInt3 < 1000 )
820 m_reader.SetOffset( partTailStart );
821 partTailStr =
m_reader.ReadString();
837 dumpDetail( wxString::Format( wxT(
"part end=0x%06zX part='%s' partNum='%s' sheet=%d "
838 "isMulti=%d partFieldB=%d partFieldC=%d "
839 "partBBox=[%d,%d,%d,%d] fieldD=%d fieldE=%d" ),
841 comp.isMultiPart ? 1 : 0, partFieldB, partFieldC, partBboxX1, partBboxY1, partBboxX2,
842 partBboxY2, fieldD, fieldE ) );
846 dumpDetail( wxString::Format( wxT(
"part-tail end=0x%06zX partTailInt=%d partTailStr='%s'" ),
847 m_reader.GetOffset(), partTailInt, partTailStr ) );
853 if( fieldE >= 1 && fieldE < 1000 )
855 comp.additionalFields.reserve( fieldE );
857 for(
int i = 0; i < fieldE; i++ )
859 wxString fieldName =
m_reader.ReadString();
860 wxString fieldValue =
m_reader.ReadString();
863 if( !fieldName.IsEmpty() )
864 comp.additionalFields.emplace_back( fieldName, fieldValue );
881 size_t tailAfterB =
m_reader.GetOffset();
882 wxString tailStrA =
m_reader.ReadString();
883 wxString extraTail = wxEmptyString;
889 bool simpleModernTail =
false;
919 if( s_dumpComponentDetail )
921 dumpDetail( wxString::Format( wxT(
"pre-pin-hdr end=0x%06zX fieldF=%d fieldG=%d "
922 "byte4=%d rotE4=%d libPath='%s' tailA=%d tailB=%d "
923 "tailStrA='%s' pinMetaA=%d pinMetaF=%d pinMetaB=%d "
926 tailA, tailB, tailStrA, pinMetaA, pinMetaF, pinMetaB, numPins ) );
931 bool usedPinSeparatorFallback =
false;
933 auto readModernExtraAndPins = [&]( wxString& aExtraTail,
int& aNumPins,
int& aPinHdr,
934 bool& aUsedPinSeparatorFallback ) ->
bool
936 size_t extraStart =
m_reader.GetOffset();
937 uint8_t extraHdr[4] = {};
940 uint32_t extraChars = (
static_cast<uint32_t
>( extraHdr[0] ) << 24 )
941 | (
static_cast<uint32_t
>( extraHdr[1] ) << 16 )
942 | (
static_cast<uint32_t
>( extraHdr[2] ) << 8 ) | extraHdr[3];
944 if( extraChars >= 10000 && extraHdr[0] == 0 && extraHdr[1] == 0 )
946 THROW_IO_ERRORF(
_(
"DipTrace import: invalid component extra-tail length %u at offset 0x%06zX." ),
947 extraChars, extraStart );
952 size_t extraBytes =
static_cast<size_t>( extraChars ) * 2;
953 bool fitsFile =
m_reader.GetOffset() + extraBytes <=
m_reader.GetFileSize();
955 if( extraChars < 10000 && fitsFile &&
m_reader.GetOffset() + extraBytes <= componentCeiling )
957 wxMBConvUTF16BE conv;
958 aExtraTail = wxString(
reinterpret_cast<const char*
>(
m_reader.GetData() +
m_reader.GetOffset() ),
962 else if( extraChars < 10000 && fitsFile )
987 size_t pinStart =
m_reader.GetOffset();
992 if( ( aNumPins < 0 || aNumPins > 500 ) && pinStart + 6 <=
m_reader.GetFileSize() )
999 if( sepPins >= 0 && sepPins <= 500 )
1003 aUsedPinSeparatorFallback =
true;
1007 m_reader.SetOffset( pinStart + 4 );
1019 bool usedTaillessFallback =
false;
1020 bool canonicalPinSeparatorFallback =
false;
1021 bool readCanonicalPins =
1022 readModernExtraAndPins( extraTail, numPins, pinHdrByte, canonicalPinSeparatorFallback );
1023 usedPinSeparatorFallback = canonicalPinSeparatorFallback;
1025 if( !readCanonicalPins || ( numPins < 0 || numPins > 500 ) )
1027 size_t canonicalEnd =
m_reader.GetOffset();
1028 wxString canonicalTailStrA = tailStrA;
1029 wxString canonicalExtraTail = extraTail;
1030 int canonicalNumPins = numPins;
1031 int canonicalPinHdrByte = pinHdrByte;
1036 tailStrA = wxEmptyString;
1037 extraTail = wxEmptyString;
1040 usedTaillessFallback =
true;
1042 bool fallbackPinSeparatorFallback =
false;
1043 bool readFallbackPins =
1044 readModernExtraAndPins( extraTail, numPins, pinHdrByte, fallbackPinSeparatorFallback );
1046 if( readFallbackPins && numPins >= 0 && numPins <= 500 )
1048 usedPinSeparatorFallback = fallbackPinSeparatorFallback;
1052 m_reader.SetOffset( canonicalEnd );
1053 tailStrA = canonicalTailStrA;
1054 extraTail = canonicalExtraTail;
1055 numPins = canonicalNumPins;
1056 pinHdrByte = canonicalPinHdrByte;
1057 usedTaillessFallback =
false;
1058 usedPinSeparatorFallback = canonicalPinSeparatorFallback;
1062 if( s_dumpComponentDetail )
1064 dumpDetail( wxString::Format( wxT(
"pre-pin-hdr end=0x%06zX fieldF=%d fieldG=%d "
1065 "byte4=%d rotE4=%d libPath='%s' tailA=%d tailB=%d "
1066 "tailStrA='%s' extraTail='%s' numPins=%d pinHdr=%d "
1067 "taillessFallback=%d pinSeparatorFallback=%d" ),
1068 m_reader.GetOffset(), fieldF, fieldG, byte4,
comp.rotationE4,
comp.libPath,
1069 tailA, tailB, tailStrA, extraTail, numPins, pinHdrByte,
1070 usedTaillessFallback ? 1 : 0, usedPinSeparatorFallback ? 1 : 0 ) );
1073 simpleModernTail = tailA == 0 && tailB == 0 && tailStrA.IsEmpty() && extraTail.IsEmpty()
1074 && !usedTaillessFallback && !usedPinSeparatorFallback;
1079 comp.datasheet = extraTail;
1082 dumpDetail( wxString::Format( wxT(
"pre-pin end=0x%06zX numPins=%d" ),
m_reader.GetOffset(), numPins ) );
1084 if( numPins < 0 || numPins > 500 )
1086 if( aUseCompEnd && !simpleModernTail )
1093 THROW_IO_ERRORF(
_(
"Invalid pin count %d at component offset 0x%06zX." ), numPins,
comp.fileOffset );
1096 for(
int pinIdx = 0; pinIdx < numPins; pinIdx++ )
1098 auto consumeLaterPinSeparatorIfPresent = [&]() ->
bool
1103 size_t start =
m_reader.GetOffset();
1105 if( start + 2 >= componentCeiling )
1108 const uint8_t* data =
m_reader.GetData();
1110 if( data[start] != 0 || data[start + 1] != 0 )
1113 bool currentRecordValid =
false;
1120 currentRecordValid =
m_reader.GetOffset() <= componentCeiling;
1122 catch(
const std::exception& )
1124 currentRecordValid =
false;
1129 if( currentRecordValid )
1132 bool shiftedRecordValid =
false;
1139 shiftedRecordValid =
m_reader.GetOffset() <= componentCeiling;
1141 catch(
const std::exception& )
1143 shiftedRecordValid =
false;
1148 if( !shiftedRecordValid )
1155 if( consumeLaterPinSeparatorIfPresent() )
1156 simpleModernTail =
false;
1162 catch(
const std::exception& e )
1164 if( aUseCompEnd && !simpleModernTail )
1167 THROW_IO_ERRORF(
_(
"DipTrace import: failed to parse pin %d in component at 0x%06zX (offset 0x%06zX): %s" ),
1168 pinIdx,
comp.fileOffset,
m_reader.GetOffset(), wxString::FromUTF8( e.what() ) );
1176 auto readShapePointCountIfHeaderPrefix = [&](
size_t aOffset,
int& aPointCount ) ->
bool
1178 const uint8_t* data =
m_reader.GetData();
1179 size_t fileSize =
m_reader.GetFileSize();
1180 size_t limit = std::min( fileSize, aCompEnd );
1182 if( aOffset + 17 > limit )
1185 if( data[aOffset + 6] != 0 || data[aOffset + 7] != 0 || data[aOffset + 8] != 0 || data[aOffset + 9] != 0 )
1190 int width =
ReadInt4At( data, aOffset + 10 );
1192 if( width < 0 || width > 200000 )
1195 aPointCount = ( ( data[aOffset + 14] << 16 ) | ( data[aOffset + 15] << 8 ) | data[aOffset + 16] ) -
INT3_BIAS;
1207 while(
m_reader.GetOffset() + 6 < componentCeiling )
1209 size_t markOff =
m_reader.GetOffset();
1210 const uint8_t* mdata =
m_reader.GetData();
1212 if( mdata[markOff] != 0 || mdata[markOff + 1] != 0 || mdata[markOff + 2] != 0 )
1215 int markType = ( ( mdata[markOff + 3] << 16 ) | ( mdata[markOff + 4] << 8 )
1216 | mdata[markOff + 5] )
1219 if( markType < 1 || markType > 3 )
1250 if(
m_reader.GetOffset() > componentCeiling )
1256 if( mark.
type == 2 || mark.
type == 3 )
1257 comp.texts.push_back( mark );
1259 catch(
const std::exception& )
1266 while(
m_reader.GetOffset() < aCompEnd &&
m_reader.GetOffset() < componentCeiling )
1268 size_t shapeOffset =
m_reader.GetOffset();
1269 int shapePointCount = 0;
1278 catch(
const std::exception& )
1286 if(
m_version >=
V31_CUTOVER && readShapePointCountIfHeaderPrefix( shapeOffset, shapePointCount )
1287 && ( shapePointCount < 1 || shapePointCount > 100 ) )
1289 THROW_IO_ERRORF(
_(
"DipTrace import: invalid component shape point count %d at offset 0x%06zX." ),
1290 shapePointCount, shapeOffset );
1302 catch(
const std::exception& )
1325 const uint8_t* data =
m_reader.GetData();
1326 size_t lim = std::min( componentCeiling > 0 ? componentCeiling :
m_reader.GetFileSize(),
1328 size_t lo = (
save > 24 ) ?
save - 24 : 0;
1330 for(
size_t probe = lo; probe + 6 < lim && probe <=
save + 4; probe++ )
1332 if( data[probe] != 0 || data[probe + 1] != 0 || data[probe + 2] != 0 )
1343 if(
vt.type != 2 &&
vt.type != 3 )
1348 if(
vt.fontName.IsEmpty() ||
vt.fontName.size() > 64 )
1353 if(
vt.text.IsEmpty() ||
vt.text.size() > 256 )
1361 bool haveType =
false;
1364 haveType = haveType || ( t.
type ==
vt.type );
1368 comp.texts.push_back(
vt );
1372 catch(
const std::exception& )
1385 size_t afterFirstPattern =
m_reader.GetOffset();
1388 if(
m_reader.GetOffset() == afterFirstPattern )
1389 m_reader.SetOffset( afterFirstPattern );
1392 catch(
const std::exception& e )
1394 if( s_dumpComponentDetail )
1396 dumpDetail( wxString::Format( wxT(
"pattern parse failed at 0x%06zX: %s" ),
m_reader.GetOffset(),
1397 wxString::FromUTF8( e.what() ) ) );
1401 size_t parsedEnd =
m_reader.GetOffset();
1403 if( s_dumpComponentDetail )
1405 dumpDetail( wxString::Format( wxT(
"post-pattern end=0x%06zX pins=%zu shapes=%zu "
1407 parsedEnd,
comp.pins.size(),
comp.shapes.size(),
comp.patternName ) );
1409 if( aUseCompEnd && parsedEnd < aCompEnd )
1411 dumpDetail( wxString::Format( wxT(
"tail skipped=%zu bytes to compEnd=0x%06zX" ), aCompEnd - parsedEnd,
1420 else if(
m_reader.GetOffset() != componentCeiling
1426 m_reader.SetOffset( componentCeiling );
1433 m_reporter->Report( wxString::Format( wxT(
"DipTrace SCH comp @0x%06zX ref='%s' name='%s' "
1434 "sheet=%d pins=%zu shapes=%zu pattern='%s'" ),
1436 comp.pins.size(),
comp.shapes.size(),
comp.patternName ),
1445 pin.index = aPinIndex;
1447 if( aPinIndex == 0 )
1449 pin.hasHeader =
true;
1502 size_t midTailStart =
m_reader.GetOffset();
1503 const uint8_t* data =
m_reader.GetData();
1505 if( midTailStart + 5 <=
m_reader.GetFileSize() && data[midTailStart] == 0 && data[midTailStart + 1] == 0 )
1540 size_t headerStart =
m_reader.GetOffset();
1542 if( headerStart >= 6 )
1544 const uint8_t* data =
m_reader.GetData();
1545 shape.
kindCode = ( ( data[headerStart - 6] << 16 ) | ( data[headerStart - 5] << 8 ) | data[headerStart - 4] )
1547 shape.
kindFlag = ( ( data[headerStart - 3] << 16 ) | ( data[headerStart - 2] << 8 ) | data[headerStart - 1] )
1565 int numPoints =
m_reader.ReadInt3();
1567 if( numPoints < 1 || numPoints > 100 )
1570 for(
int i = 0; i < numPoints; i++ )
1588 aComp.
shapes.push_back( shape );
1606 int numPoints =
m_reader.ReadInt3();
1608 if( numPoints < 1 || numPoints > 100 )
1611 for(
int i = 0; i < numPoints; i++ )
1626 aComp.
shapes.push_back( shape );
1632 size_t startOffset =
m_reader.GetOffset();
1633 const uint8_t* data =
m_reader.GetData();
1634 size_t limit = std::min( aCompEnd > 0 ? aCompEnd :
m_reader.GetFileSize(),
m_reader.GetFileSize() );
1636 if( startOffset + 6 > limit || data[startOffset] != 0 || data[startOffset + 1] != 0 || data[startOffset + 2] != 0 )
1642 ( ( data[startOffset + 3] << 16 ) | ( data[startOffset + 4] << 8 ) | data[startOffset + 5] ) -
INT3_BIAS;
1644 if( fieldType < 0 || fieldType > 100 )
1656 if(
text.fontName.IsEmpty() ||
text.fontName.size() > 128 ||
text.text.size() > 512 )
1657 throw std::runtime_error(
"invalid component text field string" );
1675 throw std::runtime_error(
"component text field overruns component" );
1677 catch(
const std::exception& )
1690 size_t startOffset =
m_reader.GetOffset();
1736 if( fieldA < 0 || fieldA > 500 )
1758 for(
int i = 0; i < fieldA; i++ )
1777 if( fieldB < 0 || fieldB > 1000 )
1787 for(
int i = 0; i < fieldB; i++ )
1789 if( i == fieldB - 1 )
1810 size_t patternCeiling = std::min( aCompEnd > 0 ? aCompEnd :
m_reader.GetFileSize(),
m_reader.GetFileSize() );
1812 for(
size_t p = startOffset + 16; p < patternCeiling; p++ )
1825 auto landingForCeiling = [&]() ->
size_t
1830 return patternCeiling;
1838 const uint8_t* data =
m_reader.GetData();
1839 size_t limit = patternCeiling;
1841 if( startOffset + 63 <= limit && data[startOffset] == 0 && data[startOffset + 1] == 0 )
1843 size_t tailEnd = startOffset + 63;
1852 for(
size_t pos = startOffset; pos + 2 <= limit; pos++ )
1854 int charCount = ( data[pos] << 8 ) | data[pos + 1];
1856 if( charCount < 0 || charCount > 512 )
1859 size_t strEnd = pos + 2 +
static_cast<size_t>( charCount ) * 2;
1861 if( strEnd > limit )
1866 for(
size_t i = pos + 2; i < strEnd; i += 2 )
1868 if( data[i] != 0x00 || data[i + 1] < 0x20 || data[i + 1] > 0x7E )
1878 wxMBConvUTF16BE conv;
1879 wxString modelName(
reinterpret_cast<const char*
>( data + pos + 2 ), conv,
1880 static_cast<size_t>( charCount ) * 2 );
1881 wxString lowerModel = modelName.Lower();
1883 if( !modelName.IsEmpty() && !lowerModel.EndsWith( wxT(
".step" ) )
1884 && !lowerModel.EndsWith( wxT(
".wrl" ) ) )
1889 for(
size_t tailSize : {
static_cast<size_t>( 61 ),
static_cast<size_t>( 28 ) } )
1891 size_t tailEnd = strEnd + tailSize;
1893 if( tailEnd <= limit
1907 m_reader.SetOffset( landingForCeiling() );
1911 auto readCount = [&](
const char* aName,
int aMax ) ->
int
1915 if( count < 0 || count > aMax )
1917 THROW_IO_ERRORF(
_(
"DipTrace import: invalid embedded pattern %s count %d at offset 0x%06zX." ),
1918 wxString::FromUTF8( aName ), count, startOffset );
1924 auto isValidUtf16StringAt = [&](
size_t aOffset ) ->
bool
1926 const uint8_t* data =
m_reader.GetData();
1927 size_t size = std::min( patternCeiling,
m_reader.GetFileSize() );
1929 if( aOffset + 2 > size )
1932 int charCount = ( data[aOffset] << 8 ) | data[aOffset + 1];
1934 if( charCount < 0 || charCount > 512 )
1937 size_t stringEnd = aOffset + 2 +
static_cast<size_t>( charCount ) * 2;
1939 if( stringEnd > size )
1942 for(
size_t i = aOffset + 2; i < stringEnd; i += 2 )
1944 if( data[i] != 0x00 || data[i + 1] < 0x20 || data[i + 1] > 0x7E )
1971 if( !isValidUtf16StringAt(
m_reader.GetOffset() ) )
1990 int aliasCount = readCount(
"alias", 100 );
1992 for(
int i = 0; i < aliasCount; i++ )
2000 if( aliasCount > 0 )
2003 int padCount = readCount(
"pad", 500 );
2015 auto readModernPadRecord = [&]()
2030 auto canReadModernPadRecordAt = [&](
size_t aOffset ) ->
bool
2038 readModernPadRecord();
2039 ok =
m_reader.GetOffset() <= patternCeiling;
2041 catch(
const std::exception& )
2050 for(
int i = 0; i < padCount; i++ )
2052 if(
m_reader.GetOffset() >= patternCeiling || !canReadModernPadRecordAt(
m_reader.GetOffset() ) )
2057 readModernPadRecord();
2059 if( i + 1 < padCount )
2061 size_t tailStart =
m_reader.GetOffset();
2063 if( tailStart + 22 <= patternCeiling && canReadModernPadRecordAt( tailStart + 22 ) )
2070 catch(
const std::exception& )
2077 auto readInt3At = [&](
size_t aOffset ) ->
int
2079 const uint8_t* data =
m_reader.GetData();
2081 return ( ( data[aOffset] << 16 ) | ( data[aOffset + 1] << 8 ) | data[aOffset + 2] ) -
INT3_BIAS;
2084 auto validUtf16StringAt = [&](
size_t aOffset,
size_t aLimit,
size_t& aEnd ) ->
bool
2086 const uint8_t* data =
m_reader.GetData();
2088 if( aOffset + 2 > aLimit )
2091 int charCount = ( data[aOffset] << 8 ) | data[aOffset + 1];
2093 if( charCount < 0 || charCount > 512 )
2096 size_t strEnd = aOffset + 2 +
static_cast<size_t>( charCount ) * 2;
2098 if( strEnd > aLimit )
2101 for(
size_t i = aOffset + 2; i < strEnd; i += 2 )
2103 if( data[i] != 0x00 )
2106 if( charCount > 0 && ( data[i + 1] < 0x20 || data[i + 1] > 0x7E ) )
2114 size_t modelSectionStart = std::string::npos;
2115 size_t modelStringStart = std::string::npos;
2116 size_t patternEnd = std::string::npos;
2117 size_t limit = std::min( patternCeiling,
m_reader.GetFileSize() );
2119 for(
size_t pos =
m_reader.GetOffset(); pos + 3 <= limit; pos++ )
2121 int modelPlacementCount = readInt3At( pos );
2123 if( modelPlacementCount < 0 || modelPlacementCount > 1000 )
2126 size_t afterPlacements = pos + 3 +
static_cast<size_t>( modelPlacementCount ) * 18;
2128 if( afterPlacements + 3 > limit || readInt3At( afterPlacements ) != 0 )
2131 size_t strStart = afterPlacements + 3;
2134 if( !validUtf16StringAt( strStart, limit, strEnd ) )
2137 for(
size_t tailSize : {
static_cast<size_t>( 61 ),
static_cast<size_t>( 28 ) } )
2139 size_t tailEnd = strEnd + tailSize;
2141 if( tailEnd > limit )
2146 modelSectionStart = pos;
2147 modelStringStart = strStart;
2148 patternEnd = tailEnd;
2153 if( modelSectionStart != std::string::npos )
2157 if( modelSectionStart == std::string::npos )
2161 m_reader.SetOffset( landingForCeiling() );
2165 m_reader.SetOffset( modelStringStart );
2179 int busCount =
m_reader.ReadInt3();
2181 if( busCount < 0 || busCount > 1000 )
2182 THROW_IO_ERRORF(
_(
"DipTrace import: invalid bus count %d." ), busCount );
2184 for(
int i = 0; i < busCount; i++ )
2201 int terminator =
m_reader.ReadInt3();
2203 if( terminator != -1 )
2204 THROW_IO_ERRORF(
_(
"DipTrace import: bus entry %d has unexpected terminator %d." ), i, terminator );
2215 catch(
const std::exception& e )
2218 i, wxString::FromUTF8( e.what() ) );
2226 const uint8_t* data =
m_reader.GetData();
2227 size_t fileSize =
m_reader.GetFileSize();
2229 size_t searchStart =
m_reader.GetOffset();
2231 if( searchStart >= searchEnd )
2236 for(
size_t off = searchStart; off + 5 < searchEnd; off++ )
2238 if( data[off] != 0x0F || data[off + 1] != 0x42 || data[off + 2] != 0x3F )
2241 size_t strOff = off + 3;
2245 if( strOff + 3 > searchEnd )
2248 int n = ( ( data[strOff] << 16 ) | ( data[strOff + 1] << 8 ) | data[strOff + 2] ) -
INT3_BIAS;
2250 if( n < 1 || n > 200 || strOff + 3 + (
size_t) n > fileSize )
2255 for(
int i = 0; i < n; i++ )
2257 uint8_t c = data[strOff + 3 + i];
2259 if( c < 0x20 || c > 0x7E )
2269 wxString
name = wxString::From8BitData(
reinterpret_cast<const char*
>( data + strOff + 3 ), n );
2270 size_t afterStr = strOff + 3 + n;
2275 if( afterStr + 11 <= fileSize )
2279 entry.
field1 = ( ( data[afterStr + 8] << 16 ) | ( data[afterStr + 9] << 8 ) | data[afterStr + 10] )
2283 m_nets.push_back( entry );
2287 if( strOff + 2 > searchEnd )
2290 int n = ( data[strOff] << 8 ) | data[strOff + 1];
2292 if( n < 1 || n > 200 || strOff + 2 + (
size_t) ( n * 2 ) > fileSize )
2297 for(
int i = 0; i < n; i++ )
2299 uint8_t hi = data[strOff + 2 +
static_cast<size_t>( i ) * 2];
2300 uint8_t lo = data[strOff + 2 +
static_cast<size_t>( i ) * 2 + 1];
2302 if( hi != 0 || lo < 0x20 || lo > 0x7E )
2312 wxMBConvUTF16BE conv;
2313 wxString
name(
reinterpret_cast<const char*
>( data + strOff + 2 ), conv,
static_cast<size_t>( n ) * 2 );
2314 size_t afterStr = strOff + 2 +
static_cast<size_t>( n ) * 2;
2319 if( afterStr + 11 <= fileSize )
2322 entry.coordY =
ReadInt4At( data, afterStr + 4 );
2323 entry.field1 = ( ( data[afterStr + 8] << 16 ) | ( data[afterStr + 9] << 8 ) | data[afterStr + 10] )
2327 m_nets.push_back( entry );
2342 if( aOffsetX == 0 && aOffsetY == 0 )
2349 int64_t halfW = aHalfWidth > 0 ? aHalfWidth : 1;
2350 int64_t halfH = aHalfHeight > 0 ? aHalfHeight : 1;
2352 if(
std::abs(
static_cast<int64_t
>( aOffsetX ) ) * halfH >=
std::abs(
static_cast<int64_t
>( aOffsetY ) ) * halfW )
2354 return ( aOffsetX >= 0 ) ? 2 : 0;
2357 return ( aOffsetY >= 0 ) ? 1 : 3;
2363 if( aSheetIndex < 0 )
2369 while( (
int)
m_sheets.size() <= aSheetIndex )
2373 return m_sheets[aSheetIndex]->GetScreen();
2380 sheetName = wxString::Format( wxT(
"Sheet%d" ), aSheetIndex + 1 );
2382 int col = ( aSheetIndex - 1 ) % 4;
2383 int row = ( aSheetIndex - 1 ) / 4;
2384 VECTOR2I pos( 2540000 + col * 50800000, 2540000 + row * 50800000 );
2385 VECTOR2I size( 40640000, 30480000 );
2391 fn.SetName( fn.GetName() + wxString::Format( wxT(
"_%d" ), aSheetIndex ) );
2397 newSheet->
SetName( sheetName );
2410 for(
size_t i = 0; i <
m_sheets.size(); ++i )
2420 wxString pageNumber = wxString::Format( wxT(
"%zu" ), i + 1 );
2422 path.push_back( sheet );
2423 path.SetPageNumber( pageNumber );
2439 std::vector<SCH_SHEET*> topLevelSheets;
2440 topLevelSheets.reserve(
m_sheets.size() );
2445 topLevelSheets.push_back( sheet );
2448 if( !topLevelSheets.empty() )
2457 wxString refdes = aComp.
refdes;
2462 int dot = refdes.Find( wxT(
'.' ),
true );
2464 if( dot <= 0 || dot >=
static_cast<int>( refdes.length() ) - 1 )
2469 if( refdes.Mid( dot + 1 ).ToLong( &suffix ) && suffix >= 1 )
2470 return refdes.Left( dot );
2480 if( base.IsEmpty() )
2483 if( base.IsEmpty() )
2486 if( base.IsEmpty() )
2487 base = wxT(
"Unknown" );
2490 base += wxString::Format( wxT(
"_r%d" ), aComp.
rotationE4 );
2500 if( drawItem.GetUnit() == aUnit )
2510 return static_cast<int>( std::lround( aMm * 30000.0 ) );
2526 shape.
fontX = -20000;
2527 shape.
fontY = 10000;
2528 shape.
points.assign( aPoints.begin(), aPoints.end() );
2535 wxString libPath = aComp.
libPath.Lower();
2536 wxString compName = aComp.
compName.Lower();
2540 return aComp.
shapes.empty() && aComp.
pins.size() == 2 && libPath.Contains( wxT(
"opto_emitters_led_tht" ) )
2541 && compName.StartsWith( wxT(
"led-3mm round" ) );
2569 bool isPower = aComp.
refdes.StartsWith( wxT(
"NetPort" ) );
2573 auto pin = std::make_unique<SCH_PIN>( aLibSymbol );
2575 pin->SetName( dchPin.
name.IsEmpty() ? wxString( wxT(
"~" ) ) : dchPin.
name );
2576 pin->SetNumber( dchPin.
number.IsEmpty() ? wxString( wxT(
"1" ) ) : dchPin.
number );
2595 case 0: connection.
x -= len;
break;
2596 case 2: connection.
x += len;
break;
2597 case 1: connection.
y += len;
break;
2598 case 3: connection.
y -= len;
break;
2601 pin->SetPosition( connection );
2602 pin->SetLength( len );
2613 pin->SetUnit( aUnit );
2617 std::vector<DCH_SHAPE> fallbackShapes;
2628 if( dchShape.points.size() < 2 )
2638 bool isRectangle = dchShape.points.size() == 2 && dchShape.kindCode == 4 && dchShape.kindFlag == 0;
2643 rect->SetParent( aLibSymbol );
2648 rect->SetUnit( aUnit );
2659 bool isEllipse = dchShape.points.size() == 2 && dchShape.kindCode == 6 && dchShape.kindFlag == 0;
2669 circle->SetParent( aLibSymbol );
2673 circle->SetUnit( aUnit );
2682 bool isArc = dchShape.points.size() == 3 && dchShape.kindCode == 2 && dchShape.kindFlag == 0;
2691 arc->SetParent( aLibSymbol );
2692 arc->SetArcGeometry( start, mid,
end );
2694 arc->SetUnit( aUnit );
2700 bool isFilledPolygon = dchShape.points.size() >= 3 && dchShape.kindCode == 8 && dchShape.kindFlag == 0;
2704 poly->SetParent( aLibSymbol );
2706 for(
const VECTOR2I& pt : dchShape.points )
2710 poly->SetUnit( aUnit );
2713 if( dchShape.kindCode == 3 && dchShape.kindFlag == 0 && dchShape.points.size() == 2 )
2717 double dx =
static_cast<double>(
end.x - start.
x );
2718 double dy =
static_cast<double>(
end.y - start.
y );
2719 double len = std::sqrt( dx * dx + dy * dy );
2723 double unitX = dx / len;
2724 double unitY = dy / len;
2725 double arrowLength =
2726 std::min( len / 2.0,
static_cast<double>( std::max( width * 4,
schIUScale.MilsToIU( 35 ) ) ) );
2727 double halfWidth = arrowLength / 2.0;
2728 double baseX =
static_cast<double>(
end.x ) - unitX * arrowLength;
2729 double baseY =
static_cast<double>(
end.y ) - unitY * arrowLength;
2730 double perpX = -unitY;
2731 double perpY = unitX;
2734 arrow->SetParent( aLibSymbol );
2735 arrow->AddPoint(
VECTOR2I(
static_cast<int>( std::lround( baseX + perpX * halfWidth ) ),
2736 static_cast<int>( std::lround( baseY + perpY * halfWidth ) ) ) );
2737 arrow->AddPoint(
end );
2738 arrow->AddPoint(
VECTOR2I(
static_cast<int>( std::lround( baseX - perpX * halfWidth ) ),
2739 static_cast<int>( std::lround( baseY - perpY * halfWidth ) ) ) );
2741 arrow->SetUnit( aUnit );
2766 auto libSymbol = std::make_unique<LIB_SYMBOL>( symName );
2767 libSymbol->SetUnitCount( aUnit,
false );
2770 libSymbol->GetFootprintField().SetText( aComp.
patternName );
2772 bool isPower = aComp.
refdes.StartsWith( wxT(
"NetPort" ) );
2775 libSymbol->SetGlobalPower();
2780 if( !aComp.
pins.empty() )
2781 libSymbol->SetShowPinNames( aComp.
pins.front().netFlagB != 0 );
2796 std::map<int, std::map<int, int>> partSheetVotes;
2800 int sheetIdx = wire.sheetIndex;
2805 for(
const VECTOR2I& pt : wire.points )
2813 if( wire.points.size() >= 2 )
2815 if( wire.object1 >= 0 )
2819 partSheetVotes[wire.object1][sheetIdx]++;
2822 if( wire.object2 >= 0 )
2826 partSheetVotes[wire.object2][sheetIdx]++;
2834 for(
const auto& [partId, sheets] : partSheetVotes )
2839 for(
const auto& [sheet, count] : sheets )
2841 if( count > bestCount )
2855 const uint8_t* data =
m_reader.GetData();
2856 size_t fileSize =
m_reader.GetFileSize();
2858 if( aOffset + 16 > fileSize )
2865 for(
int i = 0; i < 4; i++ )
2867 size_t p = aOffset +
static_cast<size_t>( i ) * 4;
2868 uint32_t raw = (
static_cast<uint32_t
>( data[p] ) << 24 ) | (
static_cast<uint32_t
>( data[p + 1] ) << 16 )
2869 | (
static_cast<uint32_t
>( data[p + 2] ) << 8 ) | data[p + 3];
2870 bbox[i] =
static_cast<int>(
static_cast<int64_t
>( raw ) -
INT4_BIAS );
2872 if(
std::abs( bbox[i] ) > 50000000 )
2878 size_t p = aOffset + 16;
2880 for(
int si = 0; si < 5; si++ )
2883 size_t dataStart = 0;
2888 if( p + 3 > fileSize )
2891 charCount = ( ( data[p] << 16 ) | ( data[p + 1] << 8 ) | data[p + 2] ) -
INT3_BIAS;
2896 if( p + 2 > fileSize )
2899 charCount = ( data[p] << 8 ) | data[p + 1];
2903 if( charCount == 0 )
2909 if( charCount < 0 || charCount > 64 )
2912 size_t byteCount = ascii ?
static_cast<size_t>( charCount ) :
static_cast<size_t>( charCount ) * 2;
2914 if( dataStart + byteCount > fileSize )
2917 for(
int k = 0; k < charCount; k++ )
2919 unsigned ch = ascii ? data[dataStart + k]
2920 : ( ( data[dataStart +
static_cast<size_t>( k ) * 2] << 8 )
2921 | data[dataStart +
static_cast<size_t>( k ) * 2 + 1] );
2925 if( ch < 0x20 && ch != 0x09 && ch != 0x0A && ch != 0x0D )
2929 p = dataStart + byteCount;
2963 if( aTally.empty() )
2968 for(
const auto& [ps, count] : aTally )
2969 bestCount = std::max( bestCount, count );
2973 for(
const auto& [ps, count] : aTally )
2983 for(
const auto& [ps, count] : aTally )
2985 if( count == bestCount )
3000 std::map<std::pair<int, int>,
int> tally;
3002 for(
const VECTOR2I& p : aConnectionPoints )
3009 std::set<std::pair<int, int>> seenHere;
3011 for(
const std::pair<int, int>& ps : it->second )
3012 if( seenHere.insert( ps ).second )
3028 std::map<int, int> votes;
3030 for(
const VECTOR2I& p : aPositions )
3037 for(
int sheet : it->second )
3044 int bestSheet = aFallback;
3047 for(
const auto& [sheet, count] : votes )
3049 if( count > bestVotes )
3068 if( aComp.
libPath.Contains( wxT(
"auto_net_ports" ) ) )
3073 bool explicitUnit =
false;
3075 if( refdes != aComp.
refdes )
3079 if( aComp.
refdes.Mid( refdes.length() + 1 ).ToLong( &suffix ) && suffix >= 1 )
3081 unit =
static_cast<int>( suffix ) + 1;
3082 explicitUnit =
true;
3086 if( !refdes.IsEmpty() )
3097 unit = it->second + 1;
3125 if( !refdes.IsEmpty() )
3138 if( !aComp.
value.IsEmpty() )
3149 if( aComp.
refdes.StartsWith( wxT(
"NetPort" ) ) && !aComp.
compName.IsEmpty() )
3160 if( !aComp.
refdes.StartsWith( wxT(
"NetPort" ) ) )
3180 if( extra.first.IsEmpty() || symbol->
GetField( extra.first ) )
3184 userField.
SetText( extra.second );
3194 bool refPositioned =
false;
3195 bool valuePositioned =
false;
3205 else if( txt.
type == 3 )
3222 refPositioned =
true;
3223 refFieldOffset = off;
3225 else if( txt.
type == 3 )
3227 valuePositioned =
true;
3228 valueFieldOffset = off;
3237 if( refPositioned != valuePositioned )
3242 valField->SetPosition( pos +
VECTOR2I( -refFieldOffset.
x, refFieldOffset.
y ) );
3246 refField->SetPosition( pos +
VECTOR2I( -valueFieldOffset.
x, valueFieldOffset.
y ) );
3255 if( !refPositioned && !valuePositioned )
3280 refField->SetPosition( pos + refOffset );
3288 valField->SetPosition( pos + valueOffset );
3326 std::vector<VECTOR2I> connectionPoints;
3335 dir.
x = ( off.
x >= 0 ) ? 1 : -1;
3337 dir.
y = ( off.
y >= 0 ) ? 1 : -1;
3339 connectionPoints.emplace_back(
center.x + off.
x + dir.
x * len,
center.y + off.
y + dir.
y * len );
3348 if( votedSheet < 0 )
3354 int partId = offsetIt->second;
3359 for(
int d = 0; d <= 12 && votedSheet < 0; d++ )
3361 for(
int candidate : { partId - d, partId + d } )
3367 votedSheet = sheetIt->second;
3377 screen->
Append( symbol );
3393 if( !
comp.libPath.Contains( wxT(
"auto_net_ports" ) ) ||
comp.compName.IsEmpty() )
3405 std::vector<VECTOR2I> connectionPoints;
3407 bool havePin =
false;
3416 dir.
x = ( off.
x >= 0 ) ? 1 : -1;
3418 dir.
y = ( off.
y >= 0 ) ? 1 : -1;
3420 connectionPoints.emplace_back( pos.
x + off.
x + dir.
x * len, pos.
y + off.
y + dir.
y * len );
3443 votedSheet = sheetIt->second;
3448 int partId = offsetIt->second;
3450 for(
int d = 1; d <= 12 && votedSheet < 0; d++ )
3452 for(
int candidate : { partId - d, partId + d } )
3458 votedSheet = sheetIt->second;
3469 if( votedSheet < 0 )
3476 VECTOR2I labelPos = ( havePin && !connectionPoints.empty() ) ? connectionPoints.front() : pos;
3482 if( firstPinDir.
x > 0 )
3484 else if( firstPinDir.
x < 0 )
3486 else if( firstPinDir.
y > 0 )
3488 else if( firstPinDir.
y < 0 )
3503 int64_t bestDist = std::numeric_limits<int64_t>::max();
3507 int64_t dx =
static_cast<int64_t
>( pt.first ) - aPos.
x;
3508 int64_t dy =
static_cast<int64_t
>( pt.second ) - aPos.
y;
3509 int64_t dist = dx * dx + dy * dy;
3511 if( dist < bestDist )
3514 bestSheet = *sheets.begin();
3527 if( aPos + 2 > aSectionEnd )
3530 int cnt = ( aData[aPos] << 8 ) | aData[aPos + 1];
3532 if( cnt < 1 || cnt > 64 )
3535 size_t end = aPos + 2 +
static_cast<size_t>( cnt ) * 2;
3537 if(
end + 8 + 3 + 1 + 3 > aSectionEnd )
3540 for(
int i = 0; i < cnt; i++ )
3542 unsigned hi = aData[aPos + 2 +
static_cast<size_t>( i ) * 2];
3543 unsigned lo = aData[aPos + 2 +
static_cast<size_t>( i ) * 2 + 1];
3544 unsigned ch = ( hi << 8 ) | lo;
3546 bool ok = ( ch >= 0x20 && ch < 0x7F )
3547 || ( ch >= 0x00A0 && ch <= 0x024F )
3548 || ( ch >= 0x0400 && ch <= 0x04FF );
3554 auto rdInt4 = [&](
size_t o ) ->
int
3556 uint32_t raw = (
static_cast<uint32_t
>( aData[o] ) << 24 ) | (
static_cast<uint32_t
>( aData[o + 1] ) << 16 )
3557 | (
static_cast<uint32_t
>( aData[o + 2] ) << 8 ) |
static_cast<uint32_t
>( aData[o + 3] );
3558 return static_cast<int>(
static_cast<int64_t
>( raw ) -
INT4_BIAS );
3561 int lx = rdInt4(
end );
3562 int ly = rdInt4(
end + 4 );
3564 auto rdInt3 = [&](
size_t o ) ->
int
3566 return ( ( aData[o] << 16 ) | ( aData[o + 1] << 8 ) | aData[o + 2] ) -
INT3_BIAS;
3569 int pad = rdInt3(
end + 8 );
3575 return lx > -2000000 && lx < 2000000 && ly > -2000000 && ly < 2000000 && (
pad == 0 ||
pad == 1 )
3588 const uint8_t* data =
m_reader.GetData();
3589 size_t fileSize =
m_reader.GetFileSize();
3593 if( sectionStart == 0 || sectionStart >= sectionEnd )
3596 auto rdInt3 = [&](
size_t o ) ->
int
3598 return ( ( data[o] << 16 ) | ( data[o + 1] << 8 ) | data[o + 2] ) -
INT3_BIAS;
3601 auto rdInt4 = [&](
size_t o ) ->
int
3603 uint32_t raw = (
static_cast<uint32_t
>( data[o] ) << 24 ) | (
static_cast<uint32_t
>( data[o + 1] ) << 16 )
3604 | (
static_cast<uint32_t
>( data[o + 2] ) << 8 ) |
static_cast<uint32_t
>( data[o + 3] );
3605 return static_cast<int>(
static_cast<int64_t
>( raw ) -
INT4_BIAS );
3608 static constexpr uint8_t WIRE_NET_MARKER[] = { 0x0F, 0x42, 0x3F };
3609 static constexpr size_t WIRE_NET_MARKER_LEN =
sizeof( WIRE_NET_MARKER );
3611 auto isExpectedWireNetMarker = [&](
size_t aMarkerOffset,
int aExpectedIndex ) ->
bool
3613 if( aMarkerOffset < 13 || aMarkerOffset + WIRE_NET_MARKER_LEN > sectionEnd )
3616 if( memcmp( data + aMarkerOffset, WIRE_NET_MARKER, WIRE_NET_MARKER_LEN ) != 0 )
3619 if( data[aMarkerOffset - 13] != 0x01 )
3622 int fieldA = rdInt3( aMarkerOffset - 9 );
3623 int fieldB = rdInt3( aMarkerOffset - 6 );
3624 int netIndex = rdInt3( aMarkerOffset - 3 );
3626 if( netIndex != aExpectedIndex )
3633 return fieldA >= -1 && fieldA <= 100000 && fieldB >= -1 && fieldB <= 100000;
3636 auto decodeWireNetName = [&](
size_t aNameOffset, wxString& aName,
size_t& aAfterName, wxString& aError ) ->
bool
3638 if( aNameOffset + 2 > sectionEnd )
3640 aError = wxT(
"missing UTF-16 length" );
3644 int nameLen = ( data[aNameOffset] << 8 ) | data[aNameOffset + 1];
3646 if( nameLen < 1 || nameLen > 64 )
3648 aError = wxString::Format( wxT(
"invalid UTF-16 length %d" ), nameLen );
3652 aAfterName = aNameOffset + 2 +
static_cast<size_t>( nameLen ) * 2;
3654 if( aAfterName + 8 + 3 + 1 + 3 > sectionEnd )
3656 aError = wxT(
"name overruns wire-net record" );
3660 for(
int i = 0; i < nameLen; i++ )
3662 unsigned hi = data[aNameOffset + 2 +
static_cast<size_t>( i ) * 2];
3663 unsigned lo = data[aNameOffset + 2 +
static_cast<size_t>( i ) * 2 + 1];
3664 unsigned ch = ( hi << 8 ) | lo;
3667 ( ch >= 0x20 && ch < 0x7F ) || ( ch >= 0x00A0 && ch <= 0x024F ) || ( ch >= 0x0400 && ch <= 0x04FF );
3671 aError = wxString::Format( wxT(
"invalid UTF-16 character 0x%04X" ), ch );
3676 wxMBConvUTF16BE conv;
3677 aName = wxString(
reinterpret_cast<const char*
>( data + aNameOffset + 2 ), conv,
3678 static_cast<size_t>( nameLen ) * 2 );
3683 auto findNextWireNetName = [&](
size_t aSearchStart,
size_t aSearchEnd,
int aExpectedIndex ) ->
size_t
3685 if( aSearchStart >= aSearchEnd )
3688 for(
size_t marker = aSearchStart; marker + WIRE_NET_MARKER_LEN <= aSearchEnd; marker++ )
3690 if( memcmp( data + marker, WIRE_NET_MARKER, WIRE_NET_MARKER_LEN ) != 0 )
3693 if( !isExpectedWireNetMarker( marker, aExpectedIndex ) )
3696 size_t nameOffset = marker + WIRE_NET_MARKER_LEN;
3697 wxString candidateName;
3699 size_t afterName = 0;
3701 if( !decodeWireNetName( nameOffset, candidateName, afterName, nameError ) )
3703 THROW_IO_ERRORF(
_(
"DipTrace import: invalid wire-net name for net index %d at offset 0x%06zX: %s." ),
3704 aExpectedIndex, nameOffset, nameError );
3715 int expectedWireNetIndex = 0;
3716 size_t pos = findNextWireNetName( sectionStart, sectionEnd, expectedWireNetIndex );
3722 size_t lastRecordEnd = 0;
3724 while( pos != 0 && pos < sectionEnd && safetyNets++ < 100000 )
3731 size_t afterName = 0;
3733 if( !decodeWireNetName( o, netName, afterName, nameError ) )
3735 THROW_IO_ERRORF(
_(
"DipTrace import: invalid wire-net name for net index %d at offset 0x%06zX: %s." ),
3736 expectedWireNetIndex, o, nameError );
3742 if( o + 3 > sectionEnd )
3745 int pinCount = rdInt3( o );
3746 size_t pinCountOffset = o;
3749 if( pinCount < 0 || pinCount > 4000 || o +
static_cast<size_t>( pinCount ) * 6 + 3 > sectionEnd )
3751 THROW_IO_ERRORF(
_(
"DipTrace import: invalid wire-net pin count %d for net '%s' at offset 0x%06zX." ),
3752 pinCount, netName, pinCountOffset );
3755 o +=
static_cast<size_t>( pinCount ) * 6;
3757 int wireCount = rdInt3( o );
3758 size_t wireCountOffset = o;
3761 if( wireCount < 0 || wireCount > 100000 )
3763 THROW_IO_ERRORF(
_(
"DipTrace import: invalid wire count %d for net '%s' at offset 0x%06zX." ),
3764 wireCount, netName, wireCountOffset );
3767 bool brokeEarly =
false;
3769 for(
int w = 0; w < wireCount; w++ )
3771 if( o + 36 + 1 + 3 > sectionEnd )
3778 wire.
object1 = rdInt3( o + 0 );
3779 wire.
object2 = rdInt3( o + 3 );
3782 wire.
bus1 = rdInt3( o + 12 );
3783 wire.
bus2 = rdInt3( o + 15 );
3789 int pointCount = rdInt3( o );
3790 size_t pointCountOffset = o;
3793 if( pointCount < 0 || pointCount > 4000 || o +
static_cast<size_t>( pointCount ) * 11 + 8 > sectionEnd )
3795 THROW_IO_ERRORF(
_(
"DipTrace import: invalid wire point count %d for net '%s' at offset 0x%06zX." ),
3796 pointCount, netName, pointCountOffset );
3799 wire.
points.reserve( pointCount );
3801 for(
int p = 0; p < pointCount; p++ )
3803 int dtX = rdInt4( o );
3804 int dtY = rdInt4( o + 4 );
3816 if( wire.
points.size() >= 2 )
3822 m_wires.push_back( std::move( wire ) );
3830 expectedWireNetIndex++;
3833 pos = findNextWireNetName( o, std::min( sectionEnd, o + 400 ), expectedWireNetIndex );
3850 if( searchStart == 0 || searchStart >= sectionEnd )
3853 size_t originalOffset =
m_reader.GetOffset();
3855 auto readSheetShapeRecord = [&]() -> std::optional<DCH_SHEET_SHAPE>
3857 uint8_t flagA =
m_reader.ReadByte();
3858 uint8_t flagB =
m_reader.ReadByte();
3860 int kindCode =
m_reader.ReadInt3();
3861 int drawOrder =
m_reader.ReadInt3();
3865 uint8_t color[3] = {};
3871 int sheetIndex =
m_reader.ReadInt3();
3873 int lineWidth =
m_reader.ReadInt4();
3877 int pointCount =
m_reader.ReadInt3();
3879 if( flagA != 1 || flagB != 0 || fieldA != 0 || fieldB != 0 || fieldC != -1 || fieldD != 0 )
3880 return std::nullopt;
3882 if( kindCode != 1 && kindCode != 4 )
3883 return std::nullopt;
3885 if( drawOrder < 0 || drawOrder > 1000 || sheetIndex < 0 || sheetIndex >=
m_numSheets )
3886 return std::nullopt;
3888 if( lineWidth < 0 || lineWidth > 200000 || pointCount < 1 || pointCount > 100 )
3889 return std::nullopt;
3895 shape.
color[0] = color[0];
3896 shape.
color[1] = color[1];
3897 shape.
color[2] = color[2];
3898 shape.
points.reserve( pointCount );
3900 for(
int i = 0; i < pointCount; i++ )
3904 shape.
points.emplace_back( x, y );
3909 uint8_t tailFlagA =
m_reader.ReadByte();
3910 uint8_t tailFlagB =
m_reader.ReadByte();
3914 if( tailA != -1 || tailB != -1 || tailFlagA != 0 || tailFlagB != 1 || extentX != -20000 || extentY != 10000 )
3915 return std::nullopt;
3920 for(
size_t offset = searchStart; offset + 3 < sectionEnd; offset++ )
3927 if( count < 1 || count > 1000 )
3930 std::vector<DCH_SHEET_SHAPE> shapes;
3931 shapes.reserve( count );
3935 for(
int i = 0; i < count; i++ )
3937 std::optional<DCH_SHEET_SHAPE> shape = readSheetShapeRecord();
3945 shapes.push_back( *shape );
3948 if( valid && !shapes.empty() &&
m_reader.GetOffset() <= sectionEnd )
3954 catch(
const std::exception& )
3959 m_reader.SetOffset( originalOffset );
3973 if( dchShape.points.size() < 2 )
3984 if( dchShape.kindCode == 4 && dchShape.points.size() == 2 )
3996 if( dchShape.kindCode == 1 )
4000 for(
const VECTOR2I& pt : dchShape.points )
4016 int sheetIdx = wire.sheetIndex;
4026 for(
size_t i = 1; i < wire.points.size(); i++ )
4046 std::set<SCH_SCREEN*> screens;
4053 if( sheet && sheet->GetScreen() )
4054 screens.insert( sheet->GetScreen() );
4057 std::map<SCH_SCREEN*, std::set<std::pair<int, int>>> junctions;
4063 std::deque<EDA_ITEM*> items;
4065 for(
SCH_ITEM* item : screen->Items() )
4066 items.push_back( item );
4068 for(
const VECTOR2I& pt : screen->GetNeededJunctions( items ) )
4069 junctions[screen].insert( { pt.x, pt.y } );
4076 std::map<SCH_SCREEN*, std::set<std::pair<int, int>>> interior;
4080 int sheetIdx = ( aWire.sheetIndex >= 0 && aWire.sheetIndex <
m_numSheets ) ? aWire.sheetIndex : 0;
4091 for(
size_t i = 1; i + 1 < wire.points.size(); i++ )
4094 interior[screen].insert( { p.
x, p.
y } );
4102 if( !screen || wire.points.empty() )
4105 const std::set<std::pair<int, int>>& sheetInterior = interior[screen];
4107 if( wire.bus1 != -1 )
4111 if( sheetInterior.count( { p.x, p.y } ) )
4112 junctions[screen].insert( { p.
x, p.
y } );
4115 if( wire.bus2 != -1 )
4119 if( sheetInterior.count( { p.x, p.y } ) )
4120 junctions[screen].insert( { p.
x, p.
y } );
4124 for(
const auto& [screen, pts] : junctions )
4126 for(
const std::pair<int, int>& pt : pts )
4144 symbol->SetLibSymbol(
new LIB_SYMBOL( *libIt->second ) );
4177 std::set<SCH_SCREEN*> screens;
4184 if( sheet && sheet->GetScreen() )
4185 screens.insert( sheet->GetScreen() );
4189 screen->SetPageSettings( pageInfo );
4206 catch(
const std::exception& e )
4210 m_reporter->Report( wxString::Format(
_(
"DipTrace import: failed to create symbol "
4211 "for %s (%s): %s" ),
4212 comp.refdes,
comp.compName, wxString::FromUTF8( e.what() ) ),
4230 m_reporter->Report( wxString::Format(
_(
"DipTrace import: loaded %zu components, %zu buses, "
4231 "%zu net-port labels from version %d file with %d sheets." ),
constexpr EDA_IU_SCALE schIUScale
void SetPageNumber(const wxString &aPageNumber)
constexpr size_type GetWidth() const
constexpr size_type GetHeight() const
constexpr coord_type GetLeft() const
constexpr coord_type GetRight() const
constexpr coord_type GetTop() const
constexpr coord_type GetBottom() const
void parseOneComponent(size_t aCompEnd, bool aUseCompEnd=true)
static int toKiCadCoordY(int aDipTraceCoord)
std::map< wxString, int > m_refdesUnitMap
Map from refdes to the number of units already created for multi-unit symbols.
void parsePreComponentSettings()
std::vector< DCH_SHEET_DEF > m_sheetDefs
int sheetForNearestWire(const VECTOR2I &aPos) const
Sheet whose decoded wire geometry is closest to aPos, or -1 when no wire exists.
bool isShapeStart(size_t aOffset) const
Check if the data at the given offset looks like a shape/polyline start.
void parseFontBearingShape(DCH_COMPONENT &aComp)
static int pinOrientationFromOffset(int aOffsetX, int aOffsetY, int aHalfWidth, int aHalfHeight)
Determine the pin orientation from the pin connection-point offset relative to the symbol body center...
void buildWirePointSheets()
Build the maps from wire-point position to the sheet(s) and part(s) connecting there,...
void createWires()
Emit SCH_LINE wire segments decoded from the net/wire section.
bool parseComponentTextField(DCH_COMPONENT &aComp, size_t aCompEnd)
size_t m_netPortLabelCount
Count of net-port labels emitted, for the import summary report.
wxString normalizedRefdes(const DCH_COMPONENT &aComp) const
std::vector< size_t > scanComponentBoundaries(size_t aFirstComp, size_t aBusSectionOffset) const
Pre-scan the file to find component start offsets using the bbox(4*int4) + 5-string pattern.
wxString componentSymbolName(const DCH_COMPONENT &aComp) const
Library symbol name for a component.
void parseComponents(size_t aBusSectionOffset)
void createJunctions()
Synthesize junctions where conductors coincide (DipTrace stores none explicitly).
void createSymbolInstance(const DCH_COMPONENT &aComp, SCH_SCREEN *aFallbackScreen)
Create a SCH_SYMBOL instance on the given screen from a DipTrace component.
std::vector< DCH_NET_ENTRY > m_nets
int sheetForComponentPins(const std::vector< VECTOR2I > &aConnectionPoints)
Resolve a symbol's sheet from its pin connection points.
DCH_PAGE m_page
Decoded page geometry and the resulting half-page placement offset (KiCad nm).
void syncEmbeddedLibrarySymbols()
size_t findTailStart() const
Find where the int3(0) tail padding begins by scanning backward from the end of file.
bool isComponentHeaderAt(size_t aOffset) const
True if a component record header (placement + five header strings) starts at aOffset.
static int toKiCadSize(int aDipTraceCoord)
Convert a DipTrace length or stroke width to KiCad schematic internal units.
void buildComponentPartIds()
Enumerate every component header in the file (real components and net ports alike) so each component'...
std::map< wxString, std::vector< SCH_SYMBOL * > > m_placedSymbolsByLibName
std::map< size_t, int > m_offsetToPartId
Component start offset -> DipTrace part id (its index in the in-file component order).
void parseDisplaySettings()
size_t findBusSection(size_t aSearchStart) const
Find the bus section start offset by searching for the characteristic marker pattern: int4(10000) int...
void assignSheetPageNumbers()
size_t m_busSectionOffset
void createNetPortLabels()
Create a global net label for every DipTrace net-port component (auto_net_ports library).
void Parse()
Parse the .dch file and populate the schematic with KiCad objects.
std::map< std::pair< int, int >, std::vector< std::pair< int, int > > > m_pointPartSheets
Wire-endpoint position (KiCad nm) -> (partId, sheet) pairs of the parts connecting there.
std::vector< DCH_WIRE > m_wires
wxString getLibName() const
Build a library name string for the import.
VECTOR2I applyPageOffset(const VECTOR2I &aPos) const
Apply the page-center offset to an absolute KiCad-nm placement so 0,0-centered DipTrace content lands...
size_t m_componentSectionStart
File offset of the component section start, used to enumerate components in part-id order.
bool isFontBearingShapeStart(size_t aOffset) const
std::set< wxString > m_netPortNames
Names of nets that own a placed net-port component; these are the only nets DipTrace draws a label fo...
std::vector< SCH_SHEET * > m_sheets
One per DipTrace sheet.
PROGRESS_REPORTER * m_progressReporter
void createKiCadObjects()
Create KiCad objects from the parsed intermediate data and add them to the appropriate schematic shee...
int m_lastSymbolPartId
Largest part id assigned to a symbol so far; enforces the monotonic part-id order used to disambiguat...
int resolveSheetTally(const std::map< std::pair< int, int >, int > &aTally)
Resolve a (partId, sheet) -> hit-count tally to a sheet, preferring the highest-count pair with a par...
size_t m_wireSectionEnd
End offset of the decoded wire section; the sheet-shape section follows it in modern files.
void parseShape(DCH_COMPONENT &aComp)
void populateLibSymbolUnit(LIB_SYMBOL *aLibSymbol, const DCH_COMPONENT &aComp, int aUnit)
void findPageGeometry()
Locate the page-geometry record (width/height/margins, each mm*30000) in the binary and fill m_page.
std::map< int, int > m_partIdSheet
DipTrace part id -> sheet index, resolved from the wire connectivity.
int sheetForPositions(const std::vector< VECTOR2I > &aPositions, int aFallback) const
Pick the sheet a placed item belongs to by matching its connection points against the decoded wire ge...
void parseSheetDefinitions()
std::vector< DCH_SHEET_SHAPE > m_sheetShapes
SCH_SCREEN * getOrCreateSheet(int aSheetIndex)
Get or create the KiCad sheet and screen for the given DipTrace sheet index.
void parsePin(int aPinIndex, DCH_COMPONENT &aComp)
std::vector< DCH_COMPONENT > m_components
std::map< wxString, std::unique_ptr< LIB_SYMBOL > > m_libSymbols
Symbol library cache.
void parseEmbeddedPattern(DCH_COMPONENT &aComp, size_t aCompEnd)
LIB_SYMBOL * getOrCreateLibSymbol(const DCH_COMPONENT &aComp, int aUnit)
Create a LIB_SYMBOL from the DipTrace component data.
static int toKiCadCoordX(int aDipTraceCoord)
Convert a DipTrace coordinate to KiCad schematic internal units.
SCH_PARSER(const wxString &aFileName, SCHEMATIC *aSchematic, SCH_SHEET *aRootSheet, PROGRESS_REPORTER *aProgressReporter=nullptr, REPORTER *aReporter=nullptr)
std::vector< DCH_BUS_ENTRY > m_buses
void finalizeFlatSheetOrder()
std::map< std::pair< int, int >, std::set< int > > m_wirePointSheets
Wire-point position (KiCad nm) -> set of sheet indices carrying a wire there.
int m_componentBoundaryScanCount
virtual void SetEnd(const VECTOR2I &aEnd)
virtual void SetVisible(bool aVisible)
Hold an error message and may be used when throwing exceptions containing meaningful error messages.
A color representation with 4 components: red, green, blue, alpha.
A logical library item identifier and consists of various portions much like a URI.
static UTF8 FixIllegalChars(const UTF8 &aLibItemName, bool aLib)
Replace illegal LIB_ID item name characters with underscores '_'.
Define a library symbol object.
LIB_ITEMS_CONTAINER & GetDrawItems()
Return a reference to the draw item list.
void SetUnitCount(int aCount, bool aDuplicateDrawItems)
Set the units per symbol count.
const BOX2I GetBodyBoundingBox(int aUnit, int aBodyStyle, bool aIncludePins, bool aIncludePrivateItems) const
Get the symbol bounding box excluding fields.
int GetUnitCount() const override
void AddDrawItem(SCH_ITEM *aItem, bool aSort=true)
Add a new draw aItem to the draw object list and sort according to aSort.
Describe the page size and margins of a paper page on which to eventually print or plot.
void SetWidthMM(double aWidthInMM)
void SetHeightMM(double aHeightInMM)
A progress reporter interface for use in multi-threaded environments.
A pure virtual class used to derive REPORTER objects from.
Holds all the data relating to one schematic.
void SetPosition(const VECTOR2I &aPosition) override
void SetText(const wxString &aText) override
void SetSpinStyle(SPIN_STYLE aSpinStyle) override
Base class for any item which can be embedded within the SCHEMATIC container class,...
void SetShape(LABEL_FLAG_SHAPE aShape)
Segment description base class to describe items which have 2 end points (track, wire,...
void SetEndPoint(const VECTOR2I &aPosition)
void Append(SCH_ITEM *aItem, bool aUpdateLibSymbol=true)
void SetFileName(const wxString &aFileName)
Set the file name for this screen to aFileName.
void SetPosition(const VECTOR2I &aPos) override
void SetStroke(const STROKE_PARAMS &aStroke) override
void AddPoint(const VECTOR2I &aPosition)
Handle access to a stack of flattened SCH_SHEET objects by way of a path for creating a flattened sch...
Sheet symbol placed in a schematic, and is the entry point for a sub schematic.
void SetFileName(const wxString &aFilename)
void SetName(const wxString &aName)
SCH_SCREEN * GetScreen() const
void SetScreen(SCH_SCREEN *aScreen)
Set the SCH_SCREEN associated with this sheet to aScreen.
bool IsVirtualRootSheet() const
void SetRef(const SCH_SHEET_PATH *aSheet, const wxString &aReference)
Set the reference for the given sheet path for this symbol.
void SetFootprintFieldText(const wxString &aFootprint)
SCH_FIELD * AddField(const SCH_FIELD &aField)
Add a field to the symbol.
void SetLibSymbol(LIB_SYMBOL *aLibSymbol)
Set this schematic symbol library symbol reference to aLibSymbol.
SCH_FIELD * GetField(FIELD_T aFieldType)
Return a mandatory field in this symbol.
Simple container to manage line stroke parameters.
static const uint8_t TAHOMA_FONT_PATTERN[]
UTF-16BE pattern for the string "Tahoma" as stored in v46+ component font blocks.
static constexpr int SCHEMATIC_UTF16_STRING_VERSION
static VECTOR2I dipTraceShapePoint(double aXmm, double aYmm)
static constexpr int V31_CUTOVER
Structural layout version threshold for the .dch schematic format.
static bool isPlausibleNetName(const uint8_t *aData, size_t aPos, size_t aSectionEnd)
static KIGFX::COLOR4D dipTraceSheetShapeColor(const DCH_SHEET_SHAPE &aShape)
static bool libSymbolHasUnit(const LIB_SYMBOL *aLibSymbol, int aUnit)
static int dipTraceMm(double aMm)
static bool needsStandardThtLedShape(const DCH_COMPONENT &aComp)
static int ReadInt4At(const uint8_t *aData, size_t aPos)
Decode a 4-byte big-endian biased integer from raw data at a given offset.
static std::vector< DCH_SHAPE > standardThtLedShapes()
static DCH_SHAPE makeDipTraceShape(int aKindCode, double aLineWidthMm, std::initializer_list< VECTOR2I > aPoints)
static constexpr EDA_ANGLE ANGLE_VERTICAL
@ RECTANGLE
Use RECTANGLE instead of RECT to avoid collision in a Windows header.
@ FILLED_SHAPE
Fill with object color.
static std::map< FOOTPRINT *, int > componentShapes
Association between shape names (using shapeName index) and components.
static const std::string KiCadSchematicFileExtension
#define THROW_IO_ERROR(msg)
macro which captures the "call site" values of FILE_, __FUNCTION & LINE
#define THROW_IO_ERRORF(msg,...)
constexpr int INT4_BIAS
Bias value added to stored 4-byte unsigned integers.
constexpr int LEGACY_STRING_VERSION
Format version at or below which strings use the legacy ASCII encoding (int3 byte-count + raw ASCII b...
constexpr int INT3_BIAS
Bias value added to stored 3-byte unsigned integers.
EDA_ANGLE abs(const EDA_ANGLE &aAngle)
@ PT_POWER_IN
power input (GND, VCC for ICs). Must be connected to a power output.
@ PT_PASSIVE
pin for passive symbols: must be connected, and can be connected to any pin.
@ PIN_UP
The pin extends upwards from the connection point: Probably on the bottom side of the symbol.
@ PIN_RIGHT
The pin extends rightwards from the connection point.
@ PIN_LEFT
The pin extends leftwards from the connection point: Probably on the right side of the symbol.
@ PIN_DOWN
The pin extends downwards from the connection: Probably on the top side of the symbol.
Definition of the SCH_SHEET_PATH and SCH_SHEET_LIST classes for Eeschema.
A bus entry as read from the bus section.
A stored component text field record that precedes the embedded footprint pattern.
A component as read from the .dch file.
wxString patternName
Embedded footprint pattern name (e.g. "LED100", "CR0805")
std::vector< DCH_COMPONENT_TEXT > texts
int rotationE4
Placement rotation in radians x 1e4 (0, 15708, 31416, 47124)
std::vector< DCH_SHAPE > shapes
std::vector< std::pair< wxString, wxString > > additionalFields
User-defined additional fields, as (name, value) pairs (e.g. "Part Number (Digi-Key)").
wxString datasheet
Datasheet URL stored in the placement tail.
std::vector< DCH_PIN > pins
A net label/wire entry from the net section.
A component pin as stored in the .dch file.
int x
DipTrace coordinate units (100/3 nm)
A graphical shape primitive (polyline) in a component.
std::vector< VECTOR2I > points
Points in DipTrace coord units.
int kindFlag
Leading kind int3; observed 0 for decoded drawing shapes.
int kindCode
Leading kind int3: 1 line, 3 arrow, 4 rect, 6 obround, 8 filled polygon, 9 outline polygon/polyline.
Sheet definition as read from the file header.
A top-level schematic sheet graphical primitive.
int kindCode
1 line, 4 rectangle.
std::vector< VECTOR2I > points
Points in DipTrace coord units.
A single schematic wire decoded from the net/wire section.
int object1
Connected item id at endpoint 1.
int sheetIndex
DipTrace sheet index.
std::vector< VECTOR2I > points
KiCad nm, ready for SCH_LINE.
int subObject1
Pin/sub index at endpoint 1.
int bus1
Bus index at endpoint 1 (-1 = none)
FIELD_T
The set of all field indices assuming an array like sequence that a SCH_COMPONENT or LIB_PART can hol...
@ USER
The field ID hasn't been set yet; field is invalid.
@ DATASHEET
name of datasheet
@ REFERENCE
Field Reference of part, i.e. "IC21".
@ VALUE
Field Value of part, i.e. "3.3K".
CADSTAR_ARCHIVE_PARSER::VERTEX_TYPE vt
SHAPE_CIRCLE circle(c.m_circle_center, c.m_circle_radius)
VECTOR2< int32_t > VECTOR2I
Definition of file extensions used in Kicad.