mirror of https://github.com/GNOME/gimp.git
Fixed crash occuring after a double free of some structured XMP
2005-04-22 Raphael Quinet <raphael@gimp.org> * plug-ins/metadata/xmp-model.[ch]: Fixed crash occuring after a double free of some structured XMP properties. Added new type XMP_TYPE_GENERIC_STRUCTURE for unknown structured properties. Be more tolerant in parsing incorrectly written schema URIs and try to extract a valid URI from them. Converted to use g_print(). Moved the definitions of standard XMP schemas from here... * plug-ins/metadata/xmp-schemas.[ch]: ...to these new files. * plug-ins/metadata/xmp-encode.[ch]: Rewritten using GString instead of fixed buffers. * plug-ins/metadata/metadata.c * plug-ins/metadata/interface.c: Adapted to the new function xmp_generate_block() using GString. * plug-ins/metadata/base64.c (base64_encode): Fixed incorrect encoding of bytes with the sign bit set. * plug-ins/metadata/testbase64.c * plug-ins/metadata/Makefile.am: Added xmp-schema.[ch] and test program testbase64.c (testing base64 encoding and decoding). * plug-ins/metadata/xmpdump.c: Converted to use g_print(). * plug-ins/metadata/xmp-parse.c: Added some #ifdef's around debugging code, added more comments.
This commit is contained in:
parent
ee1cac1475
commit
c30453f49d
30
ChangeLog
30
ChangeLog
|
@ -1,3 +1,33 @@
|
|||
2005-04-22 Raphaël Quinet <raphael@gimp.org>
|
||||
|
||||
* plug-ins/metadata/xmp-model.[ch]: Fixed crash occuring after a
|
||||
double free of some structured XMP properties. Added new type
|
||||
XMP_TYPE_GENERIC_STRUCTURE for unknown structured properties. Be
|
||||
more tolerant in parsing incorrectly written schema URIs and try
|
||||
to extract a valid URI from them. Converted to use g_print().
|
||||
Moved the definitions of standard XMP schemas from here...
|
||||
|
||||
* plug-ins/metadata/xmp-schemas.[ch]: ...to these new files.
|
||||
|
||||
* plug-ins/metadata/xmp-encode.[ch]: Rewritten using GString
|
||||
instead of fixed buffers.
|
||||
|
||||
* plug-ins/metadata/metadata.c
|
||||
* plug-ins/metadata/interface.c: Adapted to the new function
|
||||
xmp_generate_block() using GString.
|
||||
|
||||
* plug-ins/metadata/base64.c (base64_encode): Fixed incorrect
|
||||
encoding of bytes with the sign bit set.
|
||||
|
||||
* plug-ins/metadata/testbase64.c
|
||||
* plug-ins/metadata/Makefile.am: Added xmp-schema.[ch] and test
|
||||
program testbase64.c (testing base64 encoding and decoding).
|
||||
|
||||
* plug-ins/metadata/xmpdump.c: Converted to use g_print().
|
||||
|
||||
* plug-ins/metadata/xmp-parse.c: Added some #ifdef's around
|
||||
debugging code, added more comments.
|
||||
|
||||
2005-04-22 Sven Neumann <sven@gimp.org>
|
||||
|
||||
* libgimpbase/gimpbaseenums.h (GimpTransformDirection): removed
|
||||
|
|
|
@ -20,14 +20,16 @@ metadata_SOURCES = \
|
|||
metadata.c \
|
||||
interface.h \
|
||||
interface.c \
|
||||
base64.h \
|
||||
base64.c \
|
||||
xmp-model.h \
|
||||
xmp-model.c \
|
||||
xmp-parse.h \
|
||||
xmp-parse.c \
|
||||
xmp-encode.h \
|
||||
xmp-encode.c \
|
||||
base64.h \
|
||||
base64.c
|
||||
xmp-schemas.h \
|
||||
xmp-schemas.c
|
||||
# exif-decode.h \
|
||||
# exif-decode.c \
|
||||
# exif-encode.h \
|
||||
|
@ -38,10 +40,10 @@ metadata_SOURCES = \
|
|||
noinst_PROGRAMS = xmpdump
|
||||
xmpdump_SOURCES = \
|
||||
xmpdump.c \
|
||||
xmp-parse.h \
|
||||
xmp-parse.c \
|
||||
base64.h \
|
||||
base64.c
|
||||
base64.c \
|
||||
xmp-parse.h \
|
||||
xmp-parse.c
|
||||
|
||||
INCLUDES = \
|
||||
-I$(top_srcdir) \
|
||||
|
@ -58,3 +60,13 @@ LDADD = \
|
|||
$(GTK_LIBS) \
|
||||
$(RT_LIBS) \
|
||||
$(INTLLIBS)
|
||||
|
||||
# test program, not built by default
|
||||
|
||||
TESTS = testbase64$(EXEEXT)
|
||||
|
||||
EXTRA_PROGRAMS = testbase64
|
||||
testbase64_SOURCES = \
|
||||
base64.h \
|
||||
base64.c \
|
||||
testbase64.c
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* base64.h - encode and decode base64 encoding according to RFC 1521
|
||||
/* base64.h - encode and decode base64 encoding according to RFC 2045
|
||||
*
|
||||
* Copyright (C) 2005, Raphaël Quinet <raphael@gimp.org>
|
||||
*
|
||||
|
@ -24,7 +24,7 @@
|
|||
* ignore whitespace (especially those written for HTTP usage) and the
|
||||
* rest were not compatible with the LGPL (some were GPL, not LGPL).
|
||||
* Or at least I haven't been able to find LGPL implementations.
|
||||
* Writing this according to RFC 1521 did not take long anyway.
|
||||
* Writing this according to RFC 2045 did not take long anyway.
|
||||
*/
|
||||
|
||||
#ifndef WITHOUT_GIMP
|
||||
|
@ -86,7 +86,7 @@ static const gint base64_6bits[256] =
|
|||
* specified correctly. The decoder will stop at the first nul byte
|
||||
* or at the first '=' (padding byte) so you should ensure that one of
|
||||
* these is present if you supply -1 for @src_size. For more details
|
||||
* about the base64 encoding, see RFC 1521.
|
||||
* about the base64 encoding, see RFC 2045, chapter 6.8.
|
||||
*
|
||||
* Returns: the number of bytes stored in @dest, or -1 if invalid data was found.
|
||||
*/
|
||||
|
@ -160,14 +160,11 @@ base64_decode (const gchar *src_b64,
|
|||
* Since the base64 encoding uses 4 bytes for every 3 bytes of input,
|
||||
* @dest_size should be at least 4/3 of @src_size, plus optional line
|
||||
* breaks if @columns > 0 and up to two padding bytes at the end. For
|
||||
* more details about the base64 encoding, see RFC 1521.
|
||||
* more details about the base64 encoding, see RFC 2045, chapter 6.8.
|
||||
* Note that RFC 2045 recommends setting @columns to 76.
|
||||
*
|
||||
* Returns: the number of bytes stored in @dest.
|
||||
*/
|
||||
/*
|
||||
* FIXME: docs!
|
||||
* if columns <= 0, no line breaks
|
||||
*/
|
||||
gssize
|
||||
base64_encode (const gchar *src,
|
||||
gsize src_size,
|
||||
|
@ -175,10 +172,10 @@ base64_encode (const gchar *src,
|
|||
gsize dest_size,
|
||||
gint columns)
|
||||
{
|
||||
gint32 bits;
|
||||
gssize i;
|
||||
gint n;
|
||||
gint c;
|
||||
guint32 bits;
|
||||
gssize i;
|
||||
gint n;
|
||||
gint c;
|
||||
|
||||
g_return_val_if_fail (src != NULL, -1);
|
||||
g_return_val_if_fail (dest_b64 != NULL, -1);
|
||||
|
@ -188,7 +185,7 @@ base64_encode (const gchar *src,
|
|||
c = 0;
|
||||
for (i = 0; (src_size != 0) && (i + 4 <= dest_size); src++, src_size--)
|
||||
{
|
||||
bits += *src;
|
||||
bits += *(guchar *)src;
|
||||
if (++n == 3)
|
||||
{
|
||||
dest_b64[i++] = base64_code[(bits >> 18) & 0x3f];
|
||||
|
|
|
@ -50,7 +50,7 @@
|
|||
#include "libgimp/stdplugins-intl.h"
|
||||
|
||||
#include "interface.h"
|
||||
#include "xmp-model.h"
|
||||
#include "xmp-schemas.h"
|
||||
#include "xmp-encode.h"
|
||||
|
||||
|
||||
|
@ -532,25 +532,21 @@ export_dialog_response (GtkWidget *dlg,
|
|||
|
||||
if (response_id == GTK_RESPONSE_OK)
|
||||
{
|
||||
gchar *filename;
|
||||
gchar *buffer;
|
||||
gssize buffer_length;
|
||||
int fd;
|
||||
GString *buffer;
|
||||
gchar *filename;
|
||||
int fd;
|
||||
|
||||
buffer = g_string_new (NULL);
|
||||
xmp_generate_packet (mgui->xmp_model, buffer);
|
||||
|
||||
filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dlg));
|
||||
|
||||
/* FIXME: improve this code and rewrite the error handling */
|
||||
buffer_length = xmp_estimate_size (mgui->xmp_model);
|
||||
buffer = g_new (gchar, buffer_length);
|
||||
xmp_generate_block (mgui->xmp_model, buffer, buffer_length);
|
||||
|
||||
fd = g_open (filename, O_CREAT | O_TRUNC | O_WRONLY | _O_BINARY, 0666);
|
||||
if (fd < 0)
|
||||
{
|
||||
metadata_message_dialog (GTK_MESSAGE_ERROR, GTK_WINDOW (dlg),
|
||||
_("Open failed"),
|
||||
_("Cannot create file"));
|
||||
g_free (buffer);
|
||||
g_string_free (buffer, TRUE);
|
||||
g_free (filename);
|
||||
return;
|
||||
}
|
||||
|
@ -560,12 +556,12 @@ export_dialog_response (GtkWidget *dlg,
|
|||
strlen (buffer), filename);
|
||||
*/
|
||||
|
||||
if (write (fd, buffer, strlen (buffer)) < 0)
|
||||
if (write (fd, buffer->str, buffer->len) < 0)
|
||||
{
|
||||
metadata_message_dialog (GTK_MESSAGE_ERROR, GTK_WINDOW (dlg),
|
||||
_("Save failed"),
|
||||
_("Some error occurred while saving"));
|
||||
g_free (buffer);
|
||||
g_string_free (buffer, TRUE);
|
||||
g_free (filename);
|
||||
return;
|
||||
}
|
||||
|
@ -575,12 +571,12 @@ export_dialog_response (GtkWidget *dlg,
|
|||
metadata_message_dialog (GTK_MESSAGE_ERROR, GTK_WINDOW (dlg),
|
||||
_("Save failed"),
|
||||
_("Could not close the file"));
|
||||
g_free (buffer);
|
||||
g_string_free (buffer, TRUE);
|
||||
g_free (filename);
|
||||
return;
|
||||
}
|
||||
|
||||
g_free (buffer);
|
||||
g_string_free (buffer, TRUE);
|
||||
g_free (filename);
|
||||
}
|
||||
|
||||
|
|
|
@ -526,29 +526,24 @@ run (const gchar *name,
|
|||
|
||||
if (status == GIMP_PDB_SUCCESS)
|
||||
{
|
||||
gchar *buffer;
|
||||
gssize buffer_size;
|
||||
gssize used_size;
|
||||
GString *buffer;
|
||||
|
||||
/* Generate the updated parasite and attach it to the image */
|
||||
buffer_size = xmp_estimate_size (xmp_model);
|
||||
buffer = g_new (gchar, buffer_size + METADATA_MARKER_LEN);
|
||||
strcpy (buffer, METADATA_MARKER);
|
||||
used_size = xmp_generate_block (xmp_model,
|
||||
buffer + METADATA_MARKER_LEN,
|
||||
buffer_size);
|
||||
buffer = g_string_new (METADATA_MARKER);
|
||||
xmp_generate_packet (xmp_model, buffer);
|
||||
parasite = gimp_parasite_new (METADATA_PARASITE,
|
||||
GIMP_PARASITE_PERSISTENT,
|
||||
used_size + METADATA_MARKER_LEN,
|
||||
(gpointer) buffer);
|
||||
buffer->len,
|
||||
(gpointer) buffer->str);
|
||||
gimp_image_parasite_attach (image_ID, parasite);
|
||||
if (! strcmp (name, "plug_in_metadata_encode_xmp"))
|
||||
{
|
||||
*nreturn_vals = 2;
|
||||
values[1].type = GIMP_PDB_STRING;
|
||||
values[1].data.d_string = g_strdup (buffer + METADATA_MARKER_LEN);
|
||||
values[1].data.d_string = g_strdup (buffer->str
|
||||
+ METADATA_MARKER_LEN);
|
||||
}
|
||||
g_free (buffer);
|
||||
g_string_free (buffer, TRUE);
|
||||
xmp_model_free (xmp_model);
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,117 @@
|
|||
/* Small test program to test the base64 encoding and decoding */
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <glib.h>
|
||||
|
||||
#include "base64.h"
|
||||
|
||||
static int
|
||||
string_encode_decode (char *s)
|
||||
{
|
||||
int n;
|
||||
char encoded[300];
|
||||
char decoded[400];
|
||||
|
||||
n = base64_encode (s, strlen (s), encoded, sizeof (encoded) - 1, 0);
|
||||
if (n < 0)
|
||||
{
|
||||
g_print ("base64 encoding failed for '%s'", s);
|
||||
return 1;
|
||||
}
|
||||
g_print ("'%s' -> '%s' (%d) ", s, encoded, n);
|
||||
n = base64_decode (encoded, strlen (encoded), decoded, sizeof (decoded) - 1);
|
||||
if (n < 0)
|
||||
{
|
||||
g_print ("\nbase64 decoding failed for '%s'", s);
|
||||
return 1;
|
||||
}
|
||||
if (! strcmp (s, decoded))
|
||||
g_print ("-> '%s' (%d)\n", decoded, n);
|
||||
else
|
||||
{
|
||||
g_print ("-> '%s' (%d) MISMATCH!\n", decoded, n);
|
||||
g_print ("decoded buffer does not match original!\n");
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
buffer_encode_decode (char *buf,
|
||||
gint buf_len,
|
||||
gint columns)
|
||||
{
|
||||
int n;
|
||||
char encoded[3000];
|
||||
char decoded[4000];
|
||||
|
||||
n = base64_encode (buf, buf_len, encoded, sizeof (encoded) - 1, columns);
|
||||
if (n < 0)
|
||||
{
|
||||
g_print ("base64 encoding failed");
|
||||
return 1;
|
||||
}
|
||||
g_print ("buffer length %d -> encoded %d (columns: %d) ", buf_len, n,
|
||||
columns);
|
||||
n = base64_decode (encoded, strlen (encoded), decoded, sizeof (decoded) - 1);
|
||||
if (n < 0)
|
||||
{
|
||||
g_print ("\nbase64 decoding failed");
|
||||
return 1;
|
||||
}
|
||||
if ((n == buf_len) && ! memcmp (buf, decoded, buf_len))
|
||||
g_print ("-> decoded %d match OK\n", n);
|
||||
else
|
||||
{
|
||||
g_print ("-> decoded %d MISMATCH!\n", n);
|
||||
g_print ("decoded buffer does not match original!\n");
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
main (int argc,
|
||||
char *argv[])
|
||||
{
|
||||
int failed = 0;
|
||||
int i;
|
||||
char buf[1000];
|
||||
|
||||
g_print ("Testing base64 encoding ...\n");
|
||||
failed += string_encode_decode ("");
|
||||
failed += string_encode_decode ("A");
|
||||
failed += string_encode_decode ("AB");
|
||||
failed += string_encode_decode ("ABC");
|
||||
failed += string_encode_decode ("ABCD");
|
||||
failed += string_encode_decode ("ABCDE");
|
||||
failed += string_encode_decode ("ABCDEF");
|
||||
failed += string_encode_decode ("ABCDEFG");
|
||||
failed += string_encode_decode ("ABCDEFGH");
|
||||
failed += string_encode_decode ("ABCDEFGHI");
|
||||
failed += string_encode_decode ("abcdefghik");
|
||||
failed += string_encode_decode ("1234567890abcdefghijklmnopqrstuvwxyz");
|
||||
failed += string_encode_decode ("«© Raphaël»");
|
||||
for (i = 0; i < sizeof (buf); i++)
|
||||
buf[i] = (char) (i % 0xff);
|
||||
failed += buffer_encode_decode (buf, sizeof (buf), 0);
|
||||
failed += buffer_encode_decode (buf, sizeof (buf), 76);
|
||||
failed += buffer_encode_decode (buf, sizeof (buf), 4);
|
||||
failed += buffer_encode_decode (buf, sizeof (buf), 1);
|
||||
for (i = 0; i < sizeof (buf); i++)
|
||||
buf[i] = (char) (0xff - (i % 0xff));
|
||||
failed += buffer_encode_decode (buf, 600, 0);
|
||||
failed += buffer_encode_decode (buf, 500, 0);
|
||||
failed += buffer_encode_decode (buf, 400, 0);
|
||||
if (failed > 0)
|
||||
{
|
||||
g_print ("%d test(s) failed!\n", failed);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
g_print ("No problems detected.\n");
|
||||
return EXIT_SUCCESS;
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
/* xmp-gen.c - generate XMP metadata from the tree model
|
||||
/* xmp-encode.c - generate XMP metadata from the tree model
|
||||
*
|
||||
* Copyright (C) 2005, Raphaël Quinet <raphael@gimp.org>
|
||||
*
|
||||
|
@ -30,36 +30,30 @@
|
|||
#include "libgimp/stdplugins-intl.h"
|
||||
|
||||
#include "xmp-encode.h"
|
||||
#include "xmp-model.h"
|
||||
#include "xmp-schemas.h"
|
||||
|
||||
static gssize
|
||||
size_schema (GtkTreeModel *model,
|
||||
GtkTreeIter *iter,
|
||||
const XMPSchema **schema_r)
|
||||
static void
|
||||
gen_schema_start (GString *buffer,
|
||||
const XMPSchema *schema)
|
||||
{
|
||||
gtk_tree_model_get (model, iter,
|
||||
COL_XMP_TYPE_XREF, schema_r,
|
||||
-1);
|
||||
return (sizeof (" <rdf:Description xmlns:%s='%s'>\n") - 5
|
||||
+ strlen ((*schema_r)->prefix)
|
||||
+ strlen ((*schema_r)->uri)
|
||||
+ sizeof (" </rdf:Description>\n\n") - 1);
|
||||
g_string_append_printf (buffer, " <rdf:Description xmlns:%s='%s'>\n",
|
||||
schema->prefix, schema->uri);
|
||||
}
|
||||
|
||||
static gssize
|
||||
size_property (GtkTreeModel *model,
|
||||
GtkTreeIter *iter,
|
||||
const XMPSchema *schema)
|
||||
static void
|
||||
gen_schema_end (GString *buffer)
|
||||
{
|
||||
const XMPProperty *property;
|
||||
const gchar **value_array;
|
||||
gssize length;
|
||||
gint i;
|
||||
g_string_append (buffer, " </rdf:Description>\n\n");
|
||||
}
|
||||
|
||||
gtk_tree_model_get (model, iter,
|
||||
COL_XMP_TYPE_XREF, &property,
|
||||
COL_XMP_VALUE_RAW, &value_array,
|
||||
-1);
|
||||
static void
|
||||
gen_property (GString *buffer,
|
||||
const XMPSchema *schema,
|
||||
const XMPProperty *property,
|
||||
const gchar **value_array)
|
||||
{
|
||||
gint i;
|
||||
const gchar *ns_prefix;
|
||||
|
||||
switch (property->type)
|
||||
{
|
||||
|
@ -70,262 +64,162 @@ size_property (GtkTreeModel *model,
|
|||
case XMP_TYPE_MIME_TYPE:
|
||||
case XMP_TYPE_TEXT:
|
||||
case XMP_TYPE_RATIONAL:
|
||||
return (sizeof (" <%s:%s>%s</%s:%s>\n") - 11
|
||||
+ 2 * strlen (schema->prefix)
|
||||
+ 2 * strlen (property->name)
|
||||
+ strlen (value_array[0]));
|
||||
g_string_append_printf (buffer, " <%s:%s>%s</%s:%s>\n",
|
||||
schema->prefix, property->name,
|
||||
value_array[0],
|
||||
schema->prefix, property->name);
|
||||
break;
|
||||
|
||||
case XMP_TYPE_LOCALE_BAG:
|
||||
case XMP_TYPE_TEXT_BAG:
|
||||
case XMP_TYPE_XPATH_BAG:
|
||||
case XMP_TYPE_JOB_BAG:
|
||||
g_string_append_printf (buffer, " <%s:%s>\n <rdf:Bag>\n",
|
||||
schema->prefix, property->name);
|
||||
for (i = 0; value_array[i] != NULL; i++)
|
||||
g_string_append_printf (buffer, " <rdf:li>%s</rdf:li>\n",
|
||||
value_array[i]);
|
||||
g_string_append_printf (buffer, " </rdf:Bag>\n </%s:%s>\n",
|
||||
schema->prefix, property->name);
|
||||
break;
|
||||
|
||||
case XMP_TYPE_INTEGER_SEQ:
|
||||
case XMP_TYPE_TEXT_SEQ:
|
||||
case XMP_TYPE_RESOURCE_EVENT_SEQ:
|
||||
case XMP_TYPE_RATIONAL_SEQ:
|
||||
length = (sizeof (" <%s:%s>\n <rdf:Bag>\n") - 5
|
||||
+ sizeof (" </rdf:Bag>\n </%s:%s>\n") - 5
|
||||
+ 2 * strlen (schema->prefix)
|
||||
+ 2 * strlen (property->name));
|
||||
g_string_append_printf (buffer, " <%s:%s>\n <rdf:Seq>\n",
|
||||
schema->prefix, property->name);
|
||||
for (i = 0; value_array[i] != NULL; i++)
|
||||
length += (sizeof (" <rdf:li>%s</rdf:li>\n") - 3
|
||||
+ strlen (value_array[i]));
|
||||
return length;
|
||||
g_string_append_printf (buffer, " <rdf:li>%s</rdf:li>\n",
|
||||
value_array[i]);
|
||||
g_string_append_printf (buffer, " </rdf:Seq>\n </%s:%s>\n",
|
||||
schema->prefix, property->name);
|
||||
break;
|
||||
|
||||
case XMP_TYPE_LANG_ALT:
|
||||
length = (sizeof (" <%s:%s>\n <rdf:Alt>\n") - 5
|
||||
+ sizeof (" </rdf:Alt>\n </%s:%s>\n") - 5
|
||||
+ 2 * strlen (schema->prefix)
|
||||
+ 2 * strlen (property->name));
|
||||
g_string_append_printf (buffer, " <%s:%s>\n <rdf:Alt>\n",
|
||||
schema->prefix, property->name);
|
||||
for (i = 0; value_array[i] != NULL; i += 2)
|
||||
length += (sizeof (" <rdf:li xml:lang='%s'>%s</rdf:li>\n") - 5
|
||||
+ strlen (value_array[i])
|
||||
+ strlen (value_array[i + 1]));
|
||||
return length;
|
||||
g_string_append_printf (buffer,
|
||||
" <rdf:li xml:lang='%s'>%s</rdf:li>\n",
|
||||
value_array[i], value_array[i + 1]);
|
||||
g_string_append_printf (buffer, " </rdf:Alt>\n </%s:%s>\n",
|
||||
schema->prefix, property->name);
|
||||
break;
|
||||
|
||||
case XMP_TYPE_URI:
|
||||
return (sizeof (" <%s:%s rdf:resource='%s' />\n") - 7
|
||||
+ strlen (schema->prefix)
|
||||
+ strlen (property->name)
|
||||
+ strlen (value_array[0]));
|
||||
g_string_append_printf (buffer, " <%s:%s rdf:resource='%s' />\n",
|
||||
schema->prefix, property->name, value_array[0]);
|
||||
break;
|
||||
|
||||
case XMP_TYPE_RESOURCE_REF:
|
||||
case XMP_TYPE_DIMENSIONS:
|
||||
case XMP_TYPE_THUMBNAIL_ALT:
|
||||
case XMP_TYPE_GPS_COORDINATE:
|
||||
case XMP_TYPE_FLASH:
|
||||
case XMP_TYPE_OECF_SFR:
|
||||
case XMP_TYPE_CFA_PATTERN:
|
||||
case XMP_TYPE_DEVICE_SETTINGS:
|
||||
return 100; /* FIXME */
|
||||
|
||||
case XMP_TYPE_UNKNOWN:
|
||||
return 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* xmp_estimate_size:
|
||||
* @xmp_model: An #XMPModel
|
||||
*
|
||||
* Return value: estimated size (upper bound) of the XMP (RDF) encoding of
|
||||
* the given model.
|
||||
**/
|
||||
gssize
|
||||
xmp_estimate_size (XMPModel *xmp_model)
|
||||
{
|
||||
GtkTreeModel *model;
|
||||
GtkTreeIter iter;
|
||||
GtkTreeIter child;
|
||||
gssize buffer_size;
|
||||
const XMPSchema *schema;
|
||||
|
||||
model = xmp_model_get_tree_model (xmp_model);
|
||||
buffer_size = 158 + 44 + 1;
|
||||
if (gtk_tree_model_get_iter_first (GTK_TREE_MODEL (model), &iter))
|
||||
{
|
||||
do
|
||||
case XMP_TYPE_GENERIC_STRUCTURE:
|
||||
if (value_array[0] && value_array[1]
|
||||
&& !! strcmp (value_array[1], schema->uri))
|
||||
{
|
||||
buffer_size += size_schema (model, &iter, &schema);
|
||||
if (gtk_tree_model_iter_children (model, &child, &iter))
|
||||
{
|
||||
do
|
||||
{
|
||||
buffer_size += size_property (model, &child, schema);
|
||||
}
|
||||
while (gtk_tree_model_iter_next (model, &child));
|
||||
}
|
||||
g_string_append_printf (buffer,
|
||||
" <%s:%s rdf:parseType='Resource'\n"
|
||||
" xmlns:%s='%s'>\n",
|
||||
schema->prefix, property->name,
|
||||
value_array[0], value_array[1]);
|
||||
ns_prefix = value_array[0];
|
||||
}
|
||||
while (gtk_tree_model_iter_next (model, &iter));
|
||||
}
|
||||
return buffer_size;
|
||||
}
|
||||
else
|
||||
{
|
||||
g_string_append_printf (buffer,
|
||||
" <%s:%s rdf:parseType='Resource'>\n",
|
||||
schema->prefix, property->name);
|
||||
ns_prefix = schema->prefix;
|
||||
}
|
||||
for (i = 2; value_array[i] != NULL; i += 2)
|
||||
g_string_append_printf (buffer, " <%s:%s>%s</%s:%s>\n",
|
||||
ns_prefix, value_array[i],
|
||||
value_array[i + 1],
|
||||
ns_prefix, value_array[i]);
|
||||
g_string_append_printf (buffer, " </%s:%s>\n",
|
||||
schema->prefix, property->name);
|
||||
break;
|
||||
|
||||
static gint
|
||||
gen_schema_start (GtkTreeModel *model,
|
||||
GtkTreeIter *iter,
|
||||
gchar *buffer,
|
||||
const XMPSchema **schema_r)
|
||||
{
|
||||
gtk_tree_model_get (model, iter,
|
||||
COL_XMP_TYPE_XREF, schema_r,
|
||||
-1);
|
||||
return sprintf (buffer, " <rdf:Description xmlns:%s='%s'>\n",
|
||||
(*schema_r)->prefix, (*schema_r)->uri);
|
||||
}
|
||||
|
||||
static gint
|
||||
gen_schema_end (GtkTreeModel *model,
|
||||
GtkTreeIter *iter,
|
||||
gchar *buffer)
|
||||
{
|
||||
return sprintf (buffer, " </rdf:Description>\n\n");
|
||||
}
|
||||
|
||||
static gint
|
||||
gen_property (GtkTreeModel *model,
|
||||
GtkTreeIter *iter,
|
||||
gchar *buffer,
|
||||
const XMPSchema *schema)
|
||||
{
|
||||
const XMPProperty *property;
|
||||
const gchar **value_array;
|
||||
gssize length;
|
||||
gint i;
|
||||
|
||||
gtk_tree_model_get (model, iter,
|
||||
COL_XMP_TYPE_XREF, &property,
|
||||
COL_XMP_VALUE_RAW, &value_array,
|
||||
-1);
|
||||
g_return_val_if_fail (property->name != NULL, 0);
|
||||
switch (property->type)
|
||||
{
|
||||
case XMP_TYPE_BOOLEAN:
|
||||
case XMP_TYPE_DATE:
|
||||
case XMP_TYPE_INTEGER:
|
||||
case XMP_TYPE_REAL:
|
||||
case XMP_TYPE_MIME_TYPE:
|
||||
case XMP_TYPE_TEXT:
|
||||
case XMP_TYPE_RATIONAL:
|
||||
return sprintf (buffer, " <%s:%s>%s</%s:%s>\n",
|
||||
schema->prefix, property->name,
|
||||
value_array[0],
|
||||
schema->prefix, property->name);
|
||||
|
||||
case XMP_TYPE_LOCALE_BAG:
|
||||
case XMP_TYPE_TEXT_BAG:
|
||||
case XMP_TYPE_XPATH_BAG:
|
||||
case XMP_TYPE_JOB_BAG:
|
||||
length = sprintf (buffer, " <%s:%s>\n <rdf:Bag>\n",
|
||||
schema->prefix, property->name);
|
||||
for (i = 0; value_array[i] != NULL; i++)
|
||||
length += sprintf (buffer + length, " <rdf:li>%s</rdf:li>\n",
|
||||
value_array[i]);
|
||||
length += sprintf (buffer + length, " </rdf:Bag>\n </%s:%s>\n",
|
||||
schema->prefix, property->name);
|
||||
return length;
|
||||
|
||||
case XMP_TYPE_INTEGER_SEQ:
|
||||
case XMP_TYPE_TEXT_SEQ:
|
||||
case XMP_TYPE_RESOURCE_EVENT_SEQ:
|
||||
case XMP_TYPE_RATIONAL_SEQ:
|
||||
length = sprintf (buffer, " <%s:%s>\n <rdf:Seq>\n",
|
||||
schema->prefix, property->name);
|
||||
for (i = 0; value_array[i] != NULL; i++)
|
||||
length += sprintf (buffer + length, " <rdf:li>%s</rdf:li>\n",
|
||||
value_array[i]);
|
||||
length += sprintf (buffer + length, " </rdf:Seq>\n </%s:%s>\n",
|
||||
schema->prefix, property->name);
|
||||
return length;
|
||||
|
||||
case XMP_TYPE_LANG_ALT:
|
||||
length = sprintf (buffer, " <%s:%s>\n <rdf:Alt>\n",
|
||||
schema->prefix, property->name);
|
||||
for (i = 0; value_array[i] != NULL; i += 2)
|
||||
length += sprintf (buffer + length,
|
||||
" <rdf:li xml:lang='%s'>%s</rdf:li>\n",
|
||||
value_array[i], value_array[i + 1]);
|
||||
length += sprintf (buffer + length, " </rdf:Alt>\n </%s:%s>\n",
|
||||
schema->prefix, property->name);
|
||||
return length;
|
||||
|
||||
case XMP_TYPE_URI:
|
||||
return sprintf (buffer, " <%s:%s rdf:resource='%s' />\n",
|
||||
schema->prefix, property->name, value_array[0]);
|
||||
|
||||
case XMP_TYPE_RESOURCE_REF:
|
||||
case XMP_TYPE_DIMENSIONS:
|
||||
case XMP_TYPE_THUMBNAIL_ALT:
|
||||
case XMP_TYPE_GPS_COORDINATE:
|
||||
case XMP_TYPE_FLASH:
|
||||
case XMP_TYPE_OECF_SFR:
|
||||
case XMP_TYPE_CFA_PATTERN:
|
||||
case XMP_TYPE_DEVICE_SETTINGS:
|
||||
g_warning ("FIXME: output not implemented yet (%s)", property->name);
|
||||
g_warning ("FIXME: output not implemented yet (%s:%s)",
|
||||
schema->prefix, property->name);
|
||||
break;
|
||||
|
||||
case XMP_TYPE_UNKNOWN:
|
||||
g_warning ("Unknown property type for %s", property->name);
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* xmp_generate_block:
|
||||
* @xmp_model: An #XMPModel
|
||||
* @buffer: buffer in which the XMP block will be written
|
||||
* @buffer_size: maximum size of the buffer
|
||||
* @buffer: A #GString in which the generated XMP packet will be stored.
|
||||
*
|
||||
* Generate XMP block from xmp_model.
|
||||
* Generate XMP packet from xmp_model and store it in the supplied buffer.
|
||||
*
|
||||
* Return value: number of characters stored in the buffer (not including the terminating NUL).
|
||||
*/
|
||||
gssize
|
||||
xmp_generate_block (XMPModel *xmp_model,
|
||||
gchar *buffer,
|
||||
gssize buffer_size)
|
||||
void
|
||||
xmp_generate_packet (XMPModel *xmp_model,
|
||||
GString *buffer)
|
||||
{
|
||||
GtkTreeModel *model;
|
||||
GtkTreeIter iter;
|
||||
GtkTreeIter child;
|
||||
gssize n;
|
||||
const XMPSchema *schema;
|
||||
gpointer saved_ref;
|
||||
|
||||
g_return_if_fail (xmp_model != NULL);
|
||||
g_return_if_fail (buffer != NULL);
|
||||
model = xmp_model_get_tree_model (xmp_model);
|
||||
|
||||
strcpy (buffer,
|
||||
"<?xpacket begin='\357\273\277' id='W5M0MpCehiHzreSzNTczkc9d'?>\n"
|
||||
"<x:xmpmeta xmlns:x='adobe:ns:meta/'>\n"
|
||||
"<rdf:RDF xmlns:rdf='http://www.w3.org/1999/02/22-rdf-syntax-ns#'>\n"
|
||||
"\n");
|
||||
n = sizeof (
|
||||
"<?xpacket begin='\357\273\277' id='W5M0MpCehiHzreSzNTczkc9d'?>\n"
|
||||
"<x:xmpmeta xmlns:x='adobe:ns:meta/'>\n"
|
||||
"<rdf:RDF xmlns:rdf='http://www.w3.org/1999/02/22-rdf-syntax-ns#'>\n"
|
||||
"\n") - 1;
|
||||
/* generate the contents of the XMP block */
|
||||
g_return_if_fail (model != NULL);
|
||||
if (! buffer)
|
||||
buffer = g_string_new (NULL);
|
||||
buffer = g_string_append (buffer,
|
||||
"<?xpacket begin='\357\273\277' id='W5M0MpCehiHzreSzNTczkc9d'?>\n"
|
||||
"<x:xmpmeta xmlns:x='adobe:ns:meta/'>\n"
|
||||
"<rdf:RDF xmlns:rdf='http://www.w3.org/1999/02/22-rdf-syntax-ns#'>\n"
|
||||
"\n");
|
||||
/* generate the contents of the XMP packet */
|
||||
if (gtk_tree_model_get_iter_first (GTK_TREE_MODEL (model), &iter))
|
||||
{
|
||||
do
|
||||
{
|
||||
n += gen_schema_start (model, &iter, buffer + n, &schema);
|
||||
gtk_tree_model_get (model, &iter,
|
||||
COL_XMP_TYPE_XREF, &schema,
|
||||
-1);
|
||||
gen_schema_start (buffer, schema);
|
||||
if (gtk_tree_model_iter_children (model, &child, &iter))
|
||||
{
|
||||
saved_ref = NULL;
|
||||
do
|
||||
{
|
||||
n += gen_property (model, &child, buffer + n, schema);
|
||||
const XMPProperty *property;
|
||||
const gchar **value_array;
|
||||
|
||||
gtk_tree_model_get (model, &child,
|
||||
COL_XMP_TYPE_XREF, &property,
|
||||
COL_XMP_VALUE_RAW, &value_array,
|
||||
-1);
|
||||
/* do not process structured types multiple times */
|
||||
if (saved_ref != value_array)
|
||||
{
|
||||
saved_ref = value_array;
|
||||
g_return_if_fail (property->name != NULL);
|
||||
gen_property (buffer, schema, property, value_array);
|
||||
}
|
||||
}
|
||||
while (gtk_tree_model_iter_next (model, &child));
|
||||
}
|
||||
n += gen_schema_end (model, &iter, buffer + n);
|
||||
gen_schema_end (buffer);
|
||||
}
|
||||
while (gtk_tree_model_iter_next (model, &iter));
|
||||
}
|
||||
n = strlen (buffer);
|
||||
strcpy (buffer + n, "</rdf:RDF>\n</x:xmpmeta>\n<?xpacket end='r'?>\n");
|
||||
n += sizeof ("</rdf:RDF>\n</x:xmpmeta>\n<?xpacket end='r'?>\n") - 1;
|
||||
|
||||
return n;
|
||||
g_string_append (buffer, "</rdf:RDF>\n</x:xmpmeta>\n<?xpacket end='r'?>\n");
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* xmp-gen.h - generate XMP metadata from the tree model
|
||||
/* xmp-encode.h - generate XMP metadata from the tree model
|
||||
*
|
||||
* Copyright (C) 2005, Raphaël Quinet <raphael@gimp.org>
|
||||
*
|
||||
|
@ -17,20 +17,17 @@
|
|||
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
#ifndef XMP_GEN_H
|
||||
#define XMP_GEN_H
|
||||
#ifndef XMP_ENCODE_H
|
||||
#define XMP_ENCODE_H
|
||||
|
||||
#include <glib.h>
|
||||
#include "xmp-model.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
gssize xmp_estimate_size (XMPModel *xmp_model);
|
||||
|
||||
gssize xmp_generate_block (XMPModel *xmp_model,
|
||||
gchar *buffer,
|
||||
gssize buffer_size);
|
||||
void xmp_generate_packet (XMPModel *xmp_model,
|
||||
GString *buffer);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* XMP_GEN_H */
|
||||
#endif /* XMP_ENCODE_H */
|
||||
|
|
|
@ -21,9 +21,6 @@
|
|||
#include "config.h"
|
||||
|
||||
#include <string.h>
|
||||
#ifdef DEBUG_XMP_PARSER
|
||||
# include <stdio.h>
|
||||
#endif
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
#include <libgimp/gimp.h>
|
||||
|
@ -31,6 +28,7 @@
|
|||
|
||||
#include "libgimp/stdplugins-intl.h"
|
||||
|
||||
#include "xmp-schemas.h"
|
||||
#include "xmp-parse.h"
|
||||
#include "xmp-model.h"
|
||||
|
||||
|
@ -40,11 +38,12 @@
|
|||
* children of the schemas are the XMP properties.
|
||||
*
|
||||
* If the XMP file contains a schema that is not part of the XMP
|
||||
* specification, it will be included in the custom_schemas list and
|
||||
* the corresponding element in the tree will get a reference to that
|
||||
* list element instead of a reference to one of the static schema
|
||||
* definitions included below. Same for custom properties inside a
|
||||
* known or custom schema.
|
||||
* specification or a known extension (e.g., IPTC Core), it will be
|
||||
* included in the custom_schemas list and the corresponding element
|
||||
* in the tree will get a reference to that list element instead of a
|
||||
* reference to one of the static schema definitions found in
|
||||
* xmp-schemas.c. Same for custom properties inside a known or custom
|
||||
* schema.
|
||||
*/
|
||||
struct _XMPModel
|
||||
{
|
||||
|
@ -52,272 +51,8 @@ struct _XMPModel
|
|||
GSList *custom_schemas;
|
||||
GSList *custom_properties;
|
||||
|
||||
XMPSchema *current_schema;
|
||||
GtkTreeIter current_schema_iter;
|
||||
};
|
||||
|
||||
static XMPProperty dc_properties[] =
|
||||
{
|
||||
{ "contributor", XMP_TYPE_TEXT, TRUE },
|
||||
{ "coverage", XMP_TYPE_TEXT, TRUE },
|
||||
{ "creator", XMP_TYPE_TEXT_SEQ, TRUE },
|
||||
{ "date", XMP_TYPE_DATE, TRUE },
|
||||
{ "description", XMP_TYPE_LANG_ALT, TRUE },
|
||||
{ "format", XMP_TYPE_MIME_TYPE, XMP_AUTO_UPDATE },
|
||||
{ "identifier", XMP_TYPE_TEXT, TRUE }, /*xmp:Identifier*/
|
||||
{ "language", XMP_TYPE_LOCALE_BAG, FALSE },
|
||||
{ "publisher", XMP_TYPE_TEXT_BAG, TRUE },
|
||||
{ "relation", XMP_TYPE_TEXT_BAG, TRUE },
|
||||
{ "rights", XMP_TYPE_LANG_ALT, TRUE },
|
||||
{ "source", XMP_TYPE_TEXT, TRUE },
|
||||
{ "subject", XMP_TYPE_TEXT_BAG, TRUE },
|
||||
{ "title", XMP_TYPE_LANG_ALT, TRUE },
|
||||
{ "type", XMP_TYPE_TEXT_BAG, TRUE },
|
||||
{ NULL, XMP_TYPE_UNKNOWN, FALSE }
|
||||
};
|
||||
|
||||
static XMPProperty xmp_properties[] =
|
||||
{
|
||||
{ "Advisory", XMP_TYPE_XPATH_BAG, TRUE },
|
||||
{ "BaseURL", XMP_TYPE_URI, FALSE },
|
||||
{ "CreateDate", XMP_TYPE_DATE, TRUE },
|
||||
{ "CreatorTool", XMP_TYPE_TEXT, FALSE },
|
||||
{ "Identifier", XMP_TYPE_TEXT_BAG, TRUE },
|
||||
{ "MetadataDate", XMP_TYPE_DATE, XMP_AUTO_UPDATE },
|
||||
{ "ModifyDate", XMP_TYPE_DATE, XMP_AUTO_UPDATE },
|
||||
{ "NickName", XMP_TYPE_TEXT, TRUE },
|
||||
{ "Thumbnails", XMP_TYPE_THUMBNAIL_ALT, TRUE },
|
||||
{ NULL, XMP_TYPE_UNKNOWN, FALSE }
|
||||
};
|
||||
|
||||
static XMPProperty xmprights_properties[] =
|
||||
{
|
||||
{ "Certificate", XMP_TYPE_URI, TRUE },
|
||||
{ "Marked", XMP_TYPE_BOOLEAN, TRUE },
|
||||
{ "Owner", XMP_TYPE_TEXT_BAG, TRUE },
|
||||
{ "UsageTerms", XMP_TYPE_LANG_ALT, TRUE },
|
||||
{ "WebStatement", XMP_TYPE_URI, TRUE },
|
||||
{ NULL, XMP_TYPE_UNKNOWN, FALSE }
|
||||
};
|
||||
|
||||
static XMPProperty xmpmm_properties[] =
|
||||
{
|
||||
{ "DerivedFrom", XMP_TYPE_RESOURCE_REF, FALSE },
|
||||
{ "DocumentID", XMP_TYPE_URI, FALSE },
|
||||
{ "History", XMP_TYPE_RESOURCE_EVENT_SEQ, FALSE },
|
||||
{ "ManagedFrom", XMP_TYPE_RESOURCE_REF, FALSE },
|
||||
{ "Manager", XMP_TYPE_TEXT, FALSE },
|
||||
{ "ManageTo", XMP_TYPE_URI, FALSE },
|
||||
{ "ManageUI", XMP_TYPE_URI, FALSE },
|
||||
{ "ManagerVariant", XMP_TYPE_TEXT, FALSE },
|
||||
{ "RenditionClass", XMP_TYPE_TEXT, FALSE },
|
||||
{ "RenditionParams", XMP_TYPE_TEXT, FALSE },
|
||||
{ "VersionID", XMP_TYPE_TEXT, FALSE },
|
||||
{ "Versions", XMP_TYPE_TEXT_SEQ, FALSE },
|
||||
{ "LastURL", XMP_TYPE_URI, FALSE }, /*deprecated*/
|
||||
{ "RenditionOf", XMP_TYPE_RESOURCE_REF, FALSE }, /*deprecated*/
|
||||
{ "SaveID", XMP_TYPE_INTEGER, FALSE }, /*deprecated*/
|
||||
{ NULL, XMP_TYPE_UNKNOWN, FALSE }
|
||||
};
|
||||
|
||||
static XMPProperty xmpbj_properties[] =
|
||||
{
|
||||
{ "JobRef", XMP_TYPE_JOB_BAG, TRUE },
|
||||
{ NULL, XMP_TYPE_UNKNOWN, FALSE }
|
||||
};
|
||||
|
||||
static XMPProperty xmptpg_properties[] =
|
||||
{
|
||||
{ "MaxPageSize", XMP_TYPE_DIMENSIONS, FALSE },
|
||||
{ "NPages", XMP_TYPE_INTEGER, FALSE },
|
||||
{ NULL, XMP_TYPE_UNKNOWN, FALSE }
|
||||
};
|
||||
|
||||
static XMPProperty pdf_properties[] =
|
||||
{
|
||||
{ "Keywords", XMP_TYPE_TEXT, TRUE },
|
||||
{ "PDFVersion", XMP_TYPE_TEXT, FALSE },
|
||||
{ "Producer", XMP_TYPE_TEXT, FALSE },
|
||||
{ NULL, XMP_TYPE_UNKNOWN, FALSE }
|
||||
};
|
||||
|
||||
static XMPProperty photoshop_properties[] =
|
||||
{
|
||||
{ "AuthorsPosition", XMP_TYPE_TEXT, TRUE },
|
||||
{ "CaptionWriter", XMP_TYPE_TEXT, TRUE },
|
||||
{ "Category", XMP_TYPE_TEXT, TRUE },/* 3 ascii chars */
|
||||
{ "City", XMP_TYPE_TEXT, TRUE },
|
||||
{ "Country", XMP_TYPE_TEXT, TRUE },
|
||||
{ "Credit", XMP_TYPE_TEXT, TRUE },
|
||||
{ "DateCreated", XMP_TYPE_DATE, TRUE },
|
||||
{ "Headline", XMP_TYPE_TEXT, TRUE },
|
||||
{ "Instructions", XMP_TYPE_TEXT, TRUE },
|
||||
{ "Source", XMP_TYPE_TEXT, TRUE },
|
||||
{ "State", XMP_TYPE_TEXT, TRUE },
|
||||
{ "SupplementalCategories",XMP_TYPE_TEXT, TRUE },
|
||||
{ "TransmissionReference",XMP_TYPE_TEXT, TRUE },
|
||||
{ "Urgency", XMP_TYPE_INTEGER, TRUE },/* range: 1-8 */
|
||||
{ NULL, XMP_TYPE_UNKNOWN, FALSE }
|
||||
};
|
||||
|
||||
static XMPProperty tiff_properties[] =
|
||||
{
|
||||
{ "ImageWidth", XMP_TYPE_INTEGER, XMP_AUTO_UPDATE },
|
||||
{ "ImageLength", XMP_TYPE_INTEGER, XMP_AUTO_UPDATE },
|
||||
{ "BitsPerSample", XMP_TYPE_INTEGER_SEQ, FALSE },
|
||||
{ "Compression", XMP_TYPE_INTEGER, FALSE },/* 1 or 6 */
|
||||
{ "PhotometricInterpretation",XMP_TYPE_INTEGER, FALSE },/* 2 or 6 */
|
||||
{ "Orientation", XMP_TYPE_INTEGER, FALSE },/* 1-8 */
|
||||
{ "SamplesPerPixel", XMP_TYPE_INTEGER, FALSE },
|
||||
{ "PlanarConfiguration",XMP_TYPE_INTEGER, FALSE },/* 1 or 2 */
|
||||
{ "YCbCrSubSampling",XMP_TYPE_INTEGER_SEQ, FALSE },/* 2,1 or 2,2 */
|
||||
{ "YCbCrPositioning",XMP_TYPE_INTEGER, FALSE },/* 1 or 2 */
|
||||
{ "XResolution", XMP_TYPE_RATIONAL, XMP_AUTO_UPDATE },
|
||||
{ "YResolution", XMP_TYPE_RATIONAL, XMP_AUTO_UPDATE },
|
||||
{ "ResolutionUnit", XMP_TYPE_INTEGER, XMP_AUTO_UPDATE },/*2or3*/
|
||||
{ "TransferFunction",XMP_TYPE_INTEGER_SEQ, FALSE },/* 3 * 256 ints */
|
||||
{ "WhitePoint", XMP_TYPE_RATIONAL_SEQ, FALSE },
|
||||
{ "PrimaryChromaticities",XMP_TYPE_RATIONAL_SEQ, FALSE },
|
||||
{ "YCbCrCoefficients",XMP_TYPE_RATIONAL_SEQ, FALSE },
|
||||
{ "ReferenceBlackWhite",XMP_TYPE_RATIONAL_SEQ, FALSE },
|
||||
{ "DateTime", XMP_TYPE_DATE, FALSE },/*xmp:ModifyDate*/
|
||||
{ "ImageDescription",XMP_TYPE_LANG_ALT, TRUE },/*dc:description*/
|
||||
{ "Make", XMP_TYPE_TEXT, FALSE },
|
||||
{ "Model", XMP_TYPE_TEXT, FALSE },
|
||||
{ "Software", XMP_TYPE_TEXT, FALSE },/*xmp:CreatorTool*/
|
||||
{ "Artist", XMP_TYPE_TEXT, TRUE },/*dc:creator*/
|
||||
{ "Copyright", XMP_TYPE_TEXT, TRUE },/*dc:rights*/
|
||||
{ NULL, XMP_TYPE_UNKNOWN, FALSE }
|
||||
};
|
||||
|
||||
static XMPProperty exif_properties[] =
|
||||
{
|
||||
{ "ExifVersion", XMP_TYPE_TEXT, XMP_AUTO_UPDATE },/*"0210*/
|
||||
{ "FlashpixVersion", XMP_TYPE_TEXT, FALSE },/* "0100" */
|
||||
{ "ColorSpace", XMP_TYPE_INTEGER, FALSE },/* 1 or -32768 */
|
||||
{ "ComponentsConfiguration",XMP_TYPE_INTEGER_SEQ, FALSE },/* 4 ints */
|
||||
{ "CompressedBitsPerPixel",XMP_TYPE_RATIONAL, FALSE },
|
||||
{ "PixelXDimension", XMP_TYPE_INTEGER, XMP_AUTO_UPDATE },
|
||||
{ "PixelYDimension", XMP_TYPE_INTEGER, XMP_AUTO_UPDATE },
|
||||
{ "MakerNote", XMP_TYPE_TEXT, FALSE },/* base64 enc.? */
|
||||
{ "UserComment", XMP_TYPE_TEXT, TRUE },
|
||||
{ "RelatedSoundFile",XMP_TYPE_TEXT, FALSE },/* DOS 8.3 fname */
|
||||
{ "DateTimeOriginal",XMP_TYPE_DATE, FALSE },
|
||||
{ "DateTimeDigitized",XMP_TYPE_DATE, FALSE },
|
||||
{ "ExposureTime", XMP_TYPE_RATIONAL, FALSE },
|
||||
{ "FNumber", XMP_TYPE_RATIONAL, FALSE },
|
||||
{ "ExposureProgram", XMP_TYPE_INTEGER, FALSE },/* 0-8 */
|
||||
{ "SpectralSensitivity",XMP_TYPE_TEXT, FALSE },/* ? */
|
||||
{ "ISOSpeedRatings", XMP_TYPE_INTEGER_SEQ, FALSE },
|
||||
{ "OECF", XMP_TYPE_OECF_SFR, FALSE },
|
||||
{ "ShutterSpeedValue",XMP_TYPE_RATIONAL, FALSE },
|
||||
{ "ApertureValue", XMP_TYPE_RATIONAL, FALSE },
|
||||
{ "BrightnessValue", XMP_TYPE_RATIONAL, FALSE },
|
||||
{ "ExposureBiasValue",XMP_TYPE_RATIONAL, FALSE },
|
||||
{ "MaxApertureValue",XMP_TYPE_RATIONAL, FALSE },
|
||||
{ "SubjectDistance", XMP_TYPE_RATIONAL, FALSE },/* in meters */
|
||||
{ "MeteringMode", XMP_TYPE_INTEGER, FALSE },/* 0-6 or 255 */
|
||||
{ "LightSource", XMP_TYPE_INTEGER, FALSE },/* 0-3,17-22,255*/
|
||||
{ "Flash", XMP_TYPE_FLASH, FALSE },
|
||||
{ "FocalLength", XMP_TYPE_RATIONAL, FALSE },
|
||||
{ "SubjectArea", XMP_TYPE_INTEGER_SEQ, FALSE },
|
||||
{ "FlashEnergy", XMP_TYPE_RATIONAL, FALSE },
|
||||
{ "SpatialFrequencyResponse",XMP_TYPE_OECF_SFR, FALSE },
|
||||
{ "FocalPlaneXResolution",XMP_TYPE_RATIONAL, FALSE },
|
||||
{ "FocalPlaneYResolution",XMP_TYPE_RATIONAL, FALSE },
|
||||
{ "FocalPlaneResolutionUnit",XMP_TYPE_INTEGER, FALSE },/* unit: 2 or 3 */
|
||||
{ "SubjectLocation", XMP_TYPE_INTEGER_SEQ, FALSE },/* 2 ints: X, Y */
|
||||
{ "ExposureIndex", XMP_TYPE_RATIONAL, FALSE },
|
||||
{ "SensingMethod", XMP_TYPE_INTEGER, FALSE },/* 1-8 */
|
||||
{ "FileSource", XMP_TYPE_INTEGER, FALSE },/* 3 */
|
||||
{ "SceneType", XMP_TYPE_INTEGER, FALSE },/* 1 */
|
||||
{ "CFAPattern", XMP_TYPE_CFA_PATTERN, FALSE },
|
||||
{ "CustomRendered", XMP_TYPE_INTEGER, FALSE },/* 0-1 */
|
||||
{ "ExposureMode", XMP_TYPE_INTEGER, FALSE },/* 0-2 */
|
||||
{ "WhiteBalance", XMP_TYPE_INTEGER, FALSE },/* 0-1 */
|
||||
{ "DigitalZoomRatio",XMP_TYPE_RATIONAL, FALSE },
|
||||
{ "FocalLengthIn35mmFilm",XMP_TYPE_INTEGER, FALSE },/* in mm */
|
||||
{ "SceneCaptureType",XMP_TYPE_INTEGER, FALSE },/* 0-3 */
|
||||
{ "GainControl", XMP_TYPE_INTEGER, FALSE },/* 0-4 */
|
||||
{ "Contrast", XMP_TYPE_INTEGER, FALSE },/* 0-2 */
|
||||
{ "Saturation", XMP_TYPE_INTEGER, FALSE },/* 0-2 */
|
||||
{ "Sharpness", XMP_TYPE_INTEGER, FALSE },/* 0-2 */
|
||||
{ "DeviceSettingDescription",XMP_TYPE_DEVICE_SETTINGS, FALSE },
|
||||
{ "SubjectDistanceRange",XMP_TYPE_INTEGER, FALSE },/* 0-3 */
|
||||
{ "ImageUniqueID", XMP_TYPE_TEXT, FALSE },/* 32 chars */
|
||||
{ "GPSVersionID", XMP_TYPE_TEXT, FALSE },/* "2.0.0.0" */
|
||||
{ "GPSLatitude", XMP_TYPE_GPS_COORDINATE, FALSE },
|
||||
{ "GPSLongitude", XMP_TYPE_GPS_COORDINATE, FALSE },
|
||||
{ "GPSAltitudeRef", XMP_TYPE_INTEGER, FALSE },/* 0-1 */
|
||||
{ "GPSAltitude", XMP_TYPE_RATIONAL, FALSE },/* in meters */
|
||||
{ "GPSTimeStamp", XMP_TYPE_DATE, FALSE },
|
||||
{ "GPSSatellites", XMP_TYPE_TEXT, FALSE },/* ? */
|
||||
{ "GPSStatus", XMP_TYPE_TEXT, FALSE },/* "A" or "V" */
|
||||
{ "GPSMeasureMode", XMP_TYPE_INTEGER, FALSE },/* 2-3 */
|
||||
{ "GPSDOP", XMP_TYPE_RATIONAL, FALSE },
|
||||
{ "GPSSpeedRef", XMP_TYPE_TEXT, FALSE },/* "K","M","N" */
|
||||
{ "GPSSpeed", XMP_TYPE_RATIONAL, FALSE },
|
||||
{ "GPSTrackRef", XMP_TYPE_TEXT, FALSE },/* "T" or "M"" */
|
||||
{ "GPSTrack", XMP_TYPE_RATIONAL, FALSE },
|
||||
{ "GPSImgDirectionRef",XMP_TYPE_TEXT, FALSE },/* "T" or "M"" */
|
||||
{ "GPSImgDirection", XMP_TYPE_RATIONAL, FALSE },
|
||||
{ "GPSMapDatum", XMP_TYPE_TEXT, FALSE },
|
||||
{ "GPSDestLatitude", XMP_TYPE_GPS_COORDINATE, FALSE },
|
||||
{ "GPSDestLongitude",XMP_TYPE_GPS_COORDINATE, FALSE },
|
||||
{ "GPSDestBearingRef",XMP_TYPE_TEXT, FALSE },/* "T" or "M"" */
|
||||
{ "GPSDestBearing", XMP_TYPE_RATIONAL, FALSE },
|
||||
{ "GPSDestDistanceRef",XMP_TYPE_TEXT, FALSE },/* "K","M","N" */
|
||||
{ "GPSDestDistance", XMP_TYPE_RATIONAL, FALSE },
|
||||
{ "GPSProcessingMethod",XMP_TYPE_TEXT, FALSE },
|
||||
{ "GPSAreaInformation",XMP_TYPE_TEXT, FALSE },
|
||||
{ "GPSDifferential", XMP_TYPE_INTEGER, FALSE },/* 0-1 */
|
||||
{ NULL, XMP_TYPE_UNKNOWN, FALSE }
|
||||
};
|
||||
|
||||
static XMPSchema xmp_schemas[] =
|
||||
{
|
||||
/* XMP schemas defined as of January 2004 */
|
||||
{ XMP_SCHEMA_DUBLIN_CORE, "dc",
|
||||
"Dublin Core", dc_properties },
|
||||
{ XMP_SCHEMA_XMP_BASIC, "xmp",
|
||||
"XMP Basic", xmp_properties },
|
||||
{ XMP_SCHEMA_XMP_RIGHTS, "xmpRights",
|
||||
"XMP Rights Management", xmprights_properties },
|
||||
{ XMP_SCHEMA_XMP_MM, "xmpMM",
|
||||
"XMP Media Management", xmpmm_properties },
|
||||
{ XMP_SCHEMA_XMP_BJ, "xmpBJ",
|
||||
"XMP Basic Job Ticket", xmpbj_properties },
|
||||
{ XMP_SCHEMA_XMP_TPG, "xmpTPg",
|
||||
"XMP Paged-Text", xmptpg_properties },
|
||||
{ XMP_SCHEMA_PDF, "pdf",
|
||||
"Adobe PDF", pdf_properties },
|
||||
{ XMP_SCHEMA_PHOTOSHOP, "photoshop",
|
||||
"Photoshop", photoshop_properties },
|
||||
{ XMP_SCHEMA_TIFF, "tiff",
|
||||
"EXIF (TIFF Properties)", tiff_properties },
|
||||
{ XMP_SCHEMA_EXIF, "exif",
|
||||
"EXIF (EXIF-specific Properties)", exif_properties },
|
||||
/* XMP sub-types */
|
||||
{ "http://ns.adobe.com/xmp/Identifier/qual/1.0/", "xmpidq",
|
||||
NULL, NULL },
|
||||
{ "http://ns.adobe.com/xap/1.0/g/img/", "xapGImg",
|
||||
NULL, NULL },
|
||||
{ "http://ns.adobe.com/xap/1.0/sType/Dimensions#", "stDim",
|
||||
NULL, NULL },
|
||||
{ "http://ns.adobe.com/xap/1.0/sType/ResourceEvent#", "stEvt",
|
||||
NULL, NULL },
|
||||
{ "http://ns.adobe.com/xap/1.0/sType/ResourceRef#", "stRef",
|
||||
NULL, NULL },
|
||||
{ "http://ns.adobe.com/xap/1.0/sType/Version#", "stVer",
|
||||
NULL, NULL },
|
||||
{ "http://ns.adobe.com/xap/1.0/sType/Job#", "stJob",
|
||||
NULL, NULL },
|
||||
/* other useful namespaces */
|
||||
{ "http://web.resource.org/cc/", "cc",
|
||||
"Creative Commons", NULL },
|
||||
{ "http://ns.adobe.com/iX/1.0/", "iX",
|
||||
NULL, NULL },
|
||||
{ NULL, NULL, NULL }
|
||||
XMPSchema *cached_schema;
|
||||
GtkTreeIter cached_schema_iter;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -334,20 +69,20 @@ xmp_model_new (void)
|
|||
/* columns defined by the XMPModelColumns enum */
|
||||
xmp_model->treestore =
|
||||
gtk_tree_store_new (XMP_MODEL_NUM_COLUMNS,
|
||||
G_TYPE_STRING, /* name */
|
||||
G_TYPE_STRING, /* value as string (for viewing) */
|
||||
G_TYPE_POINTER, /* value as array (from parser) */
|
||||
G_TYPE_POINTER, /* XMPProperty or XMPSchema */
|
||||
G_TYPE_POINTER, /* GtkWidget cross-reference */
|
||||
G_TYPE_INT, /* editable? */
|
||||
GDK_TYPE_PIXBUF, /* edit icon */
|
||||
G_TYPE_BOOLEAN, /* visible? */
|
||||
G_TYPE_INT, /* font weight */
|
||||
G_TYPE_BOOLEAN /* font weight set? */
|
||||
G_TYPE_STRING, /* COL_XMP_NAME */
|
||||
G_TYPE_STRING, /* COL_XMP_VALUE */
|
||||
G_TYPE_POINTER, /* COL_XMP_VALUE_RAW */
|
||||
G_TYPE_POINTER, /* COL_XMP_TYPE_XREF */
|
||||
G_TYPE_POINTER, /* COL_XMP_WIDGET_XREF */
|
||||
G_TYPE_INT, /* COL_XMP_EDITABLE */
|
||||
GDK_TYPE_PIXBUF, /* COL_XMP_EDIT_ICON */
|
||||
G_TYPE_BOOLEAN, /* COL_XMP_VISIBLE */
|
||||
G_TYPE_INT, /* COL_XMP_WEIGHT */
|
||||
G_TYPE_BOOLEAN /* COL_XMP_WEIGHT_SET */
|
||||
);
|
||||
xmp_model->custom_schemas = NULL;
|
||||
xmp_model->custom_properties = NULL;
|
||||
xmp_model->current_schema = NULL;
|
||||
xmp_model->cached_schema = NULL;
|
||||
return xmp_model;
|
||||
}
|
||||
|
||||
|
@ -376,15 +111,21 @@ xmp_model_free (XMPModel *xmp_model)
|
|||
{
|
||||
if (gtk_tree_model_iter_children (model, &child, &iter))
|
||||
{
|
||||
gchar **last_value_array = NULL;
|
||||
|
||||
do
|
||||
{
|
||||
gtk_tree_model_get (model, &child,
|
||||
COL_XMP_VALUE_RAW, &value_array,
|
||||
-1);
|
||||
/* FIXME: this does not free everything */
|
||||
for (i = 0; value_array[i] != NULL; i++)
|
||||
g_free (value_array[i]);
|
||||
g_free (value_array);
|
||||
if (value_array != last_value_array)
|
||||
{
|
||||
/* FIXME: this does not free everything */
|
||||
for (i = 0; value_array[i] != NULL; i++)
|
||||
g_free (value_array[i]);
|
||||
g_free (value_array);
|
||||
}
|
||||
last_value_array = value_array;
|
||||
}
|
||||
while (gtk_tree_model_iter_next (model, &child));
|
||||
}
|
||||
|
@ -420,34 +161,20 @@ static XMPSchema *
|
|||
find_xmp_schema (XMPModel *xmp_model,
|
||||
const gchar *schema_uri)
|
||||
{
|
||||
int i;
|
||||
GSList *list;
|
||||
int i;
|
||||
GSList *list;
|
||||
const gchar *c;
|
||||
|
||||
/* check if we know about this schema (exact match for URI) */
|
||||
for (i = 0; xmp_schemas[i].uri != NULL; ++i)
|
||||
{
|
||||
if (! strcmp (xmp_schemas[i].uri, schema_uri))
|
||||
{
|
||||
#ifdef DEBUG_XMP_PARSER
|
||||
#ifdef DEBUG_XMP_MODEL
|
||||
if (xmp_schemas[i].name != NULL)
|
||||
printf ("%s \t[%s]\n", xmp_schemas[i].name, xmp_schemas[i].uri);
|
||||
g_print ("%s \t[%s]\n", xmp_schemas[i].name, xmp_schemas[i].uri);
|
||||
else
|
||||
printf ("*** \t[%s]\n", xmp_schemas[i].uri);
|
||||
#endif
|
||||
return &(xmp_schemas[i]);
|
||||
}
|
||||
}
|
||||
/* try again but accept "http:" without "//", or missing "http://" */
|
||||
for (i = 0; xmp_schemas[i].uri != NULL; ++i)
|
||||
{
|
||||
if (g_str_has_prefix (xmp_schemas[i].uri, "http://")
|
||||
&& ((! strcmp (xmp_schemas[i].uri + 7, schema_uri))
|
||||
|| (g_str_has_prefix (schema_uri, "http:")
|
||||
&& ! strcmp (xmp_schemas[i].uri + 7, schema_uri + 5))
|
||||
))
|
||||
{
|
||||
#ifdef DEBUG_XMP_PARSER
|
||||
printf ("%s \t~~~[%s]\n", xmp_schemas[i].name, xmp_schemas[i].uri);
|
||||
g_print ("(no name) \t[%s]\n", xmp_schemas[i].uri);
|
||||
#endif
|
||||
return &(xmp_schemas[i]);
|
||||
}
|
||||
|
@ -457,16 +184,58 @@ find_xmp_schema (XMPModel *xmp_model,
|
|||
{
|
||||
if (! strcmp (((XMPSchema *)(list->data))->uri, schema_uri))
|
||||
{
|
||||
#ifdef DEBUG_XMP_PARSER
|
||||
printf ("CUSTOM %s \t[%s]\n",
|
||||
#ifdef DEBUG_XMP_MODEL
|
||||
g_print ("CUSTOM %s \t[%s]\n",
|
||||
((XMPSchema *)(list->data))->name,
|
||||
((XMPSchema *)(list->data))->uri);
|
||||
#endif
|
||||
return (XMPSchema *)(list->data);
|
||||
}
|
||||
}
|
||||
#ifdef DEBUG_XMP_PARSER
|
||||
printf ("Unknown schema URI %s\n", schema_uri);
|
||||
/* now check for some common errors and results of bad encoding: */
|
||||
/* - check for "http:" without "//", or missing "http://" */
|
||||
for (i = 0; xmp_schemas[i].uri != NULL; ++i)
|
||||
{
|
||||
if (g_str_has_prefix (xmp_schemas[i].uri, "http://")
|
||||
&& ((! strcmp (xmp_schemas[i].uri + 7, schema_uri))
|
||||
|| (g_str_has_prefix (schema_uri, "http:")
|
||||
&& ! strcmp (xmp_schemas[i].uri + 7, schema_uri + 5))
|
||||
))
|
||||
{
|
||||
#ifdef DEBUG_XMP_MODEL
|
||||
g_print ("%s \t~~~[%s]\n", xmp_schemas[i].name, xmp_schemas[i].uri);
|
||||
#endif
|
||||
return &(xmp_schemas[i]);
|
||||
}
|
||||
}
|
||||
/* - check for errors such as "name (uri)" or "name (prefix, uri)" */
|
||||
for (c = schema_uri; *c; c++)
|
||||
if ((*c == '(') || (*c == ' ') || (*c == ','))
|
||||
{
|
||||
int len;
|
||||
|
||||
c++;
|
||||
while (*c == ' ')
|
||||
c++;
|
||||
if (! *c)
|
||||
break;
|
||||
for (len = 1; c[len]; len++)
|
||||
if ((c[len] == ')') || (c[len] == ' '))
|
||||
break;
|
||||
for (i = 0; xmp_schemas[i].uri != NULL; ++i)
|
||||
{
|
||||
if (! strncmp (xmp_schemas[i].uri, c, len))
|
||||
{
|
||||
#ifdef DEBUG_XMP_MODEL
|
||||
g_print ("%s \t~~~[%s]\n", xmp_schemas[i].name,
|
||||
xmp_schemas[i].uri);
|
||||
#endif
|
||||
return &(xmp_schemas[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
#ifdef DEBUG_XMP_MODEL
|
||||
g_print ("Unknown schema URI %s\n", schema_uri);
|
||||
#endif
|
||||
return NULL;
|
||||
}
|
||||
|
@ -490,13 +259,13 @@ find_xmp_schema_prefix (XMPModel *xmp_model,
|
|||
|
||||
/* make the next lookup a bit faster if the tree is not modified */
|
||||
static void
|
||||
save_iter_for_schema (XMPModel *xmp_model,
|
||||
cache_iter_for_schema (XMPModel *xmp_model,
|
||||
XMPSchema *schema,
|
||||
GtkTreeIter *iter)
|
||||
{
|
||||
xmp_model->current_schema = schema;
|
||||
xmp_model->cached_schema = schema;
|
||||
if (iter != NULL)
|
||||
memcpy (&(xmp_model->current_schema_iter), iter, sizeof (GtkTreeIter));
|
||||
memcpy (&(xmp_model->cached_schema_iter), iter, sizeof (GtkTreeIter));
|
||||
}
|
||||
|
||||
/* find the GtkTreeIter for the given schema and return TRUE if the schema was
|
||||
|
@ -508,16 +277,16 @@ find_iter_for_schema (XMPModel *xmp_model,
|
|||
{
|
||||
XMPSchema *schema_xref;
|
||||
|
||||
if (schema == xmp_model->current_schema)
|
||||
/* common case: return the cached iter */
|
||||
if (schema == xmp_model->cached_schema)
|
||||
{
|
||||
memcpy (iter, &(xmp_model->current_schema_iter), sizeof (GtkTreeIter));
|
||||
memcpy (iter, &(xmp_model->cached_schema_iter), sizeof (GtkTreeIter));
|
||||
return TRUE;
|
||||
}
|
||||
/* check where this schema has been stored in the tree */
|
||||
/* find where this schema has been stored in the tree */
|
||||
if (! gtk_tree_model_get_iter_first (GTK_TREE_MODEL (xmp_model->treestore),
|
||||
iter))
|
||||
return FALSE;
|
||||
|
||||
do
|
||||
{
|
||||
gtk_tree_model_get (GTK_TREE_MODEL (xmp_model->treestore), iter,
|
||||
|
@ -525,7 +294,7 @@ find_iter_for_schema (XMPModel *xmp_model,
|
|||
-1);
|
||||
if (schema_xref == schema)
|
||||
{
|
||||
save_iter_for_schema (xmp_model, schema, iter);
|
||||
cache_iter_for_schema (xmp_model, schema, iter);
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
@ -585,7 +354,7 @@ add_known_schema (XMPModel *xmp_model,
|
|||
COL_XMP_WEIGHT, PANGO_WEIGHT_BOLD,
|
||||
COL_XMP_WEIGHT_SET, TRUE,
|
||||
-1);
|
||||
save_iter_for_schema (xmp_model, schema, iter);
|
||||
cache_iter_for_schema (xmp_model, schema, iter);
|
||||
}
|
||||
|
||||
/* called by the XMP parser - new schema */
|
||||
|
@ -621,7 +390,7 @@ parse_start_schema (XMPParseContext *context,
|
|||
/* schemas with NULL names are special and should not go in the tree */
|
||||
if (schema->name == NULL)
|
||||
{
|
||||
save_iter_for_schema (xmp_model, NULL, NULL);
|
||||
cache_iter_for_schema (xmp_model, NULL, NULL);
|
||||
return schema;
|
||||
}
|
||||
/* if the schema is not in the tree yet, add it now */
|
||||
|
@ -641,8 +410,11 @@ parse_end_schema (XMPParseContext *context,
|
|||
|
||||
g_return_if_fail (xmp_model != NULL);
|
||||
g_return_if_fail (schema != NULL);
|
||||
xmp_model->current_schema = NULL;
|
||||
/* printf ("End of %s\n", schema->name); */
|
||||
xmp_model->cached_schema = NULL;
|
||||
#ifdef DEBUG_XMP_MODEL
|
||||
if (schema->name)
|
||||
g_print ("End of %s\n", schema->name);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* called by the XMP parser - new property */
|
||||
|
@ -689,8 +461,8 @@ parse_set_property (XMPParseContext *context,
|
|||
switch (type)
|
||||
{
|
||||
case XMP_PTYPE_TEXT:
|
||||
#ifdef DEBUG_XMP_PARSER
|
||||
printf ("\t%s:%s = \"%s\"\n", ns_prefix, name, value[0]);
|
||||
#ifdef DEBUG_XMP_MODEL
|
||||
g_print ("\t%s:%s = \"%s\"\n", ns_prefix, name, value[0]);
|
||||
#endif
|
||||
if (property != NULL)
|
||||
/* FIXME */;
|
||||
|
@ -719,8 +491,8 @@ parse_set_property (XMPParseContext *context,
|
|||
break;
|
||||
|
||||
case XMP_PTYPE_RESOURCE:
|
||||
#ifdef DEBUG_XMP_PARSER
|
||||
printf ("\t%s:%s @ = \"%s\"\n", ns_prefix, name,
|
||||
#ifdef DEBUG_XMP_MODEL
|
||||
g_print ("\t%s:%s @ = \"%s\"\n", ns_prefix, name,
|
||||
value[0]);
|
||||
#endif
|
||||
if (property != NULL)
|
||||
|
@ -753,14 +525,14 @@ parse_set_property (XMPParseContext *context,
|
|||
|
||||
case XMP_PTYPE_ORDERED_LIST:
|
||||
case XMP_PTYPE_UNORDERED_LIST:
|
||||
#ifdef DEBUG_XMP_PARSER
|
||||
printf ("\t%s:%s [] =", ns_prefix, name);
|
||||
#ifdef DEBUG_XMP_MODEL
|
||||
g_print ("\t%s:%s [] =", ns_prefix, name);
|
||||
for (i = 0; value[i] != NULL; i++)
|
||||
if (i == 0)
|
||||
printf (" \"%s\"", value[i]);
|
||||
g_print (" \"%s\"", value[i]);
|
||||
else
|
||||
printf (", \"%s\"", value[i]);
|
||||
printf ("\n");
|
||||
g_print (", \"%s\"", value[i]);
|
||||
g_print ("\n");
|
||||
#endif
|
||||
if (property != NULL)
|
||||
/* FIXME */;
|
||||
|
@ -796,11 +568,11 @@ parse_set_property (XMPParseContext *context,
|
|||
break;
|
||||
|
||||
case XMP_PTYPE_ALT_THUMBS:
|
||||
#ifdef DEBUG_XMP_PARSER
|
||||
#ifdef DEBUG_XMP_MODEL
|
||||
for (i = 0; value[i] != NULL; i += 2)
|
||||
printf ("\t%s:%s [size:%d] = \"...\"\n", ns_prefix, name,
|
||||
g_print ("\t%s:%s [size:%d] = \"...\"\n", ns_prefix, name,
|
||||
*(int *)(value[i]));
|
||||
printf ("\n");
|
||||
g_print ("\n");
|
||||
#endif
|
||||
if (property != NULL)
|
||||
/* FIXME */;
|
||||
|
@ -832,9 +604,9 @@ parse_set_property (XMPParseContext *context,
|
|||
break;
|
||||
|
||||
case XMP_PTYPE_ALT_LANG:
|
||||
#ifdef DEBUG_XMP_PARSER
|
||||
#ifdef DEBUG_XMP_MODEL
|
||||
for (i = 0; value[i] != NULL; i += 2)
|
||||
printf ("\t%s:%s [lang:%s] = \"%s\"\n", ns_prefix, name,
|
||||
g_print ("\t%s:%s [lang:%s] = \"%s\"\n", ns_prefix, name,
|
||||
value[i], value[i + 1]);
|
||||
#endif
|
||||
if (property != NULL)
|
||||
|
@ -869,9 +641,9 @@ parse_set_property (XMPParseContext *context,
|
|||
break;
|
||||
|
||||
case XMP_PTYPE_STRUCTURE:
|
||||
#ifdef DEBUG_XMP_PARSER
|
||||
#ifdef DEBUG_XMP_MODEL
|
||||
for (i = 2; value[i] != NULL; i += 2)
|
||||
printf ("\t%s:%s [%s] = \"%s\"\n", ns_prefix, name,
|
||||
g_print ("\t%s:%s [%s] = \"%s\"\n", ns_prefix, name,
|
||||
value[i], value[i + 1]);
|
||||
#endif
|
||||
if (property != NULL)
|
||||
|
@ -880,7 +652,7 @@ parse_set_property (XMPParseContext *context,
|
|||
{
|
||||
property = g_new (XMPProperty, 1);
|
||||
property->name = g_strdup (name);
|
||||
property->type = XMP_TYPE_UNKNOWN;
|
||||
property->type = XMP_TYPE_GENERIC_STRUCTURE;
|
||||
property->editable = TRUE;
|
||||
xmp_model->custom_properties =
|
||||
g_slist_prepend (xmp_model->custom_properties, property);
|
||||
|
@ -906,8 +678,8 @@ parse_set_property (XMPParseContext *context,
|
|||
break;
|
||||
|
||||
default:
|
||||
#ifdef DEBUG_XMP_PARSER
|
||||
printf ("\t%s:%s = ?\n", ns_prefix, name);
|
||||
#ifdef DEBUG_XMP_MODEL
|
||||
g_print ("\t%s:%s = ?\n", ns_prefix, name);
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -28,85 +28,25 @@ G_BEGIN_DECLS
|
|||
|
||||
typedef struct _XMPModel XMPModel;
|
||||
|
||||
/* known data types for XMP properties, as found in the XMP specification */
|
||||
typedef enum
|
||||
{
|
||||
XMP_TYPE_BOOLEAN, /* TEXT */
|
||||
XMP_TYPE_DATE, /* TEXT */
|
||||
XMP_TYPE_DIMENSIONS, /* STRUCTURE */
|
||||
XMP_TYPE_INTEGER, /* TEXT */
|
||||
XMP_TYPE_INTEGER_SEQ, /* ORDERED_LIST */
|
||||
XMP_TYPE_LANG_ALT, /* ALT_LANG */
|
||||
XMP_TYPE_LOCALE_BAG, /* UNORDERED_LIST */
|
||||
XMP_TYPE_REAL, /* TEXT */
|
||||
XMP_TYPE_MIME_TYPE, /* TEXT */
|
||||
XMP_TYPE_TEXT, /* TEXT */
|
||||
XMP_TYPE_TEXT_BAG, /* UNORDERED_LIST */
|
||||
XMP_TYPE_TEXT_SEQ, /* ORDERED_LIST */
|
||||
XMP_TYPE_THUMBNAIL_ALT, /* ALT_THUMBS */
|
||||
XMP_TYPE_URI, /* TEXT or RESOURCE (?) */
|
||||
XMP_TYPE_XPATH_BAG, /* UNORDERED_LIST */
|
||||
XMP_TYPE_RESOURCE_EVENT_SEQ, /* ORDERED_LIST */
|
||||
XMP_TYPE_RESOURCE_REF, /* TEXT */
|
||||
XMP_TYPE_JOB_BAG, /* UNORDERED_LIST */
|
||||
XMP_TYPE_RATIONAL, /* TEXT */
|
||||
XMP_TYPE_RATIONAL_SEQ, /* ORDERED_LIST */
|
||||
XMP_TYPE_GPS_COORDINATE, /* (?) */
|
||||
XMP_TYPE_FLASH, /* STRUCTURE */
|
||||
XMP_TYPE_OECF_SFR, /* (?) */
|
||||
XMP_TYPE_CFA_PATTERN, /* (?) */
|
||||
XMP_TYPE_DEVICE_SETTINGS, /* (?) */
|
||||
XMP_TYPE_UNKNOWN
|
||||
} XMPType;
|
||||
|
||||
/* columns used in the GtkTreeStore model holding the XMP metadata */
|
||||
typedef enum
|
||||
{
|
||||
COL_XMP_NAME = 0, /* G_TYPE_STRING */
|
||||
COL_XMP_VALUE, /* G_TYPE_STRING */
|
||||
COL_XMP_VALUE_RAW, /* G_TYPE_POINTER */
|
||||
COL_XMP_TYPE_XREF, /* G_TYPE_POINTER */
|
||||
COL_XMP_WIDGET_XREF, /* G_TYPE_POINTER */
|
||||
COL_XMP_EDITABLE, /* G_TYPE_INT */
|
||||
COL_XMP_EDIT_ICON, /* GDK_TYPE_PIXBUF */
|
||||
COL_XMP_VISIBLE, /* G_TYPE_BOOLEAN */
|
||||
COL_XMP_WEIGHT, /* G_TYPE_INT */
|
||||
COL_XMP_WEIGHT_SET, /* G_TYPE_BOOLEAN */
|
||||
COL_XMP_NAME = 0, /* G_TYPE_STRING - name */
|
||||
COL_XMP_VALUE, /* G_TYPE_STRING - value as string (for viewing) */
|
||||
COL_XMP_VALUE_RAW, /* G_TYPE_POINTER - value as array (from parser) */
|
||||
COL_XMP_TYPE_XREF, /* G_TYPE_POINTER - XMPProperty or XMPSchema */
|
||||
COL_XMP_WIDGET_XREF, /* G_TYPE_POINTER - GtkWidget cross-reference */
|
||||
COL_XMP_EDITABLE, /* G_TYPE_INT - editable? */
|
||||
COL_XMP_EDIT_ICON, /* GDK_TYPE_PIXBUF - edit icon */
|
||||
COL_XMP_VISIBLE, /* G_TYPE_BOOLEAN - visible? */
|
||||
COL_XMP_WEIGHT, /* G_TYPE_INT - font weight */
|
||||
COL_XMP_WEIGHT_SET, /* G_TYPE_BOOLEAN - font weight set? */
|
||||
XMP_MODEL_NUM_COLUMNS
|
||||
} XMPModelColumns;
|
||||
|
||||
/* special value for the COL_XMP_EDITABLE column. not strictly boolean... */
|
||||
#define XMP_AUTO_UPDATE 2
|
||||
|
||||
/* XMP properties referenced in the tree via COL_XMP_TYPE_XREF (depth 2) */
|
||||
typedef struct
|
||||
{
|
||||
const gchar *name;
|
||||
XMPType type;
|
||||
gboolean editable;
|
||||
} XMPProperty;
|
||||
|
||||
/* XMP schemas referenced in the tree via COL_XMP_TYPE_XREF (depth 1) */
|
||||
typedef struct
|
||||
{
|
||||
const gchar *uri;
|
||||
const gchar *prefix;
|
||||
const gchar *name;
|
||||
XMPProperty *properties;
|
||||
} XMPSchema;
|
||||
|
||||
/* URIs of standard XMP schemas (as of January 2004) */
|
||||
#define XMP_SCHEMA_DUBLIN_CORE "http://purl.org/dc/elements/1.1/"
|
||||
#define XMP_SCHEMA_XMP_BASIC "http://ns.adobe.com/xap/1.0/"
|
||||
#define XMP_SCHEMA_XMP_RIGHTS "http://ns.adobe.com/xap/1.0/rights/"
|
||||
#define XMP_SCHEMA_XMP_MM "http://ns.adobe.com/xap/1.0/mm/"
|
||||
#define XMP_SCHEMA_XMP_BJ "http://ns.adobe.com/xap/1.0/bj/"
|
||||
#define XMP_SCHEMA_XMP_TPG "http://ns.adobe.com/xap/1.0/t/pg/"
|
||||
#define XMP_SCHEMA_PDF "http://ns.adobe.com/pdf/1.3/"
|
||||
#define XMP_SCHEMA_PHOTOSHOP "http://ns.adobe.com/photoshop/1.0/"
|
||||
#define XMP_SCHEMA_TIFF "http://ns.adobe.com/tiff/1.0/"
|
||||
#define XMP_SCHEMA_EXIF "http://ns.adobe.com/exif/1.0/"
|
||||
|
||||
XMPModel *xmp_model_new (void);
|
||||
|
||||
void xmp_model_free (XMPModel *xmp_model);
|
||||
|
|
|
@ -43,7 +43,7 @@
|
|||
* in the XMP specification (including support for UCS-2 and UCS-4)
|
||||
* - provide an API for passing unknown elements or tags to the caller
|
||||
* - think about re-writing this using a better XML parser (expat?)
|
||||
* instead of GMarkupParser
|
||||
* instead of the GMarkup parser
|
||||
*/
|
||||
|
||||
#ifndef WITHOUT_GIMP
|
||||
|
@ -116,7 +116,7 @@ xmp_parse_error_quark (void)
|
|||
* qualifiers (when <rdf:Description> is used deeper than at the top
|
||||
* level inside <rdf:RDF>). In that case, QDESC_VALUE contains the
|
||||
* value of the property and QDESC_QUAL is used for each of the
|
||||
* optional qualifiers.
|
||||
* optional qualifiers (which are currently ignored).
|
||||
*/
|
||||
typedef enum
|
||||
{
|
||||
|
@ -186,7 +186,7 @@ struct _XMPParseContext
|
|||
GMarkupParseContext *markup_context;
|
||||
};
|
||||
|
||||
/* FIXME - debugging
|
||||
#ifdef DEBUG_XMP_PARSER
|
||||
static const char *state_names[] =
|
||||
{
|
||||
"START",
|
||||
|
@ -218,8 +218,9 @@ static const char *state_names[] =
|
|||
"SKIPPING_IGNORED_ELEMENTS",
|
||||
"ERROR",
|
||||
};
|
||||
*/
|
||||
#endif
|
||||
|
||||
/* report an error and propagate it */
|
||||
static void
|
||||
parse_error (XMPParseContext *context,
|
||||
GError **error,
|
||||
|
@ -228,37 +229,37 @@ parse_error (XMPParseContext *context,
|
|||
...)
|
||||
{
|
||||
GError *tmp_error;
|
||||
gchar *s;
|
||||
va_list args;
|
||||
|
||||
va_start (args, format);
|
||||
s = g_strdup_vprintf (format, args);
|
||||
va_end (args);
|
||||
|
||||
if (code == XMP_ERROR_NO_XPACKET)
|
||||
tmp_error = g_error_new (XMP_PARSE_ERROR, code, _("Error: %s"), s);
|
||||
tmp_error = g_error_new (XMP_PARSE_ERROR, code,
|
||||
_("Error: No XMP packet found"));
|
||||
else
|
||||
{
|
||||
gint line_number;
|
||||
gint char_number;
|
||||
gchar *s;
|
||||
va_list args;
|
||||
gint line_number;
|
||||
gint char_number;
|
||||
|
||||
va_start (args, format);
|
||||
s = g_strdup_vprintf (format, args);
|
||||
va_end (args);
|
||||
g_markup_parse_context_get_position (context->markup_context,
|
||||
&line_number,
|
||||
&char_number);
|
||||
tmp_error = g_error_new (XMP_PARSE_ERROR, code,
|
||||
_("Error on line %d char %d: %s"),
|
||||
line_number, char_number, s);
|
||||
g_free (s);
|
||||
}
|
||||
g_free (s);
|
||||
|
||||
context->state = STATE_ERROR;
|
||||
if (context->parser->error)
|
||||
(*context->parser->error) (context, tmp_error,
|
||||
context->user_data);
|
||||
(*context->parser->error) (context, tmp_error, context->user_data);
|
||||
|
||||
g_propagate_error (error, tmp_error);
|
||||
}
|
||||
|
||||
/* report an error if an unexpected element is found in the wrong context */
|
||||
static void
|
||||
parse_error_element (XMPParseContext *context,
|
||||
GError **error,
|
||||
|
@ -276,12 +277,15 @@ parse_error_element (XMPParseContext *context,
|
|||
expected_element, found_element);
|
||||
}
|
||||
|
||||
/* skip an unknown element (unknown property) and its contents */
|
||||
static void
|
||||
unknown_element (XMPParseContext *context,
|
||||
GError **error,
|
||||
const gchar *element_name)
|
||||
{
|
||||
g_print ("XMP: SKIPPING %s\n", element_name); /* FIXME - debugging */
|
||||
#ifdef DEBUG_XMP_PARSER
|
||||
g_print ("XMP: SKIPPING %s\n", element_name);
|
||||
#endif
|
||||
if (context->flags & XMP_FLAG_NO_UNKNOWN_ELEMENTS)
|
||||
parse_error (context, error, XMP_ERROR_UNKNOWN_ELEMENT,
|
||||
_("Unknown element <%s>"),
|
||||
|
@ -294,6 +298,7 @@ unknown_element (XMPParseContext *context,
|
|||
}
|
||||
}
|
||||
|
||||
/* skip and element and all other elements that it may contain */
|
||||
static void
|
||||
ignore_element (XMPParseContext *context)
|
||||
{
|
||||
|
@ -302,6 +307,7 @@ ignore_element (XMPParseContext *context)
|
|||
context->state = STATE_SKIPPING_IGNORED_ELEMENTS;
|
||||
}
|
||||
|
||||
/* skip an unknown attribute (or abort if flags forbid unknown attributes) */
|
||||
static void
|
||||
unknown_attribute (XMPParseContext *context,
|
||||
GError **error,
|
||||
|
@ -313,6 +319,10 @@ unknown_attribute (XMPParseContext *context,
|
|||
parse_error (context, error, XMP_ERROR_UNKNOWN_ATTRIBUTE,
|
||||
_("Unknown attribute \"%s\"=\"%s\" in element <%s>"),
|
||||
attribute_name, attribute_value, element_name);
|
||||
#ifdef DEBUG_XMP_PARSER
|
||||
g_print ("skipping unknown attribute \"%s\"=\"%s\" in element <%s>\n",
|
||||
attribute_name, attribute_value, element_name);
|
||||
#endif
|
||||
}
|
||||
|
||||
static gboolean
|
||||
|
@ -329,6 +339,7 @@ is_whitespace_string (const gchar *string)
|
|||
return TRUE;
|
||||
}
|
||||
|
||||
/* new namespace/schema seen - add it to the list of namespaces */
|
||||
static void
|
||||
push_namespace (XMPParseContext *context,
|
||||
const gchar *uri,
|
||||
|
@ -356,6 +367,7 @@ push_namespace (XMPParseContext *context,
|
|||
ns->ns_user_data = NULL;
|
||||
}
|
||||
|
||||
/* free all namespaces that are deeper than the current element depth */
|
||||
static void
|
||||
pop_namespaces (XMPParseContext *context,
|
||||
GError **error)
|
||||
|
@ -364,7 +376,6 @@ pop_namespaces (XMPParseContext *context,
|
|||
|
||||
if (context->namespaces == NULL)
|
||||
return;
|
||||
/* free all namespaces that are deeper than the current element depth */
|
||||
ns = context->namespaces->data;
|
||||
while (ns->depth >= context->depth)
|
||||
{
|
||||
|
@ -383,6 +394,7 @@ pop_namespaces (XMPParseContext *context,
|
|||
}
|
||||
}
|
||||
|
||||
/* checks if an element name starts with the prefix of the given namespace */
|
||||
static gboolean
|
||||
has_ns_prefix (const gchar *name,
|
||||
XMLNameSpace *ns)
|
||||
|
@ -393,6 +405,8 @@ has_ns_prefix (const gchar *name,
|
|||
&& (name[ns->prefix_len] == ':'));
|
||||
}
|
||||
|
||||
/* add a new property to the schema referenced by its prefix */
|
||||
/* the value(s) of the property will be added later by add_property_value() */
|
||||
static XMLNameSpace *
|
||||
new_property_in_ns (XMPParseContext *context,
|
||||
const gchar *element_name)
|
||||
|
@ -420,6 +434,10 @@ new_property_in_ns (XMPParseContext *context,
|
|||
return NULL;
|
||||
}
|
||||
|
||||
/* store a value for the current property - if the element containing the */
|
||||
/* value is being parsed but the actual value has not been seen yet, then */
|
||||
/* call this function with a NULL value so that its data structure is */
|
||||
/* allocated now; it will be updated later with update_property_value() */
|
||||
static void
|
||||
add_property_value (XMPParseContext *context,
|
||||
XMPParseType type,
|
||||
|
@ -454,9 +472,11 @@ add_property_value (XMPParseContext *context,
|
|||
context->prop_cur_value++;
|
||||
context->prop_value[context->prop_cur_value] = value;
|
||||
context->prop_value[context->prop_cur_value + 1] = NULL;
|
||||
/* if value was NULL, then we must update it later */
|
||||
context->prop_missing_value = (value == NULL);
|
||||
}
|
||||
|
||||
/* update a value that has been allocated but not stored yet */
|
||||
static void
|
||||
update_property_value (XMPParseContext *context,
|
||||
gchar *value)
|
||||
|
@ -468,6 +488,7 @@ update_property_value (XMPParseContext *context,
|
|||
context->prop_missing_value = FALSE;
|
||||
}
|
||||
|
||||
/* invoke the 'set_property' callback and free the temporary structures */
|
||||
static void
|
||||
propagate_property (XMPParseContext *context,
|
||||
GError **error)
|
||||
|
@ -511,18 +532,14 @@ start_element_handler (GMarkupParseContext *markup_context,
|
|||
XMPParseContext *context = user_data;
|
||||
gint attr;
|
||||
|
||||
/*
|
||||
g_print ("[%02d/%02d] %d <%s>\n", context->state, context->saved_state,
|
||||
context->depth, element_name);
|
||||
*/
|
||||
/* FIXME - debugging
|
||||
#ifdef DEBUG_XMP_PARSER
|
||||
g_print ("[%25s/%17s] %d <%s>\n",
|
||||
state_names[context->state],
|
||||
(context->saved_state == STATE_ERROR
|
||||
? "-"
|
||||
: state_names[context->saved_state]),
|
||||
context->depth, element_name);
|
||||
*/
|
||||
#endif
|
||||
context->depth++;
|
||||
for (attr = 0; attribute_names[attr] != NULL; ++attr)
|
||||
if (g_str_has_prefix (attribute_names[attr], "xmlns:"))
|
||||
|
@ -818,18 +835,18 @@ end_element_handler (GMarkupParseContext *markup_context,
|
|||
{
|
||||
XMPParseContext *context = user_data;
|
||||
|
||||
#ifdef DEBUG_XMP_PARSER
|
||||
/*
|
||||
g_print ("[%02d/%02d] %d </%s>\n", context->state, context->saved_state,
|
||||
context->depth, element_name);
|
||||
*/
|
||||
/* FIXME - debugging
|
||||
g_print ("[%25s/%17s] %d </%s>\n",
|
||||
state_names[context->state],
|
||||
(context->saved_state == STATE_ERROR
|
||||
? "-"
|
||||
: state_names[context->saved_state]),
|
||||
context->depth, element_name);
|
||||
*/
|
||||
#endif
|
||||
switch (context->state)
|
||||
{
|
||||
case STATE_INSIDE_PROPERTY:
|
||||
|
@ -965,10 +982,13 @@ text_handler (GMarkupParseContext *markup_context,
|
|||
gchar *decoded;
|
||||
gint decoded_size;
|
||||
|
||||
#ifdef DEBUG_XMP_PARSER
|
||||
/* g_print ("XMP: Pushing text:\n%s\n", text); */
|
||||
#endif
|
||||
max_size = text_len - text_len / 4 + 1;
|
||||
decoded = g_malloc (max_size);
|
||||
decoded_size = base64_decode (text, text_len, decoded, max_size);
|
||||
#ifdef DEBUG_XMP_PARSER
|
||||
if (decoded_size > 0)
|
||||
{
|
||||
/* FIXME: remove this debugging code */
|
||||
|
@ -981,6 +1001,7 @@ text_handler (GMarkupParseContext *markup_context,
|
|||
*/
|
||||
g_print ("XMP: Thumb text len: %d (1/4 = %d)\nMax size: %d\nUsed size: %d\n", (int) text_len, (int) text_len / 4, max_size, decoded_size);
|
||||
}
|
||||
#endif
|
||||
if (decoded_size > 0)
|
||||
{
|
||||
gint *size_p;
|
||||
|
@ -1007,11 +1028,11 @@ text_handler (GMarkupParseContext *markup_context,
|
|||
break;
|
||||
|
||||
case STATE_INSIDE_QDESC_QUAL:
|
||||
/*
|
||||
#ifdef DEBUG_XMP_PARSER
|
||||
g_print ("ignoring qualifier for part of \"%s\"[]: \"%.*s\"\n",
|
||||
context->property,
|
||||
(int)text_len, text);
|
||||
*/
|
||||
#endif
|
||||
/* FIXME: notify the user? add a way to collect qualifiers? */
|
||||
break;
|
||||
|
||||
|
@ -1234,8 +1255,7 @@ xmp_parse_context_parse (XMPParseContext *context,
|
|||
return g_markup_parse_context_parse (context->markup_context,
|
||||
text + i, e - i + 1, error);
|
||||
}
|
||||
parse_error (context, error, XMP_ERROR_NO_XPACKET,
|
||||
_("No XMP packet found"));
|
||||
parse_error (context, error, XMP_ERROR_NO_XPACKET, NULL);
|
||||
return FALSE;
|
||||
}
|
||||
return g_markup_parse_context_parse (context->markup_context,
|
||||
|
@ -1263,7 +1283,6 @@ xmp_parse_context_end_parse (XMPParseContext *context,
|
|||
g_return_val_if_fail (context->state != STATE_ERROR, FALSE);
|
||||
|
||||
if (context->state == STATE_START)
|
||||
parse_error (context, error, XMP_ERROR_NO_XPACKET,
|
||||
_("No XMP packet found"));
|
||||
parse_error (context, error, XMP_ERROR_NO_XPACKET, NULL);
|
||||
return g_markup_parse_context_end_parse (context->markup_context, error);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,314 @@
|
|||
/* xmp-schemas.h - standard schemas defined in the XMP specifications
|
||||
*
|
||||
* Copyright (C) 2004-2005, Raphaël Quinet <raphael@gimp.org>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include "xmp-model.h"
|
||||
#include "xmp-schemas.h"
|
||||
|
||||
static XMPProperty dc_properties[] =
|
||||
{
|
||||
{ "contributor", XMP_TYPE_TEXT, TRUE },
|
||||
{ "coverage", XMP_TYPE_TEXT, TRUE },
|
||||
{ "creator", XMP_TYPE_TEXT_SEQ, TRUE },
|
||||
{ "date", XMP_TYPE_DATE, TRUE },
|
||||
{ "description", XMP_TYPE_LANG_ALT, TRUE },
|
||||
{ "format", XMP_TYPE_MIME_TYPE, XMP_AUTO_UPDATE },
|
||||
{ "identifier", XMP_TYPE_TEXT, TRUE }, /*xmp:Identifier*/
|
||||
{ "language", XMP_TYPE_LOCALE_BAG, FALSE },
|
||||
{ "publisher", XMP_TYPE_TEXT_BAG, TRUE },
|
||||
{ "relation", XMP_TYPE_TEXT_BAG, TRUE },
|
||||
{ "rights", XMP_TYPE_LANG_ALT, TRUE },
|
||||
{ "source", XMP_TYPE_TEXT, TRUE },
|
||||
{ "subject", XMP_TYPE_TEXT_BAG, TRUE },
|
||||
{ "title", XMP_TYPE_LANG_ALT, TRUE },
|
||||
{ "type", XMP_TYPE_TEXT_BAG, TRUE },
|
||||
{ NULL, XMP_TYPE_UNKNOWN, FALSE }
|
||||
};
|
||||
|
||||
static XMPProperty xmp_properties[] =
|
||||
{
|
||||
{ "Advisory", XMP_TYPE_XPATH_BAG, TRUE },
|
||||
{ "BaseURL", XMP_TYPE_URI, FALSE },
|
||||
{ "CreateDate", XMP_TYPE_DATE, TRUE },
|
||||
{ "CreatorTool", XMP_TYPE_TEXT, FALSE },
|
||||
{ "Identifier", XMP_TYPE_TEXT_BAG, TRUE },
|
||||
{ "MetadataDate", XMP_TYPE_DATE, XMP_AUTO_UPDATE },
|
||||
{ "ModifyDate", XMP_TYPE_DATE, XMP_AUTO_UPDATE },
|
||||
{ "NickName", XMP_TYPE_TEXT, TRUE },
|
||||
{ "Thumbnails", XMP_TYPE_THUMBNAIL_ALT, TRUE },
|
||||
{ NULL, XMP_TYPE_UNKNOWN, FALSE }
|
||||
};
|
||||
|
||||
static XMPProperty xmprights_properties[] =
|
||||
{
|
||||
{ "Certificate", XMP_TYPE_URI, TRUE },
|
||||
{ "Marked", XMP_TYPE_BOOLEAN, TRUE },
|
||||
{ "Owner", XMP_TYPE_TEXT_BAG, TRUE },
|
||||
{ "UsageTerms", XMP_TYPE_LANG_ALT, TRUE },
|
||||
{ "WebStatement", XMP_TYPE_URI, TRUE },
|
||||
{ NULL, XMP_TYPE_UNKNOWN, FALSE }
|
||||
};
|
||||
|
||||
static XMPProperty xmpmm_properties[] =
|
||||
{
|
||||
{ "DerivedFrom", XMP_TYPE_RESOURCE_REF, FALSE },
|
||||
{ "DocumentID", XMP_TYPE_URI, FALSE },
|
||||
{ "History", XMP_TYPE_RESOURCE_EVENT_SEQ, FALSE },
|
||||
{ "ManagedFrom", XMP_TYPE_RESOURCE_REF, FALSE },
|
||||
{ "Manager", XMP_TYPE_TEXT, FALSE },
|
||||
{ "ManageTo", XMP_TYPE_URI, FALSE },
|
||||
{ "ManageUI", XMP_TYPE_URI, FALSE },
|
||||
{ "ManagerVariant", XMP_TYPE_TEXT, FALSE },
|
||||
{ "RenditionClass", XMP_TYPE_TEXT, FALSE },
|
||||
{ "RenditionParams", XMP_TYPE_TEXT, FALSE },
|
||||
{ "VersionID", XMP_TYPE_TEXT, FALSE },
|
||||
{ "Versions", XMP_TYPE_TEXT_SEQ, FALSE },
|
||||
{ "LastURL", XMP_TYPE_URI, FALSE }, /*deprecated*/
|
||||
{ "RenditionOf", XMP_TYPE_RESOURCE_REF, FALSE }, /*deprecated*/
|
||||
{ "SaveID", XMP_TYPE_INTEGER, FALSE }, /*deprecated*/
|
||||
{ NULL, XMP_TYPE_UNKNOWN, FALSE }
|
||||
};
|
||||
|
||||
static XMPProperty xmpbj_properties[] =
|
||||
{
|
||||
{ "JobRef", XMP_TYPE_JOB_BAG, TRUE },
|
||||
{ NULL, XMP_TYPE_UNKNOWN, FALSE }
|
||||
};
|
||||
|
||||
static XMPProperty xmptpg_properties[] =
|
||||
{
|
||||
{ "MaxPageSize", XMP_TYPE_DIMENSIONS, FALSE },
|
||||
{ "NPages", XMP_TYPE_INTEGER, FALSE },
|
||||
{ NULL, XMP_TYPE_UNKNOWN, FALSE }
|
||||
};
|
||||
|
||||
static XMPProperty pdf_properties[] =
|
||||
{
|
||||
{ "Keywords", XMP_TYPE_TEXT, TRUE },
|
||||
{ "PDFVersion", XMP_TYPE_TEXT, FALSE },
|
||||
{ "Producer", XMP_TYPE_TEXT, FALSE },
|
||||
{ NULL, XMP_TYPE_UNKNOWN, FALSE }
|
||||
};
|
||||
|
||||
static XMPProperty photoshop_properties[] =
|
||||
{
|
||||
{ "AuthorsPosition", XMP_TYPE_TEXT, TRUE },
|
||||
{ "CaptionWriter", XMP_TYPE_TEXT, TRUE },
|
||||
{ "Category", XMP_TYPE_TEXT, TRUE },/* 3 ascii chars */
|
||||
{ "City", XMP_TYPE_TEXT, TRUE },
|
||||
{ "Country", XMP_TYPE_TEXT, TRUE },
|
||||
{ "Credit", XMP_TYPE_TEXT, TRUE },
|
||||
{ "DateCreated", XMP_TYPE_DATE, TRUE },
|
||||
{ "Headline", XMP_TYPE_TEXT, TRUE },
|
||||
{ "Instructions", XMP_TYPE_TEXT, TRUE },
|
||||
{ "Source", XMP_TYPE_TEXT, TRUE },
|
||||
{ "State", XMP_TYPE_TEXT, TRUE },
|
||||
{ "SupplementalCategories",XMP_TYPE_TEXT, TRUE },
|
||||
{ "TransmissionReference",XMP_TYPE_TEXT, TRUE },
|
||||
{ "Urgency", XMP_TYPE_INTEGER, TRUE },/* range: 1-8 */
|
||||
{ NULL, XMP_TYPE_UNKNOWN, FALSE }
|
||||
};
|
||||
|
||||
static XMPProperty tiff_properties[] =
|
||||
{
|
||||
{ "ImageWidth", XMP_TYPE_INTEGER, XMP_AUTO_UPDATE },
|
||||
{ "ImageLength", XMP_TYPE_INTEGER, XMP_AUTO_UPDATE },
|
||||
{ "BitsPerSample", XMP_TYPE_INTEGER_SEQ, FALSE },
|
||||
{ "Compression", XMP_TYPE_INTEGER, FALSE },/* 1 or 6 */
|
||||
{ "PhotometricInterpretation",XMP_TYPE_INTEGER, FALSE },/* 2 or 6 */
|
||||
{ "Orientation", XMP_TYPE_INTEGER, FALSE },/* 1-8 */
|
||||
{ "SamplesPerPixel", XMP_TYPE_INTEGER, FALSE },
|
||||
{ "PlanarConfiguration",XMP_TYPE_INTEGER, FALSE },/* 1 or 2 */
|
||||
{ "YCbCrSubSampling",XMP_TYPE_INTEGER_SEQ, FALSE },/* 2,1 or 2,2 */
|
||||
{ "YCbCrPositioning",XMP_TYPE_INTEGER, FALSE },/* 1 or 2 */
|
||||
{ "XResolution", XMP_TYPE_RATIONAL, XMP_AUTO_UPDATE },
|
||||
{ "YResolution", XMP_TYPE_RATIONAL, XMP_AUTO_UPDATE },
|
||||
{ "ResolutionUnit", XMP_TYPE_INTEGER, XMP_AUTO_UPDATE },/*2or3*/
|
||||
{ "TransferFunction",XMP_TYPE_INTEGER_SEQ, FALSE },/* 3 * 256 ints */
|
||||
{ "WhitePoint", XMP_TYPE_RATIONAL_SEQ, FALSE },
|
||||
{ "PrimaryChromaticities",XMP_TYPE_RATIONAL_SEQ, FALSE },
|
||||
{ "YCbCrCoefficients",XMP_TYPE_RATIONAL_SEQ, FALSE },
|
||||
{ "ReferenceBlackWhite",XMP_TYPE_RATIONAL_SEQ, FALSE },
|
||||
{ "DateTime", XMP_TYPE_DATE, FALSE },/*xmp:ModifyDate*/
|
||||
{ "ImageDescription",XMP_TYPE_LANG_ALT, TRUE },/*dc:description*/
|
||||
{ "Make", XMP_TYPE_TEXT, FALSE },
|
||||
{ "Model", XMP_TYPE_TEXT, FALSE },
|
||||
{ "Software", XMP_TYPE_TEXT, FALSE },/*xmp:CreatorTool*/
|
||||
{ "Artist", XMP_TYPE_TEXT, TRUE },/*dc:creator*/
|
||||
{ "Copyright", XMP_TYPE_TEXT, TRUE },/*dc:rights*/
|
||||
{ NULL, XMP_TYPE_UNKNOWN, FALSE }
|
||||
};
|
||||
|
||||
static XMPProperty exif_properties[] =
|
||||
{
|
||||
{ "ExifVersion", XMP_TYPE_TEXT, XMP_AUTO_UPDATE },/*"0210*/
|
||||
{ "FlashpixVersion", XMP_TYPE_TEXT, FALSE },/* "0100" */
|
||||
{ "ColorSpace", XMP_TYPE_INTEGER, FALSE },/* 1 or -32768 */
|
||||
{ "ComponentsConfiguration",XMP_TYPE_INTEGER_SEQ, FALSE },/* 4 ints */
|
||||
{ "CompressedBitsPerPixel",XMP_TYPE_RATIONAL, FALSE },
|
||||
{ "PixelXDimension", XMP_TYPE_INTEGER, XMP_AUTO_UPDATE },
|
||||
{ "PixelYDimension", XMP_TYPE_INTEGER, XMP_AUTO_UPDATE },
|
||||
{ "MakerNote", XMP_TYPE_TEXT, FALSE },/* base64 enc.? */
|
||||
{ "UserComment", XMP_TYPE_TEXT, TRUE },
|
||||
{ "RelatedSoundFile",XMP_TYPE_TEXT, FALSE },/* DOS 8.3 fname */
|
||||
{ "DateTimeOriginal",XMP_TYPE_DATE, FALSE },
|
||||
{ "DateTimeDigitized",XMP_TYPE_DATE, FALSE },
|
||||
{ "ExposureTime", XMP_TYPE_RATIONAL, FALSE },
|
||||
{ "FNumber", XMP_TYPE_RATIONAL, FALSE },
|
||||
{ "ExposureProgram", XMP_TYPE_INTEGER, FALSE },/* 0-8 */
|
||||
{ "SpectralSensitivity",XMP_TYPE_TEXT, FALSE },/* ? */
|
||||
{ "ISOSpeedRatings", XMP_TYPE_INTEGER_SEQ, FALSE },
|
||||
{ "OECF", XMP_TYPE_OECF_SFR, FALSE },
|
||||
{ "ShutterSpeedValue",XMP_TYPE_RATIONAL, FALSE },
|
||||
{ "ApertureValue", XMP_TYPE_RATIONAL, FALSE },
|
||||
{ "BrightnessValue", XMP_TYPE_RATIONAL, FALSE },
|
||||
{ "ExposureBiasValue",XMP_TYPE_RATIONAL, FALSE },
|
||||
{ "MaxApertureValue",XMP_TYPE_RATIONAL, FALSE },
|
||||
{ "SubjectDistance", XMP_TYPE_RATIONAL, FALSE },/* in meters */
|
||||
{ "MeteringMode", XMP_TYPE_INTEGER, FALSE },/* 0-6 or 255 */
|
||||
{ "LightSource", XMP_TYPE_INTEGER, FALSE },/* 0-3,17-22,255*/
|
||||
{ "Flash", XMP_TYPE_FLASH, FALSE },
|
||||
{ "FocalLength", XMP_TYPE_RATIONAL, FALSE },
|
||||
{ "SubjectArea", XMP_TYPE_INTEGER_SEQ, FALSE },
|
||||
{ "FlashEnergy", XMP_TYPE_RATIONAL, FALSE },
|
||||
{ "SpatialFrequencyResponse",XMP_TYPE_OECF_SFR, FALSE },
|
||||
{ "FocalPlaneXResolution",XMP_TYPE_RATIONAL, FALSE },
|
||||
{ "FocalPlaneYResolution",XMP_TYPE_RATIONAL, FALSE },
|
||||
{ "FocalPlaneResolutionUnit",XMP_TYPE_INTEGER, FALSE },/* unit: 2 or 3 */
|
||||
{ "SubjectLocation", XMP_TYPE_INTEGER_SEQ, FALSE },/* 2 ints: X, Y */
|
||||
{ "ExposureIndex", XMP_TYPE_RATIONAL, FALSE },
|
||||
{ "SensingMethod", XMP_TYPE_INTEGER, FALSE },/* 1-8 */
|
||||
{ "FileSource", XMP_TYPE_INTEGER, FALSE },/* 3 */
|
||||
{ "SceneType", XMP_TYPE_INTEGER, FALSE },/* 1 */
|
||||
{ "CFAPattern", XMP_TYPE_CFA_PATTERN, FALSE },
|
||||
{ "CustomRendered", XMP_TYPE_INTEGER, FALSE },/* 0-1 */
|
||||
{ "ExposureMode", XMP_TYPE_INTEGER, FALSE },/* 0-2 */
|
||||
{ "WhiteBalance", XMP_TYPE_INTEGER, FALSE },/* 0-1 */
|
||||
{ "DigitalZoomRatio",XMP_TYPE_RATIONAL, FALSE },
|
||||
{ "FocalLengthIn35mmFilm",XMP_TYPE_INTEGER, FALSE },/* in mm */
|
||||
{ "SceneCaptureType",XMP_TYPE_INTEGER, FALSE },/* 0-3 */
|
||||
{ "GainControl", XMP_TYPE_INTEGER, FALSE },/* 0-4 */
|
||||
{ "Contrast", XMP_TYPE_INTEGER, FALSE },/* 0-2 */
|
||||
{ "Saturation", XMP_TYPE_INTEGER, FALSE },/* 0-2 */
|
||||
{ "Sharpness", XMP_TYPE_INTEGER, FALSE },/* 0-2 */
|
||||
{ "DeviceSettingDescription",XMP_TYPE_DEVICE_SETTINGS, FALSE },
|
||||
{ "SubjectDistanceRange",XMP_TYPE_INTEGER, FALSE },/* 0-3 */
|
||||
{ "ImageUniqueID", XMP_TYPE_TEXT, FALSE },/* 32 chars */
|
||||
{ "GPSVersionID", XMP_TYPE_TEXT, FALSE },/* "2.0.0.0" */
|
||||
{ "GPSLatitude", XMP_TYPE_GPS_COORDINATE, FALSE },
|
||||
{ "GPSLongitude", XMP_TYPE_GPS_COORDINATE, FALSE },
|
||||
{ "GPSAltitudeRef", XMP_TYPE_INTEGER, FALSE },/* 0-1 */
|
||||
{ "GPSAltitude", XMP_TYPE_RATIONAL, FALSE },/* in meters */
|
||||
{ "GPSTimeStamp", XMP_TYPE_DATE, FALSE },
|
||||
{ "GPSSatellites", XMP_TYPE_TEXT, FALSE },/* ? */
|
||||
{ "GPSStatus", XMP_TYPE_TEXT, FALSE },/* "A" or "V" */
|
||||
{ "GPSMeasureMode", XMP_TYPE_INTEGER, FALSE },/* 2-3 */
|
||||
{ "GPSDOP", XMP_TYPE_RATIONAL, FALSE },
|
||||
{ "GPSSpeedRef", XMP_TYPE_TEXT, FALSE },/* "K","M","N" */
|
||||
{ "GPSSpeed", XMP_TYPE_RATIONAL, FALSE },
|
||||
{ "GPSTrackRef", XMP_TYPE_TEXT, FALSE },/* "T" or "M"" */
|
||||
{ "GPSTrack", XMP_TYPE_RATIONAL, FALSE },
|
||||
{ "GPSImgDirectionRef",XMP_TYPE_TEXT, FALSE },/* "T" or "M"" */
|
||||
{ "GPSImgDirection", XMP_TYPE_RATIONAL, FALSE },
|
||||
{ "GPSMapDatum", XMP_TYPE_TEXT, FALSE },
|
||||
{ "GPSDestLatitude", XMP_TYPE_GPS_COORDINATE, FALSE },
|
||||
{ "GPSDestLongitude",XMP_TYPE_GPS_COORDINATE, FALSE },
|
||||
{ "GPSDestBearingRef",XMP_TYPE_TEXT, FALSE },/* "T" or "M"" */
|
||||
{ "GPSDestBearing", XMP_TYPE_RATIONAL, FALSE },
|
||||
{ "GPSDestDistanceRef",XMP_TYPE_TEXT, FALSE },/* "K","M","N" */
|
||||
{ "GPSDestDistance", XMP_TYPE_RATIONAL, FALSE },
|
||||
{ "GPSProcessingMethod",XMP_TYPE_TEXT, FALSE },
|
||||
{ "GPSAreaInformation",XMP_TYPE_TEXT, FALSE },
|
||||
{ "GPSDifferential", XMP_TYPE_INTEGER, FALSE },/* 0-1 */
|
||||
{ NULL, XMP_TYPE_UNKNOWN, FALSE }
|
||||
};
|
||||
|
||||
static XMPProperty xmpplus_properties[] =
|
||||
{
|
||||
{ "CreditLineReq", XMP_TYPE_BOOLEAN, TRUE },
|
||||
{ "ReuseAllowed", XMP_TYPE_BOOLEAN, TRUE },
|
||||
{ NULL, XMP_TYPE_UNKNOWN, FALSE }
|
||||
};
|
||||
|
||||
static XMPProperty iptccore_properties[] =
|
||||
{
|
||||
/* FIXME */
|
||||
{ "CreatorContactInfo",XMP_TYPE_GENERIC_STRUCTURE,TRUE },
|
||||
{ NULL, XMP_TYPE_UNKNOWN, FALSE }
|
||||
};
|
||||
|
||||
static XMPProperty cc_properties[] =
|
||||
{
|
||||
{ "license", XMP_TYPE_URI, TRUE },
|
||||
{ NULL, XMP_TYPE_UNKNOWN, FALSE }
|
||||
};
|
||||
|
||||
static XMPSchema xmp_schemas_array[] =
|
||||
{
|
||||
/* XMP schemas defined as of January 2004 */
|
||||
{ XMP_SCHEMA_DUBLIN_CORE, XMP_PREFIX_DUBLIN_CORE,
|
||||
"Dublin Core", dc_properties },
|
||||
{ XMP_SCHEMA_XMP_BASIC, XMP_PREFIX_XMP_BASIC,
|
||||
"XMP Basic", xmp_properties },
|
||||
{ XMP_SCHEMA_XMP_RIGHTS, XMP_PREFIX_XMP_RIGHTS,
|
||||
"XMP Rights Management", xmprights_properties },
|
||||
{ XMP_SCHEMA_XMP_MM, XMP_PREFIX_XMP_MM,
|
||||
"XMP Media Management", xmpmm_properties },
|
||||
{ XMP_SCHEMA_XMP_BJ, XMP_PREFIX_XMP_BJ,
|
||||
"XMP Basic Job Ticket", xmpbj_properties },
|
||||
{ XMP_SCHEMA_XMP_TPG, XMP_PREFIX_XMP_TPG,
|
||||
"XMP Paged-Text", xmptpg_properties },
|
||||
{ XMP_SCHEMA_PDF, XMP_PREFIX_PDF,
|
||||
"Adobe PDF", pdf_properties },
|
||||
{ XMP_SCHEMA_PHOTOSHOP, XMP_PREFIX_PHOTOSHOP,
|
||||
"Photoshop", photoshop_properties },
|
||||
{ XMP_SCHEMA_TIFF, XMP_PREFIX_TIFF,
|
||||
"EXIF (TIFF Properties)", tiff_properties },
|
||||
{ XMP_SCHEMA_EXIF, XMP_PREFIX_EXIF,
|
||||
"EXIF (EXIF-specific Properties)", exif_properties },
|
||||
/* Additional schemas published in March 2005 */
|
||||
{ XMP_SCHEMA_XMP_PLUS, XMP_PREFIX_XMP_PLUS,
|
||||
"XMP Photographic Licensing Universal System", xmpplus_properties },
|
||||
{ XMP_SCHEMA_IPTC_CORE, XMP_PREFIX_IPTC_CORE,
|
||||
"IPTC Core", iptccore_properties },
|
||||
/* other useful namespaces */
|
||||
{ "http://web.resource.org/cc/", "cc",
|
||||
"Creative Commons", cc_properties },
|
||||
{ "http://ns.adobe.com/iX/1.0/", "iX",
|
||||
NULL, NULL },
|
||||
/* XMP sub-types (not top-level schemas) */
|
||||
{ "http://ns.adobe.com/xmp/Identifier/qual/1.0/", "xmpidq",
|
||||
NULL, NULL },
|
||||
{ "http://ns.adobe.com/xap/1.0/g/img/", "xapGImg",
|
||||
NULL, NULL },
|
||||
{ "http://ns.adobe.com/xap/1.0/sType/Dimensions#", "stDim",
|
||||
NULL, NULL },
|
||||
{ "http://ns.adobe.com/xap/1.0/sType/ResourceEvent#", "stEvt",
|
||||
NULL, NULL },
|
||||
{ "http://ns.adobe.com/xap/1.0/sType/ResourceRef#", "stRef",
|
||||
NULL, NULL },
|
||||
{ "http://ns.adobe.com/xap/1.0/sType/Version#", "stVer",
|
||||
NULL, NULL },
|
||||
{ "http://ns.adobe.com/xap/1.0/sType/Job#", "stJob",
|
||||
NULL, NULL },
|
||||
{ NULL, NULL, NULL }
|
||||
};
|
||||
|
||||
XMPSchema * const xmp_schemas = xmp_schemas_array;
|
|
@ -0,0 +1,109 @@
|
|||
/* xmp-schemas.h - standard schemas defined in the XMP specifications
|
||||
*
|
||||
* Copyright (C) 2004, Raphaël Quinet <raphael@gimp.org>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#ifndef XMP_SCHEMAS_H
|
||||
#define XMP_SCHEMAS_H
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
/* known data types for XMP properties, as found in the XMP specification */
|
||||
typedef enum
|
||||
{
|
||||
XMP_TYPE_BOOLEAN, /* TEXT */
|
||||
XMP_TYPE_DATE, /* TEXT */
|
||||
XMP_TYPE_DIMENSIONS, /* STRUCTURE */
|
||||
XMP_TYPE_INTEGER, /* TEXT */
|
||||
XMP_TYPE_INTEGER_SEQ, /* ORDERED_LIST */
|
||||
XMP_TYPE_LANG_ALT, /* ALT_LANG */
|
||||
XMP_TYPE_LOCALE_BAG, /* UNORDERED_LIST */
|
||||
XMP_TYPE_REAL, /* TEXT */
|
||||
XMP_TYPE_MIME_TYPE, /* TEXT */
|
||||
XMP_TYPE_TEXT, /* TEXT */
|
||||
XMP_TYPE_TEXT_BAG, /* UNORDERED_LIST */
|
||||
XMP_TYPE_TEXT_SEQ, /* ORDERED_LIST */
|
||||
XMP_TYPE_THUMBNAIL_ALT, /* ALT_THUMBS */
|
||||
XMP_TYPE_URI, /* TEXT or RESOURCE (?) */
|
||||
XMP_TYPE_XPATH_BAG, /* UNORDERED_LIST */
|
||||
XMP_TYPE_RESOURCE_EVENT_SEQ, /* ORDERED_LIST */
|
||||
XMP_TYPE_RESOURCE_REF, /* TEXT */
|
||||
XMP_TYPE_JOB_BAG, /* UNORDERED_LIST */
|
||||
XMP_TYPE_RATIONAL, /* TEXT */
|
||||
XMP_TYPE_RATIONAL_SEQ, /* ORDERED_LIST */
|
||||
XMP_TYPE_GPS_COORDINATE, /* (?) */
|
||||
XMP_TYPE_FLASH, /* STRUCTURE */
|
||||
XMP_TYPE_OECF_SFR, /* (?) */
|
||||
XMP_TYPE_CFA_PATTERN, /* (?) */
|
||||
XMP_TYPE_DEVICE_SETTINGS, /* (?) */
|
||||
XMP_TYPE_GENERIC_STRUCTURE, /* STRUCTURE */
|
||||
XMP_TYPE_UNKNOWN
|
||||
} XMPType;
|
||||
|
||||
/* XMP properties referenced in the tree via COL_XMP_TYPE_XREF (depth 2) */
|
||||
typedef struct
|
||||
{
|
||||
const gchar *name;
|
||||
XMPType type;
|
||||
gboolean editable;
|
||||
} XMPProperty;
|
||||
|
||||
/* XMP schemas referenced in the tree via COL_XMP_TYPE_XREF (depth 1) */
|
||||
typedef struct
|
||||
{
|
||||
const gchar *uri;
|
||||
const gchar *prefix;
|
||||
const gchar *name;
|
||||
XMPProperty *properties;
|
||||
} XMPSchema;
|
||||
|
||||
/* URIs of standard XMP schemas (as of January 2004) */
|
||||
#define XMP_SCHEMA_DUBLIN_CORE "http://purl.org/dc/elements/1.1/"
|
||||
#define XMP_SCHEMA_XMP_BASIC "http://ns.adobe.com/xap/1.0/"
|
||||
#define XMP_SCHEMA_XMP_RIGHTS "http://ns.adobe.com/xap/1.0/rights/"
|
||||
#define XMP_SCHEMA_XMP_MM "http://ns.adobe.com/xap/1.0/mm/"
|
||||
#define XMP_SCHEMA_XMP_BJ "http://ns.adobe.com/xap/1.0/bj/"
|
||||
#define XMP_SCHEMA_XMP_TPG "http://ns.adobe.com/xap/1.0/t/pg/"
|
||||
#define XMP_SCHEMA_PDF "http://ns.adobe.com/pdf/1.3/"
|
||||
#define XMP_SCHEMA_PHOTOSHOP "http://ns.adobe.com/photoshop/1.0/"
|
||||
#define XMP_SCHEMA_TIFF "http://ns.adobe.com/tiff/1.0/"
|
||||
#define XMP_SCHEMA_EXIF "http://ns.adobe.com/exif/1.0/"
|
||||
/* Additional schemas published in March 2005 */
|
||||
#define XMP_SCHEMA_XMP_PLUS "http://ns.adobe.com/xap/1.0/PLUS/"
|
||||
#define XMP_SCHEMA_IPTC_CORE "http://iptc.org/std/Iptc4xmpCore/1.0/xmlns/"
|
||||
|
||||
/* recommended prefixes for the schemas listed above */
|
||||
#define XMP_PREFIX_DUBLIN_CORE "dc"
|
||||
#define XMP_PREFIX_XMP_BASIC "xmp"
|
||||
#define XMP_PREFIX_XMP_RIGHTS "xmpRights"
|
||||
#define XMP_PREFIX_XMP_MM "xmpMM"
|
||||
#define XMP_PREFIX_XMP_BJ "xmpBJ"
|
||||
#define XMP_PREFIX_XMP_TPG "xmpTPg"
|
||||
#define XMP_PREFIX_PDF "pdf"
|
||||
#define XMP_PREFIX_PHOTOSHOP "photoshop"
|
||||
#define XMP_PREFIX_TIFF "tiff"
|
||||
#define XMP_PREFIX_EXIF "exif"
|
||||
#define XMP_PREFIX_XMP_PLUS "xmpPLUS"
|
||||
#define XMP_PREFIX_IPTC_CORE "Iptc4xmpCore"
|
||||
|
||||
/* List of known XMP schemas and their properties */
|
||||
XMPSchema * const xmp_schemas;
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* XMP_SCHEMAS_H */
|
|
@ -12,7 +12,7 @@ start_schema (XMPParseContext *context,
|
|||
gpointer user_data,
|
||||
GError **error)
|
||||
{
|
||||
printf ("Schema %s = \"%s\"\n", ns_prefix, ns_uri);
|
||||
g_print ("Schema %s = \"%s\"\n", ns_prefix, ns_uri);
|
||||
return (gpointer) ns_prefix;
|
||||
}
|
||||
|
||||
|
@ -22,7 +22,7 @@ end_schema (XMPParseContext *context,
|
|||
gpointer user_data,
|
||||
GError **error)
|
||||
{
|
||||
/* printf ("End of %s\n", user_ns_prefix); */
|
||||
/* g_print ("End of %s\n", user_ns_prefix); */
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -40,47 +40,47 @@ set_property (XMPParseContext *context,
|
|||
switch (type)
|
||||
{
|
||||
case XMP_PTYPE_TEXT:
|
||||
printf ("\t%s:%s = \"%s\"\n", ns_prefix, name,
|
||||
value[0]);
|
||||
g_print ("\t%s:%s = \"%s\"\n", ns_prefix, name,
|
||||
value[0]);
|
||||
break;
|
||||
|
||||
case XMP_PTYPE_RESOURCE:
|
||||
printf ("\t%s:%s @ = \"%s\"\n", ns_prefix, name,
|
||||
value[0]);
|
||||
g_print ("\t%s:%s @ = \"%s\"\n", ns_prefix, name,
|
||||
value[0]);
|
||||
break;
|
||||
|
||||
case XMP_PTYPE_ORDERED_LIST:
|
||||
case XMP_PTYPE_UNORDERED_LIST:
|
||||
printf ("\t%s:%s [] =", ns_prefix, name);
|
||||
g_print ("\t%s:%s [] =", ns_prefix, name);
|
||||
for (i = 0; value[i] != NULL; i++)
|
||||
if (i == 0)
|
||||
printf (" \"%s\"", value[i]);
|
||||
g_print (" \"%s\"", value[i]);
|
||||
else
|
||||
printf (", \"%s\"", value[i]);
|
||||
printf ("\n");
|
||||
g_print (", \"%s\"", value[i]);
|
||||
g_print ("\n");
|
||||
break;
|
||||
|
||||
case XMP_PTYPE_ALT_THUMBS:
|
||||
for (i = 0; value[i] != NULL; i += 2)
|
||||
printf ("\t%s:%s [size = %d] = \"...\"\n", ns_prefix, name,
|
||||
*(int*)(value[i])); /* FIXME: show part of image */
|
||||
g_print ("\t%s:%s [size = %d] = \"...\"\n", ns_prefix, name,
|
||||
*(int*)(value[i])); /* FIXME: show part of image */
|
||||
break;
|
||||
|
||||
case XMP_PTYPE_ALT_LANG:
|
||||
for (i = 0; value[i] != NULL; i += 2)
|
||||
printf ("\t%s:%s [lang:%s] = \"%s\"\n", ns_prefix, name,
|
||||
value[i], value[i + 1]);
|
||||
g_print ("\t%s:%s [lang:%s] = \"%s\"\n", ns_prefix, name,
|
||||
value[i], value[i + 1]);
|
||||
break;
|
||||
|
||||
case XMP_PTYPE_STRUCTURE:
|
||||
printf ("\tLocal schema %s = \"%s\"\n", value[0], value[1]);
|
||||
g_print ("\tLocal schema %s = \"%s\"\n", value[0], value[1]);
|
||||
for (i = 2; value[i] != NULL; i += 2)
|
||||
printf ("\t%s:%s [%s] = \"%s\"\n", ns_prefix, name,
|
||||
value[i], value[i + 1]);
|
||||
g_print ("\t%s:%s [%s] = \"%s\"\n", ns_prefix, name,
|
||||
value[i], value[i + 1]);
|
||||
break;
|
||||
|
||||
default:
|
||||
printf ("\t%s:%s = ?\n", ns_prefix, name);
|
||||
g_print ("\t%s:%s = ?\n", ns_prefix, name);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -92,8 +92,8 @@ print_error (XMPParseContext *context,
|
|||
{
|
||||
gchar *filename = user_data;
|
||||
|
||||
fprintf (stderr, "While parsing XMP metadata in %s:\n%s\n",
|
||||
filename, error->message);
|
||||
g_printerr ("While parsing XMP metadata in %s:\n%s\n",
|
||||
filename, error->message);
|
||||
}
|
||||
|
||||
static XMPParser xmp_parser = {
|
||||
|
@ -111,7 +111,7 @@ scan_file (const gchar *filename)
|
|||
GError *error;
|
||||
XMPParseContext *context;
|
||||
|
||||
printf ("\nFile: %s\n", filename);
|
||||
g_print ("\nFile: %s\n", filename);
|
||||
error = NULL;
|
||||
if (!g_file_get_contents (filename,
|
||||
&contents,
|
||||
|
@ -157,7 +157,7 @@ main (int argc,
|
|||
}
|
||||
else
|
||||
{
|
||||
fprintf (stderr, "Usage:\n"
|
||||
g_print ("Usage:\n"
|
||||
"\txmpdump file [file [...]]\n\n"
|
||||
"The file(s) given on the command line will be scanned "
|
||||
"for XMP metadata\n");
|
||||
|
|
Loading…
Reference in New Issue