]> www.fi.muni.cz Git - evince.git/commitdiff
New backend to support impress slides. Fixes bug #30867.
authorBastien Nocera <hadess@hadess.net>
Mon, 10 Jul 2006 21:04:30 +0000 (21:04 +0000)
committerNickolay V. Shmyrev <nshmyrev@src.gnome.org>
Mon, 10 Jul 2006 21:04:30 +0000 (21:04 +0000)
2006-07-11  Bastien Nocera <hadess@hadess.net>

* Makefile.am:
* backend/Makefile.am:
* backend/ev-document-factory.c: (ev_document_factory_add_filters):
* backend/ev-document-factory.h:
* configure.ac:
* impress/.cvsignore:
* impress/Makefile.am:
* impress/common.h:
* impress/document.c: (_imp_load_xml), (imp_open), (imp_nr_pages),
(imp_get_page), (imp_next_page), (imp_prev_page),
(imp_get_page_no), (imp_get_page_name), (imp_get_xml), (imp_close):
* impress/f_oasis.c: (render_object), (render_page),
(get_geometry), (_imp_oasis_load):
* impress/f_oo13.c: (render_object), (render_page), (get_geometry),
(_imp_oo13_load):
* impress/iksemel.c: (iks_malloc), (iks_free), (iks_set_mem_funcs),
(iks_strdup), (iks_strcat), (iks_strcmp), (iks_strcasecmp),
(iks_strncmp), (iks_strncasecmp), (iks_strlen), (iks_escape),
(iks_unescape), (find_space), (iks_stack_new), (iks_stack_alloc),
(iks_stack_strdup), (iks_stack_strcat), (iks_stack_stat),
(iks_stack_delete), (iks_sax_new), (iks_sax_extend),
(iks_parser_stack), (iks_user_data), (iks_nr_bytes),
(iks_nr_lines), (stack_init), (stack_expand), (sax_core),
(iks_parse), (iks_parser_reset), (iks_parser_delete), (iks_new),
(iks_new_within), (iks_insert), (iks_insert_cdata),
(iks_insert_attrib), (iks_insert_node), (iks_hide), (iks_delete),
(iks_next), (iks_next_tag), (iks_prev), (iks_prev_tag),
(iks_parent), (iks_root), (iks_child), (iks_first_tag),
(iks_attrib), (iks_find), (iks_find_cdata), (iks_find_attrib),
(iks_find_with_attrib), (iks_stack), (iks_type), (iks_name),
(iks_cdata), (iks_cdata_size), (iks_has_children),
(iks_has_attribs), (escape_size), (my_strcat), (escape),
(iks_string), (iks_copy_within), (iks_copy), (tagHook),
(cdataHook), (deleteHook), (iks_dom_new), (iks_set_size_hint),
(iks_tree), (iks_load), (iks_save):
* impress/iksemel.h:
* impress/imposter.h:
* impress/impress-document.c: (G_DEFINE_TYPE_WITH_CODE),
(imp_render_draw_bezier_real), (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_markup),
(imp_render_get_text_size), (imp_render_draw_text),
(impress_document_load), (impress_document_save),
(impress_document_get_n_pages), (impress_document_get_page_size),
(imp_render_get_from_drawable), (impress_document_render_pixbuf),
(impress_document_finalize), (impress_document_class_init),
(impress_document_can_get_text), (impress_document_get_info),
(impress_document_document_iface_init),
(impress_document_thumbnails_get_thumbnail),
(impress_document_thumbnails_get_dimensions),
(impress_document_document_thumbnails_iface_init),
(impress_document_init):
* impress/impress-document.h:
* impress/internal.h:
* impress/r_back.c: (_imp_fill_back):
* impress/r_draw.c: (_imp_draw_rect), (_imp_draw_line_end),
(_imp_draw_image), (_imp_tile_image):
* impress/r_geometry.c: (r_parse_color), (r_get_color), (fg_color),
(r_get_x), (r_get_y), (r_get_angle), (r_get_viewbox), (r_polygon),
(r_polyline):
* impress/r_gradient.c: (poly_rotate), (r_draw_gradient_simple),
(r_draw_gradient_complex), (r_draw_gradient):
* impress/r_style.c: (get_style), (r_get_style), (get_style_x),
(r_get_bullet):
* impress/r_text.c: (add_line), (add_span), (calc_sizes),
(calc_pos), (_imp_draw_layout), (text_span), (text_p), (text_list),
(r_text):
* impress/render.c: (imp_create_context), (imp_context_set_page),
(imp_context_set_step), (imp_render), (imp_delete_context):
* impress/render.h:
* impress/zip.c: (zip_error), (find_cd), (get_long), (get_word),
(list_files), (zip_open), (zip_close), (find_file), (seek_file),
(zip_load_xml), (zip_get_size), (zip_load):
* impress/zip.h:
* shell/ev-utils.c:

