Graphviz 16.1.1~dev.20260917.1327
Loading...
Searching...
No Matches
psusershape.c
Go to the documentation of this file.
1
3/*************************************************************************
4 * Copyright (c) 2011 AT&T Intellectual Property
5 * All rights reserved. This program and the accompanying materials
6 * are made available under the terms of the Eclipse Public License v2.0
7 * which accompanies this distribution, and is available at
8 * https://www.eclipse.org/org/documents/epl-2.0/EPL-2.0.html
9 *
10 * Contributors: Details at https://graphviz.org
11 *************************************************************************/
12
13#include "config.h"
14
15#include <sys/stat.h>
16#include <common/render.h>
17#include <gvc/gvio.h>
18#include <stdatomic.h>
19#include <stdbool.h>
20#include <stdio.h>
21#include <util/alloc.h>
22#include <util/gv_fopen.h>
23#include <util/strcasecmp.h>
24
25static int N_EPSF_files;
27
28static void ps_image_free(void *shape) {
29 usershape_t *p = shape;
30 free(p->data);
31}
32
34 .key = offsetof(usershape_t, name),
35 .size = -1,
36 .freef = ps_image_free,
37};
38
39static usershape_t *user_init(const char *str)
40{
41 char line[BUFSIZ];
42 FILE *fp;
43 struct stat statbuf;
44 int lx, ly, ux, uy;
45
46 if (!EPSF_contents)
48
50 if (us)
51 return us;
52
53 if (!(fp = gv_fopen(str, "r"))) {
54 agwarningf("couldn't open epsf file %s\n", str);
55 return NULL;
56 }
57 /* try to find size */
58 bool saw_bb = false;
59 bool must_inline = false;
60 while (fgets(line, sizeof(line), fp)) {
61 if (sscanf
62 (line, "%%%%BoundingBox: %d %d %d %d", &lx, &ly, &ux, &uy) == 4) {
63 saw_bb = true;
64 }
65 if (line[0] != '%' && strstr(line,"read")) must_inline = true;
66 if (saw_bb && must_inline) break;
67 }
68
69 if (saw_bb) {
70 us = gv_alloc(sizeof(usershape_t));
71 us->x = lx;
72 us->y = ly;
73 us->w = ux - lx;
74 us->h = uy - ly;
75 us->name = str;
76 us->macro_id = N_EPSF_files++;
77 fstat(fileno(fp), &statbuf);
78 char *contents = us->data = gv_calloc((size_t)statbuf.st_size + 1, sizeof(char));
79 if (fseek(fp, 0, SEEK_SET) == 0 &&
80 fread(contents, (size_t)statbuf.st_size, 1, fp) == 1) {
81 contents[statbuf.st_size] = '\0';
83 us->must_inline = must_inline;
84 }
85 else {
86 agwarningf("couldn't read from epsf file %s\n", str);
87 free(us->data);
88 free(us);
89 us = NULL;
90 }
91 } else {
92 agwarningf("BoundingBox not found in epsf file %s\n", str);
93 us = NULL;
94 }
95 fclose(fp);
96 return us;
97}
98
100{
101 epsf_t *desc;
102 const char *str;
103
104 if ((str = safefile(agget(n, "shapefile")))) {
106 if (!us)
107 return;
108 const double dx = us->w;
109 const double dy = us->h;
110 ND_width(n) = PS2INCH(dx);
111 ND_height(n) = PS2INCH(dy);
112 ND_shape_info(n) = desc = gv_alloc(sizeof(epsf_t));
113 desc->macro_id = us->macro_id;
114 desc->offset.x = -us->x - dx / 2;
115 desc->offset.y = -us->y - dy / 2;
116 } else
117 agwarningf("shapefile not set or not found for epsf node %s\n", agnameof(n));
118}
119
121{
122
124}
125
126
127/* cat_libfile:
128 * Write library files onto the given file pointer.
129 * arglib is an NULL-terminated array of char*
130 * Each non-trivial entry should be the name of a file to be included.
131 * stdlib is an NULL-terminated array of char*
132 * Each of these is a line of a standard library to be included.
133 * If any item in arglib is the empty string, the stdlib is not used.
134 * The stdlib is printed first, if used, followed by the user libraries.
135 * We check that for web-safe file usage.
136 */
137void cat_libfile(GVJ_t * job, const char **arglib, const char **stdlib)
138{
139 FILE *fp;
140 const char *p;
141 bool use_stdlib = true;
142
143 /* check for empty string to turn off stdlib */
144 if (arglib) {
145 for (int i = 0; use_stdlib && (p = arglib[i]); i++) {
146 if (*p == '\0')
147 use_stdlib = false;
148 }
149 }
150 if (use_stdlib)
151 for (const char **s = stdlib; *s; s++) {
152 gvputs(job, *s);
153 gvputs(job, "\n");
154 }
155 if (arglib) {
156 for (int i = 0; (p = arglib[i]) != 0; i++) {
157 if (*p == '\0')
158 continue; /* ignore empty string */
159 const char *safepath = safefile(p); /* make sure filename is okay */
160 if (!safepath) {
161 agwarningf("can't find library file %s\n", p);
162 }
163 else if ((fp = gv_fopen(safepath, "r"))) {
164 while (true) {
165 char bp[BUFSIZ] = {0};
166 size_t r = fread(bp, 1, sizeof(bp), fp);
167 gvwrite(job, bp, r);
168 if (r < sizeof(bp)) {
169 break;
170 }
171 }
172 gvputs(job, "\n"); /* append a newline just in case */
173 fclose (fp);
174 } else
175 agwarningf("can't open library file %s\n", safepath);
176 }
177 }
178}
179
180/* this removes EPSF DSC comments that, when nested in another
181 * document, cause errors in Ghostview and other Postscript
182 * processors (although legal according to the Adobe EPSF spec).
183 *
184 * N.B. PostScript lines can end with \n, \r or \r\n.
185 */
187{
188 char *p = us->data;
189 while (*p) {
190 /* skip %%EOF lines */
191 if (!strncasecmp(p, "%%EOF", 5) || !strncasecmp(p, "%%BEGIN", 7) ||
192 !strncasecmp(p, "%%END", 5) || !strncasecmp(p, "%%TRAILER", 9)) {
193 /* check for *p since last line might not end in '\n' */
194 while (*p != '\0' && *p != '\r' && *p != '\n') p++;
195 if (*p == '\r' && p[1] == '\n') p += 2;
196 else if (*p) p++;
197 continue;
198 }
199 /* output line */
200 while (*p != '\0' && *p != '\r' && *p != '\n') {
201 gvputc(job, *p);
202 p++;
203 }
204 if (*p == '\r' && p[1] == '\n') p += 2;
205 else if (*p) p++;
206 gvputc(job, '\n');
207 }
208}
209
211{
212 if (!EPSF_contents)
213 return;
214 for (usershape_t *us = dtfirst(EPSF_contents); us; us = dtnext(EPSF_contents, us)) {
215 if (us->must_inline)
216 continue;
217 gvprintf(job, "/user_shape_%d {\n", us->macro_id);
218 gvputs(job, "%%BeginDocument:\n");
219 epsf_emit_body(job, us);
220 gvputs(job, "%%EndDocument\n");
221 gvputs(job, "} bind def\n");
222 }
223}
224
226
227/* charsetOf:
228 * Assuming legal utf-8 input, determine if
229 * the character value range is ascii, latin-1 or otherwise.
230 */
231static int
233{
234 int r = ASCII;
235 unsigned char c;
236
237 while ((c = *(unsigned char*)s++)) {
238 if (c < 0x7F)
239 continue;
240 else if ((c & 0xFC) == 0xC0) {
241 r = LATIN1;
242 s++; /* eat second byte */
243 }
244 else return NONLATIN;
245 }
246 return r;
247}
248
249char *ps_string(char *ins, int chset)
250{
251 char *base;
252 static atomic_flag warned;
253
254 switch (chset) {
255 case CHAR_UTF8 :
256 base = ins;
257 break;
258 case CHAR_LATIN1 :
259 base = utf8ToLatin1 (ins);
260 break;
261 default :
262 switch (charsetOf (ins)) {
263 case ASCII :
264 base = ins;
265 break;
266 case LATIN1 :
267 base = utf8ToLatin1 (ins);
268 break;
269 case NONLATIN :
270 if (!atomic_flag_test_and_set(&warned)) {
271 agwarningf("UTF-8 input uses non-Latin1 characters which cannot be handled by this PostScript driver\n");
272 }
273 base = ins;
274 break;
275 default:
276 base = ins;
277 break;
278 }
279 }
280
281 agxbuf xb = {0};
282 agxbputc (&xb, LPAREN);
283 char *s = base;
284 while (*s) {
285 if (*s == LPAREN || *s == RPAREN || *s == '\\')
286 agxbputc (&xb, '\\');
287 agxbputc (&xb, *s++);
288 }
289 agxbputc (&xb, RPAREN);
290 if (base != ins) free (base);
291 return agxbdisown(&xb);
292}
static int agxbputc(agxbuf *xb, char c)
add character to buffer
Definition agxbuf.h:295
static char * agxbdisown(agxbuf *xb)
Definition agxbuf.h:345
Memory allocation wrappers that exit on failure.
static void * gv_calloc(size_t nmemb, size_t size)
Definition alloc.h:26
static void * gv_alloc(size_t size)
Definition alloc.h:47
#define dtmatch(d, o)
Definition cdt.h:185
#define dtinsert(d, o)
Definition cdt.h:186
CDT_API Dtmethod_t * Dtoset
ordered set (self-adjusting tree)
Definition dttree.c:306
CDT_API Dt_t * dtopen(Dtdisc_t *, Dtmethod_t *)
Definition dtopen.c:11
#define dtnext(d, o)
Definition cdt.h:181
#define dtfirst(d)
Definition cdt.h:180
const char * safefile(const char *filename)
Definition utils.c:266
char * utf8ToLatin1(char *s)
Definition utils.c:1282
#define CHAR_UTF8
Definition const.h:187
#define CHAR_LATIN1
Definition const.h:188
#define RPAREN
Definition const.h:16
#define LPAREN
Definition const.h:15
static float dy
Definition draw.c:43
static float dx
Definition draw.c:42
static void ins(Dict_t *d, Dtlink_t **set, Agedge_t *e)
Definition edge.c:151
#define PS2INCH(a_points)
Definition geom.h:64
void free(void *)
node NULL
Definition grammar.y:181
char * agget(void *obj, char *name)
Definition attr.c:447
void agwarningf(const char *fmt,...)
Definition agerror.c:175
#define ND_height(n)
Definition types.h:498
#define ND_width(n)
Definition types.h:536
#define ND_shape_info(n)
Definition types.h:529
char * agnameof(void *)
returns a string descriptor for the object.
Definition id.c:145
FILE * gv_fopen(const char *filename, const char *mode)
Definition gv_fopen.c:34
wrapper around fopen for internal library usage
size_t gvwrite(GVJ_t *job, const char *s, size_t len)
Definition gvdevice.c:182
int gvputc(GVJ_t *job, int c)
Definition gvdevice.c:298
int gvputs(GVJ_t *job, const char *s)
Definition gvdevice.c:266
void gvprintf(GVJ_t *job, const char *format,...)
Definition gvdevice.c:402
textitem scanner parser str
Definition htmlparse.y:218
static void ps_image_free(void *shape)
Definition psusershape.c:28
void epsf_free(node_t *n)
static Dict_t * EPSF_contents
Definition psusershape.c:26
static Dtdisc_t ImageDictDisc
Definition psusershape.c:33
void epsf_define(GVJ_t *job)
@ NONLATIN
@ LATIN1
@ ASCII
void epsf_init(node_t *n)
Definition psusershape.c:99
static usershape_t * user_init(const char *str)
Definition psusershape.c:39
char * ps_string(char *ins, int chset)
void cat_libfile(GVJ_t *job, const char **arglib, const char **stdlib)
void epsf_emit_body(GVJ_t *job, usershape_t *us)
static int N_EPSF_files
Definition psusershape.c:25
static int charsetOf(char *s)
platform abstraction for case-insensitive string functions
Definition cdt.h:98
int key
Definition cdt.h:85
pointf offset
Definition render.h:46
int macro_id
Definition render.h:45
double x
Definition geom.h:29
double y
Definition geom.h:29
const char * name
Definition usershape.h:54
bool must_inline
Definition usershape.h:56
void * data
Definition usershape.h:63
double x
Definition usershape.h:61
double y
Definition usershape.h:61
double h
Definition usershape.h:61
double w
Definition usershape.h:61
Definition grammar.c:90