39#include <wx/xml/xml.h>
125constexpr uint32_t BITFIELD( uint32_t aWidth, uint32_t aFirst, uint32_t aLast )
127 return ( aWidth << 16 ) | ( aFirst << 8 ) | aLast;
142 const char* treeName;
155 unsigned cmd, cmdMask;
168 0, 0, SS_DIRECT, nullptr \
172 nullptr, T_INT, 0, 0 \
176const SCRIPT_ROW g_script[] = {
181 { { 4, 4, SS_RECURSIVE_MINUS_1,
nullptr },
TERM_S },
182 { {
"subsecs", T_INT, 2, 2 },
183 {
"numsecs", T_INT, 4, 4 },
184 {
"subsecsMSB", T_INT, 3, 1 },
185 {
"subsecsLSB", T_INT, 2, 1 },
186 {
"numsecsMSB2", T_INT, 7, 1 },
187 {
"numsecsMSB1", T_INT, 6, 1 },
188 {
"numsecsMSB0", T_INT, 5, 1 },
189 {
"numsecsLSB", T_INT, 4, 1 },
190 {
"v1", T_INT, 8, 1 },
191 {
"v2", T_INT, 9, 1 },
199 { {
"display", T_BMB, 2, 0x01 },
200 {
"visible", T_BMB, 2, 0x02 },
201 {
"unit", T_UBF, 3, BITFIELD( 1, 0, 3 ) },
202 {
"altunit", T_UBF, 3, BITFIELD( 1, 4, 7 ) },
203 {
"multiple", T_INT, 4, 3 },
204 {
"size", T_DBL, 8, 8 },
205 {
"altsize", T_DBL, 16, 8 },
212 { {
"side", T_BMB, 2, 0x10 },
213 {
"visible", T_UBF, 2, BITFIELD( 1, 2, 3 ) },
214 {
"active", T_BMB, 2, 0x02 },
215 {
"number", T_UBF, 3, BITFIELD( 1, 0, 7 ) },
216 {
"other", T_INT, 4, 1 },
217 {
"fill", T_UBF, 5, BITFIELD( 1, 0, 3 ) },
218 {
"color", T_UBF, 6, BITFIELD( 1, 0, 5 ) },
219 {
"name", T_STR, 15, 9 },
225 { { 4, 4, SS_DIRECT,
nullptr },
TERM_S },
226 { {
"shtsubsecs", T_INT, 8, 4 }, {
"atrsubsecs", T_INT, 12, 4 }, {
"xref_format", T_STR, 19, 5 },
TERM_A } },
231 { { 4, 4, SS_RECURSIVE,
nullptr }, { 8, 4, SS_RECURSIVE,
nullptr }, { 12, 4, SS_RECURSIVE,
nullptr },
TERM_S },
232 { {
"devsubsecs", T_INT, 4, 4 },
233 {
"symsubsecs", T_INT, 8, 4 },
234 {
"pacsubsecs", T_INT, 12, 4 },
235 {
"children", T_INT, 8, 4 },
236 {
"name", T_STR, 16, 8 },
242 { { 4, 4, SS_DIRECT,
nullptr },
TERM_S },
243 { {
"children", T_INT, 8, 4 }, {
"library", T_STR, 16, 8 },
TERM_A } },
248 { { 4, 4, SS_RECURSIVE,
nullptr },
TERM_S },
249 { {
"children", T_INT, 8, 4 }, {
"library", T_STR, 16, 8 },
TERM_A } },
254 { { 4, 4, SS_RECURSIVE,
nullptr },
TERM_S },
255 { {
"subsects", T_INT, 4, 4 },
256 {
"children", T_INT, 8, 2 },
257 {
"desc", T_STR, 10, 6 },
258 {
"library", T_STR, 16, 8 },
264 { { 2, 2, SS_DIRECT,
nullptr },
TERM_S },
265 { {
"minx", T_INT, 4, 2 },
266 {
"miny", T_INT, 6, 2 },
267 {
"maxx", T_INT, 8, 2 },
268 {
"maxy", T_INT, 10, 2 },
269 {
"partsubsecs", T_INT, 12, 4 },
270 {
"bussubsecs", T_INT, 16, 4 },
271 {
"netsubsecs", T_INT, 20, 4 },
277 { { 12, 4, SS_RECURSIVE,
"libraries" },
278 { 2, 2, SS_DIRECT,
"plain" },
279 { 16, 4, SS_RECURSIVE,
"elements" },
280 { 20, 4, SS_RECURSIVE,
"signals" },
282 { {
"minx", T_INT, 4, 2 },
283 {
"miny", T_INT, 6, 2 },
284 {
"maxx", T_INT, 8, 2 },
285 {
"maxy", T_INT, 10, 2 },
286 {
"defsubsecs", T_INT, 12, 4 },
287 {
"pacsubsecs", T_INT, 16, 4 },
288 {
"netsubsecs", T_INT, 20, 4 },
294 { { 2, 2, SS_DIRECT,
nullptr },
TERM_S },
295 { {
"minx", T_INT, 4, 2 },
296 {
"miny", T_INT, 6, 2 },
297 {
"maxx", T_INT, 8, 2 },
298 {
"maxy", T_INT, 10, 2 },
299 {
"airwires", T_BMB, 12, 0x02 },
300 {
"netclass", T_UBF, 13, BITFIELD( 1, 0, 3 ) },
301 {
"name", T_STR, 16, 8 },
307 { { 2, 2, SS_DIRECT,
nullptr },
TERM_S },
308 { {
"minx", T_INT, 4, 2 },
309 {
"miny", T_INT, 6, 2 },
310 {
"maxx", T_INT, 8, 2 },
311 {
"maxy", T_INT, 10, 2 },
312 {
"name", T_STR, 16, 8 },
320 { { 2, 2, SS_RECURSIVE,
nullptr },
TERM_S },
321 { {
"minx", T_INT, 4, 2 },
322 {
"miny", T_INT, 6, 2 },
323 {
"maxx", T_INT, 8, 2 },
324 {
"maxy", T_INT, 10, 2 },
325 {
"desc", T_STR, 13, 5 },
326 {
"name", T_STR, 18, 6 },
332 { { 2, 2, SS_RECURSIVE,
nullptr },
TERM_S },
333 { {
"minx", T_INT, 4, 2 },
334 {
"miny", T_INT, 6, 2 },
335 {
"maxx", T_INT, 8, 2 },
336 {
"maxy", T_INT, 10, 2 },
337 {
"netclass", T_UBF, 13, BITFIELD( 1, 0, 3 ) },
338 {
"name", T_STR, 16, 8 },
344 { { 2, 2, SS_RECURSIVE,
nullptr },
TERM_S },
345 { {
"minx", T_INT, 4, 2 }, {
"miny", T_INT, 6, 2 }, {
"maxx", T_INT, 8, 2 }, {
"maxy", T_INT, 10, 2 },
TERM_A } },
352 { { 2, 2, SS_DIRECT,
nullptr },
TERM_S },
353 { {
"minx", T_INT, 4, 2 },
354 {
"miny", T_INT, 6, 2 },
355 {
"maxx", T_INT, 8, 2 },
356 {
"maxy", T_INT, 10, 2 },
357 {
"width", T_INT, 12, 2 },
358 {
"spacing", T_INT, 14, 2 },
359 {
"isolate", T_INT, 16, 2 },
360 {
"layer", T_UBF, 18, BITFIELD( 1, 0, 7 ) },
361 {
"pour", T_BMB, 19, 0x01 },
362 {
"rank", T_BMB, 19, BITFIELD( 1, 1, 3 ) },
363 {
"thermals", T_BMB, 19, 0x80 },
364 {
"orphans", T_BMB, 19, 0x40 },
371 { {
"layer", T_UBF, 3, BITFIELD( 1, 0, 7 ) },
372 {
"half_width", T_INT, 20, 2 },
373 {
"stflags", T_BMB, 22, 0x33 },
374 {
"clockwise", T_BMB, 22, 0x20 },
375 {
"linetype", T_UBF, 23, BITFIELD( 1, 0, 7 ) },
376 {
"linetype_0_x1", T_INT, 4, 4 },
377 {
"linetype_0_y1", T_INT, 8, 4 },
378 {
"linetype_0_x2", T_INT, 12, 4 },
379 {
"linetype_0_y2", T_INT, 16, 4 },
380 {
"arc_negflags", T_UBF, 19, BITFIELD( 1, 0, 4 ) },
381 {
"arc_c1", T_INT, 7, 1 },
382 {
"arc_c2", T_INT, 11, 1 },
383 {
"arc_c3", T_INT, 15, 1 },
384 {
"arc_x1", T_INT, 4, 3 },
385 {
"arc_y1", T_INT, 8, 3 },
386 {
"arc_x2", T_INT, 12, 3 },
387 {
"arc_y2", T_INT, 16, 3 },
394 { {
"layer", T_UBF, 3, BITFIELD( 1, 0, 7 ) },
395 {
"half_width", T_INT, 20, 2 },
396 {
"clockwise", T_BMB, 22, 0x20 },
397 {
"arctype", T_UBF, 23, BITFIELD( 1, 0, 7 ) },
398 {
"arc_negflags", T_UBF, 19, BITFIELD( 1, 0, 7 ) },
399 {
"arc_c1", T_INT, 7, 1 },
400 {
"arc_c2", T_INT, 11, 1 },
401 {
"arc_c3", T_INT, 15, 1 },
402 {
"arc_x1", T_INT, 4, 3 },
403 {
"arc_y1", T_INT, 8, 3 },
404 {
"arc_x2", T_INT, 12, 3 },
405 {
"arc_y2", T_INT, 16, 3 },
406 {
"arctype_other_x1", T_INT, 4, 4 },
407 {
"arctype_other_y1", T_INT, 8, 4 },
408 {
"arctype_other_x2", T_INT, 12, 4 },
409 {
"arctype_other_y2", T_INT, 16, 4 },
416 { {
"layer", T_UBF, 3, BITFIELD( 1, 0, 7 ) },
417 {
"x", T_INT, 4, 4 },
418 {
"y", T_INT, 8, 4 },
419 {
"radius", T_INT, 12, 4 },
420 {
"half_width", T_INT, 20, 4 },
429 { {
"layer", T_UBF, 3, BITFIELD( 1, 0, 7 ) },
430 {
"x1", T_INT, 4, 4 },
431 {
"y1", T_INT, 8, 4 },
432 {
"x2", T_INT, 12, 4 },
433 {
"y2", T_INT, 16, 4 },
434 {
"bin_rot", T_INT, 20, 2 },
441 { {
"layer", T_UBF, 3, BITFIELD( 1, 0, 7 ) },
442 {
"x", T_INT, 4, 4 },
443 {
"y", T_INT, 8, 4 },
444 {
"width_2", T_INT, 12, 2 },
451 { {
"x", T_INT, 4, 4 },
452 {
"y", T_INT, 8, 4 },
453 {
"half_diameter", T_UBF, 12, BITFIELD( 2, 0, 15 ) },
454 {
"half_drill", T_UBF, 12, BITFIELD( 2, 0, 15 ) },
463 { {
"shape", T_INT, 2, 1 },
464 {
"x", T_INT, 4, 4 },
465 {
"y", T_INT, 8, 4 },
466 {
"half_drill", T_UBF, 12, BITFIELD( 2, 0, 15 ) },
467 {
"half_diameter", T_UBF, 14, BITFIELD( 2, 0, 15 ) },
468 {
"layers", T_UBF, 16, BITFIELD( 1, 0, 7 ) },
469 {
"stop", T_BMB, 17, 0x01 },
487 { {
"shape", T_INT, 2, 1 },
488 {
"x", T_INT, 4, 4 },
489 {
"y", T_INT, 8, 4 },
490 {
"half_drill", T_UBF, 12, BITFIELD( 2, 0, 15 ) },
491 {
"half_diameter", T_UBF, 14, BITFIELD( 2, 0, 15 ) },
492 {
"name", T_STR, 16, 8 },
499 { {
"roundness", T_INT, 2, 1 },
500 {
"layer", T_UBF, 3, BITFIELD( 1, 0, 7 ) },
501 {
"x", T_INT, 4, 4 },
502 {
"y", T_INT, 8, 4 },
503 {
"half_dx", T_UBF, 12, BITFIELD( 2, 0, 15 ) },
504 {
"half_dy", T_UBF, 14, BITFIELD( 2, 0, 15 ) },
505 {
"name", T_STR, 16, 8 },
512 { {
"shape", T_INT, 2, 1 },
513 {
"x", T_INT, 4, 4 },
514 {
"y", T_INT, 8, 4 },
515 {
"half_drill", T_UBF, 12, BITFIELD( 2, 0, 15 ) },
516 {
"half_diameter", T_UBF, 14, BITFIELD( 2, 0, 15 ) },
517 {
"bin_rot", T_INT, 16, 2 },
518 {
"stop", T_BMB, 18, 0x01 },
519 {
"thermals", T_BMB, 18, 0x04 },
520 {
"first", T_BMB, 18, 0x08 },
521 {
"name", T_STR, 19, 5 },
528 { {
"roundness", T_INT, 2, 1 },
529 {
"layer", T_UBF, 3, BITFIELD( 1, 0, 7 ) },
530 {
"x", T_INT, 4, 4 },
531 {
"y", T_INT, 8, 4 },
532 {
"half_dx", T_UBF, 12, BITFIELD( 2, 0, 15 ) },
533 {
"half_dy", T_UBF, 14, BITFIELD( 2, 0, 15 ) },
534 {
"bin_rot", T_UBF, 16, BITFIELD( 2, 0, 11 ) },
535 {
"stop", T_BMB, 18, 0x01 },
536 {
"cream", T_BMB, 18, 0x02 },
537 {
"thermals", T_BMB, 18, 0x04 },
538 {
"first", T_BMB, 18, 0x08 },
539 {
"name", T_STR, 19, 5 },
546 { {
"function", T_UBF, 2, BITFIELD( 1, 0, 1 ) },
547 {
"visible", T_UBF, 2, BITFIELD( 1, 6, 7 ) },
548 {
"x", T_INT, 4, 4 },
549 {
"y", T_INT, 8, 4 },
550 {
"direction", T_UBF, 12, BITFIELD( 1, 0, 3 ) },
551 {
"length", T_UBF, 12, BITFIELD( 1, 4, 5 ) },
552 {
"bin_rot", T_UBF, 12, BITFIELD( 1, 6, 7 ) },
553 {
"swaplevel", T_INT, 13, 1 },
554 {
"name", T_STR, 14, 10 },
561 { {
"x", T_INT, 4, 4 },
562 {
"y", T_INT, 8, 4 },
563 {
"addlevel", T_INT, 12, 1 },
564 {
"swap", T_INT, 13, 1 },
565 {
"symno", T_INT, 14, 2 },
566 {
"name", T_STR, 16, 8 },
576 { { 2, 2, SS_DIRECT,
nullptr },
TERM_S },
577 { {
"x", T_INT, 4, 4 },
578 {
"y", T_INT, 8, 4 },
579 {
"library", T_INT, 12, 2 },
580 {
"package", T_INT, 14, 2 },
581 {
"bin_rot", T_UBF, 16, BITFIELD( 2, 0, 11 ) },
582 {
"mirrored", T_BMB, 17, 0x10 },
583 {
"spin", T_BMB, 17, 0x40 },
590 { {
"name", T_STR, 2, 8 }, {
"value", T_STR, 10, 14 },
TERM_A } },
595 { { 2, 2, SS_DIRECT,
nullptr },
TERM_S },
596 { {
"x", T_INT, 4, 4 },
597 {
"y", T_INT, 8, 4 },
598 {
"placed", T_INT, 12, 2 },
599 {
"gateno", T_INT, 14, 2 },
600 {
"bin_rot", T_UBF, 16, BITFIELD( 2, 10, 11 ) },
601 {
"mirrored", T_UBF, 16, BITFIELD( 2, 12, 12 ) },
602 {
"smashed", T_BMB, 18, 0x01 },
609 { {
"layer", T_UBF, 3, BITFIELD( 1, 0, 7 ) },
610 {
"x", T_INT, 4, 4 },
611 {
"y", T_INT, 8, 4 },
612 {
"half_size", T_INT, 12, 2 },
613 {
"ratio", T_UBF, 14, BITFIELD( 2, 2, 6 ) },
614 {
"bin_rot", T_UBF, 16, BITFIELD( 2, 0, 11 ) },
615 {
"mirrored", T_UBF, 16, BITFIELD( 2, 12, 12 ) },
616 {
"spin", T_UBF, 16, BITFIELD( 2, 14, 14 ) },
617 {
"textfield", T_STR, 18, 5 },
621 {
EGKW_SECT_LONGTEXT, 0xFFFF,
"longtext", {
TERM_F }, {
TERM_S }, { {
"textfield", T_STR, 2, 22 },
TERM_A } },
627 { {
"layer", T_UBF, 3, BITFIELD( 1, 0, 7 ) },
628 {
"x", T_INT, 4, 4 },
629 {
"y", T_INT, 8, 4 },
630 {
"size", T_INT, 12, 2 },
631 {
"ratio", T_UBF, 14, BITFIELD( 2, 2, 6 ) },
632 {
"bin_rot", T_UBF, 16, BITFIELD( 2, 0, 11 ) },
633 {
"mirrored", T_UBF, 16, BITFIELD( 2, 12, 12 ) },
634 {
"spin", T_UBF, 16, BITFIELD( 2, 14, 14 ) },
635 {
"textfield", T_STR, 18, 5 },
642 { {
"layer", T_UBF, 3, BITFIELD( 1, 0, 7 ) },
643 {
"x", T_INT, 4, 4 },
644 {
"y", T_INT, 8, 4 },
645 {
"size", T_INT, 12, 2 },
646 {
"ratio", T_UBF, 14, BITFIELD( 2, 2, 6 ) },
647 {
"bin_rot", T_UBF, 16, BITFIELD( 2, 0, 11 ) },
648 {
"mirrored", T_UBF, 16, BITFIELD( 2, 12, 12 ) },
649 {
"spin", T_UBF, 16, BITFIELD( 2, 14, 14 ) },
650 {
"textfield", T_STR, 18, 5 },
657 { {
"layer", T_UBF, 3, BITFIELD( 1, 0, 7 ) },
658 {
"x", T_INT, 4, 4 },
659 {
"y", T_INT, 8, 4 },
660 {
"size", T_INT, 12, 2 },
661 {
"ratio", T_UBF, 14, BITFIELD( 2, 2, 6 ) },
662 {
"bin_rot", T_UBF, 16, BITFIELD( 2, 0, 11 ) },
663 {
"mirrored", T_UBF, 16, BITFIELD( 2, 12, 12 ) },
664 {
"spin", T_UBF, 16, BITFIELD( 2, 14, 14 ) },
665 {
"textfield", T_STR, 18, 5 },
671 { { 2, 2, SS_DIRECT,
nullptr },
TERM_S },
672 { {
"package", T_INT, 4, 2 }, {
"table", T_STR, 6, 13 }, {
"name", T_STR, 19, 5 },
TERM_A } },
679 { { 4, 2, SS_RECURSIVE,
"variants" }, { 2, 2, SS_RECURSIVE,
"gates" },
TERM_S },
680 { {
"gates", T_INT, 2, 2 },
681 {
"variants", T_INT, 4, 2 },
682 {
"prefix", T_STR, 8, 5 },
683 {
"desc", T_STR, 13, 5 },
684 {
"name", T_STR, 18, 5 },
690 { { 2, 2, SS_RECURSIVE,
nullptr },
TERM_S },
691 { {
"lib", T_INT, 4, 2 },
692 {
"device", T_INT, 6, 2 },
693 {
"variant", T_INT, 8, 1 },
694 {
"technology", T_INT, 9, 2 },
695 {
"name", T_STR, 11, 5 },
696 {
"value", T_STR, 16, 8 },
706 { {
"partnumber", T_INT, 4, 2 }, {
"pin", T_INT, 6, 2 },
TERM_A } },
712 { {
"layer", T_UBF, 3, BITFIELD( 1, 0, 7 ) },
713 {
"x", T_INT, 4, 4 },
714 {
"y", T_INT, 8, 4 },
715 {
"size", T_INT, 12, 2 },
716 {
"ratio", T_UBF, 14, BITFIELD( 2, 2, 6 ) },
717 {
"bin_rot", T_UBF, 16, BITFIELD( 2, 0, 11 ) },
718 {
"mirrored", T_UBF, 16, BITFIELD( 2, 12, 12 ) },
719 {
"spin", T_UBF, 16, BITFIELD( 2, 14, 14 ) },
720 {
"textfield", T_STR, 18, 5 },
727 { {
"layer", T_UBF, 3, BITFIELD( 1, 0, 7 ) },
728 {
"x", T_INT, 4, 4 },
729 {
"y", T_INT, 8, 4 },
730 {
"size", T_INT, 12, 2 },
731 {
"ratio", T_UBF, 14, BITFIELD( 2, 2, 6 ) },
732 {
"bin_rot", T_UBF, 16, BITFIELD( 2, 0, 11 ) },
733 {
"mirrored", T_UBF, 16, BITFIELD( 2, 12, 12 ) },
734 {
"spin", T_UBF, 16, BITFIELD( 2, 14, 14 ) },
735 {
"textfield", T_STR, 18, 5 },
744 { {
"layer", T_UBF, 3, BITFIELD( 1, 0, 7 ) },
745 {
"x", T_INT, 4, 4 },
746 {
"y", T_INT, 8, 4 },
747 {
"size", T_INT, 12, 2 },
748 {
"ratio", T_UBF, 14, BITFIELD( 2, 2, 6 ) },
749 {
"bin_rot", T_UBF, 16, BITFIELD( 2, 0, 11 ) },
750 {
"mirrored", T_UBF, 16, BITFIELD( 2, 12, 12 ) },
751 {
"spin", T_UBF, 16, BITFIELD( 2, 14, 14 ) },
752 {
"textfield", T_STR, 18, 5 },
759 { {
"symbol", T_STR, 2, 5 }, {
"attribute", T_STR, 7, 17 },
TERM_A } },
765 { {
"layer", T_UBF, 3, BITFIELD( 1, 0, 7 ) },
766 {
"x1", T_INT, 4, 4 },
767 {
"y1", T_INT, 8, 4 },
768 {
"x2", T_INT, 12, 4 },
769 {
"y2", T_INT, 16, 4 },
770 {
"cols", T_INT, 20, 1 },
771 {
"rows", T_INT, 21, 1 },
772 {
"borders", T_INT, 22, 1 },
779 { {
"layer", T_UBF, 3, BITFIELD( 1, 0, 7 ) },
780 {
"x", T_INT, 4, 4 },
781 {
"y", T_INT, 8, 4 },
782 {
"size", T_INT, 12, 2 },
783 {
"ratio", T_UBF, 14, BITFIELD( 2, 2, 6 ) },
784 {
"bin_rot", T_UBF, 16, BITFIELD( 2, 0, 11 ) },
785 {
"mirrored", T_UBF, 16, BITFIELD( 2, 12, 12 ) },
786 {
"spin", T_UBF, 16, BITFIELD( 2, 14, 14 ) },
787 {
"textfield", T_STR, 18, 5 },
800 auto child = std::make_unique<EGB_NODE>();
803 child->parent =
this;
804 children.push_back( std::move( child ) );
812 aChild->parent =
this;
813 children.push_back( std::move( aChild ) );
821 auto it =
props.find( aKey );
822 return it ==
props.end() ? wxString() : it->second;
829 Prop( aKey ).ToLong( &val );
837 wxLongLong_t val = 0;
838 Prop( aKey ).ToLongLong( &val );
840 return wxString::Format( wxS(
"%lld" ), val * 2 );
848 if( child->id == aId )
860 if( child->name == aName )
874 uint8_t buf[2] = { 0, 0 };
876 if( !aStream.IsOk() )
879 aStream.Read( buf, 2 );
881 if( aStream.LastRead() != 2 )
884 if( buf[0] == 0x10 && ( buf[1] == 0x00 || buf[1] == 0x80 ) )
893 if(
m_buf ==
nullptr || aOffs >
m_buf->size() || aLen >
m_buf->size() - aOffs )
894 THROW_IO_ERROR(
_(
"Short read in Eagle binary file (field out of bounds)." ) );
904 for(
unsigned n = 0; n < aLen; n++ )
907 l |= ( *m_buf )[aOffs + aLen - n - 1];
920 if( ( *
m_buf )[aOffs + aLen - 1] & 0x80 )
923 for(
unsigned n = 0; n < aLen; n++ )
926 l |= ( *m_buf )[aOffs + aLen - n - 1];
929 return static_cast<int32_t
>( l );
937 return ( ( *
m_buf )[aOffs] & aMask ) != 0;
943 unsigned first = ( aField >> 8 ) & 0xff;
944 unsigned last = aField & 0xff;
945 uint32_t mask = ( 1u << ( last - first + 1 ) ) - 1;
949 uint32_t val =
loadU32( aOffs, ( aField >> 16 ) & 0xff ) >> first;
959 const char* start =
reinterpret_cast<const char*
>(
m_buf->data() + aOffs );
965 while( n < aLen && start[n] !=
'\0' )
968 return wxString::FromUTF8( start, n );
974 static_assert(
sizeof( double ) == 8,
"Eagle binary doubles are 8-byte IEEE-754" );
983 for(
unsigned n = 0; n <
sizeof( double ); n++ )
984 bits |=
static_cast<uint64_t
>( ( *
m_buf )[aOffs + n] ) << ( 8 * n );
987 memcpy( &d, &bits,
sizeof( d ) );
1006 THROW_IO_ERROR(
_(
"Short read in Eagle binary file (truncated block)." ) );
1008 size_t blockStart =
m_pos;
1014 if( aNumBlocks < 0 && ( *
m_buf )[blockStart] == 0x10 )
1015 aNumBlocks =
loadS32( blockStart + 4, 4 );
1017 const SCRIPT_ROW* sc =
nullptr;
1019 for(
const SCRIPT_ROW* row = g_script; row->cmd != 0; row++ )
1021 unsigned cmdh = ( row->cmd >> 8 ) & 0xFF;
1022 unsigned cmdl = row->cmd & 0xFF;
1023 unsigned mskh = ( row->cmdMask >> 8 ) & 0xFF;
1024 unsigned mskl = row->cmdMask & 0xFF;
1026 if( ( cmdh != ( ( *
m_buf )[blockStart] & mskh ) ) || ( cmdl != ( ( *
m_buf )[blockStart + 1] & mskl ) ) )
1033 for(
const FMATCH* fm = row->fmatch; fm->offs != 0; fm++ )
1035 if(
loadS32( blockStart + fm->offs, fm->len ) != fm->val )
1051 THROW_IO_ERROR( wxString::Format(
_(
"Unknown Eagle binary block id 0x%02x%02x at offset %zu." ),
1052 (
unsigned) ( *
m_buf )[blockStart], (
unsigned) ( *
m_buf )[blockStart + 1],
1057 aParent->
AddChild(
static_cast<int>( sc->cmd ),
1058 sc->name ? wxString::FromUTF8( sc->name ) : wxString( wxS(
"UNKNOWN" ) ) );
1060 for(
const ATTR* at = sc->attrs; at->name !=
nullptr; at++ )
1068 case T_BMB: val =
loadBmb( blockStart + at->offs, at->len ) ? wxS(
"yes" ) : wxS(
"no" );
break;
1069 case T_UBF: val = wxString::Format( wxS(
"%u" ),
loadUbf( blockStart + at->offs, at->len ) );
break;
1070 case T_INT: val = wxString::Format( wxS(
"%d" ),
loadS32( blockStart + at->offs, at->len ) );
break;
1071 case T_DBL: val = wxString::FromCDouble(
loadDouble( blockStart + at->offs ) );
break;
1074 size_t foff = blockStart + at->offs;
1075 val =
loadStr( foff, at->len );
1080 if( foff + 5 <=
m_buf->size() && ( *
m_buf )[foff] == 0x7F )
1081 m_longRefs.push_back( { node, wxString::FromUTF8( at->name ),
loadU32( foff + 1, 4 ) } );
1087 node->
props[wxString::FromUTF8( at->name )] = val;
1092 for(
const SUBSECT* ss = sc->subs; ss->offs != 0; ss++ )
1094 uint32_t numch =
loadU32( blockStart + ss->offs, ss->len );
1097 if( ss->treeName !=
nullptr )
1098 lpar = node->
AddChild( 0, wxString::FromUTF8( ss->treeName ) );
1100 if( ss->ssType == SS_DIRECT )
1102 for( uint32_t n = 0; n < numch && aNumBlocks > 0; n++ )
1114 if( ss->ssType == SS_RECURSIVE_MINUS_1 && numch > 0 )
1119 for( uint32_t n = 0; n < numch && rem > 0; n++ )
1155 size_t total =
static_cast<size_t>( textLen ) + 4;
1163 size_t blobStart =
m_pos;
1169 while( cur <
end && ( *
m_buf )[cur] !=
'\0' )
1173 while( cur <
end && ( *
m_buf )[cur] !=
'\0' )
1176 wxString str = wxString::FromUTF8(
reinterpret_cast<const char*
>(
m_buf->data() + s ),
1192 wxLogTrace(
traceEagleIo, wxS(
"Eagle bin: free-text reference out of strings" ) );
1210 std::vector<bool> done(
m_longRefs.size(),
false );
1211 std::vector<wxString> value(
m_longRefs.size() );
1215 std::map<long long, int> votes;
1217 for(
size_t i = 0; i <
m_longRefs.size(); i++ )
1227 votes[
static_cast<long long>(
m_longRefs[i].ptr ) -
static_cast<long long>( offset )]++;
1231 long long base = -1;
1234 for(
const auto& [cand, count] : votes )
1248 for(
size_t i = 0; i <
m_longRefs.size(); i++ )
1254 static_cast<size_t>(
static_cast<long long>(
m_longRefs[i].ptr ) - base ) );
1258 value[i] = it->second;
1271 bool allResolved = std::all_of( done.begin(), done.end(), [](
bool d ) { return d; } );
1275 for(
size_t i = 0; i <
m_longRefs.size(); i++ )
1304 uint8_t c = ( *m_buf )[
m_pos++];
1321 const size_t kDrcLen = 244;
1328 auto mil = [&](
size_t aOffs ) ->
long
1330 return static_cast<long>(
loadS32( b + aOffs, 4 ) / 2.54 / 100 );
1346 auto it = aNode->
props.find( aField );
1348 if( it == aNode->
props.end() || it->second.IsEmpty() )
1355 if( it->second[0].GetValue() == 0x7F )
1362 auto fixThreeByte = [](
long num,
bool neg ) ->
long
1364 if( num < 0 && neg )
1366 else if( num > 0 && neg )
1367 return num - 0x800000;
1368 else if( num < 0 && !neg )
1369 return num + 0x800000;
1374 auto fixOneByte = [](
long num ) ->
long
1376 return num < 0 ? num + 0x80 : num;
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 );
1400 long c = fixOneByte( aElem->
PropLong( wxS(
"arc_c1" ) ) )
1401 + 256 * fixOneByte( aElem->
PropLong( wxS(
"arc_c2" ) ) )
1402 + 256L * 256 * fixOneByte( aElem->
PropLong( wxS(
"arc_c3" ) ) );
1403 c = fixThreeByte( c, arcFlags & 0x01 );
1405 setLong( wxS(
"x1" ), x1 );
1406 setLong( wxS(
"y1" ), y1 );
1407 setLong( wxS(
"x2" ), x2 );
1408 setLong( wxS(
"y2" ), y2 );
1410 long x3 = ( x1 + x2 ) / 2;
1411 long y3 = ( y1 + y2 ) / 2;
1412 long cx = 0, cy = 0;
1414 if( x1 == x2 && y1 == y2 )
1424 cy = interpolate( x3 - cx, x2 - x1, y2 - y1, y3 );
1429 cx = interpolate( y3 - cy, y2 - y1, x2 - x1, x3 );
1432 long radius =
static_cast<long>( std::hypot( cx - x2, cy - y2 ) );
1433 setLong( wxS(
"radius" ),
radius );
1434 setLong( wxS(
"x" ), cx );
1435 setLong( wxS(
"y" ), cy );
1437 if( cx == x2 && cy == y1 && x2 < x1 && y2 > y1 )
1439 aElem->
props[wxS(
"StartAngle" )] = wxS(
"90" );
1440 aElem->
props[wxS(
"Delta" )] = wxS(
"90" );
1442 else if( cx == x1 && cy == y2 && x2 < x1 && y1 > y2 )
1444 aElem->
props[wxS(
"StartAngle" )] = wxS(
"0" );
1445 aElem->
props[wxS(
"Delta" )] = wxS(
"90" );
1447 else if( cx == x2 && cy == y1 && x2 > x1 && y1 > y2 )
1449 aElem->
props[wxS(
"StartAngle" )] = wxS(
"270" );
1450 aElem->
props[wxS(
"Delta" )] = wxS(
"90" );
1452 else if( cx == x1 && cy == y2 && x2 > x1 && y2 > y1 )
1454 aElem->
props[wxS(
"StartAngle" )] = wxS(
"180" );
1455 aElem->
props[wxS(
"Delta" )] = wxS(
"90" );
1459 double theta1 = 180.0 - 180.0 /
M_PI * atan2( cy - y1, x1 - cx );
1460 double theta2 = 180.0 - 180.0 /
M_PI * atan2( cy - y2, x2 - cx );
1461 double deltaTheta = theta2 - theta1;
1463 while( theta1 > 360 )
1466 while( deltaTheta < -180 )
1469 while( deltaTheta > 180 )
1472 setLong( wxS(
"StartAngle" ),
static_cast<long>( theta1 ) );
1473 setLong( wxS(
"Delta" ),
static_cast<long>( deltaTheta ) );
1476 else if( ( aLineType > 0 && aLineType < 129 ) || aArcType > 0 )
1478 long x1 = 0, y1 = 0, x2 = 0, y2 = 0, cx = 0, cy = 0;
1480 if( aElem->
HasProp( wxS(
"arctype_other_x1" ) ) )
1482 x1 = aElem->
PropLong( wxS(
"arctype_other_x1" ) );
1483 y1 = aElem->
PropLong( wxS(
"arctype_other_y1" ) );
1484 x2 = aElem->
PropLong( wxS(
"arctype_other_x2" ) );
1485 y2 = aElem->
PropLong( wxS(
"arctype_other_y2" ) );
1489 x1 = aElem->
PropLong( wxS(
"linetype_0_x1" ) );
1490 y1 = aElem->
PropLong( wxS(
"linetype_0_y1" ) );
1491 x2 = aElem->
PropLong( wxS(
"linetype_0_x2" ) );
1492 y2 = aElem->
PropLong( wxS(
"linetype_0_y2" ) );
1496 auto setAngles = [&](
const char* aStart,
const char* aDelta )
1498 aElem->
props[wxS(
"StartAngle" )] = wxString::FromUTF8( aStart );
1499 aElem->
props[wxS(
"Delta" )] = wxString::FromUTF8( aDelta );
1502 if( aLineType == 0x78 || aArcType == 0x01 )
1504 cx = std::min( x1, x2 );
1505 cy = std::min( y1, y2 );
1506 setAngles(
"180",
"90" );
1508 else if( aLineType == 0x79 || aArcType == 0x02 )
1510 cx = std::max( x1, x2 );
1511 cy = std::min( y1, y2 );
1512 setAngles(
"270",
"90" );
1514 else if( aLineType == 0x7a || aArcType == 0x03 )
1516 cx = std::max( x1, x2 );
1517 cy = std::max( y1, y2 );
1518 setAngles(
"0",
"90" );
1520 else if( aLineType == 0x7b || aArcType == 0x04 )
1522 cx = std::min( x1, x2 );
1523 cy = std::max( y1, y2 );
1524 setAngles(
"90",
"90" );
1526 else if( aLineType == 0x7c || aArcType == 0x05 )
1528 cx = ( x1 + x2 ) / 2;
1529 cy = ( y1 + y2 ) / 2;
1530 setAngles(
"90",
"180" );
1532 else if( aLineType == 0x7d || aArcType == 0x06 )
1534 cx = ( x1 + x2 ) / 2;
1535 cy = ( y1 + y2 ) / 2;
1536 setAngles(
"270",
"180" );
1538 else if( aLineType == 0x7e || aArcType == 0x07 )
1540 cx = ( x1 + x2 ) / 2;
1541 cy = ( y1 + y2 ) / 2;
1542 setAngles(
"180",
"180" );
1544 else if( aLineType == 0x7f || aArcType == 0x08 )
1546 cx = ( x1 + x2 ) / 2;
1547 cy = ( y1 + y2 ) / 2;
1548 setAngles(
"0",
"180" );
1558 long radius =
static_cast<long>( std::hypot( cx - x2, cy - y2 ) );
1559 setLong( wxS(
"radius" ),
radius );
1560 setLong( wxS(
"x" ), cx );
1561 setLong( wxS(
"y" ), cy );
1570 int lineType = aRoot->
HasProp( wxS(
"linetype" ) ) ? (int) aRoot->
PropLong( wxS(
"linetype" ) ) : -1;
1576 aRoot->
props[wxS(
"x1" )] = aRoot->
Prop( wxS(
"linetype_0_x1" ) );
1577 aRoot->
props[wxS(
"y1" )] = aRoot->
Prop( wxS(
"linetype_0_y1" ) );
1578 aRoot->
props[wxS(
"x2" )] = aRoot->
Prop( wxS(
"linetype_0_x2" ) );
1579 aRoot->
props[wxS(
"y2" )] = aRoot->
Prop( wxS(
"linetype_0_y2" ) );
1591 if( aRoot->
HasProp( wxS(
"Delta" ) ) && aRoot->
PropLong( wxS(
"Delta" ) ) != 0 )
1592 aRoot->
props[wxS(
"curve" )] = aRoot->
Prop( wxS(
"Delta" ) );
1596 for(
const auto& child : aRoot->
children )
1605 int arcType = aRoot->
HasProp( wxS(
"arctype" ) ) ? (int) aRoot->
PropLong( wxS(
"arctype" ) ) : -1;
1609 aRoot->
props[wxS(
"x1" )] = aRoot->
Prop( wxS(
"arc_x1" ) );
1610 aRoot->
props[wxS(
"y1" )] = aRoot->
Prop( wxS(
"arc_y1" ) );
1611 aRoot->
props[wxS(
"x2" )] = aRoot->
Prop( wxS(
"arc_x2" ) );
1612 aRoot->
props[wxS(
"y2" )] = aRoot->
Prop( wxS(
"arc_y2" ) );
1614 else if( arcType > 0 )
1616 aRoot->
props[wxS(
"x1" )] = aRoot->
Prop( wxS(
"arctype_other_x1" ) );
1617 aRoot->
props[wxS(
"y1" )] = aRoot->
Prop( wxS(
"arctype_other_y1" ) );
1618 aRoot->
props[wxS(
"x2" )] = aRoot->
Prop( wxS(
"arctype_other_x2" ) );
1619 aRoot->
props[wxS(
"y2" )] = aRoot->
Prop( wxS(
"arctype_other_y2" ) );
1629 if( aRoot->
HasProp( wxS(
"Delta" ) ) && aRoot->
PropLong( wxS(
"Delta" ) ) != 0 )
1630 aRoot->
props[wxS(
"curve" )] = aRoot->
Prop( wxS(
"Delta" ) );
1633 for(
const auto& child : aRoot->
children )
1645 aRoot->
props[wxS(
"extent" )] = wxS(
"1-16" );
1648 for(
const auto& child : aRoot->
children )
1659 static const wxString dimAttrs[] = { wxS(
"x" ), wxS(
"y" ), wxS(
"x1" ), wxS(
"y1" ),
1660 wxS(
"x2" ), wxS(
"y2" ), wxS(
"x3" ), wxS(
"y3" ),
1661 wxS(
"width" ), wxS(
"drill" ), wxS(
"diameter" ), wxS(
"radius" ),
1662 wxS(
"size" ), wxS(
"dx" ), wxS(
"dy" ), wxS(
"spacing" ),
1665 for(
const wxString& key : dimAttrs )
1667 auto it = aRoot->
props.find( key );
1669 if( it == aRoot->
props.end() )
1674 if( it->second.ToCDouble( &du ) )
1675 it->second = wxString::FromCDouble( du * 0.0001, 4 );
1678 for(
const auto& child : aRoot->
children )
1690 for(
const auto& child : aRoot->
children )
1699 if( aRoot->
HasProp( wxS(
"half_dx" ) ) )
1704 if( aRoot->
HasProp( wxS(
"half_dy" ) ) )
1710 for(
const auto& child : aRoot->
children )
1720 if( aRoot->
HasProp( wxS(
"half_drill" ) ) )
1725 if( aRoot->
HasProp( wxS(
"half_diameter" ) ) )
1727 aRoot->
props[wxS(
"diameter" )] = aRoot->
PropDoubled( wxS(
"half_diameter" ) );
1730 if( aRoot->
HasProp( wxS(
"half_size" ) ) )
1736 for(
const auto& child : aRoot->
children )
1759 default:
return false;
1771 auto flagSet = [&](
const wxString& aKey )
1776 const wxString v = aRoot->
Prop( aKey );
1777 return v != wxS(
"no" ) && v != wxS(
"0" );
1780 bool mirrored = flagSet( wxS(
"mirrored" ) );
1781 bool spin = flagSet( wxS(
"spin" ) );
1783 long deg = aRoot->
PropLong( wxS(
"bin_rot" ) );
1792 degrees = ( deg & 0x3 ) * 90.0;
1794 degrees = 360.0 * ( deg & 0x0FFF ) / 4096.0;
1804 rot << wxS(
"R" ) << wxString::FromCDouble( degrees, 4 );
1806 aRoot->
props[wxS(
"rot" )] = rot;
1809 for(
const auto& child : aRoot->
children )
1879 for(
const auto& child : aRoot->
children )
1896 default:
return false;
1909 std::vector<std::unique_ptr<EGB_NODE>> kept;
1912 for(
auto& child : aRoot->
children )
1916 if( eligible !=
nullptr )
1917 eligible->
props[wxS(
"textfield" )] = child->Prop( wxS(
"textfield" ) );
1923 kept.push_back( std::move( child ) );
1924 eligible = ( kept.back()->HasProp( wxS(
"textfield" ) ) &&
isLongTextHost( kept.back()->id ) )
1929 aRoot->
children = std::move( kept );
1931 for(
const auto& child : aRoot->
children )
1941 aRoot->
content = aRoot->
Prop( wxS(
"textfield" ) );
1943 for(
const auto& child : aRoot->
children )
1952 std::vector<std::unique_ptr<EGB_NODE>> kept;
1954 for(
auto& child : aDrawing->
children )
1960 if( child->HasProp( wxS(
"visible" ) ) )
1962 child->props[wxS(
"visible" )] = child->PropLong( wxS(
"visible" ) ) != 0 ? wxS(
"yes" ) : wxS(
"no" );
1965 child->parent = aLayers;
1966 aLayers->
children.push_back( std::move( child ) );
1970 kept.push_back( std::move( child ) );
1974 aDrawing->
children = std::move( kept );
1980 auto addParam = [&](
const wxString& aName,
const wxString& aValue )
1983 p->
props[wxS(
"name" )] = aName;
1984 p->
props[wxS(
"value" )] = aValue;
1987 addParam( wxS(
"mdWireWire" ), wxString::Format( wxS(
"%ldmil" ), aDrc.
mdWireWire ) );
1988 addParam( wxS(
"msWidth" ), wxString::Format( wxS(
"%ldmil" ), aDrc.
msWidth ) );
1989 addParam( wxS(
"rvPadTop" ), wxString::FromCDouble( aDrc.
rvPadTop ) );
1990 addParam( wxS(
"rvPadInner" ), wxString::FromCDouble( aDrc.
rvPadInner ) );
1991 addParam( wxS(
"rvPadBottom" ), wxString::FromCDouble( aDrc.
rvPadBottom ) );
2000 if( aLibraries ==
nullptr )
2006 std::vector<std::unique_ptr<EGB_NODE>> wrapped;
2008 for(
auto& child : aLibraries->
children )
2013 auto lib = std::make_unique<EGB_NODE>();
2015 lib->name = wxS(
"library" );
2016 lib->parent = aLibraries;
2017 child->
parent = lib.get();
2018 lib->
children.push_back( std::move( child ) );
2019 wrapped.push_back( std::move( lib ) );
2022 if( !wrapped.empty() )
2023 aLibraries->
children = std::move( wrapped );
2029 if( aElements ==
nullptr )
2034 for(
auto& el : aElements->
children )
2039 for(
auto& el2 : el->children )
2044 for(
const auto& [key, value] : el2->props )
2046 if( key == wxS(
"name" ) )
2048 if( value == wxS(
"-" ) )
2049 el->props[wxS(
"name" )] = wxS(
"HYPHEN" );
2051 el->props[wxS(
"name" )] = value;
2053 else if( key == wxS(
"value" ) )
2055 el->props[wxS(
"value" )] = value;
2065 if( aLibraries ==
nullptr )
2073 std::map<wxString, int> seenLibs;
2075 for(
size_t li = 0; li < aLibraries->
children.size(); li++ )
2086 wxString libName = pkgs ? pkgs->
Prop( wxS(
"library" ) ) : wxString();
2088 if( libName.IsEmpty() )
2089 libName = wxString::Format( wxS(
"lib%zu" ), li + 1 );
2095 if(
int& libCount = seenLibs[libName]; libCount++ > 0 )
2096 libName = wxString::Format( wxS(
"%s_%d" ), libName, libCount );
2098 lib->
props[wxS(
"name" )] = libName;
2100 if( pkgs ==
nullptr )
2103 std::map<wxString, int> seen;
2105 for(
size_t pi = 0; pi < pkgs->
children.size(); pi++ )
2108 wxString
name = pkg->
Prop( wxS(
"name" ) );
2110 if(
name.IsEmpty() )
2111 name = wxString::Format( wxS(
"pkg%zu" ), pi + 1 );
2115 if(
int& count = seen[
name]; count++ > 0 )
2116 name = wxString::Format( wxS(
"%s_%d" ),
name, count );
2122 if( aElements ==
nullptr )
2125 auto nameByIdx = [&](
EGB_NODE* aParent,
long aIdx ) -> wxString
2127 if( aParent ==
nullptr || aIdx < 1 || aIdx > (
long) aParent->
children.size() )
2130 return aParent->
children[aIdx - 1]->Prop( wxS(
"name" ) );
2133 for(
auto& el : aElements->
children )
2138 long libIdx = el->PropLong( wxS(
"library" ) );
2139 EGB_NODE* lib = ( libIdx >= 1 && libIdx <= (long) aLibraries->
children.size() )
2140 ? aLibraries->
children[libIdx - 1].get()
2143 if( lib ==
nullptr )
2146 el->props[wxS(
"library" )] = lib->
Prop( wxS(
"name" ) );
2149 wxString pkgName = nameByIdx( pkgs, el->
PropLong( wxS(
"package" ) ) );
2151 if( !pkgName.IsEmpty() )
2152 el->props[wxS(
"package" )] = pkgName;
2159 if( aSignals ==
nullptr )
2167 for(
size_t i = 0; i < aSignals->
children.size(); i++ )
2174 std::vector<std::unique_ptr<EGB_NODE>> kept;
2175 std::vector<std::unique_ptr<EGB_NODE>> promoted;
2181 inner->parent = aSignals;
2182 promoted.push_back( std::move( inner ) );
2186 kept.push_back( std::move( inner ) );
2194 for(
auto& p : promoted )
2195 aSignals->
children.push_back( std::move( p ) );
2202 if( aSignals ==
nullptr || aElements ==
nullptr || aLibraries ==
nullptr )
2205 auto elemByIdx = [&](
long aIdx ) ->
EGB_NODE*
2207 if( aIdx < 1 || aIdx > (
long) aElements->
children.size() )
2210 return aElements->
children[aIdx - 1].get();
2213 auto libByIdx = [&](
long aIdx ) ->
EGB_NODE*
2215 if( aIdx < 1 || aIdx > (
long) aLibraries->
children.size() )
2218 return aLibraries->
children[aIdx - 1].get();
2223 if( aLib ==
nullptr )
2228 if( pkgs ==
nullptr || aIdx < 1 || aIdx > (
long) pkgs->
children.size() )
2231 return pkgs->
children[aIdx - 1].get();
2234 for(
auto& sig : aSignals->
children )
2238 for(
auto& cr : sig->children )
2243 long partNum = cr->PropLong( wxS(
"partnumber" ) );
2244 EGB_NODE* elem = elemByIdx( partNum );
2246 if( elem ==
nullptr )
2249 cr->props[wxS(
"element" )] = elem->
Prop( wxS(
"name" ) );
2255 if( pkg ==
nullptr )
2257 cr->props[wxS(
"pad" )] = wxS(
"PIN_NOT_FOUND" );
2261 long pinNum = cr->PropLong( wxS(
"pin" ) );
2264 for(
const auto& child : pkg->
children )
2266 int kind = child->id & 0xFF00;
2272 found = child.get();
2278 if( found ==
nullptr )
2279 cr->
props[wxS(
"pad" )] = wxS(
"PIN_NOT_FOUND" );
2280 else if( found->
HasProp( wxS(
"name" ) ) )
2281 cr->props[wxS(
"pad" )] = found->
Prop( wxS(
"name" ) );
2283 cr->props[wxS(
"pad" )] = cr->Prop( wxS(
"pin" ) );
2293 if( drawing ==
nullptr )
2306 if( board !=
nullptr )
2311 if( libraries ==
nullptr )
2312 THROW_IO_ERROR(
_(
"Eagle binary layout is missing a board/libraries node." ) );
2324 if( drcNode !=
nullptr )
2373 std::vector<std::unique_ptr<EGB_NODE>> kept;
2375 for(
auto& child : aRoot->
children )
2380 kept.push_back( std::move( child ) );
2383 aRoot->
children = std::move( kept );
2385 for(
const auto& child : aRoot->
children )
2392 wxXmlNode* xml =
new wxXmlNode( wxXML_ELEMENT_NODE, aNode->
name );
2394 for(
const auto& [key, value] : aNode->
props )
2395 xml->AddAttribute( key, value );
2397 if( !aNode->
content.IsEmpty() )
2398 xml->AddChild(
new wxXmlNode( wxXML_TEXT_NODE, wxEmptyString, aNode->
content ) );
2402 for(
const auto& child : aNode->
children )
2403 xml->AddChild(
toXml( child.get() ) );
2415 if( aBytes.size() < 24 )
2416 THROW_IO_ERROR(
_(
"File is too small to be an Eagle binary board." ) );
2418 m_root = std::make_unique<EGB_NODE>();
2420 m_root->name = wxS(
"eagle" );
2422 long numBlocks = -1;
2433 if( drawing !=
nullptr )
2435 long v1 = drawing->
HasProp( wxS(
"v1" ) ) ? drawing->
PropLong( wxS(
"v1" ) ) : 5;
2436 long v2 = drawing->
HasProp( wxS(
"v2" ) ) ? drawing->
PropLong( wxS(
"v2" ) ) : 0;
2437 m_root->props[wxS(
"version" )] = wxString::Format( wxS(
"%ld.%ld" ),
v1,
v2 );
2463 auto doc = std::make_unique<wxXmlDocument>();
2475 if( drawing ==
nullptr )
2476 THROW_IO_ERROR(
_(
"Eagle binary schematic has no drawing section." ) );
2480 if( schematic ==
nullptr )
2484 schematic->name = wxS(
"schematic" );
2505std::vector<EAGLE_BIN_PARSER::EGB_NODE*>
2508 std::vector<EGB_NODE*> out;
2510 if( aParent !=
nullptr )
2512 for(
const auto& child : aParent->
children )
2514 if( child->id == aChildId )
2515 out.push_back( child.get() );
2526 if( aIdx >= 1 && aIdx <= (
long) aList.size() )
2527 return aList[aIdx - 1]->Prop( wxS(
"name" ) );
2543 aNode->
props[wxS(
"columns" )] = aNode->
Prop( wxS(
"cols" ) );
2559 aNode->
props[wxS(
"name" )] = aNode->
HasProp( wxS(
"textfield" ) )
2560 ? aNode->
Prop( wxS(
"textfield" ) )
2577 if( aNode->
HasProp( wxS(
"half_size" ) ) )
2578 sizeKey = wxS(
"half_size" );
2579 else if( aNode->
HasProp( wxS(
"size" ) ) )
2580 sizeKey = wxS(
"size" );
2582 if( !sizeKey.IsEmpty() && aNode->
PropLong( sizeKey ) >= 0 )
2608 if( aNode->
name == wxS(
"variants" ) )
2609 aNode->
name = wxS(
"devices" );
2617std::vector<EAGLE_BIN_PARSER::EGB_NODE*>
2620 auto wrapChildren = [](
EGB_NODE* aParent,
const wxString& aContainer,
2623 std::vector<std::unique_ptr<EGB_NODE>> kept;
2624 std::vector<std::unique_ptr<EGB_NODE>>
moved;
2626 for(
auto& child : aParent->
children )
2628 if( aPred( child.get() ) )
2629 moved.push_back( std::move( child ) );
2631 kept.push_back( std::move( child ) );
2634 aParent->
children = std::move( kept );
2641 for(
auto& node :
moved )
2651 wrapChildren( aSchematic, wxS(
"libraries" ),
2659 for(
size_t li = 0; li < libList.size(); li++ )
2672 libName = n->
Prop( wxS(
"library" ) );
2677 if( libName.IsEmpty() )
2678 libName = wxString::Format( wxS(
"lib%zu" ), li + 1 );
2680 lib->
props[wxS(
"name" )] = libName;
2686 [](
const std::unique_ptr<EGB_NODE>& n )
2687 { return n->id == EGKW_SECT_PACKAGES; } ),
2695 std::map<wxString, int> dsSeen;
2697 for(
size_t di = 0; di < devicesetList.size(); di++ )
2700 wxString
name = ds->
Prop( wxS(
"name" ) );
2702 if(
name.IsEmpty() )
2703 name = wxString::Format( wxS(
"dset%zu" ), di + 1 );
2705 if(
int& count = dsSeen[
name]; count++ > 0 )
2706 name = wxString::Format( wxS(
"%s_%d" ),
name, count );
2713 gate->
props[wxS(
"symbol" )] =
nameByOrdinal( symbols, gate->PropLong( wxS(
"symno" ) ) );
2722 const std::vector<EGB_NODE*>& aLibList )
2724 auto adopt = [](
EGB_NODE* aParent,
EGB_NODE*& aSlot,
const wxString& aName,
2725 std::unique_ptr<EGB_NODE> aNode )
2727 if( aSlot ==
nullptr )
2728 aSlot = aParent->
AddChild( 0, aName );
2738 std::vector<std::unique_ptr<EGB_NODE>> flat = std::move( aSchematic->
children );
2741 std::vector<std::unique_ptr<EGB_NODE>> sheetNodes;
2742 std::vector<std::unique_ptr<EGB_NODE>> globalParts;
2743 std::map<wxString, bool> seenPart;
2752 for(
auto& node : flat )
2755 if( node->name == wxS(
"libraries" ) )
2757 aSchematic->
children.push_back( std::move( node ) );
2766 curSheet = node.get();
2767 curPlain = curInstances = curNets = curBusses =
nullptr;
2769 std::vector<std::unique_ptr<EGB_NODE>> drawables = std::move( curSheet->
children );
2772 for(
auto& drawable : drawables )
2773 adopt( curSheet, curPlain, wxS(
"plain" ), std::move( drawable ) );
2775 sheetNodes.push_back( std::move( node ) );
2782 long libno = part->
PropLong( wxS(
"lib" ) );
2783 long devno = part->
PropLong( wxS(
"device" ) );
2784 long varno = part->
PropLong( wxS(
"variant" ) );
2786 EGB_NODE* lib = ( libno >= 1 && libno <= (long) aLibList.size() ) ? aLibList[libno - 1]
2788 std::vector<EGB_NODE*> devicesets =
2791 EGB_NODE* ds = ( devno >= 1 && devno <= (long) devicesets.size() ) ? devicesets[devno - 1]
2793 std::vector<EGB_NODE*> variants =
2796 std::vector<EGB_NODE*> gates =
2800 wxString partName = part->
Prop( wxS(
"name" ) );
2802 part->
props[wxS(
"library" )] = lib ? lib->
Prop( wxS(
"name" ) ) : wxString();
2803 part->
props[wxS(
"deviceset" )] = ds ? ds->
Prop( wxS(
"name" ) ) : wxString();
2809 part->
props.erase( wxS(
"technology" ) );
2812 std::vector<std::unique_ptr<EGB_NODE>> partKept;
2818 partKept.push_back( std::move( sub ) );
2822 sub->props[wxS(
"part" )] = partName;
2823 sub->props[wxS(
"gate" )] =
nameByOrdinal( gates, sub->PropLong( wxS(
"gateno" ) ) );
2824 adopt( curSheet, curInstances, wxS(
"instances" ), std::move( sub ) );
2827 part->
children = std::move( partKept );
2830 if( !seenPart[partName] )
2832 seenPart[partName] =
true;
2833 node->parent = aSchematic;
2834 globalParts.push_back( std::move( node ) );
2842 node->props[wxS(
"class" )] =
2843 node->HasProp( wxS(
"netclass" ) ) ? node->Prop( wxS(
"netclass" ) ) : wxString( wxS(
"0" ) );
2846 seg->name = wxS(
"segment" );
2848 if( curSheet !=
nullptr )
2849 adopt( curSheet, curNets, wxS(
"nets" ), std::move( node ) );
2856 if( curSheet !=
nullptr )
2857 adopt( curSheet, curBusses, wxS(
"busses" ), std::move( node ) );
2865 if( curSheet !=
nullptr )
2866 adopt( curSheet, curPlain, wxS(
"plain" ), std::move( node ) );
2877 for(
auto& sheet : sheetNodes )
2878 sheetsNode->
AdoptChild( std::move( sheet ) );
2882 for(
auto& part : globalParts )
wxXmlNode * toXml(const EGB_NODE *aNode) const
void postprocSignals(EGB_NODE *aSignals)
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 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 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 postprocRotation(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
static bool IsBinaryEagle(wxInputStream &aStream)
Probe the first two bytes for the binary magic.
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)
std::map< size_t, wxString > m_freeTextByOffset
Free-text strings keyed by their byte offset within the blob, for pointer (0x7F-reference) resolution...
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
const wxChar *const traceEagleIo
#define THROW_IO_ERROR(msg)
macro which captures the "call site" values of FILE_, __FUNCTION & LINE
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.
wxLogTrace helper definitions.