New backend to support impress slides. Fixes bug #30867.

29 files changed:
ChangeLog
Makefile.am
backend/Makefile.am
backend/ev-document-factory.c
backend/ev-document-factory.h
configure.ac
impress/.cvsignore [new file with mode: 0644]
impress/Makefile.am [new file with mode: 0644]
impress/common.h [new file with mode: 0644]
impress/document.c [new file with mode: 0644]
impress/f_oasis.c [new file with mode: 0644]
impress/f_oo13.c [new file with mode: 0644]
impress/iksemel.c [new file with mode: 0644]
impress/iksemel.h [new file with mode: 0644]
impress/imposter.h [new file with mode: 0644]
impress/impress-document.c [new file with mode: 0644]
impress/impress-document.h [new file with mode: 0644]
impress/internal.h [new file with mode: 0644]
impress/r_back.c [new file with mode: 0644]
impress/r_draw.c [new file with mode: 0644]
impress/r_geometry.c [new file with mode: 0644]
impress/r_gradient.c [new file with mode: 0644]
impress/r_style.c [new file with mode: 0644]
impress/r_text.c [new file with mode: 0644]
impress/render.c [new file with mode: 0644]
impress/render.h [new file with mode: 0644]
impress/zip.c [new file with mode: 0644]
impress/zip.h [new file with mode: 0644]
shell/ev-utils.c

