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