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