[libgxps] Add API to get Core Propoerties of a XPS file



commit 3c5063e8909bcc96d75969dd5d4a4fbc5c6e129c
Author: Carlos Garcia Campos <carlosgc gnome org>
Date:   Fri Jan 11 18:10:22 2013 +0100

    Add API to get Core Propoerties of a XPS file

 TODO                                |    1 -
 docs/reference/libgxps-docs.sgml    |    1 +
 docs/reference/libgxps-sections.txt |   35 ++
 docs/reference/libgxps.types        |    1 +
 libgxps/Makefile.am                 |    2 +
 libgxps/gxps-core-properties.c      |  843 +++++++++++++++++++++++++++++++++++
 libgxps/gxps-core-properties.h      |   80 ++++
 libgxps/gxps-file.c                 |   25 +
 libgxps/gxps-file.h                 |   25 +-
 libgxps/gxps-private.h              |    4 +
 10 files changed, 1005 insertions(+), 12 deletions(-)
---
diff --git a/TODO b/TODO
index f09aff1..2f21d8e 100644
--- a/TODO
+++ b/TODO
@@ -8,7 +8,6 @@ GXPSFile
 --------
 
 - Thumbnail API
-- Core-properties API
 
 GXPSDocument
 ------------
diff --git a/docs/reference/libgxps-docs.sgml b/docs/reference/libgxps-docs.sgml
index caa7476..8fcd50f 100644
--- a/docs/reference/libgxps-docs.sgml
+++ b/docs/reference/libgxps-docs.sgml
@@ -18,6 +18,7 @@
     <xi:include href="xml/gxps-page.xml"/>
     <xi:include href="xml/gxps-links.xml"/>
     <xi:include href="xml/gxps-document-structure.xml"/>
+    <xi:include href="xml/gxps-core-properties.xml"/>
     <xi:include href="xml/gxps-error.xml"/>
     <xi:include href="xml/gxps-version.xml"/>
   </chapter>
diff --git a/docs/reference/libgxps-sections.txt b/docs/reference/libgxps-sections.txt
index 05da8a3..e8bff13 100644
--- a/docs/reference/libgxps-sections.txt
+++ b/docs/reference/libgxps-sections.txt
@@ -10,6 +10,7 @@ gxps_file_new
 gxps_file_get_n_documents
 gxps_file_get_document
 gxps_file_get_document_for_link_target
+gxps_file_get_core_properties
 
 <SUBSECTION Standard>
 GXPS_TYPE_FILE
@@ -129,6 +130,40 @@ gxps_document_structure_get_type
 </SECTION>
 
 <SECTION>
+<FILE>gxps-core-properties</FILE>
+<TITLE>GXPSCoreProperties</TITLE>
+GXPSCoreProperties
+gxps_core_properties_get_title
+gxps_core_properties_get_creator
+gxps_core_properties_get_description
+gxps_core_properties_get_subject
+gxps_core_properties_get_keywords
+gxps_core_properties_get_version
+gxps_core_properties_get_revision
+gxps_core_properties_get_identifier
+gxps_core_properties_get_language
+gxps_core_properties_get_category
+gxps_core_properties_get_content_status
+gxps_core_properties_get_content_type
+gxps_core_properties_get_created
+gxps_core_properties_get_last_modified_by
+gxps_core_properties_get_modified
+gxps_core_properties_get_last_printed
+
+<SUBSECTION Standard>
+GXPS_TYPE_CORE_PROPERTIES
+GXPS_CORE_PROPERTIES
+GXPS_IS_CORE_PROPERTIES
+GXPS_CORE_PROPERTIES_CLASS
+GXPS_IS_CORE_PROPERTIES_CLASS
+GXPS_CORE_PROPERTIES_GET_CLASS
+
+<SUBSECTION Private>
+GXPSCorePropertiesPrivate
+gxps_core_properties_get_type
+</SECTION>
+
+<SECTION>
 <FILE>gxps-error</FILE>
 GXPS_ERROR
 GXPSError
diff --git a/docs/reference/libgxps.types b/docs/reference/libgxps.types
index 77f1144..79ccb57 100644
--- a/docs/reference/libgxps.types
+++ b/docs/reference/libgxps.types
@@ -6,3 +6,4 @@ gxps_page_get_type
 gxps_link_target_get_type
 gxps_link_get_type
 gxps_document_structure_get_type
+gxps_core_properties_get_type
diff --git a/libgxps/Makefile.am b/libgxps/Makefile.am
index 02c9c21..8f633b9 100644
--- a/libgxps/Makefile.am
+++ b/libgxps/Makefile.am
@@ -16,6 +16,7 @@ NOINST_H_FILES = \
 
 INST_H_FILES = \
 	gxps.h				\
+	gxps-core-properties.h		\
 	gxps-document.h			\
 	gxps-document-structure.h	\
 	gxps-error.h			\
