Graphviz 13.0.0~dev.20250210.0415
Loading...
Searching...
No Matches
gvusershape.c
Go to the documentation of this file.
1/*************************************************************************
2 * Copyright (c) 2011 AT&T Intellectual Property
3 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the Eclipse Public License v1.0
5 * which accompanies this distribution, and is available at
6 * https://www.eclipse.org/legal/epl-v10.html
7 *
8 * Contributors: Details at https://graphviz.org
9 *************************************************************************/
10
11#include "config.h"
12#include <assert.h>
13#include <limits.h>
14#include <math.h>
15#include <stdbool.h>
16#include <stdio.h>
17#include <string.h>
18#include <stdlib.h>
19#include <errno.h>
20#include <util/gv_fopen.h>
21
22#ifdef _WIN32
23#include <windows.h>
24#define GLOB_NOSPACE 1 /* Ran out of memory. */
25#define GLOB_ABORTED 2 /* Read error. */
26#define GLOB_NOMATCH 3 /* No matches found. */
27#define GLOB_NOSORT 4
28#endif
29
30#include <common/types.h>
31#include <common/usershape.h>
32#include <common/utils.h>
34#include <gvc/gvplugin.h>
35#include <gvc/gvcint.h>
36#include <gvc/gvcproc.h>
37#include <util/agxbuf.h>
38#include <util/alloc.h>
39#include <util/gv_ctype.h>
40#include <util/strview.h>
41
42extern char *Gvimagepath;
43extern char *HTTPServerEnVar;
44extern shape_desc *find_user_shape(const char *);
45
47
48typedef struct {
49 char *template;
50 size_t size;
54
55#define HDRLEN 20
56
57#define PNG_MAGIC "\x89PNG\x0D\x0A\x1A\x0A"
58#define PS_MAGIC "%!PS-Adobe-"
59#define BMP_MAGIC "BM"
60#define GIF_MAGIC "GIF8"
61#define JPEG_MAGIC "\xFF\xD8\xFF"
62#define PDF_MAGIC "%PDF-"
63#define EPS_MAGIC "\xC5\xD0\xD3\xC6"
64#define XML_MAGIC "<?xml"
65#define SVG_MAGIC "<svg"
66#define RIFF_MAGIC "RIFF"
67#define WEBP_MAGIC "WEBP"
68#define ICO_MAGIC "\x00\x00\x01\x00"
69
71 { PNG_MAGIC, sizeof(PNG_MAGIC)-1, FT_PNG, "png", },
72 { PS_MAGIC, sizeof(PS_MAGIC)-1, FT_PS, "ps", },
73 { BMP_MAGIC, sizeof(BMP_MAGIC)-1, FT_BMP, "bmp", },
74 { GIF_MAGIC, sizeof(GIF_MAGIC)-1, FT_GIF, "gif", },
75 { JPEG_MAGIC, sizeof(JPEG_MAGIC)-1, FT_JPEG, "jpeg", },
76 { PDF_MAGIC, sizeof(PDF_MAGIC)-1, FT_PDF, "pdf", },
77 { EPS_MAGIC, sizeof(EPS_MAGIC)-1, FT_EPS, "eps", },
78 { XML_MAGIC, sizeof(XML_MAGIC)-1, FT_XML, "xml", },
79 { RIFF_MAGIC, sizeof(RIFF_MAGIC)-1, FT_RIFF, "riff", },
80 { ICO_MAGIC, sizeof(ICO_MAGIC)-1, FT_ICO, "ico", },
81};
82
84 char header[HDRLEN] = {0};
85
86 if (us->f && fread(header, 1, HDRLEN, us->f) == HDRLEN) {
87 for (size_t i = 0; i < sizeof(knowntypes) / sizeof(knowntype_t); i++) {
88 if (!memcmp (header, knowntypes[i].template, knowntypes[i].size)) {
90 us->type = knowntypes[i].type;
91 if (us->type == FT_XML) {
92 // if we did not see the closing of the XML declaration, scan for it
93 if (memchr(header, '>', HDRLEN) == NULL) {
94 while (true) {
95 int c = fgetc(us->f);
96 if (c == EOF) {
97 return us->type;
98 } else if (c == '>') {
99 break;
100 }
101 }
102 }
103 /* check for SVG in case of XML */
104 char tag[sizeof(SVG_MAGIC) - 1] = {0};
105 if (fread(tag, 1, sizeof(tag), us->f) != sizeof(tag)) {
106 return us->type;
107 }
108 while (true) {
109 if (memcmp(tag, SVG_MAGIC, sizeof(SVG_MAGIC) - 1) == 0) {
110 us->stringtype = "svg";
111 return (us->type = FT_SVG);
112 }
113 int c = fgetc(us->f);
114 if (c == EOF) {
115 return us->type;
116 }
117 memmove(&tag[0], &tag[1], sizeof(tag) - 1);
118 tag[sizeof(tag) - 1] = (char)c;
119 }
120 }
121 else if (us->type == FT_RIFF) {
122 /* check for WEBP in case of RIFF */
123 if (!memcmp(header+8, WEBP_MAGIC, sizeof(WEBP_MAGIC)-1)) {
124 us->stringtype = "webp";
125 return (us->type = FT_WEBP);
126 }
127 }
128 return us->type;
129 }
130 }
131 }
132
133 us->stringtype = "(lib)";
134 us->type = FT_NULL;
135
136 return FT_NULL;
137}
138
139static bool get_int_lsb_first(FILE *f, size_t sz, int *val) {
140 int ch;
141
142 unsigned value = 0;
143 for (size_t i = 0; i < sz; i++) {
144 ch = fgetc(f);
145 if (feof(f))
146 return false;
147 value |= (unsigned)ch << 8 * i;
148 }
149 if (value > INT_MAX) {
150 return false;
151 }
152 *val = (int)value;
153 return true;
154}
155
156static bool get_int_msb_first(FILE *f, size_t sz, int *val) {
157 int ch;
158
159 unsigned value = 0;
160 for (size_t i = 0; i < sz; i++) {
161 ch = fgetc(f);
162 if (feof(f))
163 return false;
164 value <<= 8;
165 value |= (unsigned)ch;
166 }
167 if (value > INT_MAX) {
168 return false;
169 }
170 *val = (int)value;
171 return true;
172}
173
174static double svg_units_convert(double n, char *u) {
175 if (strcmp(u, "in") == 0)
176 return round(n * POINTS_PER_INCH);
177 if (strcmp(u, "px") == 0)
178 return round(n * POINTS_PER_INCH / 96);
179 if (strcmp(u, "pc") == 0)
180 return round(n * POINTS_PER_INCH / 6);
181 if (strcmp(u, "pt") == 0 || strcmp(u, "\"") == 0) /* ugly!! - if there are no inits then the %2s get the trailing '"' */
182 return round(n);
183 if (strcmp(u, "cm") == 0)
184 return round(n * POINTS_PER_CM);
185 if (strcmp(u, "mm") == 0)
186 return round(n * POINTS_PER_MM);
187 return 0;
188}
189
190typedef struct {
193} match_t;
194
195static int find_attribute(const char *s, match_t *result) {
196
197 // look for an attribute string matching ([a-z][a-zA-Z]*)="([^"]*)"
198 for (size_t i = 0; s[i] != '\0'; ) {
199 if (s[i] >= 'a' && s[i] <= 'z') {
200 result->key.data = &s[i];
201 result->key.size = 1;
202 ++i;
203 while ((s[i] >= 'a' && s[i] <= 'z') || (s[i] >= 'A' && s[i] <= 'Z')) {
204 ++i;
205 ++result->key.size;
206 }
207 if (s[i] == '=' && s[i + 1] == '"') {
208 i += 2;
209 result->value.data = &s[i];
210 result->value.size = 0;
211 while (s[i] != '"' && s[i] != '\0') {
212 ++i;
213 ++result->value.size;
214 }
215 if (s[i] == '"') {
216 // found a valid attribute
217 return 0;
218 }
219 }
220 } else {
221 ++i;
222 }
223 }
224
225 // no attribute found
226 return -1;
227}
228
229static void svg_size (usershape_t *us)
230{
231 double n;
232 char u[3];
233 agxbuf line = {0};
234 bool eof = false;
235
236 // an analog of C++’s `std::optional<double>`
237 typedef struct { bool has_value; double value; } optional_double_t;
238#define SET(me, val) \
239 do { \
240 *(me) = (optional_double_t){.has_value = true, .value = (val)}; \
241 } while (0)
242#define VALUE_OR(me, val) ((me).has_value ? (me).value : (val))
243
244 // authoritative constraints we learned from `height` and `width`
245 optional_double_t hard_height = {0};
246 optional_double_t hard_width = {0};
247
248 // fallback constraints we learned from `viewBox`
249 optional_double_t soft_height = {0};
250 optional_double_t soft_width = {0};
251
252 rewind(us->f);
253 while (!eof && (!hard_width.has_value || !hard_height.has_value)) {
254 // read next line
255 while (true) {
256 int c = fgetc(us->f);
257 if (c == EOF) {
258 eof = true;
259 break;
260 } else if (c == '\n') {
261 break;
262 }
263 agxbputc(&line, (char)c);
264 }
265
266 const char *re_string = agxbuse(&line);
268 while (find_attribute(re_string, &match) == 0) {
269 re_string = match.value.data + match.value.size + 1;
270
271 if (strview_str_eq(match.key, "width")) {
272 char *value = strview_str(match.value);
273 if (sscanf(value, "%lf%2s", &n, u) == 2) {
274 SET(&hard_width, svg_units_convert(n, u));
275 }
276 else if (sscanf(value, "%lf", &n) == 1) {
277 SET(&hard_width, svg_units_convert(n, "pt"));
278 }
279 free(value);
280 if (hard_height.has_value)
281 break;
282 }
283 else if (strview_str_eq(match.key, "height")) {
284 char *value = strview_str(match.value);
285 if (sscanf(value, "%lf%2s", &n, u) == 2) {
286 SET(&hard_height, svg_units_convert(n, u));
287 }
288 else if (sscanf(value, "%lf", &n) == 1) {
289 SET(&hard_height, svg_units_convert(n, "pt"));
290 }
291 free(value);
292 if (hard_width.has_value)
293 break;
294 }
295 else if (strview_str_eq(match.key, "viewBox")) {
296 char *value = strview_str(match.value);
297 double w, h;
298 if (sscanf(value, "%*f %*f %lf %lf", &w, &h) == 2) {
299 SET(&soft_width, w);
300 SET(&soft_height, h);
301 }
302 free(value);
303 }
304 }
305
306 // if we have reached the end of a line and have seen `viewBox` but not
307 // `height` and/or `width`, let `viewBox` determine the dimensions
308 if (soft_height.has_value && soft_width.has_value) {
309 if (!hard_height.has_value) {
310 SET(&hard_height, soft_height.value);
311 }
312 if (!hard_width.has_value) {
313 SET(&hard_width, soft_width.value);
314 }
315 break;
316 }
317 }
318 us->dpi = 0;
319 const double h = VALUE_OR(hard_height, 0);
320 const double w = VALUE_OR(hard_width, 0);
321 assert(w >= 0 && w <= INT_MAX);
322 us->w = (int)w;
323 assert(h >= 0 && h <= INT_MAX);
324 us->h = (int)h;
325 agxbfree(&line);
326
327#undef VALUE_OR
328#undef SET
329}
330
331static void png_size (usershape_t *us)
332{
333 int w, h;
334
335 us->dpi = 0;
336 fseek(us->f, 16, SEEK_SET);
337 if (get_int_msb_first(us->f, 4, &w) && get_int_msb_first(us->f, 4, &h)) {
338 us->w = w;
339 us->h = h;
340 }
341}
342
343static void ico_size (usershape_t *us)
344{
345 int w, h;
346
347 us->dpi = 0;
348 fseek(us->f, 6, SEEK_SET);
349 if (get_int_msb_first(us->f, 1, &w) && get_int_msb_first(us->f, 1, &h)) {
350 us->w = w;
351 us->h = h;
352 }
353}
354
355static void webp_size (usershape_t *us)
356{
357 int w, h;
358
359 us->dpi = 0;
360 fseek(us->f, 15, SEEK_SET);
361 if (fgetc(us->f) == 'X') { //VP8X
362 fseek(us->f, 24, SEEK_SET);
363 if (get_int_lsb_first(us->f, 4, &w) && get_int_lsb_first(us->f, 4, &h)) {
364 us->w = w;
365 us->h = h;
366 }
367 }
368 else { //VP8
369 fseek(us->f, 26, SEEK_SET);
370 if (get_int_lsb_first(us->f, 2, &w) && get_int_lsb_first(us->f, 2, &h)) {
371 us->w = w;
372 us->h = h;
373 }
374 }
375}
376
377static void gif_size (usershape_t *us)
378{
379 int w, h;
380
381 us->dpi = 0;
382 fseek(us->f, 6, SEEK_SET);
383 if (get_int_lsb_first(us->f, 2, &w) && get_int_lsb_first(us->f, 2, &h)) {
384 us->w = w;
385 us->h = h;
386 }
387}
388
389static void bmp_size (usershape_t *us) {
390 int size_x_msw, size_x_lsw, size_y_msw, size_y_lsw;
391
392 us->dpi = 0;
393 fseek (us->f, 16, SEEK_SET);
394 if ( get_int_lsb_first (us->f, 2, &size_x_msw) &&
395 get_int_lsb_first (us->f, 2, &size_x_lsw) &&
396 get_int_lsb_first (us->f, 2, &size_y_msw) &&
397 get_int_lsb_first (us->f, 2, &size_y_lsw) ) {
398 us->w = size_x_msw << 16 | size_x_lsw;
399 us->h = size_y_msw << 16 | size_y_lsw;
400 }
401}
402
403static void jpeg_size (usershape_t *us) {
404 int marker, length, size_x, size_y;
405
406 /* These are the markers that follow 0xff in the file.
407 * Other markers implicitly have a 2-byte length field that follows.
408 */
409 static const unsigned char standalone_markers[] = {
410 0x01, /* Temporary */
411 0xd0, 0xd1, 0xd2, 0xd3, /* Reset */
412 0xd4, 0xd5, 0xd6,
413 0xd7,
414 0xd8, /* Start of image */
415 0xd9, /* End of image */
416 };
417
418 us->dpi = 0;
419 while (true) {
420 /* Now we must be at a 0xff or at a series of 0xff's.
421 * If that is not the case, or if we're at EOF, then there's
422 * a parsing error.
423 */
424 if (! get_int_msb_first (us->f, 1, &marker))
425 return;
426
427 if (marker == 0xff)
428 continue;
429
430 /* Ok.. marker now read. If it is not a stand-alone marker,
431 * then continue. If it's a Start Of Frame (0xc?), then we're there.
432 * If it's another marker with a length field, then skip ahead
433 * over that length field.
434 */
435
436 /* A stand-alone... */
437 if (memchr(standalone_markers, marker, sizeof(standalone_markers)))
438 continue;
439
440 /* Incase of a 0xc0 marker: */
441 if (marker == 0xc0) {
442 /* Skip length and 2 lengths. */
443 if (fseek(us->f, 3, SEEK_CUR) == 0 &&
444 get_int_msb_first (us->f, 2, &size_x) &&
445 get_int_msb_first (us->f, 2, &size_y) ) {
446
447 /* Store length. */
448 us->h = size_x;
449 us->w = size_y;
450 }
451 return;
452 }
453
454 /* Incase of a 0xc2 marker: */
455 if (marker == 0xc2) {
456 /* Skip length and one more byte */
457 if (fseek(us->f, 3, SEEK_CUR) != 0)
458 return;
459
460 /* Get length and store. */
461 if ( get_int_msb_first (us->f, 2, &size_x) &&
462 get_int_msb_first (us->f, 2, &size_y) ) {
463 us->h = size_x;
464 us->w = size_y;
465 }
466 return;
467 }
468
469 /* Any other marker is assumed to be followed by 2 bytes length. */
470 if (! get_int_msb_first (us->f, 2, &length))
471 return;
472
473 fseek (us->f, length - 2, SEEK_CUR);
474 }
475}
476
477static void ps_size (usershape_t *us)
478{
479 char line[BUFSIZ];
480 int lx, ly, ux, uy;
481 char* linep;
482
483 us->dpi = 72;
484 rewind(us->f);
485 bool saw_bb = false;
486 while (fgets(line, sizeof(line), us->f)) {
487 /* PostScript accepts \r as EOL, so using fgets () and looking for a
488 * bounding box comment at the beginning doesn't work in this case.
489 * As a heuristic, we first search for a bounding box comment in line.
490 * This obviously fails if not all of the numbers make it into the
491 * current buffer. This shouldn't be a problem, as the comment is
492 * typically near the beginning, and so should be read within the first
493 * BUFSIZ bytes (even on Windows where this is 512).
494 */
495 if (!(linep = strstr (line, "%%BoundingBox:")))
496 continue;
497 if (sscanf (linep, "%%%%BoundingBox: %d %d %d %d", &lx, &ly, &ux, &uy) == 4) {
498 saw_bb = true;
499 break;
500 }
501 }
502 if (saw_bb) {
503 us->x = lx;
504 us->y = ly;
505 us->w = ux - lx;
506 us->h = uy - ly;
507 }
508}
509
510#define KEY "/MediaBox"
511
512typedef struct {
513 char* s;
514 char* buf;
515 FILE* fp;
516} stream_t;
517
518static char nxtc(stream_t *str) {
519 if (fgets(str->buf, BUFSIZ, str->fp)) {
520 str->s = str->buf;
521 return *(str->s);
522 }
523 return '\0';
524
525}
526
527#define strc(x) (*(x->s)?*(x->s):nxtc(x))
528#define stradv(x) (x->s++)
529
530static void
532{
533 char c;
534 while ((c = strc(str))) {
535 if (gv_isspace(c)) stradv(str);
536 else return;
537 }
538}
539
540static int
541scanNum (char* tok, double* dp)
542{
543 char* endp;
544 double d = strtod(tok, &endp);
545
546 if (tok == endp) return 1;
547 *dp = d;
548 return 0;
549}
550
551static void
552getNum (stream_t* str, char* buf)
553{
554 int len = 0;
555 char c;
556 skipWS(str);
557 while ((c = strc(str)) && (gv_isdigit(c) || (c == '.'))) {
558 buf[len++] = c;
559 stradv(str);
560 if (len == BUFSIZ-1) break;
561 }
562 buf[len] = '\0';
563
564 return;
565}
566
567static int
569{
570 char tok[BUFSIZ];
571
572 skipWS(str);
573 if (strc(str) != '[') return 1;
574 stradv(str);
575 getNum(str, tok);
576 if (scanNum(tok,&bp->LL.x)) return 1;
577 getNum(str, tok);
578 if (scanNum(tok,&bp->LL.y)) return 1;
579 getNum(str, tok);
580 if (scanNum(tok,&bp->UR.x)) return 1;
581 getNum(str, tok);
582 if (scanNum(tok,&bp->UR.y)) return 1;
583 return 0;
584}
585
586static int
587bboxPDF (FILE* fp, boxf* bp)
588{
590 char* s;
591 char buf[BUFSIZ];
592 while (fgets(buf, BUFSIZ, fp)) {
593 if ((s = strstr(buf,KEY))) {
594 str.buf = buf;
595 str.s = s+(sizeof(KEY)-1);
596 str.fp = fp;
597 return boxof(&str,bp);
598 }
599 }
600 return 1;
601}
602
603static void pdf_size (usershape_t *us)
604{
605 boxf bb;
606
607 us->dpi = 0;
608 rewind(us->f);
609 if ( ! bboxPDF (us->f, &bb)) {
610 us->x = bb.LL.x;
611 us->y = bb.LL.y;
612 us->w = bb.UR.x - bb.LL.x;
613 us->h = bb.UR.y - bb.LL.y;
614 }
615}
616
617static void usershape_close(void *p) {
618 usershape_t *us = p;
619
620 if (us->f)
621 fclose(us->f);
622 if (us->data && us->datafree)
623 us->datafree(us);
624 free (us);
625}
626
628 .key = offsetof(usershape_t, name),
629 .size = -1,
630 .freef = usershape_close,
631};
632
634{
635 usershape_t *us;
636
637 assert(name);
638 assert(name[0]);
639
640 if (!ImageDict)
641 return NULL;
642
643 us = dtmatch(ImageDict, name);
644 return us;
645}
646
647#define MAX_USERSHAPE_FILES_OPEN 50
649{
650 static int usershape_files_open_cnt;
651 const char *fn;
652
653 assert(us);
654 assert(us->name);
655 assert(us->name[0]);
656
657 if (us->f)
658 rewind(us->f);
659 else {
660 if (! (fn = safefile(us->name))) {
661 agwarningf("Filename \"%s\" is unsafe\n", us->name);
662 return false;
663 }
664 us->f = gv_fopen(fn, "rb");
665 if (us->f == NULL) {
666 agwarningf("%s while opening %s\n", strerror(errno), fn);
667 return false;
668 }
669 if (usershape_files_open_cnt >= MAX_USERSHAPE_FILES_OPEN)
670 us->nocache = true;
671 else
672 usershape_files_open_cnt++;
673 }
674 assert(us->f);
675 return true;
676}
677
679{
680 if (us->nocache) {
681 if (us->f) {
682 fclose(us->f);
683 us->f = NULL;
684 }
685 }
686}
687
688static void freeUsershape (usershape_t* us)
689{
690 if (us->name) agstrfree(0, us->name, false);
691 free (us);
692}
693
694static usershape_t *gvusershape_open (const char *name)
695{
696 usershape_t *us;
697
698 assert(name);
699
700 if (!ImageDict)
702
703 if (! (us = gvusershape_find(name))) {
704 us = gv_alloc(sizeof(usershape_t));
705
706 us->name = agstrdup(0, name);
707 if (!gvusershape_file_access(us)) {
708 freeUsershape (us);
709 return NULL;
710 }
711
712 assert(us->f);
713
714 switch(imagetype(us)) {
715 case FT_NULL:
716 if (!(us->data = find_user_shape(us->name))) {
717 agwarningf("\"%s\" was not found as a file or as a shape library member\n", us->name);
718 freeUsershape (us);
719 return NULL;
720 }
721 break;
722 case FT_GIF:
723 gif_size(us);
724 break;
725 case FT_PNG:
726 png_size(us);
727 break;
728 case FT_BMP:
729 bmp_size(us);
730 break;
731 case FT_JPEG:
732 jpeg_size(us);
733 break;
734 case FT_PS:
735 ps_size(us);
736 break;
737 case FT_WEBP:
738 webp_size(us);
739 break;
740 case FT_SVG:
741 svg_size(us);
742 break;
743 case FT_PDF:
744 pdf_size(us);
745 break;
746 case FT_ICO:
747 ico_size(us);
748 break;
749 case FT_EPS: /* no eps_size code available */
750 default:
751 break;
752 }
754 dtinsert(ImageDict, us);
755 return us;
756 }
758 return us;
759}
760
761/* gvusershape_size_dpi:
762 * Return image size in points.
763 */
764point
766{
767 point rv;
768
769 if (!us) {
770 rv.x = rv.y = -1;
771 }
772 else {
773 if (us->dpi != 0) {
774 dpi.x = dpi.y = us->dpi;
775 }
776 rv.x = us->w * POINTS_PER_INCH / dpi.x;
777 rv.y = us->h * POINTS_PER_INCH / dpi.y;
778 }
779 return rv;
780}
781
782/* gvusershape_size:
783 * Loads user image from file name if not already loaded.
784 * Return image size in points.
785 */
787{
788 point rv;
789 pointf dpi;
790 static char* oldpath;
791 usershape_t* us;
792
793 /* no shape file, no shape size */
794 if (!name || (*name == '\0')) {
795 rv.x = rv.y = -1;
796 return rv;
797 }
798
799 if (!HTTPServerEnVar && (oldpath != Gvimagepath)) {
800 oldpath = Gvimagepath;
801 if (ImageDict) {
803 ImageDict = NULL;
804 }
805 }
806
807 if ((dpi.y = GD_drawing(g)->dpi) >= 1.0)
808 dpi.x = dpi.y;
809 else
810 dpi.x = dpi.y = DEFAULT_DPI;
811
812 us = gvusershape_open (name);
813 rv = gvusershape_size_dpi (us, dpi);
814 return rv;
815}
size_t match(char *str, char *pat)
Definition actions.c:106
static void agxbfree(agxbuf *xb)
free any malloced resources
Definition agxbuf.h:78
static WUR char * agxbuse(agxbuf *xb)
Definition agxbuf.h:307
static int agxbputc(agxbuf *xb, char c)
add character to buffer
Definition agxbuf.h:277
Memory allocation wrappers that exit on failure.
static void * gv_alloc(size_t size)
Definition alloc.h:47
#define dtmatch(d, o)
Definition cdt.h:184
#define dtinsert(d, o)
Definition cdt.h:185
CDT_API Dtmethod_t * Dttree
Definition dttree.c:308
CDT_API int dtclose(Dt_t *)
Definition dtclose.c:8
CDT_API Dt_t * dtopen(Dtdisc_t *, Dtmethod_t *)
Definition dtopen.c:9
const char * safefile(const char *filename)
Definition utils.c:260
#define POINTS_PER_MM
Definition geom.h:60
#define POINTS_PER_CM
Definition geom.h:59
#define POINTS_PER_INCH
Definition geom.h:58
static double len(glCompPoint p)
Definition glutils.c:150
void free(void *)
node NULL
Definition grammar.y:163
void agwarningf(const char *fmt,...)
Definition agerror.c:173
#define GD_drawing(g)
Definition types.h:353
int agstrfree(Agraph_t *, const char *, bool is_html)
Definition refstr.c:378
char * agstrdup(Agraph_t *, const char *)
returns a pointer to a reference-counted copy of the argument string, creating one if necessary
Definition refstr.c:370
bool gvusershape_file_access(usershape_t *us)
replacements for ctype.h functions
static bool gv_isdigit(int c)
Definition gv_ctype.h:41
static bool gv_isspace(int c)
Definition gv_ctype.h:55
FILE * gv_fopen(const char *filename, const char *mode)
Definition gv_fopen.c:32
wrapper around fopen for internal library usage
static void ico_size(usershape_t *us)
static void freeUsershape(usershape_t *us)
#define XML_MAGIC
Definition gvusershape.c:64
static char nxtc(stream_t *str)
#define HDRLEN
Definition gvusershape.c:55
#define MAX_USERSHAPE_FILES_OPEN
static bool get_int_msb_first(FILE *f, size_t sz, int *val)
#define RIFF_MAGIC
Definition gvusershape.c:66
shape_desc * find_user_shape(const char *)
Definition shapes.c:3962
#define PNG_MAGIC
Definition gvusershape.c:57
static bool get_int_lsb_first(FILE *f, size_t sz, int *val)
#define JPEG_MAGIC
Definition gvusershape.c:61
static void skipWS(stream_t *str)
static Dtdisc_t ImageDictDisc
#define PS_MAGIC
Definition gvusershape.c:58
static int find_attribute(const char *s, match_t *result)
char * HTTPServerEnVar
Definition globals.h:53
static void webp_size(usershape_t *us)
#define BMP_MAGIC
Definition gvusershape.c:59
char * Gvimagepath
Definition globals.h:49
usershape_t * gvusershape_find(const char *name)
void gvusershape_file_release(usershape_t *us)
#define SET(me, val)
point gvusershape_size(graph_t *g, char *name)
#define KEY
point gvusershape_size_dpi(usershape_t *us, pointf dpi)
#define EPS_MAGIC
Definition gvusershape.c:63
#define ICO_MAGIC
Definition gvusershape.c:68
#define GIF_MAGIC
Definition gvusershape.c:60
static int boxof(stream_t *str, boxf *bp)
static void jpeg_size(usershape_t *us)
static usershape_t * gvusershape_open(const char *name)
static int bboxPDF(FILE *fp, boxf *bp)
static knowntype_t knowntypes[]
Definition gvusershape.c:70
static void png_size(usershape_t *us)
static void gif_size(usershape_t *us)
static imagetype_t imagetype(usershape_t *us)
Definition gvusershape.c:83
static int scanNum(char *tok, double *dp)
#define PDF_MAGIC
Definition gvusershape.c:62
static Dict_t * ImageDict
Definition gvusershape.c:46
#define SVG_MAGIC
Definition gvusershape.c:65
static double svg_units_convert(double n, char *u)
static void pdf_size(usershape_t *us)
static void ps_size(usershape_t *us)
static void svg_size(usershape_t *us)
#define stradv(x)
static void bmp_size(usershape_t *us)
#define WEBP_MAGIC
Definition gvusershape.c:67
#define strc(x)
static void getNum(stream_t *str, char *buf)
#define VALUE_OR(me, val)
static void usershape_close(void *p)
textitem scanner parser str
Definition htmlparse.y:224
graph or subgraph
Definition cgraph.h:424
Definition geom.h:41
pointf UR
Definition geom.h:41
pointf LL
Definition geom.h:41
Definition cdt.h:100
int key
Definition cdt.h:85
imagetype_t type
Definition gvusershape.c:51
size_t size
Definition gvusershape.c:50
char * stringtype
Definition gvusershape.c:52
strview_t value
strview_t key
Definition geom.h:27
int y
Definition geom.h:27
int x
Definition geom.h:27
double x
Definition geom.h:29
double y
Definition geom.h:29
char * buf
FILE * fp
char * s
a non-owning string reference
Definition strview.h:20
const char * data
start of the pointed to string
Definition strview.h:21
size_t size
extent of the string in bytes
Definition strview.h:22
const char * name
Definition usershape.h:54
char * stringtype
Definition usershape.h:60
FILE * f
Definition usershape.h:58
void(* datafree)(usershape_t *us)
Definition usershape.h:65
bool nocache
Definition usershape.h:57
void * data
Definition usershape.h:63
imagetype_t type
Definition usershape.h:59
double x
Definition usershape.h:61
double y
Definition usershape.h:61
double h
Definition usershape.h:61
double w
Definition usershape.h:61
Non-owning string references.
static bool strview_str_eq(strview_t a, const char *b)
compare a string reference to a string for equality
Definition strview.h:98
static char * strview_str(strview_t source)
make a heap-allocated string from this string view
Definition strview.h:41
static tok_t tok(const char *input, const char *separators)
begin tokenization of a new string
Definition tokenize.h:43
graphs, nodes and edges info: Agraphinfo_t, Agnodeinfo_t and Agedgeinfo_t
Definition grammar.c:93
imagetype_t
Definition usershape.h:24
@ FT_BMP
Definition usershape.h:25
@ FT_PS
Definition usershape.h:26
@ FT_ICO
Definition usershape.h:27
@ FT_NULL
Definition usershape.h:24
@ FT_EPS
Definition usershape.h:26
@ FT_SVG
Definition usershape.h:26
@ FT_WEBP
Definition usershape.h:27
@ FT_GIF
Definition usershape.h:25
@ FT_JPEG
Definition usershape.h:25
@ FT_RIFF
Definition usershape.h:27
@ FT_PNG
Definition usershape.h:25
@ FT_XML
Definition usershape.h:26
@ FT_PDF
Definition usershape.h:26