diff --git a/app/core/gimppattern-load.c b/app/core/gimppattern-load.c index 24e3aee16a..d9e321d636 100644 --- a/app/core/gimppattern-load.c +++ b/app/core/gimppattern-load.c @@ -35,7 +35,211 @@ #include "gimp-intl.h" +static GList * gimp_pattern_load_photoshop_pattern (GimpContext *context, + GFile *file, + GInputStream *input, + GError **error); + + GList * +gimp_pattern_load (GimpContext *context, + GFile *file, + GInputStream *input, + GError **error) +{ + GimpPattern *pattern = NULL; + const Babl *format = NULL; + GimpPatternHeader header; + gsize size; + gsize bytes_read; + gsize bn_size; + gchar *name = NULL; + + g_return_val_if_fail (G_IS_FILE (file), NULL); + g_return_val_if_fail (G_IS_INPUT_STREAM (input), NULL); + g_return_val_if_fail (error == NULL || *error == NULL, NULL); + + /* read the size */ + if (! g_input_stream_read_all (input, &header, sizeof (header), + &bytes_read, NULL, error) || + bytes_read != sizeof (header)) + { + g_prefix_error (error, _("File appears truncated: ")); + goto error; + } + + /* Check whether it is a Photoshop pattern */ + if (memcmp (&header.header_size, "8BPT", 4) == 0) + { + GList *ps_patterns = NULL; + + ps_patterns = gimp_pattern_load_photoshop_pattern (context, file, input, error); + + return ps_patterns; + } + + /* rearrange the bytes in each unsigned int */ + header.header_size = g_ntohl (header.header_size); + header.version = g_ntohl (header.version); + header.width = g_ntohl (header.width); + header.height = g_ntohl (header.height); + header.bytes = g_ntohl (header.bytes); + header.magic_number = g_ntohl (header.magic_number); + + /* Check for correct file format */ + if (header.magic_number != GIMP_PATTERN_MAGIC || + header.version != 1 || + header.header_size <= sizeof (header)) + { + g_set_error (error, GIMP_DATA_ERROR, GIMP_DATA_ERROR_READ, + _("Unknown pattern format version %d."), + header.version); + goto error; + } + + /* Check for supported bit depths */ + if (header.bytes < 1 || header.bytes > 4) + { + g_set_error (error, GIMP_DATA_ERROR, GIMP_DATA_ERROR_READ, + _("Unsupported pattern depth %d.\n" + "GIMP Patterns must be GRAY or RGB."), + header.bytes); + goto error; + } + + /* Validate dimensions */ + if ((header.width == 0) || (header.width > GIMP_PATTERN_MAX_SIZE) || + (header.height == 0) || (header.height > GIMP_PATTERN_MAX_SIZE) || + (G_MAXSIZE / header.width / header.height / header.bytes < 1)) + { + g_set_error (error, GIMP_DATA_ERROR, GIMP_DATA_ERROR_READ, + _("Invalid header data in '%s': width=%lu (maximum %lu), " + "height=%lu (maximum %lu), bytes=%lu"), + gimp_file_get_utf8_name (file), + (gulong) header.width, (gulong) GIMP_PATTERN_MAX_SIZE, + (gulong) header.height, (gulong) GIMP_PATTERN_MAX_SIZE, + (gulong) header.bytes); + goto error; + } + + /* Read in the pattern name */ + if ((bn_size = (header.header_size - sizeof (header)))) + { + gchar *utf8; + + if (bn_size > GIMP_PATTERN_MAX_NAME) + { + g_set_error (error, GIMP_DATA_ERROR, GIMP_DATA_ERROR_READ, + _("Invalid header data in '%s': " + "Pattern name is too long: %lu"), + gimp_file_get_utf8_name (file), + (gulong) bn_size); + goto error; + } + + name = g_new0 (gchar, bn_size + 1); + + if (! g_input_stream_read_all (input, name, bn_size, + &bytes_read, NULL, error) || + bytes_read != bn_size) + { + g_prefix_error (error, _("File appears truncated.")); + g_free (name); + goto error; + } + + utf8 = gimp_any_to_utf8 (name, bn_size - 1, + _("Invalid UTF-8 string in pattern file '%s'."), + gimp_file_get_utf8_name (file)); + g_free (name); + name = utf8; + } + + if (! name) + name = g_strdup (_("Unnamed")); + + pattern = g_object_new (GIMP_TYPE_PATTERN, + "name", name, + "mime-type", "image/x-gimp-pat", + NULL); + + g_free (name); + + switch (header.bytes) + { + case 1: format = babl_format ("Y' u8"); break; + case 2: format = babl_format ("Y'A u8"); break; + case 3: format = babl_format ("R'G'B' u8"); break; + case 4: format = babl_format ("R'G'B'A u8"); break; + } + + pattern->mask = gimp_temp_buf_new (header.width, header.height, format); + size = (gsize) header.width * header.height * header.bytes; + + if (! g_input_stream_read_all (input, + gimp_temp_buf_get_data (pattern->mask), size, + &bytes_read, NULL, error) || + bytes_read != size) + { + g_prefix_error (error, _("File appears truncated.")); + goto error; + } + + return g_list_prepend (NULL, pattern); + + error: + + if (pattern) + g_object_unref (pattern); + + g_prefix_error (error, _("Fatal parse error in pattern file: ")); + + return NULL; +} + +GList * +gimp_pattern_load_pixbuf (GimpContext *context, + GFile *file, + GInputStream *input, + GError **error) +{ + GimpPattern *pattern; + GdkPixbuf *pixbuf; + gchar *name; + + g_return_val_if_fail (G_IS_FILE (file), NULL); + g_return_val_if_fail (G_IS_INPUT_STREAM (input), NULL); + g_return_val_if_fail (error == NULL || *error == NULL, NULL); + + pixbuf = gdk_pixbuf_new_from_stream (input, NULL, error); + if (! pixbuf) + return NULL; + + name = g_strdup (gdk_pixbuf_get_option (pixbuf, "tEXt::Title")); + + if (! name) + name = g_strdup (gdk_pixbuf_get_option (pixbuf, "tEXt::Comment")); + + if (! name) + name = g_path_get_basename (gimp_file_get_utf8_name (file)); + + pattern = g_object_new (GIMP_TYPE_PATTERN, + "name", name, + "mime-type", NULL, /* FIXME!! */ + NULL); + g_free (name); + + pattern->mask = gimp_temp_buf_new_from_pixbuf (pixbuf, NULL); + + g_object_unref (pixbuf); + + return g_list_prepend (NULL, pattern); +} + + +/* Private functions */ + +static GList * gimp_pattern_load_photoshop_pattern (GimpContext *context, GFile *file, GInputStream *input, @@ -134,7 +338,7 @@ gimp_pattern_load_photoshop_pattern (GimpContext *context, } ofs = g_seekable_tell (G_SEEKABLE (input)); - g_debug ("Pattern version %u, size: %u, offset: %llx, next %llx", + g_debug ("Pattern version %u, size: %u, offset: %" G_GOFFSET_FORMAT ", next %" G_GOFFSET_FORMAT, pat_version, pat_size, ofs, ofs + pat_size); if (! gimp_data_input_stream_read_long (data_input, &pat_top, error) || @@ -350,198 +554,3 @@ gimp_pattern_load_photoshop_pattern (GimpContext *context, return pattern_list; } - -GList * -gimp_pattern_load (GimpContext *context, - GFile *file, - GInputStream *input, - GError **error) -{ - GimpPattern *pattern = NULL; - const Babl *format = NULL; - GimpPatternHeader header; - gsize size; - gsize bytes_read; - gsize bn_size; - gchar *name = NULL; - - g_return_val_if_fail (G_IS_FILE (file), NULL); - g_return_val_if_fail (G_IS_INPUT_STREAM (input), NULL); - g_return_val_if_fail (error == NULL || *error == NULL, NULL); - - /* read the size */ - if (! g_input_stream_read_all (input, &header, sizeof (header), - &bytes_read, NULL, error) || - bytes_read != sizeof (header)) - { - g_prefix_error (error, _("File appears truncated: ")); - goto error; - } - - /* Check whether it is a Photoshop pattern */ - if (memcmp (&header.header_size, "8BPT", 4) == 0) - { - GList *ps_patterns = NULL; - - ps_patterns = gimp_pattern_load_photoshop_pattern (context, file, input, error); - - return ps_patterns; - } - - /* rearrange the bytes in each unsigned int */ - header.header_size = g_ntohl (header.header_size); - header.version = g_ntohl (header.version); - header.width = g_ntohl (header.width); - header.height = g_ntohl (header.height); - header.bytes = g_ntohl (header.bytes); - header.magic_number = g_ntohl (header.magic_number); - - /* Check for correct file format */ - if (header.magic_number != GIMP_PATTERN_MAGIC || - header.version != 1 || - header.header_size <= sizeof (header)) - { - g_set_error (error, GIMP_DATA_ERROR, GIMP_DATA_ERROR_READ, - _("Unknown pattern format version %d."), - header.version); - goto error; - } - - /* Check for supported bit depths */ - if (header.bytes < 1 || header.bytes > 4) - { - g_set_error (error, GIMP_DATA_ERROR, GIMP_DATA_ERROR_READ, - _("Unsupported pattern depth %d.\n" - "GIMP Patterns must be GRAY or RGB."), - header.bytes); - goto error; - } - - /* Validate dimensions */ - if ((header.width == 0) || (header.width > GIMP_PATTERN_MAX_SIZE) || - (header.height == 0) || (header.height > GIMP_PATTERN_MAX_SIZE) || - (G_MAXSIZE / header.width / header.height / header.bytes < 1)) - { - g_set_error (error, GIMP_DATA_ERROR, GIMP_DATA_ERROR_READ, - _("Invalid header data in '%s': width=%lu (maximum %lu), " - "height=%lu (maximum %lu), bytes=%lu"), - gimp_file_get_utf8_name (file), - (gulong) header.width, (gulong) GIMP_PATTERN_MAX_SIZE, - (gulong) header.height, (gulong) GIMP_PATTERN_MAX_SIZE, - (gulong) header.bytes); - goto error; - } - - /* Read in the pattern name */ - if ((bn_size = (header.header_size - sizeof (header)))) - { - gchar *utf8; - - if (bn_size > GIMP_PATTERN_MAX_NAME) - { - g_set_error (error, GIMP_DATA_ERROR, GIMP_DATA_ERROR_READ, - _("Invalid header data in '%s': " - "Pattern name is too long: %lu"), - gimp_file_get_utf8_name (file), - (gulong) bn_size); - goto error; - } - - name = g_new0 (gchar, bn_size + 1); - - if (! g_input_stream_read_all (input, name, bn_size, - &bytes_read, NULL, error) || - bytes_read != bn_size) - { - g_prefix_error (error, _("File appears truncated.")); - g_free (name); - goto error; - } - - utf8 = gimp_any_to_utf8 (name, bn_size - 1, - _("Invalid UTF-8 string in pattern file '%s'."), - gimp_file_get_utf8_name (file)); - g_free (name); - name = utf8; - } - - if (! name) - name = g_strdup (_("Unnamed")); - - pattern = g_object_new (GIMP_TYPE_PATTERN, - "name", name, - "mime-type", "image/x-gimp-pat", - NULL); - - g_free (name); - - switch (header.bytes) - { - case 1: format = babl_format ("Y' u8"); break; - case 2: format = babl_format ("Y'A u8"); break; - case 3: format = babl_format ("R'G'B' u8"); break; - case 4: format = babl_format ("R'G'B'A u8"); break; - } - - pattern->mask = gimp_temp_buf_new (header.width, header.height, format); - size = (gsize) header.width * header.height * header.bytes; - - if (! g_input_stream_read_all (input, - gimp_temp_buf_get_data (pattern->mask), size, - &bytes_read, NULL, error) || - bytes_read != size) - { - g_prefix_error (error, _("File appears truncated.")); - goto error; - } - - return g_list_prepend (NULL, pattern); - - error: - - if (pattern) - g_object_unref (pattern); - - g_prefix_error (error, _("Fatal parse error in pattern file: ")); - - return NULL; -} - -GList * -gimp_pattern_load_pixbuf (GimpContext *context, - GFile *file, - GInputStream *input, - GError **error) -{ - GimpPattern *pattern; - GdkPixbuf *pixbuf; - gchar *name; - - g_return_val_if_fail (G_IS_FILE (file), NULL); - g_return_val_if_fail (G_IS_INPUT_STREAM (input), NULL); - g_return_val_if_fail (error == NULL || *error == NULL, NULL); - - pixbuf = gdk_pixbuf_new_from_stream (input, NULL, error); - if (! pixbuf) - return NULL; - - name = g_strdup (gdk_pixbuf_get_option (pixbuf, "tEXt::Title")); - - if (! name) - name = g_strdup (gdk_pixbuf_get_option (pixbuf, "tEXt::Comment")); - - if (! name) - name = g_path_get_basename (gimp_file_get_utf8_name (file)); - - pattern = g_object_new (GIMP_TYPE_PATTERN, - "name", name, - "mime-type", NULL, /* FIXME!! */ - NULL); - g_free (name); - - pattern->mask = gimp_temp_buf_new_from_pixbuf (pixbuf, NULL); - - g_object_unref (pixbuf); - - return g_list_prepend (NULL, pattern); -}