summaryrefslogtreecommitdiffstats
path: root/filters/chalk/xcf
diff options
context:
space:
mode:
authortpearson <tpearson@283d02a7-25f6-0310-bc7c-ecb5cbfe19da>2011-06-26 00:41:16 +0000
committertpearson <tpearson@283d02a7-25f6-0310-bc7c-ecb5cbfe19da>2011-06-26 00:41:16 +0000
commit698569f8428ca088f764d704034a1330517b98c0 (patch)
treebf45be6946ebbbee9cce5a5bcf838f4c952d87e6 /filters/chalk/xcf
parent2785103a6bd4de55bd26d79e34d0fdd4b329a73a (diff)
downloadkoffice-698569f8428ca088f764d704034a1330517b98c0.tar.gz
koffice-698569f8428ca088f764d704034a1330517b98c0.zip
Finish rebranding of Krita as Chalk
git-svn-id: svn://anonsvn.kde.org/home/kde/branches/trinity/applications/koffice@1238363 283d02a7-25f6-0310-bc7c-ecb5cbfe19da
Diffstat (limited to 'filters/chalk/xcf')
-rw-r--r--filters/chalk/xcf/Makefile.am42
-rw-r--r--filters/chalk/xcf/chalk_xcf_export.desktop52
-rw-r--r--filters/chalk/xcf/chalk_xcf_import.desktop52
-rw-r--r--filters/chalk/xcf/xcf/README2
-rw-r--r--filters/chalk/xcf/xcf/xcf-load.cc1740
-rw-r--r--filters/chalk/xcf/xcf/xcf-load.h27
-rw-r--r--filters/chalk/xcf/xcf/xcf-private.h95
-rw-r--r--filters/chalk/xcf/xcf/xcf-read.cc118
-rw-r--r--filters/chalk/xcf/xcf/xcf-read.h37
-rw-r--r--filters/chalk/xcf/xcf/xcf-save.cc1826
-rw-r--r--filters/chalk/xcf/xcf/xcf-save.h29
-rw-r--r--filters/chalk/xcf/xcf/xcf-seek.cc79
-rw-r--r--filters/chalk/xcf/xcf/xcf-seek.h30
-rw-r--r--filters/chalk/xcf/xcf/xcf-write.cc104
-rw-r--r--filters/chalk/xcf/xcf/xcf-write.h39
-rw-r--r--filters/chalk/xcf/xcfexport.cpp78
-rw-r--r--filters/chalk/xcf/xcfexport.h37
-rw-r--r--filters/chalk/xcf/xcfimport.cpp99
-rw-r--r--filters/chalk/xcf/xcfimport.h37
19 files changed, 4523 insertions, 0 deletions
diff --git a/filters/chalk/xcf/Makefile.am b/filters/chalk/xcf/Makefile.am
new file mode 100644
index 00000000..88822a23
--- /dev/null
+++ b/filters/chalk/xcf/Makefile.am
@@ -0,0 +1,42 @@
+kde_module_LTLIBRARIES = libchalkxcfimport.la libchalkxcfexport.la
+
+libchalkxcfexport_la_LDFLAGS = $(KDE_PLUGIN) $(LIBMAGICK_LDFLAGS) $(KDE_RPATH) $(LIBMAGICK_RPATH) $(all_libraries) -module -avoid-version -no-undefined -lkdecore -lkdeui $(LIB_QT) -lkjs -lkdefx -lkio -lkparts \
+ -L../../../lib/kofficecore/.libs/ -lkofficecore -llcms \
+ -L../../../lib/kofficeui/.libs/ -lkofficeui -L../../../lib/store/.libs/ -lkstore -L../../../chalk/core/.libs/ -lchalkimage -L../../../chalk/ui/.libs/ -lchalkui -L../../../chalk/chalkcolor/.libs/ -lchalkcolor
+libchalkxcfexport_la_LIBADD = \
+ $(KOFFICE_LIBS) \
+ $(LIBMAGICK_LIBS) \
+ $(top_builddir)/chalk/libchalkcommon.la
+
+libchalkxcfimport_la_LDFLAGS = $(KDE_PLUGIN) $(LIBMAGICK_LDFLAGS) $(KDE_RPATH) $(LIBMAGICK_RPATH) $(all_libraries) -module -avoid-version -no-undefined -lkdecore -lkdeui $(LIB_QT) -lkjs -lkdefx -lkio -lkparts \
+ -L../../../lib/kofficecore/.libs/ -lkofficecore -llcms \
+ -L../../../lib/kofficeui/.libs/ -lkofficeui -L../../../lib/store/.libs/ -lkstore -L../../../chalk/core/.libs/ -lchalkimage -L../../../chalk/ui/.libs/ -lchalkui -L../../../chalk/chalkcolor/.libs/ -lchalkcolor
+libchalkxcfimport_la_LIBADD = \
+ $(KOFFICE_LIBS) \
+ $(LIBMAGICK_LIBS) \
+ $(top_builddir)/chalk/libchalkcommon.la
+
+INCLUDES= \
+ -I$(srcdir) \
+ $(KOFFICE_INCLUDES) \
+ -I$(top_srcdir)/chalk \
+ -I$(top_srcdir)/chalk/core \
+ -I$(top_srcdir)/chalk/sdk \
+ -I$(top_srcdir)/chalk/core/tiles \
+ -I$(top_srcdir)/chalk/chalkcolor \
+ -I$(top_srcdir)/chalk/ui \
+ $(KOFFICE_INCLUDES) -I$(interfacedir) \
+ $(KOPAINTER_INCLUDES) $(LIBMAGICK_CPPFLAGS) \
+ $(all_includes)
+
+service_DATA = chalk_xcf_import.desktop chalk_xcf_export.desktop
+servicedir = $(kde_servicesdir)
+
+libchalkxcfimport_la_SOURCES = xcfimport.cpp
+libchalkxcfexport_la_SOURCES = xcfexport.cpp
+
+METASOURCES = AUTO
+
+SUBDIRS=xcf
+
+KDE_CXXFLAGS = $(USE_EXCEPTIONS)
diff --git a/filters/chalk/xcf/chalk_xcf_export.desktop b/filters/chalk/xcf/chalk_xcf_export.desktop
new file mode 100644
index 00000000..b88afaed
--- /dev/null
+++ b/filters/chalk/xcf/chalk_xcf_export.desktop
@@ -0,0 +1,52 @@
+[Desktop Entry]
+Name=Chalk XCF Export Filter
+Name[bg]=Филтър за експортиране от Chalk в XCF
+Name[br]=Sil ezporzh XCF evit Chalk
+Name[ca]=Filtre d'exportació XCF per a Chalk
+Name[cy]=Hidl Allforio XCF Chalk
+Name[da]=Chalk XCF-eksportfilter
+Name[de]=Chalk XCF-Exportfilter
+Name[el]=Φίλτρο εξαγωγής XCF του Chalk
+Name[eo]=Chalk XCF-importfiltrilo
+Name[es]=Filtro de exportación a XCF de Chalk
+Name[et]=Chalk XCF-i ekspordifilter
+Name[fa]=پالایۀ صادرات Chalk XCF
+Name[fi]=Chalk XCF -vientisuodin
+Name[fr]=Filtre d'exportation XCF de Chalk
+Name[fy]=Chalk XCF Eksportfilter
+Name[ga]=Scagaire Easpórtála XCF Chalk
+Name[gl]=Filtro de Exportación de XCF para Chalk
+Name[he]=Chalk XCF מסנן יצוא
+Name[hr]=Chalk XCF filtar izvoza
+Name[hu]=Chalk XCF exportszűrő
+Name[is]=Chalk XCF útflutningssía
+Name[it]=Filtro di esportazione XCF per Chalk
+Name[ja]=Chalk XCF エクスポートフィルタ
+Name[km]=តម្រង​នាំចេញ XCF សម្រាប់ Chalk
+Name[lt]=Chalk XCF eksportavimo filtras
+Name[lv]=Chalk XCF eksporta filtrs
+Name[nb]=XCF-eksportfilter for Chalk
+Name[nds]=XCF-Exportfilter för Chalk
+Name[ne]=क्रिता XFC निर्यात फिल्टर
+Name[nl]=Chalk XCF Exportfilter
+Name[pl]=Filtr eksportu do formatu XCF dla Chalk
+Name[pt]=Filtro de Exportação de XCF para o Chalk
+Name[pt_BR]=Filtro de Exportação de XCF para o Chalk
+Name[ru]=Фильтр экспорта рисунков Chalk в XCF
+Name[se]=Chalk XCF-olggosfievrridansilli
+Name[sk]=Exportný filter Chalk XCF
+Name[sl]=Izvozni filter XCF za Krito
+Name[sr]=Chalk-ин филтер за извоз у XCF
+Name[sr@Latn]=Chalk-in filter za izvoz u XCF
+Name[sv]=Chalk XCF-exportfilter
+Name[uk]=Фільтр експорту XCF для Chalk
+Name[uz]=Chalk XCF eksport filteri
+Name[uz@cyrillic]=Chalk XCF экспорт филтери
+Name[zh_CN]=Chalk XCF 导出过滤器
+Name[zh_TW]=Chalk XCF 匯出過濾程式
+X-KDE-Export=image/x-xcf-gimp
+ServiceTypes=KOfficeFilter
+Type=Service
+X-KDE-Import=application/x-chalk
+X-KDE-Weight=1
+X-KDE-Library=libchalkxcfexport
diff --git a/filters/chalk/xcf/chalk_xcf_import.desktop b/filters/chalk/xcf/chalk_xcf_import.desktop
new file mode 100644
index 00000000..b2e68d13
--- /dev/null
+++ b/filters/chalk/xcf/chalk_xcf_import.desktop
@@ -0,0 +1,52 @@
+[Desktop Entry]
+Type=Service
+Name=Chalk XCF Import Filter
+Name[bg]=Филтър за импортиране от XCF в Chalk
+Name[br]=Sil enporzh XCF evit Chalk
+Name[ca]=Filtre d'importació XCF per a Chalk
+Name[cy]=Hidl Mewnforio XCF Chalk
+Name[da]=Chalk XCF-importfilter
+Name[de]=Chalk XCF-Importfilter
+Name[el]=Φίλτρο εισαγωγής XCF του Chalk
+Name[eo]=Chalk XCF-importfiltrilo
+Name[es]=Filtro de importación a XCF de Chalk
+Name[et]=Chalk XCF-i impordifilter
+Name[fa]=پالایۀ واردات Chalk XCF
+Name[fi]=Chalk XCF -tuontisuodin
+Name[fr]=Filtre d'importation XCF de Chalk
+Name[fy]=Chalk XCF Ymportfilter
+Name[ga]=Scagaire Iompórtála XCF Chalk
+Name[gl]=Filtro de Importación de XCF para Chalk
+Name[he]=Chalk XCF מסנן יבוא
+Name[hr]=Chalk XCF filtar uvoza
+Name[hu]=Chalk XCF importszűrő
+Name[is]=Chalk XCF innflutningssía
+Name[it]=Filtro di importazione XCF per Chalk
+Name[ja]=Chalk XCF インポートフィルタ
+Name[km]=តម្រង​នាំចូល XCF សម្រាប់ Chalk
+Name[lt]=Chalk XCF importavimo filtras
+Name[lv]=Chalk XCF importa filtrs
+Name[nb]=XCF-importfilter for Chalk
+Name[nds]=XCF-Importfilter för Chalk
+Name[ne]=क्रिता XCF आयात फिल्टर
+Name[nl]=Chalk XCF Importfilter
+Name[pl]=Filtr importu formatu XCF dla Chalk
+Name[pt]=Filtro de Importação de XCF para o Chalk
+Name[pt_BR]=Filtro de Importação de XCF para o Chalk
+Name[ru]=Фильтр импорта рисунков XCF в Chalk
+Name[se]=Chalk XCF-sisafievrridansilli
+Name[sk]=XCF filter pre import do Chalk
+Name[sl]=Uvozni filter XCF za Krito
+Name[sr]=Chalk-ин филтер за увоз из XCF-а
+Name[sr@Latn]=Chalk-in filter za uvoz iz XCF-a
+Name[sv]=Chalk XCF-importfilter
+Name[uk]=Фільтр імпорту XCF для Chalk
+Name[uz]=Chalk XCF import filteri
+Name[uz@cyrillic]=Chalk XCF импорт филтери
+Name[zh_CN]=Chalk XCF 导入过滤器
+Name[zh_TW]=Chalk XCF 匯入過濾程式
+X-KDE-Export=application/x-chalk
+X-KDE-Import=image/x-xcf-gimp
+X-KDE-Weight=1
+X-KDE-Library=libchalkxcfimport
+ServiceTypes=KOfficeFilter
diff --git a/filters/chalk/xcf/xcf/README b/filters/chalk/xcf/xcf/README
new file mode 100644
index 00000000..567d2ab1
--- /dev/null
+++ b/filters/chalk/xcf/xcf/README
@@ -0,0 +1,2 @@
+Note: this is source copy of 6 feb. 2006; when updated, use a diff from the gimp cvs
+to check for changes in their file format.
diff --git a/filters/chalk/xcf/xcf/xcf-load.cc b/filters/chalk/xcf/xcf/xcf-load.cc
new file mode 100644
index 00000000..07b6a145
--- /dev/null
+++ b/filters/chalk/xcf/xcf/xcf-load.cc
@@ -0,0 +1,1740 @@
+/* The GIMP -- an image manipulation program
+ * Copyright (C) 1995 Spencer Kimball and Peter Mattis
+ *
+ * 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 of the License, 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 <stdio.h>
+#include <string.h> /* strcmp, memcmp */
+
+//#include <glib-object.h>
+
+//#include "libgimpbase/gimpbase.h"
+//#include "libgimpcolor/gimpcolor.h"
+
+//#include "core/core-types.h"
+
+//#include "base/tile.h"
+//#include "base/tile-manager.h"
+//#include "base/tile-manager-private.h"
+
+//#include "config/gimpcoreconfig.h"
+
+//#include "core/gimp.h"
+//#include "core/gimpcontainer.h"
+//#include "core/gimpdrawable.h"
+//#include "core/gimpgrid.h"
+//#include "core/gimpimage.h"
+//#include "core/gimpimage-grid.h"
+//#include "core/gimpimage-guides.h"
+//#include "core/gimplayer.h"
+//#include "core/gimplayer-floating-sel.h"
+//#include "core/gimplayertqmask.h"
+//#include "core/gimpparasitelist.h"
+//#include "core/gimpselection.h"
+//#include "core/gimptemplate.h"
+//#include "core/gimpunit.h"
+
+//#include "text/gimptextlayer.h"
+//#include "text/gimptextlayer-xcf.h"
+
+//#include "vectors/gimpanchor.h"
+//#include "vectors/gimpstroke.h"
+//#include "vectors/gimpbezierstroke.h"
+//#include "vectors/gimpvectors.h"
+//#include "vectors/gimpvectors-compat.h"
+
+#include "xcf-private.h"
+#include "xcf-load.h"
+#include "xcf-read.h"
+#include "xcf-seek.h"
+
+//#include "gimp-intl.h"
+
+static bool xcf_load_image_props (XcfInfo * info, KisImage * gimage);
+static bool xcf_load_layer_props (XcfInfo * info,
+ KisImage * gimage,
+ KisLayer * layer,
+ bool * apply_tqmask,
+ bool * edit_tqmask,
+ bool * show_tqmask,
+ TQ_INT32 * text_layer_flags);
+static bool xcf_load_channel_props (XcfInfo * info,
+ KisImage * gimage,
+ GimpChannel ** channel);
+static bool xcf_load_prop (XcfInfo * info,
+ PropType * prop_type, TQ_INT32 * prop_size);
+static KisLayer *xcf_load_layer (XcfInfo * info, KisImage * gimage);
+//static GimpChannel * xcf_load_channel (XcfInfo *info,
+// KisImage *gimage);
+//static GimpLayerMask * xcf_load_layer_tqmask (XcfInfo *info,
+// KisImage *gimage);
+static bool xcf_load_hierarchy (XcfInfo * info, TileManager * tiles);
+static bool xcf_load_level (XcfInfo * info, TileManager * tiles);
+static bool xcf_load_tile (XcfInfo * info, Tile * tile);
+static bool xcf_load_tile_rle (XcfInfo * info,
+ Tile * tile, TQ_INT32 data_length);
+//static GimpParasite * xcf_load_parasite (XcfInfo *info);
+static bool xcf_load_old_paths (XcfInfo * info, KisImage * gimage);
+static bool xcf_load_old_path (XcfInfo * info, KisImage * gimage);
+static bool xcf_load_vectors (XcfInfo * info, KisImage * gimage);
+static bool xcf_load_vector (XcfInfo * info, KisImage * gimage);
+
+#ifdef SWAP_FROM_FILE
+static bool xcf_swap_func (TQ_INT32 fd,
+ Tile * tile, TQ_INT32 cmd, gpointer user_data);
+#endif
+
+
+KisImage *
+xcf_load_image (XcfInfo * info)
+{
+ KisImage *gimage;
+ KisLayer *layer;
+ //GimpChannel *channel;
+ //KisAnnotation *parasite;
+ TQ_INT32 saved_pos;
+ TQ_INT32 offset;
+ TQ_INT32 width;
+ TQ_INT32 height;
+ TQ_INT32 image_type;
+ TQ_INT32 num_successful_elements = 0;
+
+ /* read in the image width, height and type */
+ info->cp += xcf_read_int32 (info->fp, (TQ_INT32 *) & width, 1);
+ info->cp += xcf_read_int32 (info->fp, (TQ_INT32 *) & height, 1);
+ info->cp += xcf_read_int32 (info->fp, (TQ_INT32 *) & image_type, 1);
+
+ gimage = gimp_create_image (gimp, width, height, image_type, FALSE);
+
+ gimp_image_undo_disable (gimage);
+
+ /* read the image properties */
+ if (!xcf_load_image_props (info, gimage))
+ goto hard_error;
+
+ /* check for a GimpGrid parasite */
+ parasite = gimp_image_parasite_tqfind (GIMP_IMAGE (gimage),
+ gimp_grid_parasite_name ());
+ if (parasite)
+ {
+ GimpGrid *grid = gimp_grid_from_parasite (parasite);
+
+ if (grid)
+ {
+ gimp_parasite_list_remove (GIMP_IMAGE (gimage)->parasites,
+ gimp_parasite_name (parasite));
+
+ gimp_image_set_grid (GIMP_IMAGE (gimage), grid, FALSE);
+ }
+ }
+
+ while (TRUE)
+ {
+ /* read in the offset of the next layer */
+ info->cp += xcf_read_int32 (info->fp, &offset, 1);
+
+ /* if the offset is 0 then we are at the end
+ * of the layer list.
+ */
+ if (offset == 0)
+ break;
+
+ /* save the current position as it is where the
+ * next layer offset is stored.
+ */
+ saved_pos = info->cp;
+
+ /* seek to the layer offset */
+ if (!xcf_seek_pos (info, offset, NULL))
+ goto error;
+
+ /* read in the layer */
+ layer = xcf_load_layer (info, gimage);
+ if (!layer)
+ goto error;
+
+ num_successful_elements++;
+
+ /* add the layer to the image if its not the floating selection */
+ if (layer != info->floating_sel)
+ gimp_image_add_layer (gimage, layer,
+ gimp_container_num_tqchildren (gimage->layers));
+
+ /* restore the saved position so we'll be ready to
+ * read the next offset.
+ */
+ if (!xcf_seek_pos (info, saved_pos, NULL))
+ goto error;
+ }
+
+ while (TRUE)
+ {
+ /* read in the offset of the next channel */
+ info->cp += xcf_read_int32 (info->fp, &offset, 1);
+
+ /* if the offset is 0 then we are at the end
+ * of the channel list.
+ */
+ if (offset == 0)
+ break;
+
+ /* save the current position as it is where the
+ * next channel offset is stored.
+ */
+ saved_pos = info->cp;
+
+ /* seek to the channel offset */
+ if (!xcf_seek_pos (info, offset, NULL))
+ goto error;
+
+ /* read in the layer */
+ channel = xcf_load_channel (info, gimage);
+ if (!channel)
+ goto error;
+
+ num_successful_elements++;
+
+ /* add the channel to the image if its not the selection */
+ if (channel != gimage->selection_tqmask)
+ gimp_image_add_channel (gimage, channel, -1);
+
+ /* restore the saved position so we'll be ready to
+ * read the next offset.
+ */
+ if (!xcf_seek_pos (info, saved_pos, NULL))
+ goto error;
+ }
+
+ if (info->floating_sel && info->floating_sel_drawable)
+ floating_sel_attach (info->floating_sel, info->floating_sel_drawable);
+
+ if (info->active_layer)
+ gimp_image_set_active_layer (gimage, info->active_layer);
+
+ if (info->active_channel)
+ gimp_image_set_active_channel (gimage, info->active_channel);
+
+ gimp_image_set_filename (gimage, info->filename);
+
+ if (info->tattoo_state > 0)
+ gimp_image_set_tattoo_state (gimage, info->tattoo_state);
+
+ gimp_image_undo_enable (gimage);
+
+ return gimage;
+
+error:
+ if (num_successful_elements == 0)
+ goto hard_error;
+
+ g_message ("XCF: This file is corrupt! I have loaded as much\n"
+ "of it as I can, but it is incomplete.");
+
+ gimp_image_undo_enable (gimage);
+
+ return gimage;
+
+hard_error:
+ g_message ("XCF: This file is corrupt! I could not even\n"
+ "salvage any partial image data from it.");
+
+ g_object_unref (gimage);
+
+ return NULL;
+}
+
+static bool
+xcf_load_image_props (XcfInfo * info, KisImage * gimage)
+{
+ PropType prop_type;
+ TQ_INT32 prop_size;
+
+ while (TRUE)
+ {
+ if (!xcf_load_prop (info, &prop_type, &prop_size))
+ return FALSE;
+
+ switch (prop_type)
+ {
+ case PROP_END:
+ return TRUE;
+
+ case PROP_COLORMAP:
+ if (info->file_version == 0)
+ {
+ TQ_INT32 i;
+
+ g_message (_("XCF warning: version 0 of XCF file format\n"
+ "did not save indexed colormaps correctly.\n"
+ "Substituting grayscale map."));
+ info->cp +=
+ xcf_read_int32 (info->fp, (TQ_INT32 *) & gimage->num_cols, 1);
+ gimage->cmap = g_new (guchar, gimage->num_cols * 3);
+ if (!xcf_seek_pos (info, info->cp + gimage->num_cols, NULL))
+ return FALSE;
+
+ for (i = 0; i < gimage->num_cols; i++)
+ {
+ gimage->cmap[i * 3 + 0] = i;
+ gimage->cmap[i * 3 + 1] = i;
+ gimage->cmap[i * 3 + 2] = i;
+ }
+ }
+ else
+ {
+ info->cp +=
+ xcf_read_int32 (info->fp, (TQ_INT32 *) & gimage->num_cols, 1);
+ gimage->cmap = g_new (guchar, gimage->num_cols * 3);
+ info->cp +=
+ xcf_read_int8 (info->fp,
+ (TQ_UINT8 *) gimage->cmap,
+ gimage->num_cols * 3);
+ }
+
+ /* discard color map, if image is not indexed, this is just
+ * sanity checking to make sure gimp doesn't end up with an
+ * image state that is impossible.
+ */
+ if (gimp_image_base_type (gimage) != GIMP_INDEXED)
+ {
+ g_free (gimage->cmap);
+ gimage->cmap = NULL;
+ gimage->num_cols = 0;
+ }
+ break;
+
+ case PROP_COMPRESSION:
+ {
+ TQ_UINT8 compression;
+
+ info->cp +=
+ xcf_read_int8 (info->fp, (TQ_UINT8 *) & compression, 1);
+
+ if ((compression != COMPRESS_NONE) &&
+ (compression != COMPRESS_RLE) &&
+ (compression != COMPRESS_ZLIB) &&
+ (compression != COMPRESS_FRACTAL))
+ {
+ g_message ("unknown compression type: %d", (int) compression);
+ return FALSE;
+ }
+
+ info->compression = compression;
+ }
+ break;
+
+ case PROP_GUIDES:
+ {
+ TQ_INT3232 position;
+ TQ_INT328 orientation;
+ TQ_INT32 i, nguides;
+
+ nguides = prop_size / (4 + 1);
+ for (i = 0; i < nguides; i++)
+ {
+ info->cp +=
+ xcf_read_int32 (info->fp, (TQ_INT32 *) & position, 1);
+ info->cp +=
+ xcf_read_int8 (info->fp, (TQ_UINT8 *) & orientation, 1);
+
+ /* skip -1 guides from old XCFs */
+ if (position < 0)
+ continue;
+
+ switch (orientation)
+ {
+ case XCF_ORIENTATION_HORIZONTAL:
+ gimp_image_add_hguide (gimage, position, FALSE);
+ break;
+
+ case XCF_ORIENTATION_VERTICAL:
+ gimp_image_add_vguide (gimage, position, FALSE);
+ break;
+
+ default:
+ g_message ("guide orientation out of range in XCF file");
+ continue;
+ }
+ }
+
+ /* this is silly as the order of guides doesn't really matter,
+ * but it restores the list to it's original order, which
+ * cannot be wrong --Mitch
+ */
+ gimage->guides = g_list_reverse (gimage->guides);
+ }
+ break;
+
+ case PROP_RESOLUTION:
+ {
+ float xres, yres;
+
+ info->cp += xcf_read_float (info->fp, &xres, 1);
+ info->cp += xcf_read_float (info->fp, &yres, 1);
+ if (xres < GIMP_MIN_RESOLUTION || xres > GIMP_MAX_RESOLUTION ||
+ yres < GIMP_MIN_RESOLUTION || yres > GIMP_MAX_RESOLUTION)
+ {
+ g_message ("Warning, resolution out of range in XCF file");
+ xres = gimage->gimp->config->default_image->xresolution;
+ yres = gimage->gimp->config->default_image->yresolution;
+ }
+ gimage->xresolution = xres;
+ gimage->yresolution = yres;
+ }
+ break;
+
+ case PROP_TATTOO:
+ {
+ info->cp += xcf_read_int32 (info->fp, &info->tattoo_state, 1);
+ }
+ break;
+
+ case PROP_PARASITES:
+ {
+ glong base = info->cp;
+ KisAnnotation *p;
+
+ while (info->cp - base < prop_size)
+ {
+ p = xcf_load_parasite (info);
+ gimp_image_parasite_attach (gimage, p);
+ gimp_parasite_free (p);
+ }
+ if (info->cp - base != prop_size)
+ g_message ("Error while loading an image's parasites");
+ }
+ break;
+
+ case PROP_UNIT:
+ {
+ TQ_INT32 unit;
+
+ info->cp += xcf_read_int32 (info->fp, &unit, 1);
+
+ if ((unit <= GIMP_UNIT_PIXEL) ||
+ (unit >=
+ _gimp_unit_get_number_of_built_in_units (gimage->gimp)))
+ {
+ g_message ("Warning, unit out of range in XCF file, "
+ "falling back to inches");
+ unit = GIMP_UNIT_INCH;
+ }
+
+ gimage->resolution_unit = unit;
+ }
+ break;
+
+ case PROP_PATHS:
+ xcf_load_old_paths (info, gimage);
+ break;
+
+ case PROP_USER_UNIT:
+ {
+ TQCString *unit_strings[5];
+ float factor;
+ TQ_INT32 digits;
+ GimpUnit unit;
+ TQ_INT32 num_units;
+ TQ_INT32 i;
+
+ info->cp += xcf_read_float (info->fp, &factor, 1);
+ info->cp += xcf_read_int32 (info->fp, &digits, 1);
+ info->cp += xcf_read_string (info->fp, unit_strings, 5);
+
+ for (i = 0; i < 5; i++)
+ if (unit_strings[i] == NULL)
+ unit_strings[i] = g_strdup ("");
+
+ num_units = _gimp_unit_get_number_of_units (gimage->gimp);
+
+ for (unit =
+ _gimp_unit_get_number_of_built_in_units (gimage->gimp);
+ unit < num_units; unit++)
+ {
+ /* if the factor and the identifier match some unit
+ * in unitrc, use the unitrc unit
+ */
+ if ((ABS (_gimp_unit_get_factor (gimage->gimp,
+ unit) - factor) < 1e-5) &&
+ (strcmp (unit_strings[0],
+ _gimp_unit_get_identifier (gimage->gimp,
+ unit)) == 0))
+ {
+ break;
+ }
+ }
+
+ /* no match */
+ if (unit == num_units)
+ unit = _gimp_unit_new (gimage->gimp,
+ unit_strings[0],
+ factor,
+ digits,
+ unit_strings[1],
+ unit_strings[2],
+ unit_strings[3], unit_strings[4]);
+
+ gimage->resolution_unit = unit;
+
+ for (i = 0; i < 5; i++)
+ g_free (unit_strings[i]);
+ }
+ break;
+
+ case PROP_VECTORS:
+ {
+ TQ_INT32 base = info->cp;
+
+ if (xcf_load_vectors (info, gimage))
+ {
+ if (base + prop_size != info->cp)
+ {
+ g_warning
+ ("Mismatch in PROP_VECTORS size: skipping %d bytes.",
+ base + prop_size - info->cp);
+ xcf_seek_pos (info, base + prop_size, NULL);
+ }
+ }
+ else
+ {
+ /* skip silently since we don't understand the format and
+ * xcf_load_vectors already explained what was wrong
+ */
+ xcf_seek_pos (info, base + prop_size, NULL);
+ }
+ }
+ break;
+
+ default:
+#ifdef GIMP_UNSTABLE
+ g_printerr ("unexpected/unknown image property: %d (skipping)",
+ prop_type);
+#endif
+ {
+ TQ_UINT8 buf[16];
+ TQ_UINT32 amount;
+
+ while (prop_size > 0)
+ {
+ amount = MIN (16, prop_size);
+ info->cp += xcf_read_int8 (info->fp, buf, amount);
+ prop_size -= MIN (16, amount);
+ }
+ }
+ break;
+ }
+ }
+
+ return FALSE;
+}
+
+static bool
+xcf_load_layer_props (XcfInfo * info,
+ KisImage * gimage,
+ KisLayer * layer,
+ bool * apply_tqmask,
+ bool * edit_tqmask,
+ bool * show_tqmask, TQ_INT32 * text_layer_flags)
+{
+ PropType prop_type;
+ TQ_INT32 prop_size;
+
+ while (TRUE)
+ {
+ if (!xcf_load_prop (info, &prop_type, &prop_size))
+ return FALSE;
+
+ switch (prop_type)
+ {
+ case PROP_END:
+ return TRUE;
+
+ case PROP_ACTIVE_LAYER:
+ info->active_layer = layer;
+ break;
+
+ case PROP_FLOATING_SELECTION:
+ info->floating_sel = layer;
+ info->cp +=
+ xcf_read_int32 (info->fp,
+ (TQ_INT32 *) & info->floating_sel_offset, 1);
+ break;
+
+ case PROP_OPACITY:
+ {
+ TQ_INT32 opacity;
+
+ info->cp += xcf_read_int32 (info->fp, &opacity, 1);
+ layer->opacity = CLAMP ((gdouble) opacity / 255.0,
+ GIMP_OPACITY_TRANSPARENT,
+ GIMP_OPACITY_OPAQUE);
+ }
+ break;
+
+ case PROP_VISIBLE:
+ {
+ bool visible;
+
+ info->cp += xcf_read_int32 (info->fp, (TQ_INT32 *) & visible, 1);
+ gimp_item_set_visible (GIMP_ITEM (layer),
+ visible ? TRUE : FALSE, FALSE);
+ }
+ break;
+
+ case PROP_LINKED:
+ {
+ bool linked;
+
+ info->cp += xcf_read_int32 (info->fp, (TQ_INT32 *) & linked, 1);
+ gimp_item_set_linked (GIMP_ITEM (layer),
+ linked ? TRUE : FALSE, FALSE);
+ }
+ break;
+
+ case PROP_LOCK_ALPHA:
+ info->cp +=
+ xcf_read_int32 (info->fp, (TQ_INT32 *) & layer->lock_alpha, 1);
+ break;
+
+ case PROP_APPLY_MASK:
+ info->cp += xcf_read_int32 (info->fp, (TQ_INT32 *) apply_tqmask, 1);
+ break;
+
+ case PROP_EDIT_MASK:
+ info->cp += xcf_read_int32 (info->fp, (TQ_INT32 *) edit_tqmask, 1);
+ break;
+
+ case PROP_SHOW_MASK:
+ info->cp += xcf_read_int32 (info->fp, (TQ_INT32 *) show_tqmask, 1);
+ break;
+
+ case PROP_OFFSETS:
+ info->cp +=
+ xcf_read_int32 (info->fp,
+ (TQ_INT32 *) & GIMP_ITEM (layer)->offset_x, 1);
+ info->cp +=
+ xcf_read_int32 (info->fp,
+ (TQ_INT32 *) & GIMP_ITEM (layer)->offset_y, 1);
+ break;
+
+ case PROP_MODE:
+ info->cp += xcf_read_int32 (info->fp, (TQ_INT32 *) & layer->mode, 1);
+ break;
+
+ case PROP_TATTOO:
+ info->cp += xcf_read_int32 (info->fp,
+ (TQ_INT32 *) & GIMP_ITEM (layer)->tattoo,
+ 1);
+ break;
+
+ case PROP_PARASITES:
+ {
+ glong base = info->cp;
+ KisAnnotation *p;
+
+ while (info->cp - base < prop_size)
+ {
+ p = xcf_load_parasite (info);
+ gimp_item_parasite_attach (GIMP_ITEM (layer), p);
+ gimp_parasite_free (p);
+ }
+ if (info->cp - base != prop_size)
+ g_message ("Error while loading a layer's parasites");
+ }
+ break;
+
+ case PROP_TEXT_LAYER_FLAGS:
+ info->cp += xcf_read_int32 (info->fp, text_layer_flags, 1);
+ break;
+
+ default:
+ {
+ TQ_UINT8 buf[16];
+ TQ_UINT32 amount;
+
+#ifdef GIMP_UNSTABLE
+ g_printerr ("unexpected/unknown layer property: %d (skipping)",
+ prop_type);
+#endif
+ while (prop_size > 0)
+ {
+ amount = MIN (16, prop_size);
+ info->cp += xcf_read_int8 (info->fp, buf, amount);
+ prop_size -= MIN (16, amount);
+ }
+ }
+ break;
+ }
+ }
+
+ return FALSE;
+}
+
+static bool
+xcf_load_channel_props (XcfInfo * info,
+ KisImage * gimage, GimpChannel ** channel)
+{
+ PropType prop_type;
+ TQ_INT32 prop_size;
+
+ while (TRUE)
+ {
+ if (!xcf_load_prop (info, &prop_type, &prop_size))
+ return FALSE;
+
+ switch (prop_type)
+ {
+ case PROP_END:
+ return TRUE;
+
+ case PROP_ACTIVE_CHANNEL:
+ info->active_channel = *channel;
+ break;
+
+ case PROP_SELECTION:
+ g_object_unref (gimage->selection_tqmask);
+ gimage->selection_tqmask =
+ gimp_selection_new (gimage,
+ gimp_item_width (GIMP_ITEM (*channel)),
+ gimp_item_height (GIMP_ITEM (*channel)));
+ g_object_ref (gimage->selection_tqmask);
+ gimp_item_sink (GIMP_ITEM (gimage->selection_tqmask));
+
+ tile_manager_unref (GIMP_DRAWABLE (gimage->selection_tqmask)->tiles);
+ GIMP_DRAWABLE (gimage->selection_tqmask)->tiles =
+ GIMP_DRAWABLE (*channel)->tiles;
+ GIMP_DRAWABLE (*channel)->tiles = NULL;
+ g_object_unref (*channel);
+ *channel = gimage->selection_tqmask;
+ (*channel)->boundary_known = FALSE;
+ (*channel)->bounds_known = FALSE;
+ break;
+
+ case PROP_OPACITY:
+ {
+ TQ_INT32 opacity;
+
+ info->cp += xcf_read_int32 (info->fp, &opacity, 1);
+ (*channel)->color.a = opacity / 255.0;
+ }
+ break;
+
+ case PROP_VISIBLE:
+ {
+ bool visible;
+
+ info->cp += xcf_read_int32 (info->fp, (TQ_INT32 *) & visible, 1);
+ gimp_item_set_visible (GIMP_ITEM (*channel),
+ visible ? TRUE : FALSE, FALSE);
+ }
+ break;
+
+ case PROP_LINKED:
+ {
+ bool linked;
+
+ info->cp += xcf_read_int32 (info->fp, (TQ_INT32 *) & linked, 1);
+ gimp_item_set_linked (GIMP_ITEM (*channel),
+ linked ? TRUE : FALSE, FALSE);
+ }
+ break;
+
+ case PROP_SHOW_MASKED:
+ {
+ bool show_tqmasked;
+
+ info->cp +=
+ xcf_read_int32 (info->fp, (TQ_INT32 *) & show_tqmasked, 1);
+ gimp_channel_set_show_tqmasked (*channel, show_tqmasked);
+ }
+ break;
+
+ case PROP_COLOR:
+ {
+ guchar col[3];
+
+ info->cp += xcf_read_int8 (info->fp, (TQ_UINT8 *) col, 3);
+
+ gimp_rgb_set_uchar (&(*channel)->color, col[0], col[1], col[2]);
+ }
+ break;
+
+ case PROP_TATTOO:
+ info->cp +=
+ xcf_read_int32 (info->fp, &GIMP_ITEM (*channel)->tattoo, 1);
+ break;
+
+ case PROP_PARASITES:
+ {
+ glong base = info->cp;
+ KisAnnotation *p;
+
+ while ((info->cp - base) < prop_size)
+ {
+ p = xcf_load_parasite (info);
+ gimp_item_parasite_attach (GIMP_ITEM (*channel), p);
+ gimp_parasite_free (p);
+ }
+ if (info->cp - base != prop_size)
+ g_message ("Error while loading a channel's parasites");
+ }
+ break;
+
+ default:
+#ifdef GIMP_UNSTABLE
+ g_printerr ("unexpected/unknown channel property: %d (skipping)",
+ prop_type);
+#endif
+
+ {
+ TQ_UINT8 buf[16];
+ TQ_UINT32 amount;
+
+ while (prop_size > 0)
+ {
+ amount = MIN (16, prop_size);
+ info->cp += xcf_read_int8 (info->fp, buf, amount);
+ prop_size -= MIN (16, amount);
+ }
+ }
+ break;
+ }
+ }
+
+ return FALSE;
+}
+
+static bool
+xcf_load_prop (XcfInfo * info, PropType * prop_type, TQ_INT32 * prop_size)
+{
+ info->cp += xcf_read_int32 (info->fp, (TQ_INT32 *) prop_type, 1);
+ info->cp += xcf_read_int32 (info->fp, (TQ_INT32 *) prop_size, 1);
+ return TRUE;
+}
+
+static KisLayer *
+xcf_load_layer (XcfInfo * info, KisImage * gimage)
+{
+ KisLayer *layer;
+ GimpLayerMask *layer_tqmask;
+ TQ_INT32 hierarchy_offset;
+ TQ_INT32 layer_tqmask_offset;
+ bool apply_tqmask = TRUE;
+ bool edit_tqmask = FALSE;
+ bool show_tqmask = FALSE;
+ bool active;
+ bool floating;
+ TQ_INT32 text_layer_flags = 0;
+ TQ_INT32 width;
+ TQ_INT32 height;
+ TQ_INT32 type;
+ bool is_fs_drawable;
+ TQCString *name;
+
+ /* check and see if this is the drawable the floating selection
+ * is attached to. if it is then we'll do the attachment in our caller.
+ */
+ is_fs_drawable = (info->cp == info->floating_sel_offset);
+
+ /* read in the layer width, height, type and name */
+ info->cp += xcf_read_int32 (info->fp, (TQ_INT32 *) & width, 1);
+ info->cp += xcf_read_int32 (info->fp, (TQ_INT32 *) & height, 1);
+ info->cp += xcf_read_int32 (info->fp, (TQ_INT32 *) & type, 1);
+ info->cp += xcf_read_string (info->fp, &name, 1);
+
+ /* create a new layer */
+ layer = gimp_layer_new (gimage, width, height,
+ type, name, 255, GIMP_NORMAL_MODE);
+ g_free (name);
+ if (!layer)
+ return NULL;
+
+ /* read in the layer properties */
+ if (!xcf_load_layer_props (info, gimage, layer,
+ &apply_tqmask, &edit_tqmask, &show_tqmask,
+ &text_layer_flags))
+ goto error;
+
+ /* call the evil text layer hack that might change our layer pointer */
+ active = (info->active_layer == layer);
+ floating = (info->floating_sel == layer);
+
+ if (gimp_text_layer_xcf_load_hack (&layer))
+ {
+ gimp_text_layer_set_xcf_flags (GIMP_TEXT_LAYER (layer),
+ text_layer_flags);
+
+ if (active)
+ info->active_layer = layer;
+ if (floating)
+ info->floating_sel = layer;
+ }
+
+ /* read the hierarchy and layer tqmask offsets */
+ info->cp += xcf_read_int32 (info->fp, &hierarchy_offset, 1);
+ info->cp += xcf_read_int32 (info->fp, &layer_tqmask_offset, 1);
+
+ /* read in the hierarchy */
+ if (!xcf_seek_pos (info, hierarchy_offset, NULL))
+ goto error;
+
+ if (!xcf_load_hierarchy (info, GIMP_DRAWABLE (layer)->tiles))
+ goto error;
+
+ /* read in the layer tqmask */
+ if (layer_tqmask_offset != 0)
+ {
+ if (!xcf_seek_pos (info, layer_tqmask_offset, NULL))
+ goto error;
+
+ layer_tqmask = xcf_load_layer_tqmask (info, gimage);
+ if (!layer_tqmask)
+ goto error;
+
+ layer_tqmask->apply_tqmask = apply_tqmask;
+ layer_tqmask->edit_tqmask = edit_tqmask;
+ layer_tqmask->show_tqmask = show_tqmask;
+
+ gimp_layer_add_tqmask (layer, layer_tqmask, FALSE);
+ }
+
+ /* attach the floating selection... */
+ if (is_fs_drawable)
+ info->floating_sel_drawable = GIMP_DRAWABLE (layer);
+
+ return layer;
+
+error:
+ g_object_unref (layer);
+ return NULL;
+}
+
+static GimpChannel *
+xcf_load_channel (XcfInfo * info, KisImage * gimage)
+{
+ GimpChannel *channel;
+ TQ_INT32 hierarchy_offset;
+ TQ_INT32 width;
+ TQ_INT32 height;
+ bool is_fs_drawable;
+ TQCString *name;
+ GimpRGB color = { 0.0, 0.0, 0.0, GIMP_OPACITY_OPAQUE };
+
+ /* check and see if this is the drawable the floating selection
+ * is attached to. if it is then we'll do the attachment in our caller.
+ */
+ is_fs_drawable = (info->cp == info->floating_sel_offset);
+
+ /* read in the layer width, height and name */
+ info->cp += xcf_read_int32 (info->fp, (TQ_INT32 *) & width, 1);
+ info->cp += xcf_read_int32 (info->fp, (TQ_INT32 *) & height, 1);
+ info->cp += xcf_read_string (info->fp, &name, 1);
+
+ /* create a new channel */
+ channel = gimp_channel_new (gimage, width, height, name, &color);
+ g_free (name);
+ if (!channel)
+ return NULL;
+
+ /* read in the channel properties */
+ if (!xcf_load_channel_props (info, gimage, &channel))
+ goto error;
+
+ /* read the hierarchy and layer tqmask offsets */
+ info->cp += xcf_read_int32 (info->fp, &hierarchy_offset, 1);
+
+ /* read in the hierarchy */
+ if (!xcf_seek_pos (info, hierarchy_offset, NULL))
+ goto error;
+
+ if (!xcf_load_hierarchy (info, GIMP_DRAWABLE (channel)->tiles))
+ goto error;
+
+ if (is_fs_drawable)
+ info->floating_sel_drawable = GIMP_DRAWABLE (channel);
+
+ return channel;
+
+error:
+ g_object_unref (channel);
+ return NULL;
+}
+
+static GimpLayerMask *
+xcf_load_layer_tqmask (XcfInfo * info, KisImage * gimage)
+{
+ GimpLayerMask *layer_tqmask;
+ GimpChannel *channel;
+ TQ_INT32 hierarchy_offset;
+ TQ_INT32 width;
+ TQ_INT32 height;
+ bool is_fs_drawable;
+ TQCString *name;
+ GimpRGB color = { 0.0, 0.0, 0.0, GIMP_OPACITY_OPAQUE };
+
+ /* check and see if this is the drawable the floating selection
+ * is attached to. if it is then we'll do the attachment in our caller.
+ */
+ is_fs_drawable = (info->cp == info->floating_sel_offset);
+
+ /* read in the layer width, height and name */
+ info->cp += xcf_read_int32 (info->fp, (TQ_INT32 *) & width, 1);
+ info->cp += xcf_read_int32 (info->fp, (TQ_INT32 *) & height, 1);
+ info->cp += xcf_read_string (info->fp, &name, 1);
+
+ /* create a new layer tqmask */
+ layer_tqmask = gimp_layer_tqmask_new (gimage, width, height, name, &color);
+ g_free (name);
+ if (!layer_tqmask)
+ return NULL;
+
+ /* read in the layer_tqmask properties */
+ channel = GIMP_CHANNEL (layer_tqmask);
+ if (!xcf_load_channel_props (info, gimage, &channel))
+ goto error;
+
+ /* read the hierarchy and layer tqmask offsets */
+ info->cp += xcf_read_int32 (info->fp, &hierarchy_offset, 1);
+
+ /* read in the hierarchy */
+ if (!xcf_seek_pos (info, hierarchy_offset, NULL))
+ goto error;
+
+ if (!xcf_load_hierarchy (info, GIMP_DRAWABLE (layer_tqmask)->tiles))
+ goto error;
+
+ /* attach the floating selection... */
+ if (is_fs_drawable)
+ info->floating_sel_drawable = GIMP_DRAWABLE (layer_tqmask);
+
+ return layer_tqmask;
+
+error:
+ g_object_unref (layer_tqmask);
+ return NULL;
+}
+
+static bool
+xcf_load_hierarchy (XcfInfo * info, TileManager * tiles)
+{
+ TQ_INT32 saved_pos;
+ TQ_INT32 offset;
+ TQ_INT32 junk;
+ TQ_INT32 width;
+ TQ_INT32 height;
+ TQ_INT32 bpp;
+
+ info->cp += xcf_read_int32 (info->fp, (TQ_INT32 *) & width, 1);
+ info->cp += xcf_read_int32 (info->fp, (TQ_INT32 *) & height, 1);
+ info->cp += xcf_read_int32 (info->fp, (TQ_INT32 *) & bpp, 1);
+
+ /* make sure the values in the file correspond to the values
+ * calculated when the TileManager was created.
+ */
+ if (width != tile_manager_width (tiles) ||
+ height != tile_manager_height (tiles) ||
+ bpp != tile_manager_bpp (tiles))
+ return FALSE;
+
+ /* load in the levels...we make sure that the number of levels
+ * calculated when the TileManager was created is the same
+ * as the number of levels found in the file.
+ */
+
+ info->cp += xcf_read_int32 (info->fp, &offset, 1); /* top level */
+
+ /* discard offsets for layers below first, if any.
+ */
+ do
+ {
+ info->cp += xcf_read_int32 (info->fp, &junk, 1);
+ }
+ while (junk != 0);
+
+ /* save the current position as it is where the
+ * next level offset is stored.
+ */
+ saved_pos = info->cp;
+
+ /* seek to the level offset */
+ if (!xcf_seek_pos (info, offset, NULL))
+ return FALSE;
+
+ /* read in the level */
+ if (!xcf_load_level (info, tiles))
+ return FALSE;
+
+ /* restore the saved position so we'll be ready to
+ * read the next offset.
+ */
+ if (!xcf_seek_pos (info, saved_pos, NULL))
+ return FALSE;
+
+ return TRUE;
+}
+
+
+static bool
+xcf_load_level (XcfInfo * info, TileManager * tiles)
+{
+ TQ_INT32 saved_pos;
+ TQ_INT32 offset, offset2;
+ TQ_UINT32 ntiles;
+ TQ_INT32 width;
+ TQ_INT32 height;
+ TQ_INT32 i;
+ TQ_INT32 fail;
+ Tile *previous;
+ Tile *tile;
+
+ info->cp += xcf_read_int32 (info->fp, (TQ_INT32 *) & width, 1);
+ info->cp += xcf_read_int32 (info->fp, (TQ_INT32 *) & height, 1);
+
+ if (width != tile_manager_width (tiles) ||
+ height != tile_manager_height (tiles))
+ return FALSE;
+
+ /* read in the first tile offset.
+ * if it is '0', then this tile level is empty
+ * and we can simply return.
+ */
+ info->cp += xcf_read_int32 (info->fp, &offset, 1);
+ if (offset == 0)
+ return TRUE;
+
+ /* Initialise the reference for the in-memory tile-compression
+ */
+ previous = NULL;
+
+ ntiles = tiles->ntile_rows * tiles->ntile_cols;
+ for (i = 0; i < ntiles; i++)
+ {
+ fail = FALSE;
+
+ if (offset == 0)
+ {
+ g_message ("not enough tiles found in level");
+ return FALSE;
+ }
+
+ /* save the current position as it is where the
+ * next tile offset is stored.
+ */
+ saved_pos = info->cp;
+
+ /* read in the offset of the next tile so we can calculate the amount
+ of data needed for this tile */
+ info->cp += xcf_read_int32 (info->fp, &offset2, 1);
+
+ /* if the offset is 0 then we need to read in the maximum possible
+ allowing for negative compression */
+ if (offset2 == 0)
+ offset2 = offset + TILE_WIDTH * TILE_WIDTH * 4 * 1.5;
+ /* 1.5 is probably more
+ than we need to allow */
+
+ /* seek to the tile offset */
+ if (!xcf_seek_pos (info, offset, NULL))
+ return FALSE;
+
+ /* get the tile from the tile manager */
+ tile = tile_manager_get (tiles, i, TRUE, TRUE);
+
+ /* read in the tile */
+ switch (info->compression)
+ {
+ case COMPRESS_NONE:
+ if (!xcf_load_tile (info, tile))
+ fail = TRUE;
+ break;
+ case COMPRESS_RLE:
+ if (!xcf_load_tile_rle (info, tile, offset2 - offset))
+ fail = TRUE;
+ break;
+ case COMPRESS_ZLIB:
+ g_error ("xcf: zlib compression unimplemented");
+ fail = TRUE;
+ break;
+ case COMPRESS_FRACTAL:
+ g_error ("xcf: fractal compression unimplemented");
+ fail = TRUE;
+ break;
+ }
+
+ if (fail)
+ {
+ tile_release (tile, TRUE);
+ return FALSE;
+ }
+
+ /* To potentially save memory, we compare the
+ * newly-fetched tile against the last one, and
+ * if they're the same we copy-on-write mirror one against
+ * the other.
+ */
+ if (previous != NULL)
+ {
+ tile_lock (previous);
+ if (tile_ewidth (tile) == tile_ewidth (previous) &&
+ tile_eheight (tile) == tile_eheight (previous) &&
+ tile_bpp (tile) == tile_bpp (previous) &&
+ memcmp (tile_data_pointer (tile, 0, 0),
+ tile_data_pointer (previous, 0, 0),
+ tile_size (tile)) == 0)
+ tile_manager_map (tiles, i, previous);
+ tile_release (previous, FALSE);
+ }
+ tile_release (tile, TRUE);
+ previous = tile_manager_get (tiles, i, FALSE, FALSE);
+
+ /* restore the saved position so we'll be ready to
+ * read the next offset.
+ */
+ if (!xcf_seek_pos (info, saved_pos, NULL))
+ return FALSE;
+
+ /* read in the offset of the next tile */
+ info->cp += xcf_read_int32 (info->fp, &offset, 1);
+ }
+
+ if (offset != 0)
+ {
+ g_message ("encountered garbage after reading level: %d", offset);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static bool
+xcf_load_tile (XcfInfo * info, Tile * tile)
+{
+#ifdef SWAP_FROM_FILE
+
+ if (!info->swap_num)
+ {
+ info->ref_count = g_new (int, 1);
+ info->swap_num = tile_swap_add (info->filename,
+ xcf_swap_func, info->ref_count);
+ }
+
+ tile->swap_num = info->swap_num;
+ tile->swap_offset = info->cp;
+ *info->ref_count += 1;
+
+#else
+
+ info->cp += xcf_read_int8 (info->fp, tile_data_pointer (tile, 0, 0),
+ tile_size (tile));
+
+#endif
+
+ return TRUE;
+}
+
+static bool
+xcf_load_tile_rle (XcfInfo * info, Tile * tile, int data_length)
+{
+ guchar *data;
+ guchar val;
+ TQ_INT32 size;
+ TQ_INT32 count;
+ TQ_INT32 length;
+ TQ_INT32 bpp;
+ TQ_INT32 i, j;
+ TQ_INT32 nmemb_read_successfully;
+ guchar *xcfdata, *xcfodata, *xcfdatalimit;
+
+ data = tile_data_pointer (tile, 0, 0);
+ bpp = tile_bpp (tile);
+
+ xcfdata = xcfodata = g_malloc (data_length);
+
+ /* we have to use fread instead of xcf_read_* because we may be
+ reading past the end of the file here */
+ nmemb_read_successfully = fread ((TQCString *) xcfdata, sizeof (TQCString),
+ data_length, info->fp);
+ info->cp += nmemb_read_successfully;
+
+ xcfdatalimit = &xcfodata[nmemb_read_successfully - 1];
+
+ for (i = 0; i < bpp; i++)
+ {
+ data = (guchar *) tile_data_pointer (tile, 0, 0) + i;
+ size = tile_ewidth (tile) * tile_eheight (tile);
+ count = 0;
+
+ while (size > 0)
+ {
+ if (xcfdata > xcfdatalimit)
+ {
+ goto bogus_rle;
+ }
+
+ val = *xcfdata++;
+
+ length = val;
+ if (length >= 128)
+ {
+ length = 255 - (length - 1);
+ if (length == 128)
+ {
+ if (xcfdata >= xcfdatalimit)
+ {
+ goto bogus_rle;
+ }
+
+ length = (*xcfdata << 8) + xcfdata[1];
+ xcfdata += 2;
+ }
+
+ count += length;
+ size -= length;
+
+ if (size < 0)
+ {
+ goto bogus_rle;
+ }
+
+ if (&xcfdata[length - 1] > xcfdatalimit)
+ {
+ goto bogus_rle;
+ }
+
+ while (length-- > 0)
+ {
+ *data = *xcfdata++;
+ data += bpp;
+ }
+ }
+ else
+ {
+ length += 1;
+ if (length == 128)
+ {
+ if (xcfdata >= xcfdatalimit)
+ {
+ goto bogus_rle;
+ }
+
+ length = (*xcfdata << 8) + xcfdata[1];
+ xcfdata += 2;
+ }
+
+ count += length;
+ size -= length;
+
+ if (size < 0)
+ {
+ goto bogus_rle;
+ }
+
+ if (xcfdata > xcfdatalimit)
+ {
+ goto bogus_rle;
+ }
+
+ val = *xcfdata++;
+
+ for (j = 0; j < length; j++)
+ {
+ *data = val;
+ data += bpp;
+ }
+ }
+ }
+ }
+ g_free (xcfodata);
+ return TRUE;
+
+bogus_rle:
+ if (xcfodata)
+ g_free (xcfodata);
+ return FALSE;
+}
+
+static KisAnnotation *
+xcf_load_parasite (XcfInfo * info)
+{
+ KisAnnotation *p;
+
+ p = g_new (KisAnnotation, 1);
+ info->cp += xcf_read_string (info->fp, &p->name, 1);
+ info->cp += xcf_read_int32 (info->fp, &p->flags, 1);
+ info->cp += xcf_read_int32 (info->fp, &p->size, 1);
+ p->data = g_new (TQCString, p->size);
+ info->cp += xcf_read_int8 (info->fp, p->data, p->size);
+
+ return p;
+}
+
+static bool
+xcf_load_old_paths (XcfInfo * info, KisImage * gimage)
+{
+ TQ_INT32 num_paths;
+ TQ_INT32 last_selected_row;
+ GimpVectors *active_vectors;
+
+ info->cp += xcf_read_int32 (info->fp, &last_selected_row, 1);
+ info->cp += xcf_read_int32 (info->fp, &num_paths, 1);
+
+ while (num_paths-- > 0)
+ xcf_load_old_path (info, gimage);
+
+ active_vectors = (GimpVectors *)
+ gimp_container_get_child_by_index (gimage->vectors, last_selected_row);
+
+ if (active_vectors)
+ gimp_image_set_active_vectors (gimage, active_vectors);
+
+ return TRUE;
+}
+
+static bool
+xcf_load_old_path (XcfInfo * info, KisImage * gimage)
+{
+ TQCString *name;
+ TQ_INT32 locked;
+ TQ_UINT8 state;
+ TQ_INT32 closed;
+ TQ_INT32 num_points;
+ TQ_INT32 version; /* changed from num_paths */
+ GimpTattoo tattoo = 0;
+ GimpVectors *vectors;
+ GimpVectorsCompatPoint *points;
+ TQ_INT32 i;
+
+ info->cp += xcf_read_string (info->fp, &name, 1);
+ info->cp += xcf_read_int32 (info->fp, &locked, 1);
+ info->cp += xcf_read_int8 (info->fp, &state, 1);
+ info->cp += xcf_read_int32 (info->fp, &closed, 1);
+ info->cp += xcf_read_int32 (info->fp, &num_points, 1);
+ info->cp += xcf_read_int32 (info->fp, &version, 1);
+
+ if (version == 2)
+ {
+ TQ_INT32 dummy;
+
+ /* Had extra type field and points are stored as doubles */
+ info->cp += xcf_read_int32 (info->fp, (TQ_INT32 *) & dummy, 1);
+ }
+ else if (version == 3)
+ {
+ TQ_INT32 dummy;
+
+ /* Has extra tatto field */
+ info->cp += xcf_read_int32 (info->fp, (TQ_INT32 *) & dummy, 1);
+ info->cp += xcf_read_int32 (info->fp, (TQ_INT32 *) & tattoo, 1);
+ }
+ else if (version != 1)
+ {
+ g_warning ("Unknown path type. Possibly corrupt XCF file");
+
+ return FALSE;
+ }
+
+ /* skip empty compatibility paths */
+ if (num_points == 0)
+ return FALSE;
+
+ points = g_new0 (GimpVectorsCompatPoint, num_points);
+
+ for (i = 0; i < num_points; i++)
+ {
+ if (version == 1)
+ {
+ TQ_INT3232 x;
+ TQ_INT3232 y;
+
+ info->cp += xcf_read_int32 (info->fp, &points[i].type, 1);
+ info->cp += xcf_read_int32 (info->fp, (TQ_INT32 *) & x, 1);
+ info->cp += xcf_read_int32 (info->fp, (TQ_INT32 *) & y, 1);
+
+ points[i].x = x;
+ points[i].y = y;
+ }
+ else
+ {
+ float x;
+ float y;
+
+ info->cp += xcf_read_int32 (info->fp, &points[i].type, 1);
+ info->cp += xcf_read_float (info->fp, &x, 1);
+ info->cp += xcf_read_float (info->fp, &y, 1);
+
+ points[i].x = x;
+ points[i].y = y;
+ }
+ }
+
+ vectors =
+ gimp_vectors_compat_new (gimage, name, points, num_points, closed);
+
+ g_free (name);
+ g_free (points);
+
+ GIMP_ITEM (vectors)->linked = locked;
+
+ if (tattoo)
+ GIMP_ITEM (vectors)->tattoo = tattoo;
+
+ gimp_image_add_vectors (gimage, vectors,
+ gimp_container_num_tqchildren (gimage->vectors));
+
+ return TRUE;
+}
+
+static bool
+xcf_load_vectors (XcfInfo * info, KisImage * gimage)
+{
+ TQ_INT32 version;
+ TQ_INT32 active_index;
+ TQ_INT32 num_paths;
+ GimpVectors *active_vectors;
+ TQ_INT32 base;
+
+#ifdef GIMP_XCF_PATH_DEBUG
+ g_printerr ("xcf_load_vectors\n");
+#endif
+
+ base = info->cp;
+
+ info->cp += xcf_read_int32 (info->fp, &version, 1);
+
+ if (version != 1)
+ {
+ g_message ("Unknown vectors version: %d (skipping)", version);
+ return FALSE;
+ }
+
+ info->cp += xcf_read_int32 (info->fp, &active_index, 1);
+ info->cp += xcf_read_int32 (info->fp, &num_paths, 1);
+
+#ifdef GIMP_XCF_PATH_DEBUG
+ g_printerr ("%d paths (active: %d)\n", num_paths, active_index);
+#endif
+
+ while (num_paths-- > 0)
+ if (!xcf_load_vector (info, gimage))
+ return FALSE;
+
+ active_vectors = (GimpVectors *)
+ gimp_container_get_child_by_index (gimage->vectors, active_index);
+
+ if (active_vectors)
+ gimp_image_set_active_vectors (gimage, active_vectors);
+
+#ifdef GIMP_XCF_PATH_DEBUG
+ g_printerr ("xcf_load_vectors: loaded %d bytes\n", info->cp - base);
+#endif
+ return TRUE;
+}
+
+static bool
+xcf_load_vector (XcfInfo * info, KisImage * gimage)
+{
+ TQCString *name;
+ GimpTattoo tattoo = 0;
+ TQ_INT32 visible;
+ TQ_INT32 linked;
+ TQ_INT32 num_parasites;
+ TQ_INT32 num_strokes;
+ GimpVectors *vectors;
+ TQ_INT32 i;
+
+#ifdef GIMP_XCF_PATH_DEBUG
+ g_printerr ("xcf_load_vector\n");
+#endif
+
+ info->cp += xcf_read_string (info->fp, &name, 1);
+ info->cp += xcf_read_int32 (info->fp, &tattoo, 1);
+ info->cp += xcf_read_int32 (info->fp, &visible, 1);
+ info->cp += xcf_read_int32 (info->fp, &linked, 1);
+ info->cp += xcf_read_int32 (info->fp, &num_parasites, 1);
+ info->cp += xcf_read_int32 (info->fp, &num_strokes, 1);
+
+#ifdef GIMP_XCF_PATH_DEBUG
+ g_printerr
+ ("name: %s, tattoo: %d, visible: %d, linked: %d, num_parasites %d, "
+ "num_strokes %d\n", name, tattoo, visible, linked, num_parasites,
+ num_strokes);
+#endif
+
+ vectors = gimp_vectors_new (gimage, name);
+
+ GIMP_ITEM (vectors)->visible = visible ? TRUE : FALSE;
+ GIMP_ITEM (vectors)->linked = linked ? TRUE : FALSE;
+
+ if (tattoo)
+ GIMP_ITEM (vectors)->tattoo = tattoo;
+
+ for (i = 0; i < num_parasites; i++)
+ {
+ KisAnnotation *parasite;
+
+ parasite = xcf_load_parasite (info);
+
+ if (!parasite)
+ return FALSE;
+
+ gimp_item_parasite_attach (GIMP_ITEM (vectors), parasite);
+ gimp_parasite_free (parasite);
+ }
+
+ for (i = 0; i < num_strokes; i++)
+ {
+ TQ_INT32 stroke_type_id;
+ TQ_INT32 closed;
+ TQ_INT32 num_axes;
+ TQ_INT32 num_control_points;
+ TQ_INT32 type;
+ float coords[6] = { 0.0, 0.0, 1.0, 0.5, 0.5, 0.5 };
+ GimpStroke *stroke;
+ TQ_INT32 j;
+
+ GValueArray *control_points;
+ GValue value = { 0, };
+ GimpAnchor anchor;
+ GType stroke_type;
+
+ g_value_init (&value, GIMP_TYPE_ANCHOR);
+
+ info->cp += xcf_read_int32 (info->fp, &stroke_type_id, 1);
+ info->cp += xcf_read_int32 (info->fp, &closed, 1);
+ info->cp += xcf_read_int32 (info->fp, &num_axes, 1);
+ info->cp += xcf_read_int32 (info->fp, &num_control_points, 1);
+
+#ifdef GIMP_XCF_PATH_DEBUG
+ g_printerr ("stroke_type: %d, closed: %d, num_axes %d, len %d\n",
+ stroke_type_id, closed, num_axes, num_control_points);
+#endif
+
+ switch (stroke_type_id)
+ {
+ case XCF_STROKETYPE_BEZIER_STROKE:
+ stroke_type = GIMP_TYPE_BEZIER_STROKE;
+ break;
+
+ default:
+ g_printerr ("skipping unknown stroke type\n");
+ xcf_seek_pos (info,
+ info->cp + 4 * num_axes * num_control_points, NULL);
+ continue;
+ }
+
+ control_points = g_value_array_new (num_control_points);
+
+ anchor.selected = FALSE;
+
+ for (j = 0; j < num_control_points; j++)
+ {
+ info->cp += xcf_read_int32 (info->fp, &type, 1);
+ info->cp += xcf_read_float (info->fp, coords, num_axes);
+
+ anchor.type = type;
+ anchor.position.x = coords[0];
+ anchor.position.y = coords[1];
+ anchor.position.pressure = coords[2];
+ anchor.position.xtilt = coords[3];
+ anchor.position.ytilt = coords[4];
+ anchor.position.wheel = coords[5];
+
+ g_value_set_boxed (&value, &anchor);
+ g_value_array_append (control_points, &value);
+
+#ifdef GIMP_XCF_PATH_DEBUG
+ g_printerr ("Anchor: %d, (%f, %f, %f, %f, %f, %f)\n", type,
+ coords[0], coords[1], coords[2], coords[3],
+ coords[4], coords[5]);
+#endif
+ }
+
+ g_value_unset (&value);
+
+ stroke = g_object_new (stroke_type,
+ "closed", closed,
+ "control-points", control_points, NULL);
+
+ gimp_vectors_stroke_add (vectors, stroke);
+ }
+
+ gimp_image_add_vectors (gimage, vectors,
+ gimp_container_num_tqchildren (gimage->vectors));
+
+ return TRUE;
+}
+
+#ifdef SWAP_FROM_FILE
+
+static bool
+xcf_swap_func (TQ_INT32 fd, Tile * tile, TQ_INT32 cmd, gpointer user_data)
+{
+ TQ_INT32 bytes;
+ TQ_INT32 err;
+ TQ_INT32 nleft;
+ TQ_INT32 *ref_count;
+
+ switch (cmd)
+ {
+ case SWAP_IN:
+ lseek (fd, tile->swap_offset, SEEK_SET);
+
+ bytes = tile_size (tile);
+ tile_alloc (tile);
+
+ nleft = bytes;
+ while (nleft > 0)
+ {
+ do
+ {
+ err = read (fd, tile->data + bytes - nleft, nleft);
+ }
+ while ((err == -1) && ((errno == EAGAIN) || (errno == EINTR)));
+
+ if (err <= 0)
+ {
+ g_message ("unable to read tile data from xcf file: "
+ "%d ( %d ) bytes read", err, nleft);
+ return FALSE;
+ }
+
+ nleft -= err;
+ }
+ break;
+
+ case SWAP_OUT:
+ case SWAP_DELETE:
+ case SWAP_COMPRESS:
+ ref_count = user_data;
+ *ref_count -= 1;
+ if (*ref_count == 0)
+ {
+ tile_swap_remove (tile->swap_num);
+ g_free (ref_count);
+ }
+
+ tile->swap_num = 1;
+ tile->swap_offset = -1;
+
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+#endif
diff --git a/filters/chalk/xcf/xcf/xcf-load.h b/filters/chalk/xcf/xcf/xcf-load.h
new file mode 100644
index 00000000..75bc0e9c
--- /dev/null
+++ b/filters/chalk/xcf/xcf/xcf-load.h
@@ -0,0 +1,27 @@
+/* The GIMP -- an image manipulation program
+ * Copyright (C) 1995 Spencer Kimball and Peter Mattis
+ *
+ * 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 of the License, 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 __XCF_LOAD_H__
+#define __XCF_LOAD_H__
+
+class KisImage;
+class XcfInfo;
+
+KisImage * xcf_load_image (XcfInfo *info);
+
+#endif /* __XCF_LOAD_H__ */
diff --git a/filters/chalk/xcf/xcf/xcf-private.h b/filters/chalk/xcf/xcf/xcf-private.h
new file mode 100644
index 00000000..3a832fbd
--- /dev/null
+++ b/filters/chalk/xcf/xcf/xcf-private.h
@@ -0,0 +1,95 @@
+/* The GIMP -- an image manipulation program
+ * Copyright (C) 1995 Spencer Kimball and Peter Mattis
+ *
+ * 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 of the License, 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 __XCF_PRIVATE_H__
+#define __XCF_PRIVATE_H__
+
+#include <tqcstring.h>
+
+typedef enum
+{
+ PROP_END = 0,
+ PROP_COLORMAP = 1,
+ PROP_ACTIVE_LAYER = 2,
+ PROP_ACTIVE_CHANNEL = 3,
+ PROP_SELECTION = 4,
+ PROP_FLOATING_SELECTION = 5,
+ PROP_OPACITY = 6,
+ PROP_MODE = 7,
+ PROP_VISIBLE = 8,
+ PROP_LINKED = 9,
+ PROP_LOCK_ALPHA = 10,
+ PROP_APPLY_MASK = 11,
+ PROP_EDIT_MASK = 12,
+ PROP_SHOW_MASK = 13,
+ PROP_SHOW_MASKED = 14,
+ PROP_OFFSETS = 15,
+ PROP_COLOR = 16,
+ PROP_COMPRESSION = 17,
+ PROP_GUIDES = 18,
+ PROP_RESOLUTION = 19,
+ PROP_TATTOO = 20,
+ PROP_PARASITES = 21,
+ PROP_UNIT = 22,
+ PROP_PATHS = 23,
+ PROP_USER_UNIT = 24,
+ PROP_VECTORS = 25,
+ PROP_TEXT_LAYER_FLAGS = 26
+} PropType;
+
+typedef enum
+{
+ COMPRESS_NONE = 0,
+ COMPRESS_RLE = 1,
+ COMPRESS_ZLIB = 2, /* unused */
+ COMPRESS_FRACTAL = 3 /* unused */
+} XcfCompressionType;
+
+typedef enum
+{
+ XCF_ORIENTATION_HORIZONTAL = 1,
+ XCF_ORIENTATION_VERTICAL = 2
+} XcfQt::OrientationType;
+
+typedef enum
+{
+ XCF_STROKETYPE_STROKE = 0,
+ XCF_STROKETYPE_BEZIER_STROKE = 1
+} XcfStrokeType;
+
+typedef struct _XcfInfo XcfInfo;
+
+struct _XcfInfo
+{
+ FILE *fp;
+ TQ_UINT32 cp;
+ const TQCString filename;
+ //GimpTattoo tattoo_state;
+ KisLayer *active_layer;
+ //GimpChannel *active_channel;
+ //GimpDrawable *floating_sel_drawable;
+ KisLayer *floating_sel;
+ TQ_UINT32 floating_sel_offset;
+ TQ_INT32 swap_num;
+ TQ_INT32 *ref_count;
+ XcfCompressionType compression;
+ TQ_INT32 file_version;
+};
+
+
+#endif /* __XCF_PRIVATE_H__ */
diff --git a/filters/chalk/xcf/xcf/xcf-read.cc b/filters/chalk/xcf/xcf/xcf-read.cc
new file mode 100644
index 00000000..314daa90
--- /dev/null
+++ b/filters/chalk/xcf/xcf/xcf-read.cc
@@ -0,0 +1,118 @@
+/* The GIMP -- an image manipulation program
+ * Copyright (C) 1995 Spencer Kimball and Peter Mattis
+ *
+ * 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 of the License, 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 <stdio.h>
+
+#include <glib-object.h>
+
+#include "libgimpbase/gimpbase.h"
+
+#include "xcf-read.h"
+
+#include "gimp-intl.h"
+
+
+TQ_UINT32
+xcf_read_int32 (FILE *fp,
+ TQ_INT32 *data,
+ TQ_INT32 count)
+{
+ TQ_UINT32 total;
+
+ total = count;
+ if (count > 0)
+ {
+ xcf_read_int8 (fp, (TQ_UINT8 *) data, count * 4);
+
+ while (count--)
+ {
+ *data = g_ntohl (*data);
+ data++;
+ }
+ }
+
+ return total * 4;
+}
+
+TQ_UINT32
+xcf_read_float (FILE *fp,
+ float *data,
+ TQ_INT32 count)
+{
+ return xcf_read_int32 (fp, (TQ_INT32 *) ((void *) data), count);
+}
+
+TQ_UINT32
+xcf_read_int8 (FILE *fp,
+ TQ_UINT8 *data,
+ TQ_INT32 count)
+{
+ TQ_UINT32 total;
+ TQ_INT32 bytes;
+
+ total = count;
+ while (count > 0)
+ {
+ bytes = fread ((char *) data, sizeof (char), count, fp);
+ if (bytes <= 0) /* something bad happened */
+ break;
+ count -= bytes;
+ data += bytes;
+ }
+
+ return total;
+}
+
+TQ_UINT32
+xcf_read_string (FILE *fp,
+ TQCString **data,
+ TQ_INT32 count)
+{
+ TQ_INT32 tmp;
+ TQ_UINT32 total;
+ TQ_INT32 i;
+
+ total = 0;
+ for (i = 0; i < count; i++)
+ {
+ total += xcf_read_int32 (fp, &tmp, 1);
+ if (tmp > 0)
+ {
+ TQCString *str;
+
+ str = g_new (TQCString, tmp);
+ total += xcf_read_int8 (fp, (TQ_UINT8*) str, tmp);
+
+ if (str[tmp - 1] != '\0')
+ str[tmp - 1] = '\0';
+
+ data[i] = gimp_any_to_utf8 (str, -1,
+ _("Invalid UTF-8 string in XCF file"));
+
+ g_free (str);
+ }
+ else
+ {
+ data[i] = NULL;
+ }
+ }
+
+ return total;
+}
diff --git a/filters/chalk/xcf/xcf/xcf-read.h b/filters/chalk/xcf/xcf/xcf-read.h
new file mode 100644
index 00000000..b90b8a41
--- /dev/null
+++ b/filters/chalk/xcf/xcf/xcf-read.h
@@ -0,0 +1,37 @@
+/* The GIMP -- an image manipulation program
+ * Copyright (C) 1995 Spencer Kimball and Peter Mattis
+ *
+ * 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 of the License, 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 __XCF_READ_H__
+#define __XCF_READ_H__
+
+
+TQ_UINT32 xcf_read_int32 (FILE *fp,
+ TQ_INT32 *data,
+ TQ_INT32 count);
+TQ_UINT32 xcf_read_float (FILE *fp,
+ float *data,
+ TQ_INT32 count);
+TQ_UINT32 xcf_read_int8 (FILE *fp,
+ TQ_UINT8 *data,
+ TQ_INT32 count);
+TQ_UINT32 xcf_read_string (FILE *fp,
+ TQCString **data,
+ TQ_INT32 count);
+
+
+#endif /* __XCF_READ_H__ */
diff --git a/filters/chalk/xcf/xcf/xcf-save.cc b/filters/chalk/xcf/xcf/xcf-save.cc
new file mode 100644
index 00000000..50e5fb17
--- /dev/null
+++ b/filters/chalk/xcf/xcf/xcf-save.cc
@@ -0,0 +1,1826 @@
+/* The GIMP -- an image manipulation program
+ * Copyright (C) 1995 Spencer Kimball and Peter Mattis
+ *
+ * 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 of the License, 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 <stdio.h>
+#include <string.h> /* strcpy, strlen */
+
+#include <glib-object.h>
+
+#include "libgimpbase/gimpbase.h"
+#include "libgimpcolor/gimpcolor.h"
+
+#include "core/core-types.h"
+
+#include "base/tile.h"
+#include "base/tile-manager.h"
+#include "base/tile-manager-private.h"
+
+#include "core/gimpchannel.h"
+#include "core/gimpdrawable.h"
+#include "core/gimpgrid.h"
+#include "core/gimpimage.h"
+#include "core/gimpimage-grid.h"
+#include "core/gimpimage-guides.h"
+#include "core/gimplayer.h"
+#include "core/gimplayer-floating-sel.h"
+#include "core/gimplayertqmask.h"
+#include "core/gimplist.h"
+#include "core/gimpparasitelist.h"
+#include "core/gimpunit.h"
+
+#include "text/gimptextlayer.h"
+#include "text/gimptextlayer-xcf.h"
+
+#include "vectors/gimpanchor.h"
+#include "vectors/gimpstroke.h"
+#include "vectors/gimpbezierstroke.h"
+#include "vectors/gimpvectors.h"
+#include "vectors/gimpvectors-compat.h"
+
+#include "xcf-private.h"
+#include "xcf-read.h"
+#include "xcf-seek.h"
+#include "xcf-write.h"
+
+#include "gimp-intl.h"
+
+
+static bool xcf_save_image_props (XcfInfo *info,
+ KisImage *gimage,
+ GError **error);
+static bool xcf_save_layer_props (XcfInfo *info,
+ KisImage *gimage,
+ KisLayer *layer,
+ GError **error);
+static bool xcf_save_channel_props (XcfInfo *info,
+ KisImage *gimage,
+ GimpChannel *channel,
+ GError **error);
+static bool xcf_save_prop (XcfInfo *info,
+ KisImage *gimage,
+ PropType prop_type,
+ GError **error,
+ ...);
+static bool xcf_save_layer (XcfInfo *info,
+ KisImage *gimage,
+ KisLayer *layer,
+ GError **error);
+static bool xcf_save_channel (XcfInfo *info,
+ KisImage *gimage,
+ GimpChannel *channel,
+ GError **error);
+static bool xcf_save_hierarchy (XcfInfo *info,
+ TileManager *tiles,
+ GError **error);
+static bool xcf_save_level (XcfInfo *info,
+ TileManager *tiles,
+ GError **error);
+static bool xcf_save_tile (XcfInfo *info,
+ Tile *tile,
+ GError **error);
+static bool xcf_save_tile_rle (XcfInfo *info,
+ Tile *tile,
+ guchar *rlebuf,
+ GError **error);
+static bool xcf_save_parasite (XcfInfo *info,
+ KisAnnotation *parasite,
+ GError **error);
+static bool xcf_save_parasite_list (XcfInfo *info,
+ KisAnnotationList *parasite,
+ GError **error);
+static bool xcf_save_old_paths (XcfInfo *info,
+ KisImage *gimage,
+ GError **error);
+static bool xcf_save_vectors (XcfInfo *info,
+ KisImage *gimage,
+ GError **error);
+
+
+/* private convenience macros */
+#define xcf_write_int32_check_error(info, data, count) G_STMT_START { \
+ info->cp += xcf_write_int32 (info->fp, data, count, &tmp_error); \
+ if (tmp_error) \
+ { \
+ g_propagate_error (error, tmp_error); \
+ return FALSE; \
+ } \
+ } G_STMT_END
+
+#define xcf_write_int8_check_error(info, data, count) G_STMT_START { \
+ info->cp += xcf_write_int8 (info->fp, data, count, &tmp_error); \
+ if (tmp_error) \
+ { \
+ g_propagate_error (error, tmp_error); \
+ return FALSE; \
+ } \
+ } G_STMT_END
+
+#define xcf_write_float_check_error(info, data, count) G_STMT_START { \
+ info->cp += xcf_write_float (info->fp, data, count, &tmp_error); \
+ if (tmp_error) \
+ { \
+ g_propagate_error (error, tmp_error); \
+ return FALSE; \
+ } \
+ } G_STMT_END
+
+#define xcf_write_string_check_error(info, data, count) G_STMT_START { \
+ info->cp += xcf_write_string (info->fp, data, count, &tmp_error); \
+ if (tmp_error) \
+ { \
+ g_propagate_error (error, tmp_error); \
+ return FALSE; \
+ } \
+ } G_STMT_END
+
+#define xcf_write_int32_print_error(info, data, count) G_STMT_START { \
+ info->cp += xcf_write_int32 (info->fp, data, count, &error); \
+ if (error) \
+ { \
+ g_message (_("Error saving XCF file: %s"), \
+ error->message); \
+ return FALSE; \
+ } \
+ } G_STMT_END
+
+#define xcf_write_int8_print_error(info, data, count) G_STMT_START { \
+ info->cp += xcf_write_int8 (info->fp, data, count, &error); \
+ if (error) \
+ { \
+ g_message (_("Error saving XCF file: %s"), \
+ error->message); \
+ return FALSE; \
+ } \
+ } G_STMT_END
+
+#define xcf_write_float_print_error(info, data, count) G_STMT_START { \
+ info->cp += xcf_write_float (info->fp, data, count, &error); \
+ if (error) \
+ { \
+ g_message (_("Error saving XCF file: %s"), \
+ error->message); \
+ return FALSE; \
+ } \
+ } G_STMT_END
+
+#define xcf_write_string_print_error(info, data, count) G_STMT_START { \
+ info->cp += xcf_write_string (info->fp, data, count, &error); \
+ if (error) \
+ { \
+ g_message (_("Error saving XCF file: %s"), \
+ error->message); \
+ return FALSE; \
+ } \
+ } G_STMT_END
+
+#define xcf_write_prop_type_check_error(info, prop_type) G_STMT_START { \
+ TQ_INT32 _prop_int32 = prop_type; \
+ xcf_write_int32_check_error (info, &_prop_int32, 1); \
+ } G_STMT_END
+
+#define xcf_write_prop_type_print_error(info, prop_type) G_STMT_START { \
+ TQ_INT32 _prop_int32 = prop_type; \
+ xcf_write_int32_print_error (info, &_prop_int32, 1); \
+ } G_STMT_END
+
+#define xcf_check_error(x) G_STMT_START { \
+ if (! (x)) \
+ return FALSE; \
+ } G_STMT_END
+
+#define xcf_print_error(x) G_STMT_START { \
+ if (! (x)) \
+ { \
+ g_message (_("Error saving XCF file: %s"), \
+ error->message); \
+ return FALSE; \
+ } \
+ } G_STMT_END
+
+
+void
+xcf_save_choose_format (XcfInfo *info,
+ KisImage *gimage)
+{
+ KisLayer *layer;
+ GList *list;
+
+ TQ_INT32 save_version = 0; /* default to oldest */
+
+ if (gimage->cmap)
+ save_version = 1; /* need version 1 for colormaps */
+
+ for (list = GIMP_LIST (gimage->layers)->list;
+ list && save_version < 2;
+ list = g_list_next (list))
+ {
+ layer = GIMP_LAYER (list->data);
+
+ switch (layer->mode)
+ {
+ /* new layer modes not supported by gimp-1.2 */
+ case GIMP_SOFTLIGHT_MODE:
+ case GIMP_GRAIN_EXTRACT_MODE:
+ case GIMP_GRAIN_MERGE_MODE:
+ case GIMP_COLOR_ERASE_MODE:
+ save_version = 2;
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ info->file_version = save_version;
+}
+
+TQ_INT32
+xcf_save_image (XcfInfo *info,
+ KisImage *gimage)
+{
+ KisLayer *layer;
+ KisLayer *floating_layer;
+ GimpChannel *channel;
+ TQ_INT32 saved_pos;
+ TQ_INT32 offset;
+ TQ_UINT32 nlayers;
+ TQ_UINT32 nchannels;
+ GList *list;
+ bool have_selection;
+ TQ_INT32 t1, t2, t3, t4;
+ TQCString version_tag[14];
+ GError *error = NULL;
+
+ floating_layer = gimp_image_floating_sel (gimage);
+ if (floating_layer)
+ floating_sel_relax (floating_layer, FALSE);
+
+ /* write out the tag information for the image */
+ if (info->file_version > 0)
+ {
+ sprintf (version_tag, "gimp xcf v%03d", info->file_version);
+ }
+ else
+ {
+ strcpy (version_tag, "gimp xcf file");
+ }
+ xcf_write_int8_print_error (info, (TQ_UINT8 *) version_tag, 14);
+
+ /* write out the width, height and image type information for the image */
+ xcf_write_int32_print_error (info, (TQ_INT32 *) &gimage->width, 1);
+ xcf_write_int32_print_error (info, (TQ_INT32 *) &gimage->height, 1);
+ xcf_write_int32_print_error (info, (TQ_INT32 *) &gimage->base_type, 1);
+
+ /* determine the number of layers and channels in the image */
+ nlayers = (TQ_UINT32) gimp_container_num_tqchildren (gimage->layers);
+ nchannels = (TQ_UINT32) gimp_container_num_tqchildren (gimage->channels);
+
+ /* check and see if we have to save out the selection */
+ have_selection = gimp_channel_bounds (gimp_image_get_tqmask (gimage),
+ &t1, &t2, &t3, &t4);
+ if (have_selection)
+ nchannels += 1;
+
+ /* write the property information for the image.
+ */
+
+ xcf_print_error (xcf_save_image_props (info, gimage, &error));
+
+ /* save the current file position as it is the start of where
+ * we place the layer offset information.
+ */
+ saved_pos = info->cp;
+
+ /* seek to after the offset lists */
+ xcf_print_error (xcf_seek_pos (info,
+ info->cp + (nlayers + nchannels + 2) * 4,
+ &error));
+
+ for (list = GIMP_LIST (gimage->layers)->list;
+ list;
+ list = g_list_next (list))
+ {
+ layer = (KisLayer *) list->data;
+
+ /* save the start offset of where we are writing
+ * out the next layer.
+ */
+ offset = info->cp;
+
+ /* write out the layer. */
+ xcf_print_error (xcf_save_layer (info, gimage, layer, &error));
+
+ /* seek back to where we are to write out the next
+ * layer offset and write it out.
+ */
+ xcf_print_error (xcf_seek_pos (info, saved_pos, &error));
+ xcf_write_int32_print_error (info, &offset, 1);
+
+ /* increment the location we are to write out the
+ * next offset.
+ */
+ saved_pos = info->cp;
+
+ /* seek to the end of the file which is where
+ * we will write out the next layer.
+ */
+ xcf_print_error (xcf_seek_end (info, &error));
+ }
+
+ /* write out a '0' offset position to indicate the end
+ * of the layer offsets.
+ */
+ offset = 0;
+ xcf_print_error (xcf_seek_pos (info, saved_pos, &error));
+ xcf_write_int32_print_error (info, &offset, 1);
+ saved_pos = info->cp;
+ xcf_print_error (xcf_seek_end (info, &error));
+
+ list = GIMP_LIST (gimage->channels)->list;
+
+ while (list || have_selection)
+ {
+ if (list)
+ {
+ channel = (GimpChannel *) list->data;
+
+ list = g_list_next (list);
+ }
+ else
+ {
+ channel = gimage->selection_tqmask;
+ have_selection = FALSE;
+ }
+
+ /* save the start offset of where we are writing
+ * out the next channel.
+ */
+ offset = info->cp;
+
+ /* write out the layer. */
+ xcf_print_error (xcf_save_channel (info, gimage, channel, &error));
+
+ /* seek back to where we are to write out the next
+ * channel offset and write it out.
+ */
+ xcf_print_error (xcf_seek_pos (info, saved_pos, &error));
+ xcf_write_int32_print_error (info, &offset, 1);
+
+ /* increment the location we are to write out the
+ * next offset.
+ */
+ saved_pos = info->cp;
+
+ /* seek to the end of the file which is where
+ * we will write out the next channel.
+ */
+ xcf_print_error (xcf_seek_end (info, &error));
+ }
+
+ /* write out a '0' offset position to indicate the end
+ * of the channel offsets.
+ */
+ offset = 0;
+ xcf_print_error (xcf_seek_pos (info, saved_pos, &error));
+ xcf_write_int32_print_error (info, &offset, 1);
+ saved_pos = info->cp;
+
+ if (floating_layer)
+ floating_sel_rigor (floating_layer, FALSE);
+
+ return !ferror(info->fp);
+}
+
+static bool
+xcf_save_image_props (XcfInfo *info,
+ KisImage *gimage,
+ GError **error)
+{
+ KisAnnotation *parasite = NULL;
+ GimpUnit unit = gimp_image_get_unit (gimage);
+
+ /* check and see if we should save the colormap property */
+ if (gimage->cmap)
+ xcf_check_error (xcf_save_prop (info, gimage, PROP_COLORMAP, error,
+ gimage->num_cols, gimage->cmap));
+
+ if (info->compression != COMPRESS_NONE)
+ xcf_check_error (xcf_save_prop (info, gimage, PROP_COMPRESSION,
+ error, info->compression));
+
+ if (gimage->guides)
+ xcf_check_error (xcf_save_prop (info, gimage, PROP_GUIDES,
+ error, gimage->guides));
+
+ xcf_check_error (xcf_save_prop (info, gimage, PROP_RESOLUTION, error,
+ gimage->xresolution, gimage->yresolution));
+
+ xcf_check_error (xcf_save_prop (info, gimage, PROP_TATTOO, error,
+ gimage->tattoo_state));
+
+ if (gimp_parasite_list_length (gimage->parasites) > 0)
+ xcf_check_error (xcf_save_prop (info, gimage, PROP_PARASITES,
+ error, gimage->parasites));
+
+ if (unit < _gimp_unit_get_number_of_built_in_units (gimage->gimp))
+ xcf_check_error (xcf_save_prop (info, gimage, PROP_UNIT, error, unit));
+
+ if (gimp_container_num_tqchildren (gimage->vectors) > 0)
+ {
+ if (gimp_vectors_compat_is_compatible (gimage))
+ xcf_check_error (xcf_save_prop (info, gimage, PROP_PATHS, error));
+ else
+ xcf_check_error (xcf_save_prop (info, gimage, PROP_VECTORS, error));
+ }
+
+ if (unit >= _gimp_unit_get_number_of_built_in_units (gimage->gimp))
+ xcf_check_error (xcf_save_prop (info, gimage, PROP_USER_UNIT, error, unit));
+
+ if (GIMP_IS_GRID (gimage->grid))
+ {
+ GimpGrid *grid = gimp_image_get_grid (gimage);
+
+ parasite = gimp_grid_to_parasite (grid);
+ gimp_parasite_list_add (GIMP_IMAGE (gimage)->parasites, parasite);
+ }
+
+ if (gimp_parasite_list_length (GIMP_IMAGE (gimage)->parasites) > 0)
+ {
+ xcf_check_error (xcf_save_prop (info, gimage, PROP_PARASITES, error,
+ GIMP_IMAGE (gimage)->parasites));
+ }
+
+ if (parasite)
+ {
+ gimp_parasite_list_remove (GIMP_IMAGE (gimage)->parasites,
+ gimp_parasite_name (parasite));
+ gimp_parasite_free (parasite);
+ }
+
+ xcf_check_error (xcf_save_prop (info, gimage, PROP_END, error));
+
+ return TRUE;
+}
+
+static bool
+xcf_save_layer_props (XcfInfo *info,
+ KisImage *gimage,
+ KisLayer *layer,
+ GError **error)
+{
+ KisAnnotation *parasite = NULL;
+
+ if (layer == gimp_image_get_active_layer (gimage))
+ xcf_check_error (xcf_save_prop (info, gimage, PROP_ACTIVE_LAYER, error));
+
+ if (layer == gimp_image_floating_sel (gimage))
+ {
+ info->floating_sel_drawable = layer->fs.drawable;
+ xcf_check_error (xcf_save_prop (info, gimage, PROP_FLOATING_SELECTION,
+ error));
+ }
+
+ xcf_check_error (xcf_save_prop (info, gimage, PROP_OPACITY, error,
+ layer->opacity));
+ xcf_check_error (xcf_save_prop (info, gimage, PROP_VISIBLE, error,
+ gimp_item_get_visible (GIMP_ITEM (layer))));
+ xcf_check_error (xcf_save_prop (info, gimage, PROP_LINKED, error,
+ gimp_item_get_linked (GIMP_ITEM (layer))));
+ xcf_check_error (xcf_save_prop (info, gimage, PROP_LOCK_ALPHA,
+ error, layer->lock_alpha));
+
+ if (layer->tqmask)
+ {
+ xcf_check_error (xcf_save_prop (info, gimage, PROP_APPLY_MASK,
+ error, layer->tqmask->apply_tqmask));
+ xcf_check_error (xcf_save_prop (info, gimage, PROP_EDIT_MASK,
+ error, layer->tqmask->edit_tqmask));
+ xcf_check_error (xcf_save_prop (info, gimage, PROP_SHOW_MASK,
+ error, layer->tqmask->show_tqmask));
+ }
+ else
+ {
+ xcf_check_error (xcf_save_prop (info, gimage, PROP_APPLY_MASK,
+ error, FALSE));
+ xcf_check_error (xcf_save_prop (info, gimage, PROP_EDIT_MASK,
+ error, FALSE));
+ xcf_check_error (xcf_save_prop (info, gimage, PROP_SHOW_MASK,
+ error, FALSE));
+ }
+
+ xcf_check_error (xcf_save_prop (info, gimage, PROP_OFFSETS, error,
+ GIMP_ITEM (layer)->offset_x,
+ GIMP_ITEM (layer)->offset_y));
+ xcf_check_error (xcf_save_prop (info, gimage, PROP_MODE, error,
+ layer->mode));
+ xcf_check_error (xcf_save_prop (info, gimage, PROP_TATTOO, error,
+ GIMP_ITEM (layer)->tattoo));
+
+ if (GIMP_IS_TEXT_LAYER (layer) && GIMP_TEXT_LAYER (layer)->text)
+ {
+ GimpTextLayer *text_layer = GIMP_TEXT_LAYER (layer);
+ TQ_INT32 flags = gimp_text_layer_get_xcf_flags (text_layer);
+
+ gimp_text_layer_xcf_save_prepare (text_layer);
+
+ if (flags)
+ xcf_check_error (xcf_save_prop (info,
+ gimage, PROP_TEXT_LAYER_FLAGS, error,
+ flags));
+ }
+
+ if (gimp_parasite_list_length (GIMP_ITEM (layer)->parasites) > 0)
+ {
+ xcf_check_error (xcf_save_prop (info, gimage, PROP_PARASITES, error,
+ GIMP_ITEM (layer)->parasites));
+ }
+
+ if (parasite)
+ {
+ gimp_parasite_list_remove (GIMP_ITEM (layer)->parasites,
+ gimp_parasite_name (parasite));
+ gimp_parasite_free (parasite);
+ }
+
+ xcf_check_error (xcf_save_prop (info, gimage, PROP_END, error));
+
+ return TRUE;
+}
+
+static bool
+xcf_save_channel_props (XcfInfo *info,
+ KisImage *gimage,
+ GimpChannel *channel,
+ GError **error)
+{
+ guchar col[3];
+
+ if (channel == gimp_image_get_active_channel (gimage))
+ xcf_check_error (xcf_save_prop (info, gimage, PROP_ACTIVE_CHANNEL, error));
+
+ if (channel == gimage->selection_tqmask)
+ xcf_check_error (xcf_save_prop (info, gimage, PROP_SELECTION, error));
+
+ xcf_check_error (xcf_save_prop (info, gimage, PROP_OPACITY, error,
+ channel->color.a));
+ xcf_check_error (xcf_save_prop (info, gimage, PROP_VISIBLE, error,
+ gimp_item_get_visible (GIMP_ITEM (channel))));
+ xcf_check_error (xcf_save_prop (info, gimage, PROP_LINKED, error,
+ gimp_item_get_linked (GIMP_ITEM (channel))));
+ xcf_check_error (xcf_save_prop (info, gimage, PROP_SHOW_MASKED, error,
+ channel->show_tqmasked));
+
+ gimp_rgb_get_uchar (&channel->color, &col[0], &col[1], &col[2]);
+ xcf_check_error (xcf_save_prop (info, gimage, PROP_COLOR, error, col));
+
+ xcf_check_error (xcf_save_prop (info, gimage, PROP_TATTOO, error,
+ GIMP_ITEM (channel)->tattoo));
+
+ if (gimp_parasite_list_length (GIMP_ITEM (channel)->parasites) > 0)
+ xcf_check_error (xcf_save_prop (info, gimage, PROP_PARASITES, error,
+ GIMP_ITEM (channel)->parasites));
+
+ xcf_check_error (xcf_save_prop (info, gimage, PROP_END, error));
+
+ return TRUE;
+}
+
+static bool
+xcf_save_prop (XcfInfo *info,
+ KisImage *gimage,
+ PropType prop_type,
+ GError **error,
+ ...)
+{
+ TQ_INT32 size;
+ va_list args;
+
+ GError *tmp_error = NULL;
+
+ va_start (args, error);
+
+ switch (prop_type)
+ {
+ case PROP_END:
+ size = 0;
+
+ xcf_write_prop_type_check_error (info, prop_type);
+ xcf_write_int32_check_error (info, &size, 1);
+ break;
+
+ case PROP_COLORMAP:
+ {
+ TQ_INT32 ncolors;
+ guchar *colors;
+
+ ncolors = va_arg (args, TQ_INT32);
+ colors = va_arg (args, guchar*);
+ size = 4 + ncolors * 3;
+
+ xcf_write_prop_type_check_error (info, prop_type);
+ xcf_write_int32_check_error (info, &size, 1);
+ xcf_write_int32_check_error (info, &ncolors, 1);
+ xcf_write_int8_check_error (info, colors, ncolors * 3);
+ }
+ break;
+
+ case PROP_ACTIVE_LAYER:
+ case PROP_ACTIVE_CHANNEL:
+ case PROP_SELECTION:
+ size = 0;
+
+ xcf_write_prop_type_check_error (info, prop_type);
+ xcf_write_int32_check_error (info, &size, 1);
+ break;
+
+ case PROP_FLOATING_SELECTION:
+ {
+ TQ_INT32 dummy;
+
+ dummy = 0;
+ size = 4;
+
+ xcf_write_prop_type_check_error (info, prop_type);
+ xcf_write_int32_check_error (info, &size, 1);
+ info->floating_sel_offset = info->cp;
+ xcf_write_int32_check_error (info, &dummy, 1);
+ }
+ break;
+
+ case PROP_OPACITY:
+ {
+ gdouble opacity;
+ TQ_INT32 uint_opacity;
+
+ opacity = va_arg (args, gdouble);
+
+ uint_opacity = opacity * 255.999;
+
+ size = 4;
+
+ xcf_write_prop_type_check_error (info, prop_type);
+ xcf_write_int32_check_error (info, &size, 1);
+ xcf_write_int32_check_error (info, &uint_opacity, 1);
+ }
+ break;
+
+ case PROP_MODE:
+ {
+ TQ_INT3232 mode;
+
+ mode = va_arg (args, TQ_INT3232);
+ size = 4;
+
+ xcf_write_prop_type_check_error (info, prop_type);
+ xcf_write_int32_check_error (info, &size, 1);
+ xcf_write_int32_check_error (info, (TQ_INT32 *) &mode, 1);
+ }
+ break;
+
+ case PROP_VISIBLE:
+ {
+ TQ_INT32 visible;
+
+ visible = va_arg (args, TQ_INT32);
+ size = 4;
+
+ xcf_write_prop_type_check_error (info, prop_type);
+ xcf_write_int32_check_error (info, &size, 1);
+ xcf_write_int32_check_error (info, &visible, 1);
+ }
+ break;
+
+ case PROP_LINKED:
+ {
+ TQ_INT32 linked;
+
+ linked = va_arg (args, TQ_INT32);
+ size = 4;
+
+ xcf_write_prop_type_check_error (info, prop_type);
+ xcf_write_int32_check_error (info, &size, 1);
+ xcf_write_int32_check_error (info, &linked, 1);
+ }
+ break;
+
+ case PROP_LOCK_ALPHA:
+ {
+ TQ_INT32 lock_alpha;
+
+ lock_alpha = va_arg (args, TQ_INT32);
+ size = 4;
+
+ xcf_write_prop_type_check_error (info, prop_type);
+ xcf_write_int32_check_error (info, &size, 1);
+ xcf_write_int32_check_error (info, &lock_alpha, 1);
+ }
+ break;
+
+ case PROP_APPLY_MASK:
+ {
+ TQ_INT32 apply_tqmask;
+
+ apply_tqmask = va_arg (args, TQ_INT32);
+ size = 4;
+
+ xcf_write_prop_type_check_error (info, prop_type);
+ xcf_write_int32_check_error (info, &size, 1);
+ xcf_write_int32_check_error (info, &apply_tqmask, 1);
+ }
+ break;
+
+ case PROP_EDIT_MASK:
+ {
+ TQ_INT32 edit_tqmask;
+
+ edit_tqmask = va_arg (args, TQ_INT32);
+ size = 4;
+
+ xcf_write_prop_type_check_error (info, prop_type);
+ xcf_write_int32_check_error (info, &size, 1);
+ xcf_write_int32_check_error (info, &edit_tqmask, 1);
+ }
+ break;
+
+ case PROP_SHOW_MASK:
+ {
+ TQ_INT32 show_tqmask;
+
+ show_tqmask = va_arg (args, TQ_INT32);
+ size = 4;
+
+ xcf_write_prop_type_check_error (info, prop_type);
+ xcf_write_int32_check_error (info, &size, 1);
+ xcf_write_int32_check_error (info, &show_tqmask, 1);
+ }
+ break;
+
+ case PROP_SHOW_MASKED:
+ {
+ TQ_INT32 show_tqmasked;
+
+ show_tqmasked = va_arg (args, TQ_INT32);
+ size = 4;
+
+ xcf_write_prop_type_check_error (info, prop_type);
+ xcf_write_int32_check_error (info, &size, 1);
+ xcf_write_int32_check_error (info, &show_tqmasked, 1);
+ }
+ break;
+
+ case PROP_OFFSETS:
+ {
+ TQ_INT3232 offsets[2];
+
+ offsets[0] = va_arg (args, TQ_INT3232);
+ offsets[1] = va_arg (args, TQ_INT3232);
+ size = 8;
+
+ xcf_write_prop_type_check_error (info, prop_type);
+ xcf_write_int32_check_error (info, &size, 1);
+ xcf_write_int32_check_error (info, (TQ_INT32 *) offsets, 2);
+ }
+ break;
+
+ case PROP_COLOR:
+ {
+ guchar *color;
+
+ color = va_arg (args, guchar*);
+ size = 3;
+
+ xcf_write_prop_type_check_error (info, prop_type);
+ xcf_write_int32_check_error (info, &size, 1);
+ xcf_write_int8_check_error (info, color, 3);
+ }
+ break;
+
+ case PROP_COMPRESSION:
+ {
+ TQ_UINT8 compression;
+
+ compression = (TQ_UINT8) va_arg (args, TQ_INT32);
+ size = 1;
+
+ xcf_write_prop_type_check_error (info, prop_type);
+ xcf_write_int32_check_error (info, &size, 1);
+ xcf_write_int8_check_error (info, &compression, 1);
+ }
+ break;
+
+ case PROP_GUIDES:
+ {
+ GList *guides;
+ GimpGuide *guide;
+ TQ_INT3232 position;
+ TQ_INT328 orientation;
+ TQ_INT32 nguides;
+
+ guides = va_arg (args, GList *);
+ nguides = g_list_length (guides);
+
+ size = nguides * (4 + 1);
+
+ xcf_write_prop_type_check_error (info, prop_type);
+ xcf_write_int32_check_error (info, &size, 1);
+
+ for (; guides; guides = g_list_next (guides))
+ {
+ guide = (GimpGuide *) guides->data;
+
+ position = guide->position;
+
+ switch (guide->orientation)
+ {
+ case GIMP_ORIENTATION_HORIZONTAL:
+ orientation = XCF_ORIENTATION_HORIZONTAL;
+ break;
+
+ case GIMP_ORIENTATION_VERTICAL:
+ orientation = XCF_ORIENTATION_VERTICAL;
+ break;
+
+ default:
+ g_warning ("%s: skipping guide with bad orientation",
+ G_STRFUNC);
+ continue;
+ }
+
+ xcf_write_int32_check_error (info, (TQ_INT32 *) &position, 1);
+ xcf_write_int8_check_error (info, (TQ_UINT8 *) &orientation, 1);
+ }
+ }
+ break;
+
+ case PROP_RESOLUTION:
+ {
+ float xresolution, yresolution;
+
+ /* we pass in floats,
+ but they are promoted to double by the compiler */
+ xresolution = va_arg (args, double);
+ yresolution = va_arg (args, double);
+
+ size = 4*2;
+
+ xcf_write_prop_type_check_error (info, prop_type);
+ xcf_write_int32_check_error (info, &size, 1);
+
+ xcf_write_float_check_error (info, &xresolution, 1);
+ xcf_write_float_check_error (info, &yresolution, 1);
+ }
+ break;
+
+ case PROP_TATTOO:
+ {
+ TQ_INT32 tattoo;
+
+ tattoo = va_arg (args, TQ_INT32);
+ size = 4;
+
+ xcf_write_prop_type_check_error (info, prop_type);
+ xcf_write_int32_check_error (info, &size, 1);
+ xcf_write_int32_check_error (info, &tattoo, 1);
+ }
+ break;
+
+ case PROP_PARASITES:
+ {
+ KisAnnotationList *list;
+ TQ_INT32 base, length;
+ long pos;
+
+ list = va_arg (args, KisAnnotationList *);
+
+ if (gimp_parasite_list_persistent_length (list) > 0)
+ {
+ xcf_write_prop_type_check_error (info, prop_type);
+
+ /* because we don't know how much room the parasite list will take
+ * we save the file position and write the length later
+ */
+ pos = info->cp;
+ xcf_write_int32_check_error (info, &length, 1);
+ base = info->cp;
+
+ xcf_check_error (xcf_save_parasite_list (info, list, error));
+
+ length = info->cp - base;
+ /* go back to the saved position and write the length */
+ xcf_check_error (xcf_seek_pos (info, pos, error));
+ xcf_write_int32 (info->fp, &length, 1, &tmp_error);
+ if (tmp_error)
+ {
+ g_propagate_error (error, tmp_error);
+ return FALSE;
+ }
+
+ xcf_check_error (xcf_seek_end (info, error));
+ }
+ }
+ break;
+
+ case PROP_UNIT:
+ {
+ TQ_INT32 unit;
+
+ unit = va_arg (args, TQ_INT32);
+
+ size = 4;
+
+ xcf_write_prop_type_check_error (info, prop_type);
+ xcf_write_int32_check_error (info, &size, 1);
+ xcf_write_int32_check_error (info, &unit, 1);
+ }
+ break;
+
+ case PROP_PATHS:
+ {
+ TQ_INT32 base, length;
+ glong pos;
+
+ xcf_write_prop_type_check_error (info, prop_type);
+
+ /* because we don't know how much room the paths list will take
+ * we save the file position and write the length later
+ */
+ pos = info->cp;
+ xcf_write_int32_check_error (info, &length, 1);
+
+ base = info->cp;
+
+ xcf_check_error (xcf_save_old_paths (info, gimage, error));
+
+ length = info->cp - base;
+
+ /* go back to the saved position and write the length */
+ xcf_check_error (xcf_seek_pos (info, pos, error));
+ xcf_write_int32 (info->fp, &length, 1, &tmp_error);
+ if (tmp_error)
+ {
+ g_propagate_error (error, tmp_error);
+ return FALSE;
+ }
+
+ xcf_check_error (xcf_seek_end (info, error));
+ }
+ break;
+
+ case PROP_USER_UNIT:
+ {
+ GimpUnit unit;
+ const TQCString *unit_strings[5];
+ float factor;
+ TQ_INT32 digits;
+
+ unit = va_arg (args, TQ_INT32);
+
+ /* write the entire unit definition */
+ unit_strings[0] = _gimp_unit_get_identifier (gimage->gimp, unit);
+ factor = _gimp_unit_get_factor (gimage->gimp, unit);
+ digits = _gimp_unit_get_digits (gimage->gimp, unit);
+ unit_strings[1] = _gimp_unit_get_symbol (gimage->gimp, unit);
+ unit_strings[2] = _gimp_unit_get_abbreviation (gimage->gimp, unit);
+ unit_strings[3] = _gimp_unit_get_singular (gimage->gimp, unit);
+ unit_strings[4] = _gimp_unit_get_plural (gimage->gimp, unit);
+
+ size =
+ 2 * 4 +
+ strlen (unit_strings[0]) ? strlen (unit_strings[0]) + 5 : 4 +
+ strlen (unit_strings[1]) ? strlen (unit_strings[1]) + 5 : 4 +
+ strlen (unit_strings[2]) ? strlen (unit_strings[2]) + 5 : 4 +
+ strlen (unit_strings[3]) ? strlen (unit_strings[3]) + 5 : 4 +
+ strlen (unit_strings[4]) ? strlen (unit_strings[4]) + 5 : 4;
+
+ xcf_write_prop_type_check_error (info, prop_type);
+ xcf_write_int32_check_error (info, &size, 1);
+ xcf_write_float_check_error (info, &factor, 1);
+ xcf_write_int32_check_error (info, &digits, 1);
+ xcf_write_string_check_error (info, (TQCString **) unit_strings, 5);
+ }
+ break;
+
+ case PROP_VECTORS:
+ {
+ TQ_INT32 base, length;
+ glong pos;
+
+ xcf_write_prop_type_check_error (info, prop_type);
+
+ /* because we don't know how much room the paths list will take
+ * we save the file position and write the length later
+ */
+ pos = info->cp;
+ xcf_write_int32_check_error (info, &length, 1);
+
+ base = info->cp;
+
+ xcf_check_error (xcf_save_vectors (info, gimage, error));
+
+ length = info->cp - base;
+
+ /* go back to the saved position and write the length */
+ xcf_check_error (xcf_seek_pos (info, pos, error));
+ xcf_write_int32 (info->fp, &length, 1, &tmp_error);
+ if (tmp_error)
+ {
+ g_propagate_error (error, tmp_error);
+ return FALSE;
+ }
+
+ xcf_check_error (xcf_seek_end (info, error));
+ }
+ break;
+
+ case PROP_TEXT_LAYER_FLAGS:
+ {
+ TQ_INT32 flags;
+
+ flags = va_arg (args, TQ_INT32);
+ size = 4;
+
+ xcf_write_prop_type_check_error (info, prop_type);
+ xcf_write_int32_check_error (info, &size, 1);
+ xcf_write_int32_check_error (info, &flags, 1);
+ }
+ break;
+ }
+
+ va_end (args);
+
+ return TRUE;
+}
+
+static bool
+xcf_save_layer (XcfInfo *info,
+ KisImage *gimage,
+ KisLayer *layer,
+ GError **error)
+{
+ TQ_INT32 saved_pos;
+ TQ_INT32 offset;
+
+ GError *tmp_error = NULL;
+
+ /* check and see if this is the drawable that the floating
+ * selection is attached to.
+ */
+ if (GIMP_DRAWABLE (layer) == info->floating_sel_drawable)
+ {
+ saved_pos = info->cp;
+ xcf_check_error (xcf_seek_pos (info, info->floating_sel_offset, error));
+ xcf_write_int32_check_error (info, &saved_pos, 1);
+ xcf_check_error (xcf_seek_pos (info, saved_pos, error));
+ }
+
+ /* write out the width, height and image type information for the layer */
+ xcf_write_int32_check_error (info,
+ (TQ_INT32 *) &GIMP_ITEM (layer)->width, 1);
+ xcf_write_int32_check_error (info,
+ (TQ_INT32 *) &GIMP_ITEM (layer)->height, 1);
+ xcf_write_int32_check_error (info,
+ (TQ_INT32 *) &GIMP_DRAWABLE (layer)->type, 1);
+
+ /* write out the layers name */
+ xcf_write_string_check_error (info, &GIMP_OBJECT (layer)->name, 1);
+
+ /* write out the layer properties */
+ xcf_save_layer_props (info, gimage, layer, error);
+
+ /* save the current position which is where the hierarchy offset
+ * will be stored.
+ */
+ saved_pos = info->cp;
+
+ /* write out the layer tile hierarchy */
+ xcf_check_error (xcf_seek_pos (info, info->cp + 8, error));
+ offset = info->cp;
+
+ xcf_check_error (xcf_save_hierarchy (info,
+ GIMP_DRAWABLE(layer)->tiles, error));
+
+ xcf_check_error (xcf_seek_pos (info, saved_pos, error));
+ xcf_write_int32_check_error (info, &offset, 1);
+ saved_pos = info->cp;
+
+ /* write out the layer tqmask */
+ if (layer->tqmask)
+ {
+ xcf_check_error (xcf_seek_end (info, error));
+ offset = info->cp;
+
+ xcf_check_error (xcf_save_channel (info,
+ gimage, GIMP_CHANNEL(layer->tqmask),
+ error));
+ }
+ else
+ offset = 0;
+
+ xcf_check_error (xcf_seek_pos (info, saved_pos, error));
+ xcf_write_int32_check_error (info, &offset, 1);
+
+ return TRUE;
+}
+
+static bool
+xcf_save_channel (XcfInfo *info,
+ KisImage *gimage,
+ GimpChannel *channel,
+ GError **error)
+{
+ TQ_INT32 saved_pos;
+ TQ_INT32 offset;
+
+ GError *tmp_error = NULL;
+
+ /* check and see if this is the drawable that the floating
+ * selection is attached to.
+ */
+ if (GIMP_DRAWABLE (channel) == info->floating_sel_drawable)
+ {
+ saved_pos = info->cp;
+ xcf_check_error (xcf_seek_pos (info, info->floating_sel_offset, error));
+ xcf_write_int32_check_error (info, &saved_pos, 1);
+ xcf_check_error (xcf_seek_pos (info, saved_pos, error));
+ }
+
+ /* write out the width and height information for the channel */
+ xcf_write_int32_check_error (info,
+ (TQ_INT32 *) &GIMP_ITEM (channel)->width, 1);
+ xcf_write_int32_check_error (info,
+ (TQ_INT32 *) &GIMP_ITEM (channel)->height, 1);
+
+ /* write out the channels name */
+ xcf_write_string_check_error (info, &GIMP_OBJECT (channel)->name, 1);
+
+ /* write out the channel properties */
+ xcf_save_channel_props (info, gimage, channel, error);
+
+ /* save the current position which is where the hierarchy offset
+ * will be stored.
+ */
+ saved_pos = info->cp;
+
+ /* write out the channel tile hierarchy */
+ xcf_check_error (xcf_seek_pos (info, info->cp + 4, error));
+ offset = info->cp;
+
+ xcf_check_error (xcf_save_hierarchy (info,
+ GIMP_DRAWABLE (channel)->tiles, error));
+
+ xcf_check_error (xcf_seek_pos (info, saved_pos, error));
+ xcf_write_int32_check_error (info, &offset, 1);
+ saved_pos = info->cp;
+
+ return TRUE;
+}
+
+static TQ_INT32
+xcf_calc_levels (TQ_INT32 size,
+ TQ_INT32 tile_size)
+{
+ int levels;
+
+ levels = 1;
+ while (size > tile_size)
+ {
+ size /= 2;
+ levels += 1;
+ }
+
+ return levels;
+}
+
+
+static bool
+xcf_save_hierarchy (XcfInfo *info,
+ TileManager *tiles,
+ GError **error)
+{
+ TQ_INT32 saved_pos;
+ TQ_INT32 offset;
+ TQ_INT32 width;
+ TQ_INT32 height;
+ TQ_INT32 bpp;
+ TQ_INT32 i;
+ TQ_INT32 nlevels;
+ TQ_INT32 tmp1, tmp2;
+
+ GError *tmp_error = NULL;
+
+ width = tile_manager_width (tiles);
+ height = tile_manager_height (tiles);
+ bpp = tile_manager_bpp (tiles);
+
+ xcf_write_int32_check_error (info, (TQ_INT32 *) &width, 1);
+ xcf_write_int32_check_error (info, (TQ_INT32 *) &height, 1);
+ xcf_write_int32_check_error (info, (TQ_INT32 *) &bpp, 1);
+
+ saved_pos = info->cp;
+
+ tmp1 = xcf_calc_levels (width, TILE_WIDTH);
+ tmp2 = xcf_calc_levels (height, TILE_HEIGHT);
+ nlevels = MAX (tmp1, tmp2);
+
+ xcf_check_error (xcf_seek_pos (info, info->cp + (1 + nlevels) * 4, error));
+
+ for (i = 0; i < nlevels; i++)
+ {
+ offset = info->cp;
+
+ if (i == 0)
+ {
+ /* write out the level. */
+ xcf_check_error (xcf_save_level (info, tiles, error));
+ }
+ else
+ {
+ /* fake an empty level */
+ tmp1 = 0;
+ width /= 2;
+ height /= 2;
+ xcf_write_int32_check_error (info, (TQ_INT32 *) &width, 1);
+ xcf_write_int32_check_error (info, (TQ_INT32 *) &height, 1);
+ xcf_write_int32_check_error (info, (TQ_INT32 *) &tmp1, 1);
+ }
+
+ /* seek back to where we are to write out the next
+ * level offset and write it out.
+ */
+ xcf_check_error (xcf_seek_pos (info, saved_pos, error));
+ xcf_write_int32_check_error (info, &offset, 1);
+
+ /* increment the location we are to write out the
+ * next offset.
+ */
+ saved_pos = info->cp;
+
+ /* seek to the end of the file which is where
+ * we will write out the next level.
+ */
+ xcf_check_error (xcf_seek_end (info, error));
+ }
+
+ /* write out a '0' offset position to indicate the end
+ * of the level offsets.
+ */
+ offset = 0;
+ xcf_check_error (xcf_seek_pos (info, saved_pos, error));
+ xcf_write_int32_check_error (info, &offset, 1);
+
+ return TRUE;
+}
+
+static bool
+xcf_save_level (XcfInfo *info,
+ TileManager *level,
+ GError **error)
+{
+ TQ_INT32 saved_pos;
+ TQ_INT32 offset;
+ TQ_INT32 width;
+ TQ_INT32 height;
+ TQ_UINT32 ntiles;
+ TQ_INT32 i;
+ guchar *rlebuf;
+
+ GError *tmp_error = NULL;
+
+ width = tile_manager_width (level);
+ height = tile_manager_height (level);
+
+ xcf_write_int32_check_error (info, (TQ_INT32 *) &width, 1);
+ xcf_write_int32_check_error (info, (TQ_INT32 *) &height, 1);
+
+ saved_pos = info->cp;
+
+ /* allocate a temporary buffer to store the rle data before it is
+ written to disk */
+ rlebuf =
+ g_malloc (TILE_WIDTH * TILE_HEIGHT * tile_manager_bpp (level) * 1.5);
+
+ if (level->tiles)
+ {
+ ntiles = level->ntile_rows * level->ntile_cols;
+ xcf_check_error (xcf_seek_pos (info, info->cp + (ntiles + 1) * 4, error));
+
+ for (i = 0; i < ntiles; i++)
+ {
+ /* save the start offset of where we are writing
+ * out the next tile.
+ */
+ offset = info->cp;
+
+ /* write out the tile. */
+ switch (info->compression)
+ {
+ case COMPRESS_NONE:
+ xcf_check_error(xcf_save_tile (info, level->tiles[i], error));
+ break;
+ case COMPRESS_RLE:
+ xcf_check_error (xcf_save_tile_rle (info, level->tiles[i],
+ rlebuf, error));
+ break;
+ case COMPRESS_ZLIB:
+ g_error ("xcf: zlib compression unimplemented");
+ break;
+ case COMPRESS_FRACTAL:
+ g_error ("xcf: fractal compression unimplemented");
+ break;
+ }
+
+ /* seek back to where we are to write out the next
+ * tile offset and write it out.
+ */
+ xcf_check_error (xcf_seek_pos (info, saved_pos, error));
+ xcf_write_int32_check_error (info, &offset, 1);
+
+ /* increment the location we are to write out the
+ * next offset.
+ */
+ saved_pos = info->cp;
+
+ /* seek to the end of the file which is where
+ * we will write out the next tile.
+ */
+ xcf_check_error (xcf_seek_end (info, error));
+ }
+ }
+
+ g_free (rlebuf);
+
+ /* write out a '0' offset position to indicate the end
+ * of the level offsets.
+ */
+ offset = 0;
+ xcf_check_error (xcf_seek_pos (info, saved_pos, error));
+ xcf_write_int32_check_error (info, &offset, 1);
+
+ return TRUE;
+
+}
+
+static bool
+xcf_save_tile (XcfInfo *info,
+ Tile *tile,
+ GError **error)
+{
+ GError *tmp_error = NULL;
+
+ tile_lock (tile);
+ xcf_write_int8_check_error (info, tile_data_pointer (tile, 0, 0),
+ tile_size (tile));
+ tile_release (tile, FALSE);
+
+ return TRUE;
+}
+
+static bool
+xcf_save_tile_rle (XcfInfo *info,
+ Tile *tile,
+ guchar *rlebuf,
+ GError **error)
+{
+ guchar *data, *t;
+ unsigned int last;
+ TQ_INT32 state;
+ TQ_INT32 length;
+ TQ_INT32 count;
+ TQ_INT32 size;
+ TQ_INT32 bpp;
+ TQ_INT32 i, j;
+ TQ_INT32 len = 0;
+
+ GError *tmp_error = NULL;
+
+ tile_lock (tile);
+
+ bpp = tile_bpp (tile);
+
+ for (i = 0; i < bpp; i++)
+ {
+ data = (guchar*) tile_data_pointer (tile, 0, 0) + i;
+
+ state = 0;
+ length = 0;
+ count = 0;
+ size = tile_ewidth(tile) * tile_eheight(tile);
+ last = -1;
+
+ while (size > 0)
+ {
+ switch (state)
+ {
+ case 0:
+ /* in state 0 we try to find a long sequence of
+ * matching values.
+ */
+ if ((length == 32768) ||
+ ((size - length) <= 0) ||
+ ((length > 1) && (last != *data)))
+ {
+ count += length;
+ if (length >= 128)
+ {
+ rlebuf[len++] = 127;
+ rlebuf[len++] = (length >> 8);
+ rlebuf[len++] = length & 0x00FF;
+ rlebuf[len++] = last;
+ }
+ else
+ {
+ rlebuf[len++] = length - 1;
+ rlebuf[len++] = last;
+ }
+ size -= length;
+ length = 0;
+ }
+ else if ((length == 1) && (last != *data))
+ state = 1;
+ break;
+
+ case 1:
+ /* in state 1 we try and find a long sequence of
+ * non-matching values.
+ */
+ if ((length == 32768) ||
+ ((size - length) == 0) ||
+ ((length > 0) && (last == *data) &&
+ ((size - length) == 1 || last == data[bpp])))
+ {
+ count += length;
+ state = 0;
+
+ if (length >= 128)
+ {
+ rlebuf[len++] = 255 - 127;
+ rlebuf[len++] = (length >> 8);
+ rlebuf[len++] = length & 0x00FF;
+ }
+ else
+ {
+ rlebuf[len++] = 255 - (length - 1);
+ }
+
+ t = data - length * bpp;
+ for (j = 0; j < length; j++)
+ {
+ rlebuf[len++] = *t;
+ t += bpp;
+ }
+
+ size -= length;
+ length = 0;
+ }
+ break;
+ }
+
+ if (size > 0) {
+ length += 1;
+ last = *data;
+ data += bpp;
+ }
+ }
+
+ if (count != (tile_ewidth (tile) * tile_eheight (tile)))
+ g_message ("xcf: uh oh! xcf rle tile saving error: %d", count);
+ }
+ xcf_write_int8_check_error (info, rlebuf, len);
+ tile_release (tile, FALSE);
+
+ return TRUE;
+}
+
+static bool
+xcf_save_parasite (XcfInfo *info,
+ KisAnnotation *parasite,
+ GError **error)
+{
+ if (gimp_parasite_is_persistent (parasite))
+ {
+ GError *tmp_error = NULL;
+
+ xcf_write_string_check_error (info, &parasite->name, 1);
+ xcf_write_int32_check_error (info, &parasite->flags, 1);
+ xcf_write_int32_check_error (info, &parasite->size, 1);
+ xcf_write_int8_check_error (info, parasite->data, parasite->size);
+ }
+
+ return TRUE;
+}
+
+typedef struct
+{
+ XcfInfo *info;
+ GError *error;
+} XcfParasiteData;
+
+static void
+xcf_save_parasite_func (TQCString *key,
+ KisAnnotation *parasite,
+ XcfParasiteData *data)
+{
+ if (! data->error)
+ xcf_save_parasite (data->info, parasite, &data->error);
+}
+
+static bool
+xcf_save_parasite_list (XcfInfo *info,
+ KisAnnotationList *list,
+ GError **error)
+{
+ XcfParasiteData data;
+
+ data.info = info;
+ data.error = NULL;
+
+ gimp_parasite_list_foreach (list, (GHFunc) xcf_save_parasite_func, &data);
+
+ if (data.error)
+ {
+ g_propagate_error (error, data.error);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static bool
+xcf_save_old_paths (XcfInfo *info,
+ KisImage *gimage,
+ GError **error)
+{
+ GimpVectors *active_vectors;
+ TQ_INT32 num_paths;
+ TQ_INT32 active_index = 0;
+ GList *list;
+ GError *tmp_error = NULL;
+
+ /* Write out the following:-
+ *
+ * last_selected_row (TQ_INT32)
+ * number_of_paths (TQ_INT32)
+ *
+ * then each path:-
+ */
+
+ num_paths = gimp_container_num_tqchildren (gimage->vectors);
+
+ active_vectors = gimp_image_get_active_vectors (gimage);
+
+ if (active_vectors)
+ active_index = gimp_container_get_child_index (gimage->vectors,
+ GIMP_OBJECT (active_vectors));
+
+ xcf_write_int32_check_error (info, &active_index, 1);
+ xcf_write_int32_check_error (info, &num_paths, 1);
+
+ for (list = GIMP_LIST (gimage->vectors)->list;
+ list;
+ list = g_list_next (list))
+ {
+ GimpVectors *vectors = list->data;
+ TQCString *name;
+ TQ_INT32 locked;
+ TQ_UINT8 state;
+ TQ_INT32 version;
+ TQ_INT32 pathtype;
+ TQ_INT32 tattoo;
+ GimpVectorsCompatPoint *points;
+ TQ_INT3232 num_points;
+ TQ_INT3232 closed;
+ TQ_INT32 i;
+
+ /*
+ * name (string)
+ * locked (TQ_INT32)
+ * state (TQCString)
+ * closed (TQ_INT32)
+ * number points (TQ_INT32)
+ * version (TQ_INT32)
+ * pathtype (TQ_INT32)
+ * tattoo (TQ_INT32)
+ * then each point.
+ */
+
+ points = gimp_vectors_compat_get_points (vectors, &num_points, &closed);
+
+ /* if no points are generated because of a faulty path we should
+ * skip saving the path - this is unfortunately impossible, because
+ * we already saved the number of paths and I wont start seeking
+ * around to fix that cruft */
+
+ name = (TQCString *) gimp_object_get_name (GIMP_OBJECT (vectors));
+ locked = gimp_item_get_linked (GIMP_ITEM (vectors));
+ state = closed ? 4 : 2; /* EDIT : ADD (editing state, 1.2 compat) */
+ version = 3;
+ pathtype = 1; /* BEZIER (1.2 compat) */
+ tattoo = gimp_item_get_tattoo (GIMP_ITEM (vectors));
+
+ xcf_write_string_check_error (info, &name, 1);
+ xcf_write_int32_check_error (info, &locked, 1);
+ xcf_write_int8_check_error (info, &state, 1);
+ xcf_write_int32_check_error (info, &closed, 1);
+ xcf_write_int32_check_error (info, &num_points, 1);
+ xcf_write_int32_check_error (info, &version, 1);
+ xcf_write_int32_check_error (info, &pathtype, 1);
+ xcf_write_int32_check_error (info, &tattoo, 1);
+
+ for (i = 0; i < num_points; i++)
+ {
+ float x;
+ float y;
+
+ x = points[i].x;
+ y = points[i].y;
+
+ /*
+ * type (TQ_INT32)
+ * x (float)
+ * y (float)
+ */
+
+ xcf_write_int32_check_error (info, &points[i].type, 1);
+ xcf_write_float_check_error (info, &x, 1);
+ xcf_write_float_check_error (info, &y, 1);
+ }
+
+ g_free (points);
+ }
+
+ return TRUE;
+}
+
+static bool
+xcf_save_vectors (XcfInfo *info,
+ KisImage *gimage,
+ GError **error)
+{
+ GimpVectors *active_vectors;
+ TQ_INT32 version = 1;
+ TQ_INT32 active_index = 0;
+ TQ_INT32 num_paths;
+ GList *list;
+ GList *stroke_list;
+ GError *tmp_error = NULL;
+
+ /* Write out the following:-
+ *
+ * version (TQ_INT32)
+ * active_index (TQ_INT32)
+ * num_paths (TQ_INT32)
+ *
+ * then each path:-
+ */
+
+ active_vectors = gimp_image_get_active_vectors (gimage);
+
+ if (active_vectors)
+ active_index = gimp_container_get_child_index (gimage->vectors,
+ GIMP_OBJECT (active_vectors));
+
+ num_paths = gimp_container_num_tqchildren (gimage->vectors);
+
+ xcf_write_int32_check_error (info, &version, 1);
+ xcf_write_int32_check_error (info, &active_index, 1);
+ xcf_write_int32_check_error (info, &num_paths, 1);
+
+ for (list = GIMP_LIST (gimage->vectors)->list;
+ list;
+ list = g_list_next (list))
+ {
+ GimpVectors *vectors = list->data;
+ KisAnnotationList *parasites;
+ TQCString *name;
+ TQ_INT32 tattoo;
+ TQ_INT32 visible;
+ TQ_INT32 linked;
+ TQ_INT32 num_parasites;
+ TQ_INT32 num_strokes;
+
+ /*
+ * name (string)
+ * tattoo (TQ_INT32)
+ * visible (TQ_INT32)
+ * linked (TQ_INT32)
+ * num_parasites (TQ_INT32)
+ * num_strokes (TQ_INT32)
+ *
+ * then each parasite
+ * then each stroke
+ */
+
+ parasites = GIMP_ITEM (vectors)->parasites;
+
+ name = (TQCString *) gimp_object_get_name (GIMP_OBJECT (vectors));
+ visible = gimp_item_get_visible (GIMP_ITEM (vectors));
+ linked = gimp_item_get_linked (GIMP_ITEM (vectors));
+ tattoo = gimp_item_get_tattoo (GIMP_ITEM (vectors));
+ num_parasites = gimp_parasite_list_persistent_length (parasites);
+ num_strokes = g_list_length (vectors->strokes);
+
+ xcf_write_string_check_error (info, &name, 1);
+ xcf_write_int32_check_error (info, &tattoo, 1);
+ xcf_write_int32_check_error (info, &visible, 1);
+ xcf_write_int32_check_error (info, &linked, 1);
+ xcf_write_int32_check_error (info, &num_parasites, 1);
+ xcf_write_int32_check_error (info, &num_strokes, 1);
+
+ xcf_check_error (xcf_save_parasite_list (info, parasites, error));
+
+ for (stroke_list = g_list_first (vectors->strokes);
+ stroke_list;
+ stroke_list = g_list_next (stroke_list))
+ {
+ GimpStroke *stroke;
+ TQ_INT32 stroke_type;
+ TQ_INT32 closed;
+ TQ_INT32 num_axes;
+ GArray *control_points;
+ TQ_INT32 i;
+
+ TQ_INT32 type;
+ float coords[6];
+
+ /*
+ * stroke_type (TQ_INT32)
+ * closed (TQ_INT32)
+ * num_axes (TQ_INT32)
+ * num_control_points (TQ_INT32)
+ *
+ * then each control point.
+ */
+
+ stroke = GIMP_STROKE (stroke_list->data);
+
+ if (GIMP_IS_BEZIER_STROKE (stroke))
+ {
+ stroke_type = XCF_STROKETYPE_BEZIER_STROKE;
+ num_axes = 2; /* hardcoded, might be increased later */
+ }
+ else
+ {
+ g_printerr ("Skipping unknown stroke type!\n");
+ continue;
+ }
+
+ control_points = gimp_stroke_control_points_get (stroke, &closed);
+
+ xcf_write_int32_check_error (info, &stroke_type, 1);
+ xcf_write_int32_check_error (info, &closed, 1);
+ xcf_write_int32_check_error (info, &num_axes, 1);
+ xcf_write_int32_check_error (info, &control_points->len, 1);
+
+ for (i = 0; i < control_points->len; i++)
+ {
+ GimpAnchor *anchor;
+
+ anchor = & (g_array_index (control_points, GimpAnchor, i));
+
+ type = anchor->type;
+ coords[0] = anchor->position.x;
+ coords[1] = anchor->position.y;
+ coords[2] = anchor->position.pressure;
+ coords[3] = anchor->position.xtilt;
+ coords[4] = anchor->position.ytilt;
+ coords[5] = anchor->position.wheel;
+
+ /*
+ * type (TQ_INT32)
+ *
+ * the first num_axis elements of:
+ * [0] x (float)
+ * [1] y (float)
+ * [2] pressure (float)
+ * [3] xtilt (float)
+ * [4] ytilt (float)
+ * [5] wheel (float)
+ */
+
+ xcf_write_int32_check_error (info, &type, 1);
+ xcf_write_float_check_error (info, coords, num_axes);
+ }
+
+ g_array_free (control_points, TRUE);
+ }
+ }
+
+ return TRUE;
+}
diff --git a/filters/chalk/xcf/xcf/xcf-save.h b/filters/chalk/xcf/xcf/xcf-save.h
new file mode 100644
index 00000000..cc49d2d3
--- /dev/null
+++ b/filters/chalk/xcf/xcf/xcf-save.h
@@ -0,0 +1,29 @@
+/* The GIMP -- an image manipulation program
+ * Copyright (C) 1995 Spencer Kimball and Peter Mattis
+ *
+ * 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 of the License, 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 __XCF_SAVE_H__
+#define __XCF_SAVE_H__
+
+
+void xcf_save_choose_format (XcfInfo *info,
+ KisImage *gimage);
+TQ_INT32 xcf_save_image (XcfInfo *info,
+ KisImage *gimage);
+
+
+#endif /* __XCF_SAVE_H__ */
diff --git a/filters/chalk/xcf/xcf/xcf-seek.cc b/filters/chalk/xcf/xcf/xcf-seek.cc
new file mode 100644
index 00000000..a24271f5
--- /dev/null
+++ b/filters/chalk/xcf/xcf/xcf-seek.cc
@@ -0,0 +1,79 @@
+/* The GIMP -- an image manipulation program
+ * Copyright (C) 1995 Spencer Kimball and Peter Mattis
+ *
+ * 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 of the License, 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 <stdio.h>
+#include <errno.h>
+
+#include <glib-object.h>
+
+#include "core/core-types.h"
+
+#include "xcf-private.h"
+#include "xcf-seek.h"
+
+#include "gimp-intl.h"
+
+bool
+xcf_seek_pos (XcfInfo *info,
+ TQ_UINT32 pos,
+ GError **error)
+{
+ if (info->cp != pos)
+ {
+ info->cp = pos;
+ if (fseek (info->fp, info->cp, SEEK_SET) == -1)
+ {
+ g_set_error (error, G_FILE_ERROR, g_file_error_from_errno (errno),
+ _("Could not seek in XCF file: %s"),
+ g_strerror (errno));
+
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+}
+
+bool
+xcf_seek_end (XcfInfo *info,
+ GError **error)
+{
+ if (fseek (info->fp, 0, SEEK_END) == -1)
+ {
+ g_set_error (error, G_FILE_ERROR, g_file_error_from_errno (errno),
+ _("Could not seek in XCF file: %s"),
+ g_strerror (errno));
+
+ return FALSE;
+ }
+
+ info->cp = ftell (info->fp);
+
+ if (fseek (info->fp, 0, SEEK_END) == -1)
+ {
+ g_set_error (error, G_FILE_ERROR, g_file_error_from_errno (errno),
+ _("Could not seek in XCF file: %s"),
+ g_strerror (errno));
+
+ return FALSE;
+ }
+
+ return TRUE;
+}
diff --git a/filters/chalk/xcf/xcf/xcf-seek.h b/filters/chalk/xcf/xcf/xcf-seek.h
new file mode 100644
index 00000000..1bb7b7a9
--- /dev/null
+++ b/filters/chalk/xcf/xcf/xcf-seek.h
@@ -0,0 +1,30 @@
+/* The GIMP -- an image manipulation program
+ * Copyright (C) 1995 Spencer Kimball and Peter Mattis
+ *
+ * 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 of the License, 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 __XCF_SEEK_H__
+#define __XCF_SEEK_H__
+
+
+bool xcf_seek_pos (XcfInfo *info,
+ TQ_UINT32 pos,
+ GError **error);
+bool xcf_seek_end (XcfInfo *info,
+ GError **error);
+
+
+#endif /* __XCF_SEEK_H__ */
diff --git a/filters/chalk/xcf/xcf/xcf-write.cc b/filters/chalk/xcf/xcf/xcf-write.cc
new file mode 100644
index 00000000..4010ab18
--- /dev/null
+++ b/filters/chalk/xcf/xcf/xcf-write.cc
@@ -0,0 +1,104 @@
+/* The GIMP -- an image manipulation program
+ * Copyright (C) 1995 Spencer Kimball and Peter Mattis
+ *
+ * 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 of the License, 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 <stdio.h>
+#include <string.h> /* strlen */
+#include <errno.h>
+
+#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+
+#include <netinet/in.h>
+#include <limits.h>
+#include <stdlib.h>
+#include <cfloat>
+
+#include "xcf-write.h"
+
+TQ_UINT32 xcf_write_int32 (FILE *fp, TQ_INT32 *data, TQ_INT32 count);
+{
+ TQ_INT32 tmp;
+ TQ_INT32 i;
+
+ if (count > 0)
+ {
+ for (i = 0; i < count; i++)
+ {
+ tmp = htonl (data[i]);
+ xcf_write_int8 (fp, (TQ_UINT8*) &tmp, 4);
+
+ if (fp->status() != IO_Ok)
+ {
+ return i * 4;
+ }
+ }
+ }
+
+ return count * 4;
+}
+
+TQ_UINT32 xcf_write_float (FILE *fp, float *data, TQ_INT32 count);
+{
+ return xcf_write_int32 (fp, (TQ_INT32 *)((void *)data), count, error);
+}
+
+TQ_UINT32 xcf_write_int8 (FILE *fp, TQ_UINT8 *data, TQ_INT32 count);
+{
+ TQ_INT32 bytes;
+ bytes = fp->writeBlock( data, count );
+ return bytes;
+}
+
+TQ_UINT32 xcf_write_string (FILE *fp, TQCString *data, TQ_INT32 count);
+{
+ GError *tmp_error = NULL;
+ TQ_INT32 tmp;
+ TQ_UINT32 total;
+ TQ_INT32 i;
+
+ total = 0;
+ for (i = 0; i < count; i++)
+ {
+ if (data[i])
+ tmp = strlen (data[i]) + 1;
+ else
+ tmp = 0;
+
+ xcf_write_int32 (fp, &tmp, 1, &tmp_error);
+ if (tmp_error)
+ {
+ g_propagate_error (error, tmp_error);
+ return total;
+ }
+
+ if (tmp > 0)
+ xcf_write_int8 (fp, (TQ_UINT8*) data[i], tmp, &tmp_error);
+ if (tmp_error)
+ {
+ g_propagate_error (error, tmp_error);
+ return total;
+ }
+
+ total += 4 + tmp;
+ }
+
+ return total;
+}
diff --git a/filters/chalk/xcf/xcf/xcf-write.h b/filters/chalk/xcf/xcf/xcf-write.h
new file mode 100644
index 00000000..8e21a08e
--- /dev/null
+++ b/filters/chalk/xcf/xcf/xcf-write.h
@@ -0,0 +1,39 @@
+/* The GIMP -- an image manipulation program
+ * Copyright (C) 1995 Spencer Kimball and Peter Mattis
+ *
+ * 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 of the License, 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 __XCF_WRITE_H__
+#define __XCF_WRITE_H__
+
+#include <tqstring.h>
+#include <tqstringlist.h>
+#include <tqfile.h>
+
+// Write count integers to the file
+TQ_UINT32 xcf_write_int32 (TQFile *fp, TQ_INT32 *data, TQ_INT32 count);
+
+// Write count of floats to the file
+TQ_UINT32 xcf_write_float (TQFile *fp, float *data, TQ_INT32 count);
+
+// Write count chars to the file
+TQ_UINT32 xcf_write_int8 (TQFile *fp, TQ_UINT8 *data, TQ_INT32 count);
+
+// Write count zero-terminated strings to the file, each string preceded by its length as an integer
+TQ_UINT32 xcf_write_string (TQFile *fp, TQCString *data, TQ_INT32 count);
+
+
+#endif /* __XCF_WRITE_H__ */
diff --git a/filters/chalk/xcf/xcfexport.cpp b/filters/chalk/xcf/xcfexport.cpp
new file mode 100644
index 00000000..b26fdba8
--- /dev/null
+++ b/filters/chalk/xcf/xcfexport.cpp
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2005 Boudewijn Rempt <[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 of the License, 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 <xcfexport.h>
+
+#include <kurl.h>
+#include <kgenericfactory.h>
+
+#include <KoDocument.h>
+#include <KoFilterChain.h>
+
+#include <kis_doc.h>
+#include <kis_image.h>
+#include <kis_annotation.h>
+#include <kis_types.h>
+#include <kis_xcf_converter.h>
+
+typedef KGenericFactory<XCFExport, KoFilter> XCFExportFactory;
+K_EXPORT_COMPONENT_FACTORY(libchalkxcfexport, XCFExportFactory("kofficefilters"))
+
+XCFExport::XCFExport(KoFilter *, const char *, const TQStringList&) : KoFilter()
+{
+}
+
+XCFExport::~XCFExport()
+{
+}
+
+KoFilter::ConversiontqStatus XCFExport::convert(const TQCString& from, const TQCString& to)
+{
+ kdDebug(41008) << "xcf export! From: " << from << ", To: " << to << "\n";
+
+ if (from != "application/x-chalk")
+ return KoFilter::NotImplemented;
+
+ KisDoc *output = dynamic_cast<KisDoc*>(m_chain->inputDocument());
+ TQString filename = m_chain->outputFile();
+
+ if (!output)
+ return KoFilter::CreationError;
+
+
+ if (filename.isEmpty()) return KoFilter::FileNotFound;
+
+ KURL url(filename);
+
+ KisImageSP img = output->currentImage();
+ if (!img) return KoFilter::ParsingError;
+
+ KisXCFConverter ib(output, output->undoAdapter());
+
+ vKisAnnotationSP_it beginIt = img->beginAnnotations();
+ vKisAnnotationSP_it endIt = img->endAnnotations();
+
+ if (ib.buildFile(url, img, beginIt, endIt) == KisImageBuilder_RESULT_OK) {
+ return KoFilter::OK;
+ }
+
+ return KoFilter::InternalError;
+}
+
+#include <xcfexport.moc>
+
diff --git a/filters/chalk/xcf/xcfexport.h b/filters/chalk/xcf/xcfexport.h
new file mode 100644
index 00000000..b6acf737
--- /dev/null
+++ b/filters/chalk/xcf/xcfexport.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2005 Boudewijn Rempt <[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 of the License, 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 XCFEXPORT_H_
+#define XCFEXPORT_H_
+
+#include <KoFilter.h>
+
+class XCFExport : public KoFilter {
+ Q_OBJECT
+ TQ_OBJECT
+
+public:
+ XCFExport(KoFilter *tqparent, const char *name, const TQStringList&);
+ virtual ~XCFExport();
+
+public:
+ virtual KoFilter::ConversiontqStatus convert(const TQCString& from, const TQCString& to);
+};
+
+#endif // XCFEXPORT_H_
+
diff --git a/filters/chalk/xcf/xcfimport.cpp b/filters/chalk/xcf/xcfimport.cpp
new file mode 100644
index 00000000..6f07ebcf
--- /dev/null
+++ b/filters/chalk/xcf/xcfimport.cpp
@@ -0,0 +1,99 @@
+/*
+ * Copyright (c) 2005 Boudewijn Rempt <[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 of the License, 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 <tqstring.h>
+
+#include <xcfimport.h>
+#include <kgenericfactory.h>
+#include <KoDocument.h>
+#include <KoFilterChain.h>
+
+#include <kis_doc.h>
+#include <kis_view.h>
+#include <kis_xcf_converter.h>
+#include <kis_progress_display_interface.h>
+
+typedef KGenericFactory<XCFImport, KoFilter> XCFImportFactory;
+K_EXPORT_COMPONENT_FACTORY(libchalkxcfimport, XCFImportFactory("kofficefilters"))
+
+XCFImport::XCFImport(KoFilter *, const char *, const TQStringList&) : KoFilter()
+{
+}
+
+XCFImport::~XCFImport()
+{
+}
+
+KoFilter::ConversiontqStatus XCFImport::convert(const TQCString&, const TQCString& to)
+{
+ kdDebug(41008) << "Importing using XCFImport!\n";
+
+ if (to != "application/x-chalk")
+ return KoFilter::BadMimeType;
+
+ KisDoc * doc = dynamic_cast<KisDoc*>(m_chain -> outputDocument());
+ KisView * view = static_cast<KisView*>(doc -> views().getFirst());
+
+ TQString filename = m_chain -> inputFile();
+
+ if (!doc)
+ return KoFilter::CreationError;
+
+ doc -> prepareForImport();
+
+
+ if (!filename.isEmpty()) {
+
+ KURL url(filename);
+
+ if (url.isEmpty())
+ return KoFilter::FileNotFound;
+
+ KisXCFConverter ib(doc, doc -> undoAdapter());
+
+ switch (ib.buildImage(url)) {
+ case KisImageBuilder_RESULT_UNSUPPORTED:
+ return KoFilter::NotImplemented;
+ break;
+ case KisImageBuilder_RESULT_INVALID_ARG:
+ return KoFilter::BadMimeType;
+ break;
+ case KisImageBuilder_RESULT_NO_URI:
+ case KisImageBuilder_RESULT_NOT_LOCAL:
+ return KoFilter::FileNotFound;
+ break;
+ case KisImageBuilder_RESULT_BAD_FETCH:
+ case KisImageBuilder_RESULT_EMPTY:
+ return KoFilter::ParsingError;
+ break;
+ case KisImageBuilder_RESULT_FAILURE:
+ return KoFilter::InternalError;
+ break;
+ case KisImageBuilder_RESULT_OK:
+ doc -> setCurrentImage( ib.image());
+ return KoFilter::OK;
+ default:
+ break;
+ }
+
+ }
+ return KoFilter::StorageCreationError;
+}
+
+#include <xcfimport.moc>
+
diff --git a/filters/chalk/xcf/xcfimport.h b/filters/chalk/xcf/xcfimport.h
new file mode 100644
index 00000000..038e7604
--- /dev/null
+++ b/filters/chalk/xcf/xcfimport.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2005 Boudewijn Rempt <[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 of the License, 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 XCFIMPORT_H_
+#define XCFIMPORT_H_
+
+#include <KoFilter.h>
+
+class XCFImport : public KoFilter {
+ Q_OBJECT
+ TQ_OBJECT
+
+public:
+ XCFImport(KoFilter *tqparent, const char *name, const TQStringList&);
+ virtual ~XCFImport();
+
+public:
+ virtual KoFilter::ConversiontqStatus convert(const TQCString& from, const TQCString& to);
+};
+
+#endif // XCFIMPORT_H_
+