Graphviz 13.0.0~dev.20241220.2304
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 w = 0, h = 0;
232 double n, x0, y0, x1, y1;
233 char u[10];
234 agxbuf line = {0};
235 bool eof = false;
236 bool wFlag = false, hFlag = false;
237
238 rewind(us->f);
239 while (!eof && (!wFlag || !hFlag)) {
240 // read next line
241 while (true) {
242 int c = fgetc(us->f);
243 if (c == EOF) {
244 eof = true;
245 break;
246 } else if (c == '\n') {
247 break;
248 }
249 agxbputc(&line, (char)c);
250 }
251
252 const char *re_string = agxbuse(&line);
254 while (find_attribute(re_string, &match) == 0) {
255 re_string = match.value.data + match.value.size + 1;
256
257 if (strview_str_eq(match.key, "width")) {
258 char *value = strview_str(match.value);
259 if (sscanf(value, "%lf%2s", &n, u) == 2) {
260 w = svg_units_convert(n, u);
261 wFlag = true;
262 }
263 else if (sscanf(value, "%lf", &n) == 1) {
264 w = svg_units_convert(n, "pt");
265 wFlag = true;
266 }
267 free(value);
268 if (hFlag)
269 break;
270 }
271 else if (strview_str_eq(match.key, "height")) {
272 char *value = strview_str(match.value);
273 if (sscanf(value, "%lf%2s", &n, u) == 2) {
274 h = svg_units_convert(n, u);
275 hFlag = true;
276 }
277 else if (sscanf(value, "%lf", &n) == 1) {
278 h = svg_units_convert(n, "pt");
279 hFlag = true;
280 }
281 free(value);
282 if (wFlag)
283 break;
284 }
285 else if (strview_str_eq(match.key, "viewBox")) {
286 char *value = strview_str(match.value);
287 if (sscanf(value, "%lf %lf %lf %lf", &x0, &y0, &x1, &y1) == 4) {
288 w = x1 - x0 + 1;
289 h = y1 - y0 + 1;
290 wFlag = true;
291 hFlag = true;
292 free(value);
293 break;
294 }
295 free(value);
296 }
297 }
298 }
299 us->dpi = 0;
300 assert(w >= 0 && w <= INT_MAX);
301 us->w = (int)w;
302 assert(h >= 0 && h <= INT_MAX);
303 us->h = (int)h;
304 agxbfree(&line);
305}
306
307static void png_size (usershape_t *us)
308{
309 int w, h;
310
311 us->dpi = 0;
312 fseek(us->f, 16, SEEK_SET);
313 if (get_int_msb_first(us->f, 4, &w) && get_int_msb_first(us->f, 4, &h)) {
314 us->w = w;
315 us->h = h;
316 }
317}
318
319static void ico_size (usershape_t *us)
320{
321 int w, h;
322
323 us->dpi = 0;
324 fseek(us->f, 6, SEEK_SET);
325 if (get_int_msb_first(us->f, 1, &w) && get_int_msb_first(us->f, 1, &h)) {
326 us->w = w;
327 us->h = h;
328 }
329}
330
331static void webp_size (usershape_t *us)
332{
333 int w, h;
334
335 us->dpi = 0;
336 fseek(us->f, 15, SEEK_SET);
337 if (fgetc(us->f) == 'X') { //VP8X
338 fseek(us->f, 24, SEEK_SET);
339 if (get_int_lsb_first(us->f, 4, &w) && get_int_lsb_first(us->f, 4, &h)) {
340 us->w = w;
341 us->h = h;
342 }
343 }
344 else { //VP8
345 fseek(us->f, 26, SEEK_SET);
346 if (get_int_lsb_first(us->f, 2, &w) && get_int_lsb_first(us->f, 2, &h)) {
347 us->w = w;
348 us->h = h;
349 }
350 }
351}
352
353static void gif_size (usershape_t *us)
354{
355 int w, h;
356
357 us->dpi = 0;
358 fseek(us->f, 6, SEEK_SET);
359 if (get_int_lsb_first(us->f, 2, &w) && get_int_lsb_first(us->f, 2, &h)) {
360 us->w = w;
361 us->h = h;
362 }
363}
364
365static void bmp_size (usershape_t *us) {
366 int size_x_msw, size_x_lsw, size_y_msw, size_y_lsw;
367
368 us->dpi = 0;
369 fseek (us->f, 16, SEEK_SET);
370 if ( get_int_lsb_first (us->f, 2, &size_x_msw) &&
371 get_int_lsb_first (us->f, 2, &size_x_lsw) &&
372 get_int_lsb_first (us->f, 2, &size_y_msw) &&
373 get_int_lsb_first (us->f, 2, &size_y_lsw) ) {
374 us->w = size_x_msw << 16 | size_x_lsw;
375 us->h = size_y_msw << 16 | size_y_lsw;
376 }
377}
378
379static void jpeg_size (usershape_t *us) {
380 int marker, length, size_x, size_y;
381
382 /* These are the markers that follow 0xff in the file.
383 * Other markers implicitly have a 2-byte length field that follows.
384 */
385 static const unsigned char standalone_markers[] = {
386 0x01, /* Temporary */
387 0xd0, 0xd1, 0xd2, 0xd3, /* Reset */
388 0xd4, 0xd5, 0xd6,
389 0xd7,
390 0xd8, /* Start of image */
391 0xd9, /* End of image */
392 };
393
394 us->dpi = 0;
395 while (true) {
396 /* Now we must be at a 0xff or at a series of 0xff's.
397 * If that is not the case, or if we're at EOF, then there's
398 * a parsing error.
399 */
400 if (! get_int_msb_first (us->f, 1, &marker))
401 return;
402
403 if (marker == 0xff)
404 continue;
405
406 /* Ok.. marker now read. If it is not a stand-alone marker,
407 * then continue. If it's a Start Of Frame (0xc?), then we're there.
408 * If it's another marker with a length field, then skip ahead
409 * over that length field.
410 */
411
412 /* A stand-alone... */
413 if (memchr(standalone_markers, marker, sizeof(standalone_markers)))
414 continue;
415
416 /* Incase of a 0xc0 marker: */
417 if (marker == 0xc0) {
418 /* Skip length and 2 lengths. */
419 if (fseek(us->f, 3, SEEK_CUR) == 0 &&
420 get_int_msb_first (us->f, 2, &size_x) &&
421 get_int_msb_first (us->f, 2, &size_y) ) {
422
423 /* Store length. */
424 us->h = size_x;
425 us->w = size_y;
426 }
427 return;
428 }
429
430 /* Incase of a 0xc2 marker: */
431 if (marker == 0xc2) {
432 /* Skip length and one more byte */
433 if (fseek(us->f, 3, SEEK_CUR) != 0)
434 return;
435
436 /* Get length and store. */
437 if ( get_int_msb_first (us->f, 2, &size_x) &&
438 get_int_msb_first (us->f, 2, &size_y) ) {
439 us->h = size_x;
440 us->w = size_y;
441 }
442 return;
443 }
444
445 /* Any other marker is assumed to be followed by 2 bytes length. */
446 if (! get_int_msb_first (us->f, 2, &length))
447 return;
448
449 fseek (us->f, length - 2, SEEK_CUR);
450 }
451}
452
453static void ps_size (usershape_t *us)
454{
455 char line[BUFSIZ];
456 int lx, ly, ux, uy;
457 char* linep;
458
459 us->dpi = 72;
460 rewind(us->f);
461 bool saw_bb = false;
462 while (fgets(line, sizeof(line), us->f)) {
463 /* PostScript accepts \r as EOL, so using fgets () and looking for a
464 * bounding box comment at the beginning doesn't work in this case.
465 * As a heuristic, we first search for a bounding box comment in line.
466 * This obviously fails if not all of the numbers make it into the
467 * current buffer. This shouldn't be a problem, as the comment is
468 * typically near the beginning, and so should be read within the first
469 * BUFSIZ bytes (even on Windows where this is 512).
470 */
471 if (!(linep = strstr (line, "%%BoundingBox:")))
472 continue;
473 if (sscanf (linep, "%%%%BoundingBox: %d %d %d %d", &lx, &ly, &ux, &uy) == 4) {
474 saw_bb = true;
475 break;
476 }
477 }
478 if (saw_bb) {
479 us->x = lx;
480 us->y = ly;
481 us->w = ux - lx;
482 us->h = uy - ly;
483 }
484}
485
486#define KEY "/MediaBox"
487
488typedef struct {
489 char* s;
490 char* buf;
491 FILE* fp;
492} stream_t;
493
494static char nxtc(stream_t *str) {
495 if (fgets(str->buf, BUFSIZ, str->fp)) {
496 str->s = str->buf;
497 return *(str->s);
498 }
499 return '\0';
500
501}
502
503#define strc(x) (*(x->s)?*(x->s):nxtc(x))
504#define stradv(x) (x->s++)
505
506static void
508{
509 char c;
510 while ((c = strc(str))) {
511 if (gv_isspace(c)) stradv(str);
512 else return;
513 }
514}
515
516static int
517scanNum (char* tok, double* dp)
518{
519 char* endp;
520 double d = strtod(tok, &endp);
521
522 if (tok == endp) return 1;
523 *dp = d;
524 return 0;
525}
526
527static void
528getNum (stream_t* str, char* buf)
529{
530 int len = 0;
531 char c;
532 skipWS(str);
533 while ((c = strc(str)) && (gv_isdigit(c) || (c == '.'))) {
534 buf[len++] = c;
535 stradv(str);
536 if (len == BUFSIZ-1) break;
537 }
538 buf[len] = '\0';
539
540 return;
541}
542
543static int
545{
546 char tok[BUFSIZ];
547
548 skipWS(str);
549 if (strc(str) != '[') return 1;
550 stradv(str);
551 getNum(str, tok);
552 if (scanNum(tok,&bp->LL.x)) return 1;
553 getNum(str, tok);
554 if (scanNum(tok,&bp->LL.y)) return 1;
555 getNum(str, tok);
556 if (scanNum(tok,&bp->UR.x)) return 1;
557 getNum(str, tok);
558 if (scanNum(tok,&bp->UR.y)) return 1;
559 return 0;
560}
561
562static int
563bboxPDF (FILE* fp, boxf* bp)
564{
566 char* s;
567 char buf[BUFSIZ];
568 while (fgets(buf, BUFSIZ, fp)) {
569 if ((s = strstr(buf,KEY))) {
570 str.buf = buf;
571 str.s = s+(sizeof(KEY)-1);
572 str.fp = fp;
573 return boxof(&str,bp);
574 }
575 }
576 return 1;
577}
578
579static void pdf_size (usershape_t *us)
580{
581 boxf bb;
582
583 us->dpi = 0;
584 rewind(us->f);
585 if ( ! bboxPDF (us->f, &bb)) {
586 us->x = bb.LL.x;
587 us->y = bb.LL.y;
588 us->w = bb.UR.x - bb.LL.x;
589 us->h = bb.UR.y - bb.LL.y;
590 }
591}
592
593static void usershape_close(void *p) {
594 usershape_t *us = p;
595
596 if (us->f)
597 fclose(us->f);
598 if (us->data && us->datafree)
599 us->datafree(us);
600 free (us);
601}
602
604 .key = offsetof(usershape_t, name),
605 .size = -1,
606 .freef = usershape_close,
607};
608
610{
611 usershape_t *us;
612
613 assert(name);
614 assert(name[0]);
615
616 if (!ImageDict)
617 return NULL;
618
619 us = dtmatch(ImageDict, name);
620 return us;
621}
622
623#define MAX_USERSHAPE_FILES_OPEN 50
625{
626 static int usershape_files_open_cnt;
627 const char *fn;
628
629 assert(us);
630 assert(us->name);
631 assert(us->name[0]);
632
633 if (us->f)
634 rewind(us->f);
635 else {
636 if (! (fn = safefile(us->name))) {
637 agwarningf("Filename \"%s\" is unsafe\n", us->name);
638 return false;
639 }
640 us->f = gv_fopen(fn, "rb");
641 if (us->f == NULL) {
642 agwarningf("%s while opening %s\n", strerror(errno), fn);
643 return false;
644 }
645 if (usershape_files_open_cnt >= MAX_USERSHAPE_FILES_OPEN)
646 us->nocache = true;
647 else
648 usershape_files_open_cnt++;
649 }
650 assert(us->f);
651 return true;
652}
653
655{
656 if (us->nocache) {
657 if (us->f) {
658 fclose(us->f);
659 us->f = NULL;
660 }
661 }
662}
663
664static void freeUsershape (usershape_t* us)
665{
666 if (us->name) agstrfree(0, us->name);
667 free (us);
668}
669
670static usershape_t *gvusershape_open (const char *name)
671{
672 usershape_t *us;
673
674 assert(name);
675
676 if (!ImageDict)
678
679 if (! (us = gvusershape_find(name))) {
680 us = gv_alloc(sizeof(usershape_t));
681
682 us->name = agstrdup(0, name);
683 if (!gvusershape_file_access(us)) {
684 freeUsershape (us);
685 return NULL;
686 }
687
688 assert(us->f);
689
690 switch(imagetype(us)) {
691 case FT_NULL:
692 if (!(us->data = find_user_shape(us->name))) {
693 agwarningf("\"%s\" was not found as a file or as a shape library member\n", us->name);
694 freeUsershape (us);
695 return NULL;
696 }
697 break;
698 case FT_GIF:
699 gif_size(us);
700 break;
701 case FT_PNG:
702 png_size(us);
703 break;
704 case FT_BMP:
705 bmp_size(us);
706 break;
707 case FT_JPEG:
708 jpeg_size(us);
709 break;
710 case FT_PS:
711 ps_size(us);
712 break;
713 case FT_WEBP:
714 webp_size(us);
715 break;
716 case FT_SVG:
717 svg_size(us);
718 break;
719 case FT_PDF:
720 pdf_size(us);
721 break;
722 case FT_ICO:
723 ico_size(us);
724 break;
725 case FT_EPS: /* no eps_size code available */
726 default:
727 break;
728 }
730 dtinsert(ImageDict, us);
731 return us;
732 }
734 return us;
735}
736
737/* gvusershape_size_dpi:
738 * Return image size in points.
739 */
740point
742{
743 point rv;
744
745 if (!us) {
746 rv.x = rv.y = -1;
747 }
748 else {
749 if (us->dpi != 0) {
750 dpi.x = dpi.y = us->dpi;
751 }
752 rv.x = us->w * POINTS_PER_INCH / dpi.x;
753 rv.y = us->h * POINTS_PER_INCH / dpi.y;
754 }
755 return rv;
756}
757
758/* gvusershape_size:
759 * Loads user image from file name if not already loaded.
760 * Return image size in points.
761 */
763{
764 point rv;
765 pointf dpi;
766 static char* oldpath;
767 usershape_t* us;
768
769 /* no shape file, no shape size */
770 if (!name || (*name == '\0')) {
771 rv.x = rv.y = -1;
772 return rv;
773 }
774
775 if (!HTTPServerEnVar && (oldpath != Gvimagepath)) {
776 oldpath = Gvimagepath;
777 if (ImageDict) {
779 ImageDict = NULL;
780 }
781 }
782
783 if ((dpi.y = GD_drawing(g)->dpi) >= 1.0)
784 dpi.x = dpi.y;
785 else
786 dpi.x = dpi.y = DEFAULT_DPI;
787
788 us = gvusershape_open (name);
789 rv = gvusershape_size_dpi (us, dpi);
790 return rv;
791}
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:258
#define POINTS_PER_MM
Definition geom.h:66
#define POINTS_PER_CM
Definition geom.h:65
#define POINTS_PER_INCH
Definition geom.h:64
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 *)
Definition refstr.c:139
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:131
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:52
static void webp_size(usershape_t *us)
#define BMP_MAGIC
Definition gvusershape.c:59
char * Gvimagepath
Definition globals.h:48
usershape_t * gvusershape_find(const char *name)
void gvusershape_file_release(usershape_t *us)
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)
static void usershape_close(void *p)
textitem scanner parser str
Definition htmlparse.y:224
graph or subgraph
Definition cgraph.h:425
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