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 const wxFileOffset originalPos = aStream.TellI();
898 if( originalPos == wxInvalidOffset || aStream.SeekI( 0 ) == wxInvalidOffset )
901 aStream.Read( buf, 2 );
902 const size_t bytesRead = aStream.LastRead();
904 if( aStream.SeekI( originalPos ) == wxInvalidOffset || bytesRead != 2 )
907 if( buf[0] == 0x10 && ( buf[1] == 0x00 || buf[1] == 0x80 ) )
916 if(
m_buf ==
nullptr || aOffs >
m_buf->size() || aLen >
m_buf->size() - aOffs )
917 THROW_IO_ERROR(
_(
"Short read in Eagle binary file (field out of bounds)." ) );
927 for(
unsigned n = 0; n < aLen; n++ )
930 l |= ( *m_buf )[aOffs + aLen - n - 1];
943 if( ( *
m_buf )[aOffs + aLen - 1] & 0x80 )
946 for(
unsigned n = 0; n < aLen; n++ )
949 l |= ( *m_buf )[aOffs + aLen - n - 1];
952 return static_cast<int32_t
>( l );
960 return ( ( *
m_buf )[aOffs] & aMask ) != 0;
966 unsigned first = ( aField >> 8 ) & 0xff;
967 unsigned last = aField & 0xff;
968 uint32_t mask = ( 1u << ( last - first + 1 ) ) - 1;
972 uint32_t val =
loadU32( aOffs, ( aField >> 16 ) & 0xff ) >> first;
982 const char* start =
reinterpret_cast<const char*
>(
m_buf->data() + aOffs );
988 while( n < aLen && start[n] !=
'\0' )
991 return wxString::FromUTF8( start, n );
997 static_assert(
sizeof( double ) == 8,
"Eagle binary doubles are 8-byte IEEE-754" );
1006 for(
unsigned n = 0; n <
sizeof( double ); n++ )
1007 bits |=
static_cast<uint64_t
>( ( *
m_buf )[aOffs + n] ) << ( 8 * n );
1010 memcpy( &d, &bits,
sizeof( d ) );
1029 THROW_IO_ERROR(
_(
"Short read in Eagle binary file (truncated block)." ) );
1031 size_t blockStart =
m_pos;
1037 if( aNumBlocks < 0 && ( *
m_buf )[blockStart] == 0x10 )
1038 aNumBlocks =
loadS32( blockStart + 4, 4 );
1040 const SCRIPT_ROW* sc =
nullptr;
1042 for(
const SCRIPT_ROW* row = g_script; row->cmd != 0; row++ )
1044 unsigned cmdh = ( row->cmd >> 8 ) & 0xFF;
1045 unsigned cmdl = row->cmd & 0xFF;
1046 unsigned mskh = ( row->cmdMask >> 8 ) & 0xFF;
1047 unsigned mskl = row->cmdMask & 0xFF;
1049 if( ( cmdh != ( ( *
m_buf )[blockStart] & mskh ) ) || ( cmdl != ( ( *
m_buf )[blockStart + 1] & mskl ) ) )
1056 for(
const FMATCH* fm = row->fmatch; fm->offs != 0; fm++ )
1058 if(
loadS32( blockStart + fm->offs, fm->len ) != fm->val )
1071 if(
m_majorVer > 3 && isV3InlineNamePadRow( row ) )
1081 THROW_IO_ERRORF(
_(
"Unknown Eagle binary block id 0x%02x%02x at offset %zu." ),
1082 (
unsigned) ( *
m_buf )[blockStart],
1083 (
unsigned) ( *
m_buf )[blockStart + 1],
1088 sc->name ? wxString::FromUTF8( sc->name ) : wxString( wxS(
"UNKNOWN" ) ) );
1090 for(
const ATTR* at = sc->attrs; at->name !=
nullptr; at++ )
1098 case T_BMB: val =
loadBmb( blockStart + at->offs, at->len ) ? wxS(
"yes" ) : wxS(
"no" );
break;
1099 case T_UBF: val = wxString::Format( wxS(
"%u" ),
loadUbf( blockStart + at->offs, at->len ) );
break;
1100 case T_INT: val = wxString::Format( wxS(
"%d" ),
loadS32( blockStart + at->offs, at->len ) );
break;
1101 case T_UINT: val = wxString::Format( wxS(
"%u" ),
loadU32( blockStart + at->offs, at->len ) );
break;
1102 case T_DBL: val = wxString::FromCDouble(
loadDouble( blockStart + at->offs ) );
break;
1105 size_t foff = blockStart + at->offs;
1106 val =
loadStr( foff, at->len );
1111 if( foff + 5 <=
m_buf->size() && ( *
m_buf )[foff] == 0x7F )
1112 m_longRefs.push_back( { node, wxString::FromUTF8( at->name ),
loadU32( foff + 1, 4 ) } );
1118 node->
props[wxString::FromUTF8( at->name )] = val;
1123 for(
const SUBSECT* ss = sc->subs; ss->offs != 0; ss++ )
1125 uint32_t numch =
loadU32( blockStart + ss->offs, ss->len );
1128 if( ss->treeName !=
nullptr )
1129 lpar = node->
AddChild( 0, wxString::FromUTF8( ss->treeName ) );
1131 if( ss->ssType == SS_DIRECT )
1133 for( uint32_t n = 0; n < numch && aNumBlocks > 0; n++ )
1145 if( ss->ssType == SS_RECURSIVE_MINUS_1 && numch > 0 )
1150 for( uint32_t n = 0; n < numch && rem > 0; n++ )
1186 size_t total =
static_cast<size_t>( textLen ) + 4;
1194 size_t blobStart =
m_pos;
1200 while( cur <
end && ( *
m_buf )[cur] !=
'\0' )
1204 while( cur <
end && ( *
m_buf )[cur] !=
'\0' )
1207 wxString str = wxString::FromUTF8(
reinterpret_cast<const char*
>(
m_buf->data() + s ),
1223 wxLogTrace(
traceEagleIo, wxS(
"Eagle bin: free-text reference out of strings" ) );
1241 std::vector<bool> done(
m_longRefs.size(),
false );
1242 std::vector<wxString> value(
m_longRefs.size() );
1246 std::map<long long, int> votes;
1248 for(
size_t i = 0; i <
m_longRefs.size(); i++ )
1258 votes[
static_cast<long long>(
m_longRefs[i].ptr ) -
static_cast<long long>( offset )]++;
1262 long long base = -1;
1265 for(
const auto& [cand, count] : votes )
1279 for(
size_t i = 0; i <
m_longRefs.size(); i++ )
1285 static_cast<size_t>(
static_cast<long long>(
m_longRefs[i].ptr ) - base ) );
1289 value[i] = it->second;
1302 bool allResolved = std::all_of( done.begin(), done.end(), [](
bool d ) { return d; } );
1306 for(
size_t i = 0; i <
m_longRefs.size(); i++ )
1335 uint8_t c = ( *m_buf )[
m_pos++];
1352 const size_t kDrcLen = 244;
1359 auto mil = [&](
size_t aOffs ) ->
long
1361 return static_cast<long>(
loadS32( b + aOffs, 4 ) / 2.54 / 100 );
1377 auto it = aNode->
props.find( aField );
1379 if( it == aNode->
props.end() || it->second.IsEmpty() )
1386 if( it->second[0].GetValue() == 0x7F )
1393 auto fixThreeByte = [](
long num,
bool neg ) ->
long
1395 if( num < 0 && neg )
1397 else if( num > 0 && neg )
1398 return num - 0x800000;
1399 else if( num < 0 && !neg )
1400 return num + 0x800000;
1405 auto setLong = [&](
const wxString& aKey,
long aVal )
1407 aElem->
props[aKey] = wxString::Format( wxS(
"%ld" ), aVal );
1413 auto interpolate = []( int64_t aNumerator, int64_t aSpan, int64_t aDivisor, int64_t aOffset ) ->
long
1415 return static_cast<long>( aNumerator * aSpan / aDivisor + aOffset );
1418 if( aLineType == 129 || aArcType == 0 )
1420 long arcFlags = aElem->
PropLong( wxS(
"arc_negflags" ) );
1421 long x1 = fixThreeByte( aElem->
PropLong( wxS(
"arc_x1" ) ), arcFlags & 0x02 );
1422 long y1 = fixThreeByte( aElem->
PropLong( wxS(
"arc_y1" ) ), arcFlags & 0x04 );
1423 long x2 = fixThreeByte( aElem->
PropLong( wxS(
"arc_x2" ) ), arcFlags & 0x08 );
1424 long y2 = fixThreeByte( aElem->
PropLong( wxS(
"arc_y2" ) ), arcFlags & 0x10 );
1432 long c = ( aElem->
PropLong( wxS(
"arc_c1" ) ) & 0xFF )
1433 | ( ( aElem->
PropLong( wxS(
"arc_c2" ) ) & 0xFF ) << 8 )
1434 | ( ( aElem->
PropLong( wxS(
"arc_c3" ) ) & 0xFF ) << 16 );
1439 c = fixThreeByte( c, arcFlags & 0x01 );
1441 setLong( wxS(
"x1" ), x1 );
1442 setLong( wxS(
"y1" ), y1 );
1443 setLong( wxS(
"x2" ), x2 );
1444 setLong( wxS(
"y2" ), y2 );
1446 long x3 = ( x1 + x2 ) / 2;
1447 long y3 = ( y1 + y2 ) / 2;
1448 long cx = 0, cy = 0;
1450 if( x1 == x2 && y1 == y2 )
1460 cy = interpolate( x3 - cx, x2 - x1, y2 - y1, y3 );
1465 cx = interpolate( y3 - cy, y2 - y1, x2 - x1, x3 );
1468 long radius =
static_cast<long>( std::hypot( cx - x2, cy - y2 ) );
1469 setLong( wxS(
"radius" ),
radius );
1470 setLong( wxS(
"x" ), cx );
1471 setLong( wxS(
"y" ), cy );
1473 if( cx == x2 && cy == y1 && x2 < x1 && y2 > y1 )
1475 aElem->
props[wxS(
"StartAngle" )] = wxS(
"90" );
1476 aElem->
props[wxS(
"Delta" )] = wxS(
"90" );
1478 else if( cx == x1 && cy == y2 && x2 < x1 && y1 > y2 )
1480 aElem->
props[wxS(
"StartAngle" )] = wxS(
"0" );
1481 aElem->
props[wxS(
"Delta" )] = wxS(
"90" );
1483 else if( cx == x2 && cy == y1 && x2 > x1 && y1 > y2 )
1485 aElem->
props[wxS(
"StartAngle" )] = wxS(
"270" );
1486 aElem->
props[wxS(
"Delta" )] = wxS(
"90" );
1488 else if( cx == x1 && cy == y2 && x2 > x1 && y2 > y1 )
1490 aElem->
props[wxS(
"StartAngle" )] = wxS(
"180" );
1491 aElem->
props[wxS(
"Delta" )] = wxS(
"90" );
1495 double theta1 = 180.0 - 180.0 /
M_PI * atan2( cy - y1, x1 - cx );
1496 double theta2 = 180.0 - 180.0 /
M_PI * atan2( cy - y2, x2 - cx );
1497 double deltaTheta = theta2 - theta1;
1499 while( theta1 > 360 )
1502 while( deltaTheta < -180 )
1505 while( deltaTheta > 180 )
1508 setLong( wxS(
"StartAngle" ),
static_cast<long>( theta1 ) );
1509 setLong( wxS(
"Delta" ),
static_cast<long>( deltaTheta ) );
1512 else if( ( aLineType > 0 && aLineType < 129 ) || aArcType > 0 )
1514 long x1 = 0, y1 = 0, x2 = 0, y2 = 0, cx = 0, cy = 0;
1516 if( aElem->
HasProp( wxS(
"arctype_other_x1" ) ) )
1518 x1 = aElem->
PropLong( wxS(
"arctype_other_x1" ) );
1519 y1 = aElem->
PropLong( wxS(
"arctype_other_y1" ) );
1520 x2 = aElem->
PropLong( wxS(
"arctype_other_x2" ) );
1521 y2 = aElem->
PropLong( wxS(
"arctype_other_y2" ) );
1525 x1 = aElem->
PropLong( wxS(
"linetype_0_x1" ) );
1526 y1 = aElem->
PropLong( wxS(
"linetype_0_y1" ) );
1527 x2 = aElem->
PropLong( wxS(
"linetype_0_x2" ) );
1528 y2 = aElem->
PropLong( wxS(
"linetype_0_y2" ) );
1535 long dir = aElem->
Prop( wxS(
"ccw" ) ) == wxS(
"yes" ) ? 1 : -1;
1537 auto setAngles = [&](
int aStart,
int aDelta )
1539 setLong( wxS(
"StartAngle" ), aStart );
1540 setLong( wxS(
"Delta" ), dir * aDelta );
1543 if( aLineType == 0x78 || aArcType == 0x01 )
1545 cx = std::min( x1, x2 );
1546 cy = std::min( y1, y2 );
1547 setAngles( 180, 90 );
1549 else if( aLineType == 0x79 || aArcType == 0x02 )
1551 cx = std::max( x1, x2 );
1552 cy = std::min( y1, y2 );
1553 setAngles( 270, 90 );
1555 else if( aLineType == 0x7a || aArcType == 0x03 )
1557 cx = std::max( x1, x2 );
1558 cy = std::max( y1, y2 );
1561 else if( aLineType == 0x7b || aArcType == 0x04 )
1563 cx = std::min( x1, x2 );
1564 cy = std::max( y1, y2 );
1565 setAngles( 90, 90 );
1567 else if( aLineType == 0x7c || aArcType == 0x05 )
1569 cx = ( x1 + x2 ) / 2;
1570 cy = ( y1 + y2 ) / 2;
1571 setAngles( 90, 180 );
1573 else if( aLineType == 0x7d || aArcType == 0x06 )
1575 cx = ( x1 + x2 ) / 2;
1576 cy = ( y1 + y2 ) / 2;
1577 setAngles( 270, 180 );
1579 else if( aLineType == 0x7e || aArcType == 0x07 )
1581 cx = ( x1 + x2 ) / 2;
1582 cy = ( y1 + y2 ) / 2;
1583 setAngles( 180, 180 );
1585 else if( aLineType == 0x7f || aArcType == 0x08 )
1587 cx = ( x1 + x2 ) / 2;
1588 cy = ( y1 + y2 ) / 2;
1589 setAngles( 0, 180 );
1599 long radius =
static_cast<long>( std::hypot( cx - x2, cy - y2 ) );
1600 setLong( wxS(
"radius" ),
radius );
1601 setLong( wxS(
"x" ), cx );
1602 setLong( wxS(
"y" ), cy );
1611 int lineType = aRoot->
HasProp( wxS(
"linetype" ) ) ? (int) aRoot->
PropLong( wxS(
"linetype" ) ) : -1;
1617 aRoot->
props[wxS(
"x1" )] = aRoot->
Prop( wxS(
"linetype_0_x1" ) );
1618 aRoot->
props[wxS(
"y1" )] = aRoot->
Prop( wxS(
"linetype_0_y1" ) );
1619 aRoot->
props[wxS(
"x2" )] = aRoot->
Prop( wxS(
"linetype_0_x2" ) );
1620 aRoot->
props[wxS(
"y2" )] = aRoot->
Prop( wxS(
"linetype_0_y2" ) );
1632 if( aRoot->
HasProp( wxS(
"Delta" ) ) && aRoot->
PropLong( wxS(
"Delta" ) ) != 0 )
1633 aRoot->
props[wxS(
"curve" )] = aRoot->
Prop( wxS(
"Delta" ) );
1637 for(
const auto& child : aRoot->
children )
1646 int arcType = aRoot->
HasProp( wxS(
"arctype" ) ) ? (int) aRoot->
PropLong( wxS(
"arctype" ) ) : -1;
1650 aRoot->
props[wxS(
"x1" )] = aRoot->
Prop( wxS(
"arc_x1" ) );
1651 aRoot->
props[wxS(
"y1" )] = aRoot->
Prop( wxS(
"arc_y1" ) );
1652 aRoot->
props[wxS(
"x2" )] = aRoot->
Prop( wxS(
"arc_x2" ) );
1653 aRoot->
props[wxS(
"y2" )] = aRoot->
Prop( wxS(
"arc_y2" ) );
1655 else if( arcType > 0 )
1657 aRoot->
props[wxS(
"x1" )] = aRoot->
Prop( wxS(
"arctype_other_x1" ) );
1658 aRoot->
props[wxS(
"y1" )] = aRoot->
Prop( wxS(
"arctype_other_y1" ) );
1659 aRoot->
props[wxS(
"x2" )] = aRoot->
Prop( wxS(
"arctype_other_x2" ) );
1660 aRoot->
props[wxS(
"y2" )] = aRoot->
Prop( wxS(
"arctype_other_y2" ) );
1670 if( aRoot->
HasProp( wxS(
"Delta" ) ) && aRoot->
PropLong( wxS(
"Delta" ) ) != 0 )
1671 aRoot->
props[wxS(
"curve" )] = aRoot->
Prop( wxS(
"Delta" ) );
1674 for(
const auto& child : aRoot->
children )
1688 std::vector<std::unique_ptr<EGB_NODE>> rebuilt;
1690 for(
auto& child : aRoot->
children )
1694 rebuilt.push_back( std::move( child ) );
1698 auto vertex = std::make_unique<EGB_NODE>();
1699 vertex->name = wxS(
"vertex" );
1700 vertex->parent = aRoot;
1701 vertex->
props[wxS(
"x" )] = child->Prop( wxS(
"x1" ) );
1702 vertex->props[wxS(
"y" )] = child->Prop( wxS(
"y1" ) );
1704 if( child->HasProp( wxS(
"curve" ) ) )
1705 vertex->props[wxS(
"curve" )] = child->Prop( wxS(
"curve" ) );
1707 rebuilt.push_back( std::move( vertex ) );
1710 aRoot->
children = std::move( rebuilt );
1713 for(
const auto& child : aRoot->
children )
1725 aRoot->
props[wxS(
"extent" )] = wxS(
"1-16" );
1728 for(
const auto& child : aRoot->
children )
1739 static const wxString dimAttrs[] = { wxS(
"x" ), wxS(
"y" ), wxS(
"x1" ), wxS(
"y1" ),
1740 wxS(
"x2" ), wxS(
"y2" ), wxS(
"x3" ), wxS(
"y3" ),
1741 wxS(
"width" ), wxS(
"drill" ), wxS(
"diameter" ), wxS(
"radius" ),
1742 wxS(
"size" ), wxS(
"dx" ), wxS(
"dy" ), wxS(
"spacing" ),
1745 for(
const wxString& key : dimAttrs )
1747 auto it = aRoot->
props.find( key );
1749 if( it == aRoot->
props.end() )
1754 if( it->second.ToCDouble( &du ) )
1755 it->second = wxString::FromCDouble( du * 0.0001, 4 );
1758 for(
const auto& child : aRoot->
children )
1770 for(
const auto& child : aRoot->
children )
1779 if( aRoot->
HasProp( wxS(
"half_dx" ) ) )
1784 if( aRoot->
HasProp( wxS(
"half_dy" ) ) )
1790 for(
const auto& child : aRoot->
children )
1806 static const std::map<long, wxString> names = {
1807 { 0, wxS(
"square" ) }, { 1, wxS(
"round" ) }, { 2, wxS(
"octagon" ) },
1808 { 3, wxS(
"long" ) }, { 4, wxS(
"offset" ) } };
1810 auto it = names.find( aRoot->
PropLong( wxS(
"shape" ) ) );
1812 if( it != names.end() )
1813 aRoot->
props[wxS(
"shape" )] = it->second;
1815 aRoot->
props.erase( wxS(
"shape" ) );
1818 for(
const auto& child : aRoot->
children )
1828 if( aRoot->
HasProp( wxS(
"half_drill" ) ) )
1833 if( aRoot->
HasProp( wxS(
"half_diameter" ) ) )
1835 aRoot->
props[wxS(
"diameter" )] = aRoot->
PropDoubled( wxS(
"half_diameter" ) );
1838 if( aRoot->
HasProp( wxS(
"half_size" ) ) )
1844 for(
const auto& child : aRoot->
children )
1867 default:
return false;
1879 auto flagSet = [&](
const wxString& aKey )
1884 const wxString v = aRoot->
Prop( aKey );
1885 return v != wxS(
"no" ) && v != wxS(
"0" );
1888 bool mirrored = flagSet( wxS(
"mirrored" ) );
1889 bool spin = flagSet( wxS(
"spin" ) );
1891 long deg = aRoot->
PropLong( wxS(
"bin_rot" ) );
1900 degrees = ( deg & 0x3 ) * 90.0;
1902 degrees = 360.0 * ( deg & 0x0FFF ) / 4096.0;
1912 rot << wxS(
"R" ) << wxString::FromCDouble( degrees, 4 );
1914 aRoot->
props[wxS(
"rot" )] = rot;
1917 for(
const auto& child : aRoot->
children )
1928 static const wxString c_length[] = { wxS(
"point" ), wxS(
"short" ), wxS(
"middle" ), wxS(
"long" ) };
1929 static const wxString c_direction[] = { wxS(
"nc" ), wxS(
"in" ), wxS(
"out" ), wxS(
"io" ), wxS(
"oc" ),
1930 wxS(
"pwr" ), wxS(
"pas" ), wxS(
"hiz" ), wxS(
"sup" ) };
1931 static const wxString c_visible[] = { wxS(
"off" ), wxS(
"pad" ), wxS(
"pin" ), wxS(
"both" ) };
1932 static const wxString c_function[] = { wxS(
"none" ), wxS(
"dot" ), wxS(
"clk" ), wxS(
"dotclk" ) };
1934 auto mapField = [&](
EGB_NODE* aNode,
const wxString& aKey,
const wxString* aTable,
size_t aCount )
1939 long idx = aNode->
PropLong( aKey );
1941 if( idx >= 0 && idx < (
long) aCount )
1942 aNode->
props[aKey] = aTable[idx];
1951 mapField( aNode, wxS(
"length" ), c_length,
sizeof( c_length ) /
sizeof( c_length[0] ) );
1952 mapField( aNode, wxS(
"direction" ), c_direction,
sizeof( c_direction ) /
sizeof( c_direction[0] ) );
1953 mapField( aNode, wxS(
"visible" ), c_visible,
sizeof( c_visible ) /
sizeof( c_visible[0] ) );
1954 mapField( aNode, wxS(
"function" ), c_function,
sizeof( c_function ) /
sizeof( c_function[0] ) );
2024 for(
const auto& child : aRoot->
children )
2041 default:
return false;
2054 std::vector<std::unique_ptr<EGB_NODE>> kept;
2057 for(
auto& child : aRoot->
children )
2061 if( eligible !=
nullptr )
2062 eligible->
props[wxS(
"textfield" )] = child->Prop( wxS(
"textfield" ) );
2068 kept.push_back( std::move( child ) );
2069 eligible = ( kept.back()->HasProp( wxS(
"textfield" ) ) &&
isLongTextHost( kept.back()->id ) )
2074 aRoot->
children = std::move( kept );
2076 for(
const auto& child : aRoot->
children )
2086 aRoot->
content = aRoot->
Prop( wxS(
"textfield" ) );
2088 for(
const auto& child : aRoot->
children )
2097 std::vector<std::unique_ptr<EGB_NODE>> kept;
2099 for(
auto& child : aDrawing->
children )
2105 if( child->HasProp( wxS(
"visible" ) ) )
2107 child->props[wxS(
"visible" )] = child->PropLong( wxS(
"visible" ) ) != 0 ? wxS(
"yes" ) : wxS(
"no" );
2110 child->parent = aLayers;
2111 aLayers->
children.push_back( std::move( child ) );
2115 kept.push_back( std::move( child ) );
2119 aDrawing->
children = std::move( kept );
2125 auto addParam = [&](
const wxString& aName,
const wxString& aValue )
2128 p->
props[wxS(
"name" )] = aName;
2129 p->
props[wxS(
"value" )] = aValue;
2132 addParam( wxS(
"mdWireWire" ), wxString::Format( wxS(
"%ldmil" ), aDrc.
mdWireWire ) );
2133 addParam( wxS(
"msWidth" ), wxString::Format( wxS(
"%ldmil" ), aDrc.
msWidth ) );
2134 addParam( wxS(
"rvPadTop" ), wxString::FromCDouble( aDrc.
rvPadTop ) );
2135 addParam( wxS(
"rvPadInner" ), wxString::FromCDouble( aDrc.
rvPadInner ) );
2136 addParam( wxS(
"rvPadBottom" ), wxString::FromCDouble( aDrc.
rvPadBottom ) );
2145 if( aLibraries ==
nullptr )
2151 std::vector<std::unique_ptr<EGB_NODE>> wrapped;
2153 for(
auto& child : aLibraries->
children )
2158 auto lib = std::make_unique<EGB_NODE>();
2160 lib->name = wxS(
"library" );
2161 lib->parent = aLibraries;
2162 child->
parent = lib.get();
2163 lib->
children.push_back( std::move( child ) );
2164 wrapped.push_back( std::move( lib ) );
2167 if( !wrapped.empty() )
2168 aLibraries->
children = std::move( wrapped );
2174 if( aElements ==
nullptr )
2179 for(
auto& el : aElements->
children )
2184 for(
auto& el2 : el->children )
2189 for(
const auto& [key, value] : el2->props )
2191 if( key == wxS(
"name" ) )
2193 if( value == wxS(
"-" ) )
2194 el->props[wxS(
"name" )] = wxS(
"HYPHEN" );
2196 el->props[wxS(
"name" )] = value;
2198 else if( key == wxS(
"value" ) )
2200 el->props[wxS(
"value" )] = value;
2210 if( aLibraries ==
nullptr )
2218 std::map<wxString, int> seenLibs;
2220 for(
size_t li = 0; li < aLibraries->
children.size(); li++ )
2231 wxString libName = pkgs ? pkgs->
Prop( wxS(
"library" ) ) : wxString();
2233 if( libName.IsEmpty() )
2234 libName = wxString::Format( wxS(
"lib%zu" ), li + 1 );
2240 if(
int& libCount = seenLibs[libName]; libCount++ > 0 )
2241 libName = wxString::Format( wxS(
"%s_%d" ), libName, libCount );
2243 lib->
props[wxS(
"name" )] = libName;
2245 if( pkgs ==
nullptr )
2248 std::map<wxString, int> seen;
2250 for(
size_t pi = 0; pi < pkgs->
children.size(); pi++ )
2253 wxString
name = pkg->
Prop( wxS(
"name" ) );
2255 if(
name.IsEmpty() )
2256 name = wxString::Format( wxS(
"pkg%zu" ), pi + 1 );
2260 if(
int& count = seen[
name]; count++ > 0 )
2261 name = wxString::Format( wxS(
"%s_%d" ),
name, count );
2267 if( aElements ==
nullptr )
2270 auto nameByIdx = [&](
EGB_NODE* aParent,
long aIdx ) -> wxString
2272 if( aParent ==
nullptr || aIdx < 1 || aIdx > (
long) aParent->
children.size() )
2275 return aParent->
children[aIdx - 1]->Prop( wxS(
"name" ) );
2278 for(
auto& el : aElements->
children )
2283 long libIdx = el->PropLong( wxS(
"library" ) );
2284 EGB_NODE* lib = ( libIdx >= 1 && libIdx <= (long) aLibraries->
children.size() )
2285 ? aLibraries->
children[libIdx - 1].get()
2288 if( lib ==
nullptr )
2291 el->props[wxS(
"library" )] = lib->
Prop( wxS(
"name" ) );
2294 wxString pkgName = nameByIdx( pkgs, el->
PropLong( wxS(
"package" ) ) );
2296 if( !pkgName.IsEmpty() )
2297 el->props[wxS(
"package" )] = pkgName;
2304 if( aSignals ==
nullptr )
2312 for(
size_t i = 0; i < aSignals->
children.size(); i++ )
2319 std::vector<std::unique_ptr<EGB_NODE>> kept;
2320 std::vector<std::unique_ptr<EGB_NODE>> promoted;
2326 inner->parent = aSignals;
2327 promoted.push_back( std::move( inner ) );
2331 kept.push_back( std::move( inner ) );
2339 for(
auto& p : promoted )
2340 aSignals->
children.push_back( std::move( p ) );
2347 if( aSignals ==
nullptr || aElements ==
nullptr || aLibraries ==
nullptr )
2350 auto elemByIdx = [&](
long aIdx ) ->
EGB_NODE*
2352 if( aIdx < 1 || aIdx > (
long) aElements->
children.size() )
2355 return aElements->
children[aIdx - 1].get();
2358 auto libByIdx = [&](
long aIdx ) ->
EGB_NODE*
2360 if( aIdx < 1 || aIdx > (
long) aLibraries->
children.size() )
2363 return aLibraries->
children[aIdx - 1].get();
2368 if( aLib ==
nullptr )
2373 if( pkgs ==
nullptr || aIdx < 1 || aIdx > (
long) pkgs->
children.size() )
2376 return pkgs->
children[aIdx - 1].get();
2379 for(
auto& sig : aSignals->
children )
2383 for(
auto& cr : sig->children )
2388 long partNum = cr->PropLong( wxS(
"partnumber" ) );
2389 EGB_NODE* elem = elemByIdx( partNum );
2391 if( elem ==
nullptr )
2394 cr->props[wxS(
"element" )] = elem->
Prop( wxS(
"name" ) );
2400 if( pkg ==
nullptr )
2402 cr->props[wxS(
"pad" )] = wxS(
"PIN_NOT_FOUND" );
2406 long pinNum = cr->PropLong( wxS(
"pin" ) );
2409 for(
const auto& child : pkg->
children )
2411 int kind = child->id & 0xFF00;
2417 found = child.get();
2423 if( found ==
nullptr )
2424 cr->
props[wxS(
"pad" )] = wxS(
"PIN_NOT_FOUND" );
2425 else if( found->
HasProp( wxS(
"name" ) ) )
2426 cr->props[wxS(
"pad" )] = found->
Prop( wxS(
"name" ) );
2428 cr->props[wxS(
"pad" )] = cr->Prop( wxS(
"pin" ) );
2438 if( drawing ==
nullptr )
2451 if( board !=
nullptr )
2456 if( libraries ==
nullptr )
2457 THROW_IO_ERROR(
_(
"Eagle binary layout is missing a board/libraries node." ) );
2469 if( drcNode !=
nullptr )
2520 std::vector<std::unique_ptr<EGB_NODE>> kept;
2522 for(
auto& child : aRoot->
children )
2527 kept.push_back( std::move( child ) );
2530 aRoot->
children = std::move( kept );
2532 for(
const auto& child : aRoot->
children )
2539 wxXmlNode* xml =
new wxXmlNode( wxXML_ELEMENT_NODE, aNode->
name );
2541 for(
const auto& [key, value] : aNode->
props )
2542 xml->AddAttribute( key, value );
2544 if( !aNode->
content.IsEmpty() )
2545 xml->AddChild(
new wxXmlNode( wxXML_TEXT_NODE, wxEmptyString, aNode->
content ) );
2549 for(
const auto& child : aNode->
children )
2550 xml->AddChild(
toXml( child.get() ) );
2562 if( aBytes.size() < 24 )
2563 THROW_IO_ERROR(
_(
"File is too small to be an Eagle binary board." ) );
2570 m_root = std::make_unique<EGB_NODE>();
2572 m_root->name = wxS(
"eagle" );
2574 long numBlocks = -1;
2585 if( drawing !=
nullptr )
2587 long v1 = drawing->
HasProp( wxS(
"v1" ) ) ? drawing->
PropLong( wxS(
"v1" ) ) : 5;
2588 long v2 = drawing->
HasProp( wxS(
"v2" ) ) ? drawing->
PropLong( wxS(
"v2" ) ) : 0;
2589 m_root->props[wxS(
"version" )] = wxString::Format( wxS(
"%ld.%ld" ),
v1,
v2 );
2615 auto doc = std::make_unique<wxXmlDocument>();
2627 if( drawing ==
nullptr )
2628 THROW_IO_ERROR(
_(
"Eagle binary schematic has no drawing section." ) );
2632 if( schematic ==
nullptr )
2636 schematic->
name = wxS(
"schematic" );
2666std::vector<EAGLE_BIN_PARSER::EGB_NODE*>
2669 std::vector<EGB_NODE*> out;
2671 if( aParent !=
nullptr )
2673 for(
const auto& child : aParent->
children )
2675 if( child->id == aChildId )
2676 out.push_back( child.get() );
2687 if( aIdx >= 1 && aIdx <= (
long) aList.size() )
2688 return aList[aIdx - 1]->Prop( wxS(
"name" ) );
2704 aNode->
props[wxS(
"columns" )] = aNode->
Prop( wxS(
"cols" ) );
2720 aNode->
props[wxS(
"name" )] = aNode->
HasProp( wxS(
"textfield" ) )
2721 ? aNode->
Prop( wxS(
"textfield" ) )
2738 if( aNode->
HasProp( wxS(
"half_size" ) ) )
2739 sizeKey = wxS(
"half_size" );
2740 else if( aNode->
HasProp( wxS(
"size" ) ) )
2741 sizeKey = wxS(
"size" );
2743 if( !sizeKey.IsEmpty() && aNode->
PropLong( sizeKey ) >= 0 )
2771 if( aNode->
name == wxS(
"variants" ) )
2772 aNode->
name = wxS(
"devices" );
2780std::vector<EAGLE_BIN_PARSER::EGB_NODE*>
2783 auto wrapChildren = [](
EGB_NODE* aParent,
const wxString& aContainer,
2786 std::vector<std::unique_ptr<EGB_NODE>> kept;
2787 std::vector<std::unique_ptr<EGB_NODE>>
moved;
2789 for(
auto& child : aParent->
children )
2791 if( aPred( child.get() ) )
2792 moved.push_back( std::move( child ) );
2794 kept.push_back( std::move( child ) );
2797 aParent->
children = std::move( kept );
2804 for(
auto& node :
moved )
2814 wrapChildren( aSchematic, wxS(
"libraries" ),
2822 for(
size_t li = 0; li < libList.size(); li++ )
2835 libName = n->
Prop( wxS(
"library" ) );
2840 if( libName.IsEmpty() )
2841 libName = wxString::Format( wxS(
"lib%zu" ), li + 1 );
2843 lib->
props[wxS(
"name" )] = libName;
2849 [](
const std::unique_ptr<EGB_NODE>& n )
2850 { return n->id == EGKW_SECT_PACKAGES; } ),
2858 std::map<wxString, int> dsSeen;
2860 for(
size_t di = 0; di < devicesetList.size(); di++ )
2863 wxString
name = ds->
Prop( wxS(
"name" ) );
2865 if(
name.IsEmpty() )
2866 name = wxString::Format( wxS(
"dset%zu" ), di + 1 );
2868 if(
int& count = dsSeen[
name]; count++ > 0 )
2869 name = wxString::Format( wxS(
"%s_%d" ),
name, count );
2876 gate->
props[wxS(
"symbol" )] =
nameByOrdinal( symbols, gate->PropLong( wxS(
"symno" ) ) );
2885 const std::vector<EGB_NODE*>& aLibList )
2887 auto adopt = [](
EGB_NODE* aParent,
EGB_NODE*& aSlot,
const wxString& aName,
2888 std::unique_ptr<EGB_NODE> aNode )
2890 if( aSlot ==
nullptr )
2891 aSlot = aParent->
AddChild( 0, aName );
2901 std::vector<std::unique_ptr<EGB_NODE>> flat = std::move( aSchematic->
children );
2904 std::vector<std::unique_ptr<EGB_NODE>> sheetNodes;
2905 std::vector<std::unique_ptr<EGB_NODE>> globalParts;
2906 std::map<wxString, bool> seenPart;
2915 for(
auto& node : flat )
2918 if( node->name == wxS(
"libraries" ) )
2920 aSchematic->
children.push_back( std::move( node ) );
2929 curSheet = node.get();
2930 curPlain = curInstances = curNets = curBusses =
nullptr;
2932 std::vector<std::unique_ptr<EGB_NODE>> drawables = std::move( curSheet->
children );
2936 adopt( curSheet, curPlain, wxS(
"plain" ), std::move(
drawable ) );
2938 sheetNodes.push_back( std::move( node ) );
2945 long libno = part->
PropLong( wxS(
"lib" ) );
2946 long devno = part->
PropLong( wxS(
"device" ) );
2947 long varno = part->
PropLong( wxS(
"variant" ) );
2949 EGB_NODE* lib = ( libno >= 1 && libno <= (long) aLibList.size() ) ? aLibList[libno - 1]
2951 std::vector<EGB_NODE*> devicesets =
2954 EGB_NODE* ds = ( devno >= 1 && devno <= (long) devicesets.size() ) ? devicesets[devno - 1]
2956 std::vector<EGB_NODE*> variants =
2959 std::vector<EGB_NODE*> gates =
2963 wxString partName = part->
Prop( wxS(
"name" ) );
2965 part->
props[wxS(
"library" )] = lib ? lib->
Prop( wxS(
"name" ) ) : wxString();
2966 part->
props[wxS(
"deviceset" )] = ds ? ds->
Prop( wxS(
"name" ) ) : wxString();
2972 part->
props.erase( wxS(
"technology" ) );
2975 std::vector<std::unique_ptr<EGB_NODE>> partKept;
2981 partKept.push_back( std::move( sub ) );
2985 sub->props[wxS(
"part" )] = partName;
2986 sub->props[wxS(
"gate" )] =
nameByOrdinal( gates, sub->PropLong( wxS(
"gateno" ) ) );
2987 adopt( curSheet, curInstances, wxS(
"instances" ), std::move( sub ) );
2990 part->
children = std::move( partKept );
2993 if( !seenPart[partName] )
2995 seenPart[partName] =
true;
2996 node->parent = aSchematic;
2997 globalParts.push_back( std::move( node ) );
3005 node->props[wxS(
"class" )] =
3006 node->HasProp( wxS(
"netclass" ) ) ? node->Prop( wxS(
"netclass" ) ) : wxString( wxS(
"0" ) );
3009 seg->name = wxS(
"segment" );
3011 if( curSheet !=
nullptr )
3012 adopt( curSheet, curNets, wxS(
"nets" ), std::move( node ) );
3019 if( curSheet !=
nullptr )
3020 adopt( curSheet, curBusses, wxS(
"busses" ), std::move( node ) );
3028 if( curSheet !=
nullptr )
3029 adopt( curSheet, curPlain, wxS(
"plain" ), std::move( node ) );
3040 for(
auto& sheet : sheetNodes )
3041 sheetsNode->
AdoptChild( std::move( sheet ) );
3045 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 without changing the stream position.
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.