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