Bug Summary

File:svgtiny.c
Warning:line 954, column 4
Value stored to 'res' is never read

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-pc-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name svgtiny.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -pic-is-pie -mframe-pointer=none -fmath-errno -ffp-contract=on -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-dir=/var/lib/jenkins/workspace/scan-build-libsvgtiny -resource-dir /usr/lib/llvm-14/lib/clang/14.0.6 -D _BSD_SOURCE -D _DEFAULT_SOURCE -I /var/lib/jenkins/workspace/scan-build-libsvgtiny/include/ -I /var/lib/jenkins/workspace/scan-build-libsvgtiny/src -D _ALIGNED=__attribute__((aligned)) -D STMTEXPR=1 -D DEBUG -I /var/lib/jenkins/artifacts-x86_64-linux-gnu/include -internal-isystem /usr/lib/llvm-14/lib/clang/14.0.6/include -internal-isystem /usr/local/include -internal-isystem /usr/bin/../lib/gcc/x86_64-linux-gnu/12/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -Og -Wwrite-strings -Wno-error -std=c99 -fconst-strings -fdebug-compilation-dir=/var/lib/jenkins/workspace/scan-build-libsvgtiny -ferror-limit 19 -fgnuc-version=4.2.1 -analyzer-display-progress -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /var/lib/jenkins/workspace/scan-build-libsvgtiny/clangScanBuildReports/2024-12-27-083421-3320267-1 -x c src/svgtiny.c
1/*
2 * This file is part of Libsvgtiny
3 * Licensed under the MIT License,
4 * http://opensource.org/licenses/mit-license.php
5 * Copyright 2008-2009 James Bursa <james@semichrome.net>
6 * Copyright 2012 Daniel Silverstone <dsilvers@netsurf-browser.org>
7 * Copyright 2024 Vincent Sanders <vince@netsurf-browser.org>
8 */
9
10#include <assert.h>
11#include <math.h>
12#include <setjmp.h>
13#include <stdbool.h>
14#include <stdio.h>
15#include <stdlib.h>
16#include <string.h>
17
18#include <dom/dom.h>
19#include <dom/bindings/xml/xmlparser.h>
20
21#include "svgtiny.h"
22#include "svgtiny_internal.h"
23
24
25/* circles are approximated with four bezier curves
26 *
27 * The optimal distance to the control points is the constant (4/3)*tan(pi/(2n))
28 * (where n is 4)
29 */
30#define KAPPA0.5522847498 0.5522847498
31
32/* debug flag which enables printing of libdom parse messages to stderr */
33#undef PRINT_XML_PARSE_MSG
34
35#if (defined(_GNU_SOURCE) && !defined(__APPLE__) || defined(__amigaos4__) || defined(__HAIKU__) || (defined(_POSIX_C_SOURCE200809L) && ((_POSIX_C_SOURCE200809L - 0) >= 200809L)))
36#define HAVE_STRNDUP
37#else
38#undef HAVE_STRNDUP
39char *svgtiny_strndup(const char *s, size_t n);
40#define strndup svgtiny_strndup
41#endif
42
43static svgtiny_code parse_element(dom_element *element, struct svgtiny_parse_state *state);
44
45#ifndef HAVE_STRNDUP
46char *svgtiny_strndup(const char *s, size_t n)
47{
48 size_t len;
49 char *s2;
50
51 for (len = 0; len != n && s[len]; len++)
52 continue;
53
54 s2 = malloc(len + 1);
55 if (s2 == NULL((void*)0))
56 return NULL((void*)0);
57
58 memcpy(s2, s, len);
59 s2[len] = '\0';
60
61 return s2;
62}
63#endif
64
65
66/**
67 * Parse x, y, width, and height attributes, if present.
68 */
69static void
70svgtiny_parse_position_attributes(dom_element *node,
71 struct svgtiny_parse_state state,
72 float *x, float *y,
73 float *width, float *height)
74{
75 struct svgtiny_parse_internal_operation styles[] = {
76 {
77 /* x */
78 state.interned_x,
79 SVGTIOP_LENGTH,
80 &state.viewport_width,
81 x
82 },{
83 /* y */
84 state.interned_y,
85 SVGTIOP_LENGTH,
86 &state.viewport_height,
87 y
88 },{
89 /* width */
90 state.interned_width,
91 SVGTIOP_LENGTH,
92 &state.viewport_width,
93 width
94 },{
95 /* height */
96 state.interned_height,
97 SVGTIOP_LENGTH,
98 &state.viewport_height,
99 height
100 },{
101 NULL((void*)0), SVGTIOP_NONE, NULL((void*)0), NULL((void*)0)
102 },
103 };
104
105 *x = 0;
106 *y = 0;
107 *width = state.viewport_width;
108 *height = state.viewport_height;
109
110 svgtiny_parse_attributes(node, &state, styles);
111}
112
113
114/**
115 * Call this to ref the strings in a gradient state.
116 */
117static void svgtiny_grad_string_ref(struct svgtiny_parse_state_gradient *grad)
118{
119 if (grad->gradient_x1 != NULL((void*)0)) {
120 dom_string_ref(grad->gradient_x1);
121 }
122 if (grad->gradient_y1 != NULL((void*)0)) {
123 dom_string_ref(grad->gradient_y1);
124 }
125 if (grad->gradient_x2 != NULL((void*)0)) {
126 dom_string_ref(grad->gradient_x2);
127 }
128 if (grad->gradient_y2 != NULL((void*)0)) {
129 dom_string_ref(grad->gradient_y2);
130 }
131}
132
133
134/**
135 * Call this to clean up the strings in a gradient state.
136 */
137static void svgtiny_grad_string_cleanup(
138 struct svgtiny_parse_state_gradient *grad)
139{
140 if (grad->gradient_x1 != NULL((void*)0)) {
141 dom_string_unref(grad->gradient_x1);
142 grad->gradient_x1 = NULL((void*)0);
143 }
144 if (grad->gradient_y1 != NULL((void*)0)) {
145 dom_string_unref(grad->gradient_y1);
146 grad->gradient_y1 = NULL((void*)0);
147 }
148 if (grad->gradient_x2 != NULL((void*)0)) {
149 dom_string_unref(grad->gradient_x2);
150 grad->gradient_x2 = NULL((void*)0);
151 }
152 if (grad->gradient_y2 != NULL((void*)0)) {
153 dom_string_unref(grad->gradient_y2);
154 grad->gradient_y2 = NULL((void*)0);
155 }
156}
157
158
159/**
160 * Set the local externally-stored parts of a parse state.
161 * Call this in functions that made a new state on the stack.
162 * Doesn't make own copy of global state, such as the interned string list.
163 */
164static void svgtiny_setup_state_local(struct svgtiny_parse_state *state)
165{
166 svgtiny_grad_string_ref(&(state->fill_grad));
167 svgtiny_grad_string_ref(&(state->stroke_grad));
168}
169
170
171/**
172 * Cleanup the local externally-stored parts of a parse state.
173 * Call this in functions that made a new state on the stack.
174 * Doesn't cleanup global state, such as the interned string list.
175 */
176static void svgtiny_cleanup_state_local(struct svgtiny_parse_state *state)
177{
178 svgtiny_grad_string_cleanup(&(state->fill_grad));
179 svgtiny_grad_string_cleanup(&(state->stroke_grad));
180}
181
182
183static void ignore_msg(uint32_t severity, void *ctx, const char *msg, ...)
184{
185#ifdef PRINT_XML_PARSE_MSG
186#include <stdarg.h>
187 va_list l;
188
189 UNUSED(ctx)((void) (ctx));
190
191 va_start(l, msg)__builtin_va_start(l, msg);
192
193 fprintf(stderrstderr, "%"PRIu32"u"": ", severity);
194 vfprintf(stderrstderr, msg, l);
195 fprintf(stderrstderr, "\n");
196
197 va_end(l)__builtin_va_end(l);
198#else
199 UNUSED(severity)((void) (severity));
200 UNUSED(ctx)((void) (ctx));
201 UNUSED(msg)((void) (msg));
202#endif
203}
204
205
206/**
207 * Parse paint attributes, if present.
208 */
209static void
210svgtiny_parse_paint_attributes(dom_element *node,
211 struct svgtiny_parse_state *state)
212{
213 struct svgtiny_parse_internal_operation ops[] = {
214 {
215 /* fill color */
216 state->interned_fill,
217 SVGTIOP_PAINT,
218 &state->fill_grad,
219 &state->fill
220 }, {
221 /* stroke color */
222 state->interned_stroke,
223 SVGTIOP_PAINT,
224 &state->stroke_grad,
225 &state->stroke
226 }, {
227 /* stroke width */
228 state->interned_stroke_width,
229 SVGTIOP_INTLENGTH,
230 &state->viewport_width,
231 &state->stroke_width
232 },{
233 NULL((void*)0), SVGTIOP_NONE, NULL((void*)0), NULL((void*)0)
234 },
235 };
236
237 svgtiny_parse_attributes(node, state, ops);
238 svgtiny_parse_inline_style(node, state, ops);
239}
240
241
242/**
243 * Parse font attributes, if present.
244 */
245static void
246svgtiny_parse_font_attributes(dom_element *node,
247 struct svgtiny_parse_state *state)
248{
249 /* TODO: Implement this, it never used to be */
250 UNUSED(node)((void) (node));
251 UNUSED(state)((void) (state));
252#ifdef WRITTEN_THIS_PROPERLY
253 const xmlAttr *attr;
254
255 UNUSED(state)((void) (state));
256
257 for (attr = node->properties; attr; attr = attr->next) {
258 if (strcmp((const char *) attr->name, "font-size") == 0) {
259 /*if (css_parse_length(
260 (const char *) attr->children->content,
261 &state->style.font_size.value.length,
262 true, true)) {
263 state->style.font_size.size =
264 CSS_FONT_SIZE_LENGTH;
265 }*/
266 }
267 }
268#endif
269}
270
271
272/**
273 * Parse transform attributes, if present.
274 *
275 * http://www.w3.org/TR/SVG11/coords#TransformAttribute
276 */
277static void
278svgtiny_parse_transform_attributes(dom_element *node,
279 struct svgtiny_parse_state *state)
280{
281 dom_string *attr;
282 dom_exception exc;
283
284 exc = dom_element_get_attribute(node, state->interned_transform, &attr)dom_element_get_attribute( (dom_element *) (node), (state->
interned_transform), (&attr))
;
285 if (exc == DOM_NO_ERR && attr != NULL((void*)0)) {
286 svgtiny_parse_transform(dom_string_data(attr),
287 dom_string_byte_length(attr),
288 &state->ctm);
289
290 dom_string_unref(attr);
291 }
292}
293
294
295/**
296 * Add a path to the svgtiny_diagram.
297 */
298static svgtiny_code
299svgtiny_add_path(float *p, unsigned int n, struct svgtiny_parse_state *state)
300{
301 struct svgtiny_shape *shape;
302 svgtiny_code res = svgtiny_OK;
303
304 if (state->fill == svgtiny_LINEAR_GRADIENT0x2000000) {
305 /* adds a shape to fill the path with a linear gradient */
306 res = svgtiny_gradient_add_fill_path(p, n, state);
307 }
308 if (res != svgtiny_OK) {
309 free(p);
310 return res;
311 }
312
313 if (state->stroke == svgtiny_LINEAR_GRADIENT0x2000000) {
314 /* adds a shape to stroke the path with a linear gradient */
315 res = svgtiny_gradient_add_stroke_path(p, n, state);
316 }
317 if (res != svgtiny_OK) {
318 free(p);
319 return res;
320 }
321
322 /* if stroke and fill are transparent do not add a shape */
323 if ((state->fill == svgtiny_TRANSPARENT0x1000000) &&
324 (state->stroke == svgtiny_TRANSPARENT0x1000000)) {
325 free(p);
326 return res;
327 }
328
329 svgtiny_transform_path(p, n, state);
330
331 shape = svgtiny_add_shape(state);
332 if (shape == NULL((void*)0)) {
333 free(p);
334 return svgtiny_OUT_OF_MEMORY;
335 }
336 shape->path = p;
337 shape->path_length = n;
338 state->diagram->shape_count++;
339
340
341 return svgtiny_OK;
342}
343
344
345/**
346 * return svgtiny_OK if source is an ancestor of target else svgtiny_LIBDOM_ERROR
347 */
348static svgtiny_code is_ancestor_node(dom_node *source, dom_node *target)
349{
350 dom_node *parent;
351 dom_exception exc;
352
353 parent = dom_node_ref(target)dom_node_ref((dom_node *) (target));
354 while (parent != NULL((void*)0)) {
355 dom_node *next = NULL((void*)0);
356 if (parent == source) {
357 dom_node_unref(parent)dom_node_unref((dom_node *) (parent));
358 return svgtiny_OK;
359 }
360 exc = dom_node_get_parent_node(parent, &next)dom_node_get_parent_node( (dom_node *) (parent), (dom_node **
) (&next))
;
361 dom_node_unref(parent)dom_node_unref((dom_node *) (parent));
362 if (exc != DOM_NO_ERR) {
363 break;
364 }
365
366 parent = next;
367 }
368 return svgtiny_LIBDOM_ERROR;
369}
370
371
372/**
373 * Parse a <path> element node.
374 *
375 * https://svgwg.org/svg2-draft/paths.html#PathElement
376 */
377static svgtiny_code
378svgtiny_parse_path(dom_element *path, struct svgtiny_parse_state state)
379{
380 svgtiny_code res;
381 dom_string *path_d_str;
382 dom_exception exc;
383 float *p; /* path elemets */
384 unsigned int i;
385
386 svgtiny_setup_state_local(&state);
387
388 svgtiny_parse_paint_attributes(path, &state);
389 svgtiny_parse_transform_attributes(path, &state);
390
391 /* read d attribute */
392 exc = dom_element_get_attribute(path, state.interned_d, &path_d_str)dom_element_get_attribute( (dom_element *) (path), (state.interned_d
), (&path_d_str))
;
393 if (exc != DOM_NO_ERR) {
394 state.diagram->error_line = -1; /* path->line; */
395 state.diagram->error_message = "path: error retrieving d attribute";
396 svgtiny_cleanup_state_local(&state);
397 return svgtiny_SVG_ERROR;
398 }
399
400 if (path_d_str == NULL((void*)0)) {
401 state.diagram->error_line = -1; /* path->line; */
402 state.diagram->error_message = "path: missing d attribute";
403 svgtiny_cleanup_state_local(&state);
404 return svgtiny_SVG_ERROR;
405 }
406
407 res = svgtiny_parse_path_data(dom_string_data(path_d_str),
408 dom_string_byte_length(path_d_str),
409 &p,
410 &i);
411 if (res != svgtiny_OK) {
412 svgtiny_cleanup_state_local(&state);
413 return res;
414 }
415
416 if (i <= 4) {
417 /* insufficient segments in path treated as none */
418 if (i > 0) {
419 free(p);
420 }
421 res = svgtiny_OK;
422 } else {
423 res = svgtiny_add_path(p, i, &state);
424 }
425
426 svgtiny_cleanup_state_local(&state);
427
428 return res;
429}
430
431
432/**
433 * Parse a <rect> element node.
434 *
435 * http://www.w3.org/TR/SVG11/shapes#RectElement
436 */
437static svgtiny_code
438svgtiny_parse_rect(dom_element *rect, struct svgtiny_parse_state state)
439{
440 svgtiny_code err;
441 float x, y, width, height;
442 float *p;
443
444 svgtiny_setup_state_local(&state);
445
446 svgtiny_parse_position_attributes(rect, state,
447 &x, &y, &width, &height);
448 svgtiny_parse_paint_attributes(rect, &state);
449 svgtiny_parse_transform_attributes(rect, &state);
450
451 p = malloc(13 * sizeof p[0]);
452 if (!p) {
453 svgtiny_cleanup_state_local(&state);
454 return svgtiny_OUT_OF_MEMORY;
455 }
456
457 p[0] = svgtiny_PATH_MOVE;
458 p[1] = x;
459 p[2] = y;
460 p[3] = svgtiny_PATH_LINE;
461 p[4] = x + width;
462 p[5] = y;
463 p[6] = svgtiny_PATH_LINE;
464 p[7] = x + width;
465 p[8] = y + height;
466 p[9] = svgtiny_PATH_LINE;
467 p[10] = x;
468 p[11] = y + height;
469 p[12] = svgtiny_PATH_CLOSE;
470
471 err = svgtiny_add_path(p, 13, &state);
472
473 svgtiny_cleanup_state_local(&state);
474
475 return err;
476}
477
478
479/**
480 * Parse a <circle> element node.
481 */
482static svgtiny_code
483svgtiny_parse_circle(dom_element *circle, struct svgtiny_parse_state state)
484{
485 svgtiny_code err;
486 float x = 0, y = 0, r = -1;
487 float *p;
488 struct svgtiny_parse_internal_operation ops[] = {
489 {
490 state.interned_cx,
491 SVGTIOP_LENGTH,
492 &state.viewport_width,
493 &x
494 }, {
495 state.interned_cy,
496 SVGTIOP_LENGTH,
497 &state.viewport_height,
498 &y
499 }, {
500 state.interned_r,
501 SVGTIOP_LENGTH,
502 &state.viewport_width,
503 &r
504 }, {
505 NULL((void*)0), SVGTIOP_NONE, NULL((void*)0), NULL((void*)0)
506 },
507 };
508
509 svgtiny_setup_state_local(&state);
510
511 err = svgtiny_parse_attributes(circle, &state, ops);
512 if (err != svgtiny_OK) {
513 svgtiny_cleanup_state_local(&state);
514 return err;
515 }
516
517 svgtiny_parse_paint_attributes(circle, &state);
518 svgtiny_parse_transform_attributes(circle, &state);
519
520 if (r < 0) {
521 state.diagram->error_line = -1; /* circle->line; */
522 state.diagram->error_message = "circle: r missing or negative";
523 svgtiny_cleanup_state_local(&state);
524 return svgtiny_SVG_ERROR;
525 }
526 if (r == 0) {
527 svgtiny_cleanup_state_local(&state);
528 return svgtiny_OK;
529 }
530
531 p = malloc(32 * sizeof p[0]);
532 if (!p) {
533 svgtiny_cleanup_state_local(&state);
534 return svgtiny_OUT_OF_MEMORY;
535 }
536
537 p[0] = svgtiny_PATH_MOVE;
538 p[1] = x + r;
539 p[2] = y;
540 p[3] = svgtiny_PATH_BEZIER;
541 p[4] = x + r;
542 p[5] = y + r * KAPPA0.5522847498;
543 p[6] = x + r * KAPPA0.5522847498;
544 p[7] = y + r;
545 p[8] = x;
546 p[9] = y + r;
547 p[10] = svgtiny_PATH_BEZIER;
548 p[11] = x - r * KAPPA0.5522847498;
549 p[12] = y + r;
550 p[13] = x - r;
551 p[14] = y + r * KAPPA0.5522847498;
552 p[15] = x - r;
553 p[16] = y;
554 p[17] = svgtiny_PATH_BEZIER;
555 p[18] = x - r;
556 p[19] = y - r * KAPPA0.5522847498;
557 p[20] = x - r * KAPPA0.5522847498;
558 p[21] = y - r;
559 p[22] = x;
560 p[23] = y - r;
561 p[24] = svgtiny_PATH_BEZIER;
562 p[25] = x + r * KAPPA0.5522847498;
563 p[26] = y - r;
564 p[27] = x + r;
565 p[28] = y - r * KAPPA0.5522847498;
566 p[29] = x + r;
567 p[30] = y;
568 p[31] = svgtiny_PATH_CLOSE;
569
570 err = svgtiny_add_path(p, 32, &state);
571
572 svgtiny_cleanup_state_local(&state);
573
574 return err;
575}
576
577
578/**
579 * Parse an <ellipse> element node.
580 */
581static svgtiny_code
582svgtiny_parse_ellipse(dom_element *ellipse, struct svgtiny_parse_state state)
583{
584 svgtiny_code err;
585 float x = 0, y = 0, rx = -1, ry = -1;
586 float *p;
587 struct svgtiny_parse_internal_operation ops[] = {
588 {
589 state.interned_cx,
590 SVGTIOP_LENGTH,
591 &state.viewport_width,
592 &x
593 }, {
594 state.interned_cy,
595 SVGTIOP_LENGTH,
596 &state.viewport_height,
597 &y
598 }, {
599 state.interned_rx,
600 SVGTIOP_LENGTH,
601 &state.viewport_width,
602 &rx
603 }, {
604 state.interned_ry,
605 SVGTIOP_LENGTH,
606 &state.viewport_height,
607 &ry
608 }, {
609 NULL((void*)0), SVGTIOP_NONE, NULL((void*)0), NULL((void*)0)
610 },
611 };
612
613 svgtiny_setup_state_local(&state);
614
615 err = svgtiny_parse_attributes(ellipse, &state, ops);
616 if (err != svgtiny_OK) {
617 svgtiny_cleanup_state_local(&state);
618 return err;
619 }
620
621 svgtiny_parse_paint_attributes(ellipse, &state);
622 svgtiny_parse_transform_attributes(ellipse, &state);
623
624 if (rx < 0 || ry < 0) {
625 state.diagram->error_line = -1; /* ellipse->line; */
626 state.diagram->error_message = "ellipse: rx or ry missing "
627 "or negative";
628 svgtiny_cleanup_state_local(&state);
629 return svgtiny_SVG_ERROR;
630 }
631 if (rx == 0 || ry == 0) {
632 svgtiny_cleanup_state_local(&state);
633 return svgtiny_OK;
634 }
635
636 p = malloc(32 * sizeof p[0]);
637 if (!p) {
638 svgtiny_cleanup_state_local(&state);
639 return svgtiny_OUT_OF_MEMORY;
640 }
641
642 p[0] = svgtiny_PATH_MOVE;
643 p[1] = x + rx;
644 p[2] = y;
645 p[3] = svgtiny_PATH_BEZIER;
646 p[4] = x + rx;
647 p[5] = y + ry * KAPPA0.5522847498;
648 p[6] = x + rx * KAPPA0.5522847498;
649 p[7] = y + ry;
650 p[8] = x;
651 p[9] = y + ry;
652 p[10] = svgtiny_PATH_BEZIER;
653 p[11] = x - rx * KAPPA0.5522847498;
654 p[12] = y + ry;
655 p[13] = x - rx;
656 p[14] = y + ry * KAPPA0.5522847498;
657 p[15] = x - rx;
658 p[16] = y;
659 p[17] = svgtiny_PATH_BEZIER;
660 p[18] = x - rx;
661 p[19] = y - ry * KAPPA0.5522847498;
662 p[20] = x - rx * KAPPA0.5522847498;
663 p[21] = y - ry;
664 p[22] = x;
665 p[23] = y - ry;
666 p[24] = svgtiny_PATH_BEZIER;
667 p[25] = x + rx * KAPPA0.5522847498;
668 p[26] = y - ry;
669 p[27] = x + rx;
670 p[28] = y - ry * KAPPA0.5522847498;
671 p[29] = x + rx;
672 p[30] = y;
673 p[31] = svgtiny_PATH_CLOSE;
674
675 err = svgtiny_add_path(p, 32, &state);
676
677 svgtiny_cleanup_state_local(&state);
678
679 return err;
680}
681
682
683/**
684 * Parse a <line> element node.
685 */
686static svgtiny_code
687svgtiny_parse_line(dom_element *line, struct svgtiny_parse_state state)
688{
689 svgtiny_code err;
690 float x1 = 0, y1 = 0, x2 = 0, y2 = 0;
691 float *p;
692 struct svgtiny_parse_internal_operation ops[] = {
693 {
694 state.interned_x1,
695 SVGTIOP_LENGTH,
696 &state.viewport_width,
697 &x1
698 }, {
699 state.interned_y1,
700 SVGTIOP_LENGTH,
701 &state.viewport_height,
702 &y1
703 }, {
704 state.interned_x2,
705 SVGTIOP_LENGTH,
706 &state.viewport_width,
707 &x2
708 }, {
709 state.interned_y2,
710 SVGTIOP_LENGTH,
711 &state.viewport_height,
712 &y2
713 }, {
714 NULL((void*)0), SVGTIOP_NONE, NULL((void*)0), NULL((void*)0)
715 },
716 };
717
718 svgtiny_setup_state_local(&state);
719
720 err = svgtiny_parse_attributes(line, &state, ops);
721 if (err != svgtiny_OK) {
722 svgtiny_cleanup_state_local(&state);
723 return err;
724 }
725
726 svgtiny_parse_paint_attributes(line, &state);
727 svgtiny_parse_transform_attributes(line, &state);
728
729 p = malloc(7 * sizeof p[0]);
730 if (!p) {
731 svgtiny_cleanup_state_local(&state);
732 return svgtiny_OUT_OF_MEMORY;
733 }
734
735 p[0] = svgtiny_PATH_MOVE;
736 p[1] = x1;
737 p[2] = y1;
738 p[3] = svgtiny_PATH_LINE;
739 p[4] = x2;
740 p[5] = y2;
741 p[6] = svgtiny_PATH_CLOSE;
742
743 err = svgtiny_add_path(p, 7, &state);
744
745 svgtiny_cleanup_state_local(&state);
746
747 return err;
748}
749
750
751/**
752 * Parse a <polyline> or <polygon> element node.
753 *
754 * http://www.w3.org/TR/SVG11/shapes#PolylineElement
755 * http://www.w3.org/TR/SVG11/shapes#PolygonElement
756 */
757static svgtiny_code
758svgtiny_parse_poly(dom_element *poly,
759 struct svgtiny_parse_state state,
760 bool_Bool polygon)
761{
762 svgtiny_code err;
763 dom_string *points_str;
764 dom_exception exc;
765 float *pointv;
766 unsigned int pointc;
767
768 svgtiny_setup_state_local(&state);
769
770 svgtiny_parse_paint_attributes(poly, &state);
771 svgtiny_parse_transform_attributes(poly, &state);
772
773 exc = dom_element_get_attribute(poly, state.interned_points,dom_element_get_attribute( (dom_element *) (poly), (state.interned_points
), (&points_str))
774 &points_str)dom_element_get_attribute( (dom_element *) (poly), (state.interned_points
), (&points_str))
;
775 if (exc != DOM_NO_ERR) {
776 svgtiny_cleanup_state_local(&state);
777 return svgtiny_LIBDOM_ERROR;
778 }
779
780 if (points_str == NULL((void*)0)) {
781 state.diagram->error_line = -1; /* poly->line; */
782 state.diagram->error_message =
783 "polyline/polygon: missing points attribute";
784 svgtiny_cleanup_state_local(&state);
785 return svgtiny_SVG_ERROR;
786 }
787
788 /* allocate space for path: it will never have more elements than bytes
789 * in the string.
790 */
791 pointc = dom_string_byte_length(points_str);
792 pointv = malloc(sizeof pointv[0] * pointc);
793 if (pointv == NULL((void*)0)) {
794 svgtiny_cleanup_state_local(&state);
795 return svgtiny_OUT_OF_MEMORY;
796 }
797
798 err = svgtiny_parse_poly_points(dom_string_data(points_str),
799 dom_string_byte_length(points_str),
800 pointv,
801 &pointc);
802 dom_string_unref(points_str);
803 if (err != svgtiny_OK) {
804 free(pointv);
805 state.diagram->error_line = -1; /* poly->line; */
806 state.diagram->error_message =
807 "polyline/polygon: failed to parse points";
808 } else {
809 if (pointc > 0) {
810 pointv[0] = svgtiny_PATH_MOVE;
811 }
812 if (polygon) {
813 pointv[pointc++] = svgtiny_PATH_CLOSE;
814 }
815
816 err = svgtiny_add_path(pointv, pointc, &state);
817 }
818 svgtiny_cleanup_state_local(&state);
819
820 return err;
821}
822
823
824/**
825 * Parse a <text> or <tspan> element node.
826 */
827static svgtiny_code
828svgtiny_parse_text(dom_element *text, struct svgtiny_parse_state state)
829{
830 float x, y, width, height;
831 float px, py;
832 dom_node *child;
833 dom_exception exc;
834
835 svgtiny_setup_state_local(&state);
836
837 svgtiny_parse_position_attributes(text, state,
838 &x, &y, &width, &height);
839 svgtiny_parse_font_attributes(text, &state);
840 svgtiny_parse_transform_attributes(text, &state);
841
842 px = state.ctm.a * x + state.ctm.c * y + state.ctm.e;
843 py = state.ctm.b * x + state.ctm.d * y + state.ctm.f;
844/* state.ctm.e = px - state.origin_x; */
845/* state.ctm.f = py - state.origin_y; */
846
847 /*struct css_style style = state.style;
848 style.font_size.value.length.value *= state.ctm.a;*/
849
850 exc = dom_node_get_first_child(text, &child)dom_node_get_first_child( (dom_node *) (text), (dom_node **) (
&child))
;
851 if (exc != DOM_NO_ERR) {
852 return svgtiny_LIBDOM_ERROR;
853 svgtiny_cleanup_state_local(&state);
854 }
855 while (child != NULL((void*)0)) {
856 dom_node *next;
857 dom_node_type nodetype;
858 svgtiny_code code = svgtiny_OK;
859
860 exc = dom_node_get_node_type(child, &nodetype)dom_node_get_node_type( (dom_node *) (child), (dom_node_type *
) (&nodetype))
;
861 if (exc != DOM_NO_ERR) {
862 dom_node_unref(child)dom_node_unref((dom_node *) (child));
863 svgtiny_cleanup_state_local(&state);
864 return svgtiny_LIBDOM_ERROR;
865 }
866 if (nodetype == DOM_ELEMENT_NODE) {
867 dom_string *nodename;
868 exc = dom_node_get_node_name(child, &nodename)dom_node_get_node_name((dom_node *) (child), (&nodename));
869 if (exc != DOM_NO_ERR) {
870 dom_node_unref(child)dom_node_unref((dom_node *) (child));
871 svgtiny_cleanup_state_local(&state);
872 return svgtiny_LIBDOM_ERROR;
873 }
874 if (dom_string_caseless_isequal(nodename,
875 state.interned_tspan))
876 code = svgtiny_parse_text((dom_element *)child,
877 state);
878 dom_string_unref(nodename);
879 } else if (nodetype == DOM_TEXT_NODE) {
880 struct svgtiny_shape *shape = svgtiny_add_shape(&state);
881 dom_string *content;
882 if (shape == NULL((void*)0)) {
883 dom_node_unref(child)dom_node_unref((dom_node *) (child));
884 svgtiny_cleanup_state_local(&state);
885 return svgtiny_OUT_OF_MEMORY;
886 }
887 exc = dom_text_get_whole_text(child, &content)dom_text_get_whole_text((dom_text *) (child), (&content));
888 if (exc != DOM_NO_ERR) {
889 dom_node_unref(child)dom_node_unref((dom_node *) (child));
890 svgtiny_cleanup_state_local(&state);
891 return svgtiny_LIBDOM_ERROR;
892 }
893 if (content != NULL((void*)0)) {
894 shape->text = strndup(dom_string_data(content),
895 dom_string_byte_length(content));
896 dom_string_unref(content);
897 } else {
898 shape->text = strdup("");
899 }
900 shape->text_x = px;
901 shape->text_y = py;
902 state.diagram->shape_count++;
903 }
904
905 if (code != svgtiny_OK) {
906 dom_node_unref(child)dom_node_unref((dom_node *) (child));
907 svgtiny_cleanup_state_local(&state);
908 return code;
909 }
910 exc = dom_node_get_next_sibling(child, &next)dom_node_get_next_sibling( (dom_node *) (child), (dom_node **
) (&next))
;
911 dom_node_unref(child)dom_node_unref((dom_node *) (child));
912 if (exc != DOM_NO_ERR) {
913 svgtiny_cleanup_state_local(&state);
914 return svgtiny_LIBDOM_ERROR;
915 }
916 child = next;
917 }
918
919 svgtiny_cleanup_state_local(&state);
920
921 return svgtiny_OK;
922}
923
924
925/**
926 * Parse a <use> element node.
927 *
928 * https://www.w3.org/TR/SVG2/struct.html#UseElement
929 */
930static svgtiny_code
931svgtiny_parse_use(dom_element *use, struct svgtiny_parse_state state)
932{
933 svgtiny_code res;
934 dom_element *ref; /* referenced element */
935
936 svgtiny_setup_state_local(&state);
937
938 res = svgtiny_parse_element_from_href(use, &state, &ref);
939 if (res != svgtiny_OK) {
940 svgtiny_cleanup_state_local(&state);
941 return res;
942 }
943
944 if (ref != NULL((void*)0)) {
945 /* found the reference */
946
947 /**
948 * If the referenced element is a ancestor of the ‘use’ element,
949 * then this is an invalid circular reference and the ‘use’
950 * element is in error.
951 */
952 res = is_ancestor_node((dom_node *)ref, (dom_node *)use);
953 if (res != svgtiny_OK) {
954 res = parse_element(ref, &state);
Value stored to 'res' is never read
955 }
956 dom_node_unref(ref)dom_node_unref((dom_node *) (ref));
957 }
958
959 svgtiny_cleanup_state_local(&state);
960
961 return svgtiny_OK;
962}
963
964
965/**
966 * Parse a <svg> or <g> element node.
967 */
968static svgtiny_code
969svgtiny_parse_svg(dom_element *svg, struct svgtiny_parse_state state)
970{
971 float x, y, width, height;
972 dom_string *view_box;
973 dom_element *child;
974 dom_exception exc;
975
976 svgtiny_setup_state_local(&state);
977
978 svgtiny_parse_position_attributes(svg, state, &x, &y, &width, &height);
979 svgtiny_parse_paint_attributes(svg, &state);
980 svgtiny_parse_font_attributes(svg, &state);
981
982 exc = dom_element_get_attribute(svg, state.interned_viewBox,dom_element_get_attribute( (dom_element *) (svg), (state.interned_viewBox
), (&view_box))
983 &view_box)dom_element_get_attribute( (dom_element *) (svg), (state.interned_viewBox
), (&view_box))
;
984 if (exc != DOM_NO_ERR) {
985 svgtiny_cleanup_state_local(&state);
986 return svgtiny_LIBDOM_ERROR;
987 }
988
989 if (view_box) {
990 svgtiny_parse_viewbox(dom_string_data(view_box),
991 dom_string_byte_length(view_box),
992 state.viewport_width,
993 state.viewport_height,
994 &state.ctm);
995 dom_string_unref(view_box);
996 }
997
998 svgtiny_parse_transform_attributes(svg, &state);
999
1000 exc = dom_node_get_first_child(svg, (dom_node **) (void *) &child)dom_node_get_first_child( (dom_node *) (svg), (dom_node **) (
(dom_node **) (void *) &child))
;
1001 if (exc != DOM_NO_ERR) {
1002 svgtiny_cleanup_state_local(&state);
1003 return svgtiny_LIBDOM_ERROR;
1004 }
1005 while (child != NULL((void*)0)) {
1006 dom_element *next;
1007 dom_node_type nodetype;
1008 svgtiny_code code = svgtiny_OK;
1009
1010 exc = dom_node_get_node_type(child, &nodetype)dom_node_get_node_type( (dom_node *) (child), (dom_node_type *
) (&nodetype))
;
1011 if (exc != DOM_NO_ERR) {
1012 dom_node_unref(child)dom_node_unref((dom_node *) (child));
1013 return svgtiny_LIBDOM_ERROR;
1014 }
1015 if (nodetype == DOM_ELEMENT_NODE) {
1016 code = parse_element(child, &state);
1017 }
1018 if (code != svgtiny_OK) {
1019 dom_node_unref(child)dom_node_unref((dom_node *) (child));
1020 svgtiny_cleanup_state_local(&state);
1021 return code;
1022 }
1023 exc = dom_node_get_next_sibling(child,dom_node_get_next_sibling( (dom_node *) (child), (dom_node **
) ((dom_node **) (void *) &next))
1024 (dom_node **) (void *) &next)dom_node_get_next_sibling( (dom_node *) (child), (dom_node **
) ((dom_node **) (void *) &next))
;
1025 dom_node_unref(child)dom_node_unref((dom_node *) (child));
1026 if (exc != DOM_NO_ERR) {
1027 svgtiny_cleanup_state_local(&state);
1028 return svgtiny_LIBDOM_ERROR;
1029 }
1030 child = next;
1031 }
1032
1033 svgtiny_cleanup_state_local(&state);
1034 return svgtiny_OK;
1035}
1036
1037
1038static svgtiny_code
1039parse_element(dom_element *element, struct svgtiny_parse_state *state)
1040{
1041 dom_exception exc;
1042 dom_string *nodename;
1043 svgtiny_code code = svgtiny_OK;;
1044
1045 exc = dom_node_get_node_name(element, &nodename)dom_node_get_node_name((dom_node *) (element), (&nodename
))
;
1046 if (exc != DOM_NO_ERR) {
1047 return svgtiny_LIBDOM_ERROR;
1048 }
1049
1050 if (dom_string_caseless_isequal(state->interned_svg, nodename)) {
1051 code = svgtiny_parse_svg(element, *state);
1052 } else if (dom_string_caseless_isequal(state->interned_g, nodename)) {
1053 code = svgtiny_parse_svg(element, *state);
1054 } else if (dom_string_caseless_isequal(state->interned_a, nodename)) {
1055 code = svgtiny_parse_svg(element, *state);
1056 } else if (dom_string_caseless_isequal(state->interned_path, nodename)) {
1057 code = svgtiny_parse_path(element, *state);
1058 } else if (dom_string_caseless_isequal(state->interned_rect, nodename)) {
1059 code = svgtiny_parse_rect(element, *state);
1060 } else if (dom_string_caseless_isequal(state->interned_circle, nodename)) {
1061 code = svgtiny_parse_circle(element, *state);
1062 } else if (dom_string_caseless_isequal(state->interned_ellipse, nodename)) {
1063 code = svgtiny_parse_ellipse(element, *state);
1064 } else if (dom_string_caseless_isequal(state->interned_line, nodename)) {
1065 code = svgtiny_parse_line(element, *state);
1066 } else if (dom_string_caseless_isequal(state->interned_polyline, nodename)) {
1067 code = svgtiny_parse_poly(element, *state, false0);
1068 } else if (dom_string_caseless_isequal(state->interned_polygon, nodename)) {
1069 code = svgtiny_parse_poly(element, *state, true1);
1070 } else if (dom_string_caseless_isequal(state->interned_text, nodename)) {
1071 code = svgtiny_parse_text(element, *state);
1072 } else if (dom_string_caseless_isequal(state->interned_use, nodename)) {
1073 code = svgtiny_parse_use(element, *state);
1074 }
1075 dom_string_unref(nodename);
1076 return code;
1077}
1078
1079
1080static svgtiny_code
1081initialise_parse_state(struct svgtiny_parse_state *state,
1082 struct svgtiny_diagram *diagram,
1083 dom_document *document,
1084 dom_element *svg,
1085 int viewport_width,
1086 int viewport_height)
1087{
1088 float x, y, width, height;
1089
1090 memset(state, 0, sizeof(*state));
1091
1092 state->diagram = diagram;
1093 state->document = document;
1094
1095#define SVGTINY_STRING_ACTION2(s,n) \
1096 if (dom_string_create_interned((const uint8_t *) #n, \
1097 strlen(#n), \
1098 &state->interned_##s) \
1099 != DOM_NO_ERR) { \
1100 return svgtiny_LIBDOM_ERROR; \
1101 }
1102#include "svgtiny_strings.h"
1103#undef SVGTINY_STRING_ACTION2
1104
1105 /* get graphic dimensions */
1106 state->viewport_width = viewport_width;
1107 state->viewport_height = viewport_height;
1108 svgtiny_parse_position_attributes(svg, *state, &x, &y, &width, &height);
1109 diagram->width = width;
1110 diagram->height = height;
1111
1112 /* set up parsing state */
1113 state->viewport_width = width;
1114 state->viewport_height = height;
1115 state->ctm.a = 1; /*(float) viewport_width / (float) width;*/
1116 state->ctm.b = 0;
1117 state->ctm.c = 0;
1118 state->ctm.d = 1; /*(float) viewport_height / (float) height;*/
1119 state->ctm.e = 0; /*x;*/
1120 state->ctm.f = 0; /*y;*/
1121 /*state->style = css_base_style;
1122 state->style.font_size.value.length.value = option_font_size * 0.1;*/
1123 state->fill = 0x000000;
1124 state->stroke = svgtiny_TRANSPARENT0x1000000;
1125 state->stroke_width = 1;
1126 return svgtiny_OK;
1127}
1128
1129
1130static svgtiny_code finalise_parse_state(struct svgtiny_parse_state *state)
1131{
1132 svgtiny_cleanup_state_local(state);
1133
1134#define SVGTINY_STRING_ACTION2(s,n) \
1135 if (state->interned_##s != NULL((void*)0)) \
1136 dom_string_unref(state->interned_##s);
1137#include "svgtiny_strings.h"
1138#undef SVGTINY_STRING_ACTION2
1139 return svgtiny_OK;
1140}
1141
1142
1143static svgtiny_code get_svg_element(dom_document *document, dom_element **svg)
1144{
1145 dom_exception exc;
1146 dom_string *svg_name;
1147 lwc_string *svg_name_lwc;
1148
1149 /* find root <svg> element */
1150 exc = dom_document_get_document_element(document, svg)dom_document_get_document_element((dom_document *) (document)
, (struct dom_element **) (svg))
;
1151 if (exc != DOM_NO_ERR) {
1152 return svgtiny_LIBDOM_ERROR;
1153 }
1154 if (svg == NULL((void*)0)) {
1155 /* no root element */
1156 return svgtiny_SVG_ERROR;
1157 }
1158
1159 /* ensure root element is <svg> */
1160 exc = dom_node_get_node_name(*svg, &svg_name)dom_node_get_node_name((dom_node *) (*svg), (&svg_name));
1161 if (exc != DOM_NO_ERR) {
1162 dom_node_unref(*svg)dom_node_unref((dom_node *) (*svg));
1163 return svgtiny_LIBDOM_ERROR;
1164 }
1165 if (lwc_intern_string("svg", 3 /* SLEN("svg") */,
1166 &svg_name_lwc) != lwc_error_ok) {
1167 dom_string_unref(svg_name);
1168 dom_node_unref(*svg)dom_node_unref((dom_node *) (*svg));
1169 return svgtiny_LIBDOM_ERROR;
1170 }
1171 if (!dom_string_caseless_lwc_isequal(svg_name, svg_name_lwc)) {
1172 lwc_string_unref(svg_name_lwc){ lwc_string *__lwc_s = (svg_name_lwc); ((__lwc_s != ((void*)
0)) ? (void) (0) : __assert_fail ("__lwc_s != NULL", "src/svgtiny.c"
, 1172, __extension__ __PRETTY_FUNCTION__)); __lwc_s->refcnt
--; if ((__lwc_s->refcnt == 0) || ((__lwc_s->refcnt == 1
) && (__lwc_s->insensitive == __lwc_s))) lwc_string_destroy
(__lwc_s); }
;
1173 dom_string_unref(svg_name);
1174 dom_node_unref(*svg)dom_node_unref((dom_node *) (*svg));
1175 return svgtiny_NOT_SVG;
1176 }
1177
1178 lwc_string_unref(svg_name_lwc){ lwc_string *__lwc_s = (svg_name_lwc); ((__lwc_s != ((void*)
0)) ? (void) (0) : __assert_fail ("__lwc_s != NULL", "src/svgtiny.c"
, 1178, __extension__ __PRETTY_FUNCTION__)); __lwc_s->refcnt
--; if ((__lwc_s->refcnt == 0) || ((__lwc_s->refcnt == 1
) && (__lwc_s->insensitive == __lwc_s))) lwc_string_destroy
(__lwc_s); }
;
1179 dom_string_unref(svg_name);
1180
1181 return svgtiny_OK;
1182}
1183
1184
1185static svgtiny_code
1186svg_document_from_buffer(uint8_t *buffer, size_t size, dom_document **document)
1187{
1188 dom_xml_parser *parser;
1189 dom_xml_error err;
1190
1191 parser = dom_xml_parser_create(NULL((void*)0), NULL((void*)0), ignore_msg, NULL((void*)0), document);
1192
1193 if (parser == NULL((void*)0))
1194 return svgtiny_LIBDOM_ERROR;
1195
1196 err = dom_xml_parser_parse_chunk(parser, buffer, size);
1197 if (err != DOM_XML_OK) {
1198 dom_node_unref(*document)dom_node_unref((dom_node *) (*document));
1199 dom_xml_parser_destroy(parser);
1200 return svgtiny_LIBDOM_ERROR;
1201 }
1202
1203 err = dom_xml_parser_completed(parser);
1204 if (err != DOM_XML_OK) {
1205 dom_node_unref(*document)dom_node_unref((dom_node *) (*document));
1206 dom_xml_parser_destroy(parser);
1207 return svgtiny_LIBDOM_ERROR;
1208 }
1209
1210 /* We're done parsing, drop the parser.
1211 * We now own the document entirely.
1212 */
1213 dom_xml_parser_destroy(parser);
1214
1215 return svgtiny_OK;
1216}
1217
1218
1219/**
1220 * Add a svgtiny_shape to the svgtiny_diagram.
1221 *
1222 * library internal interface
1223 */
1224struct svgtiny_shape *svgtiny_add_shape(struct svgtiny_parse_state *state)
1225{
1226 struct svgtiny_shape *shape;
1227
1228 shape = realloc(state->diagram->shape,
1229 (state->diagram->shape_count + 1) *
1230 sizeof (state->diagram->shape[0]));
1231 if (shape != NULL((void*)0)) {
1232 state->diagram->shape = shape;
1233
1234 shape += state->diagram->shape_count;
1235 shape->path = 0;
1236 shape->path_length = 0;
1237 shape->text = 0;
1238 shape->fill = state->fill;
1239 shape->stroke = state->stroke;
1240 shape->stroke_width = lroundf((float) state->stroke_width *
1241 (state->ctm.a + state->ctm.d) / 2.0);
1242 if (0 < state->stroke_width && shape->stroke_width == 0)
1243 shape->stroke_width = 1;
1244 }
1245 return shape;
1246}
1247
1248
1249/**
1250 * Apply the current transformation matrix to a path.
1251 *
1252 * library internal interface
1253 */
1254void
1255svgtiny_transform_path(float *p,
1256 unsigned int n,
1257 struct svgtiny_parse_state *state)
1258{
1259 unsigned int j;
1260
1261 for (j = 0; j != n; ) {
1262 unsigned int points = 0;
1263 unsigned int k;
1264 switch ((int) p[j]) {
1265 case svgtiny_PATH_MOVE:
1266 case svgtiny_PATH_LINE:
1267 points = 1;
1268 break;
1269 case svgtiny_PATH_CLOSE:
1270 points = 0;
1271 break;
1272 case svgtiny_PATH_BEZIER:
1273 points = 3;
1274 break;
1275 default:
1276 assert(0)((0) ? (void) (0) : __assert_fail ("0", "src/svgtiny.c", 1276
, __extension__ __PRETTY_FUNCTION__))
;
1277 }
1278 j++;
1279 for (k = 0; k != points; k++) {
1280 float x0 = p[j], y0 = p[j + 1];
1281 float x = state->ctm.a * x0 + state->ctm.c * y0 +
1282 state->ctm.e;
1283 float y = state->ctm.b * x0 + state->ctm.d * y0 +
1284 state->ctm.f;
1285 p[j] = x;
1286 p[j + 1] = y;
1287 j += 2;
1288 }
1289 }
1290}
1291
1292
1293/**
1294 * Create a new svgtiny_diagram structure.
1295 */
1296struct svgtiny_diagram *svgtiny_create(void)
1297{
1298 struct svgtiny_diagram *diagram;
1299
1300 diagram = calloc(1, sizeof(*diagram));
1301
1302 return diagram;
1303}
1304
1305
1306/**
1307 * Parse a block of memory into a svgtiny_diagram.
1308 */
1309svgtiny_code svgtiny_parse(struct svgtiny_diagram *diagram,
1310 const char *buffer, size_t size, const char *url,
1311 int viewport_width, int viewport_height)
1312{
1313 dom_document *document;
1314 dom_element *svg;
1315 struct svgtiny_parse_state state;
1316 svgtiny_code code;
1317
1318 assert(diagram)((diagram) ? (void) (0) : __assert_fail ("diagram", "src/svgtiny.c"
, 1318, __extension__ __PRETTY_FUNCTION__))
;
1319 assert(buffer)((buffer) ? (void) (0) : __assert_fail ("buffer", "src/svgtiny.c"
, 1319, __extension__ __PRETTY_FUNCTION__))
;
1320 assert(url)((url) ? (void) (0) : __assert_fail ("url", "src/svgtiny.c", 1320
, __extension__ __PRETTY_FUNCTION__))
;
1321
1322 UNUSED(url)((void) (url));
1323
1324 code = svg_document_from_buffer((uint8_t *)buffer, size, &document);
1325 if (code == svgtiny_OK) {
1326 code = get_svg_element(document, &svg);
1327 if (code == svgtiny_OK) {
1328 code = initialise_parse_state(&state,
1329 diagram,
1330 document,
1331 svg,
1332 viewport_width,
1333 viewport_height);
1334 if (code == svgtiny_OK) {
1335 code = svgtiny_parse_svg(svg, state);
1336 }
1337
1338 finalise_parse_state(&state);
1339
1340 dom_node_unref(svg)dom_node_unref((dom_node *) (svg));
1341 }
1342 dom_node_unref(document)dom_node_unref((dom_node *) (document));
1343 }
1344
1345 return code;
1346}
1347
1348
1349/**
1350 * Free all memory used by a diagram.
1351 */
1352void svgtiny_free(struct svgtiny_diagram *svg)
1353{
1354 unsigned int i;
1355 assert(svg)((svg) ? (void) (0) : __assert_fail ("svg", "src/svgtiny.c", 1355
, __extension__ __PRETTY_FUNCTION__))
;
1356
1357 for (i = 0; i != svg->shape_count; i++) {
1358 free(svg->shape[i].path);
1359 free(svg->shape[i].text);
1360 }
1361
1362 free(svg->shape);
1363
1364 free(svg);
1365}