index 09fe6a5ffde933b90eb97d7415e748a1b192883e..33d6f293e797cb382a208bce95fa9fc28db8e7fe 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,87 @@
+2006-07-11  Bastien Nocera <hadess@hadess.net>
+
+       * Makefile.am:
+       * backend/Makefile.am:
+       * backend/ev-document-factory.c: (ev_document_factory_add_filters):
+       * backend/ev-document-factory.h:
+       * configure.ac:
+       * impress/.cvsignore:
+       * impress/Makefile.am:
+       * impress/common.h:
+       * impress/document.c: (_imp_load_xml), (imp_open), (imp_nr_pages),
+       (imp_get_page), (imp_next_page), (imp_prev_page),
+       (imp_get_page_no), (imp_get_page_name), (imp_get_xml), (imp_close):
+       * impress/f_oasis.c: (render_object), (render_page),
+       (get_geometry), (_imp_oasis_load):
+       * impress/f_oo13.c: (render_object), (render_page), (get_geometry),
+       (_imp_oo13_load):
+       * impress/iksemel.c: (iks_malloc), (iks_free), (iks_set_mem_funcs),
+       (iks_strdup), (iks_strcat), (iks_strcmp), (iks_strcasecmp),
+       (iks_strncmp), (iks_strncasecmp), (iks_strlen), (iks_escape),
+       (iks_unescape), (find_space), (iks_stack_new), (iks_stack_alloc),
+       (iks_stack_strdup), (iks_stack_strcat), (iks_stack_stat),
+       (iks_stack_delete), (iks_sax_new), (iks_sax_extend),
+       (iks_parser_stack), (iks_user_data), (iks_nr_bytes),
+       (iks_nr_lines), (stack_init), (stack_expand), (sax_core),
+       (iks_parse), (iks_parser_reset), (iks_parser_delete), (iks_new),
+       (iks_new_within), (iks_insert), (iks_insert_cdata),
+       (iks_insert_attrib), (iks_insert_node), (iks_hide), (iks_delete),
+       (iks_next), (iks_next_tag), (iks_prev), (iks_prev_tag),
+       (iks_parent), (iks_root), (iks_child), (iks_first_tag),
+       (iks_attrib), (iks_find), (iks_find_cdata), (iks_find_attrib),
+       (iks_find_with_attrib), (iks_stack), (iks_type), (iks_name),
+       (iks_cdata), (iks_cdata_size), (iks_has_children),
+       (iks_has_attribs), (escape_size), (my_strcat), (escape),
+       (iks_string), (iks_copy_within), (iks_copy), (tagHook),
+       (cdataHook), (deleteHook), (iks_dom_new), (iks_set_size_hint),
+       (iks_tree), (iks_load), (iks_save):
+       * impress/iksemel.h:
+       * impress/imposter.h:
+       * impress/impress-document.c: (G_DEFINE_TYPE_WITH_CODE),
+       (imp_render_draw_bezier_real), (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_markup),
+       (imp_render_get_text_size), (imp_render_draw_text),
+       (impress_document_load), (impress_document_save),
+       (impress_document_get_n_pages), (impress_document_get_page_size),
+       (imp_render_get_from_drawable), (impress_document_render_pixbuf),
+       (impress_document_finalize), (impress_document_class_init),
+       (impress_document_can_get_text), (impress_document_get_info),
+       (impress_document_document_iface_init),
+       (impress_document_thumbnails_get_thumbnail),
+       (impress_document_thumbnails_get_dimensions),
+       (impress_document_document_thumbnails_iface_init),
+       (impress_document_init):
+       * impress/impress-document.h:
+       * impress/internal.h:
+       * impress/r_back.c: (_imp_fill_back):
+       * impress/r_draw.c: (_imp_draw_rect), (_imp_draw_line_end),
+       (_imp_draw_image), (_imp_tile_image):
+       * impress/r_geometry.c: (r_parse_color), (r_get_color), (fg_color),
+       (r_get_x), (r_get_y), (r_get_angle), (r_get_viewbox), (r_polygon),
+       (r_polyline):
+       * impress/r_gradient.c: (poly_rotate), (r_draw_gradient_simple),
+       (r_draw_gradient_complex), (r_draw_gradient):
+       * impress/r_style.c: (get_style), (r_get_style), (get_style_x),
+       (r_get_bullet):
+       * impress/r_text.c: (add_line), (add_span), (calc_sizes),
+       (calc_pos), (_imp_draw_layout), (text_span), (text_p), (text_list),
+       (r_text):
+       * impress/render.c: (imp_create_context), (imp_context_set_page),
+       (imp_context_set_step), (imp_render), (imp_delete_context):
+       * impress/render.h:
+       * impress/zip.c: (zip_error), (find_cd), (get_long), (get_word),
+       (list_files), (zip_open), (zip_close), (find_file), (seek_file),
+       (zip_load_xml), (zip_get_size), (zip_load):
+       * impress/zip.h:
+       * shell/ev-utils.c:
+       
+       New backend to support impress slides. Fixes bug #30867.
+
 2006-07-10  Ghee Teo  <ghee.teo@sun.com>
 
        * shell/ev-utils.c: (using_postscript_printer):
@@ -15,7 +99,7 @@
        because a password is required, reload the existing
        instance instead of creating a new one.
 
