Evince
Evince is a document viewer capable of displaying multiple and single page document formats like PDF and Postscript.
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
ev-metadata.c
Go to the documentation of this file.
1 /* ev-metadata.c
2  * this file is part of evince, a gnome document viewer
3  *
4  * Copyright (C) 2009 Carlos Garcia Campos <carlosgc@gnome.org>
5  *
6  * Evince is free software; you can redistribute it and/or modify it
7  * under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * Evince is distributed in the hope that it will be useful, but
12  * WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14  * General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19  */
20 
21 #include <gio/gio.h>
22 #include <string.h>
23 
24 #include "ev-metadata.h"
25 #include "ev-file-helpers.h"
26 
27 struct _EvMetadata {
28  GObject base;
29 
30  GFile *file;
31  GHashTable *items;
32 };
33 
35  GObjectClass base_class;
36 };
37 
38 G_DEFINE_TYPE (EvMetadata, ev_metadata, G_TYPE_OBJECT)
39 
40 #define EV_METADATA_NAMESPACE "metadata::evince"
41 
42 static void
43 ev_metadata_finalize (GObject *object)
44 {
45  EvMetadata *metadata = EV_METADATA (object);
46 
47  if (metadata->items) {
48  g_hash_table_destroy (metadata->items);
49  metadata->items = NULL;
50  }
51 
52  if (metadata->file) {
53  g_object_unref (metadata->file);
54  metadata->file = NULL;
55  }
56 
57  G_OBJECT_CLASS (ev_metadata_parent_class)->finalize (object);
58 }
59 
60 static void
62 {
63  metadata->items = g_hash_table_new_full (g_str_hash,
64  g_str_equal,
65  g_free,
66  g_free);
67 }
68 
69 static void
71 {
72  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
73 
74  gobject_class->finalize = ev_metadata_finalize;
75 }
76 
77 static void
79 {
80  GFileInfo *info;
81  gchar **attrs;
82  gint i;
83  GError *error = NULL;
84 
85  info = g_file_query_info (metadata->file, "metadata::*", 0, NULL, &error);
86  if (!info) {
87  g_warning ("%s", error->message);
88  g_error_free (error);
89 
90  return;
91  }
92 
93  if (!g_file_info_has_namespace (info, "metadata")) {
94  g_object_unref (info);
95 
96  return;
97  }
98 
99  attrs = g_file_info_list_attributes (info, "metadata");
100  for (i = 0; attrs[i]; i++) {
101  GFileAttributeType type;
102  gpointer value;
103  const gchar *key;
104 
105  if (!g_str_has_prefix (attrs[i], EV_METADATA_NAMESPACE))
106  continue;
107 
108  if (!g_file_info_get_attribute_data (info, attrs[i],
109  &type, &value, NULL)) {
110  continue;
111  }
112 
113  key = attrs[i] + strlen (EV_METADATA_NAMESPACE"::");
114 
115  if (type == G_FILE_ATTRIBUTE_TYPE_STRING) {
116  g_hash_table_insert (metadata->items,
117  g_strdup (key),
118  g_strdup (value));
119  }
120  }
121  g_strfreev (attrs);
122  g_object_unref (info);
123 }
124 
125 EvMetadata *
126 ev_metadata_new (GFile *file)
127 {
128  EvMetadata *metadata;
129 
130  g_return_val_if_fail (G_IS_FILE (file), NULL);
131 
132  metadata = EV_METADATA (g_object_new (EV_TYPE_METADATA, NULL));
133  if (!ev_file_is_temp (file)) {
134  metadata->file = g_object_ref (file);
135  ev_metadata_load (metadata);
136  }
137 
138  return metadata;
139 }
140 
141 gboolean
143 {
144  return g_hash_table_size (metadata->items) == 0;
145 }
146 
147 gboolean
149  const gchar *key,
150  gchar **value)
151 {
152  gchar *v;
153 
154  v = g_hash_table_lookup (metadata->items, key);
155  if (!v)
156  return FALSE;
157 
158  *value = v;
159  return TRUE;
160 }
161 
162 static void
163 metadata_set_callback (GObject *file,
164  GAsyncResult *result,
165  EvMetadata *metadata)
166 {
167  GError *error = NULL;
168 
169  if (!g_file_set_attributes_finish (G_FILE (file), result, NULL, &error)) {
170  g_warning ("%s", error->message);
171  g_error_free (error);
172  }
173 }
174 
175 gboolean
177  const gchar *key,
178  const gchar *value)
179 {
180  GFileInfo *info;
181  gchar *gio_key;
182 
183  g_hash_table_insert (metadata->items, g_strdup (key), g_strdup (value));
184  if (!metadata->file)
185  return TRUE;
186 
187  info = g_file_info_new ();
188 
189  gio_key = g_strconcat (EV_METADATA_NAMESPACE"::", key, NULL);
190  if (value) {
191  g_file_info_set_attribute_string (info, gio_key, value);
192  } else {
193  g_file_info_set_attribute (info, gio_key,
194  G_FILE_ATTRIBUTE_TYPE_INVALID,
195  NULL);
196  }
197  g_free (gio_key);
198 
199  g_file_set_attributes_async (metadata->file,
200  info,
201  0,
202  G_PRIORITY_DEFAULT,
203  NULL,
204  (GAsyncReadyCallback)metadata_set_callback,
205  metadata);
206  g_object_unref (info);
207 
208  return TRUE;
209 }
210 
211 gboolean
213  const gchar *key,
214  gint *value)
215 {
216  gchar *string_value;
217  gchar *endptr;
218  gint int_value;
219 
220  if (!ev_metadata_get_string (metadata, key, &string_value))
221  return FALSE;
222 
223  int_value = g_ascii_strtoull (string_value, &endptr, 0);
224  if (int_value == 0 && string_value == endptr)
225  return FALSE;
226 
227  *value = int_value;
228  return TRUE;
229 }
230 
231 gboolean
233  const gchar *key,
234  gint value)
235 {
236  gchar string_value[32];
237 
238  g_snprintf (string_value, sizeof (string_value), "%d", value);
239 
240  return ev_metadata_set_string (metadata, key, string_value);
241 }
242 
243 gboolean
245  const gchar *key,
246  gdouble *value)
247 {
248  gchar *string_value;
249  gchar *endptr;
250  gdouble double_value;
251 
252  if (!ev_metadata_get_string (metadata, key, &string_value))
253  return FALSE;
254 
255  double_value = g_ascii_strtod (string_value, &endptr);
256  if (double_value == 0. && string_value == endptr)
257  return FALSE;
258 
259  *value = double_value;
260  return TRUE;
261 }
262 
263 gboolean
265  const gchar *key,
266  gdouble value)
267 {
268  gchar string_value[G_ASCII_DTOSTR_BUF_SIZE];
269 
270  g_ascii_dtostr (string_value, G_ASCII_DTOSTR_BUF_SIZE, value);
271 
272  return ev_metadata_set_string (metadata, key, string_value);
273 }
274 
275 gboolean
277  const gchar *key,
278  gboolean *value)
279 {
280  gint int_value;
281 
282  if (!ev_metadata_get_int (metadata, key, &int_value))
283  return FALSE;
284 
285  *value = int_value;
286  return TRUE;
287 }
288 
289 gboolean
291  const gchar *key,
292  gboolean value)
293 {
294  return ev_metadata_set_string (metadata, key, value ? "1" : "0");
295 }
296 
297 gboolean
299  const gchar *key)
300 {
301  return g_hash_table_lookup (metadata->items, key) != NULL;
302 }
303 
304 gboolean
306 {
307  GFileAttributeInfoList *namespaces;
308  gint i;
309  gboolean retval = FALSE;
310 
311  namespaces = g_file_query_writable_namespaces (file, NULL, NULL);
312  if (!namespaces)
313  return retval;
314 
315  for (i = 0; i < namespaces->n_infos; i++) {
316  if (strcmp (namespaces->infos[i].name, "metadata") == 0) {
317  retval = TRUE;
318  break;
319  }
320  }
321 
322  g_file_attribute_info_list_unref (namespaces);
323 
324  return retval;
325 }