1 /* libsvg - Library for parsing/rendering SVG documents
2 
3    Copyright � 2002 USC/Information Sciences Institute
4 
5    This program is free software; you can redistribute it and/or
6    modify it under the terms of the GNU Library General Public License as
7    published by the Free Software Foundation; either version 2 of the
8    License, or (at your option) any later version.
9 
10    This program is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13    Library General Public License for more details.
14 
15    You should have received a copy of the GNU Library General Public
16    License along with this program; if not, write to the
17    Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18    Boston, MA 02111-1307, USA.
19 
20    Author: Carl Worth <cworth@isi.edu>
21 */
22 
23 #include <errno.h>
24 #include <fcntl.h>
25 #include <string.h>
26 #include <unistd.h>
27 #include <libgen.h>
28 #include <zlib.h>
29 #include <sys/param.h>
30 
31 #include "svgint.h"
32 
33 static svg_status_t
34 _svg_init (svg_t *svg);
35 
36 svg_status_t
svg_create(svg_t ** svg)37 svg_create (svg_t **svg)
38 {
39     *svg = malloc (sizeof (svg_t));
40     if (*svg == NULL) {
41 	return SVG_STATUS_NO_MEMORY;
42     }
43 
44     return _svg_init (*svg);
45 }
46 
47 static svg_status_t
_svg_init(svg_t * svg)48 _svg_init (svg_t *svg)
49 {
50     svg->dpi = 100;
51 
52     svg->dir_name = strdup (".");
53 
54     svg->group_element = NULL;
55 
56     _svg_parser_init (&svg->parser, svg);
57 
58     svg->engine = NULL;
59 
60     svg->element_ids = _svg_xml_hash_create (100);
61 
62     return SVG_STATUS_SUCCESS;
63 }
64 
65 static svg_status_t
_svg_deinit(svg_t * svg)66 _svg_deinit (svg_t *svg)
67 {
68     free (svg->dir_name);
69     svg->dir_name = NULL;
70 
71     if (svg->group_element)
72 	_svg_element_destroy (svg->group_element);
73 
74     _svg_parser_deinit (&svg->parser);
75 
76     svg->engine = NULL;
77 
78     _svg_xml_hash_free (svg->element_ids);
79 
80     return SVG_STATUS_SUCCESS;
81 }
82 
83 svg_status_t
svg_destroy(svg_t * svg)84 svg_destroy (svg_t *svg)
85 {
86     svg_status_t status;
87     status = _svg_deinit (svg);
88     free (svg);
89 
90     return status;
91 }
92 
93 #define SVG_PARSE_BUFFER_SIZE (8 * 1024)
94 
95 svg_status_t
svg_parse_file(svg_t * svg,FILE * file)96 svg_parse_file (svg_t *svg, FILE *file)
97 {
98     svg_status_t status = SVG_STATUS_SUCCESS;
99     gzFile zfile;
100     char buf[SVG_PARSE_BUFFER_SIZE];
101     int read;
102 
103     zfile = gzdopen (dup(fileno(file)), "r");
104     if (zfile == NULL) {
105 	switch (errno) {
106 	case ENOMEM:
107 	    return SVG_STATUS_NO_MEMORY;
108 	case ENOENT:
109 	    return SVG_STATUS_FILE_NOT_FOUND;
110 	default:
111 	    return SVG_STATUS_IO_ERROR;
112 	}
113     }
114 
115     status = svg_parse_chunk_begin (svg);
116     if (status)
117 	goto CLEANUP;
118 
119     while (! gzeof (zfile)) {
120 	read = gzread (zfile, buf, SVG_PARSE_BUFFER_SIZE);
121 	if (read > -1) {
122 	    status = svg_parse_chunk (svg, buf, read);
123 	    if (status)
124 		goto CLEANUP;
125 	} else {
126 	    status = SVG_STATUS_IO_ERROR;
127 	    goto CLEANUP;
128 	}
129     }
130 
131     status = svg_parse_chunk_end (svg);
132 
133  CLEANUP:
134     gzclose (zfile);
135     return status;
136 }
137 
138 svg_status_t
svg_parse(svg_t * svg,const char * filename)139 svg_parse (svg_t *svg, const char *filename)
140 {
141     svg_status_t status = SVG_STATUS_SUCCESS;
142     FILE *file;
143     char *tmp;
144 
145     free (svg->dir_name);
146     /* awful dirname semantics require some hoops */
147     tmp = strdup (filename);
148     svg->dir_name = strdup (dirname (tmp));
149     free (tmp);
150 
151     file = fopen (filename, "r");
152     if (file == NULL) {
153 	switch (errno) {
154 	case ENOMEM:
155 	    return SVG_STATUS_NO_MEMORY;
156 	case ENOENT:
157 	    return SVG_STATUS_FILE_NOT_FOUND;
158 	default:
159 	    return SVG_STATUS_IO_ERROR;
160 	}
161     }
162     status = svg_parse_file (svg, file);
163     fclose (file);
164     return status;
165 }
166 
167 svg_status_t
svg_parse_buffer(svg_t * svg,const char * buf,size_t count)168 svg_parse_buffer (svg_t *svg, const char *buf, size_t count)
169 {
170     svg_status_t status;
171 
172     status = svg_parse_chunk_begin (svg);
173     if (status)
174 	return status;
175 
176     status = svg_parse_chunk (svg, buf, count);
177     if (status)
178 	return status;
179 
180     status = svg_parse_chunk_end (svg);
181 
182     return status;
183 }
184 
185 svg_status_t
svg_parse_chunk_begin(svg_t * svg)186 svg_parse_chunk_begin (svg_t *svg)
187 {
188     return _svg_parser_begin (&svg->parser);
189 }
190 
191 svg_status_t
svg_parse_chunk(svg_t * svg,const char * buf,size_t count)192 svg_parse_chunk (svg_t *svg, const char *buf, size_t count)
193 {
194     return _svg_parser_parse_chunk (&svg->parser, buf, count);
195 }
196 
197 svg_status_t
svg_parse_chunk_end(svg_t * svg)198 svg_parse_chunk_end (svg_t *svg)
199 {
200     return _svg_parser_end (&svg->parser);
201 }
202 
203 svg_status_t
svg_render(svg_t * svg,svg_render_engine_t * engine,void * closure)204 svg_render (svg_t		*svg,
205 	    svg_render_engine_t	*engine,
206 	    void		*closure)
207 {
208     svg_status_t status;
209     char orig_dir[MAXPATHLEN];
210 
211     if (svg->group_element == NULL)
212 	return SVG_STATUS_SUCCESS;
213 
214     /* XXX: Currently, the SVG parser doesn't resolve relative URLs
215        properly, so I'll just cheese things in by changing the current
216        directory -- at least I'll be nice about it and restore it
217        afterwards. */
218 
219     getcwd (orig_dir, MAXPATHLEN);
220     chdir (svg->dir_name);
221 
222     status = svg_element_render (svg->group_element, engine, closure);
223 
224     chdir (orig_dir);
225 
226     return status;
227 }
228 
229 svg_status_t
_svg_store_element_by_id(svg_t * svg,svg_element_t * element)230 _svg_store_element_by_id (svg_t *svg, svg_element_t *element)
231 {
232     _svg_xml_hash_add_entry (svg->element_ids,
233 			     (unsigned char *)element->id,
234 			     element);
235 
236     return SVG_STATUS_SUCCESS;
237 }
238 
239 svg_status_t
_svg_fetch_element_by_id(svg_t * svg,const char * id,svg_element_t ** element_ret)240 _svg_fetch_element_by_id (svg_t *svg, const char *id, svg_element_t **element_ret)
241 {
242     *element_ret = _svg_xml_hash_lookup (svg->element_ids, (unsigned char *)id);
243 
244     return SVG_STATUS_SUCCESS;
245 }
246 
247 void
svg_get_size(svg_t * svg,svg_length_t * width,svg_length_t * height)248 svg_get_size (svg_t *svg, svg_length_t *width, svg_length_t *height)
249 {
250     if (svg->group_element) {
251 	_svg_group_get_size (&svg->group_element->e.group, width, height);
252     } else {
253 	_svg_length_init (width, 0.0);
254 	_svg_length_init (height, 0.0);
255     }
256 }
257