-2006-06-01  Nickolay V. Shmyrev  <<nshmyrev@yandex.ru>>
+2006-06-01  Nickolay V. Shmyrev  <nshmyrev@yandex.ru>
 
        * shell/main.c: (main): Call gdk_threads_init. Thus
        we'll avoid errors in auth dialog. Fix for the bug
        * configure.ac: 
 
        Depend on poppler 0.5.2
-       
+
 2006-05-22  Nickolay V. Shmyrev  <nshmyrev@yandex.ru>
 
        * shell/ev-jobs.c: (ev_job_render_run):
index de5ad3e78595345947e0e146eeb730fa438d4423..5c04b74f11981c11b5cce539d20f05a04c80e436 100644 (file)
@@ -28,6 +28,10 @@ if ENABLE_COMICS
      SUBDIRS += comics
 endif
 
+if ENABLE_IMPRESS
+     SUBDIRS += impress
+endif
+
 SUBDIRS += backend
 
 # Library
index db21e4c5c60f7db7f7a2f3a778730787d1f7c365..f92c607adfa091b33ce6fc052facaab64ecea192 100644 (file)
@@ -7,6 +7,7 @@ INCLUDES=                                       \
        -I$(top_srcdir)/ps                      \
        -I$(top_srcdir)/djvu                    \
        -I$(top_srcdir)/dvi                     \
+       -I$(top_srcdir)/impress                 \
        -I$(top_srcdir)/comics                  \
        $(BACKEND_CFLAGS)                       \
        $(WARN_CFLAGS)                          \
@@ -83,6 +84,11 @@ libevbackend_la_LIBADD +=                    \
        $(top_builddir)/comics/libcomicsdocument.la
 endif
 
+if ENABLE_IMPRESS
+libevbackend_la_LIBADD +=                      \
+       $(top_builddir)/impress/libimpressdocument.la
+endif
+
 BUILT_SOURCES=                         \
        ev-backend-marshalers.h         \
        ev-backend-marshalers.c
index e3f384f9b864a0b121289e672a0cf3b9e87ccfc1..23364a2db1f5cdddc1a980a8104fba09bf1ad06b 100644 (file)
@@ -28,6 +28,8 @@
 #include "ev-poppler.h"
 #include "pixbuf-document.h"
 #include "tiff-document.h"
+#include "impress-document.h"
+
 #ifdef ENABLE_PS
 #include "ps-document.h"
 #endif
@@ -67,6 +69,11 @@ const EvDocumentType document_types[] = {
        {"image/x-eps",                EV_BACKEND_PS,   ps_document_get_type},
 #endif
 
+#ifdef ENABLE_IMPRESS
+       /* Impress slides: */
+       {"application/vnd.sun.xml.impress", EV_BACKEND_IMPRESS, impress_document_get_type},
+#endif
+
 #ifdef ENABLE_TIFF
        /* Tiff: */
        {"image/tiff",                 EV_BACKEND_TIFF, tiff_document_get_type},
@@ -395,6 +402,16 @@ ev_document_factory_add_filters (GtkWidget *chooser, EvDocument *document)
        }
 #endif 
 
+#ifdef ENABLE_IMPRESS
+       if (document == NULL || backend == EV_BACKEND_IMPRESS) {
+               default_filter = filter = gtk_file_filter_new ();
+               gtk_file_filter_set_name (filter, _("Impress Slides"));
+               mime_types = ev_document_factory_get_mime_types (EV_BACKEND_IMPRESS);
+               file_filter_add_mime_list_and_free (filter, mime_types);
+               gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (chooser), filter);
+       }
+#endif 
+
        filter = gtk_file_filter_new ();
        gtk_file_filter_set_name (filter, _("All Files"));
        gtk_file_filter_add_pattern (filter, "*");