@@ -31,6 +32,7 @@ libgxps_la_SOURCES = \
 	gxps-archive.c			\
 	gxps-brush.c			\
 	gxps-color.c			\
+	gxps-core-properties.c		\
 	gxps-debug.c			\
 	gxps-document.c			\
 	gxps-document-structure.c	\
diff --git a/libgxps/gxps-core-properties.c b/libgxps/gxps-core-properties.c
new file mode 100644
index 0000000..22e4555
--- /dev/null
+++ b/libgxps/gxps-core-properties.c
@@ -0,0 +1,843 @@
+/* GXPSCoreProperties
+ *
+ * Copyright (C) 2013  Carlos Garcia Campos <carlosgc gnome 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.1 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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#include <config.h>
+
+#include "gxps-core-properties.h"
+#include "gxps-private.h"
+#include "gxps-error.h"
+#include <string.h>
+#include <errno.h>
+
+/**
+ * SECTION:gxps-core-properties
+ * @Short_description: XPS Core Properties
+ * @Title: GXPSCoreProperties
+ * @See_also: #GXPSFile
+ *
+ * #GXPSCoreProperties represents the metadata of a #GXPSFile.
+ * #GXPSCoreProperties objects can not be created directly, they
+ * are retrieved from a #GXPSFile with gxps_file_get_core_properties().
+ */
+
+enum {
+        PROP_0,
+        PROP_ARCHIVE,
+        PROP_SOURCE
+};
+
+struct _GXPSCorePropertiesPrivate {
+        GXPSArchive *zip;
+        gchar       *source;
+
+        gboolean     initialized;
+        GError      *init_error;
+
+        gchar       *category;
+        gchar       *content_status;
+        gchar       *content_type;
+        time_t       created;
+        gchar       *creator;
+        gchar       *description;
+        gchar       *identifier;
+        gchar       *keywords;
+        gchar       *language;
+        gchar       *last_modified_by;
+        time_t       last_printed;
+        time_t       modified;
+        gchar       *revision;
+        gchar       *subject;
+        gchar       *title;
+        gchar       *version;
+};
+
+static void initable_iface_init (GInitableIface *initable_iface);
+
+G_DEFINE_TYPE_WITH_CODE (GXPSCoreProperties, gxps_core_properties, G_TYPE_OBJECT,
+                         G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE, initable_iface_init))
+
+/* CoreProperties parser */
+typedef enum {
+        CP_UNKNOWN,
+        CP_CATEGORY,
+        CP_CONTENT_STATUS,
+        CP_CONTENT_TYPE,
+        CP_CREATED,
+        CP_CREATOR,
+        CP_DESCRIPTION,
+        CP_IDENTIFIER,
+        CP_KEYWORDS,
+        CP_LANGUAGE,
+        CP_LAST_MODIFIED_BY,
+        CP_LAST_PRINTED,
+        CP_MODIFIED,
+        CP_REVISION,
+        CP_SUBJECT,
+        CP_TITLE,
+        CP_VERSION
+} CoreProperty;
+
+typedef struct _CorePropsParserData {
+        GXPSCoreProperties *core_props;
+        CoreProperty        property;
+        GString            *buffer;
+} CorePropsParserData;
+
+static gchar *
+parse_int (const gchar *value,
+           gint        *int_value)
+{
+        gint64 result;
+        gchar *endptr = NULL;
+
+        *int_value = -1;
+
+        if (!value)
+                return NULL;
+
+        errno = 0;
+        result = g_ascii_strtoll (value, &endptr, 10);
+        if (errno || endptr == value || result > G_MAXINT || result < G_MININT)
+                return NULL;
+
+        *int_value = result;
+
+        return endptr;
+}
+
+static gboolean
+parse_date (const gchar *date,
+            gint        *year,
+            gint        *mon,
+            gint        *day,
+            gint        *hour,
+            gint        *min,
+            gint        *sec,
+            gint        *tz)
+{
+        gint         value;
+        const gchar *str = date;
+
+        /* Year:
+         *     YYYY (eg 1997)
+         * Year and month:
+         *     YYYY-MM (eg 1997-07)
+         * Complete date:
+         *     YYYY-MM-DD (eg 1997-07-16)
+         * Complete date plus hours and minutes:
+         *     YYYY-MM-DDThh:mmTZD (eg 1997-07-16T19:20+01:00)
+         * Complete date plus hours, minutes and seconds:
+         *     YYYY-MM-DDThh:mm:ssTZD (eg 1997-07-16T19:20:30+01:00)
+         * Complete date plus hours, minutes, seconds and a decimal fraction of a second
+         *     YYYY-MM-DDThh:mm:ss.sTZD (eg 1997-07-16T19:20:30.45+01:00)
+         * where:
+         *
+         * YYYY = four-digit year
+         * MM   = two-digit month (01=January, etc.)
+         * DD   = two-digit day of month (01 through 31)
+         * hh   = two digits of hour (00 through 23) (am/pm NOT allowed)
+         * mm   = two digits of minute (00 through 59)
+         * ss   = two digits of second (00 through 59)
+         * s    = one or more digits representing a decimal fraction of a second
+         * TZD  = time zone designator (Z or +hh:mm or -hh:mm)
+         */
+
+        /* Year */
+        str = parse_int (str, &value);
+        *year = value;
+        if (!str)
+                return value != -1;
+
+        if (*str != '-')
+                return FALSE;
+        str++;
+
+        /* Month */
+        str = parse_int (str, &value);
+        *mon = value;
+        if (!str)
+                return value != -1;
+
+        if (*str != '-')
+                return FALSE;
+        str++;
+
+        /* Day */
+        str = parse_int (str, &value);
+        *day = value;
+        if (!str)
+                return value != -1;
+
+        if (*str != 'T')
+                return FALSE;
+        str++;
+
+        /* Hour */
+        str = parse_int (str, &value);
+        *hour = value;
+        if (!str)
+                return value != -1;
+
+        if (*str != ':')
+                return FALSE;
+        str++;
+
+        /* Minute */
+        str = parse_int (str, &value);
+        *min = value;
+        if (!str)
+                return value != -1;
+
+        if (*str != ':')
+                return FALSE;
+        str++;
+
+        /* Second */
+        str = parse_int (str, &value);
+        *sec = value;
+        if (!str)
+                return value != -1;
+
+        /* Fraction of a second */
+        if (*str == '.') {
+                str = parse_int (++str, &value);
+                if (!str)
+                        return TRUE;
+        }
+
+        /* Time Zone */
+        if (*str == '+' || *str == '-') {
+                gint tz_hour = -1, tz_min = -1;
+                gint sign = *str == '+' ? 1 : -1;
+
+                str++;
+
+                str = parse_int (str, &value);
+                if (!str)
+                        return value != -1;
+                tz_hour = value;
+
+                if (*str != ':')
+                        return FALSE;
+                str++;
+
+                str = parse_int (str, &value);
+                if (!str)
+                        return value != -1;
+                tz_min = value;
+
+                *tz = (tz_hour * 3600 + tz_min * 60) * sign;
+        } else if (*str == 'Z') {
+                *tz = 0;
+        }
+
+        return TRUE;
+}
+
+static time_t
+w3cdtf_to_time_t (const gchar *date)
+{
+        struct tm stm;
+        gint      year = -1, mon = -1, day = -1;
+        gint      hour = -1, min = -1, sec = -1;
+        gint      tz = 0;
+        time_t    retval;
+
+        if (!parse_date (date, &year, &mon, &day, &hour, &min, &sec, &tz))
+                return (time_t)-1;
+
+        stm.tm_year = year - 1900;
+        stm.tm_mon = mon - 1;
+        stm.tm_mday = day;
+        stm.tm_hour = hour;
+        stm.tm_min = min;
+        stm.tm_sec = sec;
+        stm.tm_isdst = -1;
+
+        retval = mktime (&stm);
+        if (retval == (time_t)-1)
+                return retval;
+
+        return retval + tz;
+}
+
+static void
+core_props_start_element (GMarkupParseContext  *context,
+                          const gchar          *element_name,
+                          const gchar         **names,
+                          const gchar         **values,
+                          gpointer              user_data,
+                          GError              **error)
+{
+        CorePropsParserData *data = (CorePropsParserData *)user_data;
+
+        data->buffer = g_string_new (NULL);
+
+        if (strcmp (element_name, "category") == 0)
+                data->property = CP_CATEGORY;
+        else if (strcmp (element_name, "contentStatus") == 0)
+                data->property = CP_CONTENT_STATUS;
+        else if (strcmp (element_name, "contentType") == 0)
+                data->property = CP_CONTENT_TYPE;
+        else if (strcmp (element_name, "dcterms:created") == 0)
+                data->property = CP_CREATED;
+        else if (strcmp (element_name, "dc:creator") == 0)
+                data->property = CP_CREATOR;
+        else if (strcmp (element_name, "dc:description") == 0)
+                data->property = CP_DESCRIPTION;
+        else if (strcmp (element_name, "dc:identifier") == 0)
+                data->property = CP_IDENTIFIER;
+        else if (strcmp (element_name, "keywords") == 0)
+                data->property = CP_KEYWORDS;
+        else if (strcmp (element_name, "dc:language") == 0)
+                data->property = CP_LANGUAGE;
+        else if (strcmp (element_name, "lastModifiedBy") == 0)
+                data->property = CP_LAST_MODIFIED_BY;
+        else if (strcmp (element_name, "lastPrinted") == 0)
+                data->property = CP_LAST_PRINTED;
+        else if (strcmp (element_name, "dcterms:modified") == 0)
+                data->property = CP_MODIFIED;
+        else if (strcmp (element_name, "revision") == 0)
+                data->property = CP_REVISION;
+        else if (strcmp (element_name, "dc:subject") == 0)
+                data->property = CP_SUBJECT;
+        else if (strcmp (element_name, "dc:title") == 0)
+                data->property = CP_TITLE;
+        else if (strcmp (element_name, "version") == 0)
+                data->property = CP_VERSION;
+        else if ((strcmp (element_name, "coreProperties") == 0) ||
+                 (strcmp (element_name, "cp:coreProperties") == 0)) {
+                /* Do nothing */
+        } else {
+                gxps_parse_error (context,
+                                  data->core_props->priv->source,
+                                  G_MARKUP_ERROR_UNKNOWN_ELEMENT,
+                                  element_name, NULL, NULL, error);
+        }
+}
+
+static void
+core_props_end_element (GMarkupParseContext  *context,
+                        const gchar          *element_name,
+                        gpointer              user_data,
+                        GError              **error)
+{
+        CorePropsParserData       *data = (CorePropsParserData *)user_data;
+        GXPSCorePropertiesPrivate *priv = data->core_props->priv;
+        gchar                     *text;
+        gsize                      text_len;
+
+        if (!data->buffer)
+                return;
+
+        text_len = data->buffer->len;
+        text = g_string_free (data->buffer, FALSE);
+        data->buffer = NULL;
+
+        switch (data->property) {
+        case CP_CATEGORY:
+                priv->category = g_strndup (text, text_len);
+                break;
+        case CP_CONTENT_STATUS:
+                priv->content_status = g_strndup (text, text_len);
+                break;
+        case CP_CONTENT_TYPE:
+                priv->content_type = g_strndup (text, text_len);
+        case CP_CREATED:
+                priv->created = w3cdtf_to_time_t (text);
+                break;
+        case CP_CREATOR:
+                priv->creator = g_strndup (text, text_len);
+                break;
+        case CP_DESCRIPTION:
+                priv->description = g_strndup (text, text_len);
+                break;
+        case CP_IDENTIFIER:
+                priv->identifier = g_strndup (text, text_len);
+                break;
+        case CP_KEYWORDS:
+                priv->keywords = g_strndup (text, text_len);
+                break;
+        case CP_LANGUAGE:
+                priv->language = g_strndup (text, text_len);
+                break;
+        case CP_LAST_MODIFIED_BY:
+                priv->last_modified_by = g_strndup (text, text_len);
+                break;
+        case CP_LAST_PRINTED:
+                priv->last_printed = w3cdtf_to_time_t (text);
+                break;
+        case CP_MODIFIED:
+                priv->modified = w3cdtf_to_time_t (text);
+                break;
+        case CP_REVISION:
+                priv->revision = g_strndup (text, text_len);
+                break;
+        case CP_SUBJECT:
+                priv->subject = g_strndup (text, text_len);
+                break;
+        case CP_TITLE:
+                priv->title = g_strndup (text, text_len);
+                break;
+        case CP_VERSION:
+                priv->version = g_strndup (text, text_len);
+                break;
+        case CP_UNKNOWN:
+                break;
+        }
+
+        data->property = CP_UNKNOWN;
+        g_free (text);
+}
+
+static void
+core_props_text (GMarkupParseContext *context,
+                 const gchar         *text,
+                 gsize                text_len,
+                 gpointer             user_data,
+                 GError             **error)
+{
+        CorePropsParserData *data = (CorePropsParserData *)user_data;
+
+        if (!data->buffer)
+                return;
+
+        g_string_append_len (data->buffer, text, text_len);
+}
+
+static const GMarkupParser core_props_parser = {
+        core_props_start_element,
+        core_props_end_element,
+        core_props_text,
+        NULL,
+        NULL
+};
+
+static gboolean
+gxps_core_properties_parse (GXPSCoreProperties *core_props,
+                            GError            **error)
+{
+        GInputStream         *stream;
+        GMarkupParseContext  *ctx;
+        CorePropsParserData   parser_data;
+
+        stream = gxps_archive_open (core_props->priv->zip,
+                                    core_props->priv->source);
+        if (!stream) {
+                g_set_error (error,
+                             GXPS_ERROR,
+                             GXPS_ERROR_SOURCE_NOT_FOUND,
+                             "CoreProperties source %s not found in archive",
+                             core_props->priv->source);
+                return FALSE;
+        }
+
+        parser_data.core_props = core_props;
+        parser_data.property = 0;
+        parser_data.buffer = NULL;
+
+        ctx = g_markup_parse_context_new (&core_props_parser, 0, &parser_data, NULL);
+        gxps_parse_stream (ctx, stream, error);
+        g_object_unref (stream);
+
+        g_markup_parse_context_free (ctx);
+
+        return (*error != NULL) ? FALSE : TRUE;
+}
+
+static void
+gxps_core_properties_finalize (GObject *object)
+{
+        GXPSCoreProperties *core_props = GXPS_CORE_PROPERTIES (object);
+
+        if (core_props->priv->zip) {
+                g_object_unref (core_props->priv->zip);
+                core_props->priv->zip = NULL;
+        }
+
+        if (core_props->priv->source) {
+                g_free (core_props->priv->source);
+                core_props->priv->source = NULL;
+        }
+
+        g_clear_error (&core_props->priv->init_error);
+
+        G_OBJECT_CLASS (gxps_core_properties_parent_class)->finalize (object);
+}
+
+static void
+gxps_core_properties_init (GXPSCoreProperties *core_props)
+{
+        core_props->priv = G_TYPE_INSTANCE_GET_PRIVATE (core_props,
+                                                        GXPS_TYPE_CORE_PROPERTIES,
+                                                        GXPSCorePropertiesPrivate);
+}
+
+static void
+gxps_core_properties_set_property (GObject      *object,
+                                   guint         prop_id,
+                                   const GValue *value,
+                                   GParamSpec   *pspec)
+{
+        GXPSCoreProperties *core_props = GXPS_CORE_PROPERTIES (object);
+
+        switch (prop_id) {
+        case PROP_ARCHIVE:
+                core_props->priv->zip = g_value_dup_object (value);
+                break;
+        case PROP_SOURCE:
+                core_props->priv->source = g_value_dup_string (value);
+                break;
+        default:
+                G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+                break;
+        }
+}
+
+static void
+gxps_core_properties_class_init (GXPSCorePropertiesClass *klass)
+{
+        GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+        object_class->set_property = gxps_core_properties_set_property;
+        object_class->finalize = gxps_core_properties_finalize;
+
+        g_object_class_install_property (object_class,
+                                         PROP_ARCHIVE,
+                                         g_param_spec_object ("archive",
+                                                              "Archive",
+                                                              "The archive",
+                                                              GXPS_TYPE_ARCHIVE,
+                                                              G_PARAM_WRITABLE |
+                                                              G_PARAM_CONSTRUCT_ONLY));
+        g_object_class_install_property (object_class,
+                                         PROP_SOURCE,
+                                         g_param_spec_string ("source",
+                                                              "Source",
+                                                              "The Core Properties Source File",
+                                                              NULL,
+                                                              G_PARAM_WRITABLE |
+                                                              G_PARAM_CONSTRUCT_ONLY));
+
+        g_type_class_add_private (klass, sizeof (GXPSCorePropertiesPrivate));
+}
+
+static gboolean
+gxps_core_properties_initable_init (GInitable     *initable,
+                                    GCancellable  *cancellable,
+                                    GError       **error)
+{
+        GXPSCoreProperties *core_props = GXPS_CORE_PROPERTIES (initable);
+
+        if (core_props->priv->initialized) {
+                if (core_props->priv->init_error) {
+                        g_propagate_error (error, g_error_copy (core_props->priv->init_error));
+
+                        return FALSE;
+                }
+
+                return TRUE;
+        }
+
+        core_props->priv->initialized = TRUE;
+
+        if (!gxps_core_properties_parse (core_props, &core_props->priv->init_error)) {
+                g_propagate_error (error, g_error_copy (core_props->priv->init_error));
+                return FALSE;
+        }
+
+        return TRUE;
+}
+
+static void
+initable_iface_init (GInitableIface *initable_iface)
+{
+        initable_iface->init = gxps_core_properties_initable_init;
+}
+
+GXPSCoreProperties *
+_gxps_core_properties_new (GXPSArchive *zip,
+                           const gchar *source,
+                           GError     **error)
+{
+        return g_initable_new (GXPS_TYPE_CORE_PROPERTIES,
+                               NULL, error,
+                               "archive", zip,
+                               "source", source,
+                               NULL);
+}
+
+/**
+ * gxps_core_properties_get_title:
+ * @core_props: a #GXPSCoreProperties
+ *
+ * Get the title.
+ *
+ * Returns: a string containing the title or %NULL
+ */
+const gchar *
+gxps_core_properties_get_title (GXPSCoreProperties *core_props)
+{
+        g_return_val_if_fail (GXPS_IS_CORE_PROPERTIES (core_props), NULL);
+
+        return core_props->priv->title;
+}
+
+/**
+ * gxps_core_properties_get_creator:
+ * @core_props: a #GXPSCoreProperties
+ *
+ * Get the creator.
+ *
+ * Returns: a string containing the creator or %NULL
+ */
+const gchar *
+gxps_core_properties_get_creator (GXPSCoreProperties *core_props)
+{
+        g_return_val_if_fail (GXPS_IS_CORE_PROPERTIES (core_props), NULL);
+
+        return core_props->priv->creator;
+}
+
+/**
+ * gxps_core_properties_get_description:
+ * @core_props: a #GXPSCoreProperties
+ *
+ * Get the description.
+ *
+ * Returns: a string containing the description or %NULL
+ */
+const gchar *
+gxps_core_properties_get_description (GXPSCoreProperties *core_props)
+{
+        g_return_val_if_fail (GXPS_IS_CORE_PROPERTIES (core_props), NULL);
+
+        return core_props->priv->description;
+}
+
+/**
+ * gxps_core_properties_get_subject:
+ * @core_props: a #GXPSCoreProperties
+ *
+ * Get the subject.
+ *
+ * Returns: a string containing the subject or %NULL
+ */
+const gchar *
+gxps_core_properties_get_subject (GXPSCoreProperties *core_props)
+{
+        g_return_val_if_fail (GXPS_IS_CORE_PROPERTIES (core_props), NULL);
+
+        return core_props->priv->subject;
+}
+
+/**
+ * gxps_core_properties_get_keywords:
+ * @core_props: a #GXPSCoreProperties
+ *
+ * Get the keywords.
+ *
+ * Returns: a string containing the keywords or %NULL
+ */
+const gchar *
+gxps_core_properties_get_keywords (GXPSCoreProperties *core_props)
+{
+        g_return_val_if_fail (GXPS_IS_CORE_PROPERTIES (core_props), NULL);
+
+        return core_props->priv->keywords;
+}
+
+/**
+ * gxps_core_properties_get_version:
+ * @core_props: a #GXPSCoreProperties
+ *
+ * Get the version number.
+ *
+ * Returns: a string containing the version number or %NULL
+ */
+const gchar *
+gxps_core_properties_get_version (GXPSCoreProperties *core_props)
+{
+        g_return_val_if_fail (GXPS_IS_CORE_PROPERTIES (core_props), NULL);
+
+        return core_props->priv->version;
+}
+
+/**
+ * gxps_core_properties_get_revision:
+ * @core_props: a #GXPSCoreProperties
+ *
+ * Get the revision number.
+ *
+ * Returns: a string containing the revision number or %NULL
+ */
+const gchar *
+gxps_core_properties_get_revision (GXPSCoreProperties *core_props)
+{
+        g_return_val_if_fail (GXPS_IS_CORE_PROPERTIES (core_props), NULL);
+
+        return core_props->priv->revision;
+}
+
+/**
+ * gxps_core_properties_get_identifier:
+ * @core_props: a #GXPSCoreProperties
+ *
+ * Get the unique identifier.
+ *
+ * Returns: a string containing the identifier or %NULL
+ */
+const gchar *
+gxps_core_properties_get_identifier (GXPSCoreProperties *core_props)
+{
+        g_return_val_if_fail (GXPS_IS_CORE_PROPERTIES (core_props), NULL);
+
+        return core_props->priv->identifier;
+}
+
+/**
+ * gxps_core_properties_get_language:
+ * @core_props: a #GXPSCoreProperties
+ *
+ * Get the language.
+ *
+ * Returns: a string containing the language or %NULL
+ */
+const gchar *
+gxps_core_properties_get_language (GXPSCoreProperties *core_props)
+{
+        g_return_val_if_fail (GXPS_IS_CORE_PROPERTIES (core_props), NULL);
+
+        return core_props->priv->language;
+}
+
+/**
+ * gxps_core_properties_get_category:
+ * @core_props: a #GXPSCoreProperties
+ *
+ * Get the category.
+ *
+ * Returns: a string containing the category or %NULL
+ */
+const gchar *
+gxps_core_properties_get_category (GXPSCoreProperties *core_props)
+{
+        g_return_val_if_fail (GXPS_IS_CORE_PROPERTIES (core_props), NULL);
+
+        return core_props->priv->category;
+}
+
+/**
+ * gxps_core_properties_get_content_status:
+ * @core_props: a #GXPSCoreProperties
+ *
+ * Get the status of the content (e.g. Draft, Reviewed, Final)
+ *
+ * Returns: a string containing the status of the content or %NULL
+ */
+const gchar *
+gxps_core_properties_get_content_status (GXPSCoreProperties *core_props)
+{
+        g_return_val_if_fail (GXPS_IS_CORE_PROPERTIES (core_props), NULL);
+
+        return core_props->priv->content_status;
+}
+
+/**
+ * gxps_core_properties_get_content_type:
+ * @core_props: a #GXPSCoreProperties
+ *
+ * Get the type of content represented, generally defined by a
+ * specific use and intended audience. This is not the MIME-Type.
+ *
+ *
+ * Returns: a string containing the type of content or %NULL
+ */
+const gchar *
+gxps_core_properties_get_content_type (GXPSCoreProperties *core_props)
+{
+        g_return_val_if_fail (GXPS_IS_CORE_PROPERTIES (core_props), NULL);
+
+        return core_props->priv->content_type;
+}
+
+/**
+ * gxps_core_properties_get_created:
+ * @core_props: a #GXPSCoreProperties
+ *
+ * Get the creating date.
+ *
+ * Returns: the creating date as a <type>time_t</type> or -1.
+ */
+time_t
+gxps_core_properties_get_created (GXPSCoreProperties *core_props)
+{
+        g_return_val_if_fail (GXPS_IS_CORE_PROPERTIES (core_props), -1);
+
+        return core_props->priv->created;
+}
+
+/**
+ * gxps_core_properties_get_last_modified_by:
+ * @core_props: a #GXPSCoreProperties
+ *
+ * Get the user who performed the last modification.
+ *
+ * Returns: a string containing the user who performed the
+ *    last modification or %NULL
+ */
+const gchar *
+gxps_core_properties_get_last_modified_by (GXPSCoreProperties *core_props)
+{
+        g_return_val_if_fail (GXPS_IS_CORE_PROPERTIES (core_props), NULL);
+
+        return core_props->priv->last_modified_by;
+}
+
+/**
+ * gxps_core_properties_get_modified:
+ * @core_props: a #GXPSCoreProperties
+ *
+ * Get the last modification date.
+ *
+ * Returns: the modification date as a <type>time_t</type> or -1.
+ */
+time_t
+gxps_core_properties_get_modified (GXPSCoreProperties *core_props)
+{
+        g_return_val_if_fail (GXPS_IS_CORE_PROPERTIES (core_props), -1);
+
+        return core_props->priv->modified;
+}
+
+/**
+ * gxps_core_properties_get_last_printed:
+ * @core_props: a #GXPSCoreProperties
+ *
+ * Get the date of the last printing.
+ *
+ * Returns: the date of the last printing as a <type>time_t</type> or -1.
+ */
+time_t
+gxps_core_properties_get_last_printed (GXPSCoreProperties *core_props)
+{
+        g_return_val_if_fail (GXPS_IS_CORE_PROPERTIES (core_props), -1);
+
+        return core_props->priv->last_printed;
+}
diff --git a/libgxps/gxps-core-properties.h b/libgxps/gxps-core-properties.h
new file mode 100644
index 0000000..4444ad4
--- /dev/null
+++ b/libgxps/gxps-core-properties.h
@@ -0,0 +1,80 @@
+/* GXPSCoreProperties
+ *
+ * Copyright (C) 2013  Carlos Garcia Campos <carlosgc gnome 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.1 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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#if !defined (__GXPS_H_INSIDE__) && !defined (GXPS_COMPILATION)
+#error "Only <libgxps/gxps.h> can be included directly."
+#endif
+
+#ifndef __GXPS_CORE_PROPERTIES_H__
+#define __GXPS_CORE_PROPERTIES_H__
+
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+#define GXPS_TYPE_CORE_PROPERTIES           (gxps_core_properties_get_type ())
+#define GXPS_CORE_PROPERTIES(obj)           (G_TYPE_CHECK_INSTANCE_CAST (obj, GXPS_TYPE_CORE_PROPERTIES, GXPSCoreProperties))
+#define GXPS_IS_CORE_PROPERTIES(obj)        (G_TYPE_CHECK_INSTANCE_TYPE (obj, GXPS_TYPE_CORE_PROPERTIES))
+#define GXPS_CORE_PROPERTIES_CLASS(cls)     (G_TYPE_CHECK_CLASS_CAST (cls, GXPS_TYPE_CORE_PROPERTIES, GXPSCorePropertiesClass))
+#define GXPS_IS_CORE_PROPERTIES_CLASS(obj)  (G_TYPE_CHECK_CLASS_TYPE (obj, GXPS_TYPE_CORE_PROPERTIES))
+#define GXPS_CORE_PROPERTIES_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GXPS_TYPE_CORE_PROPERTIES, GXPSCorePropertiesClass))
+
+typedef struct _GXPSCoreProperties        GXPSCoreProperties;
+typedef struct _GXPSCorePropertiesClass   GXPSCorePropertiesClass;
+typedef struct _GXPSCorePropertiesPrivate GXPSCorePropertiesPrivate;
+
+/**
+ * GXPSCoreProperties:
+ *
+ * The <structname>GXPSCoreProperties</structname> struct contains
+ * only private fields and should not be directly accessed.
+ */
+struct _GXPSCoreProperties {
+        GObject parent;
+
+        /*< private >*/
+        GXPSCorePropertiesPrivate *priv;
+};
+
+struct _GXPSCorePropertiesClass {
+        GObjectClass parent_class;
+};
+
+GType        gxps_core_properties_get_type             (void) G_GNUC_CONST;
+
+const gchar *gxps_core_properties_get_title            (GXPSCoreProperties *core_props);
+const gchar *gxps_core_properties_get_creator          (GXPSCoreProperties *core_props);
+const gchar *gxps_core_properties_get_description      (GXPSCoreProperties *core_props);
+const gchar *gxps_core_properties_get_subject          (GXPSCoreProperties *core_props);
+const gchar *gxps_core_properties_get_keywords         (GXPSCoreProperties *core_props);
+const gchar *gxps_core_properties_get_version          (GXPSCoreProperties *core_props);
+const gchar *gxps_core_properties_get_revision         (GXPSCoreProperties *core_props);
+const gchar *gxps_core_properties_get_identifier       (GXPSCoreProperties *core_props);
+const gchar *gxps_core_properties_get_language         (GXPSCoreProperties *core_props);
+const gchar *gxps_core_properties_get_category         (GXPSCoreProperties *core_props);
+const gchar *gxps_core_properties_get_content_status   (GXPSCoreProperties *core_props);
+const gchar *gxps_core_properties_get_content_type     (GXPSCoreProperties *core_props);
+time_t       gxps_core_properties_get_created          (GXPSCoreProperties *core_props);
+const gchar *gxps_core_properties_get_last_modified_by (GXPSCoreProperties *core_props);
+time_t       gxps_core_properties_get_modified         (GXPSCoreProperties *core_props);
+time_t       gxps_core_properties_get_last_printed     (GXPSCoreProperties *core_props);
+
+G_END_DECLS
+
+#endif /* __GXPS_CORE_PROPERTIES_H__ */
diff --git a/libgxps/gxps-file.c b/libgxps/gxps-file.c
index 17de4aa..d86d0fc 100644
--- a/libgxps/gxps-file.c
+++ b/libgxps/gxps-file.c
@@ -473,3 +473,28 @@ gxps_file_get_document_for_link_target (GXPSFile       *xps,
 	return -1;
 }
 
