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 },
484 { {
"shape", T_INT, 2, 1 },
485 {
"x", T_INT, 4, 4 },
486 {
"y", T_INT, 8, 4 },
487 {
"half_drill", T_UBF, 12, BITFIELD( 2, 0, 15 ) },
488 {
"half_diameter", T_UBF, 14, BITFIELD( 2, 0, 15 ) },
489 {
"name", T_STR, 16, 8 },
496 { {
"roundness", T_INT, 2, 1 },
497 {
"layer", T_UBF, 3, BITFIELD( 1, 0, 7 ) },
498 {
"x", T_INT, 4, 4 },
499 {
"y", T_INT, 8, 4 },
500 {
"half_dx", T_UBF, 12, BITFIELD( 2, 0, 15 ) },
501 {
"half_dy", T_UBF, 14, BITFIELD( 2, 0, 15 ) },
502 {
"name", T_STR, 16, 8 },
509 { {
"shape", T_INT, 2, 1 },
510 {
"x", T_INT, 4, 4 },
511 {
"y", T_INT, 8, 4 },
512 {
"half_drill", T_UBF, 12, BITFIELD( 2, 0, 15 ) },
513 {
"half_diameter", T_UBF, 14, BITFIELD( 2, 0, 15 ) },
514 {
"bin_rot", T_INT, 16, 2 },
515 {
"stop", T_BMB, 18, 0x01 },
516 {
"thermals", T_BMB, 18, 0x04 },
517 {
"first", T_BMB, 18, 0x08 },
518 {
"name", T_STR, 19, 5 },
525 { {
"roundness", T_INT, 2, 1 },
526 {
"layer", T_UBF, 3, BITFIELD( 1, 0, 7 ) },
527 {
"x", T_INT, 4, 4 },
528 {
"y", T_INT, 8, 4 },
529 {
"half_dx", T_UBF, 12, BITFIELD( 2, 0, 15 ) },
530 {
"half_dy", T_UBF, 14, BITFIELD( 2, 0, 15 ) },
531 {
"bin_rot", T_UBF, 16, BITFIELD( 2, 0, 11 ) },
532 {
"stop", T_BMB, 18, 0x01 },
533 {
"cream", T_BMB, 18, 0x02 },
534 {
"thermals", T_BMB, 18, 0x04 },
535 {
"first", T_BMB, 18, 0x08 },
536 {
"name", T_STR, 19, 5 },
543 { {
"function", T_UBF, 2, BITFIELD( 1, 0, 1 ) },
544 {
"visible", T_UBF, 2, BITFIELD( 1, 6, 7 ) },
545 {
"x", T_INT, 4, 4 },
546 {
"y", T_INT, 8, 4 },
547 {
"direction", T_UBF, 12, BITFIELD( 1, 0, 3 ) },
548 {
"length", T_UBF, 12, BITFIELD( 1, 4, 5 ) },
549 {
"bin_rot", T_UBF, 12, BITFIELD( 1, 6, 7 ) },
550 {
"swaplevel", T_INT, 13, 1 },
551 {
"name", T_STR, 14, 10 },
558 { {
"x", T_INT, 4, 4 },
559 {
"y", T_INT, 8, 4 },
560 {
"addlevel", T_INT, 12, 1 },
561 {
"swap", T_INT, 13, 1 },
562 {
"symno", T_INT, 14, 2 },
563 {
"name", T_STR, 16, 8 },
573 { { 2, 2, SS_DIRECT,
nullptr },
TERM_S },
574 { {
"x", T_INT, 4, 4 },
575 {
"y", T_INT, 8, 4 },
576 {
"library", T_INT, 12, 2 },
577 {
"package", T_INT, 14, 2 },
578 {
"bin_rot", T_UBF, 16, BITFIELD( 2, 0, 11 ) },
579 {
"mirrored", T_BMB, 17, 0x10 },
580 {
"spin", T_BMB, 17, 0x40 },
587 { {
"name", T_STR, 2, 8 }, {
"value", T_STR, 10, 14 },
TERM_A } },
592 { { 2, 2, SS_DIRECT,
nullptr },
TERM_S },
593 { {
"x", T_INT, 4, 4 },
594 {
"y", T_INT, 8, 4 },
595 {
"placed", T_INT, 12, 2 },
596 {
"gateno", T_INT, 14, 2 },
597 {
"bin_rot", T_UBF, 16, BITFIELD( 2, 10, 11 ) },
598 {
"mirrored", T_UBF, 16, BITFIELD( 2, 12, 12 ) },
599 {
"smashed", T_BMB, 18, 0x01 },
606 { {
"layer", T_UBF, 3, BITFIELD( 1, 0, 7 ) },
607 {
"x", T_INT, 4, 4 },
608 {
"y", T_INT, 8, 4 },
609 {
"half_size", T_INT, 12, 2 },
610 {
"ratio", T_UBF, 14, BITFIELD( 2, 2, 6 ) },
611 {
"bin_rot", T_UBF, 16, BITFIELD( 2, 0, 11 ) },
612 {
"mirrored", T_UBF, 16, BITFIELD( 2, 12, 12 ) },
613 {
"spin", T_UBF, 16, BITFIELD( 2, 14, 14 ) },
614 {
"textfield", T_STR, 18, 6 },
618 {
EGKW_SECT_LONGTEXT, 0xFFFF,
"longtext", {
TERM_F }, {
TERM_S }, { {
"textfield", T_STR, 2, 22 },
TERM_A } },
624 { {
"layer", T_UBF, 3, BITFIELD( 1, 0, 7 ) },
625 {
"x", T_INT, 4, 4 },
626 {
"y", T_INT, 8, 4 },
627 {
"size", T_INT, 12, 2 },
628 {
"ratio", T_UBF, 14, BITFIELD( 2, 2, 6 ) },
629 {
"bin_rot", T_UBF, 16, BITFIELD( 2, 0, 11 ) },
630 {
"mirrored", T_UBF, 16, BITFIELD( 2, 12, 12 ) },
631 {
"spin", T_UBF, 16, BITFIELD( 2, 14, 14 ) },
632 {
"textfield", T_STR, 18, 6 },
639 { {
"layer", T_UBF, 3, BITFIELD( 1, 0, 7 ) },
640 {
"x", T_INT, 4, 4 },
641 {
"y", T_INT, 8, 4 },
642 {
"size", T_INT, 12, 2 },
643 {
"ratio", T_UBF, 14, BITFIELD( 2, 2, 6 ) },
644 {
"bin_rot", T_UBF, 16, BITFIELD( 2, 0, 11 ) },
645 {
"mirrored", T_UBF, 16, BITFIELD( 2, 12, 12 ) },
646 {
"spin", T_UBF, 16, BITFIELD( 2, 14, 14 ) },
647 {
"textfield", T_STR, 18, 6 },
654 { {
"layer", T_UBF, 3, BITFIELD( 1, 0, 7 ) },
655 {
"x", T_INT, 4, 4 },
656 {
"y", T_INT, 8, 4 },
657 {
"size", T_INT, 12, 2 },
658 {
"ratio", T_UBF, 14, BITFIELD( 2, 2, 6 ) },
659 {
"bin_rot", T_UBF, 16, BITFIELD( 2, 0, 11 ) },
660 {
"mirrored", T_UBF, 16, BITFIELD( 2, 12, 12 ) },
661 {
"spin", T_UBF, 16, BITFIELD( 2, 14, 14 ) },
662 {
"textfield", T_STR, 18, 6 },
668 { { 2, 2, SS_DIRECT,
nullptr },
TERM_S },
669 { {
"package", T_INT, 4, 2 }, {
"table", T_STR, 6, 13 }, {
"name", T_STR, 19, 5 },
TERM_A } },
676 { { 4, 2, SS_RECURSIVE,
"variants" }, { 2, 2, SS_RECURSIVE,
"gates" },
TERM_S },
677 { {
"gates", T_INT, 2, 2 },
678 {
"variants", T_INT, 4, 2 },
679 {
"prefix", T_STR, 8, 5 },
680 {
"desc", T_STR, 13, 5 },
681 {
"name", T_STR, 18, 5 },
687 { { 2, 2, SS_RECURSIVE,
nullptr },
TERM_S },
688 { {
"lib", T_INT, 4, 2 },
689 {
"device", T_INT, 6, 2 },
690 {
"variant", T_INT, 8, 1 },
691 {
"technology", T_INT, 9, 2 },
692 {
"name", T_STR, 11, 5 },
693 {
"value", T_STR, 16, 8 },
703 { {
"partnumber", T_INT, 4, 2 }, {
"pin", T_INT, 6, 2 },
TERM_A } },
709 { {
"layer", T_UBF, 3, BITFIELD( 1, 0, 7 ) },
710 {
"x", T_INT, 4, 4 },
711 {
"y", T_INT, 8, 4 },
712 {
"size", T_INT, 12, 2 },
713 {
"ratio", T_UBF, 14, BITFIELD( 2, 2, 6 ) },
714 {
"bin_rot", T_UBF, 16, BITFIELD( 2, 0, 11 ) },
715 {
"mirrored", T_UBF, 16, BITFIELD( 2, 12, 12 ) },
716 {
"spin", T_UBF, 16, BITFIELD( 2, 14, 14 ) },
717 {
"textfield", T_STR, 18, 6 },
724 { {
"layer", T_UBF, 3, BITFIELD( 1, 0, 7 ) },
725 {
"x", T_INT, 4, 4 },
726 {
"y", T_INT, 8, 4 },
727 {
"size", T_INT, 12, 2 },
728 {
"ratio", T_UBF, 14, BITFIELD( 2, 2, 6 ) },
729 {
"bin_rot", T_UBF, 16, BITFIELD( 2, 0, 11 ) },
730 {
"mirrored", T_UBF, 16, BITFIELD( 2, 12, 12 ) },
731 {
"spin", T_UBF, 16, BITFIELD( 2, 14, 14 ) },
732 {
"textfield", T_STR, 18, 6 },
741 { {
"layer", T_UBF, 3, BITFIELD( 1, 0, 7 ) },
742 {
"x", T_INT, 4, 4 },
743 {
"y", T_INT, 8, 4 },
744 {
"size", T_INT, 12, 2 },
745 {
"ratio", T_UBF, 14, BITFIELD( 2, 2, 6 ) },
746 {
"bin_rot", T_UBF, 16, BITFIELD( 2, 0, 11 ) },
747 {
"mirrored", T_UBF, 16, BITFIELD( 2, 12, 12 ) },
748 {
"spin", T_UBF, 16, BITFIELD( 2, 14, 14 ) },
749 {
"textfield", T_STR, 18, 6 },
756 { {
"symbol", T_STR, 2, 5 }, {
"attribute", T_STR, 7, 17 },
TERM_A } },
762 { {
"layer", T_UBF, 3, BITFIELD( 1, 0, 7 ) },
763 {
"x1", T_INT, 4, 4 },
764 {
"y1", T_INT, 8, 4 },
765 {
"x2", T_INT, 12, 4 },
766 {
"y2", T_INT, 16, 4 },
767 {
"cols", T_INT, 20, 1 },
768 {
"rows", T_INT, 21, 1 },
769 {
"borders", T_INT, 22, 1 },
776 { {
"layer", T_UBF, 3, BITFIELD( 1, 0, 7 ) },
777 {
"x", T_INT, 4, 4 },
778 {
"y", T_INT, 8, 4 },
779 {
"size", T_INT, 12, 2 },
780 {
"ratio", T_UBF, 14, BITFIELD( 2, 2, 6 ) },
781 {
"bin_rot", T_UBF, 16, BITFIELD( 2, 0, 11 ) },
782 {
"mirrored", T_UBF, 16, BITFIELD( 2, 12, 12 ) },
783 {
"spin", T_UBF, 16, BITFIELD( 2, 14, 14 ) },
784 {
"textfield", T_STR, 18, 6 },
797bool isV3InlineNamePadRow(
const SCRIPT_ROW* aRow )
802 for(
const ATTR* at = aRow->attrs; at->name !=
nullptr; at++ )
804 if( strcmp( at->name,
"name" ) == 0 )
805 return at->offs == 16;
815 auto child = std::make_unique<EGB_NODE>();
818 child->parent =
this;
819 children.push_back( std::move( child ) );
827 aChild->parent =
this;
828 children.push_back( std::move( aChild ) );
836 auto it =
props.find( aKey );
837 return it ==
props.end() ? wxString() : it->second;
844 Prop( aKey ).ToLong( &val );
852 wxLongLong_t val = 0;
853 Prop( aKey ).ToLongLong( &val );
855 return wxString::Format( wxS(
"%lld" ), val * 2 );
863 if( child->id == aId )
875 if( child->name == aName )
889 uint8_t buf[2] = { 0, 0 };
891 if( !aStream.IsOk() )
894 aStream.Read( buf, 2 );
896 if( aStream.LastRead() != 2 )
899 if( buf[0] == 0x10 && ( buf[1] == 0x00 || buf[1] == 0x80 ) )
908 if(
m_buf ==
nullptr || aOffs >
m_buf->size() || aLen >
m_buf->size() - aOffs )
909 THROW_IO_ERROR(
_(
"Short read in Eagle binary file (field out of bounds)." ) );
919 for(
unsigned n = 0; n < aLen; n++ )
922 l |= ( *m_buf )[aOffs + aLen - n - 1];
935 if( ( *
m_buf )[aOffs + aLen - 1] & 0x80 )
938 for(
unsigned n = 0; n < aLen; n++ )
941 l |= ( *m_buf )[aOffs + aLen - n - 1];
944 return static_cast<int32_t
>( l );
952 return ( ( *
m_buf )[aOffs] & aMask ) != 0;
958 unsigned first = ( aField >> 8 ) & 0xff;
959 unsigned last = aField & 0xff;
960 uint32_t mask = ( 1u << ( last - first + 1 ) ) - 1;
964 uint32_t val =
loadU32( aOffs, ( aField >> 16 ) & 0xff ) >> first;
974 const char* start =
reinterpret_cast<const char*
>(
m_buf->data() + aOffs );
980 while( n < aLen && start[n] !=
'\0' )
983 return wxString::FromUTF8( start, n );
989 static_assert(
sizeof( double ) == 8,
"Eagle binary doubles are 8-byte IEEE-754" );
998 for(
unsigned n = 0; n <
sizeof( double ); n++ )
999 bits |=
static_cast<uint64_t
>( ( *
m_buf )[aOffs + n] ) << ( 8 * n );
1002 memcpy( &d, &bits,
sizeof( d ) );
1021 THROW_IO_ERROR(
_(
"Short read in Eagle binary file (truncated block)." ) );
1023 size_t blockStart =
m_pos;
1029 if( aNumBlocks < 0 && ( *
m_buf )[blockStart] == 0x10 )
1030 aNumBlocks =
loadS32( blockStart + 4, 4 );
1032 const SCRIPT_ROW* sc =
nullptr;
1034 for(
const SCRIPT_ROW* row = g_script; row->cmd != 0; row++ )
1036 unsigned cmdh = ( row->cmd >> 8 ) & 0xFF;
1037 unsigned cmdl = row->cmd & 0xFF;
1038 unsigned mskh = ( row->cmdMask >> 8 ) & 0xFF;
1039 unsigned mskl = row->cmdMask & 0xFF;
1041 if( ( cmdh != ( ( *
m_buf )[blockStart] & mskh ) ) || ( cmdl != ( ( *
m_buf )[blockStart + 1] & mskl ) ) )
1048 for(
const FMATCH* fm = row->fmatch; fm->offs != 0; fm++ )
1050 if(
loadS32( blockStart + fm->offs, fm->len ) != fm->val )
1063 if(
m_majorVer > 3 && isV3InlineNamePadRow( row ) )
1073 THROW_IO_ERROR( wxString::Format(
_(
"Unknown Eagle binary block id 0x%02x%02x at offset %zu." ),
1074 (
unsigned) ( *
m_buf )[blockStart], (
unsigned) ( *
m_buf )[blockStart + 1],
1079 aParent->
AddChild(
static_cast<int>( sc->cmd ),
1080 sc->name ? wxString::FromUTF8( sc->name ) : wxString( wxS(
"UNKNOWN" ) ) );
1082 for(
const ATTR* at = sc->attrs; at->name !=
nullptr; at++ )
1090 case T_BMB: val =
loadBmb( blockStart + at->offs, at->len ) ? wxS(
"yes" ) : wxS(
"no" );
break;
1091 case T_UBF: val = wxString::Format( wxS(
"%u" ),
loadUbf( blockStart + at->offs, at->len ) );
break;
1092 case T_INT: val = wxString::Format( wxS(
"%d" ),
loadS32( blockStart + at->offs, at->len ) );
break;
1093 case T_DBL: val = wxString::FromCDouble(
loadDouble( blockStart + at->offs ) );
break;
1096 size_t foff = blockStart + at->offs;
1097 val =
loadStr( foff, at->len );
1102 if( foff + 5 <=
m_buf->size() && ( *
m_buf )[foff] == 0x7F )
1103 m_longRefs.push_back( { node, wxString::FromUTF8( at->name ),
loadU32( foff + 1, 4 ) } );
1109 node->
props[wxString::FromUTF8( at->name )] = val;
1114 for(
const SUBSECT* ss = sc->subs; ss->offs != 0; ss++ )
1116 uint32_t numch =
loadU32( blockStart + ss->offs, ss->len );
1119 if( ss->treeName !=
nullptr )
1120 lpar = node->
AddChild( 0, wxString::FromUTF8( ss->treeName ) );
1122 if( ss->ssType == SS_DIRECT )
1124 for( uint32_t n = 0; n < numch && aNumBlocks > 0; n++ )
1136 if( ss->ssType == SS_RECURSIVE_MINUS_1 && numch > 0 )
1141 for( uint32_t n = 0; n < numch && rem > 0; n++ )
1177 size_t total =
static_cast<size_t>( textLen ) + 4;
1185 size_t blobStart =
m_pos;
1191 while( cur <
end && ( *
m_buf )[cur] !=
'\0' )
1195 while( cur <
end && ( *
m_buf )[cur] !=
'\0' )
1198 wxString str = wxString::FromUTF8(
reinterpret_cast<const char*
>(
m_buf->data() + s ),
1214 wxLogTrace(
traceEagleIo, wxS(
"Eagle bin: free-text reference out of strings" ) );
1232 std::vector<bool> done(
m_longRefs.size(),
false );
1233 std::vector<wxString> value(
m_longRefs.size() );
1237 std::map<long long, int> votes;
1239 for(
size_t i = 0; i <
m_longRefs.size(); i++ )
1249 votes[
static_cast<long long>(
m_longRefs[i].ptr ) -
static_cast<long long>( offset )]++;
1253 long long base = -1;
1256 for(
const auto& [cand, count] : votes )
1270 for(
size_t i = 0; i <
m_longRefs.size(); i++ )
1276 static_cast<size_t>(
static_cast<long long>(
m_longRefs[i].ptr ) - base ) );
1280 value[i] = it->second;
1293 bool allResolved = std::all_of( done.begin(), done.end(), [](
bool d ) { return d; } );
1297 for(
size_t i = 0; i <
m_longRefs.size(); i++ )
1326 uint8_t c = ( *m_buf )[
m_pos++];
1343 const size_t kDrcLen = 244;
1350 auto mil = [&](
size_t aOffs ) ->
long
1352 return static_cast<long>(
loadS32( b + aOffs, 4 ) / 2.54 / 100 );
1368 auto it = aNode->
props.find( aField );
1370 if( it == aNode->
props.end() || it->second.IsEmpty() )
1377 if( it->second[0].GetValue() == 0x7F )
1384 auto fixThreeByte = [](
long num,
bool neg ) ->
long
1386 if( num < 0 && neg )
1388 else if( num > 0 && neg )
1389 return num - 0x800000;
1390 else if( num < 0 && !neg )
1391 return num + 0x800000;
1396 auto setLong = [&](
const wxString& aKey,
long aVal )
1398 aElem->
props[aKey] = wxString::Format( wxS(
"%ld" ), aVal );
1404 auto interpolate = []( int64_t aNumerator, int64_t aSpan, int64_t aDivisor, int64_t aOffset ) ->
long
1406 return static_cast<long>( aNumerator * aSpan / aDivisor + aOffset );
1409 if( aLineType == 129 || aArcType == 0 )
1411 long arcFlags = aElem->
PropLong( wxS(
"arc_negflags" ) );
1412 long x1 = fixThreeByte( aElem->
PropLong( wxS(
"arc_x1" ) ), arcFlags & 0x02 );
1413 long y1 = fixThreeByte( aElem->
PropLong( wxS(
"arc_y1" ) ), arcFlags & 0x04 );
1414 long x2 = fixThreeByte( aElem->
PropLong( wxS(
"arc_x2" ) ), arcFlags & 0x08 );
1415 long y2 = fixThreeByte( aElem->
PropLong( wxS(
"arc_y2" ) ), arcFlags & 0x10 );
1423 long c = ( aElem->
PropLong( wxS(
"arc_c1" ) ) & 0xFF )
1424 | ( ( aElem->
PropLong( wxS(
"arc_c2" ) ) & 0xFF ) << 8 )
1425 | ( ( aElem->
PropLong( wxS(
"arc_c3" ) ) & 0xFF ) << 16 );
1430 c = fixThreeByte( c, arcFlags & 0x01 );
1432 setLong( wxS(
"x1" ), x1 );
1433 setLong( wxS(
"y1" ), y1 );
1434 setLong( wxS(
"x2" ), x2 );
1435 setLong( wxS(
"y2" ), y2 );
1437 long x3 = ( x1 + x2 ) / 2;
1438 long y3 = ( y1 + y2 ) / 2;
1439 long cx = 0, cy = 0;
1441 if( x1 == x2 && y1 == y2 )
1451 cy = interpolate( x3 - cx, x2 - x1, y2 - y1, y3 );
1456 cx = interpolate( y3 - cy, y2 - y1, x2 - x1, x3 );
1459 long radius =
static_cast<long>( std::hypot( cx - x2, cy - y2 ) );
1460 setLong( wxS(
"radius" ),
radius );
1461 setLong( wxS(
"x" ), cx );
1462 setLong( wxS(
"y" ), cy );
1464 if( cx == x2 && cy == y1 && x2 < x1 && y2 > y1 )
1466 aElem->
props[wxS(
"StartAngle" )] = wxS(
"90" );
1467 aElem->
props[wxS(
"Delta" )] = wxS(
"90" );
1469 else if( cx == x1 && cy == y2 && x2 < x1 && y1 > y2 )
1471 aElem->
props[wxS(
"StartAngle" )] = wxS(
"0" );
1472 aElem->
props[wxS(
"Delta" )] = wxS(
"90" );
1474 else if( cx == x2 && cy == y1 && x2 > x1 && y1 > y2 )
1476 aElem->
props[wxS(
"StartAngle" )] = wxS(
"270" );
1477 aElem->
props[wxS(
"Delta" )] = wxS(
"90" );
1479 else if( cx == x1 && cy == y2 && x2 > x1 && y2 > y1 )
1481 aElem->
props[wxS(
"StartAngle" )] = wxS(
"180" );
1482 aElem->
props[wxS(
"Delta" )] = wxS(
"90" );
1486 double theta1 = 180.0 - 180.0 /
M_PI * atan2( cy - y1, x1 - cx );
1487 double theta2 = 180.0 - 180.0 /
M_PI * atan2( cy - y2, x2 - cx );
1488 double deltaTheta = theta2 - theta1;
1490 while( theta1 > 360 )
1493 while( deltaTheta < -180 )
1496 while( deltaTheta > 180 )
1499 setLong( wxS(
"StartAngle" ),
static_cast<long>( theta1 ) );
1500 setLong( wxS(
"Delta" ),
static_cast<long>( deltaTheta ) );
1503 else if( ( aLineType > 0 && aLineType < 129 ) || aArcType > 0 )
1505 long x1 = 0, y1 = 0, x2 = 0, y2 = 0, cx = 0, cy = 0;
1507 if( aElem->
HasProp( wxS(
"arctype_other_x1" ) ) )
1509 x1 = aElem->
PropLong( wxS(
"arctype_other_x1" ) );
1510 y1 = aElem->
PropLong( wxS(
"arctype_other_y1" ) );
1511 x2 = aElem->
PropLong( wxS(
"arctype_other_x2" ) );
1512 y2 = aElem->
PropLong( wxS(
"arctype_other_y2" ) );
1516 x1 = aElem->
PropLong( wxS(
"linetype_0_x1" ) );
1517 y1 = aElem->
PropLong( wxS(
"linetype_0_y1" ) );
1518 x2 = aElem->
PropLong( wxS(
"linetype_0_x2" ) );
1519 y2 = aElem->
PropLong( wxS(
"linetype_0_y2" ) );
1523 auto setAngles = [&](
const char* aStart,
const char* aDelta )
1525 aElem->
props[wxS(
"StartAngle" )] = wxString::FromUTF8( aStart );
1526 aElem->
props[wxS(
"Delta" )] = wxString::FromUTF8( aDelta );
1529 if( aLineType == 0x78 || aArcType == 0x01 )
1531 cx = std::min( x1, x2 );
1532 cy = std::min( y1, y2 );
1533 setAngles(
"180",
"90" );
1535 else if( aLineType == 0x79 || aArcType == 0x02 )
1537 cx = std::max( x1, x2 );
1538 cy = std::min( y1, y2 );
1539 setAngles(
"270",
"90" );
1541 else if( aLineType == 0x7a || aArcType == 0x03 )
1543 cx = std::max( x1, x2 );
1544 cy = std::max( y1, y2 );
1545 setAngles(
"0",
"90" );
1547 else if( aLineType == 0x7b || aArcType == 0x04 )
1549 cx = std::min( x1, x2 );
1550 cy = std::max( y1, y2 );
1551 setAngles(
"90",
"90" );
1553 else if( aLineType == 0x7c || aArcType == 0x05 )
1555 cx = ( x1 + x2 ) / 2;
1556 cy = ( y1 + y2 ) / 2;
1557 setAngles(
"90",
"180" );
1559 else if( aLineType == 0x7d || aArcType == 0x06 )
1561 cx = ( x1 + x2 ) / 2;
1562 cy = ( y1 + y2 ) / 2;
1563 setAngles(
"270",
"180" );
1565 else if( aLineType == 0x7e || aArcType == 0x07 )
1567 cx = ( x1 + x2 ) / 2;
1568 cy = ( y1 + y2 ) / 2;
1569 setAngles(
"180",
"180" );
1571 else if( aLineType == 0x7f || aArcType == 0x08 )
1573 cx = ( x1 + x2 ) / 2;
1574 cy = ( y1 + y2 ) / 2;
1575 setAngles(
"0",
"180" );
1585 long radius =
static_cast<long>( std::hypot( cx - x2, cy - y2 ) );
1586 setLong( wxS(
"radius" ),
radius );
1587 setLong( wxS(
"x" ), cx );
1588 setLong( wxS(
"y" ), cy );
1597 int lineType = aRoot->
HasProp( wxS(
"linetype" ) ) ? (int) aRoot->
PropLong( wxS(
"linetype" ) ) : -1;
1603 aRoot->
props[wxS(
"x1" )] = aRoot->
Prop( wxS(
"linetype_0_x1" ) );
1604 aRoot->
props[wxS(
"y1" )] = aRoot->
Prop( wxS(
"linetype_0_y1" ) );
1605 aRoot->
props[wxS(
"x2" )] = aRoot->
Prop( wxS(
"linetype_0_x2" ) );
1606 aRoot->
props[wxS(
"y2" )] = aRoot->
Prop( wxS(
"linetype_0_y2" ) );
1618 if( aRoot->
HasProp( wxS(
"Delta" ) ) && aRoot->
PropLong( wxS(
"Delta" ) ) != 0 )
1619 aRoot->
props[wxS(
"curve" )] = aRoot->
Prop( wxS(
"Delta" ) );
1623 for(
const auto& child : aRoot->
children )
1632 int arcType = aRoot->
HasProp( wxS(
"arctype" ) ) ? (int) aRoot->
PropLong( wxS(
"arctype" ) ) : -1;
1636 aRoot->
props[wxS(
"x1" )] = aRoot->
Prop( wxS(
"arc_x1" ) );
1637 aRoot->
props[wxS(
"y1" )] = aRoot->
Prop( wxS(
"arc_y1" ) );
1638 aRoot->
props[wxS(
"x2" )] = aRoot->
Prop( wxS(
"arc_x2" ) );
1639 aRoot->
props[wxS(
"y2" )] = aRoot->
Prop( wxS(
"arc_y2" ) );
1641 else if( arcType > 0 )
1643 aRoot->
props[wxS(
"x1" )] = aRoot->
Prop( wxS(
"arctype_other_x1" ) );
1644 aRoot->
props[wxS(
"y1" )] = aRoot->
Prop( wxS(
"arctype_other_y1" ) );
1645 aRoot->
props[wxS(
"x2" )] = aRoot->
Prop( wxS(
"arctype_other_x2" ) );
1646 aRoot->
props[wxS(
"y2" )] = aRoot->
Prop( wxS(
"arctype_other_y2" ) );
1656 if( aRoot->
HasProp( wxS(
"Delta" ) ) && aRoot->
PropLong( wxS(
"Delta" ) ) != 0 )
1657 aRoot->
props[wxS(
"curve" )] = aRoot->
Prop( wxS(
"Delta" ) );
1660 for(
const auto& child : aRoot->
children )
1674 std::vector<std::unique_ptr<EGB_NODE>> rebuilt;
1676 for(
auto& child : aRoot->
children )
1680 rebuilt.push_back( std::move( child ) );
1684 auto vertex = std::make_unique<EGB_NODE>();
1685 vertex->name = wxS(
"vertex" );
1686 vertex->parent = aRoot;
1687 vertex->
props[wxS(
"x" )] = child->Prop( wxS(
"x1" ) );
1688 vertex->props[wxS(
"y" )] = child->Prop( wxS(
"y1" ) );
1690 if( child->HasProp( wxS(
"curve" ) ) )
1691 vertex->props[wxS(
"curve" )] = child->Prop( wxS(
"curve" ) );
1693 rebuilt.push_back( std::move( vertex ) );
1696 aRoot->
children = std::move( rebuilt );
1699 for(
const auto& child : aRoot->
children )
1711 aRoot->
props[wxS(
"extent" )] = wxS(
"1-16" );
1714 for(
const auto& child : aRoot->
children )
1725 static const wxString dimAttrs[] = { wxS(
"x" ), wxS(
"y" ), wxS(
"x1" ), wxS(
"y1" ),
1726 wxS(
"x2" ), wxS(
"y2" ), wxS(
"x3" ), wxS(
"y3" ),
1727 wxS(
"width" ), wxS(
"drill" ), wxS(
"diameter" ), wxS(
"radius" ),
1728 wxS(
"size" ), wxS(
"dx" ), wxS(
"dy" ), wxS(
"spacing" ),
1731 for(
const wxString& key : dimAttrs )
1733 auto it = aRoot->
props.find( key );
1735 if( it == aRoot->
props.end() )
1740 if( it->second.ToCDouble( &du ) )
1741 it->second = wxString::FromCDouble( du * 0.0001, 4 );
1744 for(
const auto& child : aRoot->
children )
1756 for(
const auto& child : aRoot->
children )
1765 if( aRoot->
HasProp( wxS(
"half_dx" ) ) )
1770 if( aRoot->
HasProp( wxS(
"half_dy" ) ) )
1776 for(
const auto& child : aRoot->
children )
1792 static const std::map<long, wxString> names = {
1793 { 0, wxS(
"square" ) }, { 1, wxS(
"round" ) }, { 2, wxS(
"octagon" ) },
1794 { 3, wxS(
"long" ) }, { 4, wxS(
"offset" ) } };
1796 auto it = names.find( aRoot->
PropLong( wxS(
"shape" ) ) );
1798 if( it != names.end() )
1799 aRoot->
props[wxS(
"shape" )] = it->second;
1801 aRoot->
props.erase( wxS(
"shape" ) );
1804 for(
const auto& child : aRoot->
children )
1814 if( aRoot->
HasProp( wxS(
"half_drill" ) ) )
1819 if( aRoot->
HasProp( wxS(
"half_diameter" ) ) )
1821 aRoot->
props[wxS(
"diameter" )] = aRoot->
PropDoubled( wxS(
"half_diameter" ) );
1824 if( aRoot->
HasProp( wxS(
"half_size" ) ) )
1830 for(
const auto& child : aRoot->
children )
1853 default:
return false;
1865 auto flagSet = [&](
const wxString& aKey )
1870 const wxString v = aRoot->
Prop( aKey );
1871 return v != wxS(
"no" ) && v != wxS(
"0" );
1874 bool mirrored = flagSet( wxS(
"mirrored" ) );
1875 bool spin = flagSet( wxS(
"spin" ) );
1877 long deg = aRoot->
PropLong( wxS(
"bin_rot" ) );
1886 degrees = ( deg & 0x3 ) * 90.0;
1888 degrees = 360.0 * ( deg & 0x0FFF ) / 4096.0;
1898 rot << wxS(
"R" ) << wxString::FromCDouble( degrees, 4 );
1900 aRoot->
props[wxS(
"rot" )] = rot;
1903 for(
const auto& child : aRoot->
children )
1914 static const wxString c_length[] = { wxS(
"point" ), wxS(
"short" ), wxS(
"middle" ), wxS(
"long" ) };
1915 static const wxString c_direction[] = { wxS(
"nc" ), wxS(
"in" ), wxS(
"out" ), wxS(
"io" ), wxS(
"oc" ),
1916 wxS(
"pwr" ), wxS(
"pas" ), wxS(
"hiz" ), wxS(
"sup" ) };
1917 static const wxString c_visible[] = { wxS(
"off" ), wxS(
"pad" ), wxS(
"pin" ), wxS(
"both" ) };
1918 static const wxString c_function[] = { wxS(
"none" ), wxS(
"dot" ), wxS(
"clk" ), wxS(
"dotclk" ) };
1920 auto mapField = [&](
EGB_NODE* aNode,
const wxString& aKey,
const wxString* aTable,
size_t aCount )
1925 long idx = aNode->
PropLong( aKey );
1927 if( idx >= 0 && idx < (
long) aCount )
1928 aNode->
props[aKey] = aTable[idx];
1937 mapField( aNode, wxS(
"length" ), c_length,
sizeof( c_length ) /
sizeof( c_length[0] ) );
1938 mapField( aNode, wxS(
"direction" ), c_direction,
sizeof( c_direction ) /
sizeof( c_direction[0] ) );
1939 mapField( aNode, wxS(
"visible" ), c_visible,
sizeof( c_visible ) /
sizeof( c_visible[0] ) );
1940 mapField( aNode, wxS(
"function" ), c_function,
sizeof( c_function ) /
sizeof( c_function[0] ) );
2010 for(
const auto& child : aRoot->
children )
2027 default:
return false;
2040 std::vector<std::unique_ptr<EGB_NODE>> kept;
2043 for(
auto& child : aRoot->
children )
2047 if( eligible !=
nullptr )
2048 eligible->
props[wxS(
"textfield" )] = child->Prop( wxS(
"textfield" ) );
2054 kept.push_back( std::move( child ) );
2055 eligible = ( kept.back()->HasProp( wxS(
"textfield" ) ) &&
isLongTextHost( kept.back()->id ) )
2060 aRoot->
children = std::move( kept );
2062 for(
const auto& child : aRoot->
children )
2072 aRoot->
content = aRoot->
Prop( wxS(
"textfield" ) );
2074 for(
const auto& child : aRoot->
children )
2083 std::vector<std::unique_ptr<EGB_NODE>> kept;
2085 for(
auto& child : aDrawing->
children )
2091 if( child->HasProp( wxS(
"visible" ) ) )
2093 child->props[wxS(
"visible" )] = child->PropLong( wxS(
"visible" ) ) != 0 ? wxS(
"yes" ) : wxS(
"no" );
2096 child->parent = aLayers;
2097 aLayers->
children.push_back( std::move( child ) );
2101 kept.push_back( std::move( child ) );
2105 aDrawing->
children = std::move( kept );
2111 auto addParam = [&](
const wxString& aName,
const wxString& aValue )
2114 p->
props[wxS(
"name" )] = aName;
2115 p->
props[wxS(
"value" )] = aValue;
2118 addParam( wxS(
"mdWireWire" ), wxString::Format( wxS(
"%ldmil" ), aDrc.
mdWireWire ) );
2119 addParam( wxS(
"msWidth" ), wxString::Format( wxS(
"%ldmil" ), aDrc.
msWidth ) );
2120 addParam( wxS(
"rvPadTop" ), wxString::FromCDouble( aDrc.
rvPadTop ) );
2121 addParam( wxS(
"rvPadInner" ), wxString::FromCDouble( aDrc.
rvPadInner ) );
2122 addParam( wxS(
"rvPadBottom" ), wxString::FromCDouble( aDrc.
rvPadBottom ) );
2131 if( aLibraries ==
nullptr )
2137 std::vector<std::unique_ptr<EGB_NODE>> wrapped;
2139 for(
auto& child : aLibraries->
children )
2144 auto lib = std::make_unique<EGB_NODE>();
2146 lib->name = wxS(
"library" );
2147 lib->parent = aLibraries;
2148 child->
parent = lib.get();
2149 lib->
children.push_back( std::move( child ) );
2150 wrapped.push_back( std::move( lib ) );
2153 if( !wrapped.empty() )
2154 aLibraries->
children = std::move( wrapped );
2160 if( aElements ==
nullptr )
2165 for(
auto& el : aElements->
children )
2170 for(
auto& el2 : el->children )
2175 for(
const auto& [key, value] : el2->props )
2177 if( key == wxS(
"name" ) )
2179 if( value == wxS(
"-" ) )
2180 el->props[wxS(
"name" )] = wxS(
"HYPHEN" );
2182 el->props[wxS(
"name" )] = value;
2184 else if( key == wxS(
"value" ) )
2186 el->props[wxS(
"value" )] = value;
2196 if( aLibraries ==
nullptr )
2204 std::map<wxString, int> seenLibs;
2206 for(
size_t li = 0; li < aLibraries->
children.size(); li++ )
2217 wxString libName = pkgs ? pkgs->
Prop( wxS(
"library" ) ) : wxString();
2219 if( libName.IsEmpty() )
2220 libName = wxString::Format( wxS(
"lib%zu" ), li + 1 );
2226 if(
int& libCount = seenLibs[libName]; libCount++ > 0 )
2227 libName = wxString::Format( wxS(
"%s_%d" ), libName, libCount );
2229 lib->
props[wxS(
"name" )] = libName;
2231 if( pkgs ==
nullptr )
2234 std::map<wxString, int> seen;
2236 for(
size_t pi = 0; pi < pkgs->
children.size(); pi++ )
2239 wxString
name = pkg->
Prop( wxS(
"name" ) );
2241 if(
name.IsEmpty() )
2242 name = wxString::Format( wxS(
"pkg%zu" ), pi + 1 );
2246 if(
int& count = seen[
name]; count++ > 0 )
2247 name = wxString::Format( wxS(
"%s_%d" ),
name, count );
2253 if( aElements ==
nullptr )
2256 auto nameByIdx = [&](
EGB_NODE* aParent,
long aIdx ) -> wxString
2258 if( aParent ==
nullptr || aIdx < 1 || aIdx > (
long) aParent->
children.size() )
2261 return aParent->
children[aIdx - 1]->Prop( wxS(
"name" ) );
2264 for(
auto& el : aElements->
children )
2269 long libIdx = el->PropLong( wxS(
"library" ) );
2270 EGB_NODE* lib = ( libIdx >= 1 && libIdx <= (long) aLibraries->
children.size() )
2271 ? aLibraries->
children[libIdx - 1].get()
2274 if( lib ==
nullptr )
2277 el->props[wxS(
"library" )] = lib->
Prop( wxS(
"name" ) );
2280 wxString pkgName = nameByIdx( pkgs, el->
PropLong( wxS(
"package" ) ) );
2282 if( !pkgName.IsEmpty() )
2283 el->props[wxS(
"package" )] = pkgName;
2290 if( aSignals ==
nullptr )
2298 for(
size_t i = 0; i < aSignals->
children.size(); i++ )
2305 std::vector<std::unique_ptr<EGB_NODE>> kept;
2306 std::vector<std::unique_ptr<EGB_NODE>> promoted;
2312 inner->parent = aSignals;
2313 promoted.push_back( std::move( inner ) );
2317 kept.push_back( std::move( inner ) );
2325 for(
auto& p : promoted )
2326 aSignals->
children.push_back( std::move( p ) );
2333 if( aSignals ==
nullptr || aElements ==
nullptr || aLibraries ==
nullptr )
2336 auto elemByIdx = [&](
long aIdx ) ->
EGB_NODE*
2338 if( aIdx < 1 || aIdx > (
long) aElements->
children.size() )
2341 return aElements->
children[aIdx - 1].get();
2344 auto libByIdx = [&](
long aIdx ) ->
EGB_NODE*
2346 if( aIdx < 1 || aIdx > (
long) aLibraries->
children.size() )
2349 return aLibraries->
children[aIdx - 1].get();
2354 if( aLib ==
nullptr )
2359 if( pkgs ==
nullptr || aIdx < 1 || aIdx > (
long) pkgs->
children.size() )
2362 return pkgs->
children[aIdx - 1].get();
2365 for(
auto& sig : aSignals->
children )
2369 for(
auto& cr : sig->children )
2374 long partNum = cr->PropLong( wxS(
"partnumber" ) );
2375 EGB_NODE* elem = elemByIdx( partNum );
2377 if( elem ==
nullptr )
2380 cr->props[wxS(
"element" )] = elem->
Prop( wxS(
"name" ) );
2386 if( pkg ==
nullptr )
2388 cr->props[wxS(
"pad" )] = wxS(
"PIN_NOT_FOUND" );
2392 long pinNum = cr->PropLong( wxS(
"pin" ) );
2395 for(
const auto& child : pkg->
children )
2397 int kind = child->id & 0xFF00;
2403 found = child.get();
2409 if( found ==
nullptr )
2410 cr->
props[wxS(
"pad" )] = wxS(
"PIN_NOT_FOUND" );
2411 else if( found->
HasProp( wxS(
"name" ) ) )
2412 cr->props[wxS(
"pad" )] = found->
Prop( wxS(
"name" ) );
2414 cr->props[wxS(
"pad" )] = cr->Prop( wxS(
"pin" ) );
2424 if( drawing ==
nullptr )
2437 if( board !=
nullptr )
2442 if( libraries ==
nullptr )
2443 THROW_IO_ERROR(
_(
"Eagle binary layout is missing a board/libraries node." ) );
2455 if( drcNode !=
nullptr )
2506 std::vector<std::unique_ptr<EGB_NODE>> kept;
2508 for(
auto& child : aRoot->
children )
2513 kept.push_back( std::move( child ) );
2516 aRoot->
children = std::move( kept );
2518 for(
const auto& child : aRoot->
children )
2525 wxXmlNode* xml =
new wxXmlNode( wxXML_ELEMENT_NODE, aNode->
name );
2527 for(
const auto& [key, value] : aNode->
props )
2528 xml->AddAttribute( key, value );
2530 if( !aNode->
content.IsEmpty() )
2531 xml->AddChild(
new wxXmlNode( wxXML_TEXT_NODE, wxEmptyString, aNode->
content ) );
2535 for(
const auto& child : aNode->
children )
2536 xml->AddChild(
toXml( child.get() ) );
2548 if( aBytes.size() < 24 )
2549 THROW_IO_ERROR(
_(
"File is too small to be an Eagle binary board." ) );
2556 m_root = std::make_unique<EGB_NODE>();
2558 m_root->name = wxS(
"eagle" );
2560 long numBlocks = -1;
2571 if( drawing !=
nullptr )
2573 long v1 = drawing->
HasProp( wxS(
"v1" ) ) ? drawing->
PropLong( wxS(
"v1" ) ) : 5;
2574 long v2 = drawing->
HasProp( wxS(
"v2" ) ) ? drawing->
PropLong( wxS(
"v2" ) ) : 0;
2575 m_root->props[wxS(
"version" )] = wxString::Format( wxS(
"%ld.%ld" ),
v1,
v2 );
2601 auto doc = std::make_unique<wxXmlDocument>();
2613 if( drawing ==
nullptr )
2614 THROW_IO_ERROR(
_(
"Eagle binary schematic has no drawing section." ) );
2618 if( schematic ==
nullptr )
2622 schematic->name = wxS(
"schematic" );
2652std::vector<EAGLE_BIN_PARSER::EGB_NODE*>
2655 std::vector<EGB_NODE*> out;
2657 if( aParent !=
nullptr )
2659 for(
const auto& child : aParent->
children )
2661 if( child->id == aChildId )
2662 out.push_back( child.get() );
2673 if( aIdx >= 1 && aIdx <= (
long) aList.size() )
2674 return aList[aIdx - 1]->Prop( wxS(
"name" ) );
2690 aNode->
props[wxS(
"columns" )] = aNode->
Prop( wxS(
"cols" ) );
2706 aNode->
props[wxS(
"name" )] = aNode->
HasProp( wxS(
"textfield" ) )
2707 ? aNode->
Prop( wxS(
"textfield" ) )
2724 if( aNode->
HasProp( wxS(
"half_size" ) ) )
2725 sizeKey = wxS(
"half_size" );
2726 else if( aNode->
HasProp( wxS(
"size" ) ) )
2727 sizeKey = wxS(
"size" );
2729 if( !sizeKey.IsEmpty() && aNode->
PropLong( sizeKey ) >= 0 )
2755 if( aNode->
name == wxS(
"variants" ) )
2756 aNode->
name = wxS(
"devices" );
2764std::vector<EAGLE_BIN_PARSER::EGB_NODE*>
2767 auto wrapChildren = [](
EGB_NODE* aParent,
const wxString& aContainer,
2770 std::vector<std::unique_ptr<EGB_NODE>> kept;
2771 std::vector<std::unique_ptr<EGB_NODE>>
moved;
2773 for(
auto& child : aParent->
children )
2775 if( aPred( child.get() ) )
2776 moved.push_back( std::move( child ) );
2778 kept.push_back( std::move( child ) );
2781 aParent->
children = std::move( kept );
2788 for(
auto& node :
moved )
2798 wrapChildren( aSchematic, wxS(
"libraries" ),
2806 for(
size_t li = 0; li < libList.size(); li++ )
2819 libName = n->
Prop( wxS(
"library" ) );
2824 if( libName.IsEmpty() )
2825 libName = wxString::Format( wxS(
"lib%zu" ), li + 1 );
2827 lib->
props[wxS(
"name" )] = libName;
2833 [](
const std::unique_ptr<EGB_NODE>& n )
2834 { return n->id == EGKW_SECT_PACKAGES; } ),
2842 std::map<wxString, int> dsSeen;
2844 for(
size_t di = 0; di < devicesetList.size(); di++ )
2847 wxString
name = ds->
Prop( wxS(
"name" ) );
2849 if(
name.IsEmpty() )
2850 name = wxString::Format( wxS(
"dset%zu" ), di + 1 );
2852 if(
int& count = dsSeen[
name]; count++ > 0 )
2853 name = wxString::Format( wxS(
"%s_%d" ),
name, count );
2860 gate->
props[wxS(
"symbol" )] =
nameByOrdinal( symbols, gate->PropLong( wxS(
"symno" ) ) );
2869 const std::vector<EGB_NODE*>& aLibList )
2871 auto adopt = [](
EGB_NODE* aParent,
EGB_NODE*& aSlot,
const wxString& aName,
2872 std::unique_ptr<EGB_NODE> aNode )
2874 if( aSlot ==
nullptr )
2875 aSlot = aParent->
AddChild( 0, aName );
2885 std::vector<std::unique_ptr<EGB_NODE>> flat = std::move( aSchematic->
children );
2888 std::vector<std::unique_ptr<EGB_NODE>> sheetNodes;
2889 std::vector<std::unique_ptr<EGB_NODE>> globalParts;
2890 std::map<wxString, bool> seenPart;
2899 for(
auto& node : flat )
2902 if( node->name == wxS(
"libraries" ) )
2904 aSchematic->
children.push_back( std::move( node ) );
2913 curSheet = node.get();
2914 curPlain = curInstances = curNets = curBusses =
nullptr;
2916 std::vector<std::unique_ptr<EGB_NODE>> drawables = std::move( curSheet->
children );
2919 for(
auto& drawable : drawables )
2920 adopt( curSheet, curPlain, wxS(
"plain" ), std::move( drawable ) );
2922 sheetNodes.push_back( std::move( node ) );
2929 long libno = part->
PropLong( wxS(
"lib" ) );
2930 long devno = part->
PropLong( wxS(
"device" ) );
2931 long varno = part->
PropLong( wxS(
"variant" ) );
2933 EGB_NODE* lib = ( libno >= 1 && libno <= (long) aLibList.size() ) ? aLibList[libno - 1]
2935 std::vector<EGB_NODE*> devicesets =
2938 EGB_NODE* ds = ( devno >= 1 && devno <= (long) devicesets.size() ) ? devicesets[devno - 1]
2940 std::vector<EGB_NODE*> variants =
2943 std::vector<EGB_NODE*> gates =
2947 wxString partName = part->
Prop( wxS(
"name" ) );
2949 part->
props[wxS(
"library" )] = lib ? lib->
Prop( wxS(
"name" ) ) : wxString();
2950 part->
props[wxS(
"deviceset" )] = ds ? ds->
Prop( wxS(
"name" ) ) : wxString();
2956 part->
props.erase( wxS(
"technology" ) );
2959 std::vector<std::unique_ptr<EGB_NODE>> partKept;
2965 partKept.push_back( std::move( sub ) );
2969 sub->props[wxS(
"part" )] = partName;
2970 sub->props[wxS(
"gate" )] =
nameByOrdinal( gates, sub->PropLong( wxS(
"gateno" ) ) );
2971 adopt( curSheet, curInstances, wxS(
"instances" ), std::move( sub ) );
2974 part->
children = std::move( partKept );
2977 if( !seenPart[partName] )
2979 seenPart[partName] =
true;
2980 node->parent = aSchematic;
2981 globalParts.push_back( std::move( node ) );
2989 node->props[wxS(
"class" )] =
2990 node->HasProp( wxS(
"netclass" ) ) ? node->Prop( wxS(
"netclass" ) ) : wxString( wxS(
"0" ) );
2993 seg->name = wxS(
"segment" );
2995 if( curSheet !=
nullptr )
2996 adopt( curSheet, curNets, wxS(
"nets" ), std::move( node ) );
3003 if( curSheet !=
nullptr )
3004 adopt( curSheet, curBusses, wxS(
"busses" ), std::move( node ) );
3012 if( curSheet !=
nullptr )
3013 adopt( curSheet, curPlain, wxS(
"plain" ), std::move( node ) );
3024 for(
auto& sheet : sheetNodes )
3025 sheetsNode->
AdoptChild( std::move( sheet ) );
3029 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 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 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.
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.