Index: trunk/src/plugins/io_easyeda/read_hi_pro.c =================================================================== --- trunk/src/plugins/io_easyeda/read_hi_pro.c (revision 10700) +++ trunk/src/plugins/io_easyeda/read_hi_pro.c (nonexistent) @@ -1,1500 +0,0 @@ -/* - * COPYRIGHT - * - * sch-rnd - modular/flexible schematics editor - easyeda file format support - * Copyright (C) 2024 Tibor 'Igor2' Palinkas - * - * (Supported by NLnet NGI0 Entrust Fund in 2024) - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Contact: - * Project page: http://repo.hu/projects/sch-rnd - * contact lead developer: http://www.repo.hu/projects/sch-rnd/contact.html - * mailing list: http://www.repo.hu/projects/sch-rnd/contact.html - */ - -/* high level for the 'std' format - included from read.c */ - -#define REQ_ARGC_(nd, op, num, errstr, errstmt) \ -do { \ - if (nd->type != GDOM_ARRAY) { \ - error_at(ctx, nd, ("%s: object node is not an array\n", errstr)); \ - errstmt; \ - } \ - if (nd->value.array.used op num) { \ - error_at(ctx, nd, ("%s: not enough fields: need at least %ld, got %ld\n", errstr, (long)num, nd->value.array.used)); \ - errstmt; \ - } \ -} while(0) - -#define REQ_ARGC_GTE(nd, num, errstr, errstmt) REQ_ARGC_((nd), <, (num), (errstr), errstmt) -#define REQ_ARGC_EQ(nd, num, errstr, errstmt) REQ_ARGC_((nd), !=, (num), (errstr), errstmt) - -/* call these only after a REQ_ARGC_* as it won't do bound check */ -#define GET_ARG_STR(dst, nd, num, errstr, errstmt) \ -do { \ - gdom_node_t *__tmp__ = nd->value.array.child[num]; \ - if ((__tmp__->type == GDOM_DOUBLE) && (__tmp__->value.dbl == -1)) {\ - dst = NULL; \ - } \ - else { \ - if (__tmp__->type != GDOM_STRING) { \ - error_at(ctx, nd, ("%s: wrong argument type for arg #%ld (expected string)\n", errstr, (long)num)); \ - errstmt; \ - } \ - dst = __tmp__->value.str; \ - } \ -} while(0) - -#define GET_ARG_DBL(dst, nd, num, errstr, errstmt) \ -do { \ - gdom_node_t *__tmp__ = nd->value.array.child[num]; \ - if (__tmp__->type != GDOM_DOUBLE) { \ - error_at(ctx, nd, ("%s: wrong argument type for arg #%ld (expected double)\n", errstr, (long)num)); \ - errstmt; \ - } \ - dst = __tmp__->value.dbl; \ -} while(0) - -#define GET_ARG_HASH(dst, nd, num, errstr, errstmt) \ -do { \ - gdom_node_t *__tmp__ = nd->value.array.child[num]; \ - if (__tmp__->type != GDOM_HASH) { \ - error_at(ctx, nd, ("%s: wrong argument type for arg #%ld; expected a hash\n", errstr, (long)num)); \ - errstmt; \ - } \ - dst = __tmp__; \ -} while(0) - -#define GET_ARG_ARRAY(dst, nd, num, errstr, errstmt) \ -do { \ - gdom_node_t *__tmp__ = nd->value.array.child[num]; \ - if (__tmp__->type != GDOM_ARRAY) { \ - error_at(ctx, nd, ("%s: wrong argument type for arg #%ld; expected an array\n", errstr, (long)num)); \ - errstmt; \ - } \ - dst = __tmp__; \ -} while(0) - -#define CHK_ARG_KW(nd, num, kwval, errstr, errstmt) \ -do { \ - const char *__str__;\ - GET_ARG_STR(__str__, nd, num, errstr, errstmt); \ - if (strcmp(__str__, kwval) != 0) { \ - error_at(ctx, nd, ("%s: arg #%ld must be '%s' but is '%s'\n", errstr, (long)num, kwval, __str__)); \ - errstmt; \ - }\ -} while(0) - -/* Look up style by name and return whether the given style fills */ -static int easypro_style_filled(read_ctx_t *ctx, gdom_node_t *obj, const char *sty) -{ - htsi_entry_t *e = htsi_getentry(&ctx->pro_pen_fill, sty); - if (e == NULL) { - error_at(ctx, obj, ("easypro_style_filled: undefined style '%s'\n", sty)); - return 0; - } - return e->value; -} - -/*** parse obj subtrees (lines in the file) ***/ - -/* Announces a slot (even for single-slot parts); slots are full copies */ -static int easypro_parse_part(read_ctx_t *ctx, gdom_node_t *obj, csch_cgrp_t **parent) -{ - gdom_node_t *bbox, *coords; - REQ_ARGC_GTE(obj, 3, "easypro_parse_part", return -1); - GET_ARG_HASH(bbox, obj, 2, "easypro_parse_part: bbox", return -1); - - ctx->pro_slot++; - if (ctx->pro_symtab != NULL) { /* create a new symbol group for the new part */ - csch_source_arg_t *src; - const char *name; - - GET_ARG_STR(name, obj, 1, "easypro_parse_part: name", return -1); - - *parent = csch_cgrp_alloc(ctx->sheet, &ctx->sheet->direct, csch_oid_new(ctx->sheet, &ctx->sheet->direct)); - src = csch_attrib_src_c(ctx->fn, 0, 0, NULL); /* whole-file context, no need to set location */ - csch_cobj_attrib_set(ctx->sheet, *parent, CSCH_ATP_HARDWIRED, "role", "symbol", src); - - htsp_insert(ctx->pro_symtab, rnd_strdup(name), *parent); - } - else if (ctx->pro_want_slot == -1) { - double x1, y1, x2, y2; - - coords = gdom_hash_get(bbox, easy_BBOX); - if (coords->type != GDOM_ARRAY) { - error_at(ctx, coords, ("PART/BBOX needs to be an array\n")); - return -1; - } - - REQ_ARGC_GTE(coords, 4, "easypro_parse_part PART/BBOX", return -1); - GET_ARG_DBL(x1, coords, 0, "easypro_parse_part PART/BBOX: x1", return -1); - GET_ARG_DBL(y1, coords, 1, "easypro_parse_part PART/BBOX: y1", return -1); - GET_ARG_DBL(x2, coords, 2, "easypro_parse_part PART/BBOX: x2", return -1); - GET_ARG_DBL(y2, coords, 3, "easypro_parse_part PART/BBOX: y2", return -1); - - /* when reading all slots they would badly overlap - shift by bbox */ - if (ctx->pro_slot > 1) - ctx->alien.ox += (x2-x1)*2; - } - else if (ctx->pro_slot > ctx->pro_want_slot) - ctx->pro_stop = 1; /* don't read any more slots */ - - ctx->pro_last = *parent; - return 0; -} - -/* PIN, e19, 1, null, 40, 0, 20, 180, null, 0, 0 - obj ID ? ? x y len rot ? gfx ? - rot: 0 = left *--- (* is the startpoint) - 90 = down - 180 = right ---* - 270 = up - gfx: 2 = "not" (circle r=3 on the start side) -*/ -static int easypro_parse_pin(read_ctx_t *ctx, gdom_node_t *obj, csch_cgrp_t *parent) -{ - double x, y, len, rot, gfx; - double sx, sy, ex, ey, dx = 0, dy = 0; /* start, end, direction */ - int want_circ = 0, gfxi; - static const double notr = 3; - csch_source_arg_t *src; - csch_cgrp_t *term; - - REQ_ARGC_GTE(obj, 11, "easypro_parse_pin", return -1); - - GET_ARG_DBL(x, obj, 4, "easypro_parse_pin: coord x", return -1); - GET_ARG_DBL(y, obj, 5, "easypro_parse_pin: coord y", return -1); - GET_ARG_DBL(len, obj, 6, "easypro_parse_pin: length", return -1); - GET_ARG_DBL(rot, obj, 7, "easypro_parse_pin: rotation", return -1); - GET_ARG_DBL(gfx, obj, 9, "easypro_parse_pin: gfx", return -1); - - /* figure rotation and direction */ - switch((int)rot) { - case 0: dx = +1; break; - case 90: dy = +1; break; - case 180: dx = -1; break; - case 270: dy = -1; break; - default: - error_at(ctx, obj, ("easypro_parse_pin: invalid rotation angle %f\n", rot)); - return -1; - } - - /* figure graphics */ - gfxi = gfx; - if (gfxi & 2) { want_circ = 1; gfxi &= ~2; } - if (gfxi != 0) - error_at(ctx, obj, ("easypro_parse_pin: gfx bits unhandled: %x\n(please report this bug among with the file)\n", gfxi)); - - /* figure endpoints */ - sx = x; sy = y; - ex = sx + dx * len; ey = sy + dy * len; - - if (want_circ) { - ex -= dx * notr*2; - ey -= dy * notr*2; - } - - /* create the pin */ - src = easyeda_attrib_src_c(ctx, obj, NULL); - term = (csch_cgrp_t *)csch_alien_mkpin_line(&ctx->alien, src, parent, sx, sy, ex, ey); - - if (want_circ) - csch_alien_mkarc(&ctx->alien, term, ex+dx*notr, ey+dy*notr, notr, 0, 360, "term-decor"); - - ctx->pro_last = term; - - return 0; -} - - -/* "ATTR", "e51", "", "Device", "", 1, 1, 0, -60, 0, "st1", 0] - kw id ? key val keyvis valvis x y rotdeg pen ? - rotdeg: 0 = horiz - 90 = vert, read from the right -*/ -static int easypro_parse_attr(read_ctx_t *ctx, gdom_node_t *obj, csch_cgrp_t *parent) -{ - csch_source_arg_t *src; - double x, y, rot, kvis, vvis; - const char *key, *val; - - REQ_ARGC_GTE(obj, 12, "easypro_parse_attr", return -1); - - GET_ARG_STR(key, obj, 3, "easypro_parse_attr: key", return -1); - GET_ARG_STR(val, obj, 4, "easypro_parse_attr: val", return -1); - GET_ARG_DBL(kvis, obj, 5, "easypro_parse_attr: key visibility", return -1); - GET_ARG_DBL(vvis, obj, 6, "easypro_parse_attr: value visibility", return -1); - GET_ARG_DBL(x, obj, 7, "easypro_parse_attr: coord x", return -1); - GET_ARG_DBL(y, obj, 8, "easypro_parse_attr: coord y", return -1); - GET_ARG_DBL(rot, obj, 9, "easypro_parse_attr: rotation", return -1); - - if (ctx->pro_last == NULL) { - error_at(ctx, obj, ("easypro_parse_attr: ATTR without previously created group object\n")); - return -1; - } - - - src = easyeda_attrib_src_c(ctx, obj, NULL); - csch_attrib_set(&ctx->pro_last->attr, CSCH_ATP_USER_DEFAULT, key, val, src, NULL); - - /* create a floater if anything is visible */ - if (kvis || vvis) { - const char *penname = DECOR_PEN_NAME(ctx->pro_last); - csch_coord_t tx, ty; - csch_text_t *txt; - g2d_xform_t imx; - - txt = (csch_text_t *)csch_alien_mktext(&ctx->alien, ctx->pro_last, 0, 0, penname); - txt->dyntext = 1; - if (ctx->pro_last->role == CSCH_ROLE_SYMBOL) - txt->hdr.floater = 1; - - if (kvis && vvis) txt->text = rnd_concat(key, "=", "%../a.", key, "%", NULL); - else if (kvis) txt->text = rnd_strdup(key); - else if (vvis) txt->text = rnd_concat("%../a.", key, "%", NULL); - - switch((int)rot) { - case 0: break; - case 90: - case 180: - case 270: - txt->spec_rot = (int)rot; - break; - default: - error_at(ctx, obj, ("easypro_parse_attr: invalid rotation angle %f\n", rot)); - return -1; - } - - /* inverse-transform sheet coords specified in the file to parent group - relative coords that the cschem model requires */ - tx = csch_alien_coord_x(&ctx->alien, x); - ty = csch_alien_coord_y(&ctx->alien, y); - csch_cgrp_inverse_xform(ctx->pro_last, &tx, &ty, 1); - txt->spec1.x = tx; - txt->spec1.y = ty; - txt->spec_rot -= ctx->pro_last->spec_rot; - if (ctx->pro_last->mirx) { - txt->spec_mirx ^= 1; - if ((ctx->pro_last->spec_rot == 90) || (ctx->pro_last->spec_rot == 270)) - txt->spec_rot += 180; - } - } - - return 0; -} - -/* "POLY","e253",[758,10,758,70],false,"st6",0 - kw id coords ? sty ? */ -static int easypro_parse_poly(read_ctx_t *ctx, gdom_node_t *obj, csch_cgrp_t *parent) -{ - const char *penname = DECOR_PEN_NAME(parent), *sty; - gdom_node_t *coords; - double x, y, lx, ly; - long n, v; - csch_chdr_t *poly; - - REQ_ARGC_GTE(obj, 6, "easypro_parse_poly", return -1); - - GET_ARG_ARRAY(coords, obj, 2, "easypro_parse_poly: coords", return -1); - GET_ARG_STR(sty, obj, 4, "easypro_parse_circle: style name", return -1); - - - v = coords->value.array.used; - if (v < 4) { - error_at(ctx, coords, ("easypro_parse_poly: too few coords\n")); - return -1; - } - if ((v % 2) != 0) { - error_at(ctx, coords, ("easypro_parse_poly: odd number of coords\n")); - return -1; - } - - if (v > 4) { - int filled = easypro_style_filled(ctx, obj, sty); - poly = csch_alien_mkpoly(&ctx->alien, parent, penname, filled ? penname : NULL); - } - else - poly = NULL; - - for(n = 0; n < v; n+=2) { - GET_ARG_DBL(x, coords, n, "easypro_parse_poly: coord x", return -1); - GET_ARG_DBL(y, coords, n+1, "easypro_parse_poly: coord y", return -1); - if (n > 0) { - if (poly != NULL) - csch_alien_append_poly_line(&ctx->alien, poly, lx, ly, x, y); - else - csch_alien_mkline(&ctx->alien, parent, lx, ly, x, y, penname); - } - lx = x; - ly = y; - } - - return 0; -} - -/* absolute value of the difference between two angles in radian */ -static double angle_err(double a1, double a2) -{ - /* normalize the angles */ - if (a1 < 0) a1 += M_PI*2; - if (a1 > M_PI*2) a1 -= M_PI*2; - if (a2 < 0) a2 += M_PI*2; - if (a2 > M_PI*2) a2 -= M_PI*2; - - /* now they are in the same range of 0..M_PI*2 */ - return fabs(a1-a2); -} - -/* "ARC","e11", -16.879,0.06024, -12.89446,4.35448, -8.92106,0.04999, "st4", 0 - start x y middle x y end x y linetype */ -static int easypro_parse_arc(read_ctx_t *ctx, gdom_node_t *obj, csch_cgrp_t *parent) -{ - const char *penname = DECOR_PEN_NAME(parent), *sty; - double sx, sy, mx, my, ex, ey; - double sx2, sy2, mx2, my2, ex2, ey2; - double A, B, C, D; - double cx, cy, r, sa, da, ea, ma, da1, da2; - int filled; - - REQ_ARGC_GTE(obj, 10, "easypro_parse_arc", return -1); - - GET_ARG_DBL(sx, obj, 2, "easypro_parse_arc: coord sx", return -1); - GET_ARG_DBL(sy, obj, 3, "easypro_parse_arc: coord sy", return -1); - GET_ARG_DBL(mx, obj, 4, "easypro_parse_arc: coord mx", return -1); - GET_ARG_DBL(my, obj, 5, "easypro_parse_arc: coord my", return -1); - GET_ARG_DBL(ex, obj, 6, "easypro_parse_arc: coord ex", return -1); - GET_ARG_DBL(ey, obj, 7, "easypro_parse_arc: coord ey", return -1); - GET_ARG_STR(sty, obj, 8, "easypro_parse_arc: style name", return -1); - - /* figure the center and radius, see https://math.stackexchange.com/q/4000949 */ - sx2 = sx*sx; sy2 = sy*sy; - mx2 = mx*mx; my2 = my*my; - ex2 = ex*ex; ey2 = ey*ey; - - A = sx*(my-ey) - sy*(mx-ex) + mx*ey - ex*my; - B = (sx2+sy2)*(ey-my) + (mx2+my2)*(sy-ey) + (ex2+ey2)*(my-sy); - C = (sx2+sy2)*(mx-ex) + (mx2+my2)*(ex-sx) + (ex2+ey2)*(sx-mx); - D = (sx2+sy2)*(ex*my-mx*ey) + (mx2+my2)*(sx*ey-ex*sy) + (ex2+ey2)*(mx*sy-sx*my); - - if (A == 0) { - error_at(ctx, obj, ("easypro_parse_arc: the three coords are colinear\n")); - return -1; - } - - cx = -B/(2*A); - cy = -C/(2*A); - r = (B*B+C*C-4*A*D)/(4*A*A); - if (r <= 0) { - error_at(ctx, obj, ("easypro_parse_arc: invalid radius\n")); - return -1; - } - r = sqrt(r); - - /* figure angles */ - sa = atan2(cy - sy, cx - sx); - ma = atan2(cy - my, cx - mx); - ea = atan2(cy - ey, cx - ex); - - da1 = ea - sa; - da2 = sa - ea; - da = (angle_err(ma, sa+da1/2) < angle_err(ma, sa+da2/2)) ? da1 : da2; - - /* convert to deg */ - sa *= RND_RAD_TO_DEG; - da *= RND_RAD_TO_DEG; - - /* y flip */ - sa += 180; - - filled = easypro_style_filled(ctx, obj, sty); - if (filled) { - csch_chdr_t *poly = csch_alien_mkpoly(&ctx->alien, parent, penname, penname); - csch_alien_append_poly_arc(&ctx->alien, poly, cx, cy, r, sa, da); - } - else - csch_alien_mkarc(&ctx->alien, parent, cx, cy, r, sa, da, penname); - - return 0; -} - -/* "CIRCLE", "e42", 40,10, 10, "st5", 0 - x y r sty */ -static int easypro_parse_circle(read_ctx_t *ctx, gdom_node_t *obj, csch_cgrp_t *parent) -{ - const char *penname = DECOR_PEN_NAME(parent), *sty; - double cx, cy, r; - int filled; - - REQ_ARGC_GTE(obj, 7, "easypro_parse_circle", return -1); - - GET_ARG_DBL(cx, obj, 2, "easypro_parse_circle: coord cx", return -1); - GET_ARG_DBL(cy, obj, 3, "easypro_parse_circle: coord cy", return -1); - GET_ARG_DBL(r, obj, 4, "easypro_parse_circle: coord r", return -1); - GET_ARG_STR(sty, obj, 5, "easypro_parse_circle: style name", return -1); - - if (r <= 0) { - error_at(ctx, obj, ("easypro_parse_circle: invalid radius\n")); - return -1; - } - - filled = easypro_style_filled(ctx, obj, sty); - - if (filled) { - csch_chdr_t *poly = csch_alien_mkpoly(&ctx->alien, parent, penname, penname); - csch_alien_append_poly_arc(&ctx->alien, poly, cx, cy, r, 0, 360); - } - else - csch_alien_mkarc(&ctx->alien, parent, cx, cy, r, 0, 360, penname); - - return 0; -} - -/* "ELLIPSE","e43", -10,30, 20,10, 0,"st5",0 - x y rx ,ry ? pen ? */ -static int easypro_parse_ellipse(read_ctx_t *ctx, gdom_node_t *obj, csch_cgrp_t *parent) -{ - const char *penname = DECOR_PEN_NAME(parent), *sty; - double cx, cy, rx, ry, ex, ey; - path_ctx_t pctx; - int filled; - - REQ_ARGC_GTE(obj, 7, "easypro_parse_ellipse", return -1); - - GET_ARG_DBL(cx, obj, 2, "easypro_parse_ellipse: coord cx", return -1); - GET_ARG_DBL(cy, obj, 3, "easypro_parse_ellipse: coord cy", return -1); - GET_ARG_DBL(rx, obj, 4, "easypro_parse_ellipse: coord r", return -1); - GET_ARG_DBL(ry, obj, 5, "easypro_parse_ellipse: coord r", return -1); - GET_ARG_STR(sty, obj, 7, "easypro_parse_ellipse: style name", return -1); - - if ((rx <= 0) || (ry <= 0)) { - error_at(ctx, obj, ("easypro_parse_ellipse: invalid radius\n")); - return -1; - } - - filled = easypro_style_filled(ctx, obj, sty); - - easyeda_svgpath_setup(); - - pctx.ctx = ctx; - pctx.nd = obj; - pctx.penname = penname; - pctx.in_poly = csch_alien_mkpoly(&ctx->alien, parent, penname, filled ? penname : NULL); - pctx.parent = parent; - - ex = cx + rx; - ey = cy; - svgpath_approx_earc(&pathcfg, &pctx, ex, ey, cx, cy, rx, ry, 0, 2*M_PI, 0, ex, ey, pathcfg.curve_approx_seglen*pathcfg.curve_approx_seglen); - - return 0; -} - -/* "RECT","e44", 30,30, 40,20, 0,0, 0,"st5",0 - x1 y1 x2 y2 rx,ry ? pen ? */ -static int easypro_parse_rect(read_ctx_t *ctx, gdom_node_t *obj, csch_cgrp_t *parent) -{ - const char *penname = DECOR_PEN_NAME(parent),*sty; - double x1, y1, x2, y2, rx, ry, r; - int filled; - - REQ_ARGC_GTE(obj, 11, "easypro_parse_rect", return -1); - - GET_ARG_DBL(x1, obj, 2, "easypro_parse_rect: coord x1", return -1); - GET_ARG_DBL(y1, obj, 3, "easypro_parse_rect: coord y1", return -1); - GET_ARG_DBL(x2, obj, 4, "easypro_parse_rect: coord x2", return -1); - GET_ARG_DBL(y2, obj, 5, "easypro_parse_rect: coord y2", return -1); - GET_ARG_DBL(rx, obj, 6, "easypro_parse_rect: coord rx", return -1); - GET_ARG_DBL(ry, obj, 7, "easypro_parse_rect: coord ry", return -1); - GET_ARG_STR(sty, obj, 9, "easypro_parse_rect: style name", return -1); - - if ((rx < 0) || (ry < 0)) { - error_at(ctx, obj, ("easypro_parse_rect: invalid radius\n")); - return -1; - } - - if (x1 > x2) rnd_swap(double, x1, x2); - if (y1 > y2) rnd_swap(double, y1, y2); - - filled = easypro_style_filled(ctx, obj, sty); - - easyeda_svgpath_setup(); - - r = (rx+ry)/2.0; - - parent = (csch_cgrp_t *)csch_alien_mkpoly(&ctx->alien, parent, penname, filled ? penname : NULL); - - if ((r > 0) && (rx != ry)) - error_at(ctx, obj, ("round rect: elliptical rounding not supported, using circular with average radius\n")); - - if (r > 0) csch_alien_append_poly_arc(&ctx->alien, &parent->hdr, x1+r, y1+r, r, -90, -90); - csch_alien_append_poly_line(&ctx->alien, &parent->hdr, x1+r, y1, x2-r, y1); - if (r > 0) csch_alien_append_poly_arc(&ctx->alien, &parent->hdr, x2-r, y1+r, r, 0, -90); - csch_alien_append_poly_line(&ctx->alien, &parent->hdr, x2, y1+r, x2, y2-r); - if (r > 0) csch_alien_append_poly_arc(&ctx->alien, &parent->hdr, x1+r, y2-r, r, 90, +90); - csch_alien_append_poly_line(&ctx->alien, &parent->hdr, x2-r, y2, x1+r, y2); - if (r > 0) csch_alien_append_poly_arc(&ctx->alien, &parent->hdr, x2-r, y2-r, r, 0, +90); - csch_alien_append_poly_line(&ctx->alien, &parent->hdr, x1, y2-r, x1, y1+r); - - return 0; -} - -/* "BEZIER","e41", [-20,10, 0,20, 10,10, 30,20] ,"st5",0 - id start ctrl1 ctrl2 end ? */ -static int easypro_parse_bezier(read_ctx_t *ctx, gdom_node_t *obj, csch_cgrp_t *parent) -{ - const char *penname = DECOR_PEN_NAME(parent), *sty; - double sx, sy, ex, ey, c1x, c1y, c2x, c2y; - path_ctx_t pctx; - gdom_node_t *coords; - int filled; - - REQ_ARGC_GTE(obj, 5, "easypro_parse_bezier", return -1); - - GET_ARG_ARRAY(coords, obj, 2, "easypro_parse_bezier: coords array", return -1); - GET_ARG_STR(sty, obj, 3, "easypro_parse_bezier: style name", return -1); - - REQ_ARGC_GTE(coords, 6, "easypro_parse_bezier: coords", return -1); - GET_ARG_DBL(sx, coords, 0, "easypro_parse_bezier: coord sx", return -1); - GET_ARG_DBL(sy, coords, 1, "easypro_parse_bezier: coord sy", return -1); - GET_ARG_DBL(c1x, coords, 2, "easypro_parse_bezier: coord c1x", return -1); - GET_ARG_DBL(c1y, coords, 3, "easypro_parse_bezier: coord c1y", return -1); - GET_ARG_DBL(c2x, coords, 4, "easypro_parse_bezier: coord c2x", return -1); - GET_ARG_DBL(c2y, coords, 5, "easypro_parse_bezier: coord c2y", return -1); - GET_ARG_DBL(ex, coords, 6, "easypro_parse_bezier: coord ex", return -1); - GET_ARG_DBL(ey, coords, 7, "easypro_parse_bezier: coord ey", return -1); - - filled = easypro_style_filled(ctx, obj, sty); - - easyeda_svgpath_setup(); - - pctx.ctx = ctx; - pctx.nd = coords; - pctx.penname = penname; - pctx.in_poly = csch_alien_mkpoly(&ctx->alien, parent, penname, filled ? penname : NULL); - pctx.parent = parent; - - svgpath_approx_bezier_cubic(&pathcfg, &pctx, sx, sy, c1x, c1y, c2x, c2y, ex, ey, pathcfg.curve_approx_seglen*pathcfg.curve_approx_seglen); - - return 0; -} - -/* "TEXT","e45", -10,-20, 0, "str", "st6",0 - id x y rot pen */ -static int easypro_parse_text(read_ctx_t *ctx, gdom_node_t *obj, csch_cgrp_t *parent) -{ - const char *penname = DECOR_PEN_NAME(parent); - double x, y, rot; - const char *str; - csch_text_t *txt; - int roti; - - REQ_ARGC_GTE(obj, 7, "easypro_parse_text", return -1); - - GET_ARG_DBL(x, obj, 2, "easypro_parse_text: coord x", return -1); - GET_ARG_DBL(y, obj, 3, "easypro_parse_text: coord y", return -1); - GET_ARG_DBL(rot, obj, 4, "easypro_parse_text: coord rot", return -1); - GET_ARG_STR(str, obj, 5, "easypro_parse_attr: text string", return -1); - - roti = rot; - switch(roti) { - case 0: case 90: case 180: case 270: break; - default: - error_at(ctx, obj, ("easypro_parse_text: invalid rotation angle %f\n", rot)); - return -1; - } - - txt = (csch_text_t *)csch_alien_mktext(&ctx->alien, parent, x, y, penname); - txt->text = rnd_strdup(str); - txt->spec_rot = roti; - - return 0; -} - -/* "GROUP",1,0,"border",["e607","e608","e609","e611","e613","e615","e617","e619","e621","e623","e625","e627","e629","e631","e633","e635","e637","e639","e641","e643","e645","e647","e649","e650","e651","e652","e653","e654","e655","e656","e657","e658","e659","e660","e661","e662","e663","e664"] - ? ? ? array of IDs */ -static int easypro_parse_group(read_ctx_t *ctx, gdom_node_t *obj, csch_cgrp_t *parent) -{ -#if 0 - gdom_node_t *ids; - - REQ_ARGC_GTE(obj, 5, "easypro_parse_group", return -1); - GET_ARG_ARRAY(ids, obj, 4, "easypro_parse_group: ids", return -1); - - /* No-op: groups happen within symbols (e.g. A4 frame); actualy grouping - them won't help sym editing and won't make any difference when placed - on a sheet */ -#endif - - return 0; -} - -/* "OBJ","e674","",494,43,155,30,0,0,"data:image/svg+xml;base64,PD94b...==",0 - kw id ? x y w h ? ? image ? */ -static int easypro_parse_obj(read_ctx_t *ctx, gdom_node_t *obj, csch_cgrp_t *parent) -{ - double x, y, w, h; - - REQ_ARGC_GTE(obj, 11, "easypro_parse_obj", return -1); - GET_ARG_DBL(x, obj, 3, "easypro_parse_obj: coord x", return -1); - GET_ARG_DBL(y, obj, 4, "easypro_parse_obj: coord x", return -1); - GET_ARG_DBL(w, obj, 5, "easypro_parse_obj: coord x", return -1); - GET_ARG_DBL(h, obj, 6, "easypro_parse_obj: coord x", return -1); - - easyeda_mkimage_sym(ctx, parent, obj, x, y-h, w, h); - - return 0; -} - -/* "LINESTYLE","st12",null,null,"#99CCFF",null - kw name ? ? fill ? */ -static int easypro_parse_linestyle(read_ctx_t *ctx, gdom_node_t *obj, csch_cgrp_t *parent) -{ - const char *name, *fill; - int is_filled; - - REQ_ARGC_GTE(obj, 6, "easypro_parse_linestyle", return -1); - - GET_ARG_STR(name, obj, 1, "easypro_parse_linestyle: name", return -1); - GET_ARG_STR(fill, obj, 4, "easypro_parse_linestyle: name", return -1); - - is_filled = ((fill != NULL) && (*fill == '#')); - - if (!htsi_has(&ctx->pro_pen_fill, name)) - htsi_insert(&ctx->pro_pen_fill, rnd_strdup(name), is_filled); - else - error_at(ctx, obj, ("easypro_parse_linestyle: style '%s' redefined (ignoring)\n", name)); - - return 0; -} - -/* "COMPONENT","e152","LM358.1",190,360,0, 0, {},0 - kw id symname x y rot mirx ? ? */ -static int easypro_parse_component(read_ctx_t *ctx, gdom_node_t *obj, csch_cgrp_t *parent) -{ - const char *symname; - double x, y, rot, mirx; - const csch_cgrp_t *src; - csch_cgrp_t *dst; - - if (ctx->pro_symtab == NULL) { - error_at(ctx, obj, ("easypro_parse_component: no symtab in context - component within a symbol?!\n")); - return -1; - } - - REQ_ARGC_GTE(obj, 9, "easypro_parse_component", return -1); - - GET_ARG_STR(symname, obj, 2, "easypro_parse_component: symname", return -1); - GET_ARG_DBL(x, obj, 3, "easypro_parse_component: coord x", return -1); - GET_ARG_DBL(y, obj, 4, "easypro_parse_component: coord y", return -1); - GET_ARG_DBL(rot, obj, 5, "easypro_parse_component: rotation", return -1); - GET_ARG_DBL(mirx, obj, 6, "easypro_parse_component: mirror-x", return -1); - - src = htsp_get(ctx->pro_symtab, symname); - if (src == NULL) { - error_at(ctx, obj, ("easypro_parse_component: failed to find symbol '%s' in symtab - not in the project file?\n", symname)); - return -1; - } - - dst = csch_cgrp_dup(ctx->sheet, &ctx->sheet->direct, src, 0); - if (dst == NULL) { - error_at(ctx, obj, ("easypro_parse_component: failed to copy symbol '%s' from the symtab to the sheet\n", symname)); - return -1; - } - dst->x = csch_alien_coord_x(&ctx->alien, x); - dst->y = csch_alien_coord_y(&ctx->alien, y); - dst->spec_rot = rot; - if (mirx) - dst->mirx = 1; - - csch_cgrp_xform_update(ctx->sheet, dst); /* update the matrix so that children attribute transformations are done correctly */ - - ctx->pro_last = dst; - return 0; -} - -/* "WIRE","e1", [[80,65,80,245],[80,245,150,245],[150,245,150,350]] ,"st3",0 - kw id x1 y1 x2 y2 sty ? */ -static int easypro_parse_wire(read_ctx_t *ctx, gdom_node_t *obj, csch_cgrp_t *parent) -{ - gdom_node_t *segs, *coords; - long n; - - REQ_ARGC_GTE(obj, 5, "easypro_parse_wire", return -1); - GET_ARG_ARRAY(segs, obj, 2, "easypro_parse_wire: segments", return -1); - - for(n = 0; n < segs->value.array.used; n++) { - double x1, y1, x2, y2; - - GET_ARG_ARRAY(coords, segs, n, "easypro_parse_wire: coords", return -1); - REQ_ARGC_GTE(coords, 4, "easypro_parse_wire coords", return -1); - - GET_ARG_DBL(x1, coords, 0, "easypro_parse_wire: coord x1", return -1); - GET_ARG_DBL(y1, coords, 1, "easypro_parse_wire: coord y1", return -1); - GET_ARG_DBL(x2, coords, 2, "easypro_parse_wire: coord x2", return -1); - GET_ARG_DBL(y2, coords, 3, "easypro_parse_wire: coord y2", return -1); - - csch_alien_mknet(&ctx->alien, &ctx->sheet->direct, x1, y1, x2, y2); - } - - return 0; -} - -/* object dispatcher */ -static int easypro_parse_any_obj(read_ctx_t *ctx, gdom_node_t *obj, csch_cgrp_t **parent) -{ - char *cmds; - int cmdi; - - REQ_ARGC_GTE(obj, 1, "easypro_parse_obj: need type of the object", return -1); - GET_ARG_STR(cmds, obj, 0, "easypro_parse_obj: first arg must be a string", return -1); - cmdi = easy_sphash(cmds); - - switch(cmdi) { - case easy_PART: return easypro_parse_part(ctx, obj, parent); - case easy_PIN: return easypro_parse_pin(ctx, obj, *parent); - case easy_ATTR: return easypro_parse_attr(ctx, obj, *parent); - case easy_POLY: return easypro_parse_poly(ctx, obj, *parent); - case easy_ARC: return easypro_parse_arc(ctx, obj, *parent); - case easy_CIRCLE: return easypro_parse_circle(ctx, obj, *parent); - case easy_ELLIPSE: return easypro_parse_ellipse(ctx, obj, *parent); - case easy_RECT: return easypro_parse_rect(ctx, obj, *parent); - case easy_BEZIER: return easypro_parse_bezier(ctx, obj, *parent); - case easy_TEXT: return easypro_parse_text(ctx, obj, *parent); - case easy_GROUP: return easypro_parse_group(ctx, obj, *parent); - case easy_OBJ: return easypro_parse_obj(ctx, obj, *parent); - case easy_LINESTYLE: return easypro_parse_linestyle(ctx, obj, *parent); - case easy_COMPONENT: return easypro_parse_component(ctx, obj, *parent); - case easy_WIRE: return easypro_parse_wire(ctx, obj, *parent); - - case easy_FONTSTYLE: return 0; /* ignore: sch-rnd uses pens */ - - case -1: - default: - error_at(ctx, obj, ("easypro_parse_any_obj: unrecognized obj %d '%s'\n", cmdi, cmds)); - return -1; - } - - return -1; /* can't get here */ -} - -/* On success returns start idx within the root array where the first object - node is; on error returns negative */ -static int easypro_verify_header(read_ctx_t *ctx, int is_sym) -{ - gdom_node_t *hdr, *head; - - if (ctx->root->type != GDOM_ARRAY) { - error_at(ctx, ctx->root, ("easypro_verify_header: internal error: root must be an array\n")); - return -1; - } - - if (ctx->root->value.array.used < 2) { - error_at(ctx, ctx->root, ("easypro_verify_header: root must have at least two items (headers)\n")); - return -1; - } - - /* first line: DOCTYPE */ - hdr = ctx->root->value.array.child[0]; - REQ_ARGC_GTE(hdr, 3, "easypro_verify_header: DOCTYPE", return -1); - CHK_ARG_KW(hdr, 0, "DOCTYPE", "easypro_verify_header: DOCTYPE", return -1); - if (is_sym) - CHK_ARG_KW(hdr, 1, "SYMBOL", "easypro_verify_header: DOCTYPE", return -1); - else - CHK_ARG_KW(hdr, 1, "SCH", "easypro_verify_header: DOCTYPE", return -1); - CHK_ARG_KW(hdr, 2, "1.1", "easypro_verify_header: DOCTYPE", return -1); - - /* second line: HEAD */ - hdr = ctx->root->value.array.child[1]; - REQ_ARGC_GTE(hdr, 2, "easypro_verify_header: HEAD", return -1); - CHK_ARG_KW(hdr, 0, "HEAD", "easypro_verify_header: HEAD", return -1); - GET_ARG_HASH(head, hdr, 1, "easypro_verify_header: HEAD", return -1); - - /* second line: HEAD's hash */ - (void)head; - TODO("check if any of these is needed"); - - return 2; -} - -static void easypro_init_ctx(read_ctx_t *ctx) -{ - ctx->pro_last = NULL; - htsi_init(&ctx->pro_pen_fill, strhash, strkeyeq); - - /* for whatever reason symbols seem to be y-mirrored */ - ctx->alien.flip_y = 0; -} - -static void easypro_uninit_ctx(read_ctx_t *ctx) -{ - htsi_entry_t *e; - for(e = htsi_first(&ctx->pro_pen_fill); e != NULL; e = htsi_next(&ctx->pro_pen_fill, e)) - free(e->key); - htsi_uninit(&ctx->pro_pen_fill); - - ctx->alien.flip_y = 1; -} - -/*** glue between the entry below and the actual parser above ***/ - -static int easypro_load_sheet(const char *user_name, const char *fn, csch_sheet_t *sheet, csch_cgrp_t *loclib_sym, htsp_t *symtab) -{ - read_ctx_t ctx = {0}; - csch_source_arg_t *src; - int rv = 0, starti, n; - FILE *f; - - f = rnd_fopen(&sheet->hidlib, fn, "r"); - if (f == NULL) { - rnd_message(RND_MSG_ERROR, "Error loading '%s': failed to open for read\n", fn); - return -1; - } - - ctx.f = f; - ctx.fn = fn; - ctx.sheet = sheet; - ctx.pro_symtab = symtab; - - alien_setup(&ctx); - csch_alien_sheet_setup(&ctx.alien, 1); - easypro_init_ctx(&ctx); - - ctx.root = easypro_low_parse(f); - fclose(f); - - if (ctx.root == NULL) { - rnd_message(RND_MSG_ERROR, "Error loading '%s': low level 'pro' parser failed\n", fn); - return -1; - } - - starti = easypro_verify_header(&ctx, 0); - if (starti < 0) - rv = -1; - - if (rv == 0) { - TODO("copy relevant symbols from symtab to loclib_sym"); - } - - /* parse the data section of the tree */ - if (rv == 0) { - csch_cgrp_t *parent = &sheet->direct; - for(n = starti; !ctx.pro_stop && (rv == 0) && (n < ctx.root->value.array.used); n++) - rv = easypro_parse_any_obj(&ctx, ctx.root->value.array.child[n], &parent); - } - - if (rv == 0) { - csch_cgrp_update(sheet, &sheet->direct, 1); - csch_sheet_bbox_update(sheet); - } - - easypro_uninit_ctx(&ctx); - if (ctx.root != NULL) - gdom_free(ctx.root); - return rv; -} - -/* Load a symbol using ctx into resgrp; if resgrp is NULL, allocate a - new group in sheet */ -static csch_cgrp_t *easypro_load_sym(read_ctx_t *ctx, csch_cgrp_t *resgrp) -{ - csch_source_arg_t *src; - int rv = 0, starti, n, alloced = 0; - - ctx->root = easypro_low_parse(ctx->f); - if (ctx->root == NULL) { - rnd_message(RND_MSG_ERROR, "Error loading '%s': low level 'pro' parser failed\n", ctx->fn); - return NULL; - } - - starti = easypro_verify_header(ctx, 1); - if (starti < 0) - return NULL; - - if (ctx->pro_symtab == NULL) { - /* create the symbol group (if not creating one per PART for a symtab) */ - if (resgrp == NULL) { - resgrp = csch_cgrp_alloc(ctx->sheet, &ctx->sheet->direct, csch_oid_new(ctx->sheet, &ctx->sheet->direct)); - alloced = 1; - } - - src = csch_attrib_src_c(ctx->fn, 0, 0, NULL); /* whole-file context, no need to set location */ - csch_cobj_attrib_set(ctx->sheet, resgrp, CSCH_ATP_HARDWIRED, "role", "symbol", src); - } - - easypro_init_ctx(ctx); - - /* parse the data section of the tree */ - for(n = starti; !ctx->pro_stop && (rv == 0) && (n < ctx->root->value.array.used); n++) - rv = easypro_parse_any_obj(ctx, ctx->root->value.array.child[n], &resgrp); - - if (rv == 0) { - csch_cgrp_update(ctx->sheet, resgrp, 1); - csch_sheet_bbox_update(ctx->sheet); - } - else { - if (alloced) - csch_cgrp_free(resgrp); - resgrp = NULL; - } - - easypro_uninit_ctx(ctx); - - return resgrp; -} - -/* Load a symbol into a group; if existing is NULL, allocate new */ -csch_cgrp_t *io_easypro_load_grp_into(FILE *f, const char *fn, csch_sheet_t *sheet, csch_cgrp_t *existing, int slotno) -{ - read_ctx_t ctx = {0}; - csch_cgrp_t *grp; - - if (htip_get(&sheet->direct.id2obj, 1) != NULL) { - rnd_message(RND_MSG_ERROR, "Error loading '%s': there's already a group1 in destination sheet\n", fn); - return NULL; - } - - ctx.f = f; - ctx.fn = fn; - ctx.sheet = sheet; - ctx.pro_want_slot = slotno; - - alien_setup(&ctx); - - grp = easypro_load_sym(&ctx, existing); - if (io_easyeda_postproc(&ctx, 0) != 0) - rnd_message(RND_MSG_ERROR, "io_easyeda: failed to postprocess newly loaded symbol\n"); - - if (ctx.root != NULL) { - gdom_free(ctx.root); - ctx.root = NULL; - } - - return grp; -} - - -static int easypro_is_file_zip(FILE *f) -{ - char buf[4]; - if (fread(buf, 1, 4, f) != 4) - return 0; - return (buf[0] == 'P') && (buf[1] == 'K') && (buf[2] == 3) && (buf[3] == 4); -} - -/* allocate memory and print a zip command line: first prefix (if not NULL), - then template with %s substituted wuth path */ -static char *easypro_zip_cmd(const char **prefix, const char *template, const char *path) -{ - gds_t tmp = {0}; - const char *s; - - if (prefix != NULL) { - const char **p; - for(p = prefix; *p != NULL; p++) - gds_append_str(&tmp, *p); - } - - for(s = template; *s != '\0'; s++) { - if ((s[0] == '%') && (s[1] == 's')) { - gds_append_str(&tmp, path); - s++; - } - else - gds_append(&tmp, *s); - } - - return tmp.array; -} - -static int easypro_test_parse_sym(FILE *f, const char *fn, const char *fmt, csch_plug_io_type_t type) -{ - char line_[256], *line; - - /* sheets are loaded as bundles from zip */ - if (type == CSCH_IOTYP_SHEET) - return -1; - - /* first line is: ["DOCTYPE","SYMBOL","1.1"] */ - line = fgets(line_, sizeof(line_), f); - if ((line == NULL) || (*line != '[')) - return -1; - - if (strncmp(line+1, "\"DOCTYPE\",", 10) != 0) - return -1; - line += 11; - - if (type == CSCH_IOTYP_GROUP) { - if (strncmp(line, "\"SYMBOL\",", 9) != 0) - return -1; - return 0; - } - - return -1; -} - -static int easypro_test_parse_zip(FILE *f, const char *fn, const char *fmt, csch_plug_io_type_t type, int *is_sym) -{ - int res = -1; - char *cmd; - FILE *fc; - - *is_sym = 0; - - if (!easypro_is_file_zip(f)) - return -1; - - /* get a file list and look for known index files */ - cmd = easypro_zip_cmd(NULL, io_easyeda_conf.plugins.io_easyeda.zip_list_cmd, fn); - fc = rnd_popen(NULL, cmd, "r"); - if (fc != NULL) { - char *line, buf[1024]; - while((line = fgets(buf, sizeof(buf), fc)) != NULL) { - if (strstr(line, "project.json") != NULL) { - res = 0; - break; - } - else if (strstr(line, "device.json") != NULL) { - *is_sym = 1; - res = 0; - break; - } - } - - fclose(fc); - } - free(cmd); - return res; -} - -typedef struct { - const char *fn; - char *dir; - unsigned is_sym:1; - - /* sym load */ - DIR *dr; - char *next_fn; - - /* bundled seet load */ - unsigned sheet_loader_inited:1; - unsigned symsheet_inited:1; - unsigned symtab_inited:1; - vts0_t sheets; /* list of name,filename pairs of all sheets */ - vts0_t syms; /* list of name,filename pairs of all syms */ - int sheet_idx; /* within ->sheets */ - htsp_t symtab; - csch_sheet_t symsheet; -} easypro_bundle_t; - -/* read next dirent and set bnd->next_fn; skip over . and .. and hidden files */ -static struct dirent *easypro_next_de(easypro_bundle_t *bnd) -{ - /* skip over . and .. */ - for(;;) { - struct dirent *de = rnd_readdir(bnd->dr); - if (de == NULL) - return NULL; - if (*de->d_name != '.') { - bnd->next_fn = de->d_name; - return de; - } - } -} - -static int easypro_load_sym_as_sheet(const char *fn, csch_sheet_t *sheet) -{ - FILE *f; - csch_cgrp_t *grp; - - f = rnd_fopen(&sheet->hidlib, fn, "r"); - if (f == NULL) { - rnd_message(RND_MSG_ERROR, "failed to open '%s' for read\n", fn); - return -1; - } - - grp = io_easypro_load_grp_into(f, fn, sheet, &sheet->direct, -1); - fclose(f); - - sch_rnd_sheet_setup(sheet, SCH_RND_SSC_PENS | SCH_RND_SSC_PEN_MARK_DEFAULT, sym_as_sheet_chk_copy_pen, NULL); - sheet->is_symbol = 1; - - return (grp == NULL) ? -1 : 0; -} - -/* read symbols from zip already unpacked into dir; - return 0 (more to read) or 1 (no more sheets to read) or -1 on error */ -static int easypro_load_zip_sym(easypro_bundle_t *bnd, csch_sheet_t *dst) -{ - struct dirent *de; - char *fn; - int res; - - if (bnd->dr == NULL) { - char *fn = rnd_concat(bnd->dir, "/SYMBOL", NULL); - - bnd->dr = rnd_opendir(NULL, fn); - free(fn); - if (bnd->dr == NULL) - return -1; - - de = easypro_next_de(bnd); - if (de == NULL) - return -1; - } - - /* load next symbol */ - fn = rnd_concat(bnd->dir, "/SYMBOL/", bnd->next_fn, NULL); - easypro_load_sym_as_sheet(fn, dst); - free(fn); - - /* figure name of the next symbol and terminate the load if there's no more */ - de = easypro_next_de(bnd); - return (de == NULL) ? 1 : 0; -} - - - -/* read the project file and map sheets and symbols to load */ -static int easypro_load_zip_sheet_init(easypro_bundle_t *bnd, csch_sheet_t *sheet) -{ - char *fn, *sname = NULL; - char *user_name = NULL; /* user readable sheet name or symbol title */ - char *sch_name = NULL; /* user readable sch name */ - njson_sem_ctx_t jctx = {0}; - FILE *f; - enum {M_MISC, M_SCH, M_SYM} main = M_MISC; - int level = 0, c, res = 0, sch_id= -1; - njson_sem_ev_t ev; - - fn = rnd_concat(bnd->dir, "/project.json", NULL); - f = rnd_fopen(&sheet->hidlib, fn, "r"); - if (f == NULL) { - rnd_message(RND_MSG_ERROR, "easypro sheet init: failed to open '%s' for read\n", fn); - free(fn); - return -1; - } - - - /* parse project.json and remember sheets and syms */ - while((c = fgetc(f)) != 0) { - njson_ev_t ev = njson_sem_push(&jctx, c); - - if (ev == NJSON_SEM_EV_eof) break; - if (ev == NJSON_SEM_EV_error) { - rnd_message(RND_MSG_ERROR, "easypro sheet init: project.json parse error: %s at %ld:%ld\n", jctx.njs.error, jctx.njs.lineno, jctx.njs.col); - error:; - res = -1; - break; - } - - switch(ev) { - case NJSON_SEM_EV_more: continue; - case NJSON_SEM_EV_eof: case NJSON_SEM_EV_error: break; /* can't happen */ - case NJSON_SEM_EV_OBJECT_BEGIN: - if (level == 1) { - if (strcmp(jctx.name, "schematics") == 0) main = M_SCH; - else if (strcmp(jctx.name, "symbols") == 0) main = M_SYM; - } - if ((level == 2) && ((main == M_SYM) || (main == M_SCH))) { - if (sname != NULL) free(sname); - sname = rnd_strdup(jctx.name); -/* rnd_trace(" sname: %s\n", jctx.name);*/ - } - case NJSON_SEM_EV_ARRAY_BEGIN: - level++; -/* rnd_trace(" [%d %d] %s\n", level, main, jctx.name);*/ - break; - case NJSON_SEM_EV_OBJECT_END: - case NJSON_SEM_EV_ARRAY_END: - if ((level == 5) && (main == M_SCH)) { /* finished reading a schematic block */ - char *name, *path; -/* rnd_trace("!sch flush! sname=%s uname=%s id=%d\n", sname, user_name, sch_id);*/ - name = rnd_concat(sch_name, "::", user_name, NULL); - path = rnd_strdup_printf("%s/SHEET/%s/%d.esch", bnd->dir, sname, sch_id); - - vts0_append(&bnd->sheets, name); - vts0_append(&bnd->sheets, path); - - if (user_name != NULL) free(user_name); - user_name = NULL; - sch_id = -1; - } - if ((level == 3) && (main == M_SYM)) { /* finished reading a symbol block */ - char *name, *path; -/* rnd_trace("!sym flush! sname=%s title=%s\n", sname, user_name);*/ - name = user_name; - path = rnd_concat(bnd->dir, "/SYMBOL/", sname, ".esym", NULL); - - vts0_append(&bnd->syms, name); - vts0_append(&bnd->syms, path); - - user_name = NULL; /* don't free user_name, ownership is passed to the vector */ - } - level--; - if (level == 1) main = M_MISC; - break; - - case NJSON_SEM_EV_ATOMIC: - switch(main) { - case M_SCH: - if ((level == 3) && (strcmp(jctx.name, "name") == 0)) { - /* remember user-unreadable long uid with use readable name - however, it's not necessarily unique */ - if (jctx.type != NJSON_SEM_TYPE_STRING) { - rnd_message(RND_MSG_ERROR, "easypro sheet init: project.json parse error: sch name must be a string at %ld:%ld\n", jctx.njs.lineno, jctx.njs.col); - goto error; - } - free(sch_name); - sch_name = rnd_strdup(jctx.value.string); - break; - } - - if (level != 5) break; - /* reading items of a schematic block */ -/* rnd_trace(" [%d] sch atom: %s\n", level, jctx.name);*/ - if (strcmp(jctx.name, "id") == 0) { - if (jctx.type != NJSON_SEM_TYPE_NUMBER) { - rnd_message(RND_MSG_ERROR, "easypro sheet init: project.json parse error: sch id must be a number at %ld:%ld\n", jctx.njs.lineno, jctx.njs.col); - goto error; - } - sch_id = jctx.value.number; - } - if (strcmp(jctx.name, "name") == 0) { - if (jctx.type != NJSON_SEM_TYPE_STRING) { - rnd_message(RND_MSG_ERROR, "easypro sheet init: project.json parse error: sheet name must be a string at %ld:%ld\n", jctx.njs.lineno, jctx.njs.col); - goto error; - } - if (user_name != NULL) free(user_name); - user_name = rnd_strdup(jctx.value.string); - } - break; - case M_SYM: - if (level != 3) break; - /* reading items of a symbol block */ -/* rnd_trace(" [%d] sym atom: %s\n", level, jctx.name);*/ - if (strcmp(jctx.name, "title") == 0) { - if (jctx.type != NJSON_SEM_TYPE_STRING) { - rnd_message(RND_MSG_ERROR, "easypro sheet init: project.json parse error: sym title must be a string at %ld:%ld\n", jctx.njs.lineno, jctx.njs.col); - goto error; - } - if (user_name != NULL) free(user_name); - user_name = rnd_strdup(jctx.value.string); - } - - break; - } - break; - } - } - - /* cleanup and return */ - free(sname); - free(user_name); - free(sch_name); - njson_sem_uninit(&jctx); - fclose(f); - free(fn); - return res; -} - -static int easypro_load_zip_sheet(easypro_bundle_t *bnd, csch_sheet_t *sheet) -{ - int alloced; - csch_cgrp_t *loclib_sym; - csch_source_arg_t *src; - - if (!bnd->sheet_loader_inited) { - long n; - read_ctx_t symctx = {0}; - - if (easypro_load_zip_sheet_init(bnd, sheet) != 0) - return -1; - - if (bnd->sheets.used < 2) { - rnd_message(RND_MSG_ERROR, "easypro sheet init: project.json does not name any sheet\n"); - return -1; - } - bnd->sheet_loader_inited = 1; - - csch_sheet_init(&bnd->symsheet, NULL); - bnd->symsheet_inited = 1; - - symctx.sheet = &bnd->symsheet; - symctx.pro_symtab = &bnd->symtab; - htsp_init(&bnd->symtab, strhash, strkeyeq); - bnd->symtab_inited = 1; - - alien_setup(&symctx); - - TODO("load all symbols into bnd->symtab"); - for(n = 0; n < bnd->syms.used; n+=2) { - const char *key = bnd->syms.array[n]; - const char *path = bnd->syms.array[n+1]; - csch_cgrp_t *sym; - - symctx.f = rnd_fopen(&sheet->hidlib, path, "r"); - if (symctx.f == NULL) { - rnd_message(RND_MSG_ERROR, "Failed to open symbol at '%s'\n", path); - return -1; - } - - symctx.fn = path; - sym = easypro_load_sym(&symctx, NULL); - fclose(symctx.f); - - if (sym == NULL) { - rnd_message(RND_MSG_ERROR, "Failed to load symbol from '%s'\n", path); - return -1; - } - } - } - -#if 0 -we are embedding symbols for now - /* create sheet local library */ - src = csch_attrib_src_c(bnd->fn, 0, 0, NULL); - loclib_sym = csch_loclib_get_root_by_name(sheet, "symbol", src, 1, &alloced); - if (loclib_sym == NULL) { - rnd_message(RND_MSG_ERROR, "Failed to allocate symbol local lib (root)\n"); - return -1; - } -#endif - - if (easypro_load_sheet(bnd->sheets.array[bnd->sheet_idx], bnd->sheets.array[bnd->sheet_idx+1], sheet, loclib_sym, &bnd->symtab) != 0) - return -1; - - bnd->sheet_idx += 2; - if (bnd->sheet_idx >= bnd->sheets.used) - return 1; - return 0; -} - -/*** entry ***/ - -/* IO API function (load symbol from lib) */ -csch_cgrp_t *io_easypro_load_grp(FILE *f, const char *fn, const char *fmt, csch_sheet_t *sheet) -{ - return io_easypro_load_grp_into(f, fn, sheet, NULL, 1); -} - - -#define CAN_UNZIP ((io_easyeda_conf.plugins.io_easyeda.zip_list_cmd != NULL) && (*io_easyeda_conf.plugins.io_easyeda.zip_list_cmd != '\0')) - -int io_easypro_test_parse(FILE *f, const char *fn, const char *fmt, csch_plug_io_type_t type) -{ - if (easypro_test_parse_sym(f, fn, fmt, type) == 0) - return 0; - - if (CAN_UNZIP) { - int is_sym, res; - rewind(f); - res = easypro_test_parse_zip(f, fn, fmt, type, &is_sym); - if (res == 0) { - if (is_sym) /* can load sym in both cases */ - return 0; - if (type == CSCH_IOTYP_SHEET) /* can load a sheet only as a sheet */ - return 0; - } - } - - return -1; -} - - -int io_easypro_load_sheet_bundled(void *cookie, FILE *f, const char *fn, csch_sheet_t *dst) -{ - easypro_bundle_t *bnd = cookie; - if (bnd->is_sym) - return easypro_load_zip_sym(bnd, dst); - return easypro_load_zip_sheet(bnd, dst); -} - -/* called only for sheets */ -void *io_easypro_test_parse_bundled(FILE *f, const char *fn, const char *fmt, csch_plug_io_type_t type) -{ - int is_sym, res; - easypro_bundle_t *bnd; - char *cmd, *fullpath; - const char *prefix[4]; - - if (!CAN_UNZIP) - return NULL; - - res = easypro_test_parse_zip(f, fn, fmt, type, &is_sym); - if (res != 0) - return NULL; - - bnd = calloc(sizeof(easypro_bundle_t), 1); - bnd->fn = fn; - bnd->is_sym = is_sym; - - /* unpack */ - bnd->dir = "/tmp/easypro"; - TODO("make temp dir with librnd instead"); - - prefix[0] = "cd "; - prefix[1] = bnd->dir; - prefix[2] = ";"; - prefix[3] = NULL; - - fullpath = rnd_lrealpath(fn); - cmd = easypro_zip_cmd(prefix, io_easyeda_conf.plugins.io_easyeda.zip_extract_cmd, fullpath); - free(fullpath); - - res = rnd_system(NULL, cmd); - if (res != 0) { - rnd_message(RND_MSG_ERROR, "io_easyeda: unable to unzip using command: '%s'\nDetails on stderr.\nPlease check your configuration!\n", cmd); - free(cmd); - io_easypro_end_bundled(bnd, fn); - return NULL; - } - free(cmd); - - return bnd; -} - - -void io_easypro_end_bundled(void *cookie, const char *fn) -{ - long n; - - easypro_bundle_t *bnd = cookie; - TODO("free temp dir bnd->dir with librnd"); - - if (bnd->dr != NULL) - rnd_closedir(bnd->dr); - - for(n = 0; n < bnd->sheets.used; n++) - free(bnd->sheets.array[n]); - vts0_uninit(&bnd->sheets); - - for(n = 0; n < bnd->syms.used; n++) - free(bnd->syms.array[n]); - vts0_uninit(&bnd->syms); - - if (bnd->symsheet_inited) - csch_sheet_uninit(&bnd->symsheet); - - if (bnd->symtab_inited) { - htsp_entry_t *e; - for(e = htsp_first(&bnd->symtab); e != NULL; e = htsp_next(&bnd->symtab, e)) - free(e->key); - htsp_uninit(&bnd->symtab); - } - - free(bnd); -} - Index: trunk/src/plugins/io_easyeda/read.c =================================================================== --- trunk/src/plugins/io_easyeda/read.c (revision 10700) +++ trunk/src/plugins/io_easyeda/read.c (revision 10701) @@ -430,4 +430,6 @@ } #include "read_hi_std.c" -#include "read_hi_pro.c" +#include "read_hi_pro_draw.c" +#include "read_hi_pro_glue.c" +#include "read_hi_pro_io.c" Index: trunk/src/plugins/io_easyeda/read_hi_pro_draw.c =================================================================== --- trunk/src/plugins/io_easyeda/read_hi_pro_draw.c (nonexistent) +++ trunk/src/plugins/io_easyeda/read_hi_pro_draw.c (revision 10701) @@ -0,0 +1,851 @@ +/* + * COPYRIGHT + * + * sch-rnd - modular/flexible schematics editor - easyeda file format support + * Copyright (C) 2024 Tibor 'Igor2' Palinkas + * + * (Supported by NLnet NGI0 Entrust Fund in 2024) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Contact: + * Project page: http://repo.hu/projects/sch-rnd + * contact lead developer: http://www.repo.hu/projects/sch-rnd/contact.html + * mailing list: http://www.repo.hu/projects/sch-rnd/contact.html + */ + +/* high level for the 'std' format - included from read.c; drawing objects */ + +#define REQ_ARGC_(nd, op, num, errstr, errstmt) \ +do { \ + if (nd->type != GDOM_ARRAY) { \ + error_at(ctx, nd, ("%s: object node is not an array\n", errstr)); \ + errstmt; \ + } \ + if (nd->value.array.used op num) { \ + error_at(ctx, nd, ("%s: not enough fields: need at least %ld, got %ld\n", errstr, (long)num, nd->value.array.used)); \ + errstmt; \ + } \ +} while(0) + +#define REQ_ARGC_GTE(nd, num, errstr, errstmt) REQ_ARGC_((nd), <, (num), (errstr), errstmt) +#define REQ_ARGC_EQ(nd, num, errstr, errstmt) REQ_ARGC_((nd), !=, (num), (errstr), errstmt) + +/* call these only after a REQ_ARGC_* as it won't do bound check */ +#define GET_ARG_STR(dst, nd, num, errstr, errstmt) \ +do { \ + gdom_node_t *__tmp__ = nd->value.array.child[num]; \ + if ((__tmp__->type == GDOM_DOUBLE) && (__tmp__->value.dbl == -1)) {\ + dst = NULL; \ + } \ + else { \ + if (__tmp__->type != GDOM_STRING) { \ + error_at(ctx, nd, ("%s: wrong argument type for arg #%ld (expected string)\n", errstr, (long)num)); \ + errstmt; \ + } \ + dst = __tmp__->value.str; \ + } \ +} while(0) + +#define GET_ARG_DBL(dst, nd, num, errstr, errstmt) \ +do { \ + gdom_node_t *__tmp__ = nd->value.array.child[num]; \ + if (__tmp__->type != GDOM_DOUBLE) { \ + error_at(ctx, nd, ("%s: wrong argument type for arg #%ld (expected double)\n", errstr, (long)num)); \ + errstmt; \ + } \ + dst = __tmp__->value.dbl; \ +} while(0) + +#define GET_ARG_HASH(dst, nd, num, errstr, errstmt) \ +do { \ + gdom_node_t *__tmp__ = nd->value.array.child[num]; \ + if (__tmp__->type != GDOM_HASH) { \ + error_at(ctx, nd, ("%s: wrong argument type for arg #%ld; expected a hash\n", errstr, (long)num)); \ + errstmt; \ + } \ + dst = __tmp__; \ +} while(0) + +#define GET_ARG_ARRAY(dst, nd, num, errstr, errstmt) \ +do { \ + gdom_node_t *__tmp__ = nd->value.array.child[num]; \ + if (__tmp__->type != GDOM_ARRAY) { \ + error_at(ctx, nd, ("%s: wrong argument type for arg #%ld; expected an array\n", errstr, (long)num)); \ + errstmt; \ + } \ + dst = __tmp__; \ +} while(0) + +#define CHK_ARG_KW(nd, num, kwval, errstr, errstmt) \ +do { \ + const char *__str__;\ + GET_ARG_STR(__str__, nd, num, errstr, errstmt); \ + if (strcmp(__str__, kwval) != 0) { \ + error_at(ctx, nd, ("%s: arg #%ld must be '%s' but is '%s'\n", errstr, (long)num, kwval, __str__)); \ + errstmt; \ + }\ +} while(0) + +/* Look up style by name and return whether the given style fills */ +static int easypro_style_filled(read_ctx_t *ctx, gdom_node_t *obj, const char *sty) +{ + htsi_entry_t *e = htsi_getentry(&ctx->pro_pen_fill, sty); + if (e == NULL) { + error_at(ctx, obj, ("easypro_style_filled: undefined style '%s'\n", sty)); + return 0; + } + return e->value; +} + +/*** parse obj subtrees (lines in the file) ***/ + +/* Announces a slot (even for single-slot parts); slots are full copies */ +static int easypro_parse_part(read_ctx_t *ctx, gdom_node_t *obj, csch_cgrp_t **parent) +{ + gdom_node_t *bbox, *coords; + REQ_ARGC_GTE(obj, 3, "easypro_parse_part", return -1); + GET_ARG_HASH(bbox, obj, 2, "easypro_parse_part: bbox", return -1); + + ctx->pro_slot++; + if (ctx->pro_symtab != NULL) { /* create a new symbol group for the new part */ + csch_source_arg_t *src; + const char *name; + + GET_ARG_STR(name, obj, 1, "easypro_parse_part: name", return -1); + + *parent = csch_cgrp_alloc(ctx->sheet, &ctx->sheet->direct, csch_oid_new(ctx->sheet, &ctx->sheet->direct)); + src = csch_attrib_src_c(ctx->fn, 0, 0, NULL); /* whole-file context, no need to set location */ + csch_cobj_attrib_set(ctx->sheet, *parent, CSCH_ATP_HARDWIRED, "role", "symbol", src); + + htsp_insert(ctx->pro_symtab, rnd_strdup(name), *parent); + } + else if (ctx->pro_want_slot == -1) { + double x1, y1, x2, y2; + + coords = gdom_hash_get(bbox, easy_BBOX); + if (coords->type != GDOM_ARRAY) { + error_at(ctx, coords, ("PART/BBOX needs to be an array\n")); + return -1; + } + + REQ_ARGC_GTE(coords, 4, "easypro_parse_part PART/BBOX", return -1); + GET_ARG_DBL(x1, coords, 0, "easypro_parse_part PART/BBOX: x1", return -1); + GET_ARG_DBL(y1, coords, 1, "easypro_parse_part PART/BBOX: y1", return -1); + GET_ARG_DBL(x2, coords, 2, "easypro_parse_part PART/BBOX: x2", return -1); + GET_ARG_DBL(y2, coords, 3, "easypro_parse_part PART/BBOX: y2", return -1); + + /* when reading all slots they would badly overlap - shift by bbox */ + if (ctx->pro_slot > 1) + ctx->alien.ox += (x2-x1)*2; + } + else if (ctx->pro_slot > ctx->pro_want_slot) + ctx->pro_stop = 1; /* don't read any more slots */ + + ctx->pro_last = *parent; + return 0; +} + +/* PIN, e19, 1, null, 40, 0, 20, 180, null, 0, 0 + obj ID ? ? x y len rot ? gfx ? + rot: 0 = left *--- (* is the startpoint) + 90 = down + 180 = right ---* + 270 = up + gfx: 2 = "not" (circle r=3 on the start side) +*/ +static int easypro_parse_pin(read_ctx_t *ctx, gdom_node_t *obj, csch_cgrp_t *parent) +{ + double x, y, len, rot, gfx; + double sx, sy, ex, ey, dx = 0, dy = 0; /* start, end, direction */ + int want_circ = 0, gfxi; + static const double notr = 3; + csch_source_arg_t *src; + csch_cgrp_t *term; + + REQ_ARGC_GTE(obj, 11, "easypro_parse_pin", return -1); + + GET_ARG_DBL(x, obj, 4, "easypro_parse_pin: coord x", return -1); + GET_ARG_DBL(y, obj, 5, "easypro_parse_pin: coord y", return -1); + GET_ARG_DBL(len, obj, 6, "easypro_parse_pin: length", return -1); + GET_ARG_DBL(rot, obj, 7, "easypro_parse_pin: rotation", return -1); + GET_ARG_DBL(gfx, obj, 9, "easypro_parse_pin: gfx", return -1); + + /* figure rotation and direction */ + switch((int)rot) { + case 0: dx = +1; break; + case 90: dy = +1; break; + case 180: dx = -1; break; + case 270: dy = -1; break; + default: + error_at(ctx, obj, ("easypro_parse_pin: invalid rotation angle %f\n", rot)); + return -1; + } + + /* figure graphics */ + gfxi = gfx; + if (gfxi & 2) { want_circ = 1; gfxi &= ~2; } + if (gfxi != 0) + error_at(ctx, obj, ("easypro_parse_pin: gfx bits unhandled: %x\n(please report this bug among with the file)\n", gfxi)); + + /* figure endpoints */ + sx = x; sy = y; + ex = sx + dx * len; ey = sy + dy * len; + + if (want_circ) { + ex -= dx * notr*2; + ey -= dy * notr*2; + } + + /* create the pin */ + src = easyeda_attrib_src_c(ctx, obj, NULL); + term = (csch_cgrp_t *)csch_alien_mkpin_line(&ctx->alien, src, parent, sx, sy, ex, ey); + + if (want_circ) + csch_alien_mkarc(&ctx->alien, term, ex+dx*notr, ey+dy*notr, notr, 0, 360, "term-decor"); + + ctx->pro_last = term; + + return 0; +} + + +/* "ATTR", "e51", "", "Device", "", 1, 1, 0, -60, 0, "st1", 0] + kw id ? key val keyvis valvis x y rotdeg pen ? + rotdeg: 0 = horiz + 90 = vert, read from the right +*/ +static int easypro_parse_attr(read_ctx_t *ctx, gdom_node_t *obj, csch_cgrp_t *parent) +{ + csch_source_arg_t *src; + double x, y, rot, kvis, vvis; + const char *key, *val; + + REQ_ARGC_GTE(obj, 12, "easypro_parse_attr", return -1); + + GET_ARG_STR(key, obj, 3, "easypro_parse_attr: key", return -1); + GET_ARG_STR(val, obj, 4, "easypro_parse_attr: val", return -1); + GET_ARG_DBL(kvis, obj, 5, "easypro_parse_attr: key visibility", return -1); + GET_ARG_DBL(vvis, obj, 6, "easypro_parse_attr: value visibility", return -1); + GET_ARG_DBL(x, obj, 7, "easypro_parse_attr: coord x", return -1); + GET_ARG_DBL(y, obj, 8, "easypro_parse_attr: coord y", return -1); + GET_ARG_DBL(rot, obj, 9, "easypro_parse_attr: rotation", return -1); + + if (ctx->pro_last == NULL) { + error_at(ctx, obj, ("easypro_parse_attr: ATTR without previously created group object\n")); + return -1; + } + + + src = easyeda_attrib_src_c(ctx, obj, NULL); + csch_attrib_set(&ctx->pro_last->attr, CSCH_ATP_USER_DEFAULT, key, val, src, NULL); + + /* create a floater if anything is visible */ + if (kvis || vvis) { + const char *penname = DECOR_PEN_NAME(ctx->pro_last); + csch_coord_t tx, ty; + csch_text_t *txt; + g2d_xform_t imx; + + txt = (csch_text_t *)csch_alien_mktext(&ctx->alien, ctx->pro_last, 0, 0, penname); + txt->dyntext = 1; + if (ctx->pro_last->role == CSCH_ROLE_SYMBOL) + txt->hdr.floater = 1; + + if (kvis && vvis) txt->text = rnd_concat(key, "=", "%../a.", key, "%", NULL); + else if (kvis) txt->text = rnd_strdup(key); + else if (vvis) txt->text = rnd_concat("%../a.", key, "%", NULL); + + switch((int)rot) { + case 0: break; + case 90: + case 180: + case 270: + txt->spec_rot = (int)rot; + break; + default: + error_at(ctx, obj, ("easypro_parse_attr: invalid rotation angle %f\n", rot)); + return -1; + } + + /* inverse-transform sheet coords specified in the file to parent group + relative coords that the cschem model requires */ + tx = csch_alien_coord_x(&ctx->alien, x); + ty = csch_alien_coord_y(&ctx->alien, y); + csch_cgrp_inverse_xform(ctx->pro_last, &tx, &ty, 1); + txt->spec1.x = tx; + txt->spec1.y = ty; + txt->spec_rot -= ctx->pro_last->spec_rot; + if (ctx->pro_last->mirx) { + txt->spec_mirx ^= 1; + if ((ctx->pro_last->spec_rot == 90) || (ctx->pro_last->spec_rot == 270)) + txt->spec_rot += 180; + } + } + + return 0; +} + +/* "POLY","e253",[758,10,758,70],false,"st6",0 + kw id coords ? sty ? */ +static int easypro_parse_poly(read_ctx_t *ctx, gdom_node_t *obj, csch_cgrp_t *parent) +{ + const char *penname = DECOR_PEN_NAME(parent), *sty; + gdom_node_t *coords; + double x, y, lx, ly; + long n, v; + csch_chdr_t *poly; + + REQ_ARGC_GTE(obj, 6, "easypro_parse_poly", return -1); + + GET_ARG_ARRAY(coords, obj, 2, "easypro_parse_poly: coords", return -1); + GET_ARG_STR(sty, obj, 4, "easypro_parse_circle: style name", return -1); + + + v = coords->value.array.used; + if (v < 4) { + error_at(ctx, coords, ("easypro_parse_poly: too few coords\n")); + return -1; + } + if ((v % 2) != 0) { + error_at(ctx, coords, ("easypro_parse_poly: odd number of coords\n")); + return -1; + } + + if (v > 4) { + int filled = easypro_style_filled(ctx, obj, sty); + poly = csch_alien_mkpoly(&ctx->alien, parent, penname, filled ? penname : NULL); + } + else + poly = NULL; + + for(n = 0; n < v; n+=2) { + GET_ARG_DBL(x, coords, n, "easypro_parse_poly: coord x", return -1); + GET_ARG_DBL(y, coords, n+1, "easypro_parse_poly: coord y", return -1); + if (n > 0) { + if (poly != NULL) + csch_alien_append_poly_line(&ctx->alien, poly, lx, ly, x, y); + else + csch_alien_mkline(&ctx->alien, parent, lx, ly, x, y, penname); + } + lx = x; + ly = y; + } + + return 0; +} + +/* absolute value of the difference between two angles in radian */ +static double angle_err(double a1, double a2) +{ + /* normalize the angles */ + if (a1 < 0) a1 += M_PI*2; + if (a1 > M_PI*2) a1 -= M_PI*2; + if (a2 < 0) a2 += M_PI*2; + if (a2 > M_PI*2) a2 -= M_PI*2; + + /* now they are in the same range of 0..M_PI*2 */ + return fabs(a1-a2); +} + +/* "ARC","e11", -16.879,0.06024, -12.89446,4.35448, -8.92106,0.04999, "st4", 0 + start x y middle x y end x y linetype */ +static int easypro_parse_arc(read_ctx_t *ctx, gdom_node_t *obj, csch_cgrp_t *parent) +{ + const char *penname = DECOR_PEN_NAME(parent), *sty; + double sx, sy, mx, my, ex, ey; + double sx2, sy2, mx2, my2, ex2, ey2; + double A, B, C, D; + double cx, cy, r, sa, da, ea, ma, da1, da2; + int filled; + + REQ_ARGC_GTE(obj, 10, "easypro_parse_arc", return -1); + + GET_ARG_DBL(sx, obj, 2, "easypro_parse_arc: coord sx", return -1); + GET_ARG_DBL(sy, obj, 3, "easypro_parse_arc: coord sy", return -1); + GET_ARG_DBL(mx, obj, 4, "easypro_parse_arc: coord mx", return -1); + GET_ARG_DBL(my, obj, 5, "easypro_parse_arc: coord my", return -1); + GET_ARG_DBL(ex, obj, 6, "easypro_parse_arc: coord ex", return -1); + GET_ARG_DBL(ey, obj, 7, "easypro_parse_arc: coord ey", return -1); + GET_ARG_STR(sty, obj, 8, "easypro_parse_arc: style name", return -1); + + /* figure the center and radius, see https://math.stackexchange.com/q/4000949 */ + sx2 = sx*sx; sy2 = sy*sy; + mx2 = mx*mx; my2 = my*my; + ex2 = ex*ex; ey2 = ey*ey; + + A = sx*(my-ey) - sy*(mx-ex) + mx*ey - ex*my; + B = (sx2+sy2)*(ey-my) + (mx2+my2)*(sy-ey) + (ex2+ey2)*(my-sy); + C = (sx2+sy2)*(mx-ex) + (mx2+my2)*(ex-sx) + (ex2+ey2)*(sx-mx); + D = (sx2+sy2)*(ex*my-mx*ey) + (mx2+my2)*(sx*ey-ex*sy) + (ex2+ey2)*(mx*sy-sx*my); + + if (A == 0) { + error_at(ctx, obj, ("easypro_parse_arc: the three coords are colinear\n")); + return -1; + } + + cx = -B/(2*A); + cy = -C/(2*A); + r = (B*B+C*C-4*A*D)/(4*A*A); + if (r <= 0) { + error_at(ctx, obj, ("easypro_parse_arc: invalid radius\n")); + return -1; + } + r = sqrt(r); + + /* figure angles */ + sa = atan2(cy - sy, cx - sx); + ma = atan2(cy - my, cx - mx); + ea = atan2(cy - ey, cx - ex); + + da1 = ea - sa; + da2 = sa - ea; + da = (angle_err(ma, sa+da1/2) < angle_err(ma, sa+da2/2)) ? da1 : da2; + + /* convert to deg */ + sa *= RND_RAD_TO_DEG; + da *= RND_RAD_TO_DEG; + + /* y flip */ + sa += 180; + + filled = easypro_style_filled(ctx, obj, sty); + if (filled) { + csch_chdr_t *poly = csch_alien_mkpoly(&ctx->alien, parent, penname, penname); + csch_alien_append_poly_arc(&ctx->alien, poly, cx, cy, r, sa, da); + } + else + csch_alien_mkarc(&ctx->alien, parent, cx, cy, r, sa, da, penname); + + return 0; +} + +/* "CIRCLE", "e42", 40,10, 10, "st5", 0 + x y r sty */ +static int easypro_parse_circle(read_ctx_t *ctx, gdom_node_t *obj, csch_cgrp_t *parent) +{ + const char *penname = DECOR_PEN_NAME(parent), *sty; + double cx, cy, r; + int filled; + + REQ_ARGC_GTE(obj, 7, "easypro_parse_circle", return -1); + + GET_ARG_DBL(cx, obj, 2, "easypro_parse_circle: coord cx", return -1); + GET_ARG_DBL(cy, obj, 3, "easypro_parse_circle: coord cy", return -1); + GET_ARG_DBL(r, obj, 4, "easypro_parse_circle: coord r", return -1); + GET_ARG_STR(sty, obj, 5, "easypro_parse_circle: style name", return -1); + + if (r <= 0) { + error_at(ctx, obj, ("easypro_parse_circle: invalid radius\n")); + return -1; + } + + filled = easypro_style_filled(ctx, obj, sty); + + if (filled) { + csch_chdr_t *poly = csch_alien_mkpoly(&ctx->alien, parent, penname, penname); + csch_alien_append_poly_arc(&ctx->alien, poly, cx, cy, r, 0, 360); + } + else + csch_alien_mkarc(&ctx->alien, parent, cx, cy, r, 0, 360, penname); + + return 0; +} + +/* "ELLIPSE","e43", -10,30, 20,10, 0,"st5",0 + x y rx ,ry ? pen ? */ +static int easypro_parse_ellipse(read_ctx_t *ctx, gdom_node_t *obj, csch_cgrp_t *parent) +{ + const char *penname = DECOR_PEN_NAME(parent), *sty; + double cx, cy, rx, ry, ex, ey; + path_ctx_t pctx; + int filled; + + REQ_ARGC_GTE(obj, 7, "easypro_parse_ellipse", return -1); + + GET_ARG_DBL(cx, obj, 2, "easypro_parse_ellipse: coord cx", return -1); + GET_ARG_DBL(cy, obj, 3, "easypro_parse_ellipse: coord cy", return -1); + GET_ARG_DBL(rx, obj, 4, "easypro_parse_ellipse: coord r", return -1); + GET_ARG_DBL(ry, obj, 5, "easypro_parse_ellipse: coord r", return -1); + GET_ARG_STR(sty, obj, 7, "easypro_parse_ellipse: style name", return -1); + + if ((rx <= 0) || (ry <= 0)) { + error_at(ctx, obj, ("easypro_parse_ellipse: invalid radius\n")); + return -1; + } + + filled = easypro_style_filled(ctx, obj, sty); + + easyeda_svgpath_setup(); + + pctx.ctx = ctx; + pctx.nd = obj; + pctx.penname = penname; + pctx.in_poly = csch_alien_mkpoly(&ctx->alien, parent, penname, filled ? penname : NULL); + pctx.parent = parent; + + ex = cx + rx; + ey = cy; + svgpath_approx_earc(&pathcfg, &pctx, ex, ey, cx, cy, rx, ry, 0, 2*M_PI, 0, ex, ey, pathcfg.curve_approx_seglen*pathcfg.curve_approx_seglen); + + return 0; +} + +/* "RECT","e44", 30,30, 40,20, 0,0, 0,"st5",0 + x1 y1 x2 y2 rx,ry ? pen ? */ +static int easypro_parse_rect(read_ctx_t *ctx, gdom_node_t *obj, csch_cgrp_t *parent) +{ + const char *penname = DECOR_PEN_NAME(parent),*sty; + double x1, y1, x2, y2, rx, ry, r; + int filled; + + REQ_ARGC_GTE(obj, 11, "easypro_parse_rect", return -1); + + GET_ARG_DBL(x1, obj, 2, "easypro_parse_rect: coord x1", return -1); + GET_ARG_DBL(y1, obj, 3, "easypro_parse_rect: coord y1", return -1); + GET_ARG_DBL(x2, obj, 4, "easypro_parse_rect: coord x2", return -1); + GET_ARG_DBL(y2, obj, 5, "easypro_parse_rect: coord y2", return -1); + GET_ARG_DBL(rx, obj, 6, "easypro_parse_rect: coord rx", return -1); + GET_ARG_DBL(ry, obj, 7, "easypro_parse_rect: coord ry", return -1); + GET_ARG_STR(sty, obj, 9, "easypro_parse_rect: style name", return -1); + + if ((rx < 0) || (ry < 0)) { + error_at(ctx, obj, ("easypro_parse_rect: invalid radius\n")); + return -1; + } + + if (x1 > x2) rnd_swap(double, x1, x2); + if (y1 > y2) rnd_swap(double, y1, y2); + + filled = easypro_style_filled(ctx, obj, sty); + + easyeda_svgpath_setup(); + + r = (rx+ry)/2.0; + + parent = (csch_cgrp_t *)csch_alien_mkpoly(&ctx->alien, parent, penname, filled ? penname : NULL); + + if ((r > 0) && (rx != ry)) + error_at(ctx, obj, ("round rect: elliptical rounding not supported, using circular with average radius\n")); + + if (r > 0) csch_alien_append_poly_arc(&ctx->alien, &parent->hdr, x1+r, y1+r, r, -90, -90); + csch_alien_append_poly_line(&ctx->alien, &parent->hdr, x1+r, y1, x2-r, y1); + if (r > 0) csch_alien_append_poly_arc(&ctx->alien, &parent->hdr, x2-r, y1+r, r, 0, -90); + csch_alien_append_poly_line(&ctx->alien, &parent->hdr, x2, y1+r, x2, y2-r); + if (r > 0) csch_alien_append_poly_arc(&ctx->alien, &parent->hdr, x1+r, y2-r, r, 90, +90); + csch_alien_append_poly_line(&ctx->alien, &parent->hdr, x2-r, y2, x1+r, y2); + if (r > 0) csch_alien_append_poly_arc(&ctx->alien, &parent->hdr, x2-r, y2-r, r, 0, +90); + csch_alien_append_poly_line(&ctx->alien, &parent->hdr, x1, y2-r, x1, y1+r); + + return 0; +} + +/* "BEZIER","e41", [-20,10, 0,20, 10,10, 30,20] ,"st5",0 + id start ctrl1 ctrl2 end ? */ +static int easypro_parse_bezier(read_ctx_t *ctx, gdom_node_t *obj, csch_cgrp_t *parent) +{ + const char *penname = DECOR_PEN_NAME(parent), *sty; + double sx, sy, ex, ey, c1x, c1y, c2x, c2y; + path_ctx_t pctx; + gdom_node_t *coords; + int filled; + + REQ_ARGC_GTE(obj, 5, "easypro_parse_bezier", return -1); + + GET_ARG_ARRAY(coords, obj, 2, "easypro_parse_bezier: coords array", return -1); + GET_ARG_STR(sty, obj, 3, "easypro_parse_bezier: style name", return -1); + + REQ_ARGC_GTE(coords, 6, "easypro_parse_bezier: coords", return -1); + GET_ARG_DBL(sx, coords, 0, "easypro_parse_bezier: coord sx", return -1); + GET_ARG_DBL(sy, coords, 1, "easypro_parse_bezier: coord sy", return -1); + GET_ARG_DBL(c1x, coords, 2, "easypro_parse_bezier: coord c1x", return -1); + GET_ARG_DBL(c1y, coords, 3, "easypro_parse_bezier: coord c1y", return -1); + GET_ARG_DBL(c2x, coords, 4, "easypro_parse_bezier: coord c2x", return -1); + GET_ARG_DBL(c2y, coords, 5, "easypro_parse_bezier: coord c2y", return -1); + GET_ARG_DBL(ex, coords, 6, "easypro_parse_bezier: coord ex", return -1); + GET_ARG_DBL(ey, coords, 7, "easypro_parse_bezier: coord ey", return -1); + + filled = easypro_style_filled(ctx, obj, sty); + + easyeda_svgpath_setup(); + + pctx.ctx = ctx; + pctx.nd = coords; + pctx.penname = penname; + pctx.in_poly = csch_alien_mkpoly(&ctx->alien, parent, penname, filled ? penname : NULL); + pctx.parent = parent; + + svgpath_approx_bezier_cubic(&pathcfg, &pctx, sx, sy, c1x, c1y, c2x, c2y, ex, ey, pathcfg.curve_approx_seglen*pathcfg.curve_approx_seglen); + + return 0; +} + +/* "TEXT","e45", -10,-20, 0, "str", "st6",0 + id x y rot pen */ +static int easypro_parse_text(read_ctx_t *ctx, gdom_node_t *obj, csch_cgrp_t *parent) +{ + const char *penname = DECOR_PEN_NAME(parent); + double x, y, rot; + const char *str; + csch_text_t *txt; + int roti; + + REQ_ARGC_GTE(obj, 7, "easypro_parse_text", return -1); + + GET_ARG_DBL(x, obj, 2, "easypro_parse_text: coord x", return -1); + GET_ARG_DBL(y, obj, 3, "easypro_parse_text: coord y", return -1); + GET_ARG_DBL(rot, obj, 4, "easypro_parse_text: coord rot", return -1); + GET_ARG_STR(str, obj, 5, "easypro_parse_attr: text string", return -1); + + roti = rot; + switch(roti) { + case 0: case 90: case 180: case 270: break; + default: + error_at(ctx, obj, ("easypro_parse_text: invalid rotation angle %f\n", rot)); + return -1; + } + + txt = (csch_text_t *)csch_alien_mktext(&ctx->alien, parent, x, y, penname); + txt->text = rnd_strdup(str); + txt->spec_rot = roti; + + return 0; +} + +/* "GROUP",1,0,"border",["e607","e608","e609","e611","e613","e615","e617","e619","e621","e623","e625","e627","e629","e631","e633","e635","e637","e639","e641","e643","e645","e647","e649","e650","e651","e652","e653","e654","e655","e656","e657","e658","e659","e660","e661","e662","e663","e664"] + ? ? ? array of IDs */ +static int easypro_parse_group(read_ctx_t *ctx, gdom_node_t *obj, csch_cgrp_t *parent) +{ +#if 0 + gdom_node_t *ids; + + REQ_ARGC_GTE(obj, 5, "easypro_parse_group", return -1); + GET_ARG_ARRAY(ids, obj, 4, "easypro_parse_group: ids", return -1); + + /* No-op: groups happen within symbols (e.g. A4 frame); actualy grouping + them won't help sym editing and won't make any difference when placed + on a sheet */ +#endif + + return 0; +} + +/* "OBJ","e674","",494,43,155,30,0,0,"data:image/svg+xml;base64,PD94b...==",0 + kw id ? x y w h ? ? image ? */ +static int easypro_parse_obj(read_ctx_t *ctx, gdom_node_t *obj, csch_cgrp_t *parent) +{ + double x, y, w, h; + + REQ_ARGC_GTE(obj, 11, "easypro_parse_obj", return -1); + GET_ARG_DBL(x, obj, 3, "easypro_parse_obj: coord x", return -1); + GET_ARG_DBL(y, obj, 4, "easypro_parse_obj: coord x", return -1); + GET_ARG_DBL(w, obj, 5, "easypro_parse_obj: coord x", return -1); + GET_ARG_DBL(h, obj, 6, "easypro_parse_obj: coord x", return -1); + + easyeda_mkimage_sym(ctx, parent, obj, x, y-h, w, h); + + return 0; +} + +/* "LINESTYLE","st12",null,null,"#99CCFF",null + kw name ? ? fill ? */ +static int easypro_parse_linestyle(read_ctx_t *ctx, gdom_node_t *obj, csch_cgrp_t *parent) +{ + const char *name, *fill; + int is_filled; + + REQ_ARGC_GTE(obj, 6, "easypro_parse_linestyle", return -1); + + GET_ARG_STR(name, obj, 1, "easypro_parse_linestyle: name", return -1); + GET_ARG_STR(fill, obj, 4, "easypro_parse_linestyle: name", return -1); + + is_filled = ((fill != NULL) && (*fill == '#')); + + if (!htsi_has(&ctx->pro_pen_fill, name)) + htsi_insert(&ctx->pro_pen_fill, rnd_strdup(name), is_filled); + else + error_at(ctx, obj, ("easypro_parse_linestyle: style '%s' redefined (ignoring)\n", name)); + + return 0; +} + +/* "COMPONENT","e152","LM358.1",190,360,0, 0, {},0 + kw id symname x y rot mirx ? ? */ +static int easypro_parse_component(read_ctx_t *ctx, gdom_node_t *obj, csch_cgrp_t *parent) +{ + const char *symname; + double x, y, rot, mirx; + const csch_cgrp_t *src; + csch_cgrp_t *dst; + + if (ctx->pro_symtab == NULL) { + error_at(ctx, obj, ("easypro_parse_component: no symtab in context - component within a symbol?!\n")); + return -1; + } + + REQ_ARGC_GTE(obj, 9, "easypro_parse_component", return -1); + + GET_ARG_STR(symname, obj, 2, "easypro_parse_component: symname", return -1); + GET_ARG_DBL(x, obj, 3, "easypro_parse_component: coord x", return -1); + GET_ARG_DBL(y, obj, 4, "easypro_parse_component: coord y", return -1); + GET_ARG_DBL(rot, obj, 5, "easypro_parse_component: rotation", return -1); + GET_ARG_DBL(mirx, obj, 6, "easypro_parse_component: mirror-x", return -1); + + src = htsp_get(ctx->pro_symtab, symname); + if (src == NULL) { + error_at(ctx, obj, ("easypro_parse_component: failed to find symbol '%s' in symtab - not in the project file?\n", symname)); + return -1; + } + + dst = csch_cgrp_dup(ctx->sheet, &ctx->sheet->direct, src, 0); + if (dst == NULL) { + error_at(ctx, obj, ("easypro_parse_component: failed to copy symbol '%s' from the symtab to the sheet\n", symname)); + return -1; + } + dst->x = csch_alien_coord_x(&ctx->alien, x); + dst->y = csch_alien_coord_y(&ctx->alien, y); + dst->spec_rot = rot; + if (mirx) + dst->mirx = 1; + + csch_cgrp_xform_update(ctx->sheet, dst); /* update the matrix so that children attribute transformations are done correctly */ + + ctx->pro_last = dst; + return 0; +} + +/* "WIRE","e1", [[80,65,80,245],[80,245,150,245],[150,245,150,350]] ,"st3",0 + kw id x1 y1 x2 y2 sty ? */ +static int easypro_parse_wire(read_ctx_t *ctx, gdom_node_t *obj, csch_cgrp_t *parent) +{ + gdom_node_t *segs, *coords; + long n; + + REQ_ARGC_GTE(obj, 5, "easypro_parse_wire", return -1); + GET_ARG_ARRAY(segs, obj, 2, "easypro_parse_wire: segments", return -1); + + for(n = 0; n < segs->value.array.used; n++) { + double x1, y1, x2, y2; + + GET_ARG_ARRAY(coords, segs, n, "easypro_parse_wire: coords", return -1); + REQ_ARGC_GTE(coords, 4, "easypro_parse_wire coords", return -1); + + GET_ARG_DBL(x1, coords, 0, "easypro_parse_wire: coord x1", return -1); + GET_ARG_DBL(y1, coords, 1, "easypro_parse_wire: coord y1", return -1); + GET_ARG_DBL(x2, coords, 2, "easypro_parse_wire: coord x2", return -1); + GET_ARG_DBL(y2, coords, 3, "easypro_parse_wire: coord y2", return -1); + + csch_alien_mknet(&ctx->alien, &ctx->sheet->direct, x1, y1, x2, y2); + } + + return 0; +} + +/* object dispatcher */ +static int easypro_parse_any_obj(read_ctx_t *ctx, gdom_node_t *obj, csch_cgrp_t **parent) +{ + char *cmds; + int cmdi; + + REQ_ARGC_GTE(obj, 1, "easypro_parse_obj: need type of the object", return -1); + GET_ARG_STR(cmds, obj, 0, "easypro_parse_obj: first arg must be a string", return -1); + cmdi = easy_sphash(cmds); + + switch(cmdi) { + case easy_PART: return easypro_parse_part(ctx, obj, parent); + case easy_PIN: return easypro_parse_pin(ctx, obj, *parent); + case easy_ATTR: return easypro_parse_attr(ctx, obj, *parent); + case easy_POLY: return easypro_parse_poly(ctx, obj, *parent); + case easy_ARC: return easypro_parse_arc(ctx, obj, *parent); + case easy_CIRCLE: return easypro_parse_circle(ctx, obj, *parent); + case easy_ELLIPSE: return easypro_parse_ellipse(ctx, obj, *parent); + case easy_RECT: return easypro_parse_rect(ctx, obj, *parent); + case easy_BEZIER: return easypro_parse_bezier(ctx, obj, *parent); + case easy_TEXT: return easypro_parse_text(ctx, obj, *parent); + case easy_GROUP: return easypro_parse_group(ctx, obj, *parent); + case easy_OBJ: return easypro_parse_obj(ctx, obj, *parent); + case easy_LINESTYLE: return easypro_parse_linestyle(ctx, obj, *parent); + case easy_COMPONENT: return easypro_parse_component(ctx, obj, *parent); + case easy_WIRE: return easypro_parse_wire(ctx, obj, *parent); + + case easy_FONTSTYLE: return 0; /* ignore: sch-rnd uses pens */ + + case -1: + default: + error_at(ctx, obj, ("easypro_parse_any_obj: unrecognized obj %d '%s'\n", cmdi, cmds)); + return -1; + } + + return -1; /* can't get here */ +} + +/* On success returns start idx within the root array where the first object + node is; on error returns negative */ +static int easypro_verify_header(read_ctx_t *ctx, int is_sym) +{ + gdom_node_t *hdr, *head; + + if (ctx->root->type != GDOM_ARRAY) { + error_at(ctx, ctx->root, ("easypro_verify_header: internal error: root must be an array\n")); + return -1; + } + + if (ctx->root->value.array.used < 2) { + error_at(ctx, ctx->root, ("easypro_verify_header: root must have at least two items (headers)\n")); + return -1; + } + + /* first line: DOCTYPE */ + hdr = ctx->root->value.array.child[0]; + REQ_ARGC_GTE(hdr, 3, "easypro_verify_header: DOCTYPE", return -1); + CHK_ARG_KW(hdr, 0, "DOCTYPE", "easypro_verify_header: DOCTYPE", return -1); + if (is_sym) + CHK_ARG_KW(hdr, 1, "SYMBOL", "easypro_verify_header: DOCTYPE", return -1); + else + CHK_ARG_KW(hdr, 1, "SCH", "easypro_verify_header: DOCTYPE", return -1); + CHK_ARG_KW(hdr, 2, "1.1", "easypro_verify_header: DOCTYPE", return -1); + + /* second line: HEAD */ + hdr = ctx->root->value.array.child[1]; + REQ_ARGC_GTE(hdr, 2, "easypro_verify_header: HEAD", return -1); + CHK_ARG_KW(hdr, 0, "HEAD", "easypro_verify_header: HEAD", return -1); + GET_ARG_HASH(head, hdr, 1, "easypro_verify_header: HEAD", return -1); + + /* second line: HEAD's hash */ + (void)head; + TODO("check if any of these is needed"); + + return 2; +} + +static void easypro_init_ctx(read_ctx_t *ctx) +{ + ctx->pro_last = NULL; + htsi_init(&ctx->pro_pen_fill, strhash, strkeyeq); + + /* for whatever reason symbols seem to be y-mirrored */ + ctx->alien.flip_y = 0; +} + +static void easypro_uninit_ctx(read_ctx_t *ctx) +{ + htsi_entry_t *e; + for(e = htsi_first(&ctx->pro_pen_fill); e != NULL; e = htsi_next(&ctx->pro_pen_fill, e)) + free(e->key); + htsi_uninit(&ctx->pro_pen_fill); + + ctx->alien.flip_y = 1; +} + Index: trunk/src/plugins/io_easyeda/read_hi_pro_glue.c =================================================================== --- trunk/src/plugins/io_easyeda/read_hi_pro_glue.c (nonexistent) +++ trunk/src/plugins/io_easyeda/read_hi_pro_glue.c (revision 10701) @@ -0,0 +1,562 @@ +/* + * COPYRIGHT + * + * sch-rnd - modular/flexible schematics editor - easyeda file format support + * Copyright (C) 2024 Tibor 'Igor2' Palinkas + * + * (Supported by NLnet NGI0 Entrust Fund in 2024) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Contact: + * Project page: http://repo.hu/projects/sch-rnd + * contact lead developer: http://www.repo.hu/projects/sch-rnd/contact.html + * mailing list: http://www.repo.hu/projects/sch-rnd/contact.html + */ + +/* high level for the 'std' format - included from read.c; glue layer + between draw and io */ + +static int easypro_load_sheet(const char *user_name, const char *fn, csch_sheet_t *sheet, csch_cgrp_t *loclib_sym, htsp_t *symtab) +{ + read_ctx_t ctx = {0}; + csch_source_arg_t *src; + int rv = 0, starti, n; + FILE *f; + + f = rnd_fopen(&sheet->hidlib, fn, "r"); + if (f == NULL) { + rnd_message(RND_MSG_ERROR, "Error loading '%s': failed to open for read\n", fn); + return -1; + } + + ctx.f = f; + ctx.fn = fn; + ctx.sheet = sheet; + ctx.pro_symtab = symtab; + + alien_setup(&ctx); + csch_alien_sheet_setup(&ctx.alien, 1); + easypro_init_ctx(&ctx); + + ctx.root = easypro_low_parse(f); + fclose(f); + + if (ctx.root == NULL) { + rnd_message(RND_MSG_ERROR, "Error loading '%s': low level 'pro' parser failed\n", fn); + return -1; + } + + starti = easypro_verify_header(&ctx, 0); + if (starti < 0) + rv = -1; + + if (rv == 0) { + TODO("copy relevant symbols from symtab to loclib_sym"); + } + + /* parse the data section of the tree */ + if (rv == 0) { + csch_cgrp_t *parent = &sheet->direct; + for(n = starti; !ctx.pro_stop && (rv == 0) && (n < ctx.root->value.array.used); n++) + rv = easypro_parse_any_obj(&ctx, ctx.root->value.array.child[n], &parent); + } + + if (rv == 0) { + csch_cgrp_update(sheet, &sheet->direct, 1); + csch_sheet_bbox_update(sheet); + } + + easypro_uninit_ctx(&ctx); + if (ctx.root != NULL) + gdom_free(ctx.root); + return rv; +} + +/* Load a symbol using ctx into resgrp; if resgrp is NULL, allocate a + new group in sheet */ +static csch_cgrp_t *easypro_load_sym(read_ctx_t *ctx, csch_cgrp_t *resgrp) +{ + csch_source_arg_t *src; + int rv = 0, starti, n, alloced = 0; + + ctx->root = easypro_low_parse(ctx->f); + if (ctx->root == NULL) { + rnd_message(RND_MSG_ERROR, "Error loading '%s': low level 'pro' parser failed\n", ctx->fn); + return NULL; + } + + starti = easypro_verify_header(ctx, 1); + if (starti < 0) + return NULL; + + if (ctx->pro_symtab == NULL) { + /* create the symbol group (if not creating one per PART for a symtab) */ + if (resgrp == NULL) { + resgrp = csch_cgrp_alloc(ctx->sheet, &ctx->sheet->direct, csch_oid_new(ctx->sheet, &ctx->sheet->direct)); + alloced = 1; + } + + src = csch_attrib_src_c(ctx->fn, 0, 0, NULL); /* whole-file context, no need to set location */ + csch_cobj_attrib_set(ctx->sheet, resgrp, CSCH_ATP_HARDWIRED, "role", "symbol", src); + } + + easypro_init_ctx(ctx); + + /* parse the data section of the tree */ + for(n = starti; !ctx->pro_stop && (rv == 0) && (n < ctx->root->value.array.used); n++) + rv = easypro_parse_any_obj(ctx, ctx->root->value.array.child[n], &resgrp); + + if (rv == 0) { + csch_cgrp_update(ctx->sheet, resgrp, 1); + csch_sheet_bbox_update(ctx->sheet); + } + else { + if (alloced) + csch_cgrp_free(resgrp); + resgrp = NULL; + } + + easypro_uninit_ctx(ctx); + + return resgrp; +} + +/* Load a symbol into a group; if existing is NULL, allocate new */ +csch_cgrp_t *io_easypro_load_grp_into(FILE *f, const char *fn, csch_sheet_t *sheet, csch_cgrp_t *existing, int slotno) +{ + read_ctx_t ctx = {0}; + csch_cgrp_t *grp; + + if (htip_get(&sheet->direct.id2obj, 1) != NULL) { + rnd_message(RND_MSG_ERROR, "Error loading '%s': there's already a group1 in destination sheet\n", fn); + return NULL; + } + + ctx.f = f; + ctx.fn = fn; + ctx.sheet = sheet; + ctx.pro_want_slot = slotno; + + alien_setup(&ctx); + + grp = easypro_load_sym(&ctx, existing); + if (io_easyeda_postproc(&ctx, 0) != 0) + rnd_message(RND_MSG_ERROR, "io_easyeda: failed to postprocess newly loaded symbol\n"); + + if (ctx.root != NULL) { + gdom_free(ctx.root); + ctx.root = NULL; + } + + return grp; +} + + +static int easypro_is_file_zip(FILE *f) +{ + char buf[4]; + if (fread(buf, 1, 4, f) != 4) + return 0; + return (buf[0] == 'P') && (buf[1] == 'K') && (buf[2] == 3) && (buf[3] == 4); +} + +/* allocate memory and print a zip command line: first prefix (if not NULL), + then template with %s substituted wuth path */ +static char *easypro_zip_cmd(const char **prefix, const char *template, const char *path) +{ + gds_t tmp = {0}; + const char *s; + + if (prefix != NULL) { + const char **p; + for(p = prefix; *p != NULL; p++) + gds_append_str(&tmp, *p); + } + + for(s = template; *s != '\0'; s++) { + if ((s[0] == '%') && (s[1] == 's')) { + gds_append_str(&tmp, path); + s++; + } + else + gds_append(&tmp, *s); + } + + return tmp.array; +} + +static int easypro_test_parse_sym(FILE *f, const char *fn, const char *fmt, csch_plug_io_type_t type) +{ + char line_[256], *line; + + /* sheets are loaded as bundles from zip */ + if (type == CSCH_IOTYP_SHEET) + return -1; + + /* first line is: ["DOCTYPE","SYMBOL","1.1"] */ + line = fgets(line_, sizeof(line_), f); + if ((line == NULL) || (*line != '[')) + return -1; + + if (strncmp(line+1, "\"DOCTYPE\",", 10) != 0) + return -1; + line += 11; + + if (type == CSCH_IOTYP_GROUP) { + if (strncmp(line, "\"SYMBOL\",", 9) != 0) + return -1; + return 0; + } + + return -1; +} + +static int easypro_test_parse_zip(FILE *f, const char *fn, const char *fmt, csch_plug_io_type_t type, int *is_sym) +{ + int res = -1; + char *cmd; + FILE *fc; + + *is_sym = 0; + + if (!easypro_is_file_zip(f)) + return -1; + + /* get a file list and look for known index files */ + cmd = easypro_zip_cmd(NULL, io_easyeda_conf.plugins.io_easyeda.zip_list_cmd, fn); + fc = rnd_popen(NULL, cmd, "r"); + if (fc != NULL) { + char *line, buf[1024]; + while((line = fgets(buf, sizeof(buf), fc)) != NULL) { + if (strstr(line, "project.json") != NULL) { + res = 0; + break; + } + else if (strstr(line, "device.json") != NULL) { + *is_sym = 1; + res = 0; + break; + } + } + + fclose(fc); + } + free(cmd); + return res; +} + +typedef struct { + const char *fn; + char *dir; + unsigned is_sym:1; + + /* sym load */ + DIR *dr; + char *next_fn; + + /* bundled seet load */ + unsigned sheet_loader_inited:1; + unsigned symsheet_inited:1; + unsigned symtab_inited:1; + vts0_t sheets; /* list of name,filename pairs of all sheets */ + vts0_t syms; /* list of name,filename pairs of all syms */ + int sheet_idx; /* within ->sheets */ + htsp_t symtab; + csch_sheet_t symsheet; +} easypro_bundle_t; + +/* read next dirent and set bnd->next_fn; skip over . and .. and hidden files */ +static struct dirent *easypro_next_de(easypro_bundle_t *bnd) +{ + /* skip over . and .. */ + for(;;) { + struct dirent *de = rnd_readdir(bnd->dr); + if (de == NULL) + return NULL; + if (*de->d_name != '.') { + bnd->next_fn = de->d_name; + return de; + } + } +} + +static int easypro_load_sym_as_sheet(const char *fn, csch_sheet_t *sheet) +{ + FILE *f; + csch_cgrp_t *grp; + + f = rnd_fopen(&sheet->hidlib, fn, "r"); + if (f == NULL) { + rnd_message(RND_MSG_ERROR, "failed to open '%s' for read\n", fn); + return -1; + } + + grp = io_easypro_load_grp_into(f, fn, sheet, &sheet->direct, -1); + fclose(f); + + sch_rnd_sheet_setup(sheet, SCH_RND_SSC_PENS | SCH_RND_SSC_PEN_MARK_DEFAULT, sym_as_sheet_chk_copy_pen, NULL); + sheet->is_symbol = 1; + + return (grp == NULL) ? -1 : 0; +} + +/* read symbols from zip already unpacked into dir; + return 0 (more to read) or 1 (no more sheets to read) or -1 on error */ +static int easypro_load_zip_sym(easypro_bundle_t *bnd, csch_sheet_t *dst) +{ + struct dirent *de; + char *fn; + int res; + + if (bnd->dr == NULL) { + char *fn = rnd_concat(bnd->dir, "/SYMBOL", NULL); + + bnd->dr = rnd_opendir(NULL, fn); + free(fn); + if (bnd->dr == NULL) + return -1; + + de = easypro_next_de(bnd); + if (de == NULL) + return -1; + } + + /* load next symbol */ + fn = rnd_concat(bnd->dir, "/SYMBOL/", bnd->next_fn, NULL); + easypro_load_sym_as_sheet(fn, dst); + free(fn); + + /* figure name of the next symbol and terminate the load if there's no more */ + de = easypro_next_de(bnd); + return (de == NULL) ? 1 : 0; +} + + + +/* read the project file and map sheets and symbols to load */ +static int easypro_load_zip_sheet_init(easypro_bundle_t *bnd, csch_sheet_t *sheet) +{ + char *fn, *sname = NULL; + char *user_name = NULL; /* user readable sheet name or symbol title */ + char *sch_name = NULL; /* user readable sch name */ + njson_sem_ctx_t jctx = {0}; + FILE *f; + enum {M_MISC, M_SCH, M_SYM} main = M_MISC; + int level = 0, c, res = 0, sch_id= -1; + njson_sem_ev_t ev; + + fn = rnd_concat(bnd->dir, "/project.json", NULL); + f = rnd_fopen(&sheet->hidlib, fn, "r"); + if (f == NULL) { + rnd_message(RND_MSG_ERROR, "easypro sheet init: failed to open '%s' for read\n", fn); + free(fn); + return -1; + } + + + /* parse project.json and remember sheets and syms */ + while((c = fgetc(f)) != 0) { + njson_ev_t ev = njson_sem_push(&jctx, c); + + if (ev == NJSON_SEM_EV_eof) break; + if (ev == NJSON_SEM_EV_error) { + rnd_message(RND_MSG_ERROR, "easypro sheet init: project.json parse error: %s at %ld:%ld\n", jctx.njs.error, jctx.njs.lineno, jctx.njs.col); + error:; + res = -1; + break; + } + + switch(ev) { + case NJSON_SEM_EV_more: continue; + case NJSON_SEM_EV_eof: case NJSON_SEM_EV_error: break; /* can't happen */ + case NJSON_SEM_EV_OBJECT_BEGIN: + if (level == 1) { + if (strcmp(jctx.name, "schematics") == 0) main = M_SCH; + else if (strcmp(jctx.name, "symbols") == 0) main = M_SYM; + } + if ((level == 2) && ((main == M_SYM) || (main == M_SCH))) { + if (sname != NULL) free(sname); + sname = rnd_strdup(jctx.name); +/* rnd_trace(" sname: %s\n", jctx.name);*/ + } + case NJSON_SEM_EV_ARRAY_BEGIN: + level++; +/* rnd_trace(" [%d %d] %s\n", level, main, jctx.name);*/ + break; + case NJSON_SEM_EV_OBJECT_END: + case NJSON_SEM_EV_ARRAY_END: + if ((level == 5) && (main == M_SCH)) { /* finished reading a schematic block */ + char *name, *path; +/* rnd_trace("!sch flush! sname=%s uname=%s id=%d\n", sname, user_name, sch_id);*/ + name = rnd_concat(sch_name, "::", user_name, NULL); + path = rnd_strdup_printf("%s/SHEET/%s/%d.esch", bnd->dir, sname, sch_id); + + vts0_append(&bnd->sheets, name); + vts0_append(&bnd->sheets, path); + + if (user_name != NULL) free(user_name); + user_name = NULL; + sch_id = -1; + } + if ((level == 3) && (main == M_SYM)) { /* finished reading a symbol block */ + char *name, *path; +/* rnd_trace("!sym flush! sname=%s title=%s\n", sname, user_name);*/ + name = user_name; + path = rnd_concat(bnd->dir, "/SYMBOL/", sname, ".esym", NULL); + + vts0_append(&bnd->syms, name); + vts0_append(&bnd->syms, path); + + user_name = NULL; /* don't free user_name, ownership is passed to the vector */ + } + level--; + if (level == 1) main = M_MISC; + break; + + case NJSON_SEM_EV_ATOMIC: + switch(main) { + case M_SCH: + if ((level == 3) && (strcmp(jctx.name, "name") == 0)) { + /* remember user-unreadable long uid with use readable name - however, it's not necessarily unique */ + if (jctx.type != NJSON_SEM_TYPE_STRING) { + rnd_message(RND_MSG_ERROR, "easypro sheet init: project.json parse error: sch name must be a string at %ld:%ld\n", jctx.njs.lineno, jctx.njs.col); + goto error; + } + free(sch_name); + sch_name = rnd_strdup(jctx.value.string); + break; + } + + if (level != 5) break; + /* reading items of a schematic block */ +/* rnd_trace(" [%d] sch atom: %s\n", level, jctx.name);*/ + if (strcmp(jctx.name, "id") == 0) { + if (jctx.type != NJSON_SEM_TYPE_NUMBER) { + rnd_message(RND_MSG_ERROR, "easypro sheet init: project.json parse error: sch id must be a number at %ld:%ld\n", jctx.njs.lineno, jctx.njs.col); + goto error; + } + sch_id = jctx.value.number; + } + if (strcmp(jctx.name, "name") == 0) { + if (jctx.type != NJSON_SEM_TYPE_STRING) { + rnd_message(RND_MSG_ERROR, "easypro sheet init: project.json parse error: sheet name must be a string at %ld:%ld\n", jctx.njs.lineno, jctx.njs.col); + goto error; + } + if (user_name != NULL) free(user_name); + user_name = rnd_strdup(jctx.value.string); + } + break; + case M_SYM: + if (level != 3) break; + /* reading items of a symbol block */ +/* rnd_trace(" [%d] sym atom: %s\n", level, jctx.name);*/ + if (strcmp(jctx.name, "title") == 0) { + if (jctx.type != NJSON_SEM_TYPE_STRING) { + rnd_message(RND_MSG_ERROR, "easypro sheet init: project.json parse error: sym title must be a string at %ld:%ld\n", jctx.njs.lineno, jctx.njs.col); + goto error; + } + if (user_name != NULL) free(user_name); + user_name = rnd_strdup(jctx.value.string); + } + + break; + } + break; + } + } + + /* cleanup and return */ + free(sname); + free(user_name); + free(sch_name); + njson_sem_uninit(&jctx); + fclose(f); + free(fn); + return res; +} + +static int easypro_load_zip_sheet(easypro_bundle_t *bnd, csch_sheet_t *sheet) +{ + int alloced; + csch_cgrp_t *loclib_sym; + csch_source_arg_t *src; + + if (!bnd->sheet_loader_inited) { + long n; + read_ctx_t symctx = {0}; + + if (easypro_load_zip_sheet_init(bnd, sheet) != 0) + return -1; + + if (bnd->sheets.used < 2) { + rnd_message(RND_MSG_ERROR, "easypro sheet init: project.json does not name any sheet\n"); + return -1; + } + bnd->sheet_loader_inited = 1; + + csch_sheet_init(&bnd->symsheet, NULL); + bnd->symsheet_inited = 1; + + symctx.sheet = &bnd->symsheet; + symctx.pro_symtab = &bnd->symtab; + htsp_init(&bnd->symtab, strhash, strkeyeq); + bnd->symtab_inited = 1; + + alien_setup(&symctx); + + TODO("load all symbols into bnd->symtab"); + for(n = 0; n < bnd->syms.used; n+=2) { + const char *key = bnd->syms.array[n]; + const char *path = bnd->syms.array[n+1]; + csch_cgrp_t *sym; + + symctx.f = rnd_fopen(&sheet->hidlib, path, "r"); + if (symctx.f == NULL) { + rnd_message(RND_MSG_ERROR, "Failed to open symbol at '%s'\n", path); + return -1; + } + + symctx.fn = path; + sym = easypro_load_sym(&symctx, NULL); + fclose(symctx.f); + + if (sym == NULL) { + rnd_message(RND_MSG_ERROR, "Failed to load symbol from '%s'\n", path); + return -1; + } + } + } + +#if 0 +we are embedding symbols for now + /* create sheet local library */ + src = csch_attrib_src_c(bnd->fn, 0, 0, NULL); + loclib_sym = csch_loclib_get_root_by_name(sheet, "symbol", src, 1, &alloced); + if (loclib_sym == NULL) { + rnd_message(RND_MSG_ERROR, "Failed to allocate symbol local lib (root)\n"); + return -1; + } +#endif + + if (easypro_load_sheet(bnd->sheets.array[bnd->sheet_idx], bnd->sheets.array[bnd->sheet_idx+1], sheet, loclib_sym, &bnd->symtab) != 0) + return -1; + + bnd->sheet_idx += 2; + if (bnd->sheet_idx >= bnd->sheets.used) + return 1; + return 0; +} + Index: trunk/src/plugins/io_easyeda/read_hi_pro_io.c =================================================================== --- trunk/src/plugins/io_easyeda/read_hi_pro_io.c (nonexistent) +++ trunk/src/plugins/io_easyeda/read_hi_pro_io.c (revision 10701) @@ -0,0 +1,144 @@ +/* + * COPYRIGHT + * + * sch-rnd - modular/flexible schematics editor - easyeda file format support + * Copyright (C) 2024 Tibor 'Igor2' Palinkas + * + * (Supported by NLnet NGI0 Entrust Fund in 2024) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Contact: + * Project page: http://repo.hu/projects/sch-rnd + * contact lead developer: http://www.repo.hu/projects/sch-rnd/contact.html + * mailing list: http://www.repo.hu/projects/sch-rnd/contact.html + */ + +/* high level for the 'std' format - included from read.c; I/O entry points */ + +/* IO API function (load symbol from lib) */ +csch_cgrp_t *io_easypro_load_grp(FILE *f, const char *fn, const char *fmt, csch_sheet_t *sheet) +{ + return io_easypro_load_grp_into(f, fn, sheet, NULL, 1); +} + + +#define CAN_UNZIP ((io_easyeda_conf.plugins.io_easyeda.zip_list_cmd != NULL) && (*io_easyeda_conf.plugins.io_easyeda.zip_list_cmd != '\0')) + +int io_easypro_test_parse(FILE *f, const char *fn, const char *fmt, csch_plug_io_type_t type) +{ + if (easypro_test_parse_sym(f, fn, fmt, type) == 0) + return 0; + + if (CAN_UNZIP) { + int is_sym, res; + rewind(f); + res = easypro_test_parse_zip(f, fn, fmt, type, &is_sym); + if (res == 0) { + if (is_sym) /* can load sym in both cases */ + return 0; + if (type == CSCH_IOTYP_SHEET) /* can load a sheet only as a sheet */ + return 0; + } + } + + return -1; +} + + +int io_easypro_load_sheet_bundled(void *cookie, FILE *f, const char *fn, csch_sheet_t *dst) +{ + easypro_bundle_t *bnd = cookie; + if (bnd->is_sym) + return easypro_load_zip_sym(bnd, dst); + return easypro_load_zip_sheet(bnd, dst); +} + +/* called only for sheets */ +void *io_easypro_test_parse_bundled(FILE *f, const char *fn, const char *fmt, csch_plug_io_type_t type) +{ + int is_sym, res; + easypro_bundle_t *bnd; + char *cmd, *fullpath; + const char *prefix[4]; + + if (!CAN_UNZIP) + return NULL; + + res = easypro_test_parse_zip(f, fn, fmt, type, &is_sym); + if (res != 0) + return NULL; + + bnd = calloc(sizeof(easypro_bundle_t), 1); + bnd->fn = fn; + bnd->is_sym = is_sym; + + /* unpack */ + bnd->dir = "/tmp/easypro"; + TODO("make temp dir with librnd instead"); + + prefix[0] = "cd "; + prefix[1] = bnd->dir; + prefix[2] = ";"; + prefix[3] = NULL; + + fullpath = rnd_lrealpath(fn); + cmd = easypro_zip_cmd(prefix, io_easyeda_conf.plugins.io_easyeda.zip_extract_cmd, fullpath); + free(fullpath); + + res = rnd_system(NULL, cmd); + if (res != 0) { + rnd_message(RND_MSG_ERROR, "io_easyeda: unable to unzip using command: '%s'\nDetails on stderr.\nPlease check your configuration!\n", cmd); + free(cmd); + io_easypro_end_bundled(bnd, fn); + return NULL; + } + free(cmd); + + return bnd; +} + + +void io_easypro_end_bundled(void *cookie, const char *fn) +{ + long n; + + easypro_bundle_t *bnd = cookie; + TODO("free temp dir bnd->dir with librnd"); + + if (bnd->dr != NULL) + rnd_closedir(bnd->dr); + + for(n = 0; n < bnd->sheets.used; n++) + free(bnd->sheets.array[n]); + vts0_uninit(&bnd->sheets); + + for(n = 0; n < bnd->syms.used; n++) + free(bnd->syms.array[n]); + vts0_uninit(&bnd->syms); + + if (bnd->symsheet_inited) + csch_sheet_uninit(&bnd->symsheet); + + if (bnd->symtab_inited) { + htsp_entry_t *e; + for(e = htsp_first(&bnd->symtab); e != NULL; e = htsp_next(&bnd->symtab, e)) + free(e->key); + htsp_uninit(&bnd->symtab); + } + + free(bnd); +} + Index: trunk/src/sch-rnd/Makefile.dep =================================================================== --- trunk/src/sch-rnd/Makefile.dep (revision 10700) +++ trunk/src/sch-rnd/Makefile.dep (revision 10701) @@ -353,9 +353,12 @@ ../libcschem/concrete.h ../libcschem/operation.h ../libcschem/project.h \ ../libcschem/engine.h ../libcschem/abstract.h ../libcschem/TODO.h \ ../libcschem/util_parse.h ../../src_3rd/load_cache/load_cache.h \ - ../libcschem/util_wirenet.h ../sch-rnd/buffer.h \ + ../libcschem/util_wirenet.h ../libcschem/util_loclib.h \ + ../libcschem/plug_library.h ../sch-rnd/buffer.h ../sch-rnd/util_sheet.h \ ../../src_3rd/rnd_inclib/lib_svgpath/svgpath.h \ - ../plugins/lib_alien/read_helper.h ../plugins/lib_alien/read_postproc.h \ + ../../src_3rd/libnanojson/semantic.h \ + ../../src_3rd/libnanojson/nanojson.h ../plugins/lib_alien/read_helper.h \ + ../plugins/lib_alien/read_postproc.h \ ../plugins/io_easyeda/io_easyeda_conf.h \ ../plugins/io_easyeda/read_low_std.h \ ../plugins/io_easyeda/easyeda_sphash.h \ @@ -362,7 +365,9 @@ ../../src_3rd/rnd_inclib/lib_easyeda/gendom.h \ ../plugins/io_easyeda/read_low_pro.h ../plugins/io_easyeda/read.h \ ../libcschem/plug_io.h ../plugins/io_easyeda/read_hi_std.c \ - ../plugins/io_easyeda/read_hi_pro.c + ../plugins/io_easyeda/read_hi_pro_draw.c \ + ../plugins/io_easyeda/read_hi_pro_glue.c \ + ../plugins/io_easyeda/read_hi_pro_io.c ../plugins/io_easyeda/read_low_pro.o: \ ../plugins/io_easyeda/read_low_pro.c \ ../plugins/io_easyeda/read_low_pro.h \ @@ -381,11 +386,13 @@ ../../src_3rd/rnd_inclib/lib_easyeda/gendom.h \ ../../src_3rd/libnanojson/nanojson.c \ ../../src_3rd/libnanojson/nanojson.h \ + ../../src_3rd/libnanojson/semantic.c \ + ../../src_3rd/libnanojson/semantic.h \ + ../../src_3rd/libnanojson/nanojson.h \ ../../src_3rd/rnd_inclib/lib_easyeda/gendom.c \ ../../src_3rd/rnd_inclib/lib_easyeda/gendom.h \ ../../src_3rd/rnd_inclib/lib_easyeda/gendom_json.c \ ../../src_3rd/rnd_inclib/lib_easyeda/gendom_json.h \ - ../../src_3rd/libnanojson/nanojson.h \ ../../src_3rd/rnd_inclib/lib_easyeda/easyeda_low.c \ ../plugins/io_easyeda/io_easyeda_conf.h ../plugins/io_easyeda/svgpath.o: ../plugins/io_easyeda/svgpath.c \