index 215f50bc39369f29e4f60835822530163c71175a..886be691b002567367e0773105a4582d29c360ab 100644 (file)
@@ -33,7 +33,8 @@ typedef enum {
        EV_BACKEND_PIXBUF,
        EV_BACKEND_DJVU,
        EV_BACKEND_DVI,
-       EV_BACKEND_COMICS
+       EV_BACKEND_COMICS,
+       EV_BACKEND_IMPRESS
 } EvBackend;
 
 EvDocument* ev_document_factory_get_document (const char *uri, GError **error);
index 3d404d810795d8d052cde809a900cc55a13f132a..3081339556416a0cd2e1ac355d73248f017da44c 100644 (file)
@@ -292,6 +292,17 @@ AM_CONDITIONAL(ENABLE_COMICS, test x$enable_comics = xyes)
 
 dnl ================== End of comic book checks ============================================
 
+dnl ================== comic book checks ===================================================
+
+AC_ARG_ENABLE(impress,
+       [AC_HELP_STRING([--enable-impress], [Compile with support for impress presentations])],enable_impress="$enableval",enable_impress=no)
+if test "x$enable_impress" = "xyes"; then
+       AC_DEFINE([ENABLE_IMPRESS], [1], [Enable support for impress.])
+fi 
+AM_CONDITIONAL(ENABLE_IMPRESS, test x$enable_impress = xyes)
+
+dnl ================== End of comic book checks ============================================
+
 dnl =================== Mime types list ====================================================
 
 EVINCE_MIME_TYPES="application/pdf"
@@ -314,6 +325,9 @@ fi
 if test "x$enable_pixbuf" = "xyes"; then
        EVINCE_MIME_TYPES="$EVINCE_MIME_TYPES;image/*"
 fi
