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