summaryrefslogtreecommitdiff
path: root/backend/impress
diff options
context:
space:
mode:
authorPerberos <[email protected]>2011-11-09 18:17:43 -0300
committerPerberos <[email protected]>2011-11-09 18:17:43 -0300
commitf6ce926719943751cf65cacde7fae050593eb2d6 (patch)
tree9224d1751678cf2d1fbd0431f128b711311c0287 /backend/impress
downloadatril-f6ce926719943751cf65cacde7fae050593eb2d6.tar.bz2
atril-f6ce926719943751cf65cacde7fae050593eb2d6.tar.xz
inicial
Diffstat (limited to 'backend/impress')
-rw-r--r--backend/impress/Makefile.am57
-rw-r--r--backend/impress/common.h40
-rw-r--r--backend/impress/document.c140
-rw-r--r--backend/impress/f_oasis.c170
-rw-r--r--backend/impress/f_oo13.c181
-rw-r--r--backend/impress/iksemel.c1882
-rw-r--r--backend/impress/iksemel.h402
-rw-r--r--backend/impress/imposter.h84
-rw-r--r--backend/impress/impress-document.c548
-rw-r--r--backend/impress/impress-document.h39
-rw-r--r--backend/impress/impressdocument.evince-backend.in4
-rw-r--r--backend/impress/internal.h85
-rw-r--r--backend/impress/r_back.c46
-rw-r--r--backend/impress/r_draw.c120
-rw-r--r--backend/impress/r_geometry.c208
-rw-r--r--backend/impress/r_gradient.c387
-rw-r--r--backend/impress/r_style.c111
-rw-r--r--backend/impress/r_text.c386
-rw-r--r--backend/impress/render.c54
-rw-r--r--backend/impress/zip.c349
-rw-r--r--backend/impress/zip.h18
21 files changed, 5311 insertions, 0 deletions
diff --git a/backend/impress/Makefile.am b/backend/impress/Makefile.am
new file mode 100644
index 00000000..a7b65705
--- /dev/null
+++ b/backend/impress/Makefile.am
@@ -0,0 +1,57 @@
+INCLUDES = \
+ -I$(top_srcdir) \
+ -I$(top_srcdir)/libdocument \
+ -DMATELOCALEDIR=\"$(datadir)/locale\" \
+ -DEVINCEDATADIR=\""$(datadir)"\" \
+ -DEVINCE_COMPILATION \
+ $(BACKEND_CFLAGS) \
+ $(WARN_CFLAGS) \
+ $(DISABLE_DEPRECATED)
+
+backend_LTLIBRARIES = libimpressdocument.la
+
+libimpressdocument_la_SOURCES = \
+ $(IMPOSTER_SOURCE_FILES) \
+ $(IMPOSTER_INCLUDE_FILES) \
+ impress-document.c \
+ impress-document.h
+
+IMPOSTER_SOURCE_FILES = \
+ document.c \
+ f_oasis.c \
+ f_oo13.c \
+ iksemel.c \
+ r_back.c \
+ r_draw.c \
+ render.c \
+ r_geometry.c \
+ r_gradient.c \
+ r_style.c \
+ r_text.c \
+ zip.c
+IMPOSTER_INCLUDE_FILES = \
+ common.h \
+ iksemel.h \
+ imposter.h \
+ internal.h \
+ zip.h
+IMPOSTER_RENDER_SOURCE_FILES = \
+ render.c
+IMPOSTER_RENDER_INCLUDE_FILES = \
+ render.h
+
+libimpressdocument_la_LDFLAGS = $(BACKEND_LIBTOOL_FLAGS)
+libimpressdocument_la_LIBADD = \
+ $(top_builddir)/libdocument/libevdocument.la \
+ $(BACKEND_LIBS) -lz
+
+backend_in_files = impressdocument.evince-backend.in
+backend_DATA = $(backend_in_files:.evince-backend.in=.evince-backend)
+
+EXTRA_DIST = $(backend_in_files)
+
+CLEANFILES = $(backend_DATA)
+
+@EV_INTLTOOL_EVINCE_BACKEND_RULE@
+
+-include $(top_srcdir)/git.mk
diff --git a/backend/impress/common.h b/backend/impress/common.h
new file mode 100644
index 00000000..73e4ac19
--- /dev/null
+++ b/backend/impress/common.h
@@ -0,0 +1,40 @@
+/* imposter (OO.org Impress viewer)
+** Copyright (C) 2003-2005 Gurer Ozen
+** This code is free software; you can redistribute it and/or
+** modify it under the terms of GNU General Public License.
+*/
+
+#ifndef COMMON_H
+#define COMMON_H 1
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <sys/types.h>
+#include <stdio.h>
+
+#ifdef STDC_HEADERS
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+#elif HAVE_STRINGS_H
+#include <strings.h>
+#endif
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#ifdef HAVE_ERRNO_H
+#include <errno.h>
+#endif
+#ifndef errno
+extern int errno;
+#endif
+
+#include <iksemel.h>
+#include "imposter.h"
+
+
+#endif /* COMMON_H */
diff --git a/backend/impress/document.c b/backend/impress/document.c
new file mode 100644
index 00000000..b01c0e18
--- /dev/null
+++ b/backend/impress/document.c
@@ -0,0 +1,140 @@
+/* imposter (OO.org Impress viewer)
+** Copyright (C) 2003-2005 Gurer Ozen
+** This code is free software; you can redistribute it and/or
+** modify it under the terms of GNU General Public License.
+*/
+
+#include <config.h>
+#include "common.h"
+#include "internal.h"
+
+static iks *
+_imp_load_xml(ImpDoc *doc, const char *xmlfile)
+{
+ int e;
+ iks *x;
+
+ x = zip_load_xml (doc->zfile, xmlfile, &e);
+ return x;
+}
+
+ImpDoc *
+imp_open(const char *filename, int *err)
+{
+ ImpDoc *doc;
+ int e;
+
+ doc = calloc(1, sizeof(ImpDoc));
+ if (!doc) {
+ *err = IMP_NOMEM;
+ return NULL;
+ }
+
+ doc->stack = iks_stack_new(sizeof(ImpPage) * 32, 0);
+ if (!doc->stack) {
+ *err = IMP_NOMEM;
+ imp_close(doc);
+ return NULL;
+ }
+
+ doc->zfile = zip_open(filename, &e);
+ if (e) {
+ *err = IMP_NOTZIP;
+ imp_close(doc);
+ return NULL;
+ }
+
+ doc->content = _imp_load_xml(doc, "content.xml");
+ doc->styles = _imp_load_xml(doc, "styles.xml");
+ doc->meta = _imp_load_xml(doc, "meta.xml");
+
+ if (!doc->content || !doc->styles) {
+ *err = IMP_BADDOC;
+ imp_close(doc);
+ return NULL;
+ }
+
+ e = _imp_oo13_load(doc);
+ if (e && e != IMP_NOTIMP) {
+ *err = e;
+ imp_close(doc);
+ return NULL;
+ }
+
+ if (e == IMP_NOTIMP) {
+ e = _imp_oasis_load(doc);
+ if (e) {
+ *err = e;
+ imp_close(doc);
+ return NULL;
+ }
+ }
+
+ return doc;
+}
+
+int
+imp_nr_pages(ImpDoc *doc)
+{
+ return doc->nr_pages;
+}
+
+ImpPage *
+imp_get_page(ImpDoc *doc, int page_no)
+{
+ if (page_no == IMP_LAST_PAGE) {
+ return doc->last_page;
+ } else {
+ ImpPage *page;
+ if (page_no < 0 || page_no > doc->nr_pages) return NULL;
+ for (page = doc->pages; page_no; --page_no) {
+ page = page->next;
+ }
+ return page;
+ }
+}
+
+ImpPage *
+imp_next_page(ImpPage *page)
+{
+ return page->next;
+}
+
+ImpPage *
+imp_prev_page(ImpPage *page)
+{
+ return page->prev;
+}
+
+int
+imp_get_page_no(ImpPage *page)
+{
+ return page->nr;
+}
+
+const char *
+imp_get_page_name(ImpPage *page)
+{
+ return page->name;
+}
+
+void *
+imp_get_xml(ImpDoc *doc, const char *filename)
+{
+ if (strcmp(filename, "content.xml") == 0)
+ return doc->content;
+ else if (strcmp(filename, "styles.xml") == 0)
+ return doc->styles;
+ else if (strcmp(filename, "meta.xml") == 0)
+ return doc->meta;
+ else
+ return NULL;
+}
+
+void
+imp_close(ImpDoc *doc)
+{
+ if (doc->stack) iks_stack_delete(doc->stack);
+ if (doc->zfile) zip_close(doc->zfile);
+ free(doc);
+}
diff --git a/backend/impress/f_oasis.c b/backend/impress/f_oasis.c
new file mode 100644
index 00000000..8fe6ee1a
--- /dev/null
+++ b/backend/impress/f_oasis.c
@@ -0,0 +1,170 @@
+/* imposter (OO.org Impress viewer)
+** Copyright (C) 2003-2005 Gurer Ozen
+** This code is free software; you can redistribute it and/or
+** modify it under the terms of GNU General Public License.
+*/
+
+#include <config.h>
+#include "common.h"
+#include "internal.h"
+
+static void
+render_object(ImpRenderCtx *ctx, void *drw_data, iks *node)
+{
+ char *tag, *t;
+ ImpColor fg;
+
+ tag = iks_name(node);
+ if (strcmp(tag, "draw:g") == 0) {
+ iks *x;
+ for (x = iks_first_tag(node); x; x = iks_next_tag(x)) {
+ render_object(ctx, drw_data, x);
+ }
+ } else if (strcmp(tag, "draw:frame") == 0) {
+ iks *x;
+ for (x = iks_first_tag(node); x; x = iks_next_tag(x)) {
+ render_object(ctx, drw_data, x);
+ }
+ } else if (strcmp(tag, "draw:line") == 0) {
+ r_get_color(ctx, node, "svg:stroke-color", &fg);
+ ctx->drw->set_fg_color(drw_data, &fg);
+ ctx->drw->draw_line(drw_data,
+ r_get_x(ctx, node, "svg:x1"), r_get_y(ctx, node, "svg:y1"),
+ r_get_x(ctx, node, "svg:x2"), r_get_y(ctx, node, "svg:y2")
+ );
+ } else if (strcmp(tag, "draw:rect") == 0) {
+ int x, y, w, h, r = 0;
+ char *t;
+ x = r_get_x(ctx, node, "svg:x");
+ y = r_get_y(ctx, node, "svg:y");
+ w = r_get_x(ctx, node, "svg:width");
+ h = r_get_y(ctx, node, "svg:height");
+ t = r_get_style(ctx, node, "draw:corner-radius");
+ if (t) r = atof(t) * ctx->fact_x;
+ if (r_get_style(ctx, node, "draw:fill")) {
+ r_get_color(ctx, node, "draw:fill-color", &fg);
+ ctx->drw->set_fg_color(drw_data, &fg);
+ _imp_draw_rect(ctx, drw_data, 1, x, y, w, h, r);
+ }
+ r_get_color(ctx, node, "svg:stroke-color", &fg);
+ ctx->drw->set_fg_color(drw_data, &fg);
+ _imp_draw_rect(ctx, drw_data, 0, x, y, w, h, r);
+ r_text(ctx, drw_data, node);
+ } else if (strcmp(tag, "draw:ellipse") == 0 || strcmp(tag, "draw:circle") == 0) {
+ int sa, ea, fill = 0;
+ r_get_color(ctx, node, "svg:stroke-color", &fg);
+ sa = r_get_angle(node, "draw:start-angle", 0);
+ ea = r_get_angle(node, "draw:end-angle", 360);
+ if (ea > sa) ea = ea - sa; else ea = 360 + ea - sa;
+ t = r_get_style(ctx, node, "draw:fill");
+ if (t) fill = 1;
+ ctx->drw->set_fg_color(drw_data, &fg);
+ ctx->drw->draw_arc(drw_data,
+ fill,
+ r_get_x(ctx, node, "svg:x"), r_get_y(ctx, node, "svg:y"),
+ r_get_x(ctx, node, "svg:width"), r_get_y(ctx, node, "svg:height"),
+ sa, ea
+ );
+ } else if (strcmp(tag, "draw:polygon") == 0) {
+ // FIXME:
+ r_polygon(ctx, drw_data, node);
+ } else if (strcmp(tag, "draw:text-box") == 0) {
+ // FIXME:
+ r_text(ctx, drw_data, node);
+ } else if (strcmp(tag, "draw:image") == 0) {
+ char *name;
+
+ name = iks_find_attrib(node, "xlink:href");
+ if (!name) return;
+ if (name[0] == '#') ++name;
+
+ _imp_draw_image(ctx, drw_data,
+ name,
+ r_get_x(ctx, node, "svg:x"),
+ r_get_y(ctx, node, "svg:y"),
+ r_get_x(ctx, node, "svg:width"),
+ r_get_y(ctx, node, "svg:height")
+ );
+ } else {
+ printf("Unknown element: %s\n", tag);
+ }
+}
+
+static void
+render_page(ImpRenderCtx *ctx, void *drw_data)
+{
+ iks *x;
+ char *element;
+ int i;
+
+ i = _imp_fill_back(ctx, drw_data, ctx->page->page);
+ element = iks_find_attrib(ctx->page->page, "draw:master-page-name");
+ if (element) {
+ x = iks_find_with_attrib(
+ iks_find(ctx->page->doc->styles, "office:master-styles"),
+ "style:master-page", "style:name", element
+ );
+ if (x) {
+ if (i == 0) _imp_fill_back(ctx, drw_data, x);
+ for (x = iks_first_tag(x); x; x = iks_next_tag(x)) {
+ if (iks_find_attrib(x, "presentation:class"))
+ continue;
+ render_object(ctx, drw_data, x);
+ }
+ }
+ }
+ for (x = iks_first_tag(ctx->page->page); x; x = iks_next_tag(x)) {
+ render_object(ctx, drw_data, x);
+ }
+}
+
+static void
+get_geometry(ImpRenderCtx *ctx)
+{
+ char *tmp;
+ iks *x, *y;
+
+ tmp = iks_find_attrib(ctx->page->page, "draw:master-page-name");
+ x = iks_find(ctx->page->doc->styles, "office:master-styles");
+ y = iks_find_with_attrib(x, "style:master-page", "style:name", tmp);
+ x = iks_find(ctx->page->doc->styles, "office:automatic-styles");
+ y = iks_find_with_attrib(x, "style:page-layout", "style:name",
+ iks_find_attrib(y, "style:page-layout-name"));
+ ctx->cm_w = atof(iks_find_attrib(iks_find(y, "style:page-layout-properties"), "fo:page-width"));
+ ctx->cm_h = atof(iks_find_attrib(iks_find(y, "style:page-layout-properties"), "fo:page-height"));
+}
+
+int
+_imp_oasis_load(ImpDoc *doc)
+{
+ ImpPage *page;
+ iks *x, *pres;
+ int i;
+
+ pres = iks_find(iks_find(doc->content, "office:body"), "office:presentation");
+ if (!pres) return IMP_NOTIMP;
+
+ x = iks_find(pres, "draw:page");
+ if (!x) return IMP_NOTIMP;
+ i = 0;
+ for (; x; x = iks_next_tag(x)) {
+ if (strcmp(iks_name(x), "draw:page") == 0) {
+ page = iks_stack_alloc(doc->stack, sizeof(ImpPage));
+ if (!page) return IMP_NOMEM;
+ memset(page, 0, sizeof(ImpPage));
+ page->page = x;
+ page->nr = ++i;
+ page->name = iks_find_attrib(x, "draw:name");
+ page->doc = doc;
+ if (!doc->pages) doc->pages = page;
+ page->prev = doc->last_page;
+ if (doc->last_page) doc->last_page->next = page;
+ doc->last_page = page;
+ }
+ }
+ doc->nr_pages = i;
+ doc->get_geometry = get_geometry;
+ doc->render_page = render_page;
+
+ return 0;
+}
diff --git a/backend/impress/f_oo13.c b/backend/impress/f_oo13.c
new file mode 100644
index 00000000..7bfeeb53
--- /dev/null
+++ b/backend/impress/f_oo13.c
@@ -0,0 +1,181 @@
+/* imposter (OO.org Impress viewer)
+** Copyright (C) 2003-2005 Gurer Ozen
+** This code is free software; you can redistribute it and/or
+** modify it under the terms of GNU General Public License.
+*/
+
+#include <config.h>
+#include "common.h"
+#include "internal.h"
+
+// { "draw:text-box", r_text },
+// { "draw:connector", r_line },
+// { "draw:polyline", r_polyline },
+// { "draw:polygon", r_polygon },
+// { "draw:path", r_path },
+
+static void
+render_object(ImpRenderCtx *ctx, void *drw_data, iks *node)
+{
+ char *tag, *t;
+ ImpColor fg;
+
+ tag = iks_name(node);
+ if (strcmp(tag, "draw:g") == 0) {
+ iks *x;
+ for (x = iks_first_tag(node); x; x = iks_next_tag(x)) {
+ render_object(ctx, drw_data, x);
+ }
+ } else if (strcmp(tag, "draw:line") == 0) {
+ int x1, y1, x2, y2;
+ r_get_color(ctx, node, "svg:stroke-color", &fg);
+ ctx->drw->set_fg_color(drw_data, &fg);
+ x1 = r_get_x(ctx, node, "svg:x1");
+ y1 = r_get_y(ctx, node, "svg:y1");
+ x2 = r_get_x(ctx, node, "svg:x2");
+ y2 = r_get_y(ctx, node, "svg:y2");
+ ctx->drw->draw_line(drw_data, x1, y1, x2, y2);
+ if (r_get_style(ctx, node, "draw:marker-start")) {
+ _imp_draw_line_end(ctx, drw_data, 0, 0, x2, y2, x1, y1);
+ }
+ if (r_get_style(ctx, node, "draw:marker-end")) {
+ _imp_draw_line_end(ctx, drw_data, 0, 0, x1, y1, x2, y2);
+ }
+ } else if (strcmp(tag, "draw:rect") == 0) {
+ int x, y, w, h, r = 0;
+ char *t;
+ x = r_get_x(ctx, node, "svg:x");
+ y = r_get_y(ctx, node, "svg:y");
+ w = r_get_x(ctx, node, "svg:width");
+ h = r_get_y(ctx, node, "svg:height");
+ t = r_get_style(ctx, node, "draw:corner-radius");
+ if (t) r = atof(t) * ctx->fact_x;
+ t = r_get_style(ctx, node, "draw:fill");
+ if (t && strcmp(t, "none") != 0) {
+ r_get_color(ctx, node, "draw:fill-color", &fg);
+ ctx->drw->set_fg_color(drw_data, &fg);
+ _imp_draw_rect(ctx, drw_data, 1, x, y, w, h, r);
+ }
+ r_get_color(ctx, node, "svg:stroke-color", &fg);
+ ctx->drw->set_fg_color(drw_data, &fg);
+ _imp_draw_rect(ctx, drw_data, 0, x, y, w, h, r);
+ r_text(ctx, drw_data, node);
+ } else if (strcmp(tag, "draw:ellipse") == 0 || strcmp(tag, "draw:circle") == 0) {
+ int sa, ea, fill = 0;
+ r_get_color(ctx, node, "svg:stroke-color", &fg);
+ sa = r_get_angle(node, "draw:start-angle", 0);
+ ea = r_get_angle(node, "draw:end-angle", 360);
+ if (ea > sa) ea = ea - sa; else ea = 360 + ea - sa;
+ t = r_get_style(ctx, node, "draw:fill");
+ if (t) fill = 1;
+ ctx->drw->set_fg_color(drw_data, &fg);
+ ctx->drw->draw_arc(drw_data,
+ fill,
+ r_get_x(ctx, node, "svg:x"), r_get_y(ctx, node, "svg:y"),
+ r_get_x(ctx, node, "svg:width"), r_get_y(ctx, node, "svg:height"),
+ sa, ea
+ );
+ } else if (strcmp(tag, "draw:polygon") == 0) {
+ // FIXME:
+ r_polygon(ctx, drw_data, node);
+ } else if (strcmp(tag, "draw:text-box") == 0) {
+ // FIXME:
+ r_text(ctx, drw_data, node);
+ } else if (strcmp(tag, "draw:image") == 0) {
+ char *name;
+
+ name = iks_find_attrib(node, "xlink:href");
+ if (!name) return;
+ if (name[0] == '#') ++name;
+
+ _imp_draw_image(ctx, drw_data,
+ name,
+ r_get_x(ctx, node, "svg:x"),
+ r_get_y(ctx, node, "svg:y"),
+ r_get_x(ctx, node, "svg:width"),
+ r_get_y(ctx, node, "svg:height")
+ );
+ } else {
+ printf("Unknown element: %s\n", tag);
+ }
+}
+
+static void
+render_page(ImpRenderCtx *ctx, void *drw_data)
+{
+ iks *x;
+ char *element;
+ int i;
+
+ i = _imp_fill_back(ctx, drw_data, ctx->page->page);
+ element = iks_find_attrib(ctx->page->page, "draw:master-page-name");
+ if (element) {
+ x = iks_find_with_attrib(
+ iks_find(ctx->page->doc->styles, "office:master-styles"),
+ "style:master-page", "style:name", element
+ );
+ if (x) {
+ if (i == 0) _imp_fill_back(ctx, drw_data, x);
+ for (x = iks_first_tag(x); x; x = iks_next_tag(x)) {
+ if (iks_find_attrib(x, "presentation:class"))
+ continue;
+ render_object(ctx, drw_data, x);
+ }
+ }
+ }
+ for (x = iks_first_tag(ctx->page->page); x; x = iks_next_tag(x)) {
+ render_object(ctx, drw_data, x);
+ }
+}
+
+static void
+get_geometry(ImpRenderCtx *ctx)
+{
+ char *tmp;
+ iks *x, *y;
+
+ tmp = iks_find_attrib(ctx->page->page, "draw:master-page-name");
+ x = iks_find(ctx->page->doc->styles, "office:master-styles");
+ y = iks_find_with_attrib(x, "style:master-page", "style:name", tmp);
+ x = iks_find(ctx->page->doc->styles, "office:automatic-styles");
+ y = iks_find_with_attrib(x, "style:page-master", "style:name",
+ iks_find_attrib(y, "style:page-master-name"));
+ ctx->cm_w = atof(iks_find_attrib(iks_find(y, "style:properties"), "fo:page-width"));
+ ctx->cm_h = atof(iks_find_attrib(iks_find(y, "style:properties"), "fo:page-height"));
+}
+
+int
+_imp_oo13_load(ImpDoc *doc)
+{
+ ImpPage *page;
+ char *class;
+ iks *x;
+ int i;
+
+ class = iks_find_attrib(doc->content, "office:class");
+ if (iks_strcmp(class, "presentation") != 0) return IMP_NOTIMP;
+
+ x = iks_find(iks_find(doc->content, "office:body"), "draw:page");
+ if (!x) return IMP_NOTIMP;
+ i = 0;
+ for (; x; x = iks_next_tag(x)) {
+ if (strcmp(iks_name(x), "draw:page") == 0) {
+ page = iks_stack_alloc(doc->stack, sizeof(ImpPage));
+ if (!page) return IMP_NOMEM;
+ memset(page, 0, sizeof(ImpPage));
+ page->page = x;
+ page->nr = ++i;
+ page->name = iks_find_attrib(x, "draw:name");
+ page->doc = doc;
+ if (!doc->pages) doc->pages = page;
+ page->prev = doc->last_page;
+ if (doc->last_page) doc->last_page->next = page;
+ doc->last_page = page;
+ }
+ }
+ doc->nr_pages = i;
+ doc->get_geometry = get_geometry;
+ doc->render_page = render_page;
+
+ return 0;
+}
diff --git a/backend/impress/iksemel.c b/backend/impress/iksemel.c
new file mode 100644
index 00000000..9908e132
--- /dev/null
+++ b/backend/impress/iksemel.c
@@ -0,0 +1,1882 @@
+/* iksemel (XML parser for Jabber)
+** Copyright (C) 2000-2003 Gurer Ozen <[email protected]>
+** This code is free software; you can redistribute it and/or
+** modify it under the terms of GNU Lesser General Public License.
+*/
+
+/* minimum sax buffer size */
+#define SAX_BUFFER_MIN_SIZE 128
+
+/* sax parser structure plus extra data of dom parser */
+#define DEFAULT_DOM_CHUNK_SIZE 256
+
+/* sax parser structure plus extra data of stream parser */
+#define DEFAULT_STREAM_CHUNK_SIZE 256
+
+/* iks structure, its data, child iks structures, for stream parsing */
+#define DEFAULT_IKS_CHUNK_SIZE 1024
+
+/* iks structure, its data, child iks structures, for file parsing */
+#define DEFAULT_DOM_IKS_CHUNK_SIZE 2048
+
+/* rule structure and from/to/id/ns strings */
+#define DEFAULT_RULE_CHUNK_SIZE 128
+
+/* file is read by blocks with this size */
+#define FILE_IO_BUF_SIZE 4096
+
+/* network receive buffer */
+#define NET_IO_BUF_SIZE 4096
+/* iksemel (XML parser for Jabber)
+** Copyright (C) 2000-2003 Gurer Ozen <[email protected]>
+** This code is free software; you can redistribute it and/or
+** modify it under the terms of GNU Lesser General Public License.
+*/
+
+#include <config.h>
+#include <errno.h>
+
+#include "common.h"
+#include "iksemel.h"
+
+/***** malloc wrapper *****/
+
+static void *(*my_malloc_func)(size_t size);
+static void (*my_free_func)(void *ptr);
+
+void *
+iks_malloc (size_t size)
+{
+ if (my_malloc_func)
+ return my_malloc_func (size);
+ else
+ return malloc (size);
+}
+
+void
+iks_free (void *ptr)
+{
+ if (my_free_func)
+ my_free_func (ptr);
+ else
+ free (ptr);
+}
+
+void
+iks_set_mem_funcs (void *(*malloc_func)(size_t size), void (*free_func)(void *ptr))
+{
+ my_malloc_func = malloc_func;
+ my_free_func = free_func;
+}
+
+/***** NULL-safe Functions *****/
+
+char *
+iks_strdup (const char *src)
+{
+ if (src) return strdup(src);
+ return NULL;
+}
+
+char *
+iks_strcat (char *dest, const char *src)
+{
+ size_t len;
+
+ if (!src) return dest;
+
+ len = strlen (src);
+ memcpy (dest, src, len);
+ dest[len] = '\0';
+ return dest + len;
+}
+
+int
+iks_strcmp (const char *a, const char *b)
+{
+ if (!a || !b) return -1;
+ return strcmp (a, b);
+}
+
+int
+iks_strcasecmp (const char *a, const char *b)
+{
+ if (!a || !b) return -1;
+ return strcasecmp (a, b);
+}
+
+int
+iks_strncmp (const char *a, const char *b, size_t n)
+{
+ if (!a || !b) return -1;
+ return strncmp (a, b, n);
+}
+
+int
+iks_strncasecmp (const char *a, const char *b, size_t n)
+{
+ if (!a || !b) return -1;
+ return strncasecmp (a, b, n);
+}
+
+size_t
+iks_strlen (const char *src)
+{
+ if (!src) return 0;
+ return strlen (src);
+}
+
+/***** XML Escaping *****/
+
+char *
+iks_escape (ikstack *s, char *src, size_t len)
+{
+ char *ret;
+ int i, j, nlen;
+
+ if (!src || !s) return NULL;
+ if (len == -1) len = strlen (src);
+
+ nlen = len;
+ for (i=0; i<len; i++) {
+ switch (src[i]) {
+ case '&': nlen += 4; break;
+ case '<': nlen += 3; break;
+ case '>': nlen += 3; break;
+ case '\'': nlen += 5; break;
+ case '"': nlen += 5; break;
+ }
+ }
+ if (len == nlen) return src;
+
+ ret = iks_stack_alloc (s, nlen + 1);
+ if (!ret) return NULL;
+
+ for (i=j=0; i<len; i++) {
+ switch (src[i]) {
+ case '&': memcpy (&ret[j], "&amp;", 5); j += 5; break;
+ case '\'': memcpy (&ret[j], "&apos;", 6); j += 6; break;
+ case '"': memcpy (&ret[j], "&quot;", 6); j += 6; break;
+ case '<': memcpy (&ret[j], "&lt;", 4); j += 4; break;
+ case '>': memcpy (&ret[j], "&gt;", 4); j += 4; break;
+ default: ret[j++] = src[i];
+ }
+ }
+ ret[j] = '\0';
+
+ return ret;
+}
+
+char *
+iks_unescape (ikstack *s, char *src, size_t len)
+{
+ int i,j;
+ char *ret;
+
+ if (!s || !src) return NULL;
+ if (!strchr (src, '&')) return src;
+ if (len == -1) len = strlen (src);
+
+ ret = iks_stack_alloc (s, len + 1);
+ if (!ret) return NULL;
+
+ for (i=j=0; i<len; i++) {
+ if (src[i] == '&') {
+ i++;
+ if (strncmp (&src[i], "amp;", 4) == 0) {
+ ret[j] = '&';
+ i += 3;
+ } else if (strncmp (&src[i], "quot;", 5) == 0) {
+ ret[j] = '"';
+ i += 4;
+ } else if (strncmp (&src[i], "apos;", 5) == 0) {
+ ret[j] = '\'';
+ i += 4;
+ } else if (strncmp (&src[i], "lt;", 3) == 0) {
+ ret[j] = '<';
+ i += 2;
+ } else if (strncmp (&src[i], "gt;", 3) == 0) {
+ ret[j] = '>';
+ i += 2;
+ } else {
+ ret[j] = src[--i];
+ }
+ } else {
+ ret[j] = src[i];
+ }
+ j++;
+ }
+ ret[j] = '\0';
+
+ return ret;
+}
+/* iksemel (XML parser for Jabber)
+** Copyright (C) 2000-2004 Gurer Ozen <[email protected]>
+** This code is free software; you can redistribute it and/or
+** modify it under the terms of GNU Lesser General Public License.
+*/
+
+#include "common.h"
+#include "iksemel.h"
+
+struct align_test { char a; double b; };
+#define DEFAULT_ALIGNMENT ((size_t) ((char *) &((struct align_test *) 0)->b - (char *) 0))
+#define ALIGN_MASK ( DEFAULT_ALIGNMENT - 1 )
+#define MIN_CHUNK_SIZE ( DEFAULT_ALIGNMENT * 8 )
+#define MIN_ALLOC_SIZE DEFAULT_ALIGNMENT
+#define ALIGN(x) ( (x) + (DEFAULT_ALIGNMENT - ( (x) & ALIGN_MASK)) )
+
+typedef struct ikschunk_struct {
+ struct ikschunk_struct *next;
+ size_t size;
+ size_t used;
+ size_t last;
+ char data[4];
+} ikschunk;
+
+struct ikstack_struct {
+ size_t allocated;
+ ikschunk *meta;
+ ikschunk *data;
+};
+
+static ikschunk *
+find_space (ikstack *s, ikschunk *c, size_t size)
+{
+ /* FIXME: dont use *2 after over allocated chunks */
+ while (1) {
+ if (c->size - c->used >= size) return c;
+ if (!c->next) {
+ if ((c->size * 2) > size) size = c->size * 2;
+ c->next = iks_malloc (sizeof (ikschunk) + size);
+ if (!c->next) return NULL;
+ s->allocated += sizeof (ikschunk) + size;
+ c = c->next;
+ c->next = NULL;
+ c->size = size;
+ c->used = 0;
+ c->last = (size_t) -1;
+ return c;
+ }
+ c = c->next;
+ }
+ return NULL;
+}
+
+ikstack *
+iks_stack_new (size_t meta_chunk, size_t data_chunk)
+{
+ ikstack *s;
+ size_t len;
+
+ if (meta_chunk < MIN_CHUNK_SIZE) meta_chunk = MIN_CHUNK_SIZE;
+ if (meta_chunk & ALIGN_MASK) meta_chunk = ALIGN (meta_chunk);
+ if (data_chunk < MIN_CHUNK_SIZE) data_chunk = MIN_CHUNK_SIZE;
+ if (data_chunk & ALIGN_MASK) data_chunk = ALIGN (data_chunk);
+
+ len = sizeof (ikstack) + meta_chunk + data_chunk + (sizeof (ikschunk) * 2);
+ s = iks_malloc (len);
+ if (!s) return NULL;
+ s->allocated = len;
+ s->meta = (ikschunk *) ((char *) s + sizeof (ikstack));
+ s->meta->next = NULL;
+ s->meta->size = meta_chunk;
+ s->meta->used = 0;
+ s->meta->last = (size_t) -1;
+ s->data = (ikschunk *) ((char *) s + sizeof (ikstack) + sizeof (ikschunk) + meta_chunk);
+ s->data->next = NULL;
+ s->data->size = data_chunk;
+ s->data->used = 0;
+ s->data->last = (size_t) -1;
+ return s;
+}
+
+void *
+iks_stack_alloc (ikstack *s, size_t size)
+{
+ ikschunk *c;
+ void *mem;
+
+ if (size < MIN_ALLOC_SIZE) size = MIN_ALLOC_SIZE;
+ if (size & ALIGN_MASK) size = ALIGN (size);
+
+ c = find_space (s, s->meta, size);
+ if (!c) return NULL;
+ mem = c->data + c->used;
+ c->used += size;
+ return mem;
+}
+
+char *
+iks_stack_strdup (ikstack *s, const char *src, size_t len)
+{
+ ikschunk *c;
+ char *dest;
+
+ if (!src) return NULL;
+ if (0 == len) len = strlen (src);
+
+ c = find_space (s, s->data, len + 1);
+ if (!c) return NULL;
+ dest = c->data + c->used;
+ c->last = c->used;
+ c->used += len + 1;
+ memcpy (dest, src, len);
+ dest[len] = '\0';
+ return dest;
+}
+
+char *
+iks_stack_strcat (ikstack *s, char *old, size_t old_len, const char *src, size_t src_len)
+{
+ char *ret;
+ ikschunk *c;
+
+ if (!old) {
+ return iks_stack_strdup (s, src, src_len);
+ }
+ if (0 == old_len) old_len = strlen (old);
+ if (0 == src_len) src_len = strlen (src);
+
+ for (c = s->data; c; c = c->next) {
+ if (c->data + c->last == old) break;
+ }
+ if (!c) {
+ c = find_space (s, s->data, old_len + src_len + 1);
+ if (!c) return NULL;
+ ret = c->data + c->used;
+ c->last = c->used;
+ c->used += old_len + src_len + 1;
+ memcpy (ret, old, old_len);
+ memcpy (ret + old_len, src, src_len);
+ ret[old_len + src_len] = '\0';
+ return ret;
+ }
+
+ if (c->size - c->used > src_len) {
+ ret = c->data + c->last;
+ memcpy (ret + old_len, src, src_len);
+ c->used += src_len;
+ ret[old_len + src_len] = '\0';
+ } else {
+ /* FIXME: decrease c->used before moving string to new place */
+ c = find_space (s, s->data, old_len + src_len + 1);
+ if (!c) return NULL;
+ c->last = c->used;
+ ret = c->data + c->used;
+ memcpy (ret, old, old_len);
+ c->used += old_len;
+ memcpy (c->data + c->used, src, src_len);
+ c->used += src_len;
+ c->data[c->used] = '\0';
+ c->used++;
+ }
+ return ret;
+}
+
+void
+iks_stack_stat (ikstack *s, size_t *allocated, size_t *used)
+{
+ ikschunk *c;
+
+ if (allocated) {
+ *allocated = s->allocated;
+ }
+ if (used) {
+ *used = 0;
+ for (c = s->meta; c; c = c->next) {
+ (*used) += c->used;
+ }
+ for (c = s->data; c; c = c->next) {
+ (*used) += c->used;
+ }
+ }
+}
+
+void
+iks_stack_delete (ikstack *s)
+{
+ ikschunk *c, *tmp;
+
+ c = s->meta->next;
+ while (c) {
+ tmp = c->next;
+ iks_free (c);
+ c = tmp;
+ }
+ c = s->data->next;
+ while (c) {
+ tmp = c->next;
+ iks_free (c);
+ c = tmp;
+ }
+ iks_free (s);
+}
+/* iksemel (XML parser for Jabber)
+** Copyright (C) 2000-2004 Gurer Ozen <[email protected]>
+** This code is free software; you can redistribute it and/or
+** modify it under the terms of GNU Lesser General Public License.
+*/
+
+#include "common.h"
+#include "iksemel.h"
+
+enum cons_e {
+ C_CDATA = 0,
+ C_TAG_START,
+ C_TAG,
+ C_TAG_END,
+ C_ATTRIBUTE,
+ C_ATTRIBUTE_1,
+ C_ATTRIBUTE_2,
+ C_VALUE,
+ C_VALUE_APOS,
+ C_VALUE_QUOT,
+ C_WHITESPACE,
+ C_ENTITY,
+ C_COMMENT,
+ C_COMMENT_1,
+ C_COMMENT_2,
+ C_COMMENT_3,
+ C_MARKUP,
+ C_MARKUP_1,
+ C_SECT,
+ C_SECT_CDATA,
+ C_SECT_CDATA_1,
+ C_SECT_CDATA_2,
+ C_SECT_CDATA_3,
+ C_SECT_CDATA_4,
+ C_SECT_CDATA_C,
+ C_SECT_CDATA_E,
+ C_SECT_CDATA_E2,
+ C_PI
+};
+
+/* if you add a variable here, dont forget changing iks_parser_reset */
+struct iksparser_struct {
+ ikstack *s;
+ void *user_data;
+ iksTagHook *tagHook;
+ iksCDataHook *cdataHook;
+ iksDeleteHook *deleteHook;
+ /* parser context */
+ char *stack;
+ size_t stack_pos;
+ size_t stack_max;
+
+ enum cons_e context;
+ enum cons_e oldcontext;
+
+ char *tag_name;
+ enum ikstagtype tagtype;
+
+ unsigned int attmax;
+ unsigned int attcur;
+ int attflag;
+ char **atts;
+ int valflag;
+
+ unsigned int entpos;
+ char entity[8];
+
+ unsigned long nr_bytes;
+ unsigned long nr_lines;
+
+ int uni_max;
+ int uni_len;
+};
+
+iksparser *
+iks_sax_new (void *user_data, iksTagHook *tagHook, iksCDataHook *cdataHook)
+{
+ iksparser *prs;
+
+ prs = iks_malloc (sizeof (iksparser));
+ if (NULL == prs) return NULL;
+ memset (prs, 0, sizeof (iksparser));
+ prs->user_data = user_data;
+ prs->tagHook = tagHook;
+ prs->cdataHook = cdataHook;
+ return prs;
+}
+
+iksparser *
+iks_sax_extend (ikstack *s, void *user_data, iksTagHook *tagHook, iksCDataHook *cdataHook, iksDeleteHook *deleteHook)
+{
+ iksparser *prs;
+
+ prs = iks_stack_alloc (s, sizeof (iksparser));
+ if (NULL == prs) return NULL;
+ memset (prs, 0, sizeof (iksparser));
+ prs->s = s;
+ prs->user_data = user_data;
+ prs->tagHook = tagHook;
+ prs->cdataHook = cdataHook;
+ prs->deleteHook = deleteHook;
+ return prs;
+}
+
+ikstack *
+iks_parser_stack (iksparser *prs)
+{
+ return prs->s;
+}
+
+void *
+iks_user_data (iksparser *prs)
+{
+ return prs->user_data;
+}
+
+unsigned long
+iks_nr_bytes (iksparser *prs)
+{
+ return prs->nr_bytes;
+}
+
+unsigned long
+iks_nr_lines (iksparser *prs)
+{
+ return prs->nr_lines;
+}
+
+#define IS_WHITESPACE(x) ' ' == (x) || '\t' == (x) || '\r' == (x) || '\n' == (x)
+#define NOT_WHITESPACE(x) ' ' != (x) && '\t' != (x) && '\r' != (x) && '\n' != (x)
+
+static int
+stack_init (iksparser *prs)
+{
+ prs->stack = iks_malloc (128);
+ if (!prs->stack) return 0;
+ prs->stack_max = 128;
+ prs->stack_pos = 0;
+ return 1;
+}
+
+static int
+stack_expand (iksparser *prs, int len)
+{
+ size_t need;
+ off_t diff;
+ char *tmp;
+ need = len - (prs->stack_max - prs->stack_pos);
+ if (need < prs->stack_max) {
+ need = prs->stack_max * 2;
+ } else {
+ need = prs->stack_max + (need * 1.2);
+ }
+ tmp = iks_malloc (need);
+ if (!tmp) return 0;
+ diff = tmp - prs->stack;
+ memcpy (tmp, prs->stack, prs->stack_max);
+ iks_free (prs->stack);
+ prs->stack = tmp;
+ prs->stack_max = need;
+ prs->tag_name += diff;
+ if (prs->attflag != 0) {
+ int i = 0;
+ while (i < (prs->attmax * 2)) {
+ if (prs->atts[i]) prs->atts[i] += diff;
+ i++;
+ }
+ }
+ return 1;
+}
+
+#define STACK_INIT \
+ if (NULL == prs->stack && 0 == stack_init (prs)) return IKS_NOMEM
+
+#define STACK_PUSH_START (prs->stack + prs->stack_pos)
+
+#define STACK_PUSH(buf,len) \
+{ \
+ char *sbuf = (buf); \
+ size_t slen = (len); \
+ if (prs->stack_max - prs->stack_pos <= slen) { \
+ if (0 == stack_expand (prs, slen)) return IKS_NOMEM; \
+ } \
+ memcpy (prs->stack + prs->stack_pos, sbuf, slen); \
+ prs->stack_pos += slen; \
+}
+
+#define STACK_PUSH_END \
+{ \
+ if (prs->stack_pos >= prs->stack_max) { \
+ if (0 == stack_expand (prs, 1)) return IKS_NOMEM; \
+ } \
+ prs->stack[prs->stack_pos] = '\0'; \
+ prs->stack_pos++; \
+}
+
+static enum ikserror
+sax_core (iksparser *prs, char *buf, int len)
+{
+ enum ikserror err;
+ int pos = 0, old = 0, re, stack_old = -1;
+ unsigned char c;
+
+ while (pos < len) {
+ re = 0;
+ c = buf[pos];
+ if (0 == c || 0xFE == c || 0xFF == c) return IKS_BADXML;
+ if (prs->uni_max) {
+ if ((c & 0xC0) != 0x80) return IKS_BADXML;
+ prs->uni_len++;
+ if (prs->uni_len == prs->uni_max) prs->uni_max = 0;
+ goto cont;
+ } else {
+ if (c & 0x80) {
+ unsigned char mask;
+ if ((c & 0x60) == 0x40) {
+ prs->uni_max = 2;
+ mask = 0x1F;
+ } else if ((c & 0x70) == 0x60) {
+ prs->uni_max = 3;
+ mask = 0x0F;
+ } else if ((c & 0x78) == 0x70) {
+ prs->uni_max = 4;
+ mask = 0x07;
+ } else if ((c & 0x7C) == 0x78) {
+ prs->uni_max = 5;
+ mask = 0x03;
+ } else if ((c & 0x7E) == 0x7C) {
+ prs->uni_max = 6;
+ mask = 0x01;
+ } else {
+ return IKS_BADXML;
+ }
+ if ((c & mask) == 0) return IKS_BADXML;
+ prs->uni_len = 1;
+ if (stack_old == -1) stack_old = pos;
+ goto cont;
+ }
+ }
+
+ switch (prs->context) {
+ case C_CDATA:
+ if ('&' == c) {
+ if (old < pos && prs->cdataHook) {
+ err = prs->cdataHook (prs->user_data, &buf[old], pos - old);
+ if (IKS_OK != err) return err;
+ }
+ prs->context = C_ENTITY;
+ prs->entpos = 0;
+ break;
+ }
+ if ('<' == c) {
+ if (old < pos && prs->cdataHook) {
+ err = prs->cdataHook (prs->user_data, &buf[old], pos - old);
+ if (IKS_OK != err) return err;
+ }
+ STACK_INIT;
+ prs->tag_name = STACK_PUSH_START;
+ if (!prs->tag_name) return IKS_NOMEM;
+ prs->context = C_TAG_START;
+ }
+ break;
+
+ case C_TAG_START:
+ prs->context = C_TAG;
+ if ('/' == c) {
+ prs->tagtype = IKS_CLOSE;
+ break;
+ }
+ if ('?' == c) {
+ prs->context = C_PI;
+ break;
+ }
+ if ('!' == c) {
+ prs->context = C_MARKUP;
+ break;
+ }
+ prs->tagtype = IKS_OPEN;
+ stack_old = pos;
+ break;
+
+ case C_TAG:
+ if (IS_WHITESPACE(c)) {
+ if (IKS_CLOSE == prs->tagtype)
+ prs->oldcontext = C_TAG_END;
+ else
+ prs->oldcontext = C_ATTRIBUTE;
+ prs->context = C_WHITESPACE;
+ if (stack_old != -1) STACK_PUSH (buf + stack_old, pos - stack_old);
+ stack_old = -1;
+ STACK_PUSH_END;
+ break;
+ }
+ if ('/' == c) {
+ if (IKS_CLOSE == prs->tagtype) return IKS_BADXML;
+ prs->tagtype = IKS_SINGLE;
+ prs->context = C_TAG_END;
+ if (stack_old != -1) STACK_PUSH (buf + stack_old, pos - stack_old);
+ stack_old = -1;
+ STACK_PUSH_END;
+ break;
+ }
+ if ('>' == c) {
+ prs->context = C_TAG_END;
+ if (stack_old != -1) STACK_PUSH (buf + stack_old, pos - stack_old);
+ stack_old = -1;
+ STACK_PUSH_END;
+ re = 1;
+ }
+ if (stack_old == -1) stack_old = pos;
+ break;
+
+ case C_TAG_END:
+ if (c != '>') return IKS_BADXML;
+ if (prs->tagHook) {
+ char **tmp;
+ if (prs->attcur == 0) tmp = NULL; else tmp = prs->atts;
+ err = prs->tagHook (prs->user_data, prs->tag_name, tmp, prs->tagtype);
+ if (IKS_OK != err) return err;
+ }
+ prs->stack_pos = 0;
+ stack_old = -1;
+ prs->attcur = 0;
+ prs->attflag = 0;
+ prs->context = C_CDATA;
+ old = pos + 1;
+ break;
+
+ case C_ATTRIBUTE:
+ if ('/' == c) {
+ prs->tagtype = IKS_SINGLE;
+ prs->context = C_TAG_END;
+ break;
+ }
+ if ('>' == c) {
+ prs->context = C_TAG_END;
+ re = 1;
+ break;
+ }
+ if (!prs->atts) {
+ prs->attmax = 12;
+ prs->atts = iks_malloc (sizeof(char *) * 2 * 12);
+ if (!prs->atts) return IKS_NOMEM;
+ memset (prs->atts, 0, sizeof(char *) * 2 * 12);
+ prs->attcur = 0;
+ } else {
+ if (prs->attcur >= (prs->attmax * 2)) {
+ void *tmp;
+ prs->attmax += 12;
+ tmp = iks_malloc (sizeof(char *) * (2 * prs->attmax + 1));
+ if (!tmp) return IKS_NOMEM;
+ memset (tmp, 0, sizeof(char *) * (2 * prs->attmax + 1));
+ memcpy (tmp, prs->atts, sizeof(char *) * prs->attcur);
+ iks_free (prs->atts);
+ prs->atts = tmp;
+ }
+ }
+ prs->attflag = 1;
+ prs->atts[prs->attcur] = STACK_PUSH_START;
+ stack_old = pos;
+ prs->context = C_ATTRIBUTE_1;
+ break;
+
+ case C_ATTRIBUTE_1:
+ if ('=' == c) {
+ if (stack_old != -1) STACK_PUSH (buf + stack_old, pos - stack_old);
+ stack_old = -1;
+ STACK_PUSH_END;
+ prs->context = C_VALUE;
+ break;
+ }
+ if (stack_old == -1) stack_old = pos;
+ break;
+
+ case C_ATTRIBUTE_2:
+ if ('/' == c) {
+ prs->tagtype = IKS_SINGLE;
+ prs->atts[prs->attcur] = NULL;
+ prs->context = C_TAG_END;
+ break;
+ }
+ if ('>' == c) {
+ prs->atts[prs->attcur] = NULL;
+ prs->context = C_TAG_END;
+ re = 1;
+ break;
+ }
+ prs->context = C_ATTRIBUTE;
+ re = 1;
+ break;
+
+ case C_VALUE:
+ prs->atts[prs->attcur + 1] = STACK_PUSH_START;
+ if ('\'' == c) {
+ prs->context = C_VALUE_APOS;
+ break;
+ }
+ if ('"' == c) {
+ prs->context = C_VALUE_QUOT;
+ break;
+ }
+ return IKS_BADXML;
+
+ case C_VALUE_APOS:
+ if ('\'' == c) {
+ if (stack_old != -1) STACK_PUSH (buf + stack_old, pos - stack_old);
+ stack_old = -1;
+ STACK_PUSH_END;
+ prs->oldcontext = C_ATTRIBUTE_2;
+ prs->context = C_WHITESPACE;
+ prs->attcur += 2;
+ }
+ if (stack_old == -1) stack_old = pos;
+ break;
+
+ case C_VALUE_QUOT:
+ if ('"' == c) {
+ if (stack_old != -1) STACK_PUSH (buf + stack_old, pos - stack_old);
+ stack_old = -1;
+ STACK_PUSH_END;
+ prs->oldcontext = C_ATTRIBUTE_2;
+ prs->context = C_WHITESPACE;
+ prs->attcur += 2;
+ }
+ if (stack_old == -1) stack_old = pos;
+ break;
+
+ case C_WHITESPACE:
+ if (NOT_WHITESPACE(c)) {
+ prs->context = prs->oldcontext;
+ re = 1;
+ }
+ break;
+
+ case C_ENTITY:
+ if (';' == c) {
+ char hede[2];
+ char t = '?';
+ prs->entity[prs->entpos] = '\0';
+ if (strcmp(prs->entity, "amp") == 0)
+ t = '&';
+ else if (strcmp(prs->entity, "quot") == 0)
+ t = '"';
+ else if (strcmp(prs->entity, "apos") == 0)
+ t = '\'';
+ else if (strcmp(prs->entity, "lt") == 0)
+ t = '<';
+ else if (strcmp(prs->entity, "gt") == 0)
+ t = '>';
+ old = pos + 1;
+ hede[0] = t;
+ if (prs->cdataHook) {
+ err = prs->cdataHook (prs->user_data, &hede[0], 1);
+ if (IKS_OK != err) return err;
+ }
+ prs->context = C_CDATA;
+ } else {
+ prs->entity[prs->entpos++] = buf[pos];
+ if (prs->entpos > 7) return IKS_BADXML;
+ }
+ break;
+
+ case C_COMMENT:
+ if ('-' != c) return IKS_BADXML;
+ prs->context = C_COMMENT_1;
+ break;
+
+ case C_COMMENT_1:
+ if ('-' == c) prs->context = C_COMMENT_2;
+ break;
+
+ case C_COMMENT_2:
+ if ('-' == c)
+ prs->context = C_COMMENT_3;
+ else
+ prs->context = C_COMMENT_1;
+ break;
+
+ case C_COMMENT_3:
+ if ('>' != c) return IKS_BADXML;
+ prs->context = C_CDATA;
+ old = pos + 1;
+ break;
+
+ case C_MARKUP:
+ if ('[' == c) {
+ prs->context = C_SECT;
+ break;
+ }
+ if ('-' == c) {
+ prs->context = C_COMMENT;
+ break;
+ }
+ prs->context = C_MARKUP_1;
+
+ case C_MARKUP_1:
+ if ('>' == c) {
+ old = pos + 1;
+ prs->context = C_CDATA;
+ }
+ break;
+
+ case C_SECT:
+ if ('C' == c) {
+ prs->context = C_SECT_CDATA;
+ break;
+ }
+ return IKS_BADXML;
+
+ case C_SECT_CDATA:
+ if ('D' != c) return IKS_BADXML;
+ prs->context = C_SECT_CDATA_1;
+ break;
+
+ case C_SECT_CDATA_1:
+ if ('A' != c) return IKS_BADXML;
+ prs->context = C_SECT_CDATA_2;
+ break;
+
+ case C_SECT_CDATA_2:
+ if ('T' != c) return IKS_BADXML;
+ prs->context = C_SECT_CDATA_3;
+ break;
+
+ case C_SECT_CDATA_3:
+ if ('A' != c) return IKS_BADXML;
+ prs->context = C_SECT_CDATA_4;
+ break;
+
+ case C_SECT_CDATA_4:
+ if ('[' != c) return IKS_BADXML;
+ old = pos + 1;
+ prs->context = C_SECT_CDATA_C;
+ break;
+
+ case C_SECT_CDATA_C:
+ if (']' == c) {
+ prs->context = C_SECT_CDATA_E;
+ if (prs->cdataHook && old < pos) {
+ err = prs->cdataHook (prs->user_data, &buf[old], pos - old);
+ if (IKS_OK != err) return err;
+ }
+ }
+ break;
+
+ case C_SECT_CDATA_E:
+ if (']' == c) {
+ prs->context = C_SECT_CDATA_E2;
+ } else {
+ if (prs->cdataHook) {
+ err = prs->cdataHook (prs->user_data, "]", 1);
+ if (IKS_OK != err) return err;
+ }
+ old = pos;
+ prs->context = C_SECT_CDATA_C;
+ }
+ break;
+
+ case C_SECT_CDATA_E2:
+ if ('>' == c) {
+ old = pos + 1;
+ prs->context = C_CDATA;
+ } else {
+ if (prs->cdataHook) {
+ err = prs->cdataHook (prs->user_data, "]]", 2);
+ if (IKS_OK != err) return err;
+ }
+ old = pos;
+ prs->context = C_SECT_CDATA_C;
+ }
+ break;
+
+ case C_PI:
+ old = pos + 1;
+ if ('>' == c) prs->context = C_CDATA;
+ break;
+ }
+cont:
+ if (0 == re) {
+ pos++;
+ prs->nr_bytes++;
+ if ('\n' == c) prs->nr_lines++;
+ }
+ }
+
+ if (stack_old != -1)
+ STACK_PUSH (buf + stack_old, pos - stack_old);
+
+ err = IKS_OK;
+ if (prs->cdataHook && (prs->context == C_CDATA || prs->context == C_SECT_CDATA_C) && old < pos)
+ err = prs->cdataHook (prs->user_data, &buf[old], pos - old);
+ return err;
+}
+
+int
+iks_parse (iksparser *prs, const char *data, size_t len, int finish)
+{
+ if (!data) return IKS_OK;
+ if (len == 0) len = strlen (data);
+ return sax_core (prs, (char *) data, len);
+}
+
+void
+iks_parser_reset (iksparser *prs)
+{
+ if (prs->deleteHook) prs->deleteHook (prs->user_data);
+ prs->stack_pos = 0;
+ prs->context = 0;
+ prs->oldcontext = 0;
+ prs->tagtype = 0;
+ prs->attcur = 0;
+ prs->attflag = 0;
+ prs->valflag = 0;
+ prs->entpos = 0;
+ prs->nr_bytes = 0;
+ prs->nr_lines = 0;
+ prs->uni_max = 0;
+ prs->uni_len = 0;
+}
+
+void
+iks_parser_delete (iksparser *prs)
+{
+ if (prs->deleteHook) prs->deleteHook (prs->user_data);
+ if (prs->stack) iks_free (prs->stack);
+ if (prs->atts) iks_free (prs->atts);
+ if (prs->s) iks_stack_delete (prs->s); else iks_free (prs);
+}
+/* iksemel (XML parser for Jabber)
+** Copyright (C) 2000-2004 Gurer Ozen <[email protected]>
+** This code is free software; you can redistribute it and/or
+** modify it under the terms of GNU Lesser General Public License.
+*/
+
+#include "common.h"
+#include "iksemel.h"
+
+#define IKS_COMMON \
+ struct iks_struct *next, *prev; \
+ struct iks_struct *parent; \
+ enum ikstype type; \
+ ikstack *s
+
+struct iks_struct {
+ IKS_COMMON;
+};
+
+struct iks_tag {
+ IKS_COMMON;
+ struct iks_struct *children, *last_child;
+ struct iks_struct *attribs, *last_attrib;
+ char *name;
+};
+
+#define IKS_TAG_NAME(x) ((struct iks_tag *) (x) )->name
+#define IKS_TAG_CHILDREN(x) ((struct iks_tag *) (x) )->children
+#define IKS_TAG_LAST_CHILD(x) ((struct iks_tag *) (x) )->last_child
+#define IKS_TAG_ATTRIBS(x) ((struct iks_tag *) (x) )->attribs
+#define IKS_TAG_LAST_ATTRIB(x) ((struct iks_tag *) (x) )->last_attrib
+
+struct iks_cdata {
+ IKS_COMMON;
+ char *cdata;
+ size_t len;
+};
+
+#define IKS_CDATA_CDATA(x) ((struct iks_cdata *) (x) )->cdata
+#define IKS_CDATA_LEN(x) ((struct iks_cdata *) (x) )->len
+
+struct iks_attrib {
+ IKS_COMMON;
+ char *name;
+ char *value;
+};
+
+#define IKS_ATTRIB_NAME(x) ((struct iks_attrib *) (x) )->name
+#define IKS_ATTRIB_VALUE(x) ((struct iks_attrib *) (x) )->value
+
+/***** Node Creating & Deleting *****/
+
+iks *
+iks_new (const char *name)
+{
+ ikstack *s;
+ iks *x;
+
+ s = iks_stack_new (sizeof (struct iks_tag) * 6, 256);
+ if (!s) return NULL;
+ x = iks_new_within (name, s);
+ if (!x) {
+ iks_stack_delete (s);
+ return NULL;
+ }
+ return x;
+}
+
+iks *
+iks_new_within (const char *name, ikstack *s)
+{
+ iks *x;
+ size_t len;
+
+ if (name) len = sizeof (struct iks_tag); else len = sizeof (struct iks_cdata);
+ x = iks_stack_alloc (s, len);
+ if (!x) return NULL;
+ memset (x, 0, len);
+ x->s = s;
+ x->type = IKS_TAG;
+ if (name) {
+ IKS_TAG_NAME (x) = iks_stack_strdup (s, name, 0);
+ if (!IKS_TAG_NAME (x)) return NULL;
+ }
+ return x;
+}
+
+iks *
+iks_insert (iks *x, const char *name)
+{
+ iks *y;
+
+ if (!x) return NULL;
+
+ y = iks_new_within (name, x->s);
+ if (!y) return NULL;
+ y->parent = x;
+ if (!IKS_TAG_CHILDREN (x)) IKS_TAG_CHILDREN (x) = y;
+ if (IKS_TAG_LAST_CHILD (x)) {
+ IKS_TAG_LAST_CHILD (x)->next = y;
+ y->prev = IKS_TAG_LAST_CHILD (x);
+ }
+ IKS_TAG_LAST_CHILD (x) = y;
+ return y;
+}
+
+iks *
+iks_insert_cdata (iks *x, const char *data, size_t len)
+{
+ iks *y;
+
+ if(!x || !data) return NULL;
+ if(len == 0) len = strlen (data);
+
+ y = IKS_TAG_LAST_CHILD (x);
+ if (y && y->type == IKS_CDATA) {
+ IKS_CDATA_CDATA (y) = iks_stack_strcat (x->s, IKS_CDATA_CDATA (y), IKS_CDATA_LEN (y), data, len);
+ IKS_CDATA_LEN (y) += len;
+ } else {
+ y = iks_insert (x, NULL);
+ if (!y) return NULL;
+ y->type = IKS_CDATA;
+ IKS_CDATA_CDATA (y) = iks_stack_strdup (x->s, data, len);
+ if (!IKS_CDATA_CDATA (y)) return NULL;
+ IKS_CDATA_LEN (y) = len;
+ }
+ return y;
+}
+
+iks *
+iks_insert_attrib (iks *x, const char *name, const char *value)
+{
+ iks *y;
+ size_t len;
+
+ if (!x) return NULL;
+
+ y = IKS_TAG_ATTRIBS (x);
+ while (y) {
+ if (strcmp (name, IKS_ATTRIB_NAME (y)) == 0) break;
+ y = y->next;
+ }
+ if (NULL == y) {
+ if (!value) return NULL;
+ y = iks_stack_alloc (x->s, sizeof (struct iks_attrib));
+ if (!y) return NULL;
+ memset (y, 0, sizeof (struct iks_attrib));
+ y->type = IKS_ATTRIBUTE;
+ IKS_ATTRIB_NAME (y) = iks_stack_strdup (x->s, name, 0);
+ y->parent = x;
+ if (!IKS_TAG_ATTRIBS (x)) IKS_TAG_ATTRIBS (x) = y;
+ if (IKS_TAG_LAST_ATTRIB (x)) {
+ IKS_TAG_LAST_ATTRIB (x)->next = y;
+ y->prev = IKS_TAG_LAST_ATTRIB (x);
+ }
+ IKS_TAG_LAST_ATTRIB (x) = y;
+ }
+
+ if (value) {
+ len = strlen (value);
+ IKS_ATTRIB_VALUE (y) = iks_stack_strdup (x->s, value, len);
+ if (!IKS_ATTRIB_VALUE (y)) return NULL;
+ } else {
+ if (y->next) y->next->prev = y->prev;
+ if (y->prev) y->prev->next = y->next;
+ if (IKS_TAG_ATTRIBS (x) == y) IKS_TAG_ATTRIBS (x) = y->next;
+ if (IKS_TAG_LAST_ATTRIB (x) == y) IKS_TAG_LAST_ATTRIB (x) = y->prev;
+ }
+
+ return y;
+}
+
+iks *
+iks_insert_node (iks *x, iks *y)
+{
+ y->parent = x;
+ if (!IKS_TAG_CHILDREN (x)) IKS_TAG_CHILDREN (x) = y;
+ if (IKS_TAG_LAST_CHILD (x)) {
+ IKS_TAG_LAST_CHILD (x)->next = y;
+ y->prev = IKS_TAG_LAST_CHILD (x);
+ }
+ IKS_TAG_LAST_CHILD (x) = y;
+ return y;
+}
+
+void
+iks_hide (iks *x)
+{
+ iks *y;
+
+ if (!x) return;
+
+ if (x->prev) x->prev->next = x->next;
+ if (x->next) x->next->prev = x->prev;
+ y = x->parent;
+ if (y) {
+ if (IKS_TAG_CHILDREN (y) == x) IKS_TAG_CHILDREN (y) = x->next;
+ if (IKS_TAG_LAST_CHILD (y) == x) IKS_TAG_LAST_CHILD (y) = x->prev;
+ }
+}
+
+void
+iks_delete (iks *x)
+{
+ if (x) iks_stack_delete (x->s);
+}
+
+/***** Node Traversing *****/
+
+iks *
+iks_next (iks *x)
+{
+ if (x) return x->next;
+ return NULL;
+}
+
+iks *
+iks_next_tag (iks *x)
+{
+ if (x) {
+ while (1) {
+ x = x->next;
+ if (NULL == x) break;
+ if (IKS_TAG == x->type) return x;
+ }
+ }
+ return NULL;
+}
+
+iks *
+iks_prev (iks *x)
+{
+ if (x) return x->prev;
+ return NULL;
+}
+
+iks *
+iks_prev_tag (iks *x)
+{
+ if (x) {
+ while (1) {
+ x = x->prev;
+ if (NULL == x) break;
+ if (IKS_TAG == x->type) return x;
+ }
+ }
+ return NULL;
+}
+
+iks *
+iks_parent (iks *x)
+{
+ if (x) return x->parent;
+ return NULL;
+}
+
+iks *
+iks_root (iks *x)
+{
+ if (x) {
+ while (x->parent)
+ x = x->parent;
+ }
+ return x;
+}
+
+iks *
+iks_child (iks *x)
+{
+ if (x) return IKS_TAG_CHILDREN (x);
+ return NULL;
+}
+
+iks *
+iks_first_tag (iks *x)
+{
+ if (x) {
+ x = IKS_TAG_CHILDREN (x);
+ while (x) {
+ if (IKS_TAG == x->type) return x;
+ x = x->next;
+ }
+ }
+ return NULL;
+}
+
+iks *
+iks_attrib (iks *x)
+{
+ if (x) return IKS_TAG_ATTRIBS (x);
+ return NULL;
+}
+
+iks *
+iks_find (iks *x, const char *name)
+{
+ iks *y;
+
+ if (!x) return NULL;
+ y = IKS_TAG_CHILDREN (x);
+ while (y) {
+ if (IKS_TAG == y->type && IKS_TAG_NAME (y) && strcmp (IKS_TAG_NAME (y), name) == 0) return y;
+ y = y->next;
+ }
+ return NULL;
+}
+
+char *
+iks_find_cdata (iks *x, const char *name)
+{
+ iks *y;
+
+ y = iks_find (x, name);
+ if (!y) return NULL;
+ y = IKS_TAG_CHILDREN (y);
+ if (!y || IKS_CDATA != y->type) return NULL;
+ return IKS_CDATA_CDATA (y);
+}
+
+char *
+iks_find_attrib (iks *x, const char *name)
+{
+ iks *y;
+
+ if (!x) return NULL;
+
+ y = IKS_TAG_ATTRIBS (x);
+ while (y) {
+ if (IKS_ATTRIB_NAME (y) && strcmp (IKS_ATTRIB_NAME (y), name) == 0)
+ return IKS_ATTRIB_VALUE (y);
+ y = y->next;
+ }
+ return NULL;
+}
+
+iks *
+iks_find_with_attrib (iks *x, const char *tagname, const char *attrname, const char *value)
+{
+ iks *y;
+
+ if (NULL == x) return NULL;
+
+ if (tagname) {
+ for (y = IKS_TAG_CHILDREN (x); y; y = y->next) {
+ if (IKS_TAG == y->type
+ && strcmp (IKS_TAG_NAME (y), tagname) == 0
+ && iks_strcmp (iks_find_attrib (y, attrname), value) == 0) {
+ return y;
+ }
+ }
+ } else {
+ for (y = IKS_TAG_CHILDREN (x); y; y = y->next) {
+ if (IKS_TAG == y->type
+ && iks_strcmp (iks_find_attrib (y, attrname), value) == 0) {
+ return y;
+ }
+ }
+ }
+ return NULL;
+}
+
+/***** Node Information *****/
+
+ikstack *
+iks_stack (iks *x)
+{
+ if (x) return x->s;
+ return NULL;
+}
+
+enum ikstype
+iks_type (iks *x)
+{
+ if (x) return x->type;
+ return IKS_NONE;
+}
+
+char *
+iks_name (iks *x)
+{
+ if (x) {
+ if (IKS_TAG == x->type)
+ return IKS_TAG_NAME (x);
+ else
+ return IKS_ATTRIB_NAME (x);
+ }
+ return NULL;
+}
+
+char *
+iks_cdata (iks *x)
+{
+ if (x) {
+ if (IKS_CDATA == x->type)
+ return IKS_CDATA_CDATA (x);
+ else
+ return IKS_ATTRIB_VALUE (x);
+ }
+ return NULL;
+}
+
+size_t
+iks_cdata_size (iks *x)
+{
+ if (x) return IKS_CDATA_LEN (x);
+ return 0;
+}
+
+int
+iks_has_children (iks *x)
+{
+ if (x && IKS_TAG == x->type && IKS_TAG_CHILDREN (x)) return 1;
+ return 0;
+}
+
+int
+iks_has_attribs (iks *x)
+{
+ if (x && IKS_TAG == x->type && IKS_TAG_ATTRIBS (x)) return 1;
+ return 0;
+}
+
+/***** Serializing *****/
+
+static size_t
+escape_size (char *src, size_t len)
+{
+ size_t sz;
+ char c;
+ int i;
+
+ sz = 0;
+ for (i = 0; i < len; i++) {
+ c = src[i];
+ switch (c) {
+ case '&': sz += 5; break;
+ case '\'': sz += 6; break;
+ case '"': sz += 6; break;
+ case '<': sz += 4; break;
+ case '>': sz += 4; break;
+ default: sz++; break;
+ }
+ }
+ return sz;
+}
+
+static char *
+my_strcat (char *dest, char *src, size_t len)
+{
+ if (0 == len) len = strlen (src);
+ memcpy (dest, src, len);
+ return dest + len;
+}
+
+static char *
+escape (char *dest, char *src, size_t len)
+{
+ char c;
+ int i;
+ int j = 0;
+
+ for (i = 0; i < len; i++) {
+ c = src[i];
+ if ('&' == c || '<' == c || '>' == c || '\'' == c || '"' == c) {
+ if (i - j > 0) dest = my_strcat (dest, src + j, i - j);
+ j = i + 1;
+ switch (c) {
+ case '&': dest = my_strcat (dest, "&amp;", 5); break;
+ case '\'': dest = my_strcat (dest, "&apos;", 6); break;
+ case '"': dest = my_strcat (dest, "&quot;", 6); break;
+ case '<': dest = my_strcat (dest, "&lt;", 4); break;
+ case '>': dest = my_strcat (dest, "&gt;", 4); break;
+ }
+ }
+ }
+ if (i - j > 0) dest = my_strcat (dest, src + j, i - j);
+ return dest;
+}
+
+char *
+iks_string (ikstack *s, iks *x)
+{
+ size_t size;
+ int level, dir;
+ iks *y, *z;
+ char *ret, *t;
+
+ if (!x) return NULL;
+
+ if (x->type == IKS_CDATA) {
+ if (s) {
+ return iks_stack_strdup (s, IKS_CDATA_CDATA (x), IKS_CDATA_LEN (x));
+ } else {
+ ret = iks_malloc (IKS_CDATA_LEN (x));
+ memcpy (ret, IKS_CDATA_CDATA (x), IKS_CDATA_LEN (x));
+ return ret;
+ }
+ }
+
+ size = 0;
+ level = 0;
+ dir = 0;
+ y = x;
+ while (1) {
+ if (dir==0) {
+ if (y->type == IKS_TAG) {
+ size++;
+ size += strlen (IKS_TAG_NAME (y));
+ for (z = IKS_TAG_ATTRIBS (y); z; z = z->next) {
+ size += 4 + strlen (IKS_ATTRIB_NAME (z))
+ + escape_size (IKS_ATTRIB_VALUE (z), strlen (IKS_ATTRIB_VALUE (z)));
+ }
+ if (IKS_TAG_CHILDREN (y)) {
+ size++;
+ y = IKS_TAG_CHILDREN (y);
+ level++;
+ continue;
+ } else {
+ size += 2;
+ }
+ } else {
+ size += escape_size (IKS_CDATA_CDATA (y), IKS_CDATA_LEN (y));
+ }
+ }
+ z = y->next;
+ if (z) {
+ if (0 == level) {
+ if (IKS_TAG_CHILDREN (y)) size += 3 + strlen (IKS_TAG_NAME (y));
+ break;
+ }
+ y = z;
+ dir = 0;
+ } else {
+ y = y->parent;
+ level--;
+ if (level >= 0) size += 3 + strlen (IKS_TAG_NAME (y));
+ if (level < 1) break;
+ dir = 1;
+ }
+ }
+
+ if (s) ret = iks_stack_alloc (s, size + 1);
+ else ret = iks_malloc (size + 1);
+
+ if (!ret) return NULL;
+
+ t = ret;
+ level = 0;
+ dir = 0;
+ while (1) {
+ if (dir==0) {
+ if (x->type == IKS_TAG) {
+ *t++ = '<';
+ t = my_strcat (t, IKS_TAG_NAME (x), 0);
+ y = IKS_TAG_ATTRIBS (x);
+ while (y) {
+ *t++ = ' ';
+ t = my_strcat (t, IKS_ATTRIB_NAME (y), 0);
+ *t++ = '=';
+ *t++ = '\'';
+ t = escape (t, IKS_ATTRIB_VALUE (y), strlen (IKS_ATTRIB_VALUE (y)));
+ *t++ = '\'';
+ y = y->next;
+ }
+ if (IKS_TAG_CHILDREN (x)) {
+ *t++ = '>';
+ x = IKS_TAG_CHILDREN (x);
+ level++;
+ continue;
+ } else {
+ *t++ = '/';
+ *t++ = '>';
+ }
+ } else {
+ t = escape (t, IKS_CDATA_CDATA (x), IKS_CDATA_LEN (x));
+ }
+ }
+ y = x->next;
+ if (y) {
+ if (0 == level) {
+ if (IKS_TAG_CHILDREN (x)) {
+ *t++ = '<';
+ *t++ = '/';
+ t = my_strcat (t, IKS_TAG_NAME (x), 0);
+ *t++ = '>';
+ }
+ break;
+ }
+ x = y;
+ dir = 0;
+ } else {
+ x = x->parent;
+ level--;
+ if (level >= 0) {
+ *t++ = '<';
+ *t++ = '/';
+ t = my_strcat (t, IKS_TAG_NAME (x), 0);
+ *t++ = '>';
+ }
+ if (level < 1) break;
+ dir = 1;
+ }
+ }
+ *t = '\0';
+
+ return ret;
+}
+
+/***** Copying *****/
+
+iks *
+iks_copy_within (iks *x, ikstack *s)
+{
+ int level=0, dir=0;
+ iks *copy = NULL;
+ iks *cur = NULL;
+ iks *y;
+
+ while (1) {
+ if (dir == 0) {
+ if (x->type == IKS_TAG) {
+ if (copy == NULL) {
+ copy = iks_new_within (IKS_TAG_NAME (x), s);
+ cur = copy;
+ } else {
+ cur = iks_insert (cur, IKS_TAG_NAME (x));
+ }
+ for (y = IKS_TAG_ATTRIBS (x); y; y = y->next) {
+ iks_insert_attrib (cur, IKS_ATTRIB_NAME (y), IKS_ATTRIB_VALUE (y));
+ }
+ if (IKS_TAG_CHILDREN (x)) {
+ x = IKS_TAG_CHILDREN (x);
+ level++;
+ continue;
+ } else {
+ cur = cur->parent;
+ }
+ } else {
+ iks_insert_cdata (cur, IKS_CDATA_CDATA (x), IKS_CDATA_LEN (x));
+ }
+ }
+ y = x->next;
+ if (y) {
+ if (0 == level) break;
+ x = y;
+ dir = 0;
+ } else {
+ if (level < 2) break;
+ level--;
+ x = x->parent;
+ cur = cur->parent;
+ dir = 1;
+ }
+ }
+ return copy;
+}
+
+iks *
+iks_copy (iks *x)
+{
+ return iks_copy_within (x, iks_stack_new (sizeof (struct iks_tag) * 6, 256));
+}
+/* iksemel (XML parser for Jabber)
+** Copyright (C) 2000-2003 Gurer Ozen <[email protected]>
+** This code is free software; you can redistribute it and/or
+** modify it under the terms of GNU Lesser General Public License.
+*/
+
+#include "common.h"
+#include "iksemel.h"
+
+struct dom_data {
+ iks **iksptr;
+ iks *current;
+ size_t chunk_size;
+};
+
+static int
+tagHook (struct dom_data *data, char *name, char **atts, int type)
+{
+ iks *x;
+
+ if (IKS_OPEN == type || IKS_SINGLE == type) {
+ if (data->current) {
+ x = iks_insert (data->current, name);
+ } else {
+ ikstack *s;
+ s = iks_stack_new (data->chunk_size, data->chunk_size);
+ x = iks_new_within (name, s);
+ }
+ if (atts) {
+ int i=0;
+ while (atts[i]) {
+ iks_insert_attrib (x, atts[i], atts[i+1]);
+ i += 2;
+ }
+ }
+ data->current = x;
+ }
+ if (IKS_CLOSE == type || IKS_SINGLE == type) {
+ x = iks_parent (data->current);
+ if (x)
+ data->current = x;
+ else {
+ *(data->iksptr) = data->current;
+ data->current = NULL;
+ }
+ }
+ return IKS_OK;
+}
+
+static int
+cdataHook (struct dom_data *data, char *cdata, size_t len)
+{
+ if (data->current) iks_insert_cdata (data->current, cdata, len);
+ return IKS_OK;
+}
+
+static void
+deleteHook (struct dom_data *data)
+{
+ if (data->current) iks_delete (data->current);
+ data->current = NULL;
+}
+
+iksparser *
+iks_dom_new (iks **iksptr)
+{
+ ikstack *s;
+ struct dom_data *data;
+
+ *iksptr = NULL;
+ s = iks_stack_new (DEFAULT_DOM_CHUNK_SIZE, 0);
+ if (!s) return NULL;
+ data = iks_stack_alloc (s, sizeof (struct dom_data));
+ data->iksptr = iksptr;
+ data->current = NULL;
+ data->chunk_size = DEFAULT_DOM_IKS_CHUNK_SIZE;
+ return iks_sax_extend (s, data, (iksTagHook *) tagHook, (iksCDataHook *) cdataHook, (iksDeleteHook *) deleteHook);
+}
+
+void
+iks_set_size_hint (iksparser *prs, size_t approx_size)
+{
+ size_t cs;
+ struct dom_data *data = iks_user_data (prs);
+
+ cs = approx_size / 10;
+ if (cs < DEFAULT_DOM_IKS_CHUNK_SIZE) cs = DEFAULT_DOM_IKS_CHUNK_SIZE;
+ data->chunk_size = cs;
+}
+
+iks *
+iks_tree (const char *xml_str, size_t len, int *err)
+{
+ iksparser *prs;
+ iks *x;
+ int e;
+
+ if (0 == len) len = strlen (xml_str);
+ prs = iks_dom_new (&x);
+ if (!prs) {
+ if (err) *err = IKS_NOMEM;
+ return NULL;
+ }
+ e = iks_parse (prs, xml_str, len, 1);
+ if (err) *err = e;
+ iks_parser_delete (prs);
+ return x;
+}
+
+int
+iks_load (const char *fname, iks **xptr)
+{
+ iksparser *prs;
+ char *buf;
+ FILE *f;
+ int len, done = 0;
+ int ret;
+
+ *xptr = NULL;
+
+ buf = iks_malloc (FILE_IO_BUF_SIZE);
+ if (!buf) return IKS_NOMEM;
+ ret = IKS_NOMEM;
+ prs = iks_dom_new (xptr);
+ if (prs) {
+ f = fopen (fname, "r");
+ if (f) {
+ while (0 == done) {
+ len = fread (buf, 1, FILE_IO_BUF_SIZE, f);
+ if (len < FILE_IO_BUF_SIZE) {
+ if (0 == feof (f)) {
+ ret = IKS_FILE_RWERR;
+ len = 0;
+ }
+ done = 1;
+ }
+ if (len > 0) {
+ int e;
+ e = iks_parse (prs, buf, len, done);
+ if (IKS_OK != e) {
+ ret = e;
+ break;
+ }
+ if (done) ret = IKS_OK;
+ }
+ }
+ fclose (f);
+ } else {
+ if (ENOENT == errno) ret = IKS_FILE_NOFILE;
+ else ret = IKS_FILE_NOACCESS;
+ }
+ iks_parser_delete (prs);
+ }
+ iks_free (buf);
+ return ret;
+}
+
+int
+iks_save (const char *fname, iks *x)
+{
+ FILE *f;
+ char *data;
+ int ret;
+
+ ret = IKS_NOMEM;
+ data = iks_string (NULL, x);
+ if (data) {
+ ret = IKS_FILE_NOACCESS;
+ f = fopen (fname, "w");
+ if (f) {
+ ret = IKS_FILE_RWERR;
+ if (fputs (data, f) >= 0) ret = IKS_OK;
+ fclose (f);
+ }
+ iks_free (data);
+ }
+ return ret;
+}
diff --git a/backend/impress/iksemel.h b/backend/impress/iksemel.h
new file mode 100644
index 00000000..66c87d61
--- /dev/null
+++ b/backend/impress/iksemel.h
@@ -0,0 +1,402 @@
+/* iksemel (XML parser for Jabber)
+** Copyright (C) 2000-2004 Gurer Ozen <[email protected]>
+** This code is free software; you can redistribute it and/or
+** modify it under the terms of GNU Lesser General Public License.
+*/
+
+#ifndef IKSEMEL_H
+#define IKSEMEL_H 1
+
+#ifdef __cplusplus
+#include <cstddef> /* size_t for C++ */
+extern "C" {
+#else
+#include <stddef.h> /* size_t for C */
+#endif
+
+/***** object stack *****/
+
+struct ikstack_struct;
+typedef struct ikstack_struct ikstack;
+
+ikstack *iks_stack_new (size_t meta_chunk, size_t data_chunk);
+void *iks_stack_alloc (ikstack *s, size_t size);
+char *iks_stack_strdup (ikstack *s, const char *src, size_t len);
+char *iks_stack_strcat (ikstack *s, char *old, size_t old_len, const char *src, size_t src_len);
+void iks_stack_stat (ikstack *s, size_t *allocated, size_t *used);
+void iks_stack_delete (ikstack *s);
+
+/***** utilities *****/
+
+void *iks_malloc (size_t size);
+void iks_free (void *ptr);
+void iks_set_mem_funcs (void *(*malloc_func)(size_t size), void (*free_func)(void *ptr));
+
+char *iks_strdup (const char *src);
+char *iks_strcat (char *dest, const char *src);
+int iks_strcmp (const char *a, const char *b);
+int iks_strcasecmp (const char *a, const char *b);
+int iks_strncmp (const char *a, const char *b, size_t n);
+int iks_strncasecmp (const char *a, const char *b, size_t n);
+size_t iks_strlen (const char *src);
+char *iks_escape (ikstack *s, char *src, size_t len);
+char *iks_unescape (ikstack *s, char *src, size_t len);
+
+/***** dom tree *****/
+
+enum ikstype {
+ IKS_NONE = 0,
+ IKS_TAG,
+ IKS_ATTRIBUTE,
+ IKS_CDATA
+};
+
+struct iks_struct;
+typedef struct iks_struct iks;
+
+iks *iks_new (const char *name);
+iks *iks_new_within (const char *name, ikstack *s);
+iks *iks_insert (iks *x, const char *name);
+iks *iks_insert_cdata (iks *x, const char *data, size_t len);
+iks *iks_insert_attrib (iks *x, const char *name, const char *value);
+iks *iks_insert_node (iks *x, iks *y);
+void iks_hide (iks *x);
+void iks_delete (iks *x);
+iks *iks_next (iks *x);
+iks *iks_next_tag (iks *x);
+iks *iks_prev (iks *x);
+iks *iks_prev_tag (iks *x);
+iks *iks_parent (iks *x);
+iks *iks_root (iks *x);
+iks *iks_child (iks *x);
+iks *iks_first_tag (iks *x);
+iks *iks_attrib (iks *x);
+iks *iks_find (iks *x, const char *name);
+char *iks_find_cdata (iks *x, const char *name);
+char *iks_find_attrib (iks *x, const char *name);
+iks *iks_find_with_attrib (iks *x, const char *tagname, const char *attrname, const char *value);
+ikstack *iks_stack (iks *x);
+enum ikstype iks_type (iks *x);
+char *iks_name (iks *x);
+char *iks_cdata (iks *x);
+size_t iks_cdata_size (iks *x);
+int iks_has_children (iks *x);
+int iks_has_attribs (iks *x);
+char *iks_string (ikstack *s, iks *x);
+iks *iks_copy (iks *x);
+iks *iks_copy_within (iks *x, ikstack *s);
+
+/***** sax parser *****/
+
+enum ikserror {
+ IKS_OK = 0,
+ IKS_NOMEM,
+ IKS_BADXML,
+ IKS_HOOK
+};
+
+enum ikstagtype {
+ IKS_OPEN,
+ IKS_CLOSE,
+ IKS_SINGLE
+};
+
+typedef int (iksTagHook)(void *user_data, char *name, char **atts, int type);
+typedef int (iksCDataHook)(void *user_data, char *data, size_t len);
+typedef void (iksDeleteHook)(void *user_data);
+
+struct iksparser_struct;
+typedef struct iksparser_struct iksparser;
+
+iksparser *iks_sax_new (void *user_data, iksTagHook *tagHook, iksCDataHook *cdataHook);
+iksparser *iks_sax_extend (ikstack *s, void *user_data, iksTagHook *tagHook, iksCDataHook *cdataHook, iksDeleteHook *deleteHook);
+ikstack *iks_parser_stack (iksparser *prs);
+void *iks_user_data (iksparser *prs);
+unsigned long iks_nr_bytes (iksparser *prs);
+unsigned long iks_nr_lines (iksparser *prs);
+int iks_parse (iksparser *prs, const char *data, size_t len, int finish);
+void iks_parser_reset (iksparser *prs);
+void iks_parser_delete (iksparser *prs);
+
+/***** dom parser *****/
+
+enum iksfileerror {
+ IKS_FILE_NOFILE = 4,
+ IKS_FILE_NOACCESS,
+ IKS_FILE_RWERR
+};
+
+iksparser *iks_dom_new (iks **iksptr);
+void iks_set_size_hint (iksparser *prs, size_t approx_size);
+iks *iks_tree (const char *xml_str, size_t len, int *err);
+int iks_load (const char *fname, iks **xptr);
+int iks_save (const char *fname, iks *x);
+
+/***** transport layer *****/
+
+typedef void (iksTClose)(void *socket);
+typedef int (iksTConnect)(iksparser *prs, void **socketptr, const char *server, int port);
+typedef int (iksTSend)(void *socket, const char *data, size_t len);
+typedef int (iksTRecv)(void *socket, char *buffer, size_t buf_len, int timeout);
+typedef int (iksTConnectFD)(iksparser *prs, void **socketptr, void *fd);
+typedef void *(iksTGetFD)(void *socket);
+
+enum iksasyncevents {
+ IKS_ASYNC_RESOLVED,
+ IKS_ASYNC_CONNECTED,
+ IKS_ASYNC_WRITE,
+ IKS_ASYNC_WRITTEN,
+ IKS_ASYNC_READ,
+ IKS_ASYNC_CLOSED,
+ IKS_ASYNC_ERROR
+};
+
+typedef int (iksAsyncNotify)(void *user_data, int event, void *event_data);
+typedef int (iksTConnectAsync)(iksparser *prs, void **socketptr, const char *server, int port, void *notify_data, iksAsyncNotify *notify_func);
+
+typedef struct ikstransport_struct {
+ /* basic api, connect can be NULL if one of the other connect funcs are used */
+ iksTConnect *connect;
+ iksTSend *send;
+ iksTRecv *recv;
+ iksTClose *close;
+ /* optional fd api */
+ iksTConnectFD *connect_fd;
+ iksTGetFD *get_fd;
+ /* optional async api */
+ iksTConnectAsync *connect_async;
+} ikstransport;
+
+extern ikstransport iks_default_transport;
+
+/***** stream parser *****/
+
+enum iksneterror {
+ IKS_NET_NODNS = 4,
+ IKS_NET_NOSOCK,
+ IKS_NET_NOCONN,
+ IKS_NET_RWERR,
+ IKS_NET_NOTSUPP,
+ IKS_NET_TLSFAIL
+};
+
+enum iksnodetype {
+ IKS_NODE_START,
+ IKS_NODE_NORMAL,
+ IKS_NODE_ERROR,
+ IKS_NODE_STOP
+};
+
+enum ikssasltype {
+ IKS_SASL_PLAIN,
+ IKS_SASL_DIGEST_MD5
+};
+
+#define IKS_JABBER_PORT 5222
+
+typedef int (iksStreamHook)(void *user_data, int type, iks *node);
+typedef void (iksLogHook)(void *user_data, const char *data, size_t size, int is_incoming);
+
+iksparser *iks_stream_new (char *name_space, void *user_data, iksStreamHook *streamHook);
+void *iks_stream_user_data (iksparser *prs);
+void iks_set_log_hook (iksparser *prs, iksLogHook *logHook);
+int iks_connect_tcp (iksparser *prs, const char *server, int port);
+int iks_connect_fd (iksparser *prs, int fd);
+int iks_connect_via (iksparser *prs, const char *server, int port, const char *server_name);
+int iks_connect_with (iksparser *prs, const char *server, int port, const char *server_name, ikstransport *trans);
+int iks_connect_async (iksparser *prs, const char *server, int port, void *notify_data, iksAsyncNotify *notify_func);
+int iks_connect_async_with (iksparser *prs, const char *server, int port, const char *server_name, ikstransport *trans, void *notify_data, iksAsyncNotify *notify_func);
+int iks_fd (iksparser *prs);
+int iks_recv (iksparser *prs, int timeout);
+int iks_send_header (iksparser *prs, const char *to);
+int iks_send (iksparser *prs, iks *x);
+int iks_send_raw (iksparser *prs, const char *xmlstr);
+void iks_disconnect (iksparser *prs);
+int iks_has_tls (void);
+int iks_is_secure (iksparser *prs);
+int iks_start_tls (iksparser *prs);
+int iks_start_sasl (iksparser *prs, enum ikssasltype type, char *username, char *pass);
+
+/***** jabber *****/
+
+#define IKS_NS_CLIENT "jabber:client"
+#define IKS_NS_SERVER "jabber:server"
+#define IKS_NS_AUTH "jabber:iq:auth"
+#define IKS_NS_AUTH_0K "jabber:iq:auth:0k"
+#define IKS_NS_REGISTER "jabber:iq:register"
+#define IKS_NS_ROSTER "jabber:iq:roster"
+#define IKS_NS_XROSTER "jabber:x:roster"
+#define IKS_NS_OFFLINE "jabber:x:offline"
+#define IKS_NS_AGENT "jabber:iq:agent"
+#define IKS_NS_AGENTS "jabber:iq:agents"
+#define IKS_NS_BROWSE "jabber:iq:browse"
+#define IKS_NS_CONFERENCE "jabber:iq:conference"
+#define IKS_NS_DELAY "jabber:x:delay"
+#define IKS_NS_VERSION "jabber:iq:version"
+#define IKS_NS_TIME "jabber:iq:time"
+#define IKS_NS_VCARD "vcard-temp"
+#define IKS_NS_PRIVATE "jabber:iq:private"
+#define IKS_NS_SEARCH "jabber:iq:search"
+#define IKS_NS_OOB "jabber:iq:oob"
+#define IKS_NS_XOOB "jabber:x:oob"
+#define IKS_NS_ADMIN "jabber:iq:admin"
+#define IKS_NS_FILTER "jabber:iq:filter"
+#define IKS_NS_GATEWAY "jabber:iq:gateway"
+#define IKS_NS_LAST "jabber:iq:last"
+#define IKS_NS_SIGNED "jabber:x:signed"
+#define IKS_NS_ENCRYPTED "jabber:x:encrypted"
+#define IKS_NS_ENVELOPE "jabber:x:envelope"
+#define IKS_NS_EVENT "jabber:x:event"
+#define IKS_NS_EXPIRE "jabber:x:expire"
+#define IKS_NS_XHTML "http://www.w3.org/1999/xhtml"
+#define IKS_NS_XMPP_SASL "urn:ietf:params:xml:ns:xmpp-sasl"
+#define IKS_NS_XMPP_BIND "urn:ietf:params:xml:ns:xmpp-bind"
+#define IKS_NS_XMPP_SESSION "urn:ietf:params:xml:ns:xmpp-session"
+
+#define IKS_ID_USER 1
+#define IKS_ID_SERVER 2
+#define IKS_ID_RESOURCE 4
+#define IKS_ID_PARTIAL IKS_ID_USER | IKS_ID_SERVER
+#define IKS_ID_FULL IKS_ID_USER | IKS_ID_SERVER | IKS_ID_RESOURCE
+
+#define IKS_STREAM_STARTTLS 1
+#define IKS_STREAM_SESSION 2
+#define IKS_STREAM_BIND 4
+#define IKS_STREAM_SASL_PLAIN 8
+#define IKS_STREAM_SASL_MD5 16
+
+typedef struct iksid_struct {
+ char *user;
+ char *server;
+ char *resource;
+ char *partial;
+ char *full;
+} iksid;
+
+iksid *iks_id_new (ikstack *s, const char *jid);
+int iks_id_cmp (iksid *a, iksid *b, int parts);
+
+enum ikspaktype {
+ IKS_PAK_NONE = 0,
+ IKS_PAK_MESSAGE,
+ IKS_PAK_PRESENCE,
+ IKS_PAK_IQ,
+ IKS_PAK_S10N
+};
+
+enum iksubtype {
+ IKS_TYPE_NONE = 0,
+ IKS_TYPE_ERROR,
+
+ IKS_TYPE_CHAT,
+ IKS_TYPE_GROUPCHAT,
+ IKS_TYPE_HEADLINE,
+
+ IKS_TYPE_GET,
+ IKS_TYPE_SET,
+ IKS_TYPE_RESULT,
+
+ IKS_TYPE_SUBSCRIBE,
+ IKS_TYPE_SUBSCRIBED,
+ IKS_TYPE_UNSUBSCRIBE,
+ IKS_TYPE_UNSUBSCRIBED,
+ IKS_TYPE_PROBE,
+ IKS_TYPE_AVAILABLE,
+ IKS_TYPE_UNAVAILABLE
+};
+
+enum ikshowtype {
+ IKS_SHOW_UNAVAILABLE = 0,
+ IKS_SHOW_AVAILABLE,
+ IKS_SHOW_CHAT,
+ IKS_SHOW_AWAY,
+ IKS_SHOW_XA,
+ IKS_SHOW_DND
+};
+
+typedef struct ikspak_struct {
+ iks *x;
+ iksid *from;
+ iks *query;
+ char *ns;
+ char *id;
+ enum ikspaktype type;
+ enum iksubtype subtype;
+ enum ikshowtype show;
+} ikspak;
+
+ikspak *iks_packet (iks *x);
+
+iks *iks_make_auth (iksid *id, const char *pass, const char *sid);
+iks *iks_make_msg (enum iksubtype type, const char *to, const char *body);
+iks *iks_make_s10n (enum iksubtype type, const char *to, const char *msg);
+iks *iks_make_pres (enum ikshowtype show, const char *status);
+iks *iks_make_iq (enum iksubtype type, const char *xmlns);
+iks *iks_make_resource_bind(iksid *id);
+iks *iks_make_session(void);
+int iks_stream_features(iks *x);
+
+/***** jabber packet filter *****/
+
+#define IKS_RULE_DONE 0
+#define IKS_RULE_ID 1
+#define IKS_RULE_TYPE 2
+#define IKS_RULE_SUBTYPE 4
+#define IKS_RULE_FROM 8
+#define IKS_RULE_FROM_PARTIAL 16
+#define IKS_RULE_NS 32
+
+enum iksfilterret {
+ IKS_FILTER_PASS,
+ IKS_FILTER_EAT
+};
+
+typedef int (iksFilterHook)(void *user_data, ikspak *pak);
+
+struct iksfilter_struct;
+typedef struct iksfilter_struct iksfilter;
+struct iksrule_struct;
+typedef struct iksrule_struct iksrule;
+
+iksfilter *iks_filter_new (void);
+iksrule *iks_filter_add_rule (iksfilter *f, iksFilterHook *filterHook, void *user_data, ...);
+void iks_filter_remove_rule (iksfilter *f, iksrule *rule);
+void iks_filter_remove_hook (iksfilter *f, iksFilterHook *filterHook);
+void iks_filter_packet (iksfilter *f, ikspak *pak);
+void iks_filter_delete (iksfilter *f);
+
+/***** sha1 *****/
+
+struct iksha_struct;
+typedef struct iksha_struct iksha;
+
+iksha *iks_sha_new (void);
+void iks_sha_reset (iksha *sha);
+void iks_sha_hash (iksha *sha, const unsigned char *data, size_t len, int finish);
+void iks_sha_print (iksha *sha, char *hash);
+void iks_sha_delete (iksha *sha);
+void iks_sha (const char *data, char *hash);
+
+/***** md5 *****/
+
+struct ikmd5_struct;
+typedef struct iksmd5_struct iksmd5;
+
+iksmd5 *iks_md5_new(void);
+void iks_md5_reset(iksmd5 *md5);
+void iks_md5_hash(iksmd5 *md5, const unsigned char *data, size_t slen, int finish);
+void iks_md5_delete(iksmd5 *md5);
+void iks_md5_print(iksmd5 *md5, char *buf);
+void iks_md5_digest(iksmd5 *md5, unsigned char *digest);
+void iks_md5(const char *data, char *buf);
+
+/***** base64 *****/
+
+char *iks_base64_decode(const char *buf);
+char *iks_base64_encode(const char *buf, int len);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* IKSEMEL_H */
diff --git a/backend/impress/imposter.h b/backend/impress/imposter.h
new file mode 100644
index 00000000..50c87f2c
--- /dev/null
+++ b/backend/impress/imposter.h
@@ -0,0 +1,84 @@
+/* imposter (OO.org Impress viewer)
+** Copyright (C) 2003-2005 Gurer Ozen
+** This code is free software; you can redistribute it and/or
+** modify it under the terms of GNU General Public License.
+*/
+
+#ifndef IMPOSTER_H
+#define IMPOSTER_H
+
+#include <sys/types.h>
+
+enum {
+ IMP_OK = 0,
+ IMP_NOMEM,
+ IMP_NOTZIP,
+ IMP_BADZIP,
+ IMP_BADDOC,
+ IMP_NOTIMP
+};
+
+struct ImpDoc_struct;
+typedef struct ImpDoc_struct ImpDoc;
+
+struct ImpPage_struct;
+typedef struct ImpPage_struct ImpPage;
+
+typedef struct ImpPointStruct {
+ int x;
+ int y;
+} ImpPoint;
+
+typedef struct ImpColorStruct {
+ int red;
+ int green;
+ int blue;
+} ImpColor;
+
+#define IMP_NORMAL 0
+#define IMP_BOLD 1
+#define IMP_ITALIC 2
+#define IMP_UNDERLINE 4
+
+typedef struct ImpDrawer_struct {
+ void (*get_size)(void *drw_data, int *w, int *h);
+ void (*set_fg_color)(void *drw_data, ImpColor *color);
+ void (*draw_line)(void *drw_data, int x1, int y1, int x2, int y2);
+ void (*draw_rect)(void *drw_data, int fill, int x, int y, int w, int h);
+ void (*draw_polygon)(void *drw_data, int fill, ImpPoint *pts, int nr_pts);
+ void (*draw_arc)(void *drw_data, int fill, int x, int y, int w, int h, int sa, int ea);
+ void (*draw_bezier)(void *drw_data, int x0, int y0, int x1, int y1, int x2, int y2, int x3, int y3);
+ void *(*open_image)(void *drw_data, const unsigned char *pix, size_t size);
+ void (*get_image_size)(void *drw_data, void *img_data, int *w, int *h);
+ void *(*scale_image)(void *drw_data, void *img_data, int w, int h);
+ void (*draw_image)(void *drw_data, void *img_data, int x, int y, int w, int h);
+ void (*close_image)(void *drw_data, void *img_data);
+ void (*get_text_size)(void *drw_data, const char *text, size_t len, int size, int styles, int *w, int *h);
+ void (*draw_text)(void *drw_data, int x, int y, const char *text, size_t len, int size, int styles);
+} ImpDrawer;
+
+struct ImpRenderCtx_struct;
+typedef struct ImpRenderCtx_struct ImpRenderCtx;
+
+#define IMP_LAST_PAGE -1
+
+ImpDoc *imp_open(const char *filename, int *err);
+int imp_nr_pages(ImpDoc *doc);
+ImpPage *imp_get_page(ImpDoc *doc, int page_no);
+void imp_close(ImpDoc *doc);
+
+void *imp_get_xml(ImpDoc *doc, const char *filename);
+
+ImpPage *imp_next_page(ImpPage *page);
+ImpPage *imp_prev_page(ImpPage *page);
+int imp_get_page_no(ImpPage *page);
+const char *imp_get_page_name(ImpPage *page);
+
+ImpRenderCtx *imp_create_context(const ImpDrawer *drw);
+void imp_context_set_page(ImpRenderCtx *ctx, ImpPage *page);
+void imp_context_set_step(ImpRenderCtx *ctx, int step);
+void imp_render(ImpRenderCtx *ctx, void *drw_data);
+void imp_delete_context(ImpRenderCtx *ctx);
+
+
+#endif /* IMPOSTER_H */
diff --git a/backend/impress/impress-document.c b/backend/impress/impress-document.c
new file mode 100644
index 00000000..5254a881
--- /dev/null
+++ b/backend/impress/impress-document.c
@@ -0,0 +1,548 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8; c-indent-level: 8 -*- */
+/*
+ * Copyright (C) 2005, Jonathan Blandford <[email protected]>
+ * Copyright (C) 2005, Bastien Nocera <[email protected]>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "config.h"
+
+#include <string.h>
+
+#include <glib/gi18n-lib.h>
+#include <gtk/gtk.h>
+
+#include "imposter.h"
+#include "impress-document.h"
+
+#include "ev-document-misc.h"
+#include "ev-document-thumbnails.h"
+
+struct _ImpressDocumentClass
+{
+ EvDocumentClass parent_class;
+};
+
+struct _ImpressDocument
+{
+ EvDocument parent_instance;
+
+ ImpDoc *imp;
+ ImpRenderCtx *ctx;
+
+ GMutex *mutex;
+ GdkPixmap *pixmap;
+ GdkGC *gc;
+ PangoContext *pango_ctx;
+
+ /* Only used while rendering inside the mainloop */
+ int pagenum;
+ GdkPixbuf *pixbuf;
+ GCond *cond;
+};
+
+#define PAGE_WIDTH 1024
+#define PAGE_HEIGHT 768
+
+typedef struct _ImpressDocumentClass ImpressDocumentClass;
+
+static void impress_document_document_thumbnails_iface_init (EvDocumentThumbnailsInterface *iface);
+
+EV_BACKEND_REGISTER_WITH_CODE (ImpressDocument, impress_document,
+ {
+ EV_BACKEND_IMPLEMENT_INTERFACE (EV_TYPE_DOCUMENT_THUMBNAILS,
+ impress_document_document_thumbnails_iface_init);
+ });
+
+/* Renderer */
+static void
+imp_render_draw_bezier_real (GdkDrawable *d, GdkGC *gc, int x0, int y0, int x1, int y1, int x2, int y2, int x3, int y3)
+{
+ int x, y, nx, ny;
+ int ax, bx, cx, ay, by, cy;
+ double t, t2, t3;
+
+ x = x0;
+ y = y0;
+
+ cx = 3 * (x1 - x0);
+ bx = 3 * (x2 - x1) - cx;
+ ax = x3 - x0 - cx - bx;
+ cy = 3 * (y1 - y0);
+ by = 3 * (y2 - y1) - cy;
+ ay = y3 - y0 - cy - by;
+
+ for (t = 0; t < 1; t += 0.01) {
+ t2 = t * t;
+ t3 = t2 * t;
+ nx = ax * t3 + bx * t2 + cx * t + x0;
+ ny = ay * t3 + by * t2 + cy * t + y0;
+ gdk_draw_line (d, gc, x, y, nx, ny);
+ x = nx;
+ y = ny;
+ }
+}
+
+static void
+imp_render_get_size(void *drw_data, int *w, int *h)
+{
+ ImpressDocument *impress_document = IMPRESS_DOCUMENT (drw_data);
+
+ #if GTK_CHECK_VERSION(3, 0, 0)
+ *w = gdk_window_get_width(impress_document->pixmap);
+ *h = gdk_window_get_height(impress_document->pixmap);
+ #else
+ gdk_drawable_get_size(impress_document->pixmap, w, h);
+ #endif
+}
+
+static void
+imp_render_set_fg_color(void *drw_data, ImpColor *color)
+{
+ ImpressDocument *impress_document = IMPRESS_DOCUMENT (drw_data);
+ GdkColor c;
+
+ c.red = color->red;
+ c.green = color->green;
+ c.blue = color->blue;
+ gdk_gc_set_rgb_fg_color(impress_document->gc, &c);
+}
+
+static void
+imp_render_draw_line(void *drw_data, int x1, int y1, int x2, int y2)
+{
+ ImpressDocument *impress_document = IMPRESS_DOCUMENT (drw_data);
+
+ gdk_draw_line(impress_document->pixmap, impress_document->gc, x1, y1, x2, y2);
+}
+
+static void
+imp_render_draw_rect(void *drw_data, int fill, int x, int y, int w, int h)
+{
+ ImpressDocument *impress_document = IMPRESS_DOCUMENT (drw_data);
+
+ gdk_draw_rectangle(impress_document->pixmap, impress_document->gc, fill, x, y, w, h);
+}
+
+static void
+imp_render_draw_polygon(void *drw_data, int fill, ImpPoint *pts, int nr_pts)
+{
+ ImpressDocument *impress_document = IMPRESS_DOCUMENT (drw_data);
+
+ gdk_draw_polygon(impress_document->pixmap, impress_document->gc, fill, (GdkPoint *)pts, nr_pts);
+}
+
+static void
+imp_render_draw_arc(void *drw_data, int fill, int x, int y, int w, int h, int sa, int ea)
+{
+ ImpressDocument *impress_document = IMPRESS_DOCUMENT (drw_data);
+
+ gdk_draw_arc(impress_document->pixmap, impress_document->gc, fill, x, y, w, h, sa * 64, ea * 64);
+}
+
+static void
+imp_render_draw_bezier(void *drw_data, int x0, int y0, int x1, int y1, int x2, int y2, int x3, int y3)
+{
+ ImpressDocument *impress_document = IMPRESS_DOCUMENT (drw_data);
+
+ imp_render_draw_bezier_real (impress_document->pixmap, impress_document->gc, x0, y0, x1, y1, x2, y2, x3, y3);
+}
+
+static void *
+imp_render_open_image(void *drw_data, const unsigned char *pix, size_t size)
+{
+ GdkPixbufLoader *gpl;
+ GdkPixbuf *pb;
+
+ gpl = gdk_pixbuf_loader_new();
+ gdk_pixbuf_loader_write(gpl, pix, size, NULL);
+ gdk_pixbuf_loader_close(gpl, NULL);
+ pb = gdk_pixbuf_loader_get_pixbuf(gpl);
+ return pb;
+}
+
+static void
+imp_render_get_image_size(void *drw_data, void *img_data, int *w, int *h)
+{
+ GdkPixbuf *pb = (GdkPixbuf *) img_data;
+
+ *w = gdk_pixbuf_get_width(pb);
+ *h = gdk_pixbuf_get_height(pb);
+}
+
+static void *
+imp_render_scale_image(void *drw_data, void *img_data, int w, int h)
+{
+ GdkPixbuf *pb = (GdkPixbuf *) img_data;
+
+ return gdk_pixbuf_scale_simple(pb, w, h, GDK_INTERP_BILINEAR);
+}
+
+static void
+imp_render_draw_image(void *drw_data, void *img_data, int x, int y, int w, int h)
+{
+ ImpressDocument *impress_document = IMPRESS_DOCUMENT (drw_data);
+ GdkPixbuf *pb = (GdkPixbuf *) img_data;
+
+ gdk_draw_pixbuf(impress_document->pixmap, impress_document->gc, pb, 0, 0, x, y, w, h, GDK_RGB_DITHER_NONE, 0, 0);
+}
+
+static void
+imp_render_close_image(void *drw_data, void *img_data)
+{
+ GdkPixbuf *pb = (GdkPixbuf *) img_data;
+
+ g_object_unref(G_OBJECT(pb));
+}
+
+static char *
+imp_render_markup(const char *text, size_t len, int styles, int size)
+{
+ double scr_mm, scr_px, dpi;
+ char *esc;
+ char *ret;
+ int sz;
+
+ scr_mm = gdk_screen_get_height_mm(gdk_screen_get_default());
+ scr_px = gdk_screen_get_height(gdk_screen_get_default());
+ dpi = (scr_px / scr_mm) * 25.4;
+ sz = (int) ((double) size * 72.0 * PANGO_SCALE / dpi);
+ esc = g_markup_escape_text(text, len);
+ ret = g_strdup_printf("<span size ='%d'>%s</span>", sz, esc);
+ g_free(esc);
+ return ret;
+}
+
+static void
+imp_render_get_text_size(void *drw_data, const char *text, size_t len, int size, int styles, int *w, int *h)
+{
+ ImpressDocument *impress_document = IMPRESS_DOCUMENT (drw_data);
+ PangoLayout *lay;
+ int pw, ph;
+ char *m;
+
+ g_return_if_fail (impress_document->pango_ctx != NULL);
+
+ lay = pango_layout_new(impress_document->pango_ctx);
+ m = imp_render_markup(text, len, styles, size);
+ pango_layout_set_markup(lay, m, strlen(m));
+ pango_layout_get_size(lay, &pw, &ph);
+ g_object_unref(lay);
+ g_free(m);
+ *w = pw / PANGO_SCALE;
+ *h = ph / PANGO_SCALE;
+}
+
+static void
+imp_render_draw_text(void *drw_data, int x, int y, const char *text, size_t len, int size, int styles)
+{
+ ImpressDocument *impress_document = IMPRESS_DOCUMENT (drw_data);
+ PangoLayout *lay;
+ char *m;
+
+ g_return_if_fail (impress_document->pango_ctx != NULL);
+
+ lay = pango_layout_new(impress_document->pango_ctx);
+ m = imp_render_markup(text, len, styles, size);
+ pango_layout_set_markup(lay, m, strlen(m));
+ gdk_draw_layout(impress_document->pixmap, impress_document->gc, x, y, lay);
+ g_object_unref(lay);
+ g_free(m);
+}
+
+static const ImpDrawer imp_render_functions = {
+ imp_render_get_size,
+ imp_render_set_fg_color,
+ imp_render_draw_line,
+ imp_render_draw_rect,
+ imp_render_draw_polygon,
+ imp_render_draw_arc,
+ imp_render_draw_bezier,
+ imp_render_open_image,
+ imp_render_get_image_size,
+ imp_render_scale_image,
+ imp_render_draw_image,
+ imp_render_close_image,
+ imp_render_get_text_size,
+ imp_render_draw_text
+};
+
+/* Document interface */
+static gboolean
+impress_document_load (EvDocument *document,
+ const char *uri,
+ GError **error)
+{
+ ImpressDocument *impress_document = IMPRESS_DOCUMENT (document);
+ gchar *filename;
+ ImpDoc *imp;
+ int err;
+
+ /* FIXME: Could we actually load uris ? */
+ filename = g_filename_from_uri (uri, NULL, error);
+ if (!filename)
+ return FALSE;
+
+ imp = imp_open (filename, &err);
+ g_free (filename);
+
+ if (!imp)
+ {
+ g_set_error_literal (error,
+ EV_DOCUMENT_ERROR,
+ EV_DOCUMENT_ERROR_INVALID,
+ _("Invalid document"));
+ return FALSE;
+ }
+ impress_document->imp = imp;
+
+ return TRUE;
+}
+
+static gboolean
+impress_document_save (EvDocument *document,
+ const char *uri,
+ GError **error)
+{
+ g_set_error_literal (error,
+ EV_DOCUMENT_ERROR,
+ EV_DOCUMENT_ERROR_INVALID,
+ "Not supported");
+ return FALSE;
+}
+
+static int
+impress_document_get_n_pages (EvDocument *document)
+{
+ ImpressDocument *impress_document = IMPRESS_DOCUMENT (document);
+
+ g_return_val_if_fail (IMPRESS_IS_DOCUMENT (document), 0);
+ g_return_val_if_fail (impress_document->imp != NULL, 0);
+
+ return imp_nr_pages (impress_document->imp);
+}
+
+static void
+impress_document_get_page_size (EvDocument *document,
+ EvPage *page,
+ double *width,
+ double *height)
+{
+ ImpressDocument *impress_document = IMPRESS_DOCUMENT (document);
+
+ g_return_if_fail (IMPRESS_IS_DOCUMENT (document));
+ g_return_if_fail (impress_document->imp != NULL);
+
+ //FIXME
+ *width = PAGE_WIDTH;
+ *height = PAGE_HEIGHT;
+}
+
+static gboolean
+imp_render_get_from_drawable (ImpressDocument *impress_document)
+{
+ ImpPage *page;
+
+ page = imp_get_page (impress_document->imp, impress_document->pagenum);
+
+ g_return_val_if_fail (page != NULL, FALSE);
+
+ ev_document_doc_mutex_lock ();
+ imp_context_set_page (impress_document->ctx, page);
+ imp_render (impress_document->ctx, impress_document);
+ ev_document_doc_mutex_unlock ();
+
+ impress_document->pixbuf = gdk_pixbuf_get_from_drawable (NULL,
+ GDK_DRAWABLE (impress_document->pixmap),
+ NULL,
+ 0, 0,
+ 0, 0,
+ PAGE_WIDTH, PAGE_HEIGHT);
+
+ g_cond_broadcast (impress_document->cond);
+ return FALSE;
+}
+
+static GdkPixbuf *
+impress_document_render_pixbuf (EvDocument *document,
+ EvRenderContext *rc)
+{
+ ImpressDocument *impress_document = IMPRESS_DOCUMENT (document);
+ GdkPixbuf *pixbuf;
+
+ g_return_val_if_fail (IMPRESS_IS_DOCUMENT (document), NULL);
+ g_return_val_if_fail (impress_document->imp != NULL, NULL);
+
+ impress_document->pagenum = rc->page->index;
+
+ g_mutex_lock (impress_document->mutex);
+ impress_document->cond = g_cond_new ();
+
+ ev_document_fc_mutex_unlock ();
+ ev_document_doc_mutex_unlock ();
+ g_idle_add ((GSourceFunc) imp_render_get_from_drawable, impress_document);
+ g_cond_wait (impress_document->cond, impress_document->mutex);
+ g_cond_free (impress_document->cond);
+ ev_document_doc_mutex_lock ();
+ ev_document_fc_mutex_lock ();
+
+ g_mutex_unlock (impress_document->mutex);
+
+ pixbuf = impress_document->pixbuf;
+ impress_document->pixbuf = NULL;
+
+ return pixbuf;
+}
+
+static cairo_surface_t *
+impress_document_render (EvDocument *document,
+ EvRenderContext *rc)
+{
+ GdkPixbuf *pixbuf;
+ cairo_surface_t *surface, *scaled_surface;
+
+ pixbuf = impress_document_render_pixbuf (document, rc);
+
+ /* FIXME: impress backend should be ported to cairo */
+ surface = ev_document_misc_surface_from_pixbuf (pixbuf);
+ g_object_unref (pixbuf);
+
+ scaled_surface = ev_document_misc_surface_rotate_and_scale (surface,
+ (PAGE_WIDTH * rc->scale) + 0.5,
+ (PAGE_HEIGHT * rc->scale) + 0.5,
+ rc->rotation);
+ cairo_surface_destroy (surface);
+
+ return scaled_surface;
+}
+
+static void
+impress_document_finalize (GObject *object)
+{
+ ImpressDocument *impress_document = IMPRESS_DOCUMENT (object);
+
+ if (impress_document->mutex)
+ g_mutex_free (impress_document->mutex);
+
+ if (impress_document->imp)
+ imp_close (impress_document->imp);
+
+ if (impress_document->ctx)
+ imp_delete_context (impress_document->ctx);
+
+ if (impress_document->pango_ctx)
+ g_object_unref (impress_document->pango_ctx);
+
+ if (impress_document->pixmap)
+ g_object_unref (G_OBJECT (impress_document->pixmap));
+
+ if (impress_document->gc)
+ g_object_unref (impress_document->gc);
+
+ G_OBJECT_CLASS (impress_document_parent_class)->finalize (object);
+}
+
+static void
+impress_document_class_init (ImpressDocumentClass *klass)
+{
+ GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+ EvDocumentClass *ev_document_class = EV_DOCUMENT_CLASS (klass);
+
+ gobject_class->finalize = impress_document_finalize;
+
+ ev_document_class->load = impress_document_load;
+ ev_document_class->save = impress_document_save;
+ ev_document_class->get_n_pages = impress_document_get_n_pages;
+ ev_document_class->get_page_size = impress_document_get_page_size;
+ ev_document_class->render = impress_document_render;
+}
+
+static GdkPixbuf *
+impress_document_thumbnails_get_thumbnail (EvDocumentThumbnails *document,
+ EvRenderContext *rc,
+ gboolean border)
+{
+ GdkPixbuf *pixbuf;
+ GdkPixbuf *scaled_pixbuf;
+
+ pixbuf = impress_document_render_pixbuf (EV_DOCUMENT (document), rc);
+ scaled_pixbuf = gdk_pixbuf_scale_simple (pixbuf,
+ (PAGE_WIDTH * rc->scale),
+ (PAGE_HEIGHT * rc->scale),
+ GDK_INTERP_BILINEAR);
+ g_object_unref (pixbuf);
+
+ if (border)
+ {
+ GdkPixbuf *tmp_pixbuf = scaled_pixbuf;
+
+ scaled_pixbuf = ev_document_misc_get_thumbnail_frame (-1, -1, tmp_pixbuf);
+ g_object_unref (tmp_pixbuf);
+ }
+
+ return scaled_pixbuf;
+}
+
+static void
+impress_document_thumbnails_get_dimensions (EvDocumentThumbnails *document,
+ EvRenderContext *rc,
+ gint *width,
+ gint *height)
+{
+ gdouble page_width, page_height;
+
+ impress_document_get_page_size (EV_DOCUMENT (document),
+ rc->page,
+ &page_width, &page_height);
+
+ if (rc->rotation == 90 || rc->rotation == 270)
+ {
+ *width = (gint) (page_height * rc->scale);
+ *height = (gint) (page_width * rc->scale);
+ }
+ else
+ {
+ *width = (gint) (page_width * rc->scale);
+ *height = (gint) (page_height * rc->scale);
+ }
+}
+
+static void
+impress_document_document_thumbnails_iface_init (EvDocumentThumbnailsInterface *iface)
+{
+ iface->get_thumbnail = impress_document_thumbnails_get_thumbnail;
+ iface->get_dimensions = impress_document_thumbnails_get_dimensions;
+}
+
+static void
+impress_document_init (ImpressDocument *impress_document)
+{
+ GdkWindow *window;
+
+ impress_document->mutex = g_mutex_new ();
+ impress_document->ctx = imp_create_context(&imp_render_functions);
+
+ window = gdk_screen_get_root_window (gdk_screen_get_default ());
+
+ impress_document->pixmap = gdk_pixmap_new (window,
+ PAGE_WIDTH, PAGE_HEIGHT, -1);
+ impress_document->gc = gdk_gc_new (impress_document->pixmap);
+ impress_document->pango_ctx = gdk_pango_context_get_for_screen (gdk_screen_get_default ());
+}
+
+/*
+ * vim: sw=2 ts=8 cindent noai bs=2
+ */
diff --git a/backend/impress/impress-document.h b/backend/impress/impress-document.h
new file mode 100644
index 00000000..17a3c19a
--- /dev/null
+++ b/backend/impress/impress-document.h
@@ -0,0 +1,39 @@
+
+/* pdfdocument.h: Implementation of EvDocument for impresss
+ * Copyright (C) 2005, Jonathan Blandford <[email protected]>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __IMPRESS_DOCUMENT_H__
+#define __IMPRESS_DOCUMENT_H__
+
+#include "ev-document.h"
+
+G_BEGIN_DECLS
+
+#define IMPRESS_TYPE_DOCUMENT (impress_document_get_type ())
+#define IMPRESS_DOCUMENT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), IMPRESS_TYPE_DOCUMENT, ImpressDocument))
+#define IMPRESS_IS_DOCUMENT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), IMPRESS_TYPE_DOCUMENT))
+
+typedef struct _ImpressDocument ImpressDocument;
+
+GType impress_document_get_type (void) G_GNUC_CONST;
+
+G_MODULE_EXPORT GType register_evince_backend (GTypeModule *module);
+
+G_END_DECLS
+
+#endif /* __IMPRESS_DOCUMENT_H__ */
diff --git a/backend/impress/impressdocument.evince-backend.in b/backend/impress/impressdocument.evince-backend.in
new file mode 100644
index 00000000..61de77ab
--- /dev/null
+++ b/backend/impress/impressdocument.evince-backend.in
@@ -0,0 +1,4 @@
+[Evince Backend]
+Module=impressdocument
+_TypeDescription=Impress Slides
+MimeType=application/vnd.sun.xml.impress;application/vnd.oasis.opendocument.presentation;
diff --git a/backend/impress/internal.h b/backend/impress/internal.h
new file mode 100644
index 00000000..eb99c3ec
--- /dev/null
+++ b/backend/impress/internal.h
@@ -0,0 +1,85 @@
+/* imposter (OO.org Impress viewer)
+** Copyright (C) 2003-2005 Gurer Ozen
+** This code is free software; you can redistribute it and/or
+** modify it under the terms of GNU General Public License.
+*/
+
+#include "zip.h"
+
+#ifndef INTERNAL_H
+#define INTERNAL_H
+
+struct ImpDoc_struct {
+ ikstack *stack;
+ zip *zfile;
+ iks *content;
+ iks *styles;
+ iks *meta;
+ ImpPage *pages;
+ ImpPage *last_page;
+ int nr_pages;
+ void (*get_geometry)(ImpRenderCtx *ctx);
+ void (*render_page)(ImpRenderCtx *ctx, void *drw_data);
+};
+
+struct ImpPage_struct {
+ struct ImpPage_struct *next;
+ struct ImpPage_struct *prev;
+ ImpDoc *doc;
+ iks *page;
+ const char *name;
+ int nr;
+};
+
+struct ImpRenderCtx_struct {
+ const ImpDrawer *drw;
+ ImpPage *page;
+ iks *content;
+ iks *styles;
+ iks *last_element;
+ int step;
+ int pix_w, pix_h;
+ double cm_w, cm_h;
+ double fact_x, fact_y;
+};
+
+char *r_get_style (ImpRenderCtx *ctx, iks *node, char *attr);
+int r_get_color(ImpRenderCtx *ctx, iks *node, char *name, ImpColor *ic);
+void r_parse_color(const char *color, ImpColor *ic);
+int r_get_x (ImpRenderCtx *ctx, iks *node, char *name);
+int r_get_y (ImpRenderCtx *ctx, iks *node, char *name);
+int r_get_angle (iks *node, char *name, int def);
+
+enum {
+ IMP_LE_NONE = 0,
+ IMP_LE_ARROW,
+ IMP_LE_SQUARE,
+ IMP_LE_DIMENSION,
+ IMP_LE_DOUBLE_ARROW,
+ IMP_LE_SMALL_ARROW,
+ IMP_LE_ROUND_ARROW,
+ IMP_LE_SYM_ARROW,
+ IMP_LE_LINE_ARROW,
+ IMP_LE_ROUND_LARGE_ARROW,
+ IMP_LE_CIRCLE,
+ IMP_LE_SQUARE_45,
+ IMP_LE_CONCAVE_ARROW
+};
+
+void _imp_draw_rect(ImpRenderCtx *ctx, void *drw_data, int fill, int x, int y, int w, int h, int round);
+void _imp_draw_line_end(ImpRenderCtx *ctx, void *drw_data, int type, int size, int x, int y, int x2, int y2);
+void _imp_draw_image(ImpRenderCtx *ctx, void *drw_data, const char *name, int x, int y, int w, int h);
+void _imp_tile_image(ImpRenderCtx *ctx, void *drw_data, const char *name, int x, int y, int w, int h);
+
+int _imp_fill_back(ImpRenderCtx *ctx, void *drw_data, iks *node);
+void r_text(ImpRenderCtx *ctx, void *drw_data, iks *node);
+void r_polygon(ImpRenderCtx *ctx, void *drw_data, iks *node);
+void r_circle(ImpRenderCtx *ctx, void *drw_data, iks *node);
+void r_polyline(ImpRenderCtx *ctx, void *drw_data, iks *node);
+void r_draw_gradient (ImpRenderCtx *ctx, void *drw_data, iks *node);
+
+int _imp_oo13_load(ImpDoc *doc);
+int _imp_oasis_load(ImpDoc *doc);
+
+
+#endif /* INTERNAL_H */
diff --git a/backend/impress/r_back.c b/backend/impress/r_back.c
new file mode 100644
index 00000000..3f050d9e
--- /dev/null
+++ b/backend/impress/r_back.c
@@ -0,0 +1,46 @@
+/* imposter (OO.org Impress viewer)
+** Copyright (C) 2003-2005 Gurer Ozen
+** This code is free software; you can redistribute it and/or
+** modify it under the terms of GNU General Public License.
+*/
+
+#include <config.h>
+#include "common.h"
+#include "internal.h"
+
+int
+_imp_fill_back(ImpRenderCtx *ctx, void *drw_data, iks *node)
+{
+ ImpColor col;
+ char *type;
+ char *stil, *gfx;
+ iks *x;
+
+ type = r_get_style(ctx, node, "draw:fill");
+ if (type == 0) return 0;
+
+ if (strcmp(type, "solid") == 0) {
+ if (r_get_color(ctx, node, "draw:fill-color", &col)) {
+ ctx->drw->set_fg_color(drw_data, &col);
+ }
+ ctx->drw->draw_rect(drw_data, 1, 0, 0, ctx->pix_w, ctx->pix_h);
+ } else if (strcmp (type, "bitmap") == 0) {
+ stil = r_get_style(ctx, node, "draw:fill-image-name");
+ x = iks_find_with_attrib(iks_find(ctx->styles, "office:styles"),
+ "draw:fill-image", "draw:name", stil
+ );
+ gfx = iks_find_attrib(x, "xlink:href");
+ if (gfx) {
+ if (iks_strcmp(r_get_style(ctx, node, "style:repeat"), "stretch") == 0) {
+ _imp_draw_image(ctx, drw_data, gfx, 0, 0, ctx->pix_w, ctx->pix_h);
+ } else {
+ _imp_tile_image(ctx, drw_data, gfx, 0, 0, ctx->pix_w, ctx->pix_h);
+ }
+ }
+ } else if (strcmp(type, "gradient") == 0) {
+ r_draw_gradient(ctx, drw_data, node);
+ } else {
+ return 0;
+ }
+ return 1;
+}
diff --git a/backend/impress/r_draw.c b/backend/impress/r_draw.c
new file mode 100644
index 00000000..aad1655e
--- /dev/null
+++ b/backend/impress/r_draw.c
@@ -0,0 +1,120 @@
+/* imposter (OO.org Impress viewer)
+** Copyright (C) 2003-2005 Gurer Ozen
+** This code is free software; you can redistribute it and/or
+** modify it under the terms of GNU General Public License.
+*/
+
+#include <config.h>
+#include "common.h"
+#include "internal.h"
+#include <math.h>
+
+void
+_imp_draw_rect(ImpRenderCtx *ctx, void *drw_data, int fill, int x, int y, int w, int h, int round)
+{
+ int a;
+
+ if (0 == round) {
+ ctx->drw->draw_rect(drw_data, fill, x, y, w, h);
+ return;
+ }
+
+ ctx->drw->draw_arc(drw_data, fill,
+ x, y, round, round, 90, 90);
+ ctx->drw->draw_arc(drw_data, fill,
+ x + w - round, y, round, round, 0, 90);
+ ctx->drw->draw_arc(drw_data, fill,
+ x + w - round, y + h - round, round, round, 270, 90);
+ ctx->drw->draw_arc(drw_data, fill,
+ x, y + h - round, round, round, 180, 90);
+
+ a = round / 2;
+ if (fill) {
+ ctx->drw->draw_rect(drw_data, 1, x + a, y, w - a - a, h);
+ ctx->drw->draw_rect(drw_data, 1, x, y + a, w, h - a - a);
+ return;
+ }
+ ctx->drw->draw_line(drw_data, x + a, y, x + w - a, y);
+ ctx->drw->draw_line(drw_data, x + a, y + h, x + w - a, y + h);
+ ctx->drw->draw_line(drw_data, x, y + a, x, y + h - a);
+ ctx->drw->draw_line(drw_data, x + w, y + a, x + w, y + h - a);
+}
+
+void
+_imp_draw_line_end(ImpRenderCtx *ctx, void *drw_data, int type, int size, int x, int y, int x2, int y2)
+{
+ ImpPoint pts[4];
+ double ia, a;
+
+ // FIXME: different types and sizes
+
+ pts[0].x = x2;
+ pts[0].y = y2;
+
+ ia = 20 * 3.14 * 2 / 360;
+
+ if (x2-x == 0) {
+ if (y < y2) a = 3.14 + (3.14 / 2); else a = (3.14 / 2);
+ } else if (y2-y == 0) {
+ if (x < x2) a = 3.14; else a = 0;
+ } else
+ a = atan ((y2-y) / (x2-x)) - 3.14;
+
+ pts[1].x = x2 + 0.3 * ctx->fact_x * cos (a - ia);
+ pts[1].y = y2 + 0.3 * ctx->fact_y * sin (a - ia);
+
+ pts[2].x = x2 + 0.3 * ctx->fact_x * cos (a + ia);
+ pts[2].y = y2 + 0.3 * ctx->fact_y * sin (a + ia);
+
+ ctx->drw->draw_polygon(drw_data, 1, pts, 3);
+}
+
+void
+_imp_draw_image(ImpRenderCtx *ctx, void *drw_data, const char *name, int x, int y, int w, int h)
+{
+ void *img1, *img2;
+ char *pix;
+ size_t len;
+
+ len = zip_get_size(ctx->page->doc->zfile, name);
+ pix = malloc(len);
+ if (!pix) return;
+ zip_load(ctx->page->doc->zfile, name, pix);
+
+ img1 = ctx->drw->open_image(drw_data, pix, len);
+ free(pix);
+ if (!img1) return;
+ img2 = ctx->drw->scale_image(drw_data, img1, w, h);
+ if (img2) {
+ ctx->drw->draw_image(drw_data, img2, x, y, w, h);
+ ctx->drw->close_image(drw_data, img2);
+ }
+ ctx->drw->close_image(drw_data, img1);
+}
+
+void
+_imp_tile_image(ImpRenderCtx *ctx, void *drw_data, const char *name, int x, int y, int w, int h)
+{
+ void *img1;
+ char *pix;
+ size_t len;
+ int gx, gy, gw, gh;
+
+ len = zip_get_size(ctx->page->doc->zfile, name);
+ pix = malloc(len);
+ if (!pix) return;
+ zip_load(ctx->page->doc->zfile, name, pix);
+
+ img1 = ctx->drw->open_image(drw_data, pix, len);
+ free(pix);
+ if (!img1) return;
+
+ ctx->drw->get_image_size(drw_data, img1, &gw, &gh);
+ for (gx = x; gx < w; gx += gw) {
+ for (gy = y; gy < h; gy += gh) {
+ ctx->drw->draw_image(drw_data, img1, gx, gy, gw, gh);
+ }
+ }
+
+ ctx->drw->close_image(drw_data, img1);
+}
diff --git a/backend/impress/r_geometry.c b/backend/impress/r_geometry.c
new file mode 100644
index 00000000..4819821a
--- /dev/null
+++ b/backend/impress/r_geometry.c
@@ -0,0 +1,208 @@
+/* imposter (OO.org Impress viewer)
+** Copyright (C) 2003-2005 Gurer Ozen
+** This code is free software; you can redistribute it and/or
+** modify it under the terms of GNU General Public License.
+*/
+
+#include <config.h>
+#include "common.h"
+#include "internal.h"
+#include <math.h>
+
+void
+r_parse_color(const char *color, ImpColor *ic)
+{
+ unsigned int cval;
+
+ if (1 != sscanf(color, "#%X", &cval)) return;
+
+ ic->red = (cval & 0xFF0000) >> 8;
+ ic->green = cval & 0x00FF00;
+ ic->blue = (cval & 0xFF) << 8;
+}
+
+int
+r_get_color(ImpRenderCtx *ctx, iks *node, char *name, ImpColor *ic)
+{
+ char *color;
+
+ color = r_get_style(ctx, node, name);
+ if (!color) return 0;
+ r_parse_color(color, ic);
+
+ return 1;
+}
+
+static void
+fg_color(ImpRenderCtx *ctx, void *drw_data, iks *node, char *name)
+{
+ ImpColor ic;
+
+ if (r_get_color(ctx, node, name, &ic)) {
+ ctx->drw->set_fg_color(drw_data, &ic);
+ }
+}
+
+int
+r_get_x (ImpRenderCtx *ctx, iks *node, char *name)
+{
+ char *val;
+
+ val = iks_find_attrib (node, name);
+ if (!val) return 0;
+ return atof (val) * ctx->fact_x;
+}
+
+int
+r_get_y (ImpRenderCtx *ctx, iks *node, char *name)
+{
+ char *val;
+
+ val = iks_find_attrib (node, name);
+ if (!val) return 0;
+ return atof (val) * ctx->fact_y;
+}
+
+int
+r_get_angle (iks *node, char *name, int def)
+{
+ char *tmp;
+
+ tmp = iks_find_attrib (node, name);
+ if (!tmp) return def;
+ return atof (tmp);
+}
+
+static int x, y, w, h;
+static int px, py, pw, ph;
+
+static void
+r_get_viewbox (iks *node)
+{
+ char *tmp;
+
+ tmp = iks_find_attrib (node, "svg:viewBox");
+ if (!tmp) return;
+ sscanf (tmp, "%d %d %d %d", &px, &py, &pw, &ph);
+}
+
+void
+r_polygon(ImpRenderCtx *ctx, void *drw_data, iks *node)
+{
+ char *data;
+ ImpPoint *points;
+ int i, cnt, j;
+ int num;
+ int fill = 1;
+
+ data = r_get_style (ctx, node, "draw:fill");
+ if (!data || strcmp (data, "solid") != 0) fill = 0;
+
+ x = r_get_x (ctx, node, "svg:x");
+ y = r_get_y (ctx, node, "svg:y");
+ w = r_get_x (ctx, node, "svg:width");
+ h = r_get_y (ctx, node, "svg:height");
+ r_get_viewbox (node);
+
+ data = iks_find_attrib (node, "draw:points");
+ points = malloc (sizeof (ImpPoint) * strlen (data) / 4);
+
+ cnt = 0;
+ j = 0;
+ num = -1;
+ for (i = 0; data[i]; i++) {
+ if (data[i] >= '0' && data[i] <= '9') {
+ if (num == -1) num = i;
+ } else {
+ if (num != -1) {
+ if (j == 0) {
+ points[cnt].x = atoi (data + num);
+ j = 1;
+ } else {
+ points[cnt++].y = atoi (data + num);
+ j = 0;
+ }
+ num = -1;
+ }
+ }
+ }
+ if (num != -1) {
+ if (j == 0) {
+ points[cnt].x = atoi (data + num);
+ } else {
+ points[cnt++].y = atoi (data + num);
+ }
+ }
+ for (i = 0; i < cnt; i++) {
+ points[i].x = x + points[i].x * w / pw;
+ points[i].y = y + points[i].y * h / ph;
+ }
+
+ if (fill) {
+ fg_color(ctx, drw_data, node, "draw:fill-color");
+ ctx->drw->draw_polygon(drw_data, 1, points, cnt);
+ }
+ fg_color(ctx, drw_data, node, "svg:stroke-color");
+ ctx->drw->draw_polygon(drw_data, 0, points, cnt);
+
+ free (points);
+}
+
+void
+r_polyline(ImpRenderCtx *ctx, void *drw_data, iks *node)
+{
+ char *data;
+ ImpPoint *points;
+ int i, cnt, j;
+ int num;
+ int pen_x, pen_y;
+
+ x = r_get_x (ctx, node, "svg:x");
+ y = r_get_y (ctx, node, "svg:y");
+ w = r_get_x (ctx, node, "svg:width");
+ h = r_get_y (ctx, node, "svg:height");
+ r_get_viewbox (node);
+
+ data = iks_find_attrib (node, "draw:points");
+ points = malloc (sizeof (ImpPoint) * strlen (data) / 4);
+
+ cnt = 0;
+ j = 0;
+ num = -1;
+ for (i = 0; data[i]; i++) {
+ if (data[i] >= '0' && data[i] <= '9') {
+ if (num == -1) num = i;
+ } else {
+ if (num != -1) {
+ if (j == 0) {
+ points[cnt].x = atoi (data + num);
+ j = 1;
+ } else {
+ points[cnt++].y = atoi (data + num);
+ j = 0;
+ }
+ num = -1;
+ }
+ }
+ }
+ if (num != -1) {
+ if (j == 0) {
+ points[cnt].x = atoi (data + num);
+ } else {
+ points[cnt++].y = atoi (data + num);
+ }
+ }
+
+ pen_x = x + points[0].x * w /pw;
+ pen_y = y + points[0].y * h / ph;
+ fg_color(ctx, drw_data, node, "svg:stroke-color");
+ for (i = 1; i < cnt; i++) {
+ int tx, ty;
+ tx = x + points[i].x * w / pw;
+ ty = y + points[i].y * h / ph;
+ ctx->drw->draw_line(drw_data, pen_x, pen_y, tx, ty);
+ pen_x = tx;
+ pen_y = ty;
+ }
+ free (points);
+}
diff --git a/backend/impress/r_gradient.c b/backend/impress/r_gradient.c
new file mode 100644
index 00000000..79636fe2
--- /dev/null
+++ b/backend/impress/r_gradient.c
@@ -0,0 +1,387 @@
+/* imposter (OO.org Impress viewer)
+** Copyright (C) 2003-2005 Gurer Ozen
+** This code is free software; you can redistribute it and/or
+** modify it under the terms of GNU General Public License.
+*/
+
+#include <config.h>
+#include "common.h"
+#include "internal.h"
+#include <math.h>
+
+#define GRAD_LINEAR 0
+#define GRAD_AXIAL 1
+#define GRAD_SQUARE 2
+#define GRAD_RECTANGULAR 3
+#define GRAD_RADIAL 4
+#define GRAD_ELLIPTICAL 5
+
+typedef struct Gradient_s {
+ int type;
+ ImpColor start;
+ int start_intensity;
+ ImpColor end;
+ int end_intensity;
+ int angle;
+ int border;
+ int steps;
+ int offset_x;
+ int offset_y;
+} Gradient;
+
+typedef struct Rectangle_s {
+ int Left;
+ int Top;
+ int Right;
+ int Bottom;
+} Rectangle;
+
+static void
+poly_rotate (ImpPoint *poly, int n, int cx, int cy, double fAngle)
+{
+ int i;
+ long nX, nY;
+
+ for (i = 0; i < n; i++) {
+ nX = poly->x - cx;
+ nY = poly->y - cy;
+ poly->x = (cos(fAngle) * nX + sin(fAngle) * nY) + cx;
+ poly->y = - (sin(fAngle)* nX - cos(fAngle) * nY) + cy;
+ poly++;
+ }
+}
+
+static void
+r_draw_gradient_simple (ImpRenderCtx *ctx, void *drw_data, Gradient *grad)
+{
+ Rectangle rRect = { 0, 0, ctx->pix_w - 1, ctx->pix_h - 1 };
+ Rectangle aRect, aFullRect;
+ ImpPoint poly[4], tempoly[2];
+ ImpColor gcol;
+ double fW, fH, fDX, fDY, fAngle;
+ double fScanLine, fScanInc;
+ long redSteps, greenSteps, blueSteps;
+ long nBorder;
+ int i, nSteps, nSteps2;
+ int cx, cy;
+
+ cx = rRect.Left + (rRect.Right - rRect.Left) / 2;
+ cy = rRect.Top + (rRect.Bottom - rRect.Top) / 2;
+
+ aRect = rRect;
+ aRect.Top--; aRect.Left--; aRect.Bottom++; aRect.Right++;
+ fW = rRect.Right - rRect.Left;
+ fH = rRect.Bottom - rRect.Top;
+ fAngle = (((double) grad->angle) * 3.14 / 1800.0);
+ fDX = fW * fabs (cos (fAngle)) + fH * fabs (sin (fAngle));
+ fDY = fH * fabs (cos (fAngle)) + fW * fabs (sin (fAngle));
+ fDX = (fDX - fW) * 0.5 - 0.5;
+ fDY = (fDY - fH) * 0.5 - 0.5;
+ aRect.Left -= fDX;
+ aRect.Right += fDX;
+ aRect.Top -= fDY;
+ aRect.Bottom += fDY;
+ aFullRect = aRect;
+
+ nBorder = grad->border * (aRect.Bottom - aRect.Top) / 100;
+ if (grad->type == GRAD_LINEAR) {
+ aRect.Top += nBorder;
+ } else {
+ nBorder >>= 1;
+ aRect.Top += nBorder;
+ aRect.Bottom -= nBorder;
+ }
+
+ if (aRect.Top > (aRect.Bottom - 1))
+ aRect.Top = aRect.Bottom - 1;
+
+ poly[0].x = aFullRect.Left;
+ poly[0].y = aFullRect.Top;
+ poly[1].x = aFullRect.Right;
+ poly[1].y = aFullRect.Top;
+ poly[2].x = aRect.Right;
+ poly[2].y = aRect.Top;
+ poly[3].x = aRect.Left;
+ poly[3].y = aRect.Top;
+ poly_rotate (&poly[0], 4, cx, cy, fAngle);
+
+ redSteps = grad->end.red - grad->start.red;
+ greenSteps = grad->end.green - grad->start.green;
+ blueSteps = grad->end.blue - grad->start.blue;
+ nSteps = grad->steps;
+ if (nSteps == 0) {
+ long mr;
+ mr = aRect.Bottom - aRect.Top;
+ if (mr < 50)
+ nSteps = mr / 2;
+ else
+ nSteps = mr / 4;
+ mr = abs(redSteps);
+ if (abs(greenSteps) > mr) mr = abs(greenSteps);
+ if (abs(blueSteps) > mr) mr = abs(blueSteps);
+ if (mr < nSteps) nSteps = mr;
+ }
+
+ if (grad->type == GRAD_AXIAL) {
+ if (nSteps & 1) nSteps++;
+ nSteps2 = nSteps + 2;
+ gcol = grad->end;
+ redSteps <<= 1;
+ greenSteps <<= 1;
+ blueSteps <<= 1;
+ } else {
+ nSteps2 = nSteps + 1;
+ gcol = grad->start;
+ }
+
+ fScanLine = aRect.Top;
+ fScanInc = (double)(aRect.Bottom - aRect.Top) / (double)nSteps;
+
+ for (i = 0; i < nSteps2; i++) {
+ // draw polygon
+ ctx->drw->set_fg_color(drw_data, &gcol);
+ ctx->drw->draw_polygon(drw_data, 1, &poly[0], 4);
+ // calc next polygon
+ aRect.Top = (long)(fScanLine += fScanInc);
+ if (i == nSteps) {
+ tempoly[0].x = aFullRect.Left;
+ tempoly[0].y = aFullRect.Bottom;
+ tempoly[1].x = aFullRect.Right;
+ tempoly[1].y = aFullRect.Bottom;
+ } else {
+ tempoly[0].x = aRect.Left;
+ tempoly[0].y = aRect.Top;
+ tempoly[1].x = aRect.Right;
+ tempoly[1].y = aRect.Top;
+ }
+ poly_rotate (&tempoly[0], 2, cx, cy, fAngle);
+ poly[0] = poly[3];
+ poly[1] = poly[2];
+ poly[2] = tempoly[1];
+ poly[3] = tempoly[0];
+ // calc next color
+ if (grad->type == GRAD_LINEAR) {
+ gcol.red = grad->start.red + ((redSteps * i) / nSteps2);
+ gcol.green = grad->start.green + ((greenSteps * i) / nSteps2);
+ gcol.blue = grad->start.blue + ((blueSteps * i) / nSteps2);
+ } else {
+ if (i >= nSteps) {
+ gcol.red = grad->end.red;
+ gcol.green = grad->end.green;
+ gcol.blue = grad->end.blue;
+ } else {
+ if (i <= (nSteps / 2)) {
+ gcol.red = grad->end.red - ((redSteps * i) / nSteps2);
+ gcol.green = grad->end.green - ((greenSteps * i) / nSteps2);
+ gcol.blue = grad->end.blue - ((blueSteps * i) / nSteps2);
+ } else {
+ int i2 = i - nSteps / 2;
+ gcol.red = grad->start.red + ((redSteps * i2) / nSteps2);
+ gcol.green = grad->start.green + ((greenSteps * i2) / nSteps2);
+ gcol.blue = grad->start.blue + ((blueSteps * i2) / nSteps2);
+ }
+ }
+ }
+ }
+}
+
+static void
+r_draw_gradient_complex (ImpRenderCtx *ctx, void *drw_data, Gradient *grad)
+{
+ Rectangle rRect = { 0, 0, ctx->pix_w - 1, ctx->pix_h - 1 };
+ Rectangle aRect = rRect;
+ ImpColor gcol;
+ ImpPoint poly[4];
+ double fAngle = (((double) grad->angle) * 3.14 / 1800.0);
+ long redSteps, greenSteps, blueSteps;
+ long nZW, nZH;
+ long bX, bY;
+ long sW, sH;
+ long cx, cy;
+ int i;
+ long nSteps;
+ double sTop, sLeft, sRight, sBottom, sInc;
+ int minRect;
+
+ redSteps = grad->end.red - grad->start.red;
+ greenSteps = grad->end.green - grad->start.green;
+ blueSteps = grad->end.blue - grad->start.blue;
+
+ if (grad->type == GRAD_SQUARE || grad->type == GRAD_RECTANGULAR) {
+ double fW = aRect.Right - aRect.Left;
+ double fH = aRect.Bottom - aRect.Top;
+ double fDX = fW * fabs (cos (fAngle)) + fH * fabs (sin (fAngle));
+ double fDY = fH * fabs (cos (fAngle)) + fW * fabs (sin (fAngle));
+ fDX = (fDX - fW) * 0.5 - 0.5;
+ fDY = (fDY - fH) * 0.5 - 0.5;
+ aRect.Left -= fDX;
+ aRect.Right += fDX;
+ aRect.Top -= fDY;
+ aRect.Bottom += fDY;
+ }
+
+ sW = aRect.Right - aRect.Left;
+ sH = aRect.Bottom - aRect.Top;
+
+ if (grad->type == GRAD_SQUARE) {
+ if (sW > sH) sH = sW; else sW = sH;
+ } else if (grad->type == GRAD_RADIAL) {
+ sW = 0.5 + sqrt ((double)sW*(double)sW + (double)sH*(double)sH);
+ sH = sW;
+ } else if (grad->type == GRAD_ELLIPTICAL) {
+ sW = 0.5 + (double)sW * 1.4142;
+ sH = 0.5 + (double)sH * 1.4142;
+ }
+
+ nZW = (aRect.Right - aRect.Left) * grad->offset_x / 100;
+ nZH = (aRect.Bottom - aRect.Top) * grad->offset_y / 100;
+ bX = grad->border * sW / 100;
+ bY = grad->border * sH / 100;
+ cx = aRect.Left + nZW;
+ cy = aRect.Top + nZH;
+
+ sW -= bX;
+ sH -= bY;
+
+ aRect.Left = cx - ((aRect.Right - aRect.Left) >> 1);
+ aRect.Top = cy - ((aRect.Bottom - aRect.Top) >> 1);
+
+ nSteps = grad->steps;
+ minRect = aRect.Right - aRect.Left;
+ if (aRect.Bottom - aRect.Top < minRect) minRect = aRect.Bottom - aRect.Top;
+ if (nSteps == 0) {
+ long mr;
+ if (minRect < 50)
+ nSteps = minRect / 2;
+ else
+ nSteps = minRect / 4;
+ mr = abs(redSteps);
+ if (abs(greenSteps) > mr) mr = abs(greenSteps);
+ if (abs(blueSteps) > mr) mr = abs(blueSteps);
+ if (mr < nSteps) nSteps = mr;
+ }
+
+ sLeft = aRect.Left;
+ sTop = aRect.Top;
+ sRight = aRect.Right;
+ sBottom = aRect.Bottom;
+ sInc = (double) minRect / (double) nSteps * 0.5;
+
+ gcol = grad->start;
+ poly[0].x = rRect.Left;
+ poly[0].y = rRect.Top;
+ poly[1].x = rRect.Right;
+ poly[1].y = rRect.Top;
+ poly[2].x = rRect.Right;
+ poly[2].y = rRect.Bottom;
+ poly[3].x = rRect.Left;
+ poly[3].y = rRect.Bottom;
+ ctx->drw->set_fg_color(drw_data, &gcol);
+ ctx->drw->draw_polygon(drw_data, 1, &poly[0], 4);
+
+ for (i = 0; i < nSteps; i++) {
+ aRect.Left = (long) (sLeft += sInc);
+ aRect.Top = (long) (sTop += sInc);
+ aRect.Right = (long) (sRight -= sInc);
+ aRect.Bottom = (long) (sBottom -= sInc);
+ if (aRect.Bottom - aRect.Top < 2 || aRect.Right - aRect.Left < 2)
+ break;
+
+ gcol.red = grad->start.red + (redSteps * (i+1) / nSteps);
+ gcol.green = grad->start.green + (greenSteps * (i+1) / nSteps);
+ gcol.blue = grad->start.blue + (blueSteps * (i+1) / nSteps);
+ ctx->drw->set_fg_color(drw_data, &gcol);
+
+ if (grad->type == GRAD_RADIAL || grad->type == GRAD_ELLIPTICAL) {
+ ctx->drw->draw_arc(drw_data, 1, aRect.Left, aRect.Top,
+ aRect.Right - aRect.Left, aRect.Bottom - aRect.Top,
+ 0, 360);
+ } else {
+ poly[0].x = aRect.Left;
+ poly[0].y = aRect.Top;
+ poly[1].x = aRect.Right;
+ poly[1].y = aRect.Top;
+ poly[2].x = aRect.Right;
+ poly[2].y = aRect.Bottom;
+ poly[3].x = aRect.Left;
+ poly[3].y = aRect.Bottom;
+ poly_rotate (&poly[0], 4, cx, cy, fAngle);
+ ctx->drw->draw_polygon(drw_data, 1, &poly[0], 4);
+ }
+ }
+}
+
+void
+r_draw_gradient (ImpRenderCtx *ctx, void *drw_data, iks *node)
+{
+// GdkGC *gc;
+ Gradient grad;
+ char *stil, *tmp;
+ iks *x;
+
+ stil = r_get_style (ctx, node, "draw:fill-gradient-name");
+ x = iks_find_with_attrib (iks_find (ctx->styles, "office:styles"),
+ "draw:gradient", "draw:name", stil);
+ if (x) {
+ memset (&grad, 0, sizeof (Gradient));
+ grad.type = -1;
+ grad.offset_x = 50;
+ grad.offset_y = 50;
+
+ tmp = iks_find_attrib (x, "draw:start-color");
+ if (tmp) r_parse_color (tmp, &grad.start);
+ tmp = iks_find_attrib (x, "draw:start-intensity");
+ if (tmp) {
+ int val = atoi (tmp);
+ grad.start.red = grad.start.red * val / 100;
+ grad.start.green = grad.start.green * val / 100;
+ grad.start.blue = grad.start.blue * val / 100;
+ }
+ tmp = iks_find_attrib (x, "draw:end-color");
+ if (tmp) r_parse_color (tmp, &grad.end);
+ tmp = iks_find_attrib (x, "draw:end-intensity");
+ if (tmp) {
+ int val = atoi (tmp);
+ grad.end.red = grad.end.red * val / 100;
+ grad.end.green = grad.end.green * val / 100;
+ grad.end.blue = grad.end.blue * val / 100;
+ }
+ tmp = iks_find_attrib (x, "draw:angle");
+ if (tmp) grad.angle = atoi(tmp) % 3600;
+ tmp = iks_find_attrib (x, "draw:border");
+ if (tmp) grad.border = atoi(tmp);
+ tmp = r_get_style (ctx, node, "draw:gradient-step-count");
+ if (tmp) grad.steps = atoi (tmp);
+ tmp = iks_find_attrib (x, "draw:cx");
+ if (tmp) grad.offset_x = atoi (tmp);
+ tmp = iks_find_attrib (x, "draw:cy");
+ if (tmp) grad.offset_y = atoi (tmp);
+ tmp = iks_find_attrib (x, "draw:style");
+ if (iks_strcmp (tmp, "linear") == 0)
+ grad.type = GRAD_LINEAR;
+ else if (iks_strcmp (tmp, "axial") == 0)
+ grad.type = GRAD_AXIAL;
+ else if (iks_strcmp (tmp, "radial") == 0)
+ grad.type = GRAD_RADIAL;
+ else if (iks_strcmp (tmp, "rectangular") == 0)
+ grad.type = GRAD_RECTANGULAR;
+ else if (iks_strcmp (tmp, "ellipsoid") == 0)
+ grad.type = GRAD_ELLIPTICAL;
+ else if (iks_strcmp (tmp, "square") == 0)
+ grad.type = GRAD_SQUARE;
+
+ if (grad.type == -1) return;
+
+// gc = ctx->gc;
+// ctx->gc = gdk_gc_new (ctx->d);
+// gdk_gc_copy (ctx->gc, gc);
+
+ if (grad.type == GRAD_LINEAR || grad.type == GRAD_AXIAL)
+ r_draw_gradient_simple (ctx, drw_data, &grad);
+ else
+ r_draw_gradient_complex (ctx, drw_data, &grad);
+
+// g_object_unref (ctx->gc);
+// ctx->gc = gc;
+ }
+}
diff --git a/backend/impress/r_style.c b/backend/impress/r_style.c
new file mode 100644
index 00000000..39ee9c62
--- /dev/null
+++ b/backend/impress/r_style.c
@@ -0,0 +1,111 @@
+/* imposter (OO.org Impress viewer)
+** Copyright (C) 2003-2005 Gurer Ozen
+** This code is free software; you can redistribute it and/or
+** modify it under the terms of GNU General Public License.
+*/
+
+#include <config.h>
+#include "common.h"
+#include "internal.h"
+
+static char *
+get_style(ImpRenderCtx *ctx, iks *node, char *style, char *attr)
+{
+ char *ret;
+ iks *x;
+
+ if (!style) return NULL;
+
+ if (iks_root (node) == ctx->content) {
+ x = iks_find_with_attrib (iks_find (ctx->content, "office:automatic-styles"),
+ "style:style", "style:name", style);
+ } else {
+ x = iks_find_with_attrib (iks_find (ctx->styles, "office:automatic-styles"),
+ "style:style", "style:name", style);
+ }
+ if (!x) return NULL;
+
+ while (x) {
+ ret = iks_find_attrib (iks_find (x, "style:properties"), attr);
+ if (ret) return ret;
+ ret = iks_find_attrib (iks_find (x, "style:text-properties"), attr);
+ if (ret) return ret;
+ ret = iks_find_attrib (iks_find (x, "style:paragraph-properties"), attr);
+ if (ret) return ret;
+ ret = iks_find_attrib (iks_find (x, "style:graphic-properties"), attr);
+ if (ret) return ret;
+ ret = iks_find_attrib (iks_find (x, "style:drawing-page-properties"), attr);
+ if (ret) return ret;
+
+ style = iks_find_attrib (x, "style:parent-style-name");
+ if (!style) return NULL;
+
+ x = iks_find_with_attrib (iks_find (ctx->styles, "office:styles"),
+ "style:style", "style:name", style);
+
+ }
+ return NULL;
+}
+
+char *
+r_get_style (ImpRenderCtx *ctx, iks *node, char *attr)
+{
+ char *ret, *s;
+ iks *x;
+
+ ret = iks_find_attrib (node, attr);
+ if (ret) return ret;
+
+ for (x = node; x; x = iks_parent (x)) {
+ s = iks_find_attrib (x, "text:style-name");
+ ret = get_style (ctx, node, s, attr);
+ if (ret) return ret;
+ s = iks_find_attrib (x, "presentation:style-name");
+ ret = get_style (ctx, node, s, attr);
+ if (ret) return ret;
+ s = iks_find_attrib (x, "draw:style-name");
+ ret = get_style (ctx, node, s, attr);
+ if (ret) return ret;
+ }
+ return NULL;
+}
+
+#if 0
+static iks *
+get_style_x (ImpRenderCtx *ctx, iks *node, char *style, char *attr)
+{
+ iks *x;
+
+ if (!style) return NULL;
+
+ if (iks_root (node) == ctx->content) {
+ x = iks_find_with_attrib (iks_find (ctx->content, "office:automatic-styles"),
+ "text:list-style", "style:name", style);
+ } else {
+ x = iks_find_with_attrib (iks_find (ctx->styles, "office:automatic-styles"),
+ "text:list-style", "style:name", style);
+ }
+ return x;
+}
+
+static iks *
+r_get_bullet (ImpRenderCtx *ctx, iks *node, char *attr)
+{
+ iks *ret;
+ char *s;
+ iks *x;
+
+ for (x = node; x; x = iks_parent (x)) {
+ s = iks_find_attrib (x, "text:style-name");
+ ret = get_style_x (ctx, node, s, attr);
+ if (ret) return ret;
+ s = iks_find_attrib (x, "presentation:style-name");
+ ret = get_style_x (ctx, node, s, attr);
+ if (ret) return ret;
+ s = iks_find_attrib (x, "draw:style-name");
+ ret = get_style_x (ctx, node, s, attr);
+ if (ret) return ret;
+ }
+ return NULL;
+}
+#endif
diff --git a/backend/impress/r_text.c b/backend/impress/r_text.c
new file mode 100644
index 00000000..4b89bcad
--- /dev/null
+++ b/backend/impress/r_text.c
@@ -0,0 +1,386 @@
+/* imposter (OO.org Impress viewer)
+** Copyright (C) 2003-2005 Gurer Ozen
+** This code is free software; you can redistribute it and/or
+** modify it under the terms of GNU General Public License.
+*/
+
+#include <config.h>
+#include "common.h"
+#include "internal.h"
+
+struct Span {
+ struct Span *next;
+ int x, y;
+ int w, h;
+ char *text;
+ int len;
+ int size;
+ int styles;
+ ImpColor fg;
+};
+
+struct Line {
+ struct Line *next;
+ struct Span *spans;
+ struct Span *last_span;
+ int x, y;
+ int w, h;
+};
+
+struct Layout {
+ ikstack *s;
+ int x, y, w, h;
+ int tw, th;
+ struct Line *lines;
+ struct Line *last_line;
+ char spaces[128];
+};
+
+static struct Line *
+add_line(struct Layout *lay)
+{
+ struct Line *line;
+
+ line = iks_stack_alloc(lay->s, sizeof(struct Line));
+ memset(line, 0, sizeof(struct Line));
+
+ if (!lay->lines) lay->lines = line;
+ if (lay->last_line) lay->last_line->next = line;
+ lay->last_line = line;
+
+ return line;
+}
+
+static struct Span *
+add_span(struct Layout *lay, char *text, int len, int size, int styles)
+{
+ struct Line *line;
+ struct Span *span;
+
+ span = iks_stack_alloc(lay->s, sizeof(struct Span));
+ memset(span, 0, sizeof(struct Span));
+ span->text = text;
+ span->len = len;
+ span->size = size;
+ span->styles = styles;
+
+ line = lay->last_line;
+ if (!line) line = add_line(lay);
+ if (line->spans) {
+ span->x = line->last_span->x + line->last_span->w;
+ span->y = line->last_span->y;
+ } else {
+ span->x = line->x;
+ span->y = line->y;
+ }
+
+ if (!line->spans) line->spans = span;
+ if (line->last_span) line->last_span->next = span;
+ line->last_span = span;
+
+ return span;
+}
+
+static void
+calc_sizes(ImpRenderCtx *ctx, void *drw_data, struct Layout *lay)
+{
+ struct Line *line;
+ struct Span *span;
+
+ for (line = lay->lines; line; line = line->next) {
+ for (span = line->spans; span; span = span->next) {
+ ctx->drw->get_text_size(drw_data,
+ span->text, span->len,
+ span->size, span->styles,
+ &span->w, &span->h
+ );
+ line->w += span->w;
+ if (span->h > line->h) line->h = span->h;
+ }
+ if (line->w > lay->tw) lay->tw = line->w;
+ lay->th += line->h;
+ }
+}
+
+static void
+calc_pos(ImpRenderCtx *ctx, struct Layout *lay)
+{
+ struct Line *line;
+ struct Span *span;
+ int x, y, x2;
+
+ x = lay->x;
+ y = lay->y;
+ for (line = lay->lines; line; line = line->next) {
+ line->x = x;
+ line->y = y;
+ y += line->h;
+ x2 = x;
+ for (span = line->spans; span; span = span->next) {
+ span->x = x2;
+ span->y = y;
+ x2 += span->w;
+ }
+ }
+}
+
+static void
+_imp_draw_layout(ImpRenderCtx *ctx, void *drw_data, struct Layout *lay)
+{
+ struct Line *line;
+ struct Span *span;
+
+ for (line = lay->lines; line; line = line->next) {
+ for (span = line->spans; span; span = span->next) {
+ ctx->drw->set_fg_color(drw_data, &span->fg);
+ ctx->drw->draw_text(drw_data,
+ span->x, span->y,
+ span->text, span->len,
+ span->size,
+ span->styles
+ );
+ }
+ }
+}
+
+static void
+text_span(ImpRenderCtx *ctx, struct Layout *lay, iks *node, char *text, size_t len)
+{
+ struct Span *span;
+ double cm;
+ char *attr, *t, *s;
+ int px = 0, cont = 1;
+ int styles = IMP_NORMAL;
+
+ attr = r_get_style(ctx, node, "fo:font-size");
+ if (attr) {
+ cm = atof(attr);
+ if (strstr(attr, "pt")) cm = cm * 2.54 / 102;
+ px = cm * ctx->fact_y;
+ }
+ attr = r_get_style(ctx, node, "fo:font-weight");
+ if (attr && strcmp(attr, "bold") == 0) styles |= IMP_BOLD;
+ attr = r_get_style(ctx, node, "style:text-underline");
+ if (attr && strcmp(attr, "single") == 0) styles |= IMP_UNDERLINE;
+ attr = r_get_style(ctx, node, "fo:font-style");
+ if (attr && strcmp(attr, "italic") == 0) styles |= IMP_ITALIC;
+
+ t = text;
+ while (cont) {
+ s = strchr(t, '\n');
+ if (s) {
+ int len2 = s - t;
+ span = add_span(lay, t, len2, px, styles);
+ t = s + 1;
+ len -= len2;
+ add_line(lay);
+ } else {
+ span = add_span(lay, text, len, px, styles);
+ cont = 0;
+ }
+ r_get_color(ctx, node, "fo:color", &span->fg);
+ }
+}
+
+static void
+text_p(ImpRenderCtx *ctx, struct Layout *lay, iks *node)
+{
+ iks *n, *n2;
+
+ add_line(lay);
+ for (n = iks_child(node); n; n = iks_next(n)) {
+ if (iks_type(n) == IKS_CDATA) {
+ text_span(ctx, lay, node, iks_cdata(n), iks_cdata_size(n));
+ } else if (iks_strcmp(iks_name(n), "text:span") == 0) {
+ for (n2 = iks_child(n); n2; n2 = iks_next(n2)) {
+ if (iks_type(n2) == IKS_CDATA) {
+ text_span(ctx, lay, n2, iks_cdata(n2), iks_cdata_size(n2));
+ } else if (iks_strcmp(iks_name(n2), "text:s") == 0) {
+ char *attr;
+ int c = 1;
+ attr = iks_find_attrib(n2, "text:c");
+ if (attr) c = atoi(attr);
+ if (c > 127) {
+ c = 127;
+ puts("bork bork");
+ }
+ text_span(ctx, lay, n, lay->spaces, c);
+ } else if (iks_strcmp(iks_name(n2), "text:a") == 0) {
+ text_span(ctx, lay, n, iks_cdata(iks_child(n2)), iks_cdata_size(iks_child(n2)));
+ } else if (iks_strcmp(iks_name(n2), "text:tab-stop") == 0) {
+ text_span(ctx, lay, n, "\t", 1);
+ } else if (iks_strcmp(iks_name(n2), "text:page-number") == 0) {
+ char buf[8];
+ sprintf(buf, "%d", ctx->page->nr);
+ text_span(ctx, lay, n, iks_stack_strdup(lay->s, buf, 0), strlen(buf));
+ }
+ }
+ } else if (iks_strcmp(iks_name(n), "text:line-break") == 0) {
+ add_line(lay);
+ } else if (iks_strcmp(iks_name(n), "text:a") == 0) {
+ text_span(ctx, lay, n, iks_cdata(iks_child(n)), iks_cdata_size(iks_child(n)));
+ } else if (iks_strcmp(iks_name(n), "text:page-number") == 0) {
+ char buf[8];
+ sprintf(buf, "%d", ctx->page->nr);
+ text_span(ctx, lay, n, iks_stack_strdup(lay->s, buf, 0), strlen(buf));
+ }
+ }
+}
+
+static void
+text_list(ImpRenderCtx *ctx, struct Layout *lay, iks *node)
+{
+ iks *n, *n2;
+
+ for (n = iks_first_tag(node); n; n = iks_next_tag(n)) {
+ for (n2 = iks_first_tag(n); n2; n2 = iks_next_tag(n2)) {
+ if (strcmp(iks_name(n2), "text:p") == 0) {
+ text_p(ctx, lay, n2);
+ } else if (strcmp(iks_name(n2), "text:ordered-list") == 0) {
+ text_list(ctx, lay, n2);
+ } else if (strcmp(iks_name(n2), "text:unordered-list") == 0) {
+ text_list(ctx, lay, n2);
+ } else if (strcmp(iks_name(n2), "text:list") == 0) {
+ text_list(ctx, lay, n2);
+ }
+ }
+ }
+}
+
+void
+r_text(ImpRenderCtx *ctx, void *drw_data, iks *node)
+{
+ struct Layout lay;
+ iks *n;
+
+ memset(&lay, 0, sizeof(struct Layout));
+ memset(&lay.spaces, ' ', 128);
+ lay.s = iks_stack_new(sizeof(struct Span) * 16, 0);
+ lay.x = r_get_x(ctx, node, "svg:x");
+ lay.y = r_get_y(ctx, node, "svg:y");
+ lay.w = r_get_y(ctx, node, "svg:width");
+ lay.h = r_get_y(ctx, node, "svg:height");
+
+ for (n = iks_first_tag(node); n; n = iks_next_tag(n)) {
+ if (strcmp(iks_name(n), "text:p") == 0) {
+ text_p(ctx, &lay, n);
+ } else if (strcmp(iks_name(n), "text:ordered-list") == 0) {
+ text_list(ctx, &lay, n);
+ } else if (strcmp(iks_name(n), "text:unordered-list") == 0) {
+ text_list(ctx, &lay, n);
+ } else if (strcmp(iks_name(n), "text:list") == 0) {
+ text_list(ctx, &lay, n);
+ }
+ }
+
+ calc_sizes(ctx, drw_data, &lay);
+ calc_pos(ctx, &lay);
+ _imp_draw_layout(ctx, drw_data, &lay);
+
+ iks_stack_delete(lay.s);
+}
+/*
+static void
+text_span (render_ctx *ctx, text_ctx *tc, struct layout_s *lout, iks *node, char *text, int len)
+{
+ if (tc->bullet_flag && tc->bullet_sz) size = tc->bullet_sz; else size = r_get_font_size (ctx, tc, node);
+}
+
+static int
+is_animated (render_ctx *ctx, text_ctx *tc, iks *node)
+{
+ if (!ctx->step_mode) return 0;
+ if (!tc->id) return 0;
+ while (strcmp (iks_name (node), "draw:page") != 0
+ && strcmp (iks_name (node), "style:master-page") != 0)
+ node = iks_parent (node);
+ node = iks_find (node, "presentation:animations");
+ if (!node) return 0;
+ if (iks_find_with_attrib (node, "presentation:show-text", "draw:shape-id", tc->id)) return 1;
+ return 0;
+}
+
+static void
+text_p (render_ctx *ctx, text_ctx *tc, iks *node)
+{
+ if (is_animated (ctx, tc, node) && ctx->step_cnt >= ctx->step) lout->flag = 0;
+ ctx->step_cnt++;
+
+ attr = r_get_style (ctx, node, "text:enable-numbering");
+ if (attr && strcmp (attr, "true") == 0) {
+ if (iks_child (node) && tc->bullet) {
+ tc->bullet_flag = 1;
+ text_span (ctx, tc, lout, node, tc->bullet, strlen (tc->bullet));
+ text_span (ctx, tc, lout, node, " ", 1);
+ tc->bullet_flag = 0;
+ }
+ }
+
+ if (!lout->text) {
+lout->h = 0;
+attr = r_get_style (ctx, node, "fo:line-height");
+if (attr) {
+ int ratio = atoi (attr);
+ lout->lh = ratio;
+} else {
+ lout->lh = 100;
+}
+tc->layouts = g_list_append (tc->layouts, lout);
+// g_object_unref (lout->play);
+// iks_stack_delete (s);
+ return;
+ }
+
+ attr = r_get_style (ctx, node, "fo:text-align");
+ if (attr) {
+ if (strcmp (attr, "center") == 0)
+ pango_layout_set_alignment (lout->play, PANGO_ALIGN_CENTER);
+ else if (strcmp (attr, "end") == 0)
+ pango_layout_set_alignment (lout->play, PANGO_ALIGN_RIGHT);
+ }
+ pango_layout_set_width (lout->play, tc->w * PANGO_SCALE);
+ pango_layout_set_markup (lout->play, lout->text, lout->text_len);
+ pango_layout_get_pixel_size (lout->play, &lout->w, &lout->h);
+ attr = r_get_style (ctx, node, "fo:line-height");
+ if (attr) {
+ int ratio = atoi (attr);
+ lout->lh = ratio;
+ } else {
+ lout->lh = 100;
+ }
+ tc->layouts = g_list_append (tc->layouts, lout);
+}
+
+static void
+find_bullet (render_ctx *ctx, text_ctx *tc, iks *node)
+{
+ iks *x;
+ char *t;
+ x = r_get_bullet (ctx, node, "text:list-level-style-bullet");
+ x = iks_find (x, "text:list-level-style-bullet");
+ t = iks_find_attrib (x, "text:bullet-char");
+ if (t) tc->bullet = t; else tc->bullet = "*";
+ x = iks_find (x, "style:properties");
+ t = iks_find_attrib (x, "fo:font-size");
+ if (t) tc->bullet_sz = tc->last_sz * atoi (t) / 100;
+ else tc->bullet_sz = 0;
+}
+
+void
+r_text (render_ctx *ctx, iks *node)
+{
+ tc.id = iks_find_attrib (node, "draw:id");
+ ctx->step_cnt = 0;
+ for (n = iks_first_tag (node); n; n = iks_next_tag (n)) {
+ if (strcmp (iks_name (n), "text:p") == 0) {
+ text_p (ctx, &tc, n);
+ } else if (strcmp (iks_name (n), "text:ordered-list") == 0) {
+ text_list (ctx, &tc, n);
+ } else if (strcmp (iks_name (n), "text:unordered-list") == 0) {
+ find_bullet (ctx, &tc, n);
+ text_list (ctx, &tc, n);
+ tc.bullet = 0;
+ }
+ }
+
+*/
diff --git a/backend/impress/render.c b/backend/impress/render.c
new file mode 100644
index 00000000..67b80756
--- /dev/null
+++ b/backend/impress/render.c
@@ -0,0 +1,54 @@
+/* imposter (OO.org Impress viewer)
+** Copyright (C) 2003-2005 Gurer Ozen
+** This code is free software; you can redistribute it and/or
+** modify it under the terms of GNU General Public License.
+*/
+
+#include <config.h>
+#include "common.h"
+#include "internal.h"
+
+ImpRenderCtx *
+imp_create_context(const ImpDrawer *drw)
+{
+ ImpRenderCtx *ctx;
+
+ ctx = calloc(1, sizeof(ImpRenderCtx));
+ if (!ctx) return NULL;
+ ctx->drw = drw;
+ return ctx;
+}
+
+void
+imp_context_set_page(ImpRenderCtx *ctx, ImpPage *page)
+{
+ ctx->page = page;
+ ctx->content = page->doc->content;
+ ctx->styles = page->doc->styles;
+}
+
+void
+imp_context_set_step(ImpRenderCtx *ctx, int step)
+{
+ ctx->step = step;
+}
+
+void
+imp_render(ImpRenderCtx *ctx, void *drw_data)
+{
+ // find drawing area size
+ ctx->drw->get_size(drw_data, &ctx->pix_w, &ctx->pix_h);
+ // find page size
+ ctx->page->doc->get_geometry(ctx);
+ // calculate ratio
+ ctx->fact_x = ctx->pix_w / ctx->cm_w;
+ ctx->fact_y = ctx->pix_h / ctx->cm_h;
+ // call renderer
+ ctx->page->doc->render_page(ctx, drw_data);
+}
+
+void
+imp_delete_context(ImpRenderCtx *ctx)
+{
+ free(ctx);
+}
diff --git a/backend/impress/zip.c b/backend/impress/zip.c
new file mode 100644
index 00000000..b1f25c8c
--- /dev/null
+++ b/backend/impress/zip.c
@@ -0,0 +1,349 @@
+/* imposter (OO.org Impress viewer)
+** Copyright (C) 2003-2005 Gurer Ozen
+** This code is free software; you can redistribute it and/or
+** modify it under the terms of GNU General Public License.
+*/
+
+#include <config.h>
+#include "common.h"
+#include "zip.h"
+#include <zlib.h>
+#define _(x) x
+
+typedef unsigned long ulong;
+
+enum {
+ ZIP_OK = 0,
+ ZIP_NOMEM,
+ ZIP_NOSIG,
+ ZIP_BADZIP,
+ ZIP_NOMULTI,
+ ZIP_EOPEN,
+ ZIP_EREAD,
+ ZIP_NOFILE
+};
+
+struct zipfile {
+ struct zipfile *next;
+ char *name;
+ ulong crc;
+ ulong zip_size;
+ ulong real_size;
+ ulong pos;
+};
+
+struct zip_struct {
+ FILE *f;
+ struct zipfile *files;
+ ulong cd_pos;
+ ulong cd_size;
+ ulong cd_offset;
+ ulong head_size;
+ ulong rem_size;
+ ulong nr_files;
+};
+
+char *
+zip_error (int err)
+{
+ char *ret;
+
+ switch (err) {
+ case ZIP_OK:
+ ret = _("No error");
+ break;
+ case ZIP_NOMEM:
+ ret = _("Not enough memory");
+ break;
+ case ZIP_NOSIG:
+ ret = _("Cannot find ZIP signature");
+ break;
+ case ZIP_BADZIP:
+ ret = _("Invalid ZIP file");
+ break;
+ case ZIP_NOMULTI:
+ ret = _("Multi file ZIPs are not supported");
+ break;
+ case ZIP_EOPEN:
+ ret = _("Cannot open the file");
+ break;
+ case ZIP_EREAD:
+ ret = _("Cannot read data from file");
+ break;
+ case ZIP_NOFILE:
+ ret = _("Cannot find file in the ZIP archive");
+ break;
+ default:
+ ret = _("Unknown error");
+ break;
+ }
+ return ret;
+}
+
+static int
+find_cd (zip *z)
+{
+ FILE *f;
+ char *buf;
+ ulong size, pos, i, flag;
+
+ f = z->f;
+ if (fseek (f, 0, SEEK_END) != 0) return 1;
+ size = ftell (f);
+ if (size < 0xffff) pos = 0; else pos = size - 0xffff;
+ buf = malloc (size - pos + 1);
+ if (!buf) return 1;
+ if (fseek (f, pos, SEEK_SET) != 0) {
+ free (buf);
+ return 1;
+ }
+ if (fread (buf, size - pos, 1, f) != 1) {
+ free (buf);
+ return 1;
+ }
+ flag = 0;
+ for (i = size - pos - 3; i > 0; i--) {
+ if (buf[i] == 0x50 && buf[i+1] == 0x4b && buf[i+2] == 0x05 && buf[i+3] == 0x06) {
+ z->cd_pos = i + pos;
+ flag = 1;
+ break;
+ }
+ }
+ free (buf);
+ if (flag != 1) return 1;
+ return 0;
+}
+
+static unsigned long
+get_long (unsigned char *buf)
+{
+ return buf[0] + (buf[1] << 8) + (buf[2] << 16) + (buf[3] << 24);
+}
+
+static unsigned long
+get_word (unsigned char *buf)
+{
+ return buf[0] + (buf[1] << 8);
+}
+
+static int
+list_files (zip *z)
+{
+ unsigned char buf[46];
+ struct zipfile *zfile;
+ ulong pat, fn_size;
+ int nr = 0;
+
+ pat = z->cd_offset;
+ while (nr < z->nr_files) {
+ fseek (z->f, pat + z->head_size, SEEK_SET);
+
+ if (fread (buf, 46, 1, z->f) != 1) return ZIP_EREAD;
+ if (get_long (buf) != 0x02014b50) return ZIP_BADZIP;
+
+ zfile = malloc (sizeof (struct zipfile));
+ if (!zfile) return ZIP_NOMEM;
+ memset (zfile, 0, sizeof (struct zipfile));
+
+ zfile->crc = get_long (buf + 16);
+ zfile->zip_size = get_long (buf + 20);
+ zfile->real_size = get_long (buf + 24);
+ fn_size = get_word (buf + 28);
+ zfile->pos = get_long (buf + 42);
+
+ zfile->name = malloc (fn_size + 1);
+ if (!zfile->name) {
+ free (zfile);
+ return ZIP_NOMEM;
+ }
+ fread (zfile->name, fn_size, 1, z->f);
+ zfile->name[fn_size] = '\0';
+
+ zfile->next = z->files;
+ z->files = zfile;
+
+ pat += 0x2e + fn_size + get_word (buf + 30) + get_word (buf + 32);
+ nr++;
+ }
+ return ZIP_OK;
+}
+
+zip *
+zip_open (const char *fname, int *err)
+{
+ unsigned char buf[22];
+ zip *z;
+ FILE *f;
+
+ f = fopen (fname, "rb");
+ if (NULL == f) {
+ *err = ZIP_EOPEN;
+ return NULL;
+ }
+
+ z = malloc (sizeof (zip));
+ memset (z, 0, sizeof (zip));
+ z->f = f;
+
+ if (find_cd (z)) {
+ zip_close (z);
+ *err = ZIP_NOSIG;
+ return NULL;
+ }
+
+ fseek (f, z->cd_pos, SEEK_SET);
+ if (fread (buf, 22, 1, f) != 1) {
+ zip_close (z);
+ *err = ZIP_EREAD;
+ return NULL;
+ }
+ z->nr_files = get_word (buf + 10);
+ if (get_word (buf + 8) != z->nr_files) {
+ zip_close (z);
+ *err = ZIP_NOMULTI;
+ return NULL;
+ }
+ z->cd_size = get_long (buf + 12);
+ z->cd_offset = get_long (buf + 16);
+ z->rem_size = get_word (buf + 20);
+ z->head_size = z->cd_pos - (z->cd_offset + z->cd_size);
+
+ *err = list_files (z);
+ if (*err != ZIP_OK) {
+ zip_close (z);
+ return NULL;
+ }
+
+ *err = ZIP_OK;
+ return z;
+}
+
+void
+zip_close (zip *z)
+{
+ struct zipfile *zfile, *tmp;
+
+ zfile = z->files;
+ while (zfile) {
+ tmp = zfile->next;
+ if (zfile->name) free (zfile->name);
+ free (zfile);
+ zfile = tmp;
+ }
+ z->files = NULL;
+ if (z->f) fclose (z->f);
+ z->f = NULL;
+}
+
+static struct zipfile *
+find_file (zip *z, const char *name)
+{
+ struct zipfile *zfile;
+
+ zfile = z->files;
+ while (zfile) {
+ if (strcmp (zfile->name, name) == 0) return zfile;
+ zfile = zfile->next;
+ }
+ return NULL;
+}
+
+static int
+seek_file (zip *z, struct zipfile *zfile)
+{
+ unsigned char buf[30];
+
+ fseek (z->f, zfile->pos + z->head_size, SEEK_SET);
+ if (fread (buf, 30, 1, z->f) != 1) return ZIP_EREAD;
+ if (get_long (buf) != 0x04034b50) return ZIP_BADZIP;
+ fseek (z->f, get_word (buf + 26) + get_word (buf + 28), SEEK_CUR);
+ return ZIP_OK;
+}
+
+iks *
+zip_load_xml (zip *z, const char *name, int *err)
+{
+ iksparser *prs;
+ char *real_buf;
+ iks *x;
+ struct zipfile *zfile;
+
+ *err = ZIP_OK;
+
+ zfile = find_file (z, name);
+ if (!zfile) {
+ *err = ZIP_NOFILE;
+ return NULL;
+ }
+
+ seek_file (z, zfile);
+
+ real_buf = malloc (zfile->real_size + 1);
+ if (zfile->zip_size < zfile->real_size) {
+ char *zip_buf;
+ z_stream zs;
+ zs.zalloc = NULL;
+ zs.zfree = NULL;
+ zs.opaque = NULL;
+ zip_buf = malloc (zfile->zip_size);
+ fread (zip_buf, zfile->zip_size, 1, z->f);
+ zs.next_in = zip_buf;
+ zs.avail_in = zfile->zip_size;
+ zs.next_out = real_buf;
+ zs.avail_out = zfile->real_size;
+ inflateInit2 (&zs, -MAX_WBITS);
+ inflate (&zs, Z_FINISH);
+ inflateEnd (&zs);
+ free (zip_buf);
+ } else {
+ fread (real_buf, zfile->real_size, 1, z->f);
+ }
+
+ real_buf[zfile->real_size] = '\0';
+ prs = iks_dom_new (&x);
+ iks_parse (prs, real_buf, zfile->real_size, 1);
+ iks_parser_delete (prs);
+ free (real_buf);
+ return x;
+}
+
+unsigned long zip_get_size (zip *z, const char *name)
+{
+ struct zipfile *zf;
+
+ zf = find_file (z, name);
+ if (!zf) return 0;
+ return zf->real_size;
+}
+
+int zip_load (zip *z, const char *name, char *buf)
+{
+ struct zipfile *zfile;
+
+ zfile = find_file (z, name);
+ if (!zfile) return ZIP_NOFILE;
+
+ seek_file (z, zfile);
+
+ if (zfile->zip_size < zfile->real_size) {
+ char *zip_buf;
+ z_stream zs;
+ zs.zalloc = NULL;
+ zs.zfree = NULL;
+ zs.opaque = NULL;
+ zip_buf = malloc (zfile->zip_size);
+ fread (zip_buf, zfile->zip_size, 1, z->f);
+ zs.next_in = zip_buf;
+ zs.avail_in = zfile->zip_size;
+ zs.next_out = buf;
+ zs.avail_out = zfile->real_size;
+ inflateInit2 (&zs, -MAX_WBITS);
+ inflate (&zs, Z_FINISH);
+ inflateEnd (&zs);
+ free (zip_buf);
+ } else {
+ fread (buf, zfile->real_size, 1, z->f);
+ }
+
+ return ZIP_OK;
+}
diff --git a/backend/impress/zip.h b/backend/impress/zip.h
new file mode 100644
index 00000000..23ff3631
--- /dev/null
+++ b/backend/impress/zip.h
@@ -0,0 +1,18 @@
+/* imposter (OO.org Impress viewer)
+** Copyright (C) 2003-2005 Gurer Ozen
+** This code is free software; you can redistribute it and/or
+** modify it under the terms of GNU General Public License.
+*/
+
+struct zip_struct;
+typedef struct zip_struct zip;
+
+char *zip_error (int err);
+
+zip *zip_open (const char *fname, int *err);
+void zip_close (zip *z);
+
+iks *zip_load_xml (zip *z, const char *name, int *err);
+
+unsigned long zip_get_size (zip *z, const char *name);
+int zip_load (zip *z, const char *name, char *buf);