+if test "x$enable_impress" = "xyes"; then
+       EVINCE_MIME_TYPES="$EVINCE_MIME_TYPES;application/vnd.sun.xml.impress"
+fi
 AC_SUBST(EVINCE_MIME_TYPES)
 
 AC_CONFIG_FILES([
@@ -332,6 +346,7 @@ ps/Makefile
 djvu/Makefile
 dvi/Makefile
 dvi/mdvi-lib/Makefile
+impress/Makefile
 comics/Makefile
 po/Makefile.in
 backend/Makefile
@@ -355,4 +370,5 @@ Configure summary:
        DVI Backend........:  $enable_dvi
        Pixbuf Backend.....:  $enable_pixbuf
        Comics Backend.....:  $enable_comics
+       Impress Backend....:  $enable_impress
 "
diff --git a/impress/.cvsignore b/impress/.cvsignore
new file mode 100644 (file)
index 0000000..3dda729
--- /dev/null
@@ -0,0 +1,2 @@
+Makefile.in
+Makefile
diff --git a/impress/Makefile.am b/impress/Makefile.am
new file mode 100644 (file)
index 0000000..3740855
--- /dev/null
@@ -0,0 +1,38 @@
+INCLUDES =                                                     \
+       -I$(top_srcdir)                                         \
+       -I$(top_srcdir)/backend                                 \
+       $(SHELL_CFLAGS)                                         \
+       -DDATADIR=\""$(datadir)"\"
+
+noinst_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
+
diff --git a/impress/common.h b/impress/common.h
new file mode 100644 (file)
index 0000000..73e4ac1
--- /dev/null
@@ -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/impress/document.c b/impress/document.c
new file mode 100644 (file)
index 0000000..8ecbfae
--- /dev/null
@@ -0,0 +1,139 @@
+/* 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 "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/impress/f_oasis.c b/impress/f_oasis.c
new file mode 100644 (file)
index 0000000..193cef8
--- /dev/null
@@ -0,0 +1,169 @@
+/* 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 "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/impress/f_oo13.c b/impress/f_oo13.c
new file mode 100644 (file)
index 0000000..ce84132
--- /dev/null
@@ -0,0 +1,180 @@
+/* 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 "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/impress/iksemel.c b/impress/iksemel.c
new file mode 100644 (file)
index 0000000..6d24d43
--- /dev/null
@@ -0,0 +1,1881 @@
+/* iksemel (XML parser for Jabber)
+** Copyright (C) 2000-2003 Gurer Ozen <madcat@e-kolay.net>
+** 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 <madcat@e-kolay.net>
+** This code is free software; you can redistribute it and/or
+** modify it under the terms of GNU Lesser General Public License.
+*/
+
+#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 <madcat@e-kolay.net>
+** 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 <madcat@e-kolay.net>
+** 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);
+                                               if (!tmp) return IKS_NOMEM;
+                                               memset (tmp, 0, sizeof(char *) * 2 * prs->attmax);
+                                               memcpy (tmp, prs->atts, sizeof(char *) * prs->attcur);
+                                               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 <madcat@e-kolay.net>
+** 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 <madcat@e-kolay.net>
+** 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/impress/iksemel.h b/impress/iksemel.h
new file mode 100644 (file)
index 0000000..66c87d6
--- /dev/null
@@ -0,0 +1,402 @@
+/* iksemel (XML parser for Jabber)
+** Copyright (C) 2000-2004 Gurer Ozen <madcat@e-kolay.net>
+** 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/impress/imposter.h b/impress/imposter.h
new file mode 100644 (file)
index 0000000..50c87f2
--- /dev/null
@@ -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/impress/impress-document.c b/impress/impress-document.c
new file mode 100644 (file)
index 0000000..3ea993d
--- /dev/null
@@ -0,0 +1,521 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8; c-indent-level: 8 -*- */
+/*
+ * Copyright (C) 2005, Jonathan Blandford <jrb@gnome.org>
+ * Copyright (C) 2005, Bastien Nocera <hadess@hadess.net>
+ *
+ * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <gtk/gtk.h>
+#include <string.h>
+#include "imposter.h"
+#include "impress-document.h"
+#include "ev-document-thumbnails.h"
+#include "ev-document-misc.h"
+
+struct _ImpressDocumentClass
+{
+  GObjectClass parent_class;
+};
+
+struct _ImpressDocument
+{
+  GObject 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_iface_init (EvDocumentIface *iface);
+static void impress_document_document_thumbnails_iface_init (EvDocumentThumbnailsIface *iface);
+
+G_DEFINE_TYPE_WITH_CODE (ImpressDocument, impress_document, G_TYPE_OBJECT,
+                         { G_IMPLEMENT_INTERFACE (EV_TYPE_DOCUMENT,
+                                                 impress_document_document_iface_init);
+                          G_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);
+
+  gdk_drawable_get_size(impress_document->pixmap, w, h);
+}
+
+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)
+    {
+      //FIXME
+      //g_error_set ();
+      return FALSE;
+    }
+
+  imp = imp_open (filename, &err);
+
+  if (!imp)
+    {
+      //FIXME translate the err, set error
+      g_free (filename);
+      return FALSE;
+    }
+  impress_document->imp = imp;
+
+  return TRUE;
+}
+
+static gboolean
+impress_document_save (EvDocument  *document,
+                     const char  *uri,
+                     GError     **error)
+{
+       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,
+                            int           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);
+
+  imp_context_set_page (impress_document->ctx, page);
+  imp_render (impress_document->ctx, impress_document);
+
+  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 *scaled_pixbuf;
+
+  g_return_val_if_fail (IMPRESS_IS_DOCUMENT (document), 0);
+  g_return_val_if_fail (impress_document->imp != NULL, 0);
+
+  impress_document->pagenum = rc->page;
+
+  g_mutex_lock (impress_document->mutex);
+  impress_document->cond = g_cond_new ();
+
+  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);
+  g_mutex_unlock (impress_document->mutex);
+
+  scaled_pixbuf = gdk_pixbuf_scale_simple (impress_document->pixbuf,
+                                          PAGE_WIDTH * rc->scale,
+                                          PAGE_HEIGHT * rc->scale,
+                                          GDK_INTERP_BILINEAR);
+  gdk_pixbuf_unref (impress_document->pixbuf);
+  impress_document->pixbuf = NULL;
+
+  return scaled_pixbuf;
+}
+
+static void
+impress_document_finalize (GObject *object)
+{
+  ImpressDocument *impress_document = IMPRESS_DOCUMENT (object);
+
+  g_mutex_free (impress_document->mutex);
+
+  imp_close (impress_document->imp);
+  imp_delete_context (impress_document->ctx);
+  g_free (impress_document->pango_ctx);
+  g_object_unref (G_OBJECT (impress_document->pixmap));
+  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);
+
+  gobject_class->finalize = impress_document_finalize;
+}
+
+static gboolean
+impress_document_can_get_text (EvDocument *document)
+{
+  return FALSE;
+}
+
+static EvDocumentInfo *
+impress_document_get_info (EvDocument *document)
+{
+  EvDocumentInfo *info;
+
+  info = g_new0 (EvDocumentInfo, 1);
+  info->fields_mask = 0;
+
+  return info;
+}
+
+static void
+impress_document_document_iface_init (EvDocumentIface *iface)
+{
+  iface->load = impress_document_load;
+  iface->save = impress_document_save;
+  iface->can_get_text = impress_document_can_get_text;
+  iface->get_n_pages = impress_document_get_n_pages;
+  iface->get_page_size = impress_document_get_page_size;
+  iface->render_pixbuf = impress_document_render_pixbuf;
+  iface->get_info = impress_document_get_info;
+}
+
+static GdkPixbuf *
+impress_document_thumbnails_get_thumbnail (EvDocumentThumbnails *document,
+                                       gint                  page,
+                                       gint                  rotation,
+                                       gint                  size,
+                                       gboolean              border)
+{
+  GdkPixbuf *pixbuf = NULL;
+  gdouble w, h;
+  EvRenderContext *rc;
+
+  impress_document_get_page_size (EV_DOCUMENT (document),
+                              page,
+                              &w, &h);
+
+  rc = ev_render_context_new (rotation, page, size/w);
+  pixbuf = impress_document_render_pixbuf (EV_DOCUMENT (document), rc);
+  g_object_unref (G_OBJECT (rc));
+
+  if (border)
+    {
+      GdkPixbuf *tmp_pixbuf = pixbuf;
+      pixbuf = ev_document_misc_get_thumbnail_frame (-1, -1, 0, tmp_pixbuf);
+      g_object_unref (tmp_pixbuf);
+    }
+
+  return pixbuf;
+}
+
+static void
+impress_document_thumbnails_get_dimensions (EvDocumentThumbnails *document,
+                                        gint                  page,
+                                        gint                  suggested_width,
+                                        gint                 *width,
+                                        gint                 *height)
+{
+  gdouble page_ratio;
+  gdouble w, h;
+
+  impress_document_get_page_size (EV_DOCUMENT (document),
+                              page,
+                              &w, &h);
+  g_return_if_fail (w > 0);
+  page_ratio = h/w;
+  *width = suggested_width;
+  *height = (gint) (suggested_width * page_ratio);
+}
+
+static void
+impress_document_document_thumbnails_iface_init (EvDocumentThumbnailsIface *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 ();
+}
+
+/*
+ * vim: sw=2 ts=8 cindent noai bs=2
+ */
diff --git a/impress/impress-document.h b/impress/impress-document.h
new file mode 100644 (file)
index 0000000..7698e98
--- /dev/null
@@ -0,0 +1,38 @@
+
+/* pdfdocument.h: Implementation of EvDocument for impresss
+ * Copyright (C) 2005, Jonathan Blandford <jrb@gnome.org>
+ *
+ * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, 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;
+
+ImpressDocument *impress_document_new      (void);
+GType         impress_document_get_type (void) G_GNUC_CONST;
+     
+G_END_DECLS
+
+#endif /* __IMPRESS_DOCUMENT_H__ */
diff --git a/impress/internal.h b/impress/internal.h
new file mode 100644 (file)
index 0000000..eb99c3e
--- /dev/null
@@ -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/impress/r_back.c b/impress/r_back.c
new file mode 100644 (file)
index 0000000..84681da
--- /dev/null
@@ -0,0 +1,45 @@
+/* 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 "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) 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/impress/r_draw.c b/impress/r_draw.c
new file mode 100644 (file)
index 0000000..746afbd
--- /dev/null
@@ -0,0 +1,119 @@
+/* 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 "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/impress/r_geometry.c b/impress/r_geometry.c
new file mode 100644 (file)
index 0000000..6662de6
--- /dev/null
@@ -0,0 +1,207 @@
+/* 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 "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/impress/r_gradient.c b/impress/r_gradient.c
new file mode 100644 (file)
index 0000000..f6b9af2
--- /dev/null
@@ -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 "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);
+
+//             gdk_gc_unref (ctx->gc);
+//             ctx->gc = gc;
+       }
+}
diff --git a/impress/r_style.c b/impress/r_style.c
new file mode 100644 (file)
index 0000000..570c000
--- /dev/null
@@ -0,0 +1,110 @@
+/* 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 "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/impress/r_text.c b/impress/r_text.c
new file mode 100644 (file)
index 0000000..e08fd15
--- /dev/null
@@ -0,0 +1,385 @@
+/* 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 "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/impress/render.c b/impress/render.c
new file mode 100644 (file)
index 0000000..0338600
--- /dev/null
@@ -0,0 +1,53 @@
+/* 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 "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/impress/render.h b/impress/render.h
new file mode 100644 (file)
index 0000000..64c994c
--- /dev/null
@@ -0,0 +1,42 @@
+/* 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 "imposter.h"
+
+#ifndef OO_RENDER_H
+#define OO_RENDER_H
+
+#include <gtk/gtkdrawingarea.h>
+
+#define OO_TYPE_RENDER (oo_render_get_type())
+#define OO_RENDER(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), OO_TYPE_RENDER , OORender))
+#define OO_RENDER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), OO_TYPE_RENDER , OORenderClass))
+
+typedef struct _OORender OORender;
+typedef struct _OORenderClass OORenderClass;
+
+struct _OORender {
+       GtkDrawingArea area;
+       ImpRenderCtx *ctx;
+       ImpPage *page;
+       int step;
+       int step_mode;
+};
+
+struct _OORenderClass {
+       GtkDrawingAreaClass parent_class;
+       void (*page_changed)(OORender *obj);
+};
+
+GType oo_render_get_type(void);
+GtkWidget *oo_render_new(void);
+void oo_render_set_page(OORender *obj, ImpPage *page);
+ImpPage *oo_render_get_page(OORender *obj);
+void oo_render_step(OORender *obj);
+void oo_render_step_mode(OORender *obj, int mode);
+
+
+#endif /* OO_RENDER_H */
diff --git a/impress/zip.c b/impress/zip.c
new file mode 100644 (file)
index 0000000..4b179b5
--- /dev/null
@@ -0,0 +1,346 @@
+/* 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 "common.h"
+#include "zip.h"
+#include <zlib.h>
+#define _(x) x
+
+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/impress/zip.h b/impress/zip.h
new file mode 100644 (file)
index 0000000..23ff363
--- /dev/null
@@ -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);
index ba560d53f2effc42fda4f71c90640150f3cb768c..38281f6d0f33e4b0ef8adb875e4489641df44d55 100644 (file)
@@ -22,6 +22,8 @@
 
 #include "ev-utils.h"
 #include "ev-file-helpers.h"
+
+#include <string.h>
 #include <math.h>
 
 #define PRINT_CONFIG_FILENAME  "ev-print-config.xml"