39#include <wx/xml/xml.h>
126constexpr uint32_t BITFIELD( uint32_t aWidth, uint32_t aFirst, uint32_t aLast )
128 return ( aWidth << 16 ) | ( aFirst << 8 ) | aLast;
143 const char* treeName;
156 unsigned cmd, cmdMask;
169 0, 0, SS_DIRECT, nullptr \
173 nullptr, T_INT, 0, 0 \
177const SCRIPT_ROW g_script[] = {
182 { { 4, 4, SS_RECURSIVE_MINUS_1,
nullptr },
TERM_S },
183 { {
"subsecs", T_INT, 2, 2 },
184 {
"numsecs", T_INT, 4, 4 },
185 {
"subsecsMSB", T_INT, 3, 1 },
186 {
"subsecsLSB", T_INT, 2, 1 },
187 {
"numsecsMSB2", T_INT, 7, 1 },
188 {
"numsecsMSB1", T_INT, 6, 1 },
189 {
"numsecsMSB0", T_INT, 5, 1 },
190 {
"numsecsLSB", T_INT, 4, 1 },
191 {
"v1", T_INT, 8, 1 },
192 {
"v2", T_INT, 9, 1 },
200 { {
"display", T_BMB, 2, 0x01 },
201 {
"visible", T_BMB, 2, 0x02 },
202 {
"unit", T_UBF, 3, BITFIELD( 1, 0, 3 ) },
203 {
"altunit", T_UBF, 3, BITFIELD( 1, 4, 7 ) },
204 {
"multiple", T_INT, 4, 3 },
205 {
"size", T_DBL, 8, 8 },
206 {
"altsize", T_DBL, 16, 8 },
213 { {
"side", T_BMB, 2, 0x10 },
214 {
"visible", T_UBF, 2, BITFIELD( 1, 2, 3 ) },
215 {
"active", T_BMB, 2, 0x02 },
216 {
"number", T_UBF, 3, BITFIELD( 1, 0, 7 ) },
217 {
"other", T_INT, 4, 1 },
218 {
"fill", T_UBF, 5, BITFIELD( 1, 0, 3 ) },
219 {
"color", T_UBF, 6, BITFIELD( 1, 0, 5 ) },
220 {
"name", T_STR, 15, 9 },
226 { { 4, 4, SS_DIRECT,
nullptr },
TERM_S },
227 { {
"shtsubsecs", T_INT, 8, 4 }, {
"atrsubsecs", T_INT, 12, 4 }, {
"xref_format", T_STR, 19, 5 },
TERM_A } },
232 { { 4, 4, SS_RECURSIVE,
nullptr }, { 8, 4, SS_RECURSIVE,
nullptr }, { 12, 4, SS_RECURSIVE,
nullptr },
TERM_S },
233 { {
"devsubsecs", T_INT, 4, 4 },
234 {
"symsubsecs", T_INT, 8, 4 },
235 {
"pacsubsecs", T_INT, 12, 4 },
236 {
"children", T_INT, 8, 4 },
237 {
"name", T_STR, 16, 8 },
243 { { 4, 4, SS_DIRECT,
nullptr },
TERM_S },
244 { {
"children", T_INT, 8, 4 }, {
"library", T_STR, 16, 8 },
TERM_A } },
249 { { 4, 4, SS_RECURSIVE,
nullptr },
TERM_S },
250 { {
"children", T_INT, 8, 4 }, {
"library", T_STR, 16, 8 },
TERM_A } },
255 { { 4, 4, SS_RECURSIVE,
nullptr },
TERM_S },
256 { {
"subsects", T_INT, 4, 4 },
257 {
"children", T_INT, 8, 2 },
258 {
"desc", T_STR, 10, 6 },
259 {
"library", T_STR, 16, 8 },
265 { { 2, 2, SS_DIRECT,
nullptr },
TERM_S },
266 { {
"minx", T_INT, 4, 2 },
267 {
"miny", T_INT, 6, 2 },
268 {
"maxx", T_INT, 8, 2 },
269 {
"maxy", T_INT, 10, 2 },
270 {
"partsubsecs", T_INT, 12, 4 },
271 {
"bussubsecs", T_INT, 16, 4 },
272 {
"netsubsecs", T_INT, 20, 4 },
278 { { 12, 4, SS_RECURSIVE,
"libraries" },
279 { 2, 2, SS_DIRECT,
"plain" },
280 { 16, 4, SS_RECURSIVE,
"elements" },
281 { 20, 4, SS_RECURSIVE,
"signals" },
283 { {
"minx", T_INT, 4, 2 },
284 {
"miny", T_INT, 6, 2 },
285 {
"maxx", T_INT, 8, 2 },
286 {
"maxy", T_INT, 10, 2 },
287 {
"defsubsecs", T_INT, 12, 4 },
288 {
"pacsubsecs", T_INT, 16, 4 },
289 {
"netsubsecs", T_INT, 20, 4 },
295 { { 2, 2, SS_DIRECT,
nullptr },
TERM_S },
296 { {
"minx", T_INT, 4, 2 },
297 {
"miny", T_INT, 6, 2 },
298 {
"maxx", T_INT, 8, 2 },
299 {
"maxy", T_INT, 10, 2 },
300 {
"airwires", T_BMB, 12, 0x02 },
301 {
"netclass", T_UBF, 13, BITFIELD( 1, 0, 3 ) },
302 {
"name", T_STR, 16, 8 },
308 { { 2, 2, SS_DIRECT,
nullptr },
TERM_S },
309 { {
"minx", T_INT, 4, 2 },
310 {
"miny", T_INT, 6, 2 },
311 {
"maxx", T_INT, 8, 2 },
312 {
"maxy", T_INT, 10, 2 },
313 {
"name", T_STR, 16, 8 },
321 { { 2, 2, SS_RECURSIVE,
nullptr },
TERM_S },
322 { {
"minx", T_INT, 4, 2 },
323 {
"miny", T_INT, 6, 2 },
324 {
"maxx", T_INT, 8, 2 },
325 {
"maxy", T_INT, 10, 2 },
326 {
"desc", T_STR, 13, 5 },
327 {
"name", T_STR, 18, 6 },
333 { { 2, 2, SS_RECURSIVE,
nullptr },
TERM_S },
334 { {
"minx", T_INT, 4, 2 },
335 {
"miny", T_INT, 6, 2 },
336 {
"maxx", T_INT, 8, 2 },
337 {
"maxy", T_INT, 10, 2 },
338 {
"netclass", T_UBF, 13, BITFIELD( 1, 0, 3 ) },
339 {
"name", T_STR, 16, 8 },
345 { { 2, 2, SS_RECURSIVE,
nullptr },
TERM_S },
346 { {
"minx", T_INT, 4, 2 }, {
"miny", T_INT, 6, 2 }, {
"maxx", T_INT, 8, 2 }, {
"maxy", T_INT, 10, 2 },
TERM_A } },
353 { { 2, 2, SS_DIRECT,
nullptr },
TERM_S },
354 { {
"minx", T_INT, 4, 2 },
355 {
"miny", T_INT, 6, 2 },
356 {
"maxx", T_INT, 8, 2 },
357 {
"maxy", T_INT, 10, 2 },
358 {
"width", T_INT, 12, 2 },
359 {
"spacing", T_INT, 14, 2 },
360 {
"isolate", T_INT, 16, 2 },
361 {
"layer", T_UBF, 18, BITFIELD( 1, 0, 7 ) },
362 {
"pour", T_BMB, 19, 0x01 },
363 {
"rank", T_BMB, 19, BITFIELD( 1, 1, 3 ) },
364 {
"thermals", T_BMB, 19, 0x80 },
365 {
"orphans", T_BMB, 19, 0x40 },
372 { {
"layer", T_UBF, 3, BITFIELD( 1, 0, 7 ) },
373 {
"half_width", T_INT, 20, 2 },
374 {
"stflags", T_BMB, 22, 0x33 },
375 {
"ccw", T_BMB, 22, 0x20 },
376 {
"linetype", T_UBF, 23, BITFIELD( 1, 0, 7 ) },
377 {
"linetype_0_x1", T_INT, 4, 4 },
378 {
"linetype_0_y1", T_INT, 8, 4 },
379 {
"linetype_0_x2", T_INT, 12, 4 },
380 {
"linetype_0_y2", T_INT, 16, 4 },
381 {
"arc_negflags", T_UBF, 19, BITFIELD( 1, 0, 4 ) },
382 {
"arc_c1", T_INT, 7, 1 },
383 {
"arc_c2", T_INT, 11, 1 },
384 {
"arc_c3", T_INT, 15, 1 },
385 {
"arc_x1", T_INT, 4, 3 },
386 {
"arc_y1", T_INT, 8, 3 },
387 {
"arc_x2", T_INT, 12, 3 },
388 {
"arc_y2", T_INT, 16, 3 },
395 { {
"layer", T_UBF, 3, BITFIELD( 1, 0, 7 ) },
396 {
"half_width", T_INT, 20, 2 },
397 {
"ccw", T_BMB, 22, 0x20 },
398 {
"arctype", T_UBF, 23, BITFIELD( 1, 0, 7 ) },
399 {
"arc_negflags", T_UBF, 19, BITFIELD( 1, 0, 7 ) },
400 {
"arc_c1", T_INT, 7, 1 },
401 {
"arc_c2", T_INT, 11, 1 },
402 {
"arc_c3", T_INT, 15, 1 },
403 {
"arc_x1", T_INT, 4, 3 },
404 {
"arc_y1", T_INT, 8, 3 },
405 {
"arc_x2", T_INT, 12, 3 },
406 {
"arc_y2", T_INT, 16, 3 },
407 {
"arctype_other_x1", T_INT, 4, 4 },
408 {
"arctype_other_y1", T_INT, 8, 4 },
409 {
"arctype_other_x2", T_INT, 12, 4 },
410 {
"arctype_other_y2", T_INT, 16, 4 },
417 { {
"layer", T_UBF, 3, BITFIELD( 1, 0, 7 ) },
418 {
"x", T_INT, 4, 4 },
419 {
"y", T_INT, 8, 4 },
420 {
"radius", T_INT, 12, 4 },
421 {
"half_width", T_INT, 20, 4 },
430 { {
"layer", T_UBF, 3, BITFIELD( 1, 0, 7 ) },
431 {
"x1", T_INT, 4, 4 },
432 {
"y1", T_INT, 8, 4 },
433 {
"x2", T_INT, 12, 4 },
434 {
"y2", T_INT, 16, 4 },
435 {
"bin_rot", T_INT, 20, 2 },
442 { {
"layer", T_UBF, 3, BITFIELD( 1, 0, 7 ) },
443 {
"x", T_INT, 4, 4 },
444 {
"y", T_INT, 8, 4 },
445 {
"width_2", T_INT, 12, 2 },
452 { {
"x", T_INT, 4, 4 },
453 {
"y", T_INT, 8, 4 },
454 {
"half_diameter", T_UBF, 12, BITFIELD( 2, 0, 15 ) },
455 {
"half_drill", T_UBF, 12, BITFIELD( 2, 0, 15 ) },
464 { {
"shape", T_INT, 2, 1 },
465 {
"x", T_INT, 4, 4 },
466 {
"y", T_INT, 8, 4 },
467 {
"half_drill", T_UBF, 12, BITFIELD( 2, 0, 15 ) },
468 {
"half_diameter", T_UBF, 14, BITFIELD( 2, 0, 15 ) },
469 {
"layers", T_UBF, 16, BITFIELD( 1, 0, 7 ) },
470 {
"stop", T_BMB, 17, 0x01 },
485 { {
"shape", T_INT, 2, 1 },
486 {
"x", T_INT, 4, 4 },
487 {
"y", T_INT, 8, 4 },
488 {
"half_drill", T_UBF, 12, BITFIELD( 2, 0, 15 ) },
489 {
"half_diameter", T_UBF, 14, BITFIELD( 2, 0, 15 ) },
490 {
"name", T_STR, 16, 8 },
497 { {
"roundness", T_INT, 2, 1 },
498 {
"layer", T_UBF, 3, BITFIELD( 1, 0, 7 ) },
499 {
"x", T_INT, 4, 4 },
500 {
"y", T_INT, 8, 4 },
501 {
"half_dx", T_UBF, 12, BITFIELD( 2, 0, 15 ) },
502 {
"half_dy", T_UBF, 14, BITFIELD( 2, 0, 15 ) },
503 {
"name", T_STR, 16, 8 },
510 { {
"shape", T_INT, 2, 1 },
511 {
"x", T_INT, 4, 4 },
512 {
"y", T_INT, 8, 4 },
513 {
"half_drill", T_UBF, 12, BITFIELD( 2, 0, 15 ) },
514 {
"half_diameter", T_UBF, 14, BITFIELD( 2, 0, 15 ) },
515 {
"bin_rot", T_INT, 16, 2 },
516 {
"stop", T_BMB, 18, 0x01 },
517 {
"thermals", T_BMB, 18, 0x04 },
518 {
"first", T_BMB, 18, 0x08 },
519 {
"name", T_STR, 19, 5 },
526 { {
"roundness", T_INT, 2, 1 },
527 {
"layer", T_UBF, 3, BITFIELD( 1, 0, 7 ) },
528 {
"x", T_INT, 4, 4 },
529 {
"y", T_INT, 8, 4 },
530 {
"half_dx", T_UBF, 12, BITFIELD( 2, 0, 15 ) },
531 {
"half_dy", T_UBF, 14, BITFIELD( 2, 0, 15 ) },
532 {
"bin_rot", T_UBF, 16, BITFIELD( 2, 0, 11 ) },
533 {
"stop", T_BMB, 18, 0x01 },
534 {
"cream", T_BMB, 18, 0x02 },
535 {
"thermals", T_BMB, 18, 0x04 },
536 {
"first", T_BMB, 18, 0x08 },
537 {
"name", T_STR, 19, 5 },
544 { {
"function", T_UBF, 2, BITFIELD( 1, 0, 1 ) },
545 {
"visible", T_UBF, 2, BITFIELD( 1, 6, 7 ) },
546 {
"x", T_INT, 4, 4 },
547 {
"y", T_INT, 8, 4 },
548 {
"direction", T_UBF, 12, BITFIELD( 1, 0, 3 ) },
549 {
"length", T_UBF, 12, BITFIELD( 1, 4, 5 ) },
550 {
"bin_rot", T_UBF, 12, BITFIELD( 1, 6, 7 ) },
551 {
"swaplevel", T_INT, 13, 1 },
552 {
"name", T_STR, 14, 10 },
559 { {
"x", T_INT, 4, 4 },
560 {
"y", T_INT, 8, 4 },
561 {
"addlevel", T_INT, 12, 1 },
562 {
"swap", T_INT, 13, 1 },
563 {
"symno", T_INT, 14, 2 },
564 {
"name", T_STR, 16, 8 },
574 { { 2, 2, SS_DIRECT,
nullptr },
TERM_S },
575 { {
"x", T_INT, 4, 4 },
576 {
"y", T_INT, 8, 4 },
577 {
"library", T_INT, 12, 2 },
578 {
"package", T_INT, 14, 2 },
579 {
"bin_rot", T_UBF, 16, BITFIELD( 2, 0, 11 ) },
580 {
"mirrored", T_BMB, 17, 0x10 },
581 {
"spin", T_BMB, 17, 0x40 },
588 { {
"name", T_STR, 2, 8 }, {
"value", T_STR, 10, 14 },
TERM_A } },
593 { { 2, 2, SS_DIRECT,
nullptr },
TERM_S },
594 { {
"x", T_INT, 4, 4 },
595 {
"y", T_INT, 8, 4 },
596 {
"placed", T_INT, 12, 2 },
597 {
"gateno", T_INT, 14, 2 },
598 {
"bin_rot", T_UBF, 16, BITFIELD( 2, 10, 11 ) },
599 {
"mirrored", T_UBF, 16, BITFIELD( 2, 12, 12 ) },
600 {
"smashed", T_BMB, 18, 0x01 },
607 { {
"layer", T_UBF, 3, BITFIELD( 1, 0, 7 ) },
608 {
"x", T_INT, 4, 4 },
609 {
"y", T_INT, 8, 4 },
610 {
"half_size", T_INT, 12, 2 },
611 {
"ratio", T_UBF, 14, BITFIELD( 2, 2, 6 ) },
612 {
"bin_rot", T_UBF, 16, BITFIELD( 2, 0, 11 ) },
613 {
"mirrored", T_UBF, 16, BITFIELD( 2, 12, 12 ) },
614 {
"spin", T_UBF, 16, BITFIELD( 2, 14, 14 ) },
615 {
"textfield", T_STR, 18, 6 },
619 {
EGKW_SECT_LONGTEXT, 0xFFFF,
"longtext", {
TERM_F }, {
TERM_S }, { {
"textfield", T_STR, 2, 22 },
TERM_A } },
625 { {
"layer", T_UBF, 3, BITFIELD( 1, 0, 7 ) },
626 {
"x", T_INT, 4, 4 },
627 {
"y", T_INT, 8, 4 },
628 {
"size", T_INT, 12, 2 },
629 {
"ratio", T_UBF, 14, BITFIELD( 2, 2, 6 ) },
630 {
"bin_rot", T_UBF, 16, BITFIELD( 2, 0, 11 ) },
631 {
"mirrored", T_UBF, 16, BITFIELD( 2, 12, 12 ) },
632 {
"spin", T_UBF, 16, BITFIELD( 2, 14, 14 ) },
633 {
"textfield", T_STR, 18, 6 },
640 { {
"layer", T_UBF, 3, BITFIELD( 1, 0, 7 ) },
641 {
"x", T_INT, 4, 4 },
642 {
"y", T_INT, 8, 4 },
643 {
"size", T_INT, 12, 2 },
644 {
"ratio", T_UBF, 14, BITFIELD( 2, 2, 6 ) },
645 {
"bin_rot", T_UBF, 16, BITFIELD( 2, 0, 11 ) },
646 {
"mirrored", T_UBF, 16, BITFIELD( 2, 12, 12 ) },
647 {
"spin", T_UBF, 16, BITFIELD( 2, 14, 14 ) },
648 {
"textfield", T_STR, 18, 6 },
655 { {
"layer", T_UBF, 3, BITFIELD( 1, 0, 7 ) },
656 {
"x", T_INT, 4, 4 },
657 {
"y", T_INT, 8, 4 },
658 {
"size", T_INT, 12, 2 },
659 {
"ratio", T_UBF, 14, BITFIELD( 2, 2, 6 ) },
660 {
"bin_rot", T_UBF, 16, BITFIELD( 2, 0, 11 ) },
661 {
"mirrored", T_UBF, 16, BITFIELD( 2, 12, 12 ) },
662 {
"spin", T_UBF, 16, BITFIELD( 2, 14, 14 ) },
663 {
"textfield", T_STR, 18, 6 },
669 { { 2, 2, SS_DIRECT,
nullptr },
TERM_S },
670 { {
"package", T_INT, 4, 2 }, {
"table", T_STR, 6, 13 }, {
"name", T_STR, 19, 5 },
TERM_A } },
677 { { 4, 2, SS_RECURSIVE,
"variants" }, { 2, 2, SS_RECURSIVE,
"gates" },
TERM_S },
678 { {
"gates", T_INT, 2, 2 },
679 {
"variants", T_INT, 4, 2 },
680 {
"prefix", T_STR, 8, 5 },
681 {
"desc", T_STR, 13, 5 },
682 {
"name", T_STR, 18, 5 },
688 { { 2, 2, SS_RECURSIVE,
nullptr },
TERM_S },
689 { {
"lib", T_INT, 4, 2 },
690 {
"device", T_INT, 6, 2 },
692 {
"variant", T_UINT, 8, 1 },
693 {
"technology", T_INT, 9, 2 },
694 {
"name", T_STR, 11, 5 },
695 {
"value", T_STR, 16, 8 },
705 { {
"partnumber", T_INT, 4, 2 }, {
"pin", T_INT, 6, 2 },
TERM_A } },
711 { {
"layer", T_UBF, 3, BITFIELD( 1, 0, 7 ) },
712 {
"x", T_INT, 4, 4 },
713 {
"y", T_INT, 8, 4 },
714 {
"size", T_INT, 12, 2 },
715 {
"ratio", T_UBF, 14, BITFIELD( 2, 2, 6 ) },
716 {
"bin_rot", T_UBF, 16, BITFIELD( 2, 0, 11 ) },
717 {
"mirrored", T_UBF, 16, BITFIELD( 2, 12, 12 ) },
718 {
"spin", T_UBF, 16, BITFIELD( 2, 14, 14 ) },
719 {
"textfield", T_STR, 18, 6 },
726 { {
"layer", T_UBF, 3, BITFIELD( 1, 0, 7 ) },
727 {
"x", T_INT, 4, 4 },
728 {
"y", T_INT, 8, 4 },
729 {
"size", T_INT, 12, 2 },
730 {
"ratio", T_UBF, 14, BITFIELD( 2, 2, 6 ) },
731 {
"bin_rot", T_UBF, 16, BITFIELD( 2, 0, 11 ) },
732 {
"mirrored", T_UBF, 16, BITFIELD( 2, 12, 12 ) },
733 {
"spin", T_UBF, 16, BITFIELD( 2, 14, 14 ) },
734 {
"textfield", T_STR, 18, 6 },
743 { {
"layer", T_UBF, 3, BITFIELD( 1, 0, 7 ) },
744 {
"x", T_INT, 4, 4 },
745 {
"y", T_INT, 8, 4 },
746 {
"size", T_INT, 12, 2 },
747 {
"ratio", T_UBF, 14, BITFIELD( 2, 2, 6 ) },
748 {
"bin_rot", T_UBF, 16, BITFIELD( 2, 0, 11 ) },
749 {
"mirrored", T_UBF, 16, BITFIELD( 2, 12, 12 ) },
750 {
"spin", T_UBF, 16, BITFIELD( 2, 14, 14 ) },
751 {
"textfield", T_STR, 18, 6 },
758 { {
"symbol", T_STR, 2, 5 }, {
"attribute", T_STR, 7, 17 },
TERM_A } },
764 { {
"layer", T_UBF, 3, BITFIELD( 1, 0, 7 ) },
765 {
"x1", T_INT, 4, 4 },
766 {
"y1", T_INT, 8, 4 },
767 {
"x2", T_INT, 12, 4 },
768 {
"y2", T_INT, 16, 4 },
769 {
"cols", T_INT, 20, 1 },
770 {
"rows", T_INT, 21, 1 },
771 {
"borders", T_INT, 22, 1 },
778 { {
"layer", T_UBF, 3, BITFIELD( 1, 0, 7 ) },
779 {
"x", T_INT, 4, 4 },
780 {
"y", T_INT, 8, 4 },
781 {
"size", T_INT, 12, 2 },
782 {
"ratio", T_UBF, 14, BITFIELD( 2, 2, 6 ) },
783 {
"bin_rot", T_UBF, 16, BITFIELD( 2, 0, 11 ) },
784 {
"mirrored", T_UBF, 16, BITFIELD( 2, 12, 12 ) },
785 {
"spin", T_UBF, 16, BITFIELD( 2, 14, 14 ) },
786 {
"textfield", T_STR, 18, 6 },
799bool isV3InlineNamePadRow(
const SCRIPT_ROW* aRow )
804 for(
const ATTR* at = aRow->attrs; at->name !=
nullptr; at++ )
806 if( strcmp( at->name,
"name" ) == 0 )
807 return at->offs == 16;
817 auto child = std::make_unique<EGB_NODE>();
820 child->parent =
this;
821 children.push_back( std::move( child ) );
829 aChild->parent =
this;
830 children.push_back( std::move( aChild ) );
838 auto it =
props.find( aKey );
839 return it ==
props.end() ? wxString() : it->second;
846 Prop( aKey ).ToLong( &val );
854 wxLongLong_t val = 0;
855 Prop( aKey ).ToLongLong( &val );
857 return wxString::Format( wxS(
"%lld" ), val * 2 );
865 if( child->id == aId )
877 if( child->name == aName )
891 uint8_t buf[2] = { 0, 0 };
893 if( !aStream.IsOk() )
896 aStream.Read( buf, 2 );
898 if( aStream.LastRead() != 2 )
901 if( buf[0] == 0x10 && ( buf[1] == 0x00 || buf[1] == 0x80 ) )
910 if(
m_buf ==
nullptr || aOffs >
m_buf->size() || aLen >
m_buf->size() - aOffs )
911 THROW_IO_ERROR(
_(
"Short read in Eagle binary file (field out of bounds)." ) );
921 for(
unsigned n = 0; n < aLen; n++ )
924 l |= ( *m_buf )[aOffs + aLen - n - 1];
937 if( ( *
m_buf )[aOffs + aLen - 1] & 0x80 )
940 for(
unsigned n = 0; n < aLen; n++ )
943 l |= ( *m_buf )[aOffs + aLen - n - 1];
946 return static_cast<int32_t
>( l );
954 return ( ( *
m_buf )[aOffs] & aMask ) != 0;
960 unsigned first = ( aField >> 8 ) & 0xff;
961 unsigned last = aField & 0xff;
962 uint32_t mask = ( 1u << ( last - first + 1 ) ) - 1;
966 uint32_t val =
loadU32( aOffs, ( aField >> 16 ) & 0xff ) >> first;
976 const char* start =
reinterpret_cast<const char*
>(
m_buf->data() + aOffs );
982 while( n < aLen && start[n] !=
'\0' )
985 return wxString::FromUTF8( start, n );
991 static_assert(
sizeof( double ) == 8,
"Eagle binary doubles are 8-byte IEEE-754" );
1000 for(
unsigned n = 0; n <
sizeof( double ); n++ )
1001 bits |=
static_cast<uint64_t
>( ( *
m_buf )[aOffs + n] ) << ( 8 * n );
1004 memcpy( &d, &bits,
sizeof( d ) );
1023 THROW_IO_ERROR(
_(
"Short read in Eagle binary file (truncated block)." ) );
1025 size_t blockStart =
m_pos;
1031 if( aNumBlocks < 0 && ( *
m_buf )[blockStart] == 0x10 )
1032 aNumBlocks =
loadS32( blockStart + 4, 4 );
1034 const SCRIPT_ROW* sc =
nullptr;
1036 for(
const SCRIPT_ROW* row = g_script; row->cmd != 0; row++ )
1038 unsigned cmdh = ( row->cmd >> 8 ) & 0xFF;
1039 unsigned cmdl = row->cmd & 0xFF;
1040 unsigned mskh = ( row->cmdMask >> 8 ) & 0xFF;
1041 unsigned mskl = row->cmdMask & 0xFF;
1043 if( ( cmdh != ( ( *
m_buf )[blockStart] & mskh ) ) || ( cmdl != ( ( *
m_buf )[blockStart + 1] & mskl ) ) )
1050 for(
const FMATCH* fm = row->fmatch; fm->offs != 0; fm++ )
1052 if(
loadS32( blockStart + fm->offs, fm->len ) != fm->val )
1065 if(
m_majorVer > 3 && isV3InlineNamePadRow( row ) )
1075 THROW_IO_ERRORF(
_(
"Unknown Eagle binary block id 0x%02x%02x at offset %zu." ),
1076 (
unsigned) ( *
m_buf )[blockStart],
1077 (
unsigned) ( *
m_buf )[blockStart + 1],
1082 sc->name ? wxString::FromUTF8( sc->name ) : wxString( wxS(
"UNKNOWN" ) ) );
1084 for(
const ATTR* at = sc->attrs; at->name !=
nullptr; at++ )
1092 case T_BMB: val =
loadBmb( blockStart + at->offs, at->len ) ? wxS(
"yes" ) : wxS(
"no" );
break;
1093 case T_UBF: val = wxString::Format( wxS(
"%u" ),
loadUbf( blockStart + at->offs, at->len ) );
break;
1094 case T_INT: val = wxString::Format( wxS(
"%d" ),
loadS32( blockStart + at->offs, at->len ) );
break;
1095 case T_UINT: val = wxString::Format( wxS(
"%u" ),
loadU32( blockStart + at->offs, at->len ) );
break;
1096 case T_DBL: val = wxString::FromCDouble(
loadDouble( blockStart + at->offs ) );
break;
1099 size_t foff = blockStart + at->offs;
1100 val =
loadStr( foff, at->len );
1105 if( foff + 5 <=
m_buf->size() && ( *
m_buf )[foff] == 0x7F )
1106 m_longRefs.push_back( { node, wxString::FromUTF8( at->name ),
loadU32( foff + 1, 4 ) } );
1112 node->
props[wxString::FromUTF8( at->name )] = val;
1117 for(
const SUBSECT* ss = sc->subs; ss->offs != 0; ss++ )
1119 uint32_t numch =
loadU32( blockStart + ss->offs, ss->len );
1122 if( ss->treeName !=
nullptr )
1123 lpar = node->
AddChild( 0, wxString::FromUTF8( ss->treeName ) );
1125 if( ss->ssType == SS_DIRECT )
1127 for( uint32_t n = 0; n < numch && aNumBlocks > 0; n++ )
1139 if( ss->ssType == SS_RECURSIVE_MINUS_1 && numch > 0 )
1144 for( uint32_t n = 0; n < numch && rem > 0; n++ )
1180 size_t total =
static_cast<size_t>( textLen ) + 4;
1188 size_t blobStart =
m_pos;
1194 while( cur <
end && ( *
m_buf )[cur] !=
'\0' )
1198 while( cur <
end && ( *
m_buf )[cur] !=
'\0' )
1201 wxString str = wxString::FromUTF8(
reinterpret_cast<const char*
>(
m_buf->data() + s ),
1217 wxLogTrace(
traceEagleIo, wxS(
"Eagle bin: free-text reference out of strings" ) );
1235 std::vector<bool> done(
m_longRefs.size(),
false );
1236 std::vector<wxString> value(
m_longRefs.size() );
1240 std::map<long long, int> votes;
1242 for(
size_t i = 0; i <
m_longRefs.size(); i++ )
1252 votes[
static_cast<long long>(
m_longRefs[i].ptr ) -
static_cast<long long>( offset )]++;
1256 long long base = -1;
1259 for(
const auto& [cand, count] : votes )
1273 for(
size_t i = 0; i <
m_longRefs.size(); i++ )
1279 static_cast<size_t>(
static_cast<long long>(
m_longRefs[i].ptr ) - base ) );
1283 value[i] = it->second;
1296 bool allResolved = std::all_of( done.begin(), done.end(), [](
bool d ) { return d; } );
1300 for(
size_t i = 0; i <
m_longRefs.size(); i++ )
1329 uint8_t c = ( *m_buf )[
m_pos++];
1346 const size_t kDrcLen = 244;
1353 auto mil = [&](
size_t aOffs ) ->
long
1355 return static_cast<long>(
loadS32( b + aOffs, 4 ) / 2.54 / 100 );
1371 auto it = aNode->
props.find( aField );
1373 if( it == aNode->
props.end() || it->second.IsEmpty() )
1380 if( it->second[0].GetValue() == 0x7F )
1387 auto fixThreeByte = [](
long num,
bool neg ) ->
long
1389 if( num < 0 && neg )
1391 else if( num > 0 && neg )
1392 return num - 0x800000;
1393 else if( num < 0 && !neg )
1394 return num + 0x800000;
1399 auto setLong = [&](
const wxString& aKey,
long aVal )
1401 aElem->
props[aKey] = wxString::Format( wxS(
"%ld" ), aVal );
1407 auto interpolate = []( int64_t aNumerator, int64_t aSpan, int64_t aDivisor, int64_t aOffset ) ->
long
1409 return static_cast<long>( aNumerator * aSpan / aDivisor + aOffset );
1412 if( aLineType == 129 || aArcType == 0 )
1414 long arcFlags = aElem->
PropLong( wxS(
"arc_negflags" ) );
1415 long x1 = fixThreeByte( aElem->
PropLong( wxS(
"arc_x1" ) ), arcFlags & 0x02 );
1416 long y1 = fixThreeByte( aElem->
PropLong( wxS(
"arc_y1" ) ), arcFlags & 0x04 );
1417 long x2 = fixThreeByte( aElem->
PropLong( wxS(
"arc_x2" ) ), arcFlags & 0x08 );
1418 long y2 = fixThreeByte( aElem->
PropLong( wxS(
"arc_y2" ) ), arcFlags & 0x10 );
1426 long c = ( aElem->
PropLong( wxS(
"arc_c1" ) ) & 0xFF )
1427 | ( ( aElem->
PropLong( wxS(
"arc_c2" ) ) & 0xFF ) << 8 )
1428 | ( ( aElem->
PropLong( wxS(
"arc_c3" ) ) & 0xFF ) << 16 );
1433 c = fixThreeByte( c, arcFlags & 0x01 );
1435 setLong( wxS(
"x1" ), x1 );
1436 setLong( wxS(
"y1" ), y1 );
1437 setLong( wxS(
"x2" ), x2 );
1438 setLong( wxS(
"y2" ), y2 );
1440 long x3 = ( x1 + x2 ) / 2;
1441 long y3 = ( y1 + y2 ) / 2;
1442 long cx = 0, cy = 0;
1444 if( x1 == x2 && y1 == y2 )
1454 cy = interpolate( x3 - cx, x2 - x1, y2 - y1, y3 );
1459 cx = interpolate( y3 - cy, y2 - y1, x2 - x1, x3 );
1462 long radius =
static_cast<long>( std::hypot( cx - x2, cy - y2 ) );
1463 setLong( wxS(
"radius" ),
radius );
1464 setLong( wxS(
"x" ), cx );
1465 setLong( wxS(
"y" ), cy );
1467 if( cx == x2 && cy == y1 && x2 < x1 && y2 > y1 )
1469 aElem->
props[wxS(
"StartAngle" )] = wxS(
"90" );
1470 aElem->
props[wxS(
"Delta" )] = wxS(
"90" );
1472 else if( cx == x1 && cy == y2 && x2 < x1 && y1 > y2 )
1474 aElem->
props[wxS(
"StartAngle" )] = wxS(
"0" );
1475 aElem->
props[wxS(
"Delta" )] = wxS(
"90" );
1477 else if( cx == x2 && cy == y1 && x2 > x1 && y1 > y2 )
1479 aElem->
props[wxS(
"StartAngle" )] = wxS(
"270" );
1480 aElem->
props[wxS(
"Delta" )] = wxS(
"90" );
1482 else if( cx == x1 && cy == y2 && x2 > x1 && y2 > y1 )
1484 aElem->
props[wxS(
"StartAngle" )] = wxS(
"180" );
1485 aElem->
props[wxS(
"Delta" )] = wxS(
"90" );
1489 double theta1 = 180.0 - 180.0 /
M_PI * atan2( cy - y1, x1 - cx );
1490 double theta2 = 180.0 - 180.0 /
M_PI * atan2( cy - y2, x2 - cx );
1491 double deltaTheta = theta2 - theta1;
1493 while( theta1 > 360 )
1496 while( deltaTheta < -180 )
1499 while( deltaTheta > 180 )
1502 setLong( wxS(
"StartAngle" ),
static_cast<long>( theta1 ) );
1503 setLong( wxS(
"Delta" ),
static_cast<long>( deltaTheta ) );
1506 else if( ( aLineType > 0 && aLineType < 129 ) || aArcType > 0 )
1508 long x1 = 0, y1 = 0, x2 = 0, y2 = 0, cx = 0, cy = 0;
1510 if( aElem->
HasProp( wxS(
"arctype_other_x1" ) ) )
1512 x1 = aElem->
PropLong( wxS(
"arctype_other_x1" ) );
1513 y1 = aElem->
PropLong( wxS(
"arctype_other_y1" ) );
1514 x2 = aElem->
PropLong( wxS(
"arctype_other_x2" ) );
1515 y2 = aElem->
PropLong( wxS(
"arctype_other_y2" ) );
1519 x1 = aElem->
PropLong( wxS(
"linetype_0_x1" ) );
1520 y1 = aElem->
PropLong( wxS(
"linetype_0_y1" ) );
1521 x2 = aElem->
PropLong( wxS(
"linetype_0_x2" ) );
1522 y2 = aElem->
PropLong( wxS(
"linetype_0_y2" ) );
1529 long dir = aElem->
Prop( wxS(
"ccw" ) ) == wxS(
"yes" ) ? 1 : -1;
1531 auto setAngles = [&](
int aStart,
int aDelta )
1533 setLong( wxS(
"StartAngle" ), aStart );
1534 setLong( wxS(
"Delta" ), dir * aDelta );
1537 if( aLineType == 0x78 || aArcType == 0x01 )
1539 cx = std::min( x1, x2 );
1540 cy = std::min( y1, y2 );
1541 setAngles( 180, 90 );
1543 else if( aLineType == 0x79 || aArcType == 0x02 )
1545 cx = std::max( x1, x2 );
1546 cy = std::min( y1, y2 );
1547 setAngles( 270, 90 );
1549 else if( aLineType == 0x7a || aArcType == 0x03 )
1551 cx = std::max( x1, x2 );
1552 cy = std::max( y1, y2 );
1555 else if( aLineType == 0x7b || aArcType == 0x04 )
1557 cx = std::min( x1, x2 );
1558 cy = std::max( y1, y2 );
1559 setAngles( 90, 90 );
1561 else if( aLineType == 0x7c || aArcType == 0x05 )
1563 cx = ( x1 + x2 ) / 2;
1564 cy = ( y1 + y2 ) / 2;
1565 setAngles( 90, 180 );
1567 else if( aLineType == 0x7d || aArcType == 0x06 )
1569 cx = ( x1 + x2 ) / 2;
1570 cy = ( y1 + y2 ) / 2;
1571 setAngles( 270, 180 );
1573 else if( aLineType == 0x7e || aArcType == 0x07 )
1575 cx = ( x1 + x2 ) / 2;
1576 cy = ( y1 + y2 ) / 2;
1577 setAngles( 180, 180 );
1579 else if( aLineType == 0x7f || aArcType == 0x08 )
1581 cx = ( x1 + x2 ) / 2;
1582 cy = ( y1 + y2 ) / 2;
1583 setAngles( 0, 180 );
1593 long radius =
static_cast<long>( std::hypot( cx - x2, cy - y2 ) );
1594 setLong( wxS(
"radius" ),
radius );
1595 setLong( wxS(
"x" ), cx );
1596 setLong( wxS(
"y" ), cy );
1605 int lineType = aRoot->
HasProp( wxS(
"linetype" ) ) ? (int) aRoot->
PropLong( wxS(
"linetype" ) ) : -1;
1611 aRoot->
props[wxS(
"x1" )] = aRoot->
Prop( wxS(
"linetype_0_x1" ) );
1612 aRoot->
props[wxS(
"y1" )] = aRoot->
Prop( wxS(
"linetype_0_y1" ) );
1613 aRoot->
props[wxS(
"x2" )] = aRoot->
Prop( wxS(
"linetype_0_x2" ) );
1614 aRoot->
props[wxS(
"y2" )] = aRoot->
Prop( wxS(
"linetype_0_y2" ) );
1626 if( aRoot->
HasProp( wxS(
"Delta" ) ) && aRoot->
PropLong( wxS(
"Delta" ) ) != 0 )
1627 aRoot->
props[wxS(
"curve" )] = aRoot->
Prop( wxS(
"Delta" ) );
1631 for(
const auto& child : aRoot->
children )
1640 int arcType = aRoot->
HasProp( wxS(
"arctype" ) ) ? (int) aRoot->
PropLong( wxS(
"arctype" ) ) : -1;
1644 aRoot->
props[wxS(
"x1" )] = aRoot->
Prop( wxS(
"arc_x1" ) );
1645 aRoot->
props[wxS(
"y1" )] = aRoot->
Prop( wxS(
"arc_y1" ) );
1646 aRoot->
props[wxS(
"x2" )] = aRoot->
Prop( wxS(
"arc_x2" ) );
1647 aRoot->
props[wxS(
"y2" )] = aRoot->
Prop( wxS(
"arc_y2" ) );
1649 else if( arcType > 0 )
1651 aRoot->
props[wxS(
"x1" )] = aRoot->
Prop( wxS(
"arctype_other_x1" ) );
1652 aRoot->
props[wxS(
"y1" )] = aRoot->
Prop( wxS(
"arctype_other_y1" ) );
1653 aRoot->
props[wxS(
"x2" )] = aRoot->
Prop( wxS(
"arctype_other_x2" ) );
1654 aRoot->
props[wxS(
"y2" )] = aRoot->
Prop( wxS(
"arctype_other_y2" ) );
1664 if( aRoot->
HasProp( wxS(
"Delta" ) ) && aRoot->
PropLong( wxS(
"Delta" ) ) != 0 )
1665 aRoot->
props[wxS(
"curve" )] = aRoot->
Prop( wxS(
"Delta" ) );
1668 for(
const auto& child : aRoot->
children )
1682 std::vector<std::unique_ptr<EGB_NODE>> rebuilt;
1684 for(
auto& child : aRoot->
children )
1688 rebuilt.push_back( std::move( child ) );
1692 auto vertex = std::make_unique<EGB_NODE>();
1693 vertex->name = wxS(
"vertex" );
1694 vertex->parent = aRoot;
1695 vertex->
props[wxS(
"x" )] = child->Prop( wxS(
"x1" ) );
1696 vertex->props[wxS(
"y" )] = child->Prop( wxS(
"y1" ) );
1698 if( child->HasProp( wxS(
"curve" ) ) )
1699 vertex->props[wxS(
"curve" )] = child->Prop( wxS(
"curve" ) );
1701 rebuilt.push_back( std::move( vertex ) );
1704 aRoot->
children = std::move( rebuilt );
1707 for(
const auto& child : aRoot->
children )
1719 aRoot->
props[wxS(
"extent" )] = wxS(
"1-16" );
1722 for(
const auto& child : aRoot->
children )
1733 static const wxString dimAttrs[] = { wxS(
"x" ), wxS(
"y" ), wxS(
"x1" ), wxS(
"y1" ),
1734 wxS(
"x2" ), wxS(
"y2" ), wxS(
"x3" ), wxS(
"y3" ),
1735 wxS(
"width" ), wxS(
"drill" ), wxS(
"diameter" ), wxS(
"radius" ),
1736 wxS(
"size" ), wxS(
"dx" ), wxS(
"dy" ), wxS(
"spacing" ),
1739 for(
const wxString& key : dimAttrs )
1741 auto it = aRoot->
props.find( key );
1743 if( it == aRoot->
props.end() )
1748 if( it->second.ToCDouble( &du ) )
1749 it->second = wxString::FromCDouble( du * 0.0001, 4 );
1752 for(
const auto& child : aRoot->
children )
1764 for(
const auto& child : aRoot->
children )
1773 if( aRoot->
HasProp( wxS(
"half_dx" ) ) )
1778 if( aRoot->
HasProp( wxS(
"half_dy" ) ) )
1784 for(
const auto& child : aRoot->
children )
1800 static const std::map<long, wxString> names = {
1801 { 0, wxS(
"square" ) }, { 1, wxS(
"round" ) }, { 2, wxS(
"octagon" ) },
1802 { 3, wxS(
"long" ) }, { 4, wxS(
"offset" ) } };
1804 auto it = names.find( aRoot->
PropLong( wxS(
"shape" ) ) );
1806 if( it != names.end() )
1807 aRoot->
props[wxS(
"shape" )] = it->second;
1809 aRoot->
props.erase( wxS(
"shape" ) );
1812 for(
const auto& child : aRoot->
children )
1822 if( aRoot->
HasProp( wxS(
"half_drill" ) ) )
1827 if( aRoot->
HasProp( wxS(
"half_diameter" ) ) )
1829 aRoot->
props[wxS(
"diameter" )] = aRoot->
PropDoubled( wxS(
"half_diameter" ) );
1832 if( aRoot->
HasProp( wxS(
"half_size" ) ) )
1838 for(
const auto& child : aRoot->
children )
1861 default:
return false;
1873 auto flagSet = [&](
const wxString& aKey )
1878 const wxString v = aRoot->
Prop( aKey );
1879 return v != wxS(
"no" ) && v != wxS(
"0" );
1882 bool mirrored = flagSet( wxS(
"mirrored" ) );
1883 bool spin = flagSet( wxS(
"spin" ) );
1885 long deg = aRoot->
PropLong( wxS(
"bin_rot" ) );
1894 degrees = ( deg & 0x3 ) * 90.0;
1896 degrees = 360.0 * ( deg & 0x0FFF ) / 4096.0;
1906 rot << wxS(
"R" ) << wxString::FromCDouble( degrees, 4 );
1908 aRoot->
props[wxS(
"rot" )] = rot;
1911 for(
const auto& child : aRoot->
children )
1922 static const wxString c_length[] = { wxS(
"point" ), wxS(
"short" ), wxS(
"middle" ), wxS(
"long" ) };
1923 static const wxString c_direction[] = { wxS(
"nc" ), wxS(
"in" ), wxS(
"out" ), wxS(
"io" ), wxS(
"oc" ),
1924 wxS(
"pwr" ), wxS(
"pas" ), wxS(
"hiz" ), wxS(
"sup" ) };
1925 static const wxString c_visible[] = { wxS(
"off" ), wxS(
"pad" ), wxS(
"pin" ), wxS(
"both" ) };
1926 static const wxString c_function[] = { wxS(
"none" ), wxS(
"dot" ), wxS(
"clk" ), wxS(
"dotclk" ) };
1928 auto mapField = [&](
EGB_NODE* aNode,
const wxString& aKey,
const wxString* aTable,
size_t aCount )
1933 long idx = aNode->
PropLong( aKey );
1935 if( idx >= 0 && idx < (
long) aCount )
1936 aNode->
props[aKey] = aTable[idx];
1945 mapField( aNode, wxS(
"length" ), c_length,
sizeof( c_length ) /
sizeof( c_length[0] ) );
1946 mapField( aNode, wxS(
"direction" ), c_direction,
sizeof( c_direction ) /
sizeof( c_direction[0] ) );
1947 mapField( aNode, wxS(
"visible" ), c_visible,
sizeof( c_visible ) /
sizeof( c_visible[0] ) );
1948 mapField( aNode, wxS(
"function" ), c_function,
sizeof( c_function ) /
sizeof( c_function[0] ) );
2018 for(
const auto& child : aRoot->
children )
2035 default:
return false;
2048 std::vector<std::unique_ptr<EGB_NODE>> kept;
2051 for(
auto& child : aRoot->
children )
2055 if( eligible !=
nullptr )
2056 eligible->
props[wxS(
"textfield" )] = child->Prop( wxS(
"textfield" ) );
2062 kept.push_back( std::move( child ) );
2063 eligible = ( kept.back()->HasProp( wxS(
"textfield" ) ) &&
isLongTextHost( kept.back()->id ) )
2068 aRoot->
children = std::move( kept );
2070 for(
const auto& child : aRoot->
children )
2080 aRoot->
content = aRoot->
Prop( wxS(
"textfield" ) );
2082 for(
const auto& child : aRoot->
children )
2091 std::vector<std::unique_ptr<EGB_NODE>> kept;
2093 for(
auto& child : aDrawing->
children )
2099 if( child->HasProp( wxS(
"visible" ) ) )
2101 child->props[wxS(
"visible" )] = child->PropLong( wxS(
"visible" ) ) != 0 ? wxS(
"yes" ) : wxS(
"no" );
2104 child->parent = aLayers;
2105 aLayers->
children.push_back( std::move( child ) );
2109 kept.push_back( std::move( child ) );
2113 aDrawing->
children = std::move( kept );
2119 auto addParam = [&](
const wxString& aName,
const wxString& aValue )
2122 p->
props[wxS(
"name" )] = aName;
2123 p->
props[wxS(
"value" )] = aValue;
2126 addParam( wxS(
"mdWireWire" ), wxString::Format( wxS(
"%ldmil" ), aDrc.
mdWireWire ) );
2127 addParam( wxS(
"msWidth" ), wxString::Format( wxS(
"%ldmil" ), aDrc.
msWidth ) );
2128 addParam( wxS(
"rvPadTop" ), wxString::FromCDouble( aDrc.
rvPadTop ) );
2129 addParam( wxS(
"rvPadInner" ), wxString::FromCDouble( aDrc.
rvPadInner ) );
2130 addParam( wxS(
"rvPadBottom" ), wxString::FromCDouble( aDrc.
rvPadBottom ) );
2139 if( aLibraries ==
nullptr )
2145 std::vector<std::unique_ptr<EGB_NODE>> wrapped;
2147 for(
auto& child : aLibraries->
children )
2152 auto lib = std::make_unique<EGB_NODE>();
2154 lib->name = wxS(
"library" );
2155 lib->parent = aLibraries;
2156 child->
parent = lib.get();
2157 lib->
children.push_back( std::move( child ) );
2158 wrapped.push_back( std::move( lib ) );
2161 if( !wrapped.empty() )
2162 aLibraries->
children = std::move( wrapped );
2168 if( aElements ==
nullptr )
2173 for(
auto& el : aElements->
children )
2178 for(
auto& el2 : el->children )
2183 for(
const auto& [key, value] : el2->props )
2185 if( key == wxS(
"name" ) )
2187 if( value == wxS(
"-" ) )
2188 el->props[wxS(
"name" )] = wxS(
"HYPHEN" );
2190 el->props[wxS(
"name" )] = value;
2192 else if( key == wxS(
"value" ) )
2194 el->props[wxS(
"value" )] = value;
2204 if( aLibraries ==
nullptr )
2212 std::map<wxString, int> seenLibs;
2214 for(
size_t li = 0; li < aLibraries->
children.size(); li++ )
2225 wxString libName = pkgs ? pkgs->
Prop( wxS(
"library" ) ) : wxString();
2227 if( libName.IsEmpty() )
2228 libName = wxString::Format( wxS(
"lib%zu" ), li + 1 );
2234 if(
int& libCount = seenLibs[libName]; libCount++ > 0 )
2235 libName = wxString::Format( wxS(
"%s_%d" ), libName, libCount );
2237 lib->
props[wxS(
"name" )] = libName;
2239 if( pkgs ==
nullptr )
2242 std::map<wxString, int> seen;
2244 for(
size_t pi = 0; pi < pkgs->
children.size(); pi++ )
2247 wxString
name = pkg->
Prop( wxS(
"name" ) );
2249 if(
name.IsEmpty() )
2250 name = wxString::Format( wxS(
"pkg%zu" ), pi + 1 );
2254 if(
int& count = seen[
name]; count++ > 0 )
2255 name = wxString::Format( wxS(
"%s_%d" ),
name, count );
2261 if( aElements ==
nullptr )
2264 auto nameByIdx = [&](
EGB_NODE* aParent,
long aIdx ) -> wxString
2266 if( aParent ==
nullptr || aIdx < 1 || aIdx > (
long) aParent->
children.size() )
2269 return aParent->
children[aIdx - 1]->Prop( wxS(
"name" ) );
2272 for(
auto& el : aElements->
children )
2277 long libIdx = el->PropLong( wxS(
"library" ) );
2278 EGB_NODE* lib = ( libIdx >= 1 && libIdx <= (long) aLibraries->
children.size() )
2279 ? aLibraries->
children[libIdx - 1].get()
2282 if( lib ==
nullptr )
2285 el->props[wxS(
"library" )] = lib->
Prop( wxS(
"name" ) );
2288 wxString pkgName = nameByIdx( pkgs, el->
PropLong( wxS(
"package" ) ) );
2290 if( !pkgName.IsEmpty() )
2291 el->props[wxS(
"package" )] = pkgName;
2298 if( aSignals ==
nullptr )
2306 for(
size_t i = 0; i < aSignals->
children.size(); i++ )
2313 std::vector<std::unique_ptr<EGB_NODE>> kept;
2314 std::vector<std::unique_ptr<EGB_NODE>> promoted;
2320 inner->parent = aSignals;
2321 promoted.push_back( std::move( inner ) );
2325 kept.push_back( std::move( inner ) );
2333 for(
auto& p : promoted )
2334 aSignals->
children.push_back( std::move( p ) );
2341 if( aSignals ==
nullptr || aElements ==
nullptr || aLibraries ==
nullptr )
2344 auto elemByIdx = [&](
long aIdx ) ->
EGB_NODE*
2346 if( aIdx < 1 || aIdx > (
long) aElements->
children.size() )
2349 return aElements->
children[aIdx - 1].get();
2352 auto libByIdx = [&](
long aIdx ) ->
EGB_NODE*
2354 if( aIdx < 1 || aIdx > (
long) aLibraries->
children.size() )
2357 return aLibraries->
children[aIdx - 1].get();
2362 if( aLib ==
nullptr )
2367 if( pkgs ==
nullptr || aIdx < 1 || aIdx > (
long) pkgs->
children.size() )
2370 return pkgs->
children[aIdx - 1].get();
2373 for(
auto& sig : aSignals->
children )
2377 for(
auto& cr : sig->children )
2382 long partNum = cr->PropLong( wxS(
"partnumber" ) );
2383 EGB_NODE* elem = elemByIdx( partNum );
2385 if( elem ==
nullptr )
2388 cr->props[wxS(
"element" )] = elem->
Prop( wxS(
"name" ) );
2394 if( pkg ==
nullptr )
2396 cr->props[wxS(
"pad" )] = wxS(
"PIN_NOT_FOUND" );
2400 long pinNum = cr->PropLong( wxS(
"pin" ) );
2403 for(
const auto& child : pkg->
children )
2405 int kind = child->id & 0xFF00;
2411 found = child.get();
2417 if( found ==
nullptr )
2418 cr->
props[wxS(
"pad" )] = wxS(
"PIN_NOT_FOUND" );
2419 else if( found->
HasProp( wxS(
"name" ) ) )
2420 cr->props[wxS(
"pad" )] = found->
Prop( wxS(
"name" ) );
2422 cr->props[wxS(
"pad" )] = cr->Prop( wxS(
"pin" ) );
2432 if( drawing ==
nullptr )
2445 if( board !=
nullptr )
2450 if( libraries ==
nullptr )
2451 THROW_IO_ERROR(
_(
"Eagle binary layout is missing a board/libraries node." ) );
2463 if( drcNode !=
nullptr )
2514 std::vector<std::unique_ptr<EGB_NODE>> kept;
2516 for(
auto& child : aRoot->
children )
2521 kept.push_back( std::move( child ) );
2524 aRoot->
children = std::move( kept );
2526 for(
const auto& child : aRoot->
children )
2533 wxXmlNode* xml =
new wxXmlNode( wxXML_ELEMENT_NODE, aNode->
name );
2535 for(
const auto& [key, value] : aNode->
props )
2536 xml->AddAttribute( key, value );
2538 if( !aNode->
content.IsEmpty() )
2539 xml->AddChild(
new wxXmlNode( wxXML_TEXT_NODE, wxEmptyString, aNode->
content ) );
2543 for(
const auto& child : aNode->
children )
2544 xml->AddChild(
toXml( child.get() ) );
2556 if( aBytes.size() < 24 )
2557 THROW_IO_ERROR(
_(
"File is too small to be an Eagle binary board." ) );
2564 m_root = std::make_unique<EGB_NODE>();
2566 m_root->name = wxS(
"eagle" );
2568 long numBlocks = -1;
2579 if( drawing !=
nullptr )
2581 long v1 = drawing->
HasProp( wxS(
"v1" ) ) ? drawing->
PropLong( wxS(
"v1" ) ) : 5;
2582 long v2 = drawing->
HasProp( wxS(
"v2" ) ) ? drawing->
PropLong( wxS(
"v2" ) ) : 0;
2583 m_root->props[wxS(
"version" )] = wxString::Format( wxS(
"%ld.%ld" ),
v1,
v2 );
2609 auto doc = std::make_unique<wxXmlDocument>();
2621 if( drawing ==
nullptr )
2622 THROW_IO_ERROR(
_(
"Eagle binary schematic has no drawing section." ) );
2626 if( schematic ==
nullptr )
2630 schematic->name = wxS(
"schematic" );
2660std::vector<EAGLE_BIN_PARSER::EGB_NODE*>
2663 std::vector<EGB_NODE*> out;
2665 if( aParent !=
nullptr )
2667 for(
const auto& child : aParent->
children )
2669 if( child->id == aChildId )
2670 out.push_back( child.get() );
2681 if( aIdx >= 1 && aIdx <= (
long) aList.size() )
2682 return aList[aIdx - 1]->Prop( wxS(
"name" ) );
2698 aNode->
props[wxS(
"columns" )] = aNode->
Prop( wxS(
"cols" ) );
2714 aNode->
props[wxS(
"name" )] = aNode->
HasProp( wxS(
"textfield" ) )
2715 ? aNode->
Prop( wxS(
"textfield" ) )
2732 if( aNode->
HasProp( wxS(
"half_size" ) ) )
2733 sizeKey = wxS(
"half_size" );
2734 else if( aNode->
HasProp( wxS(
"size" ) ) )
2735 sizeKey = wxS(
"size" );
2737 if( !sizeKey.IsEmpty() && aNode->
PropLong( sizeKey ) >= 0 )
2765 if( aNode->
name == wxS(
"variants" ) )
2766 aNode->
name = wxS(
"devices" );
2774std::vector<EAGLE_BIN_PARSER::EGB_NODE*>
2777 auto wrapChildren = [](
EGB_NODE* aParent,
const wxString& aContainer,
2780 std::vector<std::unique_ptr<EGB_NODE>> kept;
2781 std::vector<std::unique_ptr<EGB_NODE>>
moved;
2783 for(
auto& child : aParent->
children )
2785 if( aPred( child.get() ) )
2786 moved.push_back( std::move( child ) );
2788 kept.push_back( std::move( child ) );
2791 aParent->
children = std::move( kept );
2798 for(
auto& node :
moved )
2808 wrapChildren( aSchematic, wxS(
"libraries" ),
2816 for(
size_t li = 0; li < libList.size(); li++ )
2829 libName = n->
Prop( wxS(
"library" ) );
2834 if( libName.IsEmpty() )
2835 libName = wxString::Format( wxS(
"lib%zu" ), li + 1 );
2837 lib->
props[wxS(
"name" )] = libName;
2843 [](
const std::unique_ptr<EGB_NODE>& n )
2844 { return n->id == EGKW_SECT_PACKAGES; } ),
2852 std::map<wxString, int> dsSeen;
2854 for(
size_t di = 0; di < devicesetList.size(); di++ )
2857 wxString
name = ds->
Prop( wxS(
"name" ) );
2859 if(
name.IsEmpty() )
2860 name = wxString::Format( wxS(
"dset%zu" ), di + 1 );
2862 if(
int& count = dsSeen[
name]; count++ > 0 )
2863 name = wxString::Format( wxS(
"%s_%d" ),
name, count );
2870 gate->
props[wxS(
"symbol" )] =
nameByOrdinal( symbols, gate->PropLong( wxS(
"symno" ) ) );
2879 const std::vector<EGB_NODE*>& aLibList )
2881 auto adopt = [](
EGB_NODE* aParent,
EGB_NODE*& aSlot,
const wxString& aName,
2882 std::unique_ptr<EGB_NODE> aNode )
2884 if( aSlot ==
nullptr )
2885 aSlot = aParent->
AddChild( 0, aName );
2895 std::vector<std::unique_ptr<EGB_NODE>> flat = std::move( aSchematic->
children );
2898 std::vector<std::unique_ptr<EGB_NODE>> sheetNodes;
2899 std::vector<std::unique_ptr<EGB_NODE>> globalParts;
2900 std::map<wxString, bool> seenPart;
2909 for(
auto& node : flat )
2912 if( node->name == wxS(
"libraries" ) )
2914 aSchematic->
children.push_back( std::move( node ) );
2923 curSheet = node.get();
2924 curPlain = curInstances = curNets = curBusses =
nullptr;
2926 std::vector<std::unique_ptr<EGB_NODE>> drawables = std::move( curSheet->
children );
2929 for(
auto& drawable : drawables )
2930 adopt( curSheet, curPlain, wxS(
"plain" ), std::move( drawable ) );
2932 sheetNodes.push_back( std::move( node ) );
2939 long libno = part->
PropLong( wxS(
"lib" ) );
2940 long devno = part->
PropLong( wxS(
"device" ) );
2941 long varno = part->
PropLong( wxS(
"variant" ) );
2943 EGB_NODE* lib = ( libno >= 1 && libno <= (long) aLibList.size() ) ? aLibList[libno - 1]
2945 std::vector<EGB_NODE*> devicesets =
2948 EGB_NODE* ds = ( devno >= 1 && devno <= (long) devicesets.size() ) ? devicesets[devno - 1]
2950 std::vector<EGB_NODE*> variants =
2953 std::vector<EGB_NODE*> gates =
2957 wxString partName = part->
Prop( wxS(
"name" ) );
2959 part->
props[wxS(
"library" )] = lib ? lib->
Prop( wxS(
"name" ) ) : wxString();
2960 part->
props[wxS(
"deviceset" )] = ds ? ds->
Prop( wxS(
"name" ) ) : wxString();
2966 part->
props.erase( wxS(
"technology" ) );
2969 std::vector<std::unique_ptr<EGB_NODE>> partKept;
2975 partKept.push_back( std::move( sub ) );
2979 sub->props[wxS(
"part" )] = partName;
2980 sub->props[wxS(
"gate" )] =
nameByOrdinal( gates, sub->PropLong( wxS(
"gateno" ) ) );
2981 adopt( curSheet, curInstances, wxS(
"instances" ), std::move( sub ) );
2984 part->
children = std::move( partKept );
2987 if( !seenPart[partName] )
2989 seenPart[partName] =
true;
2990 node->parent = aSchematic;
2991 globalParts.push_back( std::move( node ) );
2999 node->props[wxS(
"class" )] =
3000 node->HasProp( wxS(
"netclass" ) ) ? node->Prop( wxS(
"netclass" ) ) : wxString( wxS(
"0" ) );
3003 seg->name = wxS(
"segment" );
3005 if( curSheet !=
nullptr )
3006 adopt( curSheet, curNets, wxS(
"nets" ), std::move( node ) );
3013 if( curSheet !=
nullptr )
3014 adopt( curSheet, curBusses, wxS(
"busses" ), std::move( node ) );
3022 if( curSheet !=
nullptr )
3023 adopt( curSheet, curPlain, wxS(
"plain" ), std::move( node ) );
3034 for(
auto& sheet : sheetNodes )
3035 sheetsNode->
AdoptChild( std::move( sheet ) );
3039 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
#define THROW_IO_ERRORF(msg,...)
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.