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