1 /* GXPSCoreProperties
2  *
3  * Copyright (C) 2013  Carlos Garcia Campos <carlosgc@gnome.org>
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2.1 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this library; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
18  */
19 
20 #include <config.h>
21 
22 #include "gxps-core-properties.h"
23 #include "gxps-private.h"
24 #include "gxps-error.h"
25 #include <string.h>
26 #include <errno.h>
27 
28 /**
29  * SECTION:gxps-core-properties
30  * @Short_description: XPS Core Properties
31  * @Title: GXPSCoreProperties
32  * @See_also: #GXPSFile
33  *
34  * #GXPSCoreProperties represents the metadata of a #GXPSFile.
35  * #GXPSCoreProperties objects can not be created directly, they
36  * are retrieved from a #GXPSFile with gxps_file_get_core_properties().
37  *
38  * Since: 0.2.3
39  */
40 
41 enum {
42         PROP_0,
43         PROP_ARCHIVE,
44         PROP_SOURCE
45 };
46 
47 struct _GXPSCorePropertiesPrivate {
48         GXPSArchive *zip;
49         gchar       *source;
50 
51         gboolean     initialized;
52         GError      *init_error;
53 
54         gchar       *category;
55         gchar       *content_status;
56         gchar       *content_type;
57         time_t       created;
58         gchar       *creator;
59         gchar       *description;
60         gchar       *identifier;
61         gchar       *keywords;
62         gchar       *language;
63         gchar       *last_modified_by;
64         time_t       last_printed;
65         time_t       modified;
66         gchar       *revision;
67         gchar       *subject;
68         gchar       *title;
69         gchar       *version;
70 };
71 
72 static void initable_iface_init (GInitableIface *initable_iface);
73 
74 G_DEFINE_TYPE_WITH_CODE (GXPSCoreProperties, gxps_core_properties, G_TYPE_OBJECT,
75                          G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE, initable_iface_init))
76 
77 /* CoreProperties parser */
78 typedef enum {
79         CP_UNKNOWN,
80         CP_CATEGORY,
81         CP_CONTENT_STATUS,
82         CP_CONTENT_TYPE,
83         CP_CREATED,
84         CP_CREATOR,
85         CP_DESCRIPTION,
86         CP_IDENTIFIER,
87         CP_KEYWORDS,
88         CP_LANGUAGE,
89         CP_LAST_MODIFIED_BY,
90         CP_LAST_PRINTED,
91         CP_MODIFIED,
92         CP_REVISION,
93         CP_SUBJECT,
94         CP_TITLE,
95         CP_VERSION
96 } CoreProperty;
97 
98 typedef struct _CorePropsParserData {
99         GXPSCoreProperties *core_props;
100         CoreProperty        property;
101         GString            *buffer;
102 } CorePropsParserData;
103 
104 static gchar *
parse_int(const gchar * value,gint * int_value)105 parse_int (const gchar *value,
106            gint        *int_value)
107 {
108         gint64 result;
109         gchar *endptr = NULL;
110 
111         *int_value = -1;
112 
113         if (!value)
114                 return NULL;
115 
116         errno = 0;
117         result = g_ascii_strtoll (value, &endptr, 10);
118         if (errno || endptr == value || result > G_MAXINT || result < G_MININT)
119                 return NULL;
120 
121         *int_value = result;
122 
123         return endptr;
124 }
125 
126 static gboolean
parse_date(const gchar * date,gint * year,gint * mon,gint * day,gint * hour,gint * min,gint * sec,gint * tz)127 parse_date (const gchar *date,
128             gint        *year,
129             gint        *mon,
130             gint        *day,
131             gint        *hour,
132             gint        *min,
133             gint        *sec,
134             gint        *tz)
135 {
136         gint         value;
137         const gchar *str = date;
138 
139         /* Year:
140          *     YYYY (eg 1997)
141          * Year and month:
142          *     YYYY-MM (eg 1997-07)
143          * Complete date:
144          *     YYYY-MM-DD (eg 1997-07-16)
145          * Complete date plus hours and minutes:
146          *     YYYY-MM-DDThh:mmTZD (eg 1997-07-16T19:20+01:00)
147          * Complete date plus hours, minutes and seconds:
148          *     YYYY-MM-DDThh:mm:ssTZD (eg 1997-07-16T19:20:30+01:00)
149          * Complete date plus hours, minutes, seconds and a decimal fraction of a second
150          *     YYYY-MM-DDThh:mm:ss.sTZD (eg 1997-07-16T19:20:30.45+01:00)
151          * where:
152          *
153          * YYYY = four-digit year
154          * MM   = two-digit month (01=January, etc.)
155          * DD   = two-digit day of month (01 through 31)
156          * hh   = two digits of hour (00 through 23) (am/pm NOT allowed)
157          * mm   = two digits of minute (00 through 59)
158          * ss   = two digits of second (00 through 59)
159          * s    = one or more digits representing a decimal fraction of a second
160          * TZD  = time zone designator (Z or +hh:mm or -hh:mm)
161          */
162 
163         /* Year */
164         str = parse_int (str, &value);
165         *year = value;
166         if (!str)
167                 return value != -1;
168 
169         if (*str != '-')
170                 return FALSE;
171         str++;
172 
173         /* Month */
174         str = parse_int (str, &value);
175         *mon = value;
176         if (!str)
177                 return value != -1;
178 
179         if (*str != '-')
180                 return FALSE;
181         str++;
182 
183         /* Day */
184         str = parse_int (str, &value);
185         *day = value;
186         if (!str)
187                 return value != -1;
188 
189         if (*str != 'T')
190                 return FALSE;
191         str++;
192 
193         /* Hour */
194         str = parse_int (str, &value);
195         *hour = value;
196         if (!str)
197                 return value != -1;
198 
199         if (*str != ':')
200                 return FALSE;
201         str++;
202 
203         /* Minute */
204         str = parse_int (str, &value);
205         *min = value;
206         if (!str)
207                 return value != -1;
208 
209         if (*str != ':')
210                 return FALSE;
211         str++;
212 
213         /* Second */
214         str = parse_int (str, &value);
215         *sec = value;
216         if (!str)
217                 return value != -1;
218 
219         /* Fraction of a second */
220         if (*str == '.') {
221                 str = parse_int (++str, &value);
222                 if (!str)
223                         return TRUE;
224         }
225 
226         /* Time Zone */
227         if (*str == '+' || *str == '-') {
228                 gint tz_hour = -1, tz_min = -1;
229                 gint sign = *str == '+' ? 1 : -1;
230 
231                 str++;
232 
233                 str = parse_int (str, &value);
234                 if (!str)
235                         return value != -1;
236                 tz_hour = value;
237 
238                 if (*str != ':')
239                         return FALSE;
240                 str++;
241 
242                 str = parse_int (str, &value);
243                 if (!str)
244                         return value != -1;
245                 tz_min = value;
246 
247                 *tz = (tz_hour * 3600 + tz_min * 60) * sign;
248         } else if (*str == 'Z') {
249                 *tz = 0;
250         }
251 
252         return TRUE;
253 }
254 
255 static time_t
w3cdtf_to_time_t(const gchar * date)256 w3cdtf_to_time_t (const gchar *date)
257 {
258         struct tm stm;
259         gint      year = -1, mon = -1, day = -1;
260         gint      hour = -1, min = -1, sec = -1;
261         gint      tz = 0;
262         time_t    retval;
263 
264         if (!parse_date (date, &year, &mon, &day, &hour, &min, &sec, &tz))
265                 return (time_t)-1;
266 
267         stm.tm_year = year - 1900;
268         stm.tm_mon = mon - 1;
269         stm.tm_mday = day;
270         stm.tm_hour = hour;
271         stm.tm_min = min;
272         stm.tm_sec = sec;
273         stm.tm_isdst = -1;
274 
275         retval = mktime (&stm);
276         if (retval == (time_t)-1)
277                 return retval;
278 
279         return retval + tz;
280 }
281 
282 static void
core_props_start_element(GMarkupParseContext * context,const gchar * element_name,const gchar ** names,const gchar ** values,gpointer user_data,GError ** error)283 core_props_start_element (GMarkupParseContext  *context,
284                           const gchar          *element_name,
285                           const gchar         **names,
286                           const gchar         **values,
287                           gpointer              user_data,
288                           GError              **error)
289 {
290         CorePropsParserData *data = (CorePropsParserData *)user_data;
291 
292         data->buffer = g_string_new (NULL);
293 
294         if (strcmp (element_name, "category") == 0)
295                 data->property = CP_CATEGORY;
296         else if (strcmp (element_name, "contentStatus") == 0)
297                 data->property = CP_CONTENT_STATUS;
298         else if (strcmp (element_name, "contentType") == 0)
299                 data->property = CP_CONTENT_TYPE;
300         else if (strcmp (element_name, "dcterms:created") == 0)
301                 data->property = CP_CREATED;
302         else if (strcmp (element_name, "dc:creator") == 0)
303                 data->property = CP_CREATOR;
304         else if (strcmp (element_name, "dc:description") == 0)
305                 data->property = CP_DESCRIPTION;
306         else if (strcmp (element_name, "dc:identifier") == 0)
307                 data->property = CP_IDENTIFIER;
308         else if (strcmp (element_name, "keywords") == 0)
309                 data->property = CP_KEYWORDS;
310         else if (strcmp (element_name, "dc:language") == 0)
311                 data->property = CP_LANGUAGE;
312         else if (strcmp (element_name, "lastModifiedBy") == 0)
313                 data->property = CP_LAST_MODIFIED_BY;
314         else if (strcmp (element_name, "lastPrinted") == 0)
315                 data->property = CP_LAST_PRINTED;
316         else if (strcmp (element_name, "dcterms:modified") == 0)
317                 data->property = CP_MODIFIED;
318         else if (strcmp (element_name, "revision") == 0)
319                 data->property = CP_REVISION;
320         else if (strcmp (element_name, "dc:subject") == 0)
321                 data->property = CP_SUBJECT;
322         else if (strcmp (element_name, "dc:title") == 0)
323                 data->property = CP_TITLE;
324         else if (strcmp (element_name, "version") == 0)
325                 data->property = CP_VERSION;
326         else if ((strcmp (element_name, "coreProperties") == 0) ||
327                  (strcmp (element_name, "cp:coreProperties") == 0)) {
328                 /* Do nothing */
329         } else {
330                 gxps_parse_error (context,
331                                   data->core_props->priv->source,
332                                   G_MARKUP_ERROR_UNKNOWN_ELEMENT,
333                                   element_name, NULL, NULL, error);
334         }
335 }
336 
337 static void
core_props_end_element(GMarkupParseContext * context,const gchar * element_name,gpointer user_data,GError ** error)338 core_props_end_element (GMarkupParseContext  *context,
339                         const gchar          *element_name,
340                         gpointer              user_data,
341                         GError              **error)
342 {
343         CorePropsParserData       *data = (CorePropsParserData *)user_data;
344         GXPSCorePropertiesPrivate *priv = data->core_props->priv;
345         gchar                     *text;
346         gsize                      text_len;
347 
348         if (!data->buffer)
349                 return;
350 
351         text_len = data->buffer->len;
352         text = g_string_free (data->buffer, FALSE);
353         data->buffer = NULL;
354 
355         switch (data->property) {
356         case CP_CATEGORY:
357                 priv->category = g_strndup (text, text_len);
358                 break;
359         case CP_CONTENT_STATUS:
360                 priv->content_status = g_strndup (text, text_len);
361                 break;
362         case CP_CONTENT_TYPE:
363                 priv->content_type = g_strndup (text, text_len);
364                 break;
365         case CP_CREATED:
366                 priv->created = w3cdtf_to_time_t (text);
367                 break;
368         case CP_CREATOR:
369                 priv->creator = g_strndup (text, text_len);
370                 break;
371         case CP_DESCRIPTION:
372                 priv->description = g_strndup (text, text_len);
373                 break;
374         case CP_IDENTIFIER:
375                 priv->identifier = g_strndup (text, text_len);
376                 break;
377         case CP_KEYWORDS:
378                 priv->keywords = g_strndup (text, text_len);
379                 break;
380         case CP_LANGUAGE:
381                 priv->language = g_strndup (text, text_len);
382                 break;
383         case CP_LAST_MODIFIED_BY:
384                 priv->last_modified_by = g_strndup (text, text_len);
385                 break;
386         case CP_LAST_PRINTED:
387                 priv->last_printed = w3cdtf_to_time_t (text);
388                 break;
389         case CP_MODIFIED:
390                 priv->modified = w3cdtf_to_time_t (text);
391                 break;
392         case CP_REVISION:
393                 priv->revision = g_strndup (text, text_len);
394                 break;
395         case CP_SUBJECT:
396                 priv->subject = g_strndup (text, text_len);
397                 break;
398         case CP_TITLE:
399                 priv->title = g_strndup (text, text_len);
400                 break;
401         case CP_VERSION:
402                 priv->version = g_strndup (text, text_len);
403                 break;
404         case CP_UNKNOWN:
405                 break;
406         }
407 
408         data->property = CP_UNKNOWN;
409         g_free (text);
410 }
411 
412 static void
core_props_text(GMarkupParseContext * context,const gchar * text,gsize text_len,gpointer user_data,GError ** error)413 core_props_text (GMarkupParseContext *context,
414                  const gchar         *text,
415                  gsize                text_len,
416                  gpointer             user_data,
417                  GError             **error)
418 {
419         CorePropsParserData *data = (CorePropsParserData *)user_data;
420 
421         if (!data->buffer)
422                 return;
423 
424         g_string_append_len (data->buffer, text, text_len);
425 }
426 
427 static const GMarkupParser core_props_parser = {
428         core_props_start_element,
429         core_props_end_element,
430         core_props_text,
431         NULL,
432         NULL
433 };
434 
435 static gboolean
gxps_core_properties_parse(GXPSCoreProperties * core_props,GError ** error)436 gxps_core_properties_parse (GXPSCoreProperties *core_props,
437                             GError            **error)
438 {
439         GInputStream         *stream;
440         GMarkupParseContext  *ctx;
441         CorePropsParserData   parser_data;
442 
443         stream = gxps_archive_open (core_props->priv->zip,
444                                     core_props->priv->source);
445         if (!stream) {
446                 g_set_error (error,
447                              GXPS_ERROR,
448                              GXPS_ERROR_SOURCE_NOT_FOUND,
449                              "CoreProperties source %s not found in archive",
450                              core_props->priv->source);
451                 return FALSE;
452         }
453 
454         parser_data.core_props = core_props;
455         parser_data.property = 0;
456         parser_data.buffer = NULL;
457 
458         ctx = g_markup_parse_context_new (&core_props_parser, 0, &parser_data, NULL);
459         gxps_parse_stream (ctx, stream, error);
460         g_object_unref (stream);
461 
462         g_markup_parse_context_free (ctx);
463 
464         return (*error != NULL) ? FALSE : TRUE;
465 }
466 
467 static void
gxps_core_properties_finalize(GObject * object)468 gxps_core_properties_finalize (GObject *object)
469 {
470         GXPSCoreProperties *core_props = GXPS_CORE_PROPERTIES (object);
471 
472         g_clear_object (&core_props->priv->zip);
473         g_clear_pointer (&core_props->priv->source, g_free);
474         g_clear_error (&core_props->priv->init_error);
475 
476         G_OBJECT_CLASS (gxps_core_properties_parent_class)->finalize (object);
477 }
478 
479 static void
gxps_core_properties_init(GXPSCoreProperties * core_props)480 gxps_core_properties_init (GXPSCoreProperties *core_props)
481 {
482         core_props->priv = G_TYPE_INSTANCE_GET_PRIVATE (core_props,
483                                                         GXPS_TYPE_CORE_PROPERTIES,
484                                                         GXPSCorePropertiesPrivate);
485 }
486 
487 static void
gxps_core_properties_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)488 gxps_core_properties_set_property (GObject      *object,
489                                    guint         prop_id,
490                                    const GValue *value,
491                                    GParamSpec   *pspec)
492 {
493         GXPSCoreProperties *core_props = GXPS_CORE_PROPERTIES (object);
494 
495         switch (prop_id) {
496         case PROP_ARCHIVE:
497                 core_props->priv->zip = g_value_dup_object (value);
498                 break;
499         case PROP_SOURCE:
500                 core_props->priv->source = g_value_dup_string (value);
501                 break;
502         default:
503                 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
504                 break;
505         }
506 }
507 
508 static void
gxps_core_properties_class_init(GXPSCorePropertiesClass * klass)509 gxps_core_properties_class_init (GXPSCorePropertiesClass *klass)
510 {
511         GObjectClass *object_class = G_OBJECT_CLASS (klass);
512 
513         object_class->set_property = gxps_core_properties_set_property;
514         object_class->finalize = gxps_core_properties_finalize;
515 
516         g_object_class_install_property (object_class,
517                                          PROP_ARCHIVE,
518                                          g_param_spec_object ("archive",
519                                                               "Archive",
520                                                               "The archive",
521                                                               GXPS_TYPE_ARCHIVE,
522                                                               G_PARAM_WRITABLE |
523                                                               G_PARAM_CONSTRUCT_ONLY));
524         g_object_class_install_property (object_class,
525                                          PROP_SOURCE,
526                                          g_param_spec_string ("source",
527                                                               "Source",
528                                                               "The Core Properties Source File",
529                                                               NULL,
530                                                               G_PARAM_WRITABLE |
531                                                               G_PARAM_CONSTRUCT_ONLY));
532 
533         g_type_class_add_private (klass, sizeof (GXPSCorePropertiesPrivate));
534 }
535 
536 static gboolean
gxps_core_properties_initable_init(GInitable * initable,GCancellable * cancellable,GError ** error)537 gxps_core_properties_initable_init (GInitable     *initable,
538                                     GCancellable  *cancellable,
539                                     GError       **error)
540 {
541         GXPSCoreProperties *core_props = GXPS_CORE_PROPERTIES (initable);
542 
543         if (core_props->priv->initialized) {
544                 if (core_props->priv->init_error) {
545                         g_propagate_error (error, g_error_copy (core_props->priv->init_error));
546 
547                         return FALSE;
548                 }
549 
550                 return TRUE;
551         }
552 
553         core_props->priv->initialized = TRUE;
554 
555         if (!gxps_core_properties_parse (core_props, &core_props->priv->init_error)) {
556                 g_propagate_error (error, g_error_copy (core_props->priv->init_error));
557                 return FALSE;
558         }
559 
560         return TRUE;
561 }
562 
563 static void
initable_iface_init(GInitableIface * initable_iface)564 initable_iface_init (GInitableIface *initable_iface)
565 {
566         initable_iface->init = gxps_core_properties_initable_init;
567 }
568 
569 GXPSCoreProperties *
_gxps_core_properties_new(GXPSArchive * zip,const gchar * source,GError ** error)570 _gxps_core_properties_new (GXPSArchive *zip,
571                            const gchar *source,
572                            GError     **error)
573 {
574         return g_initable_new (GXPS_TYPE_CORE_PROPERTIES,
575                                NULL, error,
576                                "archive", zip,
577                                "source", source,
578                                NULL);
579 }
580 
581 /**
582  * gxps_core_properties_get_title:
583  * @core_props: a #GXPSCoreProperties
584  *
585  * Get the title.
586  *
587  * Returns: a string containing the title or %NULL
588  *
589  * Since: 0.2.3
590  */
591 const gchar *
gxps_core_properties_get_title(GXPSCoreProperties * core_props)592 gxps_core_properties_get_title (GXPSCoreProperties *core_props)
593 {
594         g_return_val_if_fail (GXPS_IS_CORE_PROPERTIES (core_props), NULL);
595 
596         return core_props->priv->title;
597 }
598 
599 /**
600  * gxps_core_properties_get_creator:
601  * @core_props: a #GXPSCoreProperties
602  *
603  * Get the creator.
604  *
605  * Returns: a string containing the creator or %NULL
606  *
607  * Since: 0.2.3
608  */
609 const gchar *
gxps_core_properties_get_creator(GXPSCoreProperties * core_props)610 gxps_core_properties_get_creator (GXPSCoreProperties *core_props)
611 {
612         g_return_val_if_fail (GXPS_IS_CORE_PROPERTIES (core_props), NULL);
613 
614         return core_props->priv->creator;
615 }
616 
617 /**
618  * gxps_core_properties_get_description:
619  * @core_props: a #GXPSCoreProperties
620  *
621  * Get the description.
622  *
623  * Returns: a string containing the description or %NULL
624  *
625  * Since: 0.2.3
626  */
627 const gchar *
gxps_core_properties_get_description(GXPSCoreProperties * core_props)628 gxps_core_properties_get_description (GXPSCoreProperties *core_props)
629 {
630         g_return_val_if_fail (GXPS_IS_CORE_PROPERTIES (core_props), NULL);
631 
632         return core_props->priv->description;
633 }
634 
635 /**
636  * gxps_core_properties_get_subject:
637  * @core_props: a #GXPSCoreProperties
638  *
639  * Get the subject.
640  *
641  * Returns: a string containing the subject or %NULL
642  *
643  * Since: 0.2.3
644  */
645 const gchar *
gxps_core_properties_get_subject(GXPSCoreProperties * core_props)646 gxps_core_properties_get_subject (GXPSCoreProperties *core_props)
647 {
648         g_return_val_if_fail (GXPS_IS_CORE_PROPERTIES (core_props), NULL);
649 
650         return core_props->priv->subject;
651 }
652 
653 /**
654  * gxps_core_properties_get_keywords:
655  * @core_props: a #GXPSCoreProperties
656  *
657  * Get the keywords.
658  *
659  * Returns: a string containing the keywords or %NULL
660  *
661  * Since: 0.2.3
662  */
663 const gchar *
gxps_core_properties_get_keywords(GXPSCoreProperties * core_props)664 gxps_core_properties_get_keywords (GXPSCoreProperties *core_props)
665 {
666         g_return_val_if_fail (GXPS_IS_CORE_PROPERTIES (core_props), NULL);
667 
668         return core_props->priv->keywords;
669 }
670 
671 /**
672  * gxps_core_properties_get_version:
673  * @core_props: a #GXPSCoreProperties
674  *
675  * Get the version number.
676  *
677  * Returns: a string containing the version number or %NULL
678  *
679  * Since: 0.2.3
680  */
681 const gchar *
gxps_core_properties_get_version(GXPSCoreProperties * core_props)682 gxps_core_properties_get_version (GXPSCoreProperties *core_props)
683 {
684         g_return_val_if_fail (GXPS_IS_CORE_PROPERTIES (core_props), NULL);
685 
686         return core_props->priv->version;
687 }
688 
689 /**
690  * gxps_core_properties_get_revision:
691  * @core_props: a #GXPSCoreProperties
692  *
693  * Get the revision number.
694  *
695  * Returns: a string containing the revision number or %NULL
696  *
697  * Since: 0.2.3
698  */
699 const gchar *
gxps_core_properties_get_revision(GXPSCoreProperties * core_props)700 gxps_core_properties_get_revision (GXPSCoreProperties *core_props)
701 {
702         g_return_val_if_fail (GXPS_IS_CORE_PROPERTIES (core_props), NULL);
703 
704         return core_props->priv->revision;
705 }
706 
707 /**
708  * gxps_core_properties_get_identifier:
709  * @core_props: a #GXPSCoreProperties
710  *
711  * Get the unique identifier.
712  *
713  * Returns: a string containing the identifier or %NULL
714  *
715  * Since: 0.2.3
716  */
717 const gchar *
gxps_core_properties_get_identifier(GXPSCoreProperties * core_props)718 gxps_core_properties_get_identifier (GXPSCoreProperties *core_props)
719 {
720         g_return_val_if_fail (GXPS_IS_CORE_PROPERTIES (core_props), NULL);
721 
722         return core_props->priv->identifier;
723 }
724 
725 /**
726  * gxps_core_properties_get_language:
727  * @core_props: a #GXPSCoreProperties
728  *
729  * Get the language.
730  *
731  * Returns: a string containing the language or %NULL
732  *
733  * Since: 0.2.3
734  */
735 const gchar *
gxps_core_properties_get_language(GXPSCoreProperties * core_props)736 gxps_core_properties_get_language (GXPSCoreProperties *core_props)
737 {
738         g_return_val_if_fail (GXPS_IS_CORE_PROPERTIES (core_props), NULL);
739 
740         return core_props->priv->language;
741 }
742 
743 /**
744  * gxps_core_properties_get_category:
745  * @core_props: a #GXPSCoreProperties
746  *
747  * Get the category.
748  *
749  * Returns: a string containing the category or %NULL
750  *
751  * Since: 0.2.3
752  */
753 const gchar *
gxps_core_properties_get_category(GXPSCoreProperties * core_props)754 gxps_core_properties_get_category (GXPSCoreProperties *core_props)
755 {
756         g_return_val_if_fail (GXPS_IS_CORE_PROPERTIES (core_props), NULL);
757 
758         return core_props->priv->category;
759 }
760 
761 /**
762  * gxps_core_properties_get_content_status:
763  * @core_props: a #GXPSCoreProperties
764  *
765  * Get the status of the content (e.g. Draft, Reviewed, Final)
766  *
767  * Returns: a string containing the status of the content or %NULL
768  *
769  * Since: 0.2.3
770  */
771 const gchar *
gxps_core_properties_get_content_status(GXPSCoreProperties * core_props)772 gxps_core_properties_get_content_status (GXPSCoreProperties *core_props)
773 {
774         g_return_val_if_fail (GXPS_IS_CORE_PROPERTIES (core_props), NULL);
775 
776         return core_props->priv->content_status;
777 }
778 
779 /**
780  * gxps_core_properties_get_content_type:
781  * @core_props: a #GXPSCoreProperties
782  *
783  * Get the type of content represented, generally defined by a
784  * specific use and intended audience. This is not the MIME-Type.
785  *
786  * Returns: a string containing the type of content or %NULL
787  *
788  * Since: 0.2.3
789  */
790 const gchar *
gxps_core_properties_get_content_type(GXPSCoreProperties * core_props)791 gxps_core_properties_get_content_type (GXPSCoreProperties *core_props)
792 {
793         g_return_val_if_fail (GXPS_IS_CORE_PROPERTIES (core_props), NULL);
794 
795         return core_props->priv->content_type;
796 }
797 
798 /**
799  * gxps_core_properties_get_created:
800  * @core_props: a #GXPSCoreProperties
801  *
802  * Get the creating date.
803  *
804  * Returns: the creating date as a <type>time_t</type> or -1.
805  *
806  * Since: 0.2.3
807  */
808 time_t
gxps_core_properties_get_created(GXPSCoreProperties * core_props)809 gxps_core_properties_get_created (GXPSCoreProperties *core_props)
810 {
811         g_return_val_if_fail (GXPS_IS_CORE_PROPERTIES (core_props), -1);
812 
813         return core_props->priv->created;
814 }
815 
816 /**
817  * gxps_core_properties_get_last_modified_by:
818  * @core_props: a #GXPSCoreProperties
819  *
820  * Get the user who performed the last modification.
821  *
822  * Returns: a string containing the user who performed the
823  *    last modification or %NULL
824  *
825  * Since: 0.2.3
826  */
827 const gchar *
gxps_core_properties_get_last_modified_by(GXPSCoreProperties * core_props)828 gxps_core_properties_get_last_modified_by (GXPSCoreProperties *core_props)
829 {
830         g_return_val_if_fail (GXPS_IS_CORE_PROPERTIES (core_props), NULL);
831 
832         return core_props->priv->last_modified_by;
833 }
834 
835 /**
836  * gxps_core_properties_get_modified:
837  * @core_props: a #GXPSCoreProperties
838  *
839  * Get the last modification date.
840  *
841  * Returns: the modification date as a <type>time_t</type> or -1.
842  *
843  * Since: 0.2.3
844  */
845 time_t
gxps_core_properties_get_modified(GXPSCoreProperties * core_props)846 gxps_core_properties_get_modified (GXPSCoreProperties *core_props)
847 {
848         g_return_val_if_fail (GXPS_IS_CORE_PROPERTIES (core_props), -1);
849 
850         return core_props->priv->modified;
851 }
852 
853 /**
854  * gxps_core_properties_get_last_printed:
855  * @core_props: a #GXPSCoreProperties
856  *
857  * Get the date of the last printing.
858  *
859  * Returns: the date of the last printing as a <type>time_t</type> or -1.
860  *
861  * Since: 0.2.3
862  */
863 time_t
gxps_core_properties_get_last_printed(GXPSCoreProperties * core_props)864 gxps_core_properties_get_last_printed (GXPSCoreProperties *core_props)
865 {
866         g_return_val_if_fail (GXPS_IS_CORE_PROPERTIES (core_props), -1);
867 
868         return core_props->priv->last_printed;
869 }
870