/* Cataract - Static web photo gallery generator * Copyright (C) 2008 Tomas Bzatek * * 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 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 #include #include #include #include #include #include #include #include #include "gallery-utils.h" #include "setup.h" #include "xml-parser.h" /* * find_setup_xml: try to find setup.xml in standard paths */ TGallerySetup * find_setup_xml () { gchar *pth; gchar *cwd; TGallerySetup *setup = NULL; cwd = g_get_current_dir (); /* Prefer setup2.xml over setup.xml but only in current working directory */ pth = g_build_filename (cwd, SETUP_V2_XML, NULL); if (g_access (pth, R_OK) == 0) setup = parse_setup_xml (pth); g_free (pth); if (! setup) { pth = g_build_filename (cwd, SETUP_XML, NULL); if (g_access (pth, R_OK) == 0) setup = parse_setup_xml (pth); g_free (pth); } g_free (cwd); if (! setup) { pth = g_build_filename (g_getenv ("HOME"), ".cgg", SETUP_XML, NULL); if (g_access (pth, R_OK) == 0) setup = parse_setup_xml (pth); g_free (pth); } if (! setup) { pth = g_build_filename (DATADIR, "cgg", SETUP_XML, NULL); if (g_access (pth, R_OK) == 0) setup = parse_setup_xml (pth); g_free (pth); } return setup; } /* * parse_setup_xml: XML parser for setup.xml file */ TGallerySetup * parse_setup_xml (const gchar *filename) { TXMLFile *xml; TGallerySetup *setup; xml = xml_parser_load (filename); if (xml == NULL) return NULL; setup = g_malloc0 (sizeof (TGallerySetup)); setup->setup_xml_path = g_strdup (filename); setup->version = nearbyint (xml_file_get_node_attribute_double_with_default (xml, "/gallery_setup", "version", -1) * 100); /* design section */ setup->design_setup_file = xml_file_get_node_value (xml, "/gallery_setup/design/setup_file/text()"); setup->supplemental_files_use_common_root = xml_file_get_node_attribute_boolean_with_default (xml, "/gallery_setup/design/supplemental_files_use_common_root", "value", FALSE); /* images section */ setup->preload = xml_file_get_node_attribute_boolean_with_default (xml, "/gallery_setup/images/preload", "value", TRUE); setup->use_iptc_exif = xml_file_get_node_attribute_boolean_with_default (xml, "/gallery_setup/images/use_iptc_exif", "value", FALSE); setup->erase_exif_thumbnail = xml_file_get_node_attribute_boolean_with_default (xml, "/gallery_setup/images/erase_embed_thumbnail", "value", FALSE); setup->strip_xmp = xml_file_get_node_attribute_boolean_with_default (xml, "/gallery_setup/images/strip_xmp", "value", TRUE); setup->write_supplied_exif = xml_file_get_node_attribute_boolean_with_default (xml, "/gallery_setup/images/write_supplied_exif", "value", FALSE); setup->nofullsize = xml_file_get_node_present (xml, "/gallery_setup/images/nofullsize"); setup->autorotate = xml_file_get_node_attribute_boolean_with_default (xml, "/gallery_setup/images/autorotate", "value", TRUE); /* meta section */ setup->meta_author = xml_file_get_node_value (xml, "/gallery_setup/meta/author/text()"); setup->meta_author_email = xml_file_get_node_value (xml, "/gallery_setup/meta/author_email/text()"); setup->meta_description = xml_file_get_node_value (xml, "/gallery_setup/meta/description/text()"); setup->meta_keywords = xml_file_get_node_value (xml, "/gallery_setup/meta/keywords/text()"); setup->use_title_as_meta = xml_file_get_node_attribute_boolean_with_default (xml, "/gallery_setup/meta/use_title_as_meta", "value", TRUE); setup->site_title = xml_file_get_node_attribute (xml, "/gallery_setup/meta/site", "title"); setup->add_copyright = xml_file_get_node_value (xml, "/gallery_setup/meta/add_copyright/text()"); setup->favicon_file = xml_file_get_node_value (xml, "/gallery_setup/meta/favicon/text()"); setup->favicon_type = xml_file_get_node_attribute (xml, "/gallery_setup/meta/favicon", "type"); /* navigation section */ setup->use_inpage_links = xml_file_get_node_attribute_boolean_with_default (xml, "/gallery_setup/navigation/use_inpage_links", "value", TRUE); /* feed section */ setup->feed_enabled = xml_file_get_node_attribute_boolean_with_default (xml, "/gallery_setup/feed", "enable", FALSE); setup->feed_filename = xml_file_get_node_value (xml, "/gallery_setup/feed/filename/text()"); setup->feed_title = xml_file_get_node_value (xml, "/gallery_setup/feed/title/text()"); /* location section */ setup->location_base_url = xml_file_get_node_value (xml, "/gallery_setup/location/base_url/text()"); setup->location_local_path = xml_file_get_node_value (xml, "/gallery_setup/location/local_path/text()"); /* footer section */ setup->footer = xml_file_get_node_value (xml, "/gallery_setup/footer/text()"); /* legacy mode */ if (SETUP_IS_LEGACY (setup)) { setup->design_setup_file = xml_file_get_node_value (xml, "/gallery_setup/templates/path/text()"); setup->supplemental_files_use_common_root = xml_file_get_node_attribute_boolean_with_default (xml, "/gallery_setup/templates/support_files_use_common_root", "value", FALSE); setup->location_base_url = xml_file_get_node_value (xml, "/gallery_setup/feed/base_url/text()"); } xml_parser_free (xml); return setup; } /* * parse_design_setup_xml: XML parser for design.xml file */ TGalleryDesign * parse_design_setup_xml (const gchar *filename) { TXMLFile *xml; gchar *s; gchar *s2; gchar *s3; TGalleryDesign *design; TImageSize *image_size; TGalleryDesignTheme *theme; int count, c; int i, j; xml = xml_parser_load (filename); if (xml == NULL) return NULL; design = g_malloc0 (sizeof (TGalleryDesign)); design->version = nearbyint (xml_file_get_node_attribute_double_with_default (xml, "/design_setup", "version", -1) * 100); s2 = xml_file_get_node_value (xml, "/design_setup/supplemental_files/text()"); if (s2) { design->supplemental_files = g_strsplit (s2, "\n", -1); g_free (s2); } /* image_sizes section */ count = xml_file_node_get_children_count (xml, "/design_setup/image_sizes/size"); for (i = 0; i < count; i++) { s = g_strdup_printf ("/design_setup/image_sizes/size[%d]", i + 1); s2 = xml_file_get_node_attribute (xml, s, "name"); if (s2 == NULL || strlen (s2) == 0) { fprintf (stderr, "design setup error: image size #%d defined with no name, ignoring\n", i + 1); g_free (s); g_free (s2); continue; } image_size = g_malloc0 (sizeof (TImageSize)); design->image_sizes = g_list_append (design->image_sizes, image_size); image_size->name = s2; s2 = xml_file_get_node_attribute (xml, s, "type"); if (s2 && g_ascii_strcasecmp (s2, "thumbnail") == 0) image_size->is_thumbnail = TRUE; g_free (s2); image_size->thumb_crop_style = CROP_STYLE_NORMAL; if (image_size->is_thumbnail) { s2 = xml_file_get_node_attribute (xml, s, "style"); if (s2 && g_ascii_strcasecmp (s2, "squared") == 0) image_size->thumb_crop_style = CROP_STYLE_SQUARED; else if (s2 && g_ascii_strcasecmp (s2, "fixed") == 0) image_size->thumb_crop_style = CROP_STYLE_FIXED; g_free (s2); } g_free (s); s = g_strdup_printf ("/design_setup/image_sizes/size[%d]/no_resize", i + 1); image_size->no_resize = xml_file_get_node_present (xml, s); g_free (s); s = g_strdup_printf ("/design_setup/image_sizes/size[%d]/landscape", i + 1); image_size->landscape_width = xml_file_get_node_attribute_long_with_default (xml, s, "w", 0); image_size->landscape_height = xml_file_get_node_attribute_long_with_default (xml, s, "h", 0); g_free (s); s = g_strdup_printf ("/design_setup/image_sizes/size[%d]/portrait", i + 1); image_size->portrait_width = xml_file_get_node_attribute_long_with_default (xml, s, "w", 0); image_size->portrait_height = xml_file_get_node_attribute_long_with_default (xml, s, "h", 0); g_free (s); s = g_strdup_printf ("/design_setup/image_sizes/size[%d]/square", i + 1); image_size->square_size = xml_file_get_node_attribute_long_with_default (xml, s, "size", 0); g_free (s); s = g_strdup_printf ("/design_setup/image_sizes/size[%d]/crop", i + 1); image_size->crop_width = xml_file_get_node_attribute_long_with_default (xml, s, "w", 0); image_size->crop_height = xml_file_get_node_attribute_long_with_default (xml, s, "h", 0); g_free (s); s = g_strdup_printf ("/design_setup/image_sizes/size[%d]/quality", i + 1); image_size->quality = xml_file_get_node_attribute_long_with_default (xml, s, "value", -1); g_free (s); s = g_strdup_printf ("/design_setup/image_sizes/size[%d]/no_resize", i + 1); image_size->no_resize = xml_file_get_node_present (xml, s); g_free (s); } /* theme section */ count = xml_file_node_get_children_count (xml, "/design_setup/theme"); for (i = 0; i < count; i++) { theme = g_malloc0 (sizeof (TGalleryDesignTheme)); design->themes = g_list_append (design->themes, theme); s = g_strdup_printf ("/design_setup/theme[%d]", i + 1); theme->enabled = xml_file_get_node_attribute_boolean_with_default (xml, s, "enabled", TRUE); g_free (s); s = g_strdup_printf ("/design_setup/theme[%d]/index/template/text()", i + 1); theme->index_template = xml_file_get_node_value (xml, s); g_free (s); s = g_strdup_printf ("/design_setup/theme[%d]/index/target_filename/text()", i + 1); theme->index_filename = xml_file_get_node_value_with_default (xml, s, DEFAULT_INDEX_FILENAME); g_free (s); s = g_strdup_printf ("/design_setup/theme[%d]/index/thumbnail_size/text()", i + 1); theme->index_thumb_size = xml_file_get_node_value (xml, s); g_free (s); s = g_strdup_printf ("/design_setup/theme[%d]/index/protected_thumbnail/text()", i + 1); theme->index_protected_thumbnail = xml_file_get_node_value (xml, s); g_free (s); s = g_strdup_printf ("/design_setup/theme[%d]/album/template/text()", i + 1); theme->album_template = xml_file_get_node_value (xml, s); g_free (s); s = g_strdup_printf ("/design_setup/theme[%d]/album/target_filename/text()", i + 1); theme->album_filename = xml_file_get_node_value_with_default (xml, s, DEFAULT_INDEX_FILENAME); g_free (s); s = g_strdup_printf ("/design_setup/theme[%d]/album/picture_size/text()", i + 1); theme->album_image_size = xml_file_get_node_value (xml, s); g_free (s); s = g_strdup_printf ("/design_setup/theme[%d]/album/thumbnail_size/text()", i + 1); theme->album_thumb_size = xml_file_get_node_value (xml, s); g_free (s); s = g_strdup_printf ("/design_setup/theme[%d]/picture/template/text()", i + 1); theme->picture_template = xml_file_get_node_value (xml, s); g_free (s); s = g_strdup_printf ("/design_setup/theme[%d]/picture/target_filename/text()", i + 1); theme->picture_filename = xml_file_get_node_value (xml, s); g_free (s); s = g_strdup_printf ("/design_setup/theme[%d]/picture/picture_size/text()", i + 1); theme->picture_image_size = xml_file_get_node_value (xml, s); g_free (s); s = g_strdup_printf ("/design_setup/theme[%d]/supplemental_files/text()", i + 1); s2 = xml_file_get_node_value (xml, s); if (s2) { theme->supplemental_files = g_strsplit (s2, "\n", -1); g_free (s2); } g_free (s); theme->defines = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free); s = g_strdup_printf ("/design_setup/theme[%d]/define", i + 1); c = xml_file_node_get_children_count (xml, s); g_free (s); for (j = 0; j < c; j++) { s = g_strdup_printf ("/design_setup/theme[%d]/define[%d]", i + 1, j + 1); s2 = xml_file_get_node_attribute (xml, s, "name"); s3 = xml_file_get_node_attribute (xml, s, "value"); if (s2) g_hash_table_replace (theme->defines, s2, s3 ? s3 : g_strdup ("")); g_free (s); } } xml_parser_free (xml); return design; } /* * makeup_legacy_design: create design using legacy setup.xml file */ TGalleryDesign * makeup_legacy_design (const gchar *filename) { TXMLFile *xml; gchar *s; TGalleryDesign *design; TImageSize *image_size; TGalleryDesignTheme *theme; gboolean squared_thumbs; int i; const gchar * image_sizes[3] = { "thumbnail", "preview", "original" }; xml = xml_parser_load (filename); if (xml == NULL) return NULL; design = g_malloc0 (sizeof (TGalleryDesign)); s = xml_file_get_node_value (xml, "/gallery_setup/templates/template_files/text()"); if (s) { design->supplemental_files = g_strsplit (s, "\n", -1); g_free (s); } squared_thumbs = FALSE; s = xml_file_get_node_attribute (xml, "/gallery_setup/images/squared_thumbnails", "type"); if (s && g_ascii_strcasecmp (s, "simple") == 0) squared_thumbs = TRUE; g_free (s); /* image_sizes section */ for (i = 0; i < G_N_ELEMENTS (image_sizes); i++) { image_size = g_malloc0 (sizeof (TImageSize)); image_size->name = g_strdup (image_sizes[i]); s = g_strdup_printf ("/gallery_setup/images/%s", image_sizes[i]); image_size->landscape_width = xml_file_get_node_attribute_long_with_default (xml, s, "landscape_w", 0); image_size->landscape_height = xml_file_get_node_attribute_long_with_default (xml, s, "landscape_h", 0); image_size->portrait_width = xml_file_get_node_attribute_long_with_default (xml, s, "portrait_w", 0); image_size->portrait_height = xml_file_get_node_attribute_long_with_default (xml, s, "portrait_h", 0); image_size->square_size = xml_file_get_node_attribute_long_with_default (xml, s, "square", 0); image_size->quality = xml_file_get_node_attribute_long_with_default (xml, s, "quality", -1); image_size->no_resize = (i != 0); image_size->is_thumbnail = (i == 0); image_size->thumb_crop_style = ((i == 0) && squared_thumbs) ? CROP_STYLE_SQUARED : CROP_STYLE_NORMAL; g_free (s); design->image_sizes = g_list_append (design->image_sizes, image_size); } /* theme section */ theme = g_malloc0 (sizeof (TGalleryDesignTheme)); theme->enabled = TRUE; theme->index_template = xml_file_get_node_value (xml, "/gallery_setup/templates/index/text()"); if (g_strcmp0 (theme->index_template, "template-index.tmpl") == 0) { g_free (theme->index_template); theme->index_template = g_strdup ("template_index.html"); } theme->index_filename = xml_file_get_node_value_with_default (xml, "/gallery_setup/templates/index_file/text()", DEFAULT_INDEX_FILENAME); theme->index_thumb_size = g_strdup (image_sizes[0]); theme->index_protected_thumbnail = NULL; theme->album_template = xml_file_get_node_value (xml, "/gallery_setup/templates/album/text()"); if (g_strcmp0 (theme->album_template, "template-album.tmpl") == 0) { g_free (theme->album_template); theme->album_template = g_strdup ("template_album.html"); } theme->album_filename = xml_file_get_node_value_with_default (xml, "/gallery_setup/templates/index_file/text()", DEFAULT_INDEX_FILENAME); theme->album_image_size = g_strdup (image_sizes[1]); theme->album_thumb_size = g_strdup (image_sizes[0]); theme->picture_template = xml_file_get_node_value (xml, "/gallery_setup/templates/photo/text()"); if (g_strcmp0 (theme->picture_template, "template-view_photo.tmpl") == 0) { g_free (theme->picture_template); theme->picture_template = g_strdup ("template_picture.html"); } theme->picture_filename = g_strdup ("%s.html"); theme->picture_image_size = g_strdup (image_sizes[1]); theme->defines = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free); if (xml_file_get_node_attribute_boolean_with_default (xml, "/gallery_setup/navigation/show_go_up", "value", TRUE)) g_hash_table_replace (theme->defines, g_strdup ("SHOW_GO_UP"), g_strdup ("")); if (xml_file_get_node_attribute_boolean_with_default (xml, "/gallery_setup/navigation/show_exif_table", "value", TRUE)) g_hash_table_replace (theme->defines, g_strdup ("SHOW_EXIF_TABLE"), g_strdup ("")); s = xml_file_get_node_attribute (xml, "/gallery_setup/images/border", "style"); g_hash_table_replace (theme->defines, g_strdup ("BORDER_STYLE"), s ? s : g_strdup ("border_single")); design->themes = g_list_append (design->themes, theme); xml_parser_free (xml); return design; } /* * lookup_image_size_for_name: looks up an image size record for given image size name */ TImageSize * lookup_image_size_for_name (TGallerySetup *setup, const gchar *name) { GList *l; TImageSize *image_size; if (name == NULL) return NULL; for (l = g_list_first (setup->design->image_sizes); l; l = g_list_next (l)) { image_size = l->data; g_assert (image_size != NULL); if (g_ascii_strcasecmp (name, image_size->name) == 0) return image_size; } return NULL; } /* * validate_design_setup: validate design.xml file setup */ gboolean validate_design_setup (TGallerySetup *setup) { GList *l; TImageSize *image_size; TGalleryDesignTheme *theme; /* check for version match */ if (! SETUP_IS_NATIVE (setup->design)) { fprintf (stderr, "design validation error: version mismatch\n"); return FALSE; } /* validate sizes */ if (g_list_length (setup->design->image_sizes) == 0) { fprintf (stderr, "design validation error: no image size defined\n"); return FALSE; } if (lookup_image_size_for_name (setup, "original") == NULL) { fprintf (stderr, "design validation error: mandatory \"original\" image size not defined\n"); return FALSE; } for (l = g_list_first (setup->design->image_sizes); l; l = g_list_next (l)) { image_size = l->data; g_assert (image_size != NULL); if (image_size->landscape_width <= 0 || image_size->landscape_height <= 0 || image_size->portrait_width <= 0 || image_size->portrait_height <= 0) { fprintf (stderr, "design validation warning: image size %s defined with zero sized element\n", image_size->name); continue; } } /* validate themes */ if (g_list_length (setup->design->themes) == 0) { fprintf (stderr, "design validation error: no theme defined\n"); return FALSE; } for (l = g_list_first (setup->design->themes); l; l = g_list_next (l)) { theme = l->data; g_assert (theme != NULL); if (theme->album_image_size && lookup_image_size_for_name (setup, theme->album_image_size) == NULL) { fprintf (stderr, "design validation error: theme-defined image size '%s' not found\n", theme->album_image_size); return FALSE; } if (theme->picture_image_size && lookup_image_size_for_name (setup, theme->picture_image_size) == NULL) { fprintf (stderr, "design validation error: theme-defined image size '%s' not found\n", theme->picture_image_size); return FALSE; } if (theme->album_thumb_size) { image_size = lookup_image_size_for_name (setup, theme->album_thumb_size); if (image_size == NULL) { fprintf (stderr, "design validation error: referenced thumbnail image size '%s' not found\n", theme->album_thumb_size); return FALSE; } if (! image_size->is_thumbnail) { fprintf (stderr, "design validation error: referenced thumbnail image size '%s' is not of type \"thumbnail\"\n", theme->album_thumb_size); return FALSE; } } if (theme->index_thumb_size) { image_size = lookup_image_size_for_name (setup, theme->index_thumb_size); if (image_size == NULL) { fprintf (stderr, "design validation error: referenced thumbnail image size '%s' not found\n", theme->index_thumb_size); return FALSE; } if (! image_size->is_thumbnail) { fprintf (stderr, "design validation error: referenced thumbnail image size '%s' is not of type \"thumbnail\"\n", theme->index_thumb_size); return FALSE; } } } return TRUE; } /* * find_design_directory: try to find design templates directory * - returned string should be freed */ gchar * find_design_directory (TGallerySetup *setup) { gchar *base_dir; gchar *base_design_dir; gchar *pth = NULL; if (IS_DIR_SEP (*setup->design_setup_file)) { if (SETUP_IS_LEGACY (setup)) pth = g_strdup (setup->design_setup_file); else pth = g_path_get_dirname (setup->design_setup_file); if (g_access (pth, R_OK) == 0) return pth; } else { base_dir = g_path_get_dirname (setup->setup_xml_path); if (SETUP_IS_LEGACY (setup)) base_design_dir = g_strdup (setup->design_setup_file); else base_design_dir = g_path_get_dirname (setup->design_setup_file); pth = g_build_path (G_DIR_SEPARATOR_S, base_dir, base_design_dir, NULL); g_free (base_dir); g_free (base_design_dir); if (g_access (pth, R_OK) == 0) return pth; } log_error ("Couldn't find proper design templates directory (tried '%s')\n", pth); g_free (pth); return NULL; } /* * free_setup_data: free allocated setup data */ void free_setup_data (TGallerySetup *setup) { if (setup) { g_free (setup->setup_xml_path); g_free (setup->design_setup_file); g_free (setup->meta_author); g_free (setup->meta_author_email); g_free (setup->meta_description); g_free (setup->meta_keywords); g_free (setup->site_title); g_free (setup->add_copyright); g_free (setup->favicon_file); g_free (setup->favicon_type); g_free (setup->feed_filename); g_free (setup->feed_title); g_free (setup->location_base_url); g_free (setup->location_local_path); g_free (setup->footer); free_design_setup_data (setup->design); g_free (setup); } } static void free_image_size_data (TImageSize *image_size) { if (image_size) { g_free (image_size->name); g_free (image_size); } } static void free_design_theme_data (TGalleryDesignTheme *theme) { if (theme) { g_free (theme->index_template); g_free (theme->index_filename); g_free (theme->index_thumb_size); g_free (theme->index_protected_thumbnail); g_free (theme->album_template); g_free (theme->album_filename); g_free (theme->album_image_size); g_free (theme->album_thumb_size); g_free (theme->picture_template); g_free (theme->picture_filename); g_free (theme->picture_image_size); g_strfreev (theme->supplemental_files); g_hash_table_destroy (theme->defines); g_free (theme); } } /* * free_design_setup_data: free allocated design setup data */ void free_design_setup_data (TGalleryDesign *design) { if (design) { g_list_foreach (design->image_sizes, (GFunc) free_image_size_data, NULL); g_list_free (design->image_sizes); g_list_foreach (design->themes, (GFunc) free_design_theme_data, NULL); g_list_free (design->themes); g_strfreev (design->supplemental_files); g_free (design); } }