Graphviz 14.1.3~dev.20260201.0907
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 "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 rewind(fp);
80 size_t rc = fread(contents, (size_t)statbuf.st_size, 1, fp);
81 if (rc == 1) {
82 contents[statbuf.st_size] = '\0';
84 us->must_inline = must_inline;
85 }
86 else {
87 agwarningf("couldn't read from epsf file %s\n", str);
88 free(us->data);
89 free(us);
90 us = NULL;
91 }
92 } else {
93 agwarningf("BoundingBox not found in epsf file %s\n", str);
94 us = NULL;
95 }
96 fclose(fp);
97 return us;
98}
99
101{
102 epsf_t *desc;
103 const char *str;
104
105 if ((str = safefile(agget(n, "shapefile")))) {
107 if (!us)
108 return;
109 const double dx = us->w;
110 const double dy = us->h;
111 ND_width(n) = PS2INCH(dx);
112 ND_height(n) = PS2INCH(dy);
113 ND_shape_info(n) = desc = gv_alloc(sizeof(epsf_t));
114 desc->macro_id = us->macro_id;
115 desc->offset.x = -us->x - dx / 2;
116 desc->offset.y = -us->y - dy / 2;
117 } else
118 agwarningf("shapefile not set or not found for epsf node %s\n", agnameof(n));
119}
120
122{
123
125}
126
127
128/* cat_libfile:
129 * Write library files onto the given file pointer.
130 * arglib is an NULL-terminated array of char*
131 * Each non-trivial entry should be the name of a file to be included.
132 * stdlib is an NULL-terminated array of char*
133 * Each of these is a line of a standard library to be included.
134 * If any item in arglib is the empty string, the stdlib is not used.
135 * The stdlib is printed first, if used, followed by the user libraries.
136 * We check that for web-safe file usage.
137 */
138void cat_libfile(GVJ_t * job, const char **arglib, const char **stdlib)
139{
140 FILE *fp;
141 const char *p;
142 bool use_stdlib = true;
143
144 /* check for empty string to turn off stdlib */
145 if (arglib) {
146 for (int i = 0; use_stdlib && (p = arglib[i]); i++) {
147 if (*p == '\0')
148 use_stdlib = false;
149 }
150 }
151 if (use_stdlib)
152 for (const char **s = stdlib; *s; s++) {
153 gvputs(job, *s);
154 gvputs(job, "\n");
155 }
156 if (arglib) {
157 for (int i = 0; (p = arglib[i]) != 0; i++) {
158 if (*p == '\0')
159 continue; /* ignore empty string */
160 const char *safepath = safefile(p); /* make sure filename is okay */
161 if (!safepath) {
162 agwarningf("can't find library file %s\n", p);
163 }
164 else if ((fp = gv_fopen(safepath, "r"))) {
165 while (true) {
166 char bp[BUFSIZ] = {0};
167 size_t r = fread(bp, 1, sizeof(bp), fp);
168 gvwrite(job, bp, r);
169 if (r < sizeof(bp)) {
170 break;
171 }
172 }
173 gvputs(job, "\n"); /* append a newline just in case */
174 fclose (fp);
175 } else
176 agwarningf("can't open library file %s\n", safepath);
177 }
178 }
179}
180
181/* this removes EPSF DSC comments that, when nested in another
182 * document, cause errors in Ghostview and other Postscript
183 * processors (although legal according to the Adobe EPSF spec).
184 *
185 * N.B. PostScript lines can end with \n, \r or \r\n.
186 */
188{
189 char *p = us->data;
190 while (*p) {
191 /* skip %%EOF lines */
192 if (!strncasecmp(p, "%%EOF", 5) || !strncasecmp(p, "%%BEGIN", 7) ||
193 !strncasecmp(p, "%%END", 5) || !strncasecmp(p, "%%TRAILER", 9)) {
194 /* check for *p since last line might not end in '\n' */
195 while (*p != '\0' && *p != '\r' && *p != '\n') p++;
196 if (*p == '\r' && p[1] == '\n') p += 2;
197 else if (*p) p++;
198 continue;
199 }
200 /* output line */
201 while (*p != '\0' && *p != '\r' && *p != '\n') {
202 gvputc(job, *p);
203 p++;
204 }
205 if (*p == '\r' && p[1] == '\n') p += 2;
206 else if (*p) p++;
207 gvputc(job, '\n');
208 }
209}
210
212{
213 if (!EPSF_contents)
214 return;
215 for (usershape_t *us = dtfirst(EPSF_contents); us; us = dtnext(EPSF_contents, us)) {
216 if (us->must_inline)
217 continue;
218 gvprintf(job, "/user_shape_%d {\n", us->macro_id);
219 gvputs(job, "%%BeginDocument:\n");
220 epsf_emit_body(job, us);
221 gvputs(job, "%%EndDocument\n");
222 gvputs(job, "} bind def\n");
223 }
224}
225
227
228/* charsetOf:
229 * Assuming legal utf-8 input, determine if
230 * the character value range is ascii, latin-1 or otherwise.
231 */
232static int
234{
235 int r = ASCII;
236 unsigned char c;
237
238 while ((c = *(unsigned char*)s++)) {
239 if (c < 0x7F)
240 continue;
241 else if ((c & 0xFC) == 0xC0) {
242 r = LATIN1;
243 s++; /* eat second byte */
244 }
245 else return NONLATIN;
246 }
247 return r;
248}
249
250char *ps_string(char *ins, int chset)
251{
252 char *base;
253 static atomic_flag warned;
254
255 switch (chset) {
256 case CHAR_UTF8 :
257 base = ins;
258 break;
259 case CHAR_LATIN1 :
260 base = utf8ToLatin1 (ins);
261 break;
262 default :
263 switch (charsetOf (ins)) {
264 case ASCII :
265 base = ins;
266 break;
267 case LATIN1 :
268 base = utf8ToLatin1 (ins);
269 break;
270 case NONLATIN :
271 if (!atomic_flag_test_and_set(&warned)) {
272 agwarningf("UTF-8 input uses non-Latin1 characters which cannot be handled by this PostScript driver\n");
273 }
274 base = ins;
275 break;
276 default:
277 base = ins;
278 break;
279 }
280 }
281
282 agxbuf xb = {0};
283 agxbputc (&xb, LPAREN);
284 char *s = base;
285 while (*s) {
286 if (*s == LPAREN || *s == RPAREN || *s == '\\')
287 agxbputc (&xb, '\\');
288 agxbputc (&xb, *s++);
289 }
290 agxbputc (&xb, RPAREN);
291 if (base != ins) free (base);
292 return agxbdisown(&xb);
293}
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:265
char * utf8ToLatin1(char *s)
Definition utils.c:1292
#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:450
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)
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