tracker-0.16.2/src/libtracker-extract/tracker-iptc.c

No issues found

  1 /*
  2  * Copyright (C) 2009, Nokia <ivan.frade@nokia.com>
  3  *
  4  * This library is free software; you can redistribute it and/or
  5  * modify it under the terms of the GNU Lesser General Public
  6  * License as published by the Free Software Foundation; either
  7  * version 2.1 of the License, or (at your option) any later version.
  8  *
  9  * This library is distributed in the hope that it will be useful,
 10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
 11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 12  * Lesser General Public License for more details.
 13  *
 14  * You should have received a copy of the GNU Lesser General Public
 15  * License along with this library; if not, write to the
 16  * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 17  * Boston, MA  02110-1301, USA.
 18  */
 19 
 20 #include "config.h"
 21 
 22 #include <string.h>
 23 
 24 #include "tracker-iptc.h"
 25 #include "tracker-utils.h"
 26 
 27 #ifdef HAVE_LIBIPTCDATA
 28 
 29 #include <libiptcdata/iptc-data.h>
 30 #include <libiptcdata/iptc-dataset.h>
 31 
 32 #define IPTC_DATE_FORMAT "%Y %m %d"
 33 
 34 /**
 35  * SECTION:tracker-iptc
 36  * @title: IPTC
 37  * @short_description: Information Interchange Model (IIM) /
 38  * International Press Telecommunications Council (IPTC)
 39  * @stability: Stable
 40  * @include: libtracker-extract/tracker-extract.h
 41  *
 42  * The Information Interchange Model (IIM) is a file structure and set
 43  * of metadata attributes that can be applied to text, images and
 44  * other media types. It was developed in the early 1990s by the
 45  * International Press Telecommunications Council (IPTC) to expedite
 46  * the international exchange of news among newspapers and news
 47  * agencies.
 48  *
 49  * The full IIM specification includes a complex data structure and a
 50  * set of metadata definitions.
 51  *
 52  * Although IIM was intended for use with all types of news items —
 53  * including simple text articles — a subset found broad worldwide
 54  * acceptance as the standard embedded metadata used by news and
 55  * commercial photographers. Information such as the name of the
 56  * photographer, copyright information and the caption or other
 57  * description can be embedded either manually or automatically.
 58  *
 59  * IIM metadata embedded in images are often referred to as "IPTC
 60  * headers," and can be easily encoded and decoded by most popular
 61  * photo editing software.
 62  *
 63  * The Extensible Metadata Platform (XMP) has largely superseded IIM's
 64  * file structure, but the IIM image attributes are defined in the
 65  * IPTC Core schema for XMP and most image manipulation programs keep
 66  * the XMP and non-XMP IPTC attributes synchronized.
 67  *
 68  * This API is provided to remove code duplication between extractors
 69  * using these standards.
 70  **/
 71 
 72 static const gchar *
 73 fix_iptc_orientation (const gchar *orientation)
 74 {
 75 	if (g_strcmp0 (orientation, "P") == 0) {
 76 		return "nfo:orientation-left";
 77 	}
 78 
 79 	return "nfo:orientation-top"; /* We take this as default */
 80 }
 81 
 82 static void
 83 foreach_dataset (IptcDataSet *dataset,
 84                  void        *user_data)
 85 {
 86 	TrackerIptcData *data = user_data;
 87 	gchar mbuffer[1024];
 88 
 89 	/* The meaning of dataset->tag DEPENDS on the value of dataset->record.
 90 	 * See iptc-tag.h for the relationship.
 91 	 *
 92 	 * Now, We only want record-2 tags, otherwise we'll end up mixing
 93 	 * for example IPTC_TAG_CITY and IPTC_TAG_CHARACTER_SET, which BOTH
 94 	 * have a value of 90. */
 95 	if (dataset->record != IPTC_RECORD_APP_2)
 96 		return;
 97 
 98 	switch (dataset->tag) {
 99 	case IPTC_TAG_KEYWORDS:
100 		if (!data->keywords) {
101 			iptc_dataset_get_as_str (dataset, mbuffer, 1024);
102 			data->keywords = g_strdup (mbuffer);
103 		} else {
104 			gchar *tmp = data->keywords;
105 			iptc_dataset_get_as_str (dataset, mbuffer, 1024);
106 			data->keywords = g_strdup_printf ("%s, %s", data->keywords, mbuffer);
107 			g_free (tmp);
108 		}
109 		break;
110 
111 	case IPTC_TAG_DATE_CREATED:
112 		if (!data->date_created) {
113 			iptc_dataset_get_as_str (dataset, mbuffer, 1024);
114 			/* From: ex; date "2007 04 15"
115 			 * To : ex. "2007-04-15T00:00:00+0200 where +0200 is offset w.r.t gmt */
116 			data->date_created = tracker_date_format_to_iso8601 (mbuffer, IPTC_DATE_FORMAT);
117 		}
118 		break;
119 
120 	case IPTC_TAG_BYLINE:
121 		if (!data->byline) {
122 			iptc_dataset_get_as_str (dataset, mbuffer, 1024);
123 			data->byline = g_strdup (mbuffer);
124 		}
125 		break;
126 
127 	case IPTC_TAG_CREDIT:
128 		if (!data->credit) {
129 			iptc_dataset_get_as_str (dataset, mbuffer, 1024);
130 			data->credit = g_strdup (mbuffer);
131 		}
132 		break;
133 
134 	case IPTC_TAG_COPYRIGHT_NOTICE:
135 		if (!data->copyright_notice) {
136 			iptc_dataset_get_as_str (dataset, mbuffer, 1024);
137 			data->copyright_notice = g_strdup (mbuffer);
138 		}
139 		break;
140 
141 	case IPTC_TAG_IMAGE_ORIENTATION:
142 		if (!data->image_orientation) {
143 			iptc_dataset_get_as_str (dataset, mbuffer, 1024);
144 			data->image_orientation = g_strdup (fix_iptc_orientation (mbuffer));
145 		}
146 		break;
147 
148 	case IPTC_TAG_BYLINE_TITLE:
149 		if (!data->byline_title) {
150 			iptc_dataset_get_as_str (dataset, mbuffer, 1024);
151 			data->byline_title = g_strdup (mbuffer);
152 		}
153 		break;
154 
155 	case IPTC_TAG_CITY:
156 		if (!data->city) {
157 			iptc_dataset_get_as_str (dataset, mbuffer, 1024);
158 			data->city = g_strdup (mbuffer);
159 		}
160 		break;
161 
162 	case IPTC_TAG_STATE:
163 		if (!data->state) {
164 			iptc_dataset_get_as_str (dataset, mbuffer, 1024);
165 			data->state = g_strdup (mbuffer);
166 		}
167 		break;
168 
169 	case IPTC_TAG_SUBLOCATION:
170 		if (!data->sublocation) {
171 			iptc_dataset_get_as_str (dataset, mbuffer, 1024);
172 			data->sublocation = g_strdup (mbuffer);
173 		}
174 		break;
175 
176 	case IPTC_TAG_COUNTRY_NAME:
177 		if (!data->country_name) {
178 			iptc_dataset_get_as_str (dataset, mbuffer, 1024);
179 			data->country_name = g_strdup (mbuffer);
180 		}
181 		break;
182 
183 	case IPTC_TAG_CONTACT:
184 		if (!data->contact) {
185 			iptc_dataset_get_as_str (dataset, mbuffer, 1024);
186 			data->contact = g_strdup (mbuffer);
187 		}
188 		break;
189 
190 	default:
191 		break;
192 	}
193 }
194 
195 #endif /* HAVE_LIBIPTCDATA */
196 
197 static gboolean
198 parse_iptc (const unsigned char *buffer,
199             size_t               len,
200             const gchar         *uri,
201             TrackerIptcData     *data)
202 {
203 #ifdef HAVE_LIBIPTCDATA
204 	IptcData *iptc;
205 #endif /* HAVE_LIBIPTCDATA */
206 
207 	memset (data, 0, sizeof (TrackerIptcData));
208 
209 #ifdef HAVE_LIBIPTCDATA
210 
211 	/* FIXME According to valgrind this is leaking (together with the unref).
212 	 * Problem in libiptc (I replaced this with the _free equivalent) */
213 
214 	iptc = iptc_data_new ();
215 
216 	if (!iptc)
217 		return FALSE;
218 
219 	if (iptc_data_load (iptc, buffer, len) < 0) {
220 		iptc_data_free (iptc);
221 		return FALSE;
222 	}
223 
224 	iptc_data_foreach_dataset (iptc, foreach_dataset, data);
225 	iptc_data_free (iptc);
226 #endif /* HAVE_LIBIPTCDATA */
227 
228 	return TRUE;
229 }
230 
231 #ifndef TRACKER_DISABLE_DEPRECATED
232 
233 // LCOV_EXCL_START
234 
235 /**
236  * tracker_iptc_read:
237  * @buffer: a chunk of data with iptc data in it.
238  * @len: the size of @buffer.
239  * @uri: the URI this is related to.
240  * @data: a pointer to a TrackerIptcData struture to populate.
241  *
242  * This function takes @len bytes of @buffer and runs it through the
243  * IPTC library. The result is that @data is populated with the IPTC
244  * data found in @uri.
245  *
246  * Returns: %TRUE if the @data was populated successfully, otherwise
247  * %FALSE is returned.
248  *
249  * Since: 0.8
250  *
251  * Deprecated: 0.9. Use tracker_iptc_new() instead.
252  **/
253 gboolean
254 tracker_iptc_read (const unsigned char *buffer,
255                    size_t               len,
256                    const gchar         *uri,
257                    TrackerIptcData     *data)
258 {
259 	g_return_val_if_fail (buffer != NULL, FALSE);
260 	g_return_val_if_fail (len > 0, FALSE);
261 	g_return_val_if_fail (uri != NULL, FALSE);
262 	g_return_val_if_fail (data != NULL, FALSE);
263 
264 	return parse_iptc (buffer, len, uri, data);
265 }
266 
267 // LCOV_EXCL_STOP
268 
269 #endif /* TRACKER_DISABLE_DEPRECATED */
270 
271 /**
272  * tracker_iptc_new:
273  * @buffer: a chunk of data with iptc data in it.
274  * @len: the size of @buffer.
275  * @uri: the URI this is related to.
276  *
277  * This function takes @len bytes of @buffer and runs it through the
278  * IPTC library.
279  *
280  * Returns: a newly allocated #TrackerIptcData struct if IPTC data was
281  * found, %NULL otherwise. Free the returned struct with
282  * tracker_iptc_free().
283  *
284  * Since: 0.10
285  **/
286 TrackerIptcData *
287 tracker_iptc_new (const guchar *buffer,
288                   gsize         len,
289                   const gchar  *uri)
290 {
291 	TrackerIptcData *data;
292 
293 	g_return_val_if_fail (buffer != NULL, NULL);
294 	g_return_val_if_fail (len > 0, NULL);
295 	g_return_val_if_fail (uri != NULL, NULL);
296 
297 	data = g_new0 (TrackerIptcData, 1);
298 
299 	if (!parse_iptc (buffer, len, uri, data)) {
300 		tracker_iptc_free (data);
301 		return NULL;
302 	}
303 
304 	return data;
305 }
306 
307 /**
308  * tracker_iptc_free:
309  * @data: a #TrackerIptcData
310  *
311  * Frees @data and all #TrackerIptcData members. %NULL will produce a
312  * a warning.
313  *
314  * Since: 0.10
315  **/
316 void
317 tracker_iptc_free (TrackerIptcData *data)
318 {
319 	g_return_if_fail (data != NULL);
320 
321 	g_free (data->keywords);
322 	g_free (data->date_created);
323 	g_free (data->byline);
324 	g_free (data->credit);
325 	g_free (data->copyright_notice);
326 	g_free (data->image_orientation);
327 	g_free (data->byline_title);
328 	g_free (data->city);
329 	g_free (data->state);
330 	g_free (data->sublocation);
331 	g_free (data->country_name);
332 	g_free (data->contact);
333 
334 	g_free (data);
335 }