]> www.fi.muni.cz Git - evince.git/blobdiff - backend/pdf/ev-poppler.cc
Add libdocument/ev-file-helpers.c to POTFILES.in
[evince.git] / backend / pdf / ev-poppler.cc
index 0333d715564810d5209bc9856e0c2386fc8b6733..917529e100e92daf80e47938f10fe8e5c5c1ac30 100644 (file)
@@ -1,5 +1,7 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8; c-indent-level: 8 -*- */
-/* pdfdocument.h: Implementation of EvDocument for PDF
+/* this file is part of evince, a gnome document viewer
+ *
+ * Copyright (C) 2009, Juanjo MarĂ­n <juanj.marin@juntadeandalucia.es>
  * Copyright (C) 2004, Red Hat, Inc.
  *
  * This program is free software; you can redistribute it and/or modify
 #define HAVE_CAIRO_PRINT
 #endif
 
+/* fields from the XMP Rights Management Schema, XMP Specification Sept 2005, pag. 45 */
+#define LICENSE_MARKED "/x:xmpmeta/rdf:RDF/rdf:Description/xmpRights:Marked"
+#define LICENSE_TEXT "/x:xmpmeta/rdf:RDF/rdf:Description/dc:rights/rdf:Alt/rdf:li[lang('%s')]"
+#define LICENSE_WEB_STATEMENT "/x:xmpmeta/rdf:RDF/rdf:Description/xmpRights:WebStatement"
+/* license field from Creative Commons schema, http://creativecommons.org/ns */
+#define LICENSE_URI "/x:xmpmeta/rdf:RDF/rdf:Description/cc:license/@rdf:resource"
+
 typedef struct {
        PdfDocument *document;
        char *text;
@@ -92,12 +101,12 @@ typedef struct {
 
 struct _PdfDocumentClass
 {
-       GObjectClass parent_class;
+       EvDocumentClass parent_class;
 };
 
 struct _PdfDocument
 {
-       GObject parent_instance;
+       EvDocument parent_instance;
 
        PopplerDocument *document;
        gchar *password;
@@ -113,7 +122,6 @@ struct _PdfDocument
        GList *layers;
 };
 
-static void pdf_document_document_iface_init             (EvDocumentIface            *iface);
 static void pdf_document_security_iface_init             (EvDocumentSecurityIface    *iface);
 static void pdf_document_document_thumbnails_iface_init  (EvDocumentThumbnailsIface  *iface);
 static void pdf_document_document_links_iface_init       (EvDocumentLinksIface       *iface);
@@ -233,14 +241,6 @@ pdf_document_dispose (GObject *object)
        G_OBJECT_CLASS (pdf_document_parent_class)->dispose (object);
 }
 
-static void
-pdf_document_class_init (PdfDocumentClass *klass)
-{
-       GObjectClass *g_object_class = G_OBJECT_CLASS (klass);
-
-       g_object_class->dispose = pdf_document_dispose;
-}
-
 static void
 pdf_document_init (PdfDocument *pdf_document)
 {
@@ -448,51 +448,18 @@ pdf_document_render (EvDocument      *document,
                                width, height, rc);
 }
 
-/* EvDocumentSecurity */
-
-static gboolean
-pdf_document_has_document_security (EvDocumentSecurity *document_security)
-{
-       /* FIXME: do we really need to have this? */
-       return FALSE;
-}
-
-static void
-pdf_document_set_password (EvDocumentSecurity *document_security,
-                          const char         *password)
-{
-       PdfDocument *document = PDF_DOCUMENT (document_security);
-
-       if (document->password)
-               g_free (document->password);
-
-       document->password = g_strdup (password);
-}
-
-
 /* reference:
 http://www.pdfa.org/lib/exe/fetch.php?id=pdfa%3Aen%3Atechdoc&cache=cache&media=pdfa:techdoc:tn0001_pdfa-1_and_namespaces_2008-03-18.pdf */
 static char *
-pdf_document_get_format_from_metadata (const char *metadata)
+pdf_document_get_format_from_metadata (xmlDocPtr          doc,
+                                      xmlXPathContextPtr xpathCtx)
 {
-       xmlDocPtr doc;
-       xmlXPathContextPtr xpathCtx;
        xmlXPathObjectPtr xpathObj;
        xmlChar *part = NULL;
        xmlChar *conf = NULL;
        char *result = NULL;
        int i;
 
-       doc = xmlParseMemory (metadata, strlen (metadata));
-       if (doc == NULL)
-               return NULL;      /* invalid xml metadata */
-
-       xpathCtx = xmlXPathNewContext (doc);
-       if (xpathCtx == NULL) {
-               xmlFreeDoc (doc);
-               return NULL;      /* invalid xpath context */
-       }
-
        /* add pdf/a namespaces */
        xmlXPathRegisterNs (xpathCtx, BAD_CAST "x", BAD_CAST "adobe:ns:meta/");
        xmlXPathRegisterNs (xpathCtx, BAD_CAST "rdf", BAD_CAST "http://www.w3.org/1999/02/22-rdf-syntax-ns#");
@@ -550,12 +517,159 @@ pdf_document_get_format_from_metadata (const char *metadata)
        /* Cleanup */
        xmlFree (part);
        xmlFree (conf);
-       xmlXPathFreeContext (xpathCtx);
-       xmlFreeDoc (doc);
 
        return result;
 }
 
+static EvDocumentLicense *
+pdf_document_get_license_from_metadata (xmlDocPtr          doc,
+                                       xmlXPathContextPtr xpathCtx)
+{
+       xmlXPathObjectPtr xpathObj;
+       xmlChar *marked = NULL;
+       const char *language_string;
+       char  *aux;
+       gchar **tags;
+       gchar *tag, *tag_aux;
+       int i, j;
+       EvDocumentLicense *license;
+
+       /* register namespaces */
+       xmlXPathRegisterNs (xpathCtx, BAD_CAST "x", BAD_CAST "adobe:ns:meta/");
+       xmlXPathRegisterNs (xpathCtx, BAD_CAST "rdf", BAD_CAST "http://www.w3.org/1999/02/22-rdf-syntax-ns#");
+       xmlXPathRegisterNs (xpathCtx, BAD_CAST "dc", BAD_CAST "http://purl.org/dc/elements/1.1/");
+       /* XMP Rights Management Schema */
+       xmlXPathRegisterNs (xpathCtx, BAD_CAST "xmpRights", BAD_CAST "http://ns.adobe.com/xap/1.0/rights/");
+       /* Creative Commons Schema */
+       xmlXPathRegisterNs (xpathCtx, BAD_CAST "cc", BAD_CAST "http://creativecommons.org/ns#");
+
+       /* checking if the document has been marked as defined on the XMP Rights
+        * Management Schema */
+       xpathObj = xmlXPathEvalExpression (BAD_CAST LICENSE_MARKED, xpathCtx);
+       if (xpathObj != NULL) {
+               if (xpathObj->nodesetval != NULL &&
+                   xpathObj->nodesetval->nodeNr != 0)
+                       marked = xmlNodeGetContent (xpathObj->nodesetval->nodeTab[0]);
+               xmlXPathFreeObject (xpathObj);
+       }
+
+       /* a) Not marked => No XMP Rights information */
+       if (!marked) {
+               xmlFree (marked);
+               return NULL;
+       }
+
+       license = ev_document_license_new ();
+
+       /* b) Marked False => Public Domain, no copyrighted material and no
+        * license needed */
+       if (g_strrstr ((char *) marked, "False") != NULL) {
+               license->text = g_strdup (_("This work is in the Public Domain"));
+       /* c) Marked True => Copyrighted material */
+       } else {
+               /* Checking usage terms as defined by the XMP Rights Management
+                * Schema. This field is recomended to be checked by Creative
+                * Commons */
+               /* 1) checking for a suitable localized string */
+               language_string = pango_language_to_string (gtk_get_default_language ());
+               tags = g_strsplit (language_string, "-", -1);
+               i = g_strv_length (tags);
+               while (i-- && !license->text) {
+                       tag = g_strdup (tags[0]);
+                       for (j = 1; j <= i; j++) {
+                               tag_aux = g_strdup_printf ("%s-%s", tag, tags[j]);
+                               g_free (tag);
+                               tag = tag_aux;
+                       }
+                       aux = g_strdup_printf (LICENSE_TEXT, tag);
+                       xpathObj = xmlXPathEvalExpression (BAD_CAST aux, xpathCtx);
+                       if (xpathObj != NULL) {
+                               if (xpathObj->nodesetval != NULL &&
+                                   xpathObj->nodesetval->nodeNr != 0)
+                                       license->text = (gchar *)xmlNodeGetContent (xpathObj->nodesetval->nodeTab[0]);
+                               xmlXPathFreeObject (xpathObj);
+                       }
+                       g_free (tag);
+                       g_free (aux);
+               }
+               g_strfreev(tags);
+
+               /* 2) if not, use the default string */
+               if (!license->text) {
+                       aux = g_strdup_printf (LICENSE_TEXT, "x-default");
+                       xpathObj = xmlXPathEvalExpression (BAD_CAST aux, xpathCtx);
+                       if (xpathObj != NULL) {
+                               if (xpathObj->nodesetval != NULL &&
+                                   xpathObj->nodesetval->nodeNr != 0)
+                                       license->text = (gchar *)xmlNodeGetContent (xpathObj->nodesetval->nodeTab[0]);
+                               xmlXPathFreeObject (xpathObj);
+                       }
+                       g_free (aux);
+               }
+
+               /* Checking the license URI as defined by the Creative Commons
+                * Schema. This field is recomended to be checked by Creative
+                * Commons */
+               xpathObj = xmlXPathEvalExpression (BAD_CAST LICENSE_URI, xpathCtx);
+               if (xpathObj != NULL) {
+                       if (xpathObj->nodesetval != NULL &&
+                           xpathObj->nodesetval->nodeNr != 0)
+                               license->uri = (gchar *)xmlNodeGetContent (xpathObj->nodesetval->nodeTab[0]);
+                       xmlXPathFreeObject (xpathObj);
+               }
+
+               /* Checking the web statement as defined by the XMP Rights
+                * Management Schema. Checking it out is a sort of above-and-beyond
+                * the basic recommendations by Creative Commons. It can be
+                * considered as a "reinforcement" approach to add certainty. */
+               xpathObj = xmlXPathEvalExpression (BAD_CAST LICENSE_WEB_STATEMENT, xpathCtx);
+               if (xpathObj != NULL) {
+                       if (xpathObj->nodesetval != NULL &&
+                           xpathObj->nodesetval->nodeNr != 0)
+                               license->web_statement = (gchar *)xmlNodeGetContent (xpathObj->nodesetval->nodeTab[0]);
+                       xmlXPathFreeObject (xpathObj);
+               }
+       }
+       xmlFree (marked);
+
+       if (!license->text && !license->uri && !license->web_statement) {
+               ev_document_license_free (license);
+               return NULL;
+       }
+
+       return license;
+}
+
+static void
+pdf_document_parse_metadata (const gchar    *metadata,
+                            EvDocumentInfo *info)
+{
+       xmlDocPtr          doc;
+       xmlXPathContextPtr xpathCtx;
+       gchar             *fmt;
+
+       doc = xmlParseMemory (metadata, strlen (metadata));
+       if (doc == NULL)
+               return;         /* invalid xml metadata */
+
+       xpathCtx = xmlXPathNewContext (doc);
+       if (xpathCtx == NULL) {
+               xmlFreeDoc (doc);
+               return;         /* invalid xpath context */
+       }
+
+       fmt = pdf_document_get_format_from_metadata (doc, xpathCtx);
+       if (fmt != NULL) {
+               g_free (info->format);
+               info->format = fmt;
+       }
+
+       info->license = pdf_document_get_license_from_metadata (doc, xpathCtx);
+
+       xmlXPathFreeContext (xpathCtx);
+       xmlFreeDoc (doc);
+}
+
 
 static EvDocumentInfo *
 pdf_document_get_info (EvDocument *document)
@@ -567,7 +681,6 @@ pdf_document_get_info (EvDocument *document)
        PopplerPermissions permissions;
        EvPage *page;
        char *metadata;
-       char *fmt;
 
        info = g_new0 (EvDocumentInfo, 1);
 
@@ -587,7 +700,8 @@ pdf_document_get_info (EvDocument *document)
                            EV_DOCUMENT_INFO_LINEARIZED |
                            EV_DOCUMENT_INFO_N_PAGES |
                            EV_DOCUMENT_INFO_SECURITY | 
-                           EV_DOCUMENT_INFO_PAPER_SIZE;
+                           EV_DOCUMENT_INFO_PAPER_SIZE |
+                           EV_DOCUMENT_INFO_LICENSE;
 
        g_object_get (PDF_DOCUMENT (document)->document,
                      "title", &(info->title),
@@ -608,24 +722,16 @@ pdf_document_get_info (EvDocument *document)
                      NULL);
 
        if (metadata != NULL) {
-               fmt = pdf_document_get_format_from_metadata(metadata);
-               if (fmt != NULL) {
-                       g_free (info->format);
-                       info->format = fmt;
-               }
+               pdf_document_parse_metadata (metadata, info);
                g_free (metadata);
        }
 
        info->n_pages = ev_document_get_n_pages (document);
 
        if (info->n_pages > 0) {
-               page = ev_document_get_page (document, 0);
-               ev_document_get_page_size (document, page,
+               ev_document_get_page_size (document, 0,
                                           &(info->paper_width),
                                           &(info->paper_height));
-               g_object_unref (page);
-               
-
                // Convert to mm.
                info->paper_width = info->paper_width / 72.0f * 25.4f;
                info->paper_height = info->paper_height / 72.0f * 25.4f;
@@ -721,17 +827,42 @@ pdf_document_get_info (EvDocument *document)
 }
 
 static void
-pdf_document_document_iface_init (EvDocumentIface *iface)
-{
-       iface->save = pdf_document_save;
-       iface->load = pdf_document_load;
-       iface->get_n_pages = pdf_document_get_n_pages;
-       iface->get_page = pdf_document_get_page;
-       iface->get_page_size = pdf_document_get_page_size;
-       iface->get_page_label = pdf_document_get_page_label;
-       iface->render = pdf_document_render;
-       iface->get_info = pdf_document_get_info;
-};
+pdf_document_class_init (PdfDocumentClass *klass)
+{
+       GObjectClass    *g_object_class = G_OBJECT_CLASS (klass);
+       EvDocumentClass *ev_document_class = EV_DOCUMENT_CLASS (klass);
+
+       g_object_class->dispose = pdf_document_dispose;
+
+       ev_document_class->save = pdf_document_save;
+       ev_document_class->load = pdf_document_load;
+       ev_document_class->get_n_pages = pdf_document_get_n_pages;
+       ev_document_class->get_page = pdf_document_get_page;
+       ev_document_class->get_page_size = pdf_document_get_page_size;
+       ev_document_class->get_page_label = pdf_document_get_page_label;
+       ev_document_class->render = pdf_document_render;
+       ev_document_class->get_info = pdf_document_get_info;
+}
+
+/* EvDocumentSecurity */
+static gboolean
+pdf_document_has_document_security (EvDocumentSecurity *document_security)
+{
+       /* FIXME: do we really need to have this? */
+       return FALSE;
+}
+
+static void
+pdf_document_set_password (EvDocumentSecurity *document_security,
+                          const char         *password)
+{
+       PdfDocument *document = PDF_DOCUMENT (document_security);
+
+       if (document->password)
+               g_free (document->password);
+
+       document->password = g_strdup (password);
+}
 
 static void
 pdf_document_security_iface_init (EvDocumentSecurityIface *iface)