|
Graphviz
2.29.20120524.0446
|
00001 /* $Id$ $Revision$ */ 00002 /* vim:set shiftwidth=4 ts=8: */ 00003 00004 /************************************************************************* 00005 * Copyright (c) 2011 AT&T Intellectual Property 00006 * All rights reserved. This program and the accompanying materials 00007 * are made available under the terms of the Eclipse Public License v1.0 00008 * which accompanies this distribution, and is available at 00009 * http://www.eclipse.org/legal/epl-v10.html 00010 * 00011 * Contributors: See CVS logs. Details at http://www.graphviz.org/ 00012 *************************************************************************/ 00013 00014 #ifndef WIN32 00015 #include <unistd.h> 00016 #endif 00017 00018 #include <sys/stat.h> 00019 00020 #include "render.h" 00021 #include "gvio.h" 00022 00023 static int N_EPSF_files; 00024 static Dict_t *EPSF_contents; 00025 00026 static void ps_image_free(Dict_t * dict, usershape_t * p, Dtdisc_t * disc) 00027 { 00028 free(p->data); 00029 } 00030 00031 static Dtdisc_t ImageDictDisc = { 00032 offsetof(usershape_t, name),/* key */ 00033 -1, /* size */ 00034 0, /* link offset */ 00035 NIL(Dtmake_f), 00036 (Dtfree_f) ps_image_free, 00037 NIL(Dtcompar_f), 00038 NIL(Dthash_f), 00039 NIL(Dtmemory_f), 00040 NIL(Dtevent_f) 00041 }; 00042 00043 static usershape_t *user_init(const char *str) 00044 { 00045 char *contents; 00046 char line[BUFSIZ]; 00047 FILE *fp; 00048 struct stat statbuf; 00049 int saw_bb, must_inline, rc; 00050 int lx, ly, ux, uy; 00051 usershape_t *us; 00052 00053 if (!EPSF_contents) 00054 EPSF_contents = dtopen(&ImageDictDisc, Dtoset); 00055 00056 us = dtmatch(EPSF_contents, str); 00057 if (us) 00058 return us; 00059 00060 if (!(fp = fopen(str, "r"))) { 00061 agerr(AGWARN, "couldn't open epsf file %s\n", str); 00062 return NULL; 00063 } 00064 /* try to find size */ 00065 saw_bb = must_inline = FALSE; 00066 while (fgets(line, sizeof(line), fp)) { 00067 if (sscanf 00068 (line, "%%%%BoundingBox: %d %d %d %d", &lx, &ly, &ux, &uy) == 4) { 00069 saw_bb = TRUE; 00070 } 00071 if ((line[0] != '%') && strstr(line,"read")) must_inline = TRUE; 00072 if (saw_bb && must_inline) break; 00073 } 00074 00075 if (saw_bb) { 00076 us = GNEW(usershape_t); 00077 us->x = lx; 00078 us->y = ly; 00079 us->w = ux - lx; 00080 us->y = uy - ly; 00081 us->name = str; 00082 us->macro_id = N_EPSF_files++; 00083 fstat(fileno(fp), &statbuf); 00084 contents = us->data = N_GNEW(statbuf.st_size + 1, char); 00085 fseek(fp, 0, SEEK_SET); 00086 rc = fread(contents, statbuf.st_size, 1, fp); 00087 contents[statbuf.st_size] = '\0'; 00088 dtinsert(EPSF_contents, us); 00089 us->must_inline = must_inline; 00090 } else { 00091 agerr(AGWARN, "BoundingBox not found in epsf file %s\n", str); 00092 us = NULL; 00093 } 00094 fclose(fp); 00095 return us; 00096 } 00097 00098 void epsf_init(node_t * n) 00099 { 00100 epsf_t *desc; 00101 const char *str; 00102 usershape_t *us; 00103 int dx, dy; 00104 00105 if ((str = safefile(agget(n, "shapefile")))) { 00106 us = user_init(str); 00107 if (!us) 00108 return; 00109 dx = us->w; 00110 dy = us->h; 00111 ND_width(n) = PS2INCH(dx); 00112 ND_height(n) = PS2INCH(dy); 00113 ND_shape_info(n) = desc = NEW(epsf_t); 00114 desc->macro_id = us->macro_id; 00115 desc->offset.x = -us->x - (dx) / 2; 00116 desc->offset.y = -us->y - (dy) / 2; 00117 } else 00118 agerr(AGWARN, "shapefile not set or not found for epsf node %s\n", agnameof(n)); 00119 } 00120 00121 void epsf_free(node_t * n) 00122 { 00123 00124 if (ND_shape_info(n)) 00125 free(ND_shape_info(n)); 00126 } 00127 00128 00129 /* cat_libfile: 00130 * Write library files onto the given file pointer. 00131 * arglib is an NULL-terminated array of char* 00132 * Each non-trivial entry should be the name of a file to be included. 00133 * stdlib is an NULL-terminated array of char* 00134 * Each of these is a line of a standard library to be included. 00135 * If any item in arglib is the empty string, the stdlib is not used. 00136 * The stdlib is printed first, if used, followed by the user libraries. 00137 * We check that for web-safe file usage. 00138 */ 00139 void cat_libfile(GVJ_t * job, const char **arglib, const char **stdlib) 00140 { 00141 FILE *fp; 00142 const char **s, *bp, *p, *path; 00143 int i; 00144 boolean use_stdlib = TRUE; 00145 00146 /* check for empty string to turn off stdlib */ 00147 if (arglib) { 00148 for (i = 0; use_stdlib && ((p = arglib[i])); i++) { 00149 if (*p == '\0') 00150 use_stdlib = FALSE; 00151 } 00152 } 00153 if (use_stdlib) 00154 for (s = stdlib; *s; s++) { 00155 gvputs(job, *s); 00156 gvputs(job, "\n"); 00157 } 00158 if (arglib) { 00159 for (i = 0; (p = arglib[i]) != 0; i++) { 00160 if (*p == '\0') 00161 continue; /* ignore empty string */ 00162 path = safefile(p); /* make sure filename is okay */ 00163 if (!path) { 00164 agerr(AGWARN, "can't find library file %s\n", p); 00165 } 00166 else if ((fp = fopen(path, "r"))) { 00167 while ((bp = Fgets(fp))) 00168 gvputs(job, bp); 00169 gvputs(job, "\n"); /* append a newline just in case */ 00170 fclose (fp); 00171 } else 00172 agerr(AGWARN, "can't open library file %s\n", path); 00173 } 00174 } 00175 } 00176 00177 #define FILTER_EPSF 1 00178 #ifdef FILTER_EPSF 00179 /* this removes EPSF DSC comments that, when nested in another 00180 * document, cause errors in Ghostview and other Postscript 00181 * processors (although legal according to the Adobe EPSF spec). 00182 * 00183 * N.B. PostScript lines can end with \n, \r or \r\n. 00184 */ 00185 void epsf_emit_body(GVJ_t *job, usershape_t *us) 00186 { 00187 char *p; 00188 char c; 00189 p = us->data; 00190 while (*p) { 00191 /* skip %%EOF lines */ 00192 if ((p[0] == '%') && (p[1] == '%') 00193 && (!strncasecmp(&p[2], "EOF", 3) 00194 || !strncasecmp(&p[2], "BEGIN", 5) 00195 || !strncasecmp(&p[2], "END", 3) 00196 || !strncasecmp(&p[2], "TRAILER", 7) 00197 )) { 00198 /* check for *p since last line might not end in '\n' */ 00199 while ((c = *p) && (c != '\r') && (c != '\n')) p++; 00200 if ((*p == '\r') && (*(p+1) == '\n')) p += 2; 00201 else if (*p) p++; 00202 continue; 00203 } 00204 /* output line */ 00205 while ((c = *p) && (c != '\r') && (c != '\n')) { 00206 gvputc(job, c); 00207 p++; 00208 } 00209 if ((*p == '\r') && (*(p+1) == '\n')) p += 2; 00210 else if (*p) p++; 00211 gvputc(job, '\n'); 00212 } 00213 } 00214 #else 00215 void epsf_emit_body(GVJ_t *job, usershape_t *us) 00216 { 00217 gvputs(job, us->data); 00218 } 00219 #endif 00220 00221 void epsf_define(GVJ_t *job) 00222 { 00223 usershape_t *us; 00224 00225 if (!EPSF_contents) 00226 return; 00227 for (us = dtfirst(EPSF_contents); us; us = dtnext(EPSF_contents, us)) { 00228 if (us->must_inline) 00229 continue; 00230 gvprintf(job, "/user_shape_%d {\n", us->macro_id); 00231 gvputs(job, "%%BeginDocument:\n"); 00232 epsf_emit_body(job, us); 00233 gvputs(job, "%%EndDocument\n"); 00234 gvputs(job, "} bind def\n"); 00235 } 00236 } 00237 00238 enum {ASCII, LATIN1, NONLATIN}; 00239 00240 /* charsetOf: 00241 * Assuming legal utf-8 input, determine if 00242 * the character value range is ascii, latin-1 or otherwise. 00243 */ 00244 static int 00245 charsetOf (char* s) 00246 { 00247 int r = ASCII; 00248 unsigned char c; 00249 00250 while ((c = *(unsigned char*)s++)) { 00251 if (c < 0x7F) 00252 continue; 00253 else if ((c & 0xFC) == 0xC0) { 00254 r = LATIN1; 00255 s++; /* eat second byte */ 00256 } 00257 else return NONLATIN; 00258 } 00259 return r; 00260 } 00261 00262 char *ps_string(char *ins, int latin) 00263 { 00264 char *s; 00265 char *base; 00266 static agxbuf xb; 00267 static int warned; 00268 int rc; 00269 00270 if (latin) 00271 base = utf8ToLatin1 (ins); 00272 else { 00273 switch (charsetOf (ins)) { 00274 case ASCII : 00275 base = ins; 00276 break; 00277 case LATIN1 : 00278 base = utf8ToLatin1 (ins); 00279 break; 00280 case NONLATIN : 00281 if (!warned) { 00282 agerr (AGWARN, "UTF-8 input uses non-Latin1 characters which cannot be handled by this PostScript driver\n"); 00283 warned = 1; 00284 } 00285 base = ins; 00286 break; 00287 default: 00288 base = ins; 00289 break; 00290 } 00291 } 00292 00293 if (xb.buf == NULL) 00294 agxbinit (&xb, 0, NULL); 00295 00296 rc = agxbputc (&xb, LPAREN); 00297 s = base; 00298 while (*s) { 00299 if ((*s == LPAREN) || (*s == RPAREN) || (*s == '\\')) 00300 rc = agxbputc (&xb, '\\'); 00301 rc = agxbputc (&xb, *s++); 00302 } 00303 agxbputc (&xb, RPAREN); 00304 if (base != ins) free (base); 00305 s = agxbuse(&xb); 00306 return s; 00307 }
1.7.5