40#include <wx/xml/xml.h>
128constexpr uint32_t BITFIELD( uint32_t aWidth, uint32_t aFirst, uint32_t aLast )
130 return ( aWidth << 16 ) | ( aFirst << 8 ) | aLast;
145 const char* treeName;
158 unsigned cmd, cmdMask;
171 0, 0, SS_DIRECT, nullptr \
175 nullptr, T_INT, 0, 0 \
179const SCRIPT_ROW g_script[] = {
184 { { 4, 4, SS_RECURSIVE_MINUS_1,
nullptr },
TERM_S },
185 { {
"subsecs", T_INT, 2, 2 },
186 {
"numsecs", T_INT, 4, 4 },
187 {
"subsecsMSB", T_INT, 3, 1 },
188 {
"subsecsLSB", T_INT, 2, 1 },
189 {
"numsecsMSB2", T_INT, 7, 1 },
190 {
"numsecsMSB1", T_INT, 6, 1 },
191 {
"numsecsMSB0", T_INT, 5, 1 },
192 {
"numsecsLSB", T_INT, 4, 1 },
193 {
"v1", T_INT, 8, 1 },
194 {
"v2", T_INT, 9, 1 },
202 { {
"display", T_BMB, 2, 0x01 },
203 {
"visible", T_BMB, 2, 0x02 },
204 {
"unit", T_UBF, 3, BITFIELD( 1, 0, 3 ) },
205 {
"altunit", T_UBF, 3, BITFIELD( 1, 4, 7 ) },
206 {
"multiple", T_INT, 4, 3 },
207 {
"size", T_DBL, 8, 8 },
208 {
"altsize", T_DBL, 16, 8 },
215 { {
"side", T_BMB, 2, 0x10 },
216 {
"visible", T_UBF, 2, BITFIELD( 1, 2, 3 ) },
217 {
"active", T_BMB, 2, 0x02 },
218 {
"number", T_UBF, 3, BITFIELD( 1, 0, 7 ) },
219 {
"other", T_INT, 4, 1 },
220 {
"fill", T_UBF, 5, BITFIELD( 1, 0, 3 ) },
221 {
"color", T_UBF, 6, BITFIELD( 1, 0, 5 ) },
222 {
"name", T_STR, 15, 9 },
228 { { 4, 4, SS_DIRECT,
nullptr },
TERM_S },
229 { {
"shtsubsecs", T_INT, 8, 4 }, {
"atrsubsecs", T_INT, 12, 4 }, {
"xref_format", T_STR, 19, 5 },
TERM_A } },
234 { { 4, 4, SS_RECURSIVE,
nullptr }, { 8, 4, SS_RECURSIVE,
nullptr }, { 12, 4, SS_RECURSIVE,
nullptr },
TERM_S },
235 { {
"devsubsecs", T_INT, 4, 4 },
236 {
"symsubsecs", T_INT, 8, 4 },
237 {
"pacsubsecs", T_INT, 12, 4 },
238 {
"children", T_INT, 8, 4 },
239 {
"name", T_STR, 16, 8 },
245 { { 4, 4, SS_DIRECT,
nullptr },
TERM_S },
246 { {
"children", T_INT, 8, 4 }, {
"library", T_STR, 16, 8 },
TERM_A } },
251 { { 4, 4, SS_RECURSIVE,
nullptr },
TERM_S },
252 { {
"children", T_INT, 8, 4 }, {
"library", T_STR, 16, 8 },
TERM_A } },
257 { { 4, 4, SS_RECURSIVE,
nullptr },
TERM_S },
258 { {
"subsects", T_INT, 4, 4 },
259 {
"children", T_INT, 8, 2 },
260 {
"desc", T_STR, 10, 6 },
261 {
"library", T_STR, 16, 8 },
267 { { 2, 2, SS_DIRECT,
nullptr },
TERM_S },
268 { {
"minx", T_INT, 4, 2 },
269 {
"miny", T_INT, 6, 2 },
270 {
"maxx", T_INT, 8, 2 },
271 {
"maxy", T_INT, 10, 2 },
272 {
"partsubsecs", T_INT, 12, 4 },
273 {
"bussubsecs", T_INT, 16, 4 },
274 {
"netsubsecs", T_INT, 20, 4 },
280 { { 12, 4, SS_RECURSIVE,
"libraries" },
281 { 2, 2, SS_DIRECT,
"plain" },
282 { 16, 4, SS_RECURSIVE,
"elements" },
283 { 20, 4, SS_RECURSIVE,
"signals" },
285 { {
"minx", T_INT, 4, 2 },
286 {
"miny", T_INT, 6, 2 },
287 {
"maxx", T_INT, 8, 2 },
288 {
"maxy", T_INT, 10, 2 },
289 {
"defsubsecs", T_INT, 12, 4 },
290 {
"pacsubsecs", T_INT, 16, 4 },
291 {
"netsubsecs", T_INT, 20, 4 },
298 { { 2, 2, SS_RECURSIVE,
nullptr },
TERM_S },
299 { {
"minx", T_INT, 4, 2 },
300 {
"miny", T_INT, 6, 2 },
301 {
"maxx", T_INT, 8, 2 },
302 {
"maxy", T_INT, 10, 2 },
303 {
"airwires", T_BMB, 12, 0x02 },
304 {
"netclass", T_UBF, 13, BITFIELD( 1, 0, 3 ) },
305 {
"name", T_STR, 16, 8 },
312 { { 2, 2, SS_RECURSIVE,
nullptr },
TERM_S },
313 { {
"minx", T_INT, 4, 2 },
314 {
"miny", T_INT, 6, 2 },
315 {
"maxx", T_INT, 8, 2 },
316 {
"maxy", T_INT, 10, 2 },
317 {
"name", T_STR, 16, 8 },
325 { { 2, 2, SS_RECURSIVE,
nullptr },
TERM_S },
326 { {
"minx", T_INT, 4, 2 },
327 {
"miny", T_INT, 6, 2 },
328 {
"maxx", T_INT, 8, 2 },
329 {
"maxy", T_INT, 10, 2 },
330 {
"desc", T_STR, 13, 5 },
331 {
"name", T_STR, 18, 6 },
337 { { 2, 2, SS_RECURSIVE,
nullptr },
TERM_S },
338 { {
"minx", T_INT, 4, 2 },
339 {
"miny", T_INT, 6, 2 },
340 {
"maxx", T_INT, 8, 2 },
341 {
"maxy", T_INT, 10, 2 },
342 {
"netclass", T_UBF, 13, BITFIELD( 1, 0, 3 ) },
343 {
"name", T_STR, 16, 8 },
349 { { 2, 2, SS_RECURSIVE,
nullptr },
TERM_S },
350 { {
"minx", T_INT, 4, 2 }, {
"miny", T_INT, 6, 2 }, {
"maxx", T_INT, 8, 2 }, {
"maxy", T_INT, 10, 2 },
TERM_A } },
357 { { 2, 2, SS_DIRECT,
nullptr },
TERM_S },
358 { {
"minx", T_INT, 4, 2 },
359 {
"miny", T_INT, 6, 2 },
360 {
"maxx", T_INT, 8, 2 },
361 {
"maxy", T_INT, 10, 2 },
362 {
"half_width", T_UINT, 12, 2 },
363 {
"half_spacing", T_UINT, 14, 2 },
364 {
"half_isolate", T_UINT, 16, 2 },
365 {
"layer", T_UBF, 18, BITFIELD( 1, 0, 7 ) },
366 {
"pour", T_BMB, 19, 0x01 },
367 {
"rank", T_BMB, 19, BITFIELD( 1, 1, 3 ) },
368 {
"thermals", T_BMB, 19, 0x80 },
369 {
"orphans", T_BMB, 19, 0x40 },
376 { {
"layer", T_UBF, 3, BITFIELD( 1, 0, 7 ) },
377 {
"half_width", T_INT, 20, 2 },
378 {
"stflags", T_BMB, 22, 0x33 },
379 {
"ccw", T_BMB, 22, 0x20 },
380 {
"linetype", T_UBF, 23, BITFIELD( 1, 0, 7 ) },
381 {
"linetype_0_x1", T_INT, 4, 4 },
382 {
"linetype_0_y1", T_INT, 8, 4 },
383 {
"linetype_0_x2", T_INT, 12, 4 },
384 {
"linetype_0_y2", T_INT, 16, 4 },
385 {
"arc_negflags", T_UBF, 19, BITFIELD( 1, 0, 4 ) },
386 {
"arc_c1", T_INT, 7, 1 },
387 {
"arc_c2", T_INT, 11, 1 },
388 {
"arc_c3", T_INT, 15, 1 },
389 {
"arc_x1", T_INT, 4, 3 },
390 {
"arc_y1", T_INT, 8, 3 },
391 {
"arc_x2", T_INT, 12, 3 },
392 {
"arc_y2", T_INT, 16, 3 },
399 { {
"layer", T_UBF, 3, BITFIELD( 1, 0, 7 ) },
400 {
"half_width", T_INT, 20, 2 },
401 {
"ccw", T_BMB, 22, 0x20 },
402 {
"arctype", T_UBF, 23, BITFIELD( 1, 0, 7 ) },
403 {
"arc_negflags", T_UBF, 19, BITFIELD( 1, 0, 7 ) },
404 {
"arc_c1", T_INT, 7, 1 },
405 {
"arc_c2", T_INT, 11, 1 },
406 {
"arc_c3", T_INT, 15, 1 },
407 {
"arc_x1", T_INT, 4, 3 },
408 {
"arc_y1", T_INT, 8, 3 },
409 {
"arc_x2", T_INT, 12, 3 },
410 {
"arc_y2", T_INT, 16, 3 },
411 {
"arctype_other_x1", T_INT, 4, 4 },
412 {
"arctype_other_y1", T_INT, 8, 4 },
413 {
"arctype_other_x2", T_INT, 12, 4 },
414 {
"arctype_other_y2", T_INT, 16, 4 },
421 { {
"layer", T_UBF, 3, BITFIELD( 1, 0, 7 ) },
422 {
"x", T_INT, 4, 4 },
423 {
"y", T_INT, 8, 4 },
424 {
"radius", T_INT, 12, 4 },
425 {
"half_width", T_INT, 20, 4 },
434 { {
"layer", T_UBF, 3, BITFIELD( 1, 0, 7 ) },
435 {
"x1", T_INT, 4, 4 },
436 {
"y1", T_INT, 8, 4 },
437 {
"x2", T_INT, 12, 4 },
438 {
"y2", T_INT, 16, 4 },
439 {
"bin_rot", T_INT, 20, 2 },
446 { {
"layer", T_UBF, 3, BITFIELD( 1, 0, 7 ) },
447 {
"x", T_INT, 4, 4 },
448 {
"y", T_INT, 8, 4 },
449 {
"width_2", T_INT, 12, 2 },
456 { {
"x", T_INT, 4, 4 },
457 {
"y", T_INT, 8, 4 },
458 {
"half_diameter", T_UBF, 12, BITFIELD( 2, 0, 15 ) },
459 {
"half_drill", T_UBF, 12, BITFIELD( 2, 0, 15 ) },
468 { {
"shape", T_INT, 2, 1 },
469 {
"x", T_INT, 4, 4 },
470 {
"y", T_INT, 8, 4 },
471 {
"half_drill", T_UBF, 12, BITFIELD( 2, 0, 15 ) },
472 {
"half_diameter", T_UBF, 14, BITFIELD( 2, 0, 15 ) },
473 {
"layers", T_UBF, 16, BITFIELD( 1, 0, 7 ) },
474 {
"stop", T_BMB, 17, 0x01 },
489 { {
"shape", T_INT, 2, 1 },
490 {
"x", T_INT, 4, 4 },
491 {
"y", T_INT, 8, 4 },
492 {
"half_drill", T_UBF, 12, BITFIELD( 2, 0, 15 ) },
493 {
"half_diameter", T_UBF, 14, BITFIELD( 2, 0, 15 ) },
494 {
"name", T_STR, 16, 8 },
501 { {
"roundness", T_INT, 2, 1 },
502 {
"layer", T_UBF, 3, BITFIELD( 1, 0, 7 ) },
503 {
"x", T_INT, 4, 4 },
504 {
"y", T_INT, 8, 4 },
505 {
"half_dx", T_UBF, 12, BITFIELD( 2, 0, 15 ) },
506 {
"half_dy", T_UBF, 14, BITFIELD( 2, 0, 15 ) },
507 {
"name", T_STR, 16, 8 },
514 { {
"shape", T_INT, 2, 1 },
515 {
"x", T_INT, 4, 4 },
516 {
"y", T_INT, 8, 4 },
517 {
"half_drill", T_UBF, 12, BITFIELD( 2, 0, 15 ) },
518 {
"half_diameter", T_UBF, 14, BITFIELD( 2, 0, 15 ) },
519 {
"bin_rot", T_INT, 16, 2 },
520 {
"stop", T_BMB, 18, 0x01 },
521 {
"thermals", T_BMB, 18, 0x04 },
522 {
"first", T_BMB, 18, 0x08 },
523 {
"name", T_STR, 19, 5 },
530 { {
"roundness", T_INT, 2, 1 },
531 {
"layer", T_UBF, 3, BITFIELD( 1, 0, 7 ) },
532 {
"x", T_INT, 4, 4 },
533 {
"y", T_INT, 8, 4 },
534 {
"half_dx", T_UBF, 12, BITFIELD( 2, 0, 15 ) },
535 {
"half_dy", T_UBF, 14, BITFIELD( 2, 0, 15 ) },
536 {
"bin_rot", T_UBF, 16, BITFIELD( 2, 0, 11 ) },
537 {
"stop", T_BMB, 18, 0x01 },
538 {
"cream", T_BMB, 18, 0x02 },
539 {
"thermals", T_BMB, 18, 0x04 },
540 {
"first", T_BMB, 18, 0x08 },
541 {
"name", T_STR, 19, 5 },
548 { {
"function", T_UBF, 2, BITFIELD( 1, 0, 1 ) },
549 {
"visible", T_UBF, 2, BITFIELD( 1, 6, 7 ) },
550 {
"x", T_INT, 4, 4 },
551 {
"y", T_INT, 8, 4 },
552 {
"direction", T_UBF, 12, BITFIELD( 1, 0, 3 ) },
553 {
"length", T_UBF, 12, BITFIELD( 1, 4, 5 ) },
554 {
"bin_rot", T_UBF, 12, BITFIELD( 1, 6, 7 ) },
555 {
"swaplevel", T_INT, 13, 1 },
556 {
"name", T_STR, 14, 10 },
563 { {
"x", T_INT, 4, 4 },
564 {
"y", T_INT, 8, 4 },
565 {
"addlevel", T_INT, 12, 1 },
566 {
"swap", T_INT, 13, 1 },
567 {
"symno", T_INT, 14, 2 },
568 {
"name", T_STR, 16, 8 },
578 { { 2, 2, SS_DIRECT,
nullptr },
TERM_S },
579 { {
"x", T_INT, 4, 4 },
580 {
"y", T_INT, 8, 4 },
581 {
"library", T_INT, 12, 2 },
582 {
"package", T_INT, 14, 2 },
583 {
"bin_rot", T_UBF, 16, BITFIELD( 2, 0, 11 ) },
584 {
"mirrored", T_BMB, 17, 0x10 },
585 {
"spin", T_BMB, 17, 0x40 },
592 { {
"name", T_STR, 2, 8 }, {
"value", T_STR, 10, 14 },
TERM_A } },
597 { { 2, 2, SS_DIRECT,
nullptr },
TERM_S },
598 { {
"x", T_INT, 4, 4 },
599 {
"y", T_INT, 8, 4 },
600 {
"placed", T_INT, 12, 2 },
601 {
"gateno", T_INT, 14, 2 },
602 {
"bin_rot", T_UBF, 16, BITFIELD( 2, 10, 11 ) },
603 {
"mirrored", T_UBF, 16, BITFIELD( 2, 12, 12 ) },
604 {
"smashed", T_BMB, 18, 0x01 },
611 { {
"layer", T_UBF, 3, BITFIELD( 1, 0, 7 ) },
612 {
"x", T_INT, 4, 4 },
613 {
"y", T_INT, 8, 4 },
614 {
"half_size", T_UINT, 12, 2 },
615 {
"ratio", T_UBF, 14, BITFIELD( 2, 2, 6 ) },
616 {
"bin_rot", T_UBF, 16, BITFIELD( 2, 0, 11 ) },
617 {
"mirrored", T_UBF, 16, BITFIELD( 2, 12, 12 ) },
618 {
"spin", T_UBF, 16, BITFIELD( 2, 14, 14 ) },
619 {
"textfield", T_STR, 18, 6 },
623 {
EGKW_SECT_LONGTEXT, 0xFFFF,
"longtext", {
TERM_F }, {
TERM_S }, { {
"textfield", T_STR, 2, 22 },
TERM_A } },
629 { {
"layer", T_UBF, 3, BITFIELD( 1, 0, 7 ) },
630 {
"x", T_INT, 4, 4 },
631 {
"y", T_INT, 8, 4 },
632 {
"size", T_UINT, 12, 2 },
633 {
"ratio", T_UBF, 14, BITFIELD( 2, 2, 6 ) },
634 {
"bin_rot", T_UBF, 16, BITFIELD( 2, 0, 11 ) },
635 {
"mirrored", T_UBF, 16, BITFIELD( 2, 12, 12 ) },
636 {
"spin", T_UBF, 16, BITFIELD( 2, 14, 14 ) },
637 {
"textfield", T_STR, 18, 6 },
644 { {
"layer", T_UBF, 3, BITFIELD( 1, 0, 7 ) },
645 {
"x", T_INT, 4, 4 },
646 {
"y", T_INT, 8, 4 },
647 {
"size", T_UINT, 12, 2 },
648 {
"ratio", T_UBF, 14, BITFIELD( 2, 2, 6 ) },
649 {
"bin_rot", T_UBF, 16, BITFIELD( 2, 0, 11 ) },
650 {
"mirrored", T_UBF, 16, BITFIELD( 2, 12, 12 ) },
651 {
"spin", T_UBF, 16, BITFIELD( 2, 14, 14 ) },
652 {
"textfield", T_STR, 18, 6 },
659 { {
"layer", T_UBF, 3, BITFIELD( 1, 0, 7 ) },
660 {
"x", T_INT, 4, 4 },
661 {
"y", T_INT, 8, 4 },
662 {
"size", T_UINT, 12, 2 },
663 {
"ratio", T_UBF, 14, BITFIELD( 2, 2, 6 ) },
664 {
"bin_rot", T_UBF, 16, BITFIELD( 2, 0, 11 ) },
665 {
"mirrored", T_UBF, 16, BITFIELD( 2, 12, 12 ) },
666 {
"spin", T_UBF, 16, BITFIELD( 2, 14, 14 ) },
667 {
"textfield", T_STR, 18, 6 },
673 { { 2, 2, SS_DIRECT,
nullptr },
TERM_S },
674 { {
"package", T_INT, 4, 2 }, {
"table", T_STR, 6, 13 }, {
"name", T_STR, 19, 5 },
TERM_A } },
681 { { 4, 2, SS_RECURSIVE,
"variants" }, { 2, 2, SS_RECURSIVE,
"gates" },
TERM_S },
682 { {
"gates", T_INT, 2, 2 },
683 {
"variants", T_INT, 4, 2 },
684 {
"prefix", T_STR, 8, 5 },
685 {
"desc", T_STR, 13, 5 },
686 {
"name", T_STR, 18, 5 },
687 {
"pin_bits", T_UBF, 7, BITFIELD( 1, 0, 3 ) },
688 {
"con_byte", T_UBF, 7, BITFIELD( 1, 7, 7 ) },
694 { { 2, 2, SS_RECURSIVE,
nullptr },
TERM_S },
695 { {
"lib", T_INT, 4, 2 },
696 {
"device", T_INT, 6, 2 },
698 {
"variant", T_UINT, 8, 1 },
699 {
"technology", T_INT, 9, 2 },
700 {
"name", T_STR, 11, 5 },
701 {
"value", T_STR, 16, 8 },
704 {
EGKW_SECT_SCHEMABUS, 0xFF00,
nullptr, {
TERM_F }, {
TERM_S }, { {
"name", T_STR, 4, 20 },
TERM_A } },
707 "variantconnections",
710 { {
"pads", T_RAW, 2, 22 },
TERM_A } },
717 { {
"partnumber", T_INT, 4, 2 }, {
"pin", T_INT, 6, 2 },
TERM_A } },
723 { {
"layer", T_UBF, 3, BITFIELD( 1, 0, 7 ) },
724 {
"x", T_INT, 4, 4 },
725 {
"y", T_INT, 8, 4 },
726 {
"size", T_UINT, 12, 2 },
727 {
"ratio", T_UBF, 14, BITFIELD( 2, 2, 6 ) },
728 {
"bin_rot", T_UBF, 16, BITFIELD( 2, 0, 11 ) },
729 {
"mirrored", T_UBF, 16, BITFIELD( 2, 12, 12 ) },
730 {
"spin", T_UBF, 16, BITFIELD( 2, 14, 14 ) },
731 {
"textfield", T_STR, 18, 6 },
738 { {
"layer", T_UBF, 3, BITFIELD( 1, 0, 7 ) },
739 {
"x", T_INT, 4, 4 },
740 {
"y", T_INT, 8, 4 },
741 {
"size", T_UINT, 12, 2 },
742 {
"ratio", T_UBF, 14, BITFIELD( 2, 2, 6 ) },
743 {
"bin_rot", T_UBF, 16, BITFIELD( 2, 0, 11 ) },
744 {
"mirrored", T_UBF, 16, BITFIELD( 2, 12, 12 ) },
745 {
"spin", T_UBF, 16, BITFIELD( 2, 14, 14 ) },
746 {
"textfield", T_STR, 18, 6 },
755 { {
"layer", T_UBF, 3, BITFIELD( 1, 0, 7 ) },
756 {
"x", T_INT, 4, 4 },
757 {
"y", T_INT, 8, 4 },
758 {
"size", T_UINT, 12, 2 },
759 {
"ratio", T_UBF, 14, BITFIELD( 2, 2, 6 ) },
760 {
"bin_rot", T_UBF, 16, BITFIELD( 2, 0, 11 ) },
761 {
"mirrored", T_UBF, 16, BITFIELD( 2, 12, 12 ) },
762 {
"spin", T_UBF, 16, BITFIELD( 2, 14, 14 ) },
763 {
"textfield", T_STR, 18, 6 },
770 { {
"symbol", T_STR, 2, 5 }, {
"attribute", T_STR, 7, 17 },
TERM_A } },
776 { {
"layer", T_UBF, 3, BITFIELD( 1, 0, 7 ) },
777 {
"x1", T_INT, 4, 4 },
778 {
"y1", T_INT, 8, 4 },
779 {
"x2", T_INT, 12, 4 },
780 {
"y2", T_INT, 16, 4 },
781 {
"cols", T_INT, 20, 1 },
782 {
"rows", T_INT, 21, 1 },
783 {
"borders", T_INT, 22, 1 },
790 { {
"layer", T_UBF, 3, BITFIELD( 1, 0, 7 ) },
791 {
"x", T_INT, 4, 4 },
792 {
"y", T_INT, 8, 4 },
793 {
"size", T_UINT, 12, 2 },
794 {
"ratio", T_UBF, 14, BITFIELD( 2, 2, 6 ) },
795 {
"bin_rot", T_UBF, 16, BITFIELD( 2, 0, 11 ) },
796 {
"mirrored", T_UBF, 16, BITFIELD( 2, 12, 12 ) },
797 {
"spin", T_UBF, 16, BITFIELD( 2, 14, 14 ) },
798 {
"textfield", T_STR, 18, 6 },
811bool isV3InlineNamePadRow(
const SCRIPT_ROW* aRow )
816 for(
const ATTR* at = aRow->attrs; at->name !=
nullptr; at++ )
818 if( strcmp( at->name,
"name" ) == 0 )
819 return at->offs == 16;
829 auto child = std::make_unique<EGB_NODE>();
832 child->parent =
this;
833 children.push_back( std::move( child ) );
841 aChild->parent =
this;
842 children.push_back( std::move( aChild ) );
850 auto it =
props.find( aKey );
851 return it ==
props.end() ? wxString() : it->second;
858 Prop( aKey ).ToLong( &val );
866 wxLongLong_t val = 0;
867 Prop( aKey ).ToLongLong( &val );
869 return wxString::Format( wxS(
"%lld" ), val * 2 );
877 if( child->id == aId )
889 if( child->name == aName )
903 uint8_t buf[2] = { 0, 0 };
905 if( !aStream.IsOk() )
908 const wxFileOffset originalPos = aStream.TellI();
910 if( originalPos == wxInvalidOffset || aStream.SeekI( 0 ) == wxInvalidOffset )
913 aStream.Read( buf, 2 );
914 const size_t bytesRead = aStream.LastRead();
916 if( aStream.SeekI( originalPos ) == wxInvalidOffset || bytesRead != 2 )
919 if( buf[0] == 0x10 && ( buf[1] == 0x00 || buf[1] == 0x80 ) )
928 if(
m_buf ==
nullptr || aOffs >
m_buf->size() || aLen >
m_buf->size() - aOffs )
929 THROW_IO_ERROR(
_(
"Short read in Eagle binary file (field out of bounds)." ) );
939 for(
unsigned n = 0; n < aLen; n++ )
942 l |= ( *m_buf )[aOffs + aLen - n - 1];
955 if( ( *
m_buf )[aOffs + aLen - 1] & 0x80 )
958 for(
unsigned n = 0; n < aLen; n++ )
961 l |= ( *m_buf )[aOffs + aLen - n - 1];
964 return static_cast<int32_t
>( l );
972 return ( ( *
m_buf )[aOffs] & aMask ) != 0;
978 unsigned first = ( aField >> 8 ) & 0xff;
979 unsigned last = aField & 0xff;
980 uint32_t mask = ( 1u << ( last - first + 1 ) ) - 1;
984 uint32_t val =
loadU32( aOffs, ( aField >> 16 ) & 0xff ) >> first;
994 const char* start =
reinterpret_cast<const char*
>(
m_buf->data() + aOffs );
1000 while( n < aLen && start[n] !=
'\0' )
1003 return wxString::FromUTF8( start, n );
1009 static_assert(
sizeof( double ) == 8,
"Eagle binary doubles are 8-byte IEEE-754" );
1018 for(
unsigned n = 0; n <
sizeof( double ); n++ )
1019 bits |=
static_cast<uint64_t
>( ( *
m_buf )[aOffs + n] ) << ( 8 * n );
1022 memcpy( &d, &bits,
sizeof( d ) );
1041 THROW_IO_ERROR(
_(
"Short read in Eagle binary file (truncated block)." ) );
1043 size_t blockStart =
m_pos;
1049 if( aNumBlocks < 0 && ( *
m_buf )[blockStart] == 0x10 )
1050 aNumBlocks =
loadS32( blockStart + 4, 4 );
1052 const SCRIPT_ROW* sc =
nullptr;
1054 for(
const SCRIPT_ROW* row = g_script; row->cmd != 0; row++ )
1056 unsigned cmdh = ( row->cmd >> 8 ) & 0xFF;
1057 unsigned cmdl = row->cmd & 0xFF;
1058 unsigned mskh = ( row->cmdMask >> 8 ) & 0xFF;
1059 unsigned mskl = row->cmdMask & 0xFF;
1061 if( ( cmdh != ( ( *
m_buf )[blockStart] & mskh ) ) || ( cmdl != ( ( *
m_buf )[blockStart + 1] & mskl ) ) )
1068 for(
const FMATCH* fm = row->fmatch; fm->offs != 0; fm++ )
1070 if(
loadS32( blockStart + fm->offs, fm->len ) != fm->val )
1083 if(
m_majorVer > 3 && isV3InlineNamePadRow( row ) )
1093 THROW_IO_ERRORF(
_(
"Unknown Eagle binary block id 0x%02x%02x at offset %zu." ),
1094 (
unsigned) ( *
m_buf )[blockStart],
1095 (
unsigned) ( *
m_buf )[blockStart + 1],
1100 sc->name ? wxString::FromUTF8( sc->name ) : wxString( wxS(
"UNKNOWN" ) ) );
1102 for(
const ATTR* at = sc->attrs; at->name !=
nullptr; at++ )
1110 case T_BMB: val =
loadBmb( blockStart + at->offs, at->len ) ? wxS(
"yes" ) : wxS(
"no" );
break;
1111 case T_UBF: val = wxString::Format( wxS(
"%u" ),
loadUbf( blockStart + at->offs, at->len ) );
break;
1112 case T_INT: val = wxString::Format( wxS(
"%d" ),
loadS32( blockStart + at->offs, at->len ) );
break;
1113 case T_UINT: val = wxString::Format( wxS(
"%u" ),
loadU32( blockStart + at->offs, at->len ) );
break;
1114 case T_DBL: val = wxString::FromCDouble(
loadDouble( blockStart + at->offs ) );
break;
1119 for(
unsigned n = 0; n < at->len; n++ )
1120 val += wxString::Format( wxS(
"%02x" ), (
unsigned) ( *
m_buf )[blockStart + at->offs + n] );
1126 size_t foff = blockStart + at->offs;
1127 val =
loadStr( foff, at->len );
1130 if( foff + 5 <=
m_buf->size() && ( *
m_buf )[foff] == 0x7F )
1131 m_longRefs.push_back( { node, wxString::FromUTF8( at->name ) } );
1137 node->
props[wxString::FromUTF8( at->name )] = val;
1142 for(
const SUBSECT* ss = sc->subs; ss->offs != 0; ss++ )
1144 uint32_t numch =
loadU32( blockStart + ss->offs, ss->len );
1147 if( ss->treeName !=
nullptr )
1148 lpar = node->
AddChild( 0, wxString::FromUTF8( ss->treeName ) );
1150 if( ss->ssType == SS_DIRECT )
1152 for( uint32_t n = 0; n < numch && aNumBlocks > 0; n++ )
1164 if( ss->ssType == SS_RECURSIVE_MINUS_1 && numch > 0 )
1169 for( uint32_t n = 0; n < numch && rem > 0; n++ )
1203 size_t total =
static_cast<size_t>( textLen ) + 4;
1212 while( cur <
end && ( *
m_buf )[cur] !=
'\0' )
1216 while( cur <
end && ( *
m_buf )[cur] !=
'\0' )
1219 wxString str = wxString::FromUTF8(
reinterpret_cast<const char*
>(
m_buf->data() + s ),
1234 wxLogTrace(
traceEagleIo, wxS(
"Eagle bin: free-text reference out of strings" ) );
1247 wxLogTrace(
traceEagleIo, wxS(
"Eagle bin: %zu long strings for %zu references" ),
m_freeText.size(), refCount );
1249 if( refCount == 0 ||
m_freeText.size() != refCount )
1252 std::vector<wxString> placed( refCount );
1256 for(
size_t first = 0; first < refCount; )
1258 size_t end = first + 1;
1263 for(
size_t i =
end; i-- > first; )
1278 if( placed.empty() )
1281 for(
size_t i = 0; i <
m_longRefs.size(); i++ )
1309 uint8_t c = ( *m_buf )[
m_pos++];
1326 const size_t kDrcLen = 244;
1333 auto mil = [&](
size_t aOffs ) ->
long
1335 return static_cast<long>(
loadS32( b + aOffs, 4 ) / 2.54 / 100 );
1351 auto it = aNode->
props.find( aField );
1353 if( it == aNode->
props.end() || it->second.IsEmpty() )
1360 if( it->second[0].GetValue() == 0x7F )
1367 auto fixThreeByte = [](
long num,
bool neg ) ->
long
1369 if( num < 0 && neg )
1371 else if( num > 0 && neg )
1372 return num - 0x800000;
1373 else if( num < 0 && !neg )
1374 return num + 0x800000;
1379 auto setLong = [&](
const wxString& aKey,
long aVal )
1381 aElem->
props[aKey] = wxString::Format( wxS(
"%ld" ), aVal );
1387 auto interpolate = []( int64_t aNumerator, int64_t aSpan, int64_t aDivisor, int64_t aOffset ) ->
long
1389 return static_cast<long>( aNumerator * aSpan / aDivisor + aOffset );
1392 if( aLineType == 129 || aArcType == 0 )
1394 long arcFlags = aElem->
PropLong( wxS(
"arc_negflags" ) );
1395 long x1 = fixThreeByte( aElem->
PropLong( wxS(
"arc_x1" ) ), arcFlags & 0x02 );
1396 long y1 = fixThreeByte( aElem->
PropLong( wxS(
"arc_y1" ) ), arcFlags & 0x04 );
1397 long x2 = fixThreeByte( aElem->
PropLong( wxS(
"arc_x2" ) ), arcFlags & 0x08 );
1398 long y2 = fixThreeByte( aElem->
PropLong( wxS(
"arc_y2" ) ), arcFlags & 0x10 );
1406 long c = ( aElem->
PropLong( wxS(
"arc_c1" ) ) & 0xFF )
1407 | ( ( aElem->
PropLong( wxS(
"arc_c2" ) ) & 0xFF ) << 8 )
1408 | ( ( aElem->
PropLong( wxS(
"arc_c3" ) ) & 0xFF ) << 16 );
1413 c = fixThreeByte( c, arcFlags & 0x01 );
1415 setLong( wxS(
"x1" ), x1 );
1416 setLong( wxS(
"y1" ), y1 );
1417 setLong( wxS(
"x2" ), x2 );
1418 setLong( wxS(
"y2" ), y2 );
1420 long x3 = ( x1 + x2 ) / 2;
1421 long y3 = ( y1 + y2 ) / 2;
1422 long cx = 0, cy = 0;
1424 if( x1 == x2 && y1 == y2 )
1434 cy = interpolate( x3 - cx, x2 - x1, y2 - y1, y3 );
1439 cx = interpolate( y3 - cy, y2 - y1, x2 - x1, x3 );
1442 long radius =
static_cast<long>( std::hypot( cx - x2, cy - y2 ) );
1443 setLong( wxS(
"radius" ),
radius );
1444 setLong( wxS(
"x" ), cx );
1445 setLong( wxS(
"y" ), cy );
1447 if( cx == x2 && cy == y1 && x2 < x1 && y2 > y1 )
1449 aElem->
props[wxS(
"StartAngle" )] = wxS(
"90" );
1450 aElem->
props[wxS(
"Delta" )] = wxS(
"90" );
1452 else if( cx == x1 && cy == y2 && x2 < x1 && y1 > y2 )
1454 aElem->
props[wxS(
"StartAngle" )] = wxS(
"0" );
1455 aElem->
props[wxS(
"Delta" )] = wxS(
"90" );
1457 else if( cx == x2 && cy == y1 && x2 > x1 && y1 > y2 )
1459 aElem->
props[wxS(
"StartAngle" )] = wxS(
"270" );
1460 aElem->
props[wxS(
"Delta" )] = wxS(
"90" );
1462 else if( cx == x1 && cy == y2 && x2 > x1 && y2 > y1 )
1464 aElem->
props[wxS(
"StartAngle" )] = wxS(
"180" );
1465 aElem->
props[wxS(
"Delta" )] = wxS(
"90" );
1469 double theta1 = 180.0 - 180.0 /
M_PI * atan2( cy - y1, x1 - cx );
1470 double theta2 = 180.0 - 180.0 /
M_PI * atan2( cy - y2, x2 - cx );
1471 double deltaTheta = theta2 - theta1;
1473 while( theta1 > 360 )
1476 while( deltaTheta < -180 )
1479 while( deltaTheta > 180 )
1482 setLong( wxS(
"StartAngle" ),
static_cast<long>( theta1 ) );
1483 setLong( wxS(
"Delta" ),
static_cast<long>( deltaTheta ) );
1486 else if( ( aLineType > 0 && aLineType < 129 ) || aArcType > 0 )
1488 long x1 = 0, y1 = 0, x2 = 0, y2 = 0, cx = 0, cy = 0;
1490 if( aElem->
HasProp( wxS(
"arctype_other_x1" ) ) )
1492 x1 = aElem->
PropLong( wxS(
"arctype_other_x1" ) );
1493 y1 = aElem->
PropLong( wxS(
"arctype_other_y1" ) );
1494 x2 = aElem->
PropLong( wxS(
"arctype_other_x2" ) );
1495 y2 = aElem->
PropLong( wxS(
"arctype_other_y2" ) );
1499 x1 = aElem->
PropLong( wxS(
"linetype_0_x1" ) );
1500 y1 = aElem->
PropLong( wxS(
"linetype_0_y1" ) );
1501 x2 = aElem->
PropLong( wxS(
"linetype_0_x2" ) );
1502 y2 = aElem->
PropLong( wxS(
"linetype_0_y2" ) );
1509 long dir = aElem->
Prop( wxS(
"ccw" ) ) == wxS(
"yes" ) ? 1 : -1;
1511 auto setAngles = [&](
int aStart,
int aDelta )
1513 setLong( wxS(
"StartAngle" ), aStart );
1514 setLong( wxS(
"Delta" ), dir * aDelta );
1517 if( aLineType == 0x78 || aArcType == 0x01 )
1519 cx = std::min( x1, x2 );
1520 cy = std::min( y1, y2 );
1521 setAngles( 180, 90 );
1523 else if( aLineType == 0x79 || aArcType == 0x02 )
1525 cx = std::max( x1, x2 );
1526 cy = std::min( y1, y2 );
1527 setAngles( 270, 90 );
1529 else if( aLineType == 0x7a || aArcType == 0x03 )
1531 cx = std::max( x1, x2 );
1532 cy = std::max( y1, y2 );
1535 else if( aLineType == 0x7b || aArcType == 0x04 )
1537 cx = std::min( x1, x2 );
1538 cy = std::max( y1, y2 );
1539 setAngles( 90, 90 );
1541 else if( aLineType == 0x7c || aArcType == 0x05 )
1543 cx = ( x1 + x2 ) / 2;
1544 cy = ( y1 + y2 ) / 2;
1545 setAngles( 90, 180 );
1547 else if( aLineType == 0x7d || aArcType == 0x06 )
1549 cx = ( x1 + x2 ) / 2;
1550 cy = ( y1 + y2 ) / 2;
1551 setAngles( 270, 180 );
1553 else if( aLineType == 0x7e || aArcType == 0x07 )
1555 cx = ( x1 + x2 ) / 2;
1556 cy = ( y1 + y2 ) / 2;
1557 setAngles( 180, 180 );
1559 else if( aLineType == 0x7f || aArcType == 0x08 )
1561 cx = ( x1 + x2 ) / 2;
1562 cy = ( y1 + y2 ) / 2;
1563 setAngles( 0, 180 );
1573 long radius =
static_cast<long>( std::hypot( cx - x2, cy - y2 ) );
1574 setLong( wxS(
"radius" ),
radius );
1575 setLong( wxS(
"x" ), cx );
1576 setLong( wxS(
"y" ), cy );
1585 int lineType = aRoot->
HasProp( wxS(
"linetype" ) ) ? (int) aRoot->
PropLong( wxS(
"linetype" ) ) : -1;
1591 aRoot->
props[wxS(
"x1" )] = aRoot->
Prop( wxS(
"linetype_0_x1" ) );
1592 aRoot->
props[wxS(
"y1" )] = aRoot->
Prop( wxS(
"linetype_0_y1" ) );
1593 aRoot->
props[wxS(
"x2" )] = aRoot->
Prop( wxS(
"linetype_0_x2" ) );
1594 aRoot->
props[wxS(
"y2" )] = aRoot->
Prop( wxS(
"linetype_0_y2" ) );
1606 if( aRoot->
HasProp( wxS(
"Delta" ) ) && aRoot->
PropLong( wxS(
"Delta" ) ) != 0 )
1607 aRoot->
props[wxS(
"curve" )] = aRoot->
Prop( wxS(
"Delta" ) );
1611 for(
const auto& child : aRoot->
children )
1620 int arcType = aRoot->
HasProp( wxS(
"arctype" ) ) ? (int) aRoot->
PropLong( wxS(
"arctype" ) ) : -1;
1624 aRoot->
props[wxS(
"x1" )] = aRoot->
Prop( wxS(
"arc_x1" ) );
1625 aRoot->
props[wxS(
"y1" )] = aRoot->
Prop( wxS(
"arc_y1" ) );
1626 aRoot->
props[wxS(
"x2" )] = aRoot->
Prop( wxS(
"arc_x2" ) );
1627 aRoot->
props[wxS(
"y2" )] = aRoot->
Prop( wxS(
"arc_y2" ) );
1629 else if( arcType > 0 )
1631 aRoot->
props[wxS(
"x1" )] = aRoot->
Prop( wxS(
"arctype_other_x1" ) );
1632 aRoot->
props[wxS(
"y1" )] = aRoot->
Prop( wxS(
"arctype_other_y1" ) );
1633 aRoot->
props[wxS(
"x2" )] = aRoot->
Prop( wxS(
"arctype_other_x2" ) );
1634 aRoot->
props[wxS(
"y2" )] = aRoot->
Prop( wxS(
"arctype_other_y2" ) );
1644 if( aRoot->
HasProp( wxS(
"Delta" ) ) && aRoot->
PropLong( wxS(
"Delta" ) ) != 0 )
1645 aRoot->
props[wxS(
"curve" )] = aRoot->
Prop( wxS(
"Delta" ) );
1648 for(
const auto& child : aRoot->
children )
1663 aRoot->
props[wxS(
"spacing" )] = aRoot->
PropDoubled( wxS(
"half_spacing" ) );
1664 aRoot->
props[wxS(
"isolate" )] = aRoot->
PropDoubled( wxS(
"half_isolate" ) );
1666 std::vector<std::unique_ptr<EGB_NODE>> rebuilt;
1668 for(
auto& child : aRoot->
children )
1672 rebuilt.push_back( std::move( child ) );
1676 auto vertex = std::make_unique<EGB_NODE>();
1677 vertex->name = wxS(
"vertex" );
1678 vertex->parent = aRoot;
1679 vertex->
props[wxS(
"x" )] = child->Prop( wxS(
"x1" ) );
1680 vertex->props[wxS(
"y" )] = child->Prop( wxS(
"y1" ) );
1682 if( child->HasProp( wxS(
"curve" ) ) )
1683 vertex->props[wxS(
"curve" )] = child->Prop( wxS(
"curve" ) );
1685 rebuilt.push_back( std::move( vertex ) );
1688 aRoot->
children = std::move( rebuilt );
1691 for(
const auto& child : aRoot->
children )
1703 aRoot->
props[wxS(
"extent" )] = wxS(
"1-16" );
1706 for(
const auto& child : aRoot->
children )
1717 static const wxString dimAttrs[] = { wxS(
"x" ), wxS(
"y" ), wxS(
"x1" ), wxS(
"y1" ),
1718 wxS(
"x2" ), wxS(
"y2" ), wxS(
"x3" ), wxS(
"y3" ),
1719 wxS(
"width" ), wxS(
"drill" ), wxS(
"diameter" ), wxS(
"radius" ),
1720 wxS(
"size" ), wxS(
"dx" ), wxS(
"dy" ), wxS(
"spacing" ),
1723 for(
const wxString& key : dimAttrs )
1725 auto it = aRoot->
props.find( key );
1727 if( it == aRoot->
props.end() )
1732 if( it->second.ToCDouble( &du ) )
1733 it->second = wxString::FromCDouble( du * 0.0001, 4 );
1736 for(
const auto& child : aRoot->
children )
1748 for(
const auto& child : aRoot->
children )
1757 if( aRoot->
HasProp( wxS(
"half_dx" ) ) )
1762 if( aRoot->
HasProp( wxS(
"half_dy" ) ) )
1768 for(
const auto& child : aRoot->
children )
1784 static const std::map<long, wxString> names = {
1785 { 0, wxS(
"square" ) }, { 1, wxS(
"round" ) }, { 2, wxS(
"octagon" ) },
1786 { 3, wxS(
"long" ) }, { 4, wxS(
"offset" ) } };
1788 auto it = names.find( aRoot->
PropLong( wxS(
"shape" ) ) );
1790 if( it != names.end() )
1791 aRoot->
props[wxS(
"shape" )] = it->second;
1793 aRoot->
props.erase( wxS(
"shape" ) );
1796 for(
const auto& child : aRoot->
children )
1806 if( aRoot->
HasProp( wxS(
"half_drill" ) ) )
1811 if( aRoot->
HasProp( wxS(
"half_diameter" ) ) )
1813 aRoot->
props[wxS(
"diameter" )] = aRoot->
PropDoubled( wxS(
"half_diameter" ) );
1816 if( aRoot->
HasProp( wxS(
"half_size" ) ) )
1822 for(
const auto& child : aRoot->
children )
1845 default:
return false;
1857 auto flagSet = [&](
const wxString& aKey )
1862 const wxString v = aRoot->
Prop( aKey );
1863 return v != wxS(
"no" ) && v != wxS(
"0" );
1866 bool mirrored = flagSet( wxS(
"mirrored" ) );
1867 bool spin = flagSet( wxS(
"spin" ) );
1869 long deg = aRoot->
PropLong( wxS(
"bin_rot" ) );
1878 degrees = ( deg & 0x3 ) * 90.0;
1880 degrees = 360.0 * ( deg & 0x0FFF ) / 4096.0;
1890 rot << wxS(
"R" ) << wxString::FromCDouble( degrees, 4 );
1892 aRoot->
props[wxS(
"rot" )] = rot;
1895 for(
const auto& child : aRoot->
children )
1906 static const wxString c_length[] = { wxS(
"point" ), wxS(
"short" ), wxS(
"middle" ), wxS(
"long" ) };
1907 static const wxString c_direction[] = { wxS(
"nc" ), wxS(
"in" ), wxS(
"out" ), wxS(
"io" ), wxS(
"oc" ),
1908 wxS(
"pwr" ), wxS(
"pas" ), wxS(
"hiz" ), wxS(
"sup" ) };
1909 static const wxString c_visible[] = { wxS(
"off" ), wxS(
"pad" ), wxS(
"pin" ), wxS(
"both" ) };
1910 static const wxString c_function[] = { wxS(
"none" ), wxS(
"dot" ), wxS(
"clk" ), wxS(
"dotclk" ) };
1912 auto mapField = [&](
EGB_NODE* aNode,
const wxString& aKey,
const wxString* aTable,
size_t aCount )
1917 long idx = aNode->
PropLong( aKey );
1919 if( idx >= 0 && idx < (
long) aCount )
1920 aNode->
props[aKey] = aTable[idx];
1929 mapField( aNode, wxS(
"length" ), c_length,
sizeof( c_length ) /
sizeof( c_length[0] ) );
1930 mapField( aNode, wxS(
"direction" ), c_direction,
sizeof( c_direction ) /
sizeof( c_direction[0] ) );
1931 mapField( aNode, wxS(
"visible" ), c_visible,
sizeof( c_visible ) /
sizeof( c_visible[0] ) );
1932 mapField( aNode, wxS(
"function" ), c_function,
sizeof( c_function ) /
sizeof( c_function[0] ) );
1977 if( aRoot->
Prop( wxS(
"name" ) ) == wxS(
"''" ) )
1978 aRoot->
props[wxS(
"name" )] = wxEmptyString;
2008 for(
const auto& child : aRoot->
children )
2025 default:
return false;
2038 std::vector<std::unique_ptr<EGB_NODE>> kept;
2041 for(
auto& child : aRoot->
children )
2045 if( eligible !=
nullptr )
2046 eligible->
props[wxS(
"textfield" )] = child->Prop( wxS(
"textfield" ) );
2052 kept.push_back( std::move( child ) );
2053 eligible = ( kept.back()->HasProp( wxS(
"textfield" ) ) &&
isLongTextHost( kept.back()->id ) )
2058 aRoot->
children = std::move( kept );
2060 for(
const auto& child : aRoot->
children )
2070 aRoot->
content = aRoot->
Prop( wxS(
"textfield" ) );
2072 for(
const auto& child : aRoot->
children )
2081 std::vector<std::unique_ptr<EGB_NODE>> kept;
2083 for(
auto& child : aDrawing->
children )
2089 if( child->HasProp( wxS(
"visible" ) ) )
2091 child->props[wxS(
"visible" )] = child->PropLong( wxS(
"visible" ) ) != 0 ? wxS(
"yes" ) : wxS(
"no" );
2094 child->parent = aLayers;
2095 aLayers->
children.push_back( std::move( child ) );
2099 kept.push_back( std::move( child ) );
2103 aDrawing->
children = std::move( kept );
2109 auto addParam = [&](
const wxString& aName,
const wxString& aValue )
2112 p->
props[wxS(
"name" )] = aName;
2113 p->
props[wxS(
"value" )] = aValue;
2116 addParam( wxS(
"mdWireWire" ), wxString::Format( wxS(
"%ldmil" ), aDrc.
mdWireWire ) );
2117 addParam( wxS(
"msWidth" ), wxString::Format( wxS(
"%ldmil" ), aDrc.
msWidth ) );
2118 addParam( wxS(
"rvPadTop" ), wxString::FromCDouble( aDrc.
rvPadTop ) );
2119 addParam( wxS(
"rvPadInner" ), wxString::FromCDouble( aDrc.
rvPadInner ) );
2120 addParam( wxS(
"rvPadBottom" ), wxString::FromCDouble( aDrc.
rvPadBottom ) );
2129 if( aLibraries ==
nullptr )
2135 std::vector<std::unique_ptr<EGB_NODE>> wrapped;
2137 for(
auto& child : aLibraries->
children )
2142 auto lib = std::make_unique<EGB_NODE>();
2144 lib->name = wxS(
"library" );
2145 lib->parent = aLibraries;
2146 child->
parent = lib.get();
2147 lib->
children.push_back( std::move( child ) );
2148 wrapped.push_back( std::move( lib ) );
2151 if( !wrapped.empty() )
2152 aLibraries->
children = std::move( wrapped );
2158 if( aElements ==
nullptr )
2163 for(
auto& el : aElements->
children )
2168 for(
auto& el2 : el->children )
2173 for(
const auto& [key, value] : el2->props )
2175 if( key == wxS(
"name" ) )
2177 if( value == wxS(
"-" ) )
2178 el->props[wxS(
"name" )] = wxS(
"HYPHEN" );
2180 el->props[wxS(
"name" )] = value;
2182 else if( key == wxS(
"value" ) )
2184 el->props[wxS(
"value" )] = value;
2194 if( aLibraries ==
nullptr )
2202 std::map<wxString, int> seenLibs;
2204 for(
size_t li = 0; li < aLibraries->
children.size(); li++ )
2215 wxString libName = pkgs ? pkgs->
Prop( wxS(
"library" ) ) : wxString();
2217 if( libName.IsEmpty() )
2218 libName = wxString::Format( wxS(
"lib%zu" ), li + 1 );
2224 if(
int& libCount = seenLibs[libName]; libCount++ > 0 )
2225 libName = wxString::Format( wxS(
"%s_%d" ), libName, libCount );
2227 lib->
props[wxS(
"name" )] = libName;
2229 if( pkgs ==
nullptr )
2232 std::map<wxString, int> seen;
2234 for(
size_t pi = 0; pi < pkgs->
children.size(); pi++ )
2237 wxString
name = pkg->
Prop( wxS(
"name" ) );
2239 if(
name.IsEmpty() )
2240 name = wxString::Format( wxS(
"pkg%zu" ), pi + 1 );
2244 if(
int& count = seen[
name]; count++ > 0 )
2245 name = wxString::Format( wxS(
"%s_%d" ),
name, count );
2251 if( aElements ==
nullptr )
2254 auto nameByIdx = [&](
EGB_NODE* aParent,
long aIdx ) -> wxString
2256 if( aParent ==
nullptr || aIdx < 1 || aIdx > (
long) aParent->
children.size() )
2259 return aParent->
children[aIdx - 1]->Prop( wxS(
"name" ) );
2262 for(
auto& el : aElements->
children )
2267 long libIdx = el->PropLong( wxS(
"library" ) );
2268 EGB_NODE* lib = ( libIdx >= 1 && libIdx <= (long) aLibraries->
children.size() )
2269 ? aLibraries->
children[libIdx - 1].get()
2272 if( lib ==
nullptr )
2275 el->props[wxS(
"library" )] = lib->
Prop( wxS(
"name" ) );
2278 wxString pkgName = nameByIdx( pkgs, el->
PropLong( wxS(
"package" ) ) );
2280 if( !pkgName.IsEmpty() )
2281 el->props[wxS(
"package" )] = pkgName;
2288 if( aSignals ==
nullptr || aElements ==
nullptr || aLibraries ==
nullptr )
2291 auto elemByIdx = [&](
long aIdx ) ->
EGB_NODE*
2293 if( aIdx < 1 || aIdx > (
long) aElements->
children.size() )
2296 return aElements->
children[aIdx - 1].get();
2299 auto libByIdx = [&](
long aIdx ) ->
EGB_NODE*
2301 if( aIdx < 1 || aIdx > (
long) aLibraries->
children.size() )
2304 return aLibraries->
children[aIdx - 1].get();
2309 if( aLib ==
nullptr )
2314 if( pkgs ==
nullptr || aIdx < 1 || aIdx > (
long) pkgs->
children.size() )
2317 return pkgs->
children[aIdx - 1].get();
2320 for(
auto& sig : aSignals->
children )
2324 for(
auto& cr : sig->children )
2329 long partNum = cr->PropLong( wxS(
"partnumber" ) );
2330 EGB_NODE* elem = elemByIdx( partNum );
2332 if( elem ==
nullptr )
2335 cr->props[wxS(
"element" )] = elem->
Prop( wxS(
"name" ) );
2341 if( pkg ==
nullptr )
2343 cr->props[wxS(
"pad" )] = wxS(
"PIN_NOT_FOUND" );
2347 long pinNum = cr->PropLong( wxS(
"pin" ) );
2350 for(
const auto& child : pkg->
children )
2352 int kind = child->id & 0xFF00;
2358 found = child.get();
2364 if( found ==
nullptr )
2365 cr->
props[wxS(
"pad" )] = wxS(
"PIN_NOT_FOUND" );
2366 else if( found->
HasProp( wxS(
"name" ) ) )
2367 cr->props[wxS(
"pad" )] = found->
Prop( wxS(
"name" ) );
2369 cr->props[wxS(
"pad" )] = cr->Prop( wxS(
"pin" ) );
2379 if( drawing ==
nullptr )
2392 if( board !=
nullptr )
2397 if( libraries ==
nullptr )
2398 THROW_IO_ERROR(
_(
"Eagle binary layout is missing a board/libraries node." ) );
2410 if( drcNode !=
nullptr )
2460 std::vector<std::unique_ptr<EGB_NODE>> kept;
2462 for(
auto& child : aRoot->
children )
2467 kept.push_back( std::move( child ) );
2470 aRoot->
children = std::move( kept );
2472 for(
const auto& child : aRoot->
children )
2479 wxXmlNode* xml =
new wxXmlNode( wxXML_ELEMENT_NODE, aNode->
name );
2481 for(
const auto& [key, value] : aNode->
props )
2482 xml->AddAttribute( key, value );
2484 if( !aNode->
content.IsEmpty() )
2485 xml->AddChild(
new wxXmlNode( wxXML_TEXT_NODE, wxEmptyString, aNode->
content ) );
2489 for(
const auto& child : aNode->
children )
2490 xml->AddChild(
toXml( child.get() ) );
2502 if( aBytes.size() < 24 )
2503 THROW_IO_ERROR(
_(
"File is too small to be an Eagle binary board." ) );
2510 m_root = std::make_unique<EGB_NODE>();
2512 m_root->name = wxS(
"eagle" );
2514 long numBlocks = -1;
2525 if( drawing !=
nullptr )
2527 long v1 = drawing->
HasProp( wxS(
"v1" ) ) ? drawing->
PropLong( wxS(
"v1" ) ) : 5;
2528 long v2 = drawing->
HasProp( wxS(
"v2" ) ) ? drawing->
PropLong( wxS(
"v2" ) ) : 0;
2529 m_root->props[wxS(
"version" )] = wxString::Format( wxS(
"%ld.%ld" ),
v1,
v2 );
2554 auto doc = std::make_unique<wxXmlDocument>();
2566 if( drawing ==
nullptr )
2567 THROW_IO_ERROR(
_(
"Eagle binary schematic has no drawing section." ) );
2571 if( schematic ==
nullptr )
2575 schematic->
name = wxS(
"schematic" );
2605std::vector<EAGLE_BIN_PARSER::EGB_NODE*>
2608 std::vector<EGB_NODE*> out;
2610 if( aParent !=
nullptr )
2612 for(
const auto& child : aParent->
children )
2614 if( child->id == aChildId )
2615 out.push_back( child.get() );
2626 if( aIdx >= 1 && aIdx <= (
long) aList.size() )
2627 return aList[aIdx - 1]->Prop( wxS(
"name" ) );
2643 aNode->
props[wxS(
"columns" )] = aNode->
Prop( wxS(
"cols" ) );
2659 aNode->
props[wxS(
"name" )] = aNode->
HasProp( wxS(
"textfield" ) )
2660 ? aNode->
Prop( wxS(
"textfield" ) )
2677 if( aNode->
HasProp( wxS(
"half_size" ) ) )
2678 sizeKey = wxS(
"half_size" );
2679 else if( aNode->
HasProp( wxS(
"size" ) ) )
2680 sizeKey = wxS(
"size" );
2682 if( !sizeKey.IsEmpty() && aNode->
PropLong( sizeKey ) >= 0 )
2710 if( aNode->
name == wxS(
"variants" ) )
2711 aNode->
name = wxS(
"devices" );
2719std::vector<EAGLE_BIN_PARSER::EGB_NODE*>
2722 auto wrapChildren = [](
EGB_NODE* aParent,
const wxString& aContainer,
2725 std::vector<std::unique_ptr<EGB_NODE>> kept;
2726 std::vector<std::unique_ptr<EGB_NODE>>
moved;
2728 for(
auto& child : aParent->
children )
2730 if( aPred( child.get() ) )
2731 moved.push_back( std::move( child ) );
2733 kept.push_back( std::move( child ) );
2736 aParent->
children = std::move( kept );
2743 for(
auto& node :
moved )
2753 wrapChildren( aSchematic, wxS(
"libraries" ),
2761 for(
size_t li = 0; li < libList.size(); li++ )
2774 libName = n->
Prop( wxS(
"library" ) );
2779 if( libName.IsEmpty() )
2780 libName = wxString::Format( wxS(
"lib%zu" ), li + 1 );
2782 lib->
props[wxS(
"name" )] = libName;
2790 std::map<wxString, int> dsSeen;
2792 for(
size_t di = 0; di < devicesetList.size(); di++ )
2795 wxString
name = ds->
Prop( wxS(
"name" ) );
2797 if(
name.IsEmpty() )
2798 name = wxString::Format( wxS(
"dset%zu" ), di + 1 );
2800 if(
int& count = dsSeen[
name]; count++ > 0 )
2801 name = wxString::Format( wxS(
"%s_%d" ),
name, count );
2808 gate->
props[wxS(
"symbol" )] =
nameByOrdinal( symbols, gate->PropLong( wxS(
"symno" ) ) );
2817 [](
const std::unique_ptr<EGB_NODE>& n )
2818 { return n->id == EGKW_SECT_PACKAGES; } ),
2827 const std::vector<EGB_NODE*>& aPackages )
2829 std::vector<std::vector<wxString>> gatePins;
2830 std::vector<wxString> gateNames;
2836 long symno = gate->
PropLong( wxS(
"symno" ) );
2837 std::vector<wxString> pins;
2839 if( symno >= 1 && symno <= (
long) aSymbols.size() )
2840 symbol = aSymbols[symno - 1];
2843 pins.push_back(
pin->Prop( wxS(
"name" ) ) );
2845 maxPins = std::max( maxPins, pins.size() );
2846 gateNames.push_back( gate->Prop( wxS(
"name" ) ) );
2847 gatePins.push_back( std::move( pins ) );
2852 long pkgno = variant->PropLong( wxS(
"package" ) );
2853 EGB_NODE*
package = ( pkgno >= 1 && pkgno <= (long) aPackages.size() ) ? aPackages[pkgno - 1] : nullptr;
2856 if( package !=
nullptr )
2857 variant->
props[wxS(
"package" )] = package->Prop( wxS(
"name" ) );
2859 variant->props.erase( wxS(
"package" ) );
2861 std::vector<uint8_t>
bytes;
2865 const wxString hex = conn->Prop( wxS(
"pads" ) );
2867 for(
size_t n = 0; n + 1 < hex.length(); n += 2 )
2869 unsigned long value = 0;
2870 hex.Mid( n, 2 ).ToULong( &value, 16 );
2871 bytes.push_back(
static_cast<uint8_t
>( value ) );
2875 variant->children.erase( std::remove_if( variant->children.begin(), variant->children.end(),
2876 [](
const std::unique_ptr<EGB_NODE>& n )
2877 { return n->id == EGKW_SECT_VARIANTCONNECTIONS; } ),
2878 variant->children.end() );
2880 if( package ==
nullptr ||
bytes.empty() || maxPins == 0 )
2883 std::vector<wxString> pads;
2885 for(
const auto& child : package->children )
2887 if( child->id == EGKW_SECT_PAD || child->id == EGKW_SECT_SMD )
2888 pads.push_back( child->Prop( wxS(
"name" ) ) );
2893 const unsigned width =
static_cast<unsigned>( aDeviceSet->
PropLong( wxS(
"pin_bits" ) ) );
2894 const size_t entrySize = aDeviceSet->
PropLong( wxS(
"con_byte" ) ) != 0 ? 1 : 2;
2899 if(
bytes.size() < pads.size() * entrySize )
2902 std::map<std::pair<size_t, size_t>, wxString> padList;
2905 for(
size_t pad = 0;
pad < pads.size() && valid;
pad++ )
2907 unsigned entry = bytes[pad * entrySize];
2909 if( entrySize == 2 )
2910 entry |= static_cast<unsigned>( bytes[pad * 2 + 1] ) << 8;
2915 size_t gate = entry >> width;
2916 size_t pin = entry & ( ( 1u << width ) - 1 );
2918 if( gate < 1 || gate > gatePins.size() || pin < 1 || pin > gatePins[gate - 1].size() )
2924 wxString& list = padList[{ gate - 1, pin - 1 }];
2925 list += list.IsEmpty() ? pads[
pad] : wxS(
" " ) + pads[
pad];
2930 wxLogTrace(
traceEagleIo, wxS(
"Eagle bin: connects of device '%s' do not match its symbols" ),
2931 variant->Prop( wxS(
"name" ) ) );
2937 for(
const auto& [key, padNames] : padList )
2940 connect->
props[wxS(
"gate" )] = gateNames[key.first];
2941 connect->
props[wxS(
"pin" )] = gatePins[key.first][key.second];
2942 connect->
props[wxS(
"pad" )] = padNames;
2949 const std::vector<EGB_NODE*>& aLibList )
2951 auto adopt = [](
EGB_NODE* aParent,
EGB_NODE*& aSlot,
const wxString& aName,
2952 std::unique_ptr<EGB_NODE> aNode )
2954 if( aSlot ==
nullptr )
2955 aSlot = aParent->
AddChild( 0, aName );
2965 std::vector<std::unique_ptr<EGB_NODE>> flat = std::move( aSchematic->
children );
2968 std::vector<std::unique_ptr<EGB_NODE>> sheetNodes;
2969 std::vector<std::unique_ptr<EGB_NODE>> globalParts;
2970 std::map<wxString, bool> seenPart;
2979 for(
auto& node : flat )
2982 if( node->name == wxS(
"libraries" ) )
2984 aSchematic->
children.push_back( std::move( node ) );
2993 curSheet = node.get();
2994 curPlain = curInstances = curNets = curBusses =
nullptr;
2996 std::vector<std::unique_ptr<EGB_NODE>> drawables = std::move( curSheet->
children );
3000 adopt( curSheet, curPlain, wxS(
"plain" ), std::move(
drawable ) );
3002 sheetNodes.push_back( std::move( node ) );
3009 long libno = part->
PropLong( wxS(
"lib" ) );
3010 long devno = part->
PropLong( wxS(
"device" ) );
3011 long varno = part->
PropLong( wxS(
"variant" ) );
3013 EGB_NODE* lib = ( libno >= 1 && libno <= (long) aLibList.size() ) ? aLibList[libno - 1]
3015 std::vector<EGB_NODE*> devicesets =
3018 EGB_NODE* ds = ( devno >= 1 && devno <= (long) devicesets.size() ) ? devicesets[devno - 1]
3020 std::vector<EGB_NODE*> variants =
3023 std::vector<EGB_NODE*> gates =
3027 wxString partName = part->
Prop( wxS(
"name" ) );
3029 part->
props[wxS(
"library" )] = lib ? lib->
Prop( wxS(
"name" ) ) : wxString();
3030 part->
props[wxS(
"deviceset" )] = ds ? ds->
Prop( wxS(
"name" ) ) : wxString();
3036 part->
props.erase( wxS(
"technology" ) );
3039 std::vector<std::unique_ptr<EGB_NODE>> partKept;
3045 partKept.push_back( std::move( sub ) );
3049 sub->props[wxS(
"part" )] = partName;
3050 sub->props[wxS(
"gate" )] =
nameByOrdinal( gates, sub->PropLong( wxS(
"gateno" ) ) );
3051 adopt( curSheet, curInstances, wxS(
"instances" ), std::move( sub ) );
3054 part->
children = std::move( partKept );
3057 if( !seenPart[partName] )
3059 seenPart[partName] =
true;
3060 node->parent = aSchematic;
3061 globalParts.push_back( std::move( node ) );
3069 node->props[wxS(
"class" )] =
3070 node->HasProp( wxS(
"netclass" ) ) ? node->Prop( wxS(
"netclass" ) ) : wxString( wxS(
"0" ) );
3073 seg->name = wxS(
"segment" );
3075 if( curSheet !=
nullptr )
3076 adopt( curSheet, curNets, wxS(
"nets" ), std::move( node ) );
3083 if( curSheet !=
nullptr )
3084 adopt( curSheet, curBusses, wxS(
"busses" ), std::move( node ) );
3092 if( curSheet !=
nullptr )
3093 adopt( curSheet, curPlain, wxS(
"plain" ), std::move( node ) );
3104 for(
auto& sheet : sheetNodes )
3105 sheetsNode->
AdoptChild( std::move( sheet ) );
3109 for(
auto& part : globalParts )
wxXmlNode * toXml(const EGB_NODE *aNode) const
std::unique_ptr< wxXmlDocument > Parse(const std::vector< uint8_t > &aBytes)
Parse a binary Eagle board into an XML DOM compatible with the XML walker.
static wxString nameByOrdinal(const std::vector< EGB_NODE * > &aList, long aIdx)
void requireBytes(size_t aOffs, size_t aLen) const
uint32_t loadUbf(size_t aOffs, uint32_t aField) const
void postprocCircles(EGB_NODE *aRoot)
bool readDrc(DRC_CTX &aDrc)
void postprocSchAttrs(EGB_NODE *aRoot)
void postprocFreeText(EGB_NODE *aRoot)
std::vector< EGB_NODE * > resolveSchLibraries(EGB_NODE *aSchematic)
bool isRotatable(int aId) const
void postprocLibs(EGB_NODE *aLibraries)
std::vector< LONG_REF > m_longRefs
const wxString & nextLongText()
uint32_t loadU32(size_t aOffs, unsigned aLen) const
void postprocTextContent(EGB_NODE *aRoot)
size_t m_pos
current read cursor
void postprocPolygons(EGB_NODE *aRoot)
void postprocUnits(EGB_NODE *aRoot)
void postprocArcs(EGB_NODE *aRoot)
wxString loadStr(size_t aOffs, unsigned aLen) const
void fixLongText(EGB_NODE *aNode, const wxString &aField)
void renameSchSections(EGB_NODE *aSchematic)
void postProcess(EGB_NODE *aRoot, const DRC_CTX &aDrc)
int readBlock(long &aNumBlocks, EGB_NODE *aParent)
void postprocSmd(EGB_NODE *aRoot)
const std::vector< uint8_t > * m_buf
file contents, not owned
void postprocContactRefs(EGB_NODE *aSignals, EGB_NODE *aElements, EGB_NODE *aLibraries)
void postProcessSchematic(EGB_NODE *aRoot)
void resolveSchConnects(EGB_NODE *aDeviceSet, const std::vector< EGB_NODE * > &aSymbols, const std::vector< EGB_NODE * > &aPackages)
void postprocWires(EGB_NODE *aRoot)
std::vector< wxString > m_freeText
NUL-delimited notes strings.
void postprocLongText(EGB_NODE *aRoot)
void postprocLayers(EGB_NODE *aDrawing, EGB_NODE *aLayers)
bool loadBmb(size_t aOffs, uint32_t aMask) const
void postprocPadShapes(EGB_NODE *aRoot)
void postprocRotation(EGB_NODE *aRoot)
void postprocPins(EGB_NODE *aRoot)
void postprocAttributes(EGB_NODE *aRoot)
void arcDecode(EGB_NODE *aElem, int aArcType, int aLineType)
double loadDouble(size_t aOffs) const
bool isLongTextHost(int aId) const
int m_majorVer
format major version from the drawing header
static bool IsBinaryEagle(wxInputStream &aStream)
Probe the first two bytes for the binary magic without changing the stream position.
std::vector< wxString > matchLongRefsInRecordOrder() const
void postprocDimensions(EGB_NODE *aRoot)
void resegmentSchSheets(EGB_NODE *aSchematic, const std::vector< EGB_NODE * > &aLibList)
std::unique_ptr< EGB_NODE > m_root
wxString m_invalidText
returned when out of strings
static std::vector< EGB_NODE * > childrenById(EGB_NODE *aParent, int aChildId)
void postprocRequiredAttrs(EGB_NODE *aRoot)
void postprocDrc(EGB_NODE *aDrcNode, const DRC_CTX &aDrc)
void postprocVias(EGB_NODE *aRoot)
void postprocNames(EGB_NODE *aLibraries, EGB_NODE *aElements)
void resolveLongPointers()
void postprocElements(EGB_NODE *aElements)
int32_t loadS32(size_t aOffs, unsigned aLen) const
@ EGKW_SECT_PACKAGEVARIANT
@ EGKW_SECT_SCHEMACONNECTION
@ EGKW_SECT_VARIANTCONNECTIONS
@ EGKW_SECT_ATTRIBUTEVALUE
#define THROW_IO_ERROR(msg)
macro which captures the "call site" values of FILE_, __FUNCTION & LINE
#define THROW_IO_ERRORF(msg,...)
const wxChar *const traceEagleIo
This file contains miscellaneous commonly used macros and functions.
EDA_ANGLE abs(const EDA_ANGLE &aAngle)
DRC values pulled from the trailing 244-byte block (or sane defaults).
Lightweight mutable tree node for the intermediate Eagle binary tree.
std::map< wxString, wxString > props
long PropLong(const wxString &aKey) const
EGB_NODE * AdoptChild(std::unique_ptr< EGB_NODE > aChild)
Move an existing node in as a child, repointing its parent link.
std::vector< std::unique_ptr< EGB_NODE > > children
EGB_NODE * FindChildById(int aId) const
bool HasProp(const wxString &aKey) const
void ForEach(FN &&aFn)
Apply aFn to this node and every descendant, pre-order.
EGB_NODE * AddChild(int aId, const wxString &aName)
wxString PropDoubled(const wxString &aKey) const
Format a property doubled in 64-bit so the half-to-full widening cannot overflow a 32-bit long.
wxString Prop(const wxString &aKey) const
EGB_NODE * FindChildByName(const wxString &aName) const
wxString content
PCDATA emitted as the XML node's text body.
static std::vector< uint8_t > bytes(const std::string &aText)
wxLogTrace helper definitions.