+/**
+ * gxps_file_get_core_properties:
+ * @xps: a #GXPSFile
+ * @error: #GError for error reporting, or %NULL to ignore
+ *
+ * Create a #GXPSCoreProperties object containing the metadata
+ * of @xpsm, or %NULL in case of error or if the #GXPSFile
+ * doesn't contain core properties.
+ *
+ * Returns: (transfer full): a new #GXPSCoreProperties or %NULL.
+ *    Free the returned object with g_object_unref().
+ */
+GXPSCoreProperties *
+gxps_file_get_core_properties (GXPSFile *xps,
+                               GError  **error)
+{
+        g_return_val_if_fail (GXPS_IS_FILE (xps), NULL);
+
+        if (!xps->priv->core_props)
+                return NULL;
+
+        return _gxps_core_properties_new (xps->priv->zip,
+                                          xps->priv->core_props,
+                                          error);
+}
diff --git a/libgxps/gxps-file.h b/libgxps/gxps-file.h
index 252cc91..250f31a 100644
--- a/libgxps/gxps-file.h
+++ b/libgxps/gxps-file.h
@@ -29,6 +29,7 @@
 
 #include "gxps-document.h"
 #include "gxps-links.h"
+#include "gxps-core-properties.h"
 
 G_BEGIN_DECLS
 
@@ -79,17 +80,19 @@ struct _GXPSFileClass {
 	GObjectClass parent_class;
 };
 
-GType         gxps_file_get_type                     (void) G_GNUC_CONST;
-GQuark        gxps_file_error_quark                  (void) G_GNUC_CONST;
-GXPSFile     *gxps_file_new                          (GFile          *filename,
-						      GError        **error);
-
-guint         gxps_file_get_n_documents              (GXPSFile       *xps);
-GXPSDocument *gxps_file_get_document                 (GXPSFile       *xps,
-						      guint           n_doc,
-						      GError        **error);
-gint          gxps_file_get_document_for_link_target (GXPSFile       *xps,
-						      GXPSLinkTarget *target);
+GType               gxps_file_get_type                     (void) G_GNUC_CONST;
+GQuark              gxps_file_error_quark                  (void) G_GNUC_CONST;
+GXPSFile           *gxps_file_new                          (GFile          *filename,
+                                                            GError        **error);
+
+guint               gxps_file_get_n_documents              (GXPSFile       *xps);
+GXPSDocument       *gxps_file_get_document                 (GXPSFile       *xps,
+                                                            guint           n_doc,
+                                                            GError        **error);
+gint                gxps_file_get_document_for_link_target (GXPSFile       *xps,
+                                                            GXPSLinkTarget *target);
+GXPSCoreProperties *gxps_file_get_core_properties          (GXPSFile       *xps,
+                                                            GError        **error);
 
 G_END_DECLS
 
diff --git a/libgxps/gxps-private.h b/libgxps/gxps-private.h
index c649051..1394451 100644
--- a/libgxps/gxps-private.h
+++ b/libgxps/gxps-private.h
@@ -27,6 +27,7 @@
 #include "gxps-parse-utils.h"
 #include "gxps-links.h"
 #include "gxps-document-structure.h"
+#include "gxps-core-properties.h"
 
 G_BEGIN_DECLS
 
@@ -43,6 +44,9 @@ GXPSLinkTarget        *_gxps_link_target_new        (GXPSArchive       *zip,
 						     const gchar       *uri);
 GXPSDocumentStructure *_gxps_document_structure_new (GXPSArchive       *zip,
 						     const gchar       *source);
+GXPSCoreProperties    *_gxps_core_properties_new    (GXPSArchive       *zip,
+                                                     const gchar       *source,
+                                                     GError           **error);
 
 G_END_DECLS
 



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]