Location | Tool | Test ID | Function | Issue |
---|---|---|---|---|
tracker-extract-png.c:158:2 | clang-analyzer | Value stored to 'o' is never read | ||
tracker-extract-png.c:284:29 | gcc | pointer-sign | read_metadata | pointer targets in passing argument 1 of 'tracker_exif_new' differ in signedness |
1 /*
2 * Copyright (C) 2006, Jamie McCracken <jamiemcc@gnome.org>
3 * Copyright (C) 2008, Nokia <ivan.frade@nokia.com>
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
17 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 * Boston, MA 02110-1301, USA.
19 */
20
21 #include "config.h"
22
23 #ifndef _GNU_SOURCE
24 #define _GNU_SOURCE
25 #endif
26
27 #include <png.h>
28
29 #include <libtracker-common/tracker-file-utils.h>
30 #include <libtracker-common/tracker-date-time.h>
31 #include <libtracker-extract/tracker-extract.h>
32
33 #define RFC1123_DATE_FORMAT "%d %B %Y %H:%M:%S %z"
34 #define CM_TO_INCH 0.393700787
35
36 typedef struct {
37 const gchar *title;
38 const gchar *copyright;
39 const gchar *creator;
40 const gchar *description;
41 const gchar *date;
42 const gchar *license;
43 const gchar *artist;
44 const gchar *make;
45 const gchar *model;
46 const gchar *orientation;
47 const gchar *white_balance;
48 const gchar *fnumber;
49 const gchar *flash;
50 const gchar *focal_length;
51 const gchar *exposure_time;
52 const gchar *iso_speed_ratings;
53 const gchar *metering_mode;
54 const gchar *comment;
55 const gchar *city;
56 const gchar *state;
57 const gchar *address;
58 const gchar *country;
59 const gchar *gps_direction;
60 } MergeData;
61
62 typedef struct {
63 const gchar *author;
64 const gchar *creator;
65 const gchar *description;
66 const gchar *comment;
67 const gchar *copyright;
68 gchar *creation_time;
69 const gchar *title;
70 const gchar *disclaimer;
71 } PngData;
72
73 static gchar *
74 rfc1123_to_iso8601_date (const gchar *date)
75 {
76 /* From: ex. RFC1123 date: "22 May 1997 18:07:10 -0600"
77 * To : ex. ISO8601 date: "2007-05-22T18:07:10-0600"
78 */
79 return tracker_date_format_to_iso8601 (date, RFC1123_DATE_FORMAT);
80 }
81
82 #if defined(PNG_iTXt_SUPPORTED) && (defined(HAVE_EXEMPI) || defined(HAVE_LIBEXIF))
83
84 /* Handle raw profiles by Imagemagick (at least). Hex encoded with
85 * line-changes and other (undocumented/unofficial) twists.
86 */
87 static gchar *
88 raw_profile_new (const gchar *input,
89 const guint input_length,
90 guint *output_length)
91 {
92 static const gchar* const lut = "0123456789abcdef";
93 gchar *output;
94 const gchar *ptr;
95 const gchar *length_ptr;
96 gsize size;
97 gchar *length_str;
98 guint length;
99
100 size_t len;
101 size_t i;
102 size_t o;
103 char *p;
104 char *q;
105
106 ptr = input;
107
108 if (*ptr != '\n') {
109 return NULL;
110 }
111
112 ptr++;
113
114 if (!g_ascii_isalpha (*ptr)) {
115 return NULL;
116 }
117
118 /* Skip the type string */
119 do {
120 ptr++;
121 } while (g_ascii_isalpha (*ptr));
122
123 if (*ptr != '\n') {
124 return NULL;
125 }
126
127 /* Hop over whitespaces */
128 do {
129 ptr++;
130 } while (*ptr == ' ');
131
132 if (!g_ascii_isdigit (*ptr)) {
133 return NULL;
134 }
135
136 /* Get the length string */
137 length_ptr = ptr;
138 size = 1;
139
140 do {
141 ptr++;
142 size++;
143 } while (g_ascii_isdigit (*ptr));
144
145 length_str = g_strndup (length_ptr, size - 1);
146
147 if (*ptr != '\n') {
148 return NULL;
149 }
150
151 ptr++;
152
153 length = atoi (length_str);
154 g_free (length_str);
155
156 len = length;
157 i = 0;
158 o = 0;
(emitted by clang-analyzer)TODO: a detailed trace is available in the data model (not yet rendered in this report)
159
160 output = malloc (length + 1); /* A bit less with non-valid */
161
162 o = 0;
163 while (o < len) {
164 do {
165 gchar a = ptr[i];
166 p = strchr (lut, a);
167 i++;
168 } while (p == 0);
169
170 do {
171 gchar b = ptr[i];
172 q = strchr (lut, b);
173 i++;
174 } while (q == 0);
175
176 output[o] = (((p - lut) << 4) | (q - lut));
177 o++;
178 }
179
180 output[o] = '\0';
181 *output_length = o;
182
183 return output;
184 }
185
186 #endif /* defined(PNG_iTXt_SUPPORTED) && (defined(HAVE_EXEMPI) || defined(HAVE_LIBEXIF)) */
187
188 static void
189 read_metadata (TrackerSparqlBuilder *preupdate,
190 TrackerSparqlBuilder *metadata,
191 GString *where,
192 png_structp png_ptr,
193 png_infop info_ptr,
194 png_infop end_ptr,
195 const gchar *uri,
196 const gchar *graph)
197 {
198 MergeData md = { 0 };
199 PngData pd = { 0 };
200 TrackerExifData *ed = NULL;
201 TrackerXmpData *xd = NULL;
202 png_infop info_ptrs[2];
203 png_textp text_ptr;
204 gint info_index;
205 gint num_text;
206 gint i;
207 gint found;
208 GPtrArray *keywords;
209
210 info_ptrs[0] = info_ptr;
211 info_ptrs[1] = end_ptr;
212
213 for (info_index = 0; info_index < 2; info_index++) {
214 if ((found = png_get_text (png_ptr, info_ptrs[info_index], &text_ptr, &num_text)) < 1) {
215 g_debug ("Calling png_get_text() returned %d (< 1)", found);
216 continue;
217 }
218
219 for (i = 0; i < num_text; i++) {
220 if (!text_ptr[i].key || !text_ptr[i].text || text_ptr[i].text[0] == '\0') {
221 continue;
222 }
223
224 #if defined(HAVE_EXEMPI) && defined(PNG_iTXt_SUPPORTED)
225 if (g_strcmp0 ("XML:com.adobe.xmp", text_ptr[i].key) == 0) {
226 /* ATM tracker_extract_xmp_read supports setting xd
227 * multiple times, keep it that way as here it's
228 * theoretically possible that the function gets
229 * called multiple times
230 */
231 xd = tracker_xmp_new (text_ptr[i].text,
232 text_ptr[i].itxt_length,
233 uri);
234
235 continue;
236 }
237
238 if (g_strcmp0 ("Raw profile type xmp", text_ptr[i].key) == 0) {
239 gchar *xmp_buffer;
240 guint xmp_buffer_length = 0;
241 guint input_len;
242
243 if (text_ptr[i].text_length) {
244 input_len = text_ptr[i].text_length;
245 } else {
246 input_len = text_ptr[i].itxt_length;
247 }
248
249 xmp_buffer = raw_profile_new (text_ptr[i].text,
250 input_len,
251 &xmp_buffer_length);
252
253 if (xmp_buffer) {
254 xd = tracker_xmp_new (xmp_buffer,
255 xmp_buffer_length,
256 uri);
257 }
258
259 g_free (xmp_buffer);
260
261 continue;
262 }
263 #endif /*HAVE_EXEMPI && PNG_iTXt_SUPPORTED */
264
265 #if defined(HAVE_LIBEXIF) && defined(PNG_iTXt_SUPPORTED)
266 if (g_strcmp0 ("Raw profile type exif", text_ptr[i].key) == 0) {
267 gchar *exif_buffer;
268 guint exif_buffer_length = 0;
269 guint input_len;
270
271 if (text_ptr[i].text_length) {
272 input_len = text_ptr[i].text_length;
273 } else {
274 input_len = text_ptr[i].itxt_length;
275 }
276
277 exif_buffer = raw_profile_new (text_ptr[i].text,
278 input_len,
279 &exif_buffer_length);
280
281 if (exif_buffer) {
282 ed = tracker_exif_new (exif_buffer,
283 exif_buffer_length,
284 uri);
(emitted by gcc) 285 }
286
287 g_free (exif_buffer);
288
289 continue;
290 }
291 #endif /* HAVE_LIBEXIF && PNG_iTXt_SUPPORTED */
292
293 if (g_strcmp0 (text_ptr[i].key, "Author") == 0) {
294 pd.author = text_ptr[i].text;
295 continue;
296 }
297
298 if (g_strcmp0 (text_ptr[i].key, "Creator") == 0) {
299 pd.creator = text_ptr[i].text;
300 continue;
301 }
302
303 if (g_strcmp0 (text_ptr[i].key, "Description") == 0) {
304 pd.description = text_ptr[i].text;
305 continue;
306 }
307
308 if (g_strcmp0 (text_ptr[i].key, "Comment") == 0) {
309 pd.comment = text_ptr[i].text;
310 continue;
311 }
312
313 if (g_strcmp0 (text_ptr[i].key, "Copyright") == 0) {
314 pd.copyright = text_ptr[i].text;
315 continue;
316 }
317
318 if (g_strcmp0 (text_ptr[i].key, "Creation Time") == 0) {
319 pd.creation_time = rfc1123_to_iso8601_date (text_ptr[i].text);
320 continue;
321 }
322
323 if (g_strcmp0 (text_ptr[i].key, "Title") == 0) {
324 pd.title = text_ptr[i].text;
325 continue;
326 }
327
328 if (g_strcmp0 (text_ptr[i].key, "Disclaimer") == 0) {
329 pd.disclaimer = text_ptr[i].text;
330 continue;
331 }
332 }
333 }
334
335 if (!ed) {
336 ed = g_new0 (TrackerExifData, 1);
337 }
338
339 if (!xd) {
340 xd = g_new0 (TrackerXmpData, 1);
341 }
342
343 md.creator = tracker_coalesce_strip (3, xd->creator, pd.creator, pd.author);
344 md.title = tracker_coalesce_strip (5, xd->title, pd.title, ed->document_name, xd->title2, xd->pdf_title);
345 md.copyright = tracker_coalesce_strip (3, xd->rights, pd.copyright, ed->copyright);
346 md.license = tracker_coalesce_strip (2, xd->license, pd.disclaimer);
347 md.description = tracker_coalesce_strip (3, xd->description, pd.description, ed->description);
348 md.date = tracker_coalesce_strip (5, xd->date, xd->time_original, pd.creation_time, ed->time, ed->time_original);
349 md.comment = tracker_coalesce_strip (2, pd.comment, ed->user_comment);
350 md.artist = tracker_coalesce_strip (3, xd->artist, ed->artist, xd->contributor);
351 md.orientation = tracker_coalesce_strip (2, xd->orientation, ed->orientation);
352 md.exposure_time = tracker_coalesce_strip (2, xd->exposure_time, ed->exposure_time);
353 md.iso_speed_ratings = tracker_coalesce_strip (2, xd->iso_speed_ratings, ed->iso_speed_ratings);
354 md.fnumber = tracker_coalesce_strip (2, xd->fnumber, ed->fnumber);
355 md.flash = tracker_coalesce_strip (2, xd->flash, ed->flash);
356 md.focal_length = tracker_coalesce_strip (2, xd->focal_length, ed->focal_length);
357 md.metering_mode = tracker_coalesce_strip (2, xd->metering_mode, ed->metering_mode);
358 md.white_balance = tracker_coalesce_strip (2, xd->white_balance, ed->white_balance);
359 md.make = tracker_coalesce_strip (2, xd->make, ed->make);
360 md.model = tracker_coalesce_strip (2, xd->model, ed->model);
361
362 keywords = g_ptr_array_new ();
363
364 if (md.comment) {
365 tracker_sparql_builder_predicate (metadata, "nie:comment");
366 tracker_sparql_builder_object_unvalidated (metadata, md.comment);
367 }
368
369 if (md.license) {
370 tracker_sparql_builder_predicate (metadata, "nie:license");
371 tracker_sparql_builder_object_unvalidated (metadata, md.license);
372 }
373
374 /* TODO: add ontology and store this ed->software */
375
376 if (md.creator) {
377 gchar *uri = tracker_sparql_escape_uri_printf ("urn:contact:%s", md.creator);
378
379 tracker_sparql_builder_insert_open (preupdate, NULL);
380 if (graph) {
381 tracker_sparql_builder_graph_open (preupdate, graph);
382 }
383
384 tracker_sparql_builder_subject_iri (preupdate, uri);
385 tracker_sparql_builder_predicate (preupdate, "a");
386 tracker_sparql_builder_object (preupdate, "nco:Contact");
387 tracker_sparql_builder_predicate (preupdate, "nco:fullname");
388 tracker_sparql_builder_object_unvalidated (preupdate, md.creator);
389
390 if (graph) {
391 tracker_sparql_builder_graph_close (preupdate);
392 }
393 tracker_sparql_builder_insert_close (preupdate);
394
395 tracker_sparql_builder_predicate (metadata, "nco:creator");
396 tracker_sparql_builder_object_iri (metadata, uri);
397 g_free (uri);
398 }
399
400 tracker_guarantee_date_from_file_mtime (metadata,
401 "nie:contentCreated",
402 md.date,
403 uri);
404
405 if (md.description) {
406 tracker_sparql_builder_predicate (metadata, "nie:description");
407 tracker_sparql_builder_object_unvalidated (metadata, md.description);
408 }
409
410 if (md.copyright) {
411 tracker_sparql_builder_predicate (metadata, "nie:copyright");
412 tracker_sparql_builder_object_unvalidated (metadata, md.copyright);
413 }
414
415 tracker_guarantee_title_from_file (metadata,
416 "nie:title",
417 md.title,
418 uri,
419 NULL);
420
421 if (md.make || md.model) {
422 gchar *equip_uri;
423
424 equip_uri = tracker_sparql_escape_uri_printf ("urn:equipment:%s:%s:",
425 md.make ? md.make : "",
426 md.model ? md.model : "");
427
428 tracker_sparql_builder_insert_open (preupdate, NULL);
429 if (graph) {
430 tracker_sparql_builder_graph_open (preupdate, graph);
431 }
432
433 tracker_sparql_builder_subject_iri (preupdate, equip_uri);
434 tracker_sparql_builder_predicate (preupdate, "a");
435 tracker_sparql_builder_object (preupdate, "nfo:Equipment");
436
437 if (md.make) {
438 tracker_sparql_builder_predicate (preupdate, "nfo:manufacturer");
439 tracker_sparql_builder_object_unvalidated (preupdate, md.make);
440 }
441 if (md.model) {
442 tracker_sparql_builder_predicate (preupdate, "nfo:model");
443 tracker_sparql_builder_object_unvalidated (preupdate, md.model);
444 }
445
446 if (graph) {
447 tracker_sparql_builder_graph_close (preupdate);
448 }
449 tracker_sparql_builder_insert_close (preupdate);
450
451 tracker_sparql_builder_predicate (metadata, "nfo:equipment");
452 tracker_sparql_builder_object_iri (metadata, equip_uri);
453 g_free (equip_uri);
454 }
455
456 if (md.artist) {
457 gchar *uri = tracker_sparql_escape_uri_printf ("urn:contact:%s", md.artist);
458
459 tracker_sparql_builder_insert_open (preupdate, NULL);
460 if (graph) {
461 tracker_sparql_builder_graph_open (preupdate, graph);
462 }
463
464 tracker_sparql_builder_subject_iri (preupdate, uri);
465 tracker_sparql_builder_predicate (preupdate, "a");
466 tracker_sparql_builder_object (preupdate, "nco:Contact");
467 tracker_sparql_builder_predicate (preupdate, "nco:fullname");
468 tracker_sparql_builder_object_unvalidated (preupdate, md.artist);
469
470 if (graph) {
471 tracker_sparql_builder_graph_close (preupdate);
472 }
473 tracker_sparql_builder_insert_close (preupdate);
474
475 tracker_sparql_builder_predicate (metadata, "nco:contributor");
476 tracker_sparql_builder_object_iri (metadata, uri);
477 g_free (uri);
478 }
479
480 if (md.orientation) {
481 tracker_sparql_builder_predicate (metadata, "nfo:orientation");
482 tracker_sparql_builder_object_unvalidated (metadata, md.orientation);
483 }
484
485 if (md.exposure_time) {
486 tracker_sparql_builder_predicate (metadata, "nmm:exposureTime");
487 tracker_sparql_builder_object_unvalidated (metadata, md.exposure_time);
488 }
489
490 if (md.iso_speed_ratings) {
491 tracker_sparql_builder_predicate (metadata, "nmm:isoSpeed");
492 tracker_sparql_builder_object_unvalidated (metadata, md.iso_speed_ratings);
493 }
494
495 if (md.white_balance) {
496 tracker_sparql_builder_predicate (metadata, "nmm:whiteBalance");
497 tracker_sparql_builder_object_unvalidated (metadata, md.white_balance);
498 }
499
500 if (md.fnumber) {
501 tracker_sparql_builder_predicate (metadata, "nmm:fnumber");
502 tracker_sparql_builder_object_unvalidated (metadata, md.fnumber);
503 }
504
505 if (md.flash) {
506 tracker_sparql_builder_predicate (metadata, "nmm:flash");
507 tracker_sparql_builder_object_unvalidated (metadata, md.flash);
508 }
509
510 if (md.focal_length) {
511 tracker_sparql_builder_predicate (metadata, "nmm:focalLength");
512 tracker_sparql_builder_object_unvalidated (metadata, md.focal_length);
513 }
514
515 if (md.metering_mode) {
516 tracker_sparql_builder_predicate (metadata, "nmm:meteringMode");
517 tracker_sparql_builder_object_unvalidated (metadata, md.metering_mode);
518 }
519
520
521 if (xd->keywords) {
522 tracker_keywords_parse (keywords, xd->keywords);
523 }
524
525 if (xd->pdf_keywords) {
526 tracker_keywords_parse (keywords, xd->pdf_keywords);
527 }
528
529 if (xd->rating) {
530 tracker_sparql_builder_predicate (metadata, "nao:numericRating");
531 tracker_sparql_builder_object_unvalidated (metadata, xd->rating);
532 }
533
534 if (xd->subject) {
535 tracker_keywords_parse (keywords, xd->subject);
536 }
537
538 if (xd->publisher) {
539 gchar *uri = tracker_sparql_escape_uri_printf ("urn:contact:%s", xd->publisher);
540
541 tracker_sparql_builder_insert_open (preupdate, NULL);
542 if (graph) {
543 tracker_sparql_builder_graph_open (preupdate, graph);
544 }
545
546 tracker_sparql_builder_subject_iri (preupdate, uri);
547 tracker_sparql_builder_predicate (preupdate, "a");
548 tracker_sparql_builder_object (preupdate, "nco:Contact");
549 tracker_sparql_builder_predicate (preupdate, "nco:fullname");
550 tracker_sparql_builder_object_unvalidated (preupdate, xd->publisher);
551
552 if (graph) {
553 tracker_sparql_builder_graph_close (preupdate);
554 }
555 tracker_sparql_builder_insert_close (preupdate);
556
557 tracker_sparql_builder_predicate (metadata, "nco:creator");
558 tracker_sparql_builder_object_iri (metadata, uri);
559 g_free (uri);
560 }
561
562 if (xd->type) {
563 tracker_sparql_builder_predicate (metadata, "dc:type");
564 tracker_sparql_builder_object_unvalidated (metadata, xd->type);
565 }
566
567 if (xd->format) {
568 tracker_sparql_builder_predicate (metadata, "dc:format");
569 tracker_sparql_builder_object_unvalidated (metadata, xd->format);
570 }
571
572 if (xd->identifier) {
573 tracker_sparql_builder_predicate (metadata, "dc:identifier");
574 tracker_sparql_builder_object_unvalidated (metadata, xd->identifier);
575 }
576
577 if (xd->source) {
578 tracker_sparql_builder_predicate (metadata, "dc:source");
579 tracker_sparql_builder_object_unvalidated (metadata, xd->source);
580 }
581
582 if (xd->language) {
583 tracker_sparql_builder_predicate (metadata, "dc:language");
584 tracker_sparql_builder_object_unvalidated (metadata, xd->language);
585 }
586
587 if (xd->relation) {
588 tracker_sparql_builder_predicate (metadata, "dc:relation");
589 tracker_sparql_builder_object_unvalidated (metadata, xd->relation);
590 }
591
592 if (xd->coverage) {
593 tracker_sparql_builder_predicate (metadata, "dc:coverage");
594 tracker_sparql_builder_object_unvalidated (metadata, xd->coverage);
595 }
596
597 if (xd->address || xd->state || xd->country || xd->city ||
598 xd->gps_altitude || xd->gps_latitude || xd-> gps_longitude) {
599
600 tracker_sparql_builder_predicate (metadata, "slo:location");
601
602 tracker_sparql_builder_object_blank_open (metadata); /* GeoLocation */
603 tracker_sparql_builder_predicate (metadata, "a");
604 tracker_sparql_builder_object (metadata, "slo:GeoLocation");
605
606 if (xd->address || xd->state || xd->country || xd->city) {
607 gchar *addruri;
608
609 addruri = tracker_sparql_get_uuid_urn ();
610
611 tracker_sparql_builder_predicate (metadata, "slo:postalAddress");
612 tracker_sparql_builder_object_iri (metadata, addruri);
613
614 tracker_sparql_builder_insert_open (preupdate, NULL);
615 if (graph) {
616 tracker_sparql_builder_graph_open (preupdate, graph);
617 }
618
619 tracker_sparql_builder_subject_iri (preupdate, addruri);
620
621 g_free (addruri);
622
623 tracker_sparql_builder_predicate (preupdate, "a");
624 tracker_sparql_builder_object (preupdate, "nco:PostalAddress");
625
626 if (xd->address) {
627 tracker_sparql_builder_predicate (preupdate, "nco:streetAddress");
628 tracker_sparql_builder_object_unvalidated (preupdate, xd->address);
629 }
630
631 if (xd->state) {
632 tracker_sparql_builder_predicate (preupdate, "nco:region");
633 tracker_sparql_builder_object_unvalidated (preupdate, xd->state);
634 }
635
636 if (xd->city) {
637 tracker_sparql_builder_predicate (preupdate, "nco:locality");
638 tracker_sparql_builder_object_unvalidated (preupdate, xd->city);
639 }
640
641 if (xd->country) {
642 tracker_sparql_builder_predicate (preupdate, "nco:country");
643 tracker_sparql_builder_object_unvalidated (preupdate, xd->country);
644 }
645
646 if (graph) {
647 tracker_sparql_builder_graph_close (preupdate);
648 }
649 tracker_sparql_builder_insert_close (preupdate);
650 }
651
652 if (xd->gps_altitude) {
653 tracker_sparql_builder_predicate (metadata, "slo:altitude");
654 tracker_sparql_builder_object_unvalidated (metadata, xd->gps_altitude);
655 }
656
657 if (xd->gps_latitude) {
658 tracker_sparql_builder_predicate (metadata, "slo:latitude");
659 tracker_sparql_builder_object_unvalidated (metadata, xd->gps_latitude);
660 }
661
662 if (xd->gps_longitude) {
663 tracker_sparql_builder_predicate (metadata, "slo:longitude");
664 tracker_sparql_builder_object_unvalidated (metadata, xd->gps_longitude);
665 }
666
667 tracker_sparql_builder_object_blank_close (metadata); /* GeoLocation */
668 }
669
670 if (xd->gps_direction) {
671 tracker_sparql_builder_predicate (metadata, "nfo:heading");
672 tracker_sparql_builder_object_unvalidated (metadata, xd->gps_direction);
673 }
674
675 if (ed->x_resolution) {
676 gdouble value;
677
678 value = ed->resolution_unit != 3 ? g_strtod (ed->x_resolution, NULL) : g_strtod (ed->x_resolution, NULL) * CM_TO_INCH;
679 tracker_sparql_builder_predicate (metadata, "nfo:horizontalResolution");
680 tracker_sparql_builder_object_double (metadata, value);
681 }
682
683 if (ed->y_resolution) {
684 gdouble value;
685
686 value = ed->resolution_unit != 3 ? g_strtod (ed->y_resolution, NULL) : g_strtod (ed->y_resolution, NULL) * CM_TO_INCH;
687 tracker_sparql_builder_predicate (metadata, "nfo:verticalResolution");
688 tracker_sparql_builder_object_double (metadata, value);
689 }
690
691 if (xd->regions) {
692 tracker_xmp_apply_regions (preupdate, metadata, graph, xd);
693 }
694
695 for (i = 0; i < keywords->len; i++) {
696 gchar *p, *escaped, *var;
697
698 p = g_ptr_array_index (keywords, i);
699 escaped = tracker_sparql_escape_string (p);
700 var = g_strdup_printf ("tag%d", i + 1);
701
702 /* ensure tag with specified label exists */
703 tracker_sparql_builder_append (preupdate, "INSERT { ");
704
705 if (graph) {
706 tracker_sparql_builder_append (preupdate, "GRAPH <");
707 tracker_sparql_builder_append (preupdate, graph);
708 tracker_sparql_builder_append (preupdate, "> { ");
709 }
710
711 tracker_sparql_builder_append (preupdate,
712 "_:tag a nao:Tag ; nao:prefLabel \"");
713 tracker_sparql_builder_append (preupdate, escaped);
714 tracker_sparql_builder_append (preupdate, "\"");
715
716 if (graph) {
717 tracker_sparql_builder_append (preupdate, " } ");
718 }
719
720 tracker_sparql_builder_append (preupdate, " }\n");
721 tracker_sparql_builder_append (preupdate,
722 "WHERE { FILTER (NOT EXISTS { "
723 "?tag a nao:Tag ; nao:prefLabel \"");
724 tracker_sparql_builder_append (preupdate, escaped);
725 tracker_sparql_builder_append (preupdate,
726 "\" }) }\n");
727
728 /* associate file with tag */
729 tracker_sparql_builder_predicate (metadata, "nao:hasTag");
730 tracker_sparql_builder_object_variable (metadata, var);
731
732 g_string_append_printf (where, "?%s a nao:Tag ; nao:prefLabel \"%s\" .\n", var, escaped);
733
734 g_free (var);
735 g_free (escaped);
736 g_free (p);
737 }
738 g_ptr_array_free (keywords, TRUE);
739
740 tracker_exif_free (ed);
741 tracker_xmp_free (xd);
742 g_free (pd.creation_time);
743 }
744
745 static gboolean
746 guess_dlna_profile (gint depth,
747 gint width,
748 gint height,
749 const gchar **dlna_profile,
750 const gchar **dlna_mimetype)
751 {
752 const gchar *profile = NULL;
753
754 if (dlna_profile) {
755 *dlna_profile = NULL;
756 }
757
758 if (dlna_mimetype) {
759 *dlna_mimetype = NULL;
760 }
761
762 profile = "PNG_LRG";
763
764 if (profile) {
765 if (dlna_profile) {
766 *dlna_profile = profile;
767 }
768
769 if (dlna_mimetype) {
770 *dlna_mimetype = "image/png";
771 }
772
773 return TRUE;
774 }
775
776 return FALSE;
777 }
778
779 G_MODULE_EXPORT gboolean
780 tracker_extract_get_metadata (TrackerExtractInfo *info)
781 {
782 goffset size;
783 FILE *f;
784 png_structp png_ptr;
785 png_infop info_ptr;
786 png_infop end_ptr;
787 png_bytepp row_pointers;
788 guint row;
789 png_uint_32 width, height;
790 gint bit_depth, color_type;
791 gint interlace_type, compression_type, filter_type;
792 const gchar *dlna_profile, *dlna_mimetype, *graph;
793 TrackerSparqlBuilder *preupdate, *metadata;
794 gchar *filename, *uri;
795 GString *where;
796 GFile *file;
797
798 file = tracker_extract_info_get_file (info);
799 filename = g_file_get_path (file);
800 size = tracker_file_get_size (filename);
801
802 preupdate = tracker_extract_info_get_preupdate_builder (info);
803 metadata = tracker_extract_info_get_metadata_builder (info);
804 graph = tracker_extract_info_get_graph (info);
805
806 if (size < 64) {
807 return FALSE;
808 }
809
810 f = tracker_file_open (filename);
811 g_free (filename);
812
813 if (!f) {
814 return FALSE;
815 }
816
817 png_ptr = png_create_read_struct (PNG_LIBPNG_VER_STRING,
818 NULL,
819 NULL,
820 NULL);
821 if (!png_ptr) {
822 tracker_file_close (f, FALSE);
823 return FALSE;
824 }
825
826 info_ptr = png_create_info_struct (png_ptr);
827 if (!info_ptr) {
828 png_destroy_read_struct (&png_ptr, &info_ptr, NULL);
829 tracker_file_close (f, FALSE);
830 return FALSE;
831 }
832
833 end_ptr = png_create_info_struct (png_ptr);
834 if (!end_ptr) {
835 png_destroy_read_struct (&png_ptr, &info_ptr, NULL);
836 tracker_file_close (f, FALSE);
837 return FALSE;
838 }
839
840 if (setjmp (png_jmpbuf (png_ptr))) {
841 png_destroy_read_struct (&png_ptr, &info_ptr, &end_ptr);
842 tracker_file_close (f, FALSE);
843 return FALSE;
844 }
845
846 png_init_io (png_ptr, f);
847 png_read_info (png_ptr, info_ptr);
848
849 if (!png_get_IHDR (png_ptr,
850 info_ptr,
851 &width,
852 &height,
853 &bit_depth,
854 &color_type,
855 &interlace_type,
856 &compression_type,
857 &filter_type)) {
858 png_destroy_read_struct (&png_ptr, &info_ptr, &end_ptr);
859 tracker_file_close (f, FALSE);
860 return FALSE;
861 }
862
863 /* Read the image. FIXME We should be able to skip this step and
864 * just get the info from the end. This causes some errors atm.
865 */
866 row_pointers = g_new0 (png_bytep, height);
867
868 for (row = 0; row < height; row++) {
869 row_pointers[row] = png_malloc (png_ptr,
870 png_get_rowbytes (png_ptr,info_ptr));
871 }
872
873 png_read_image (png_ptr, row_pointers);
874
875 for (row = 0; row < height; row++) {
876 png_free (png_ptr, row_pointers[row]);
877 }
878
879 g_free (row_pointers);
880
881 png_read_end (png_ptr, end_ptr);
882
883 tracker_sparql_builder_predicate (metadata, "a");
884 tracker_sparql_builder_object (metadata, "nfo:Image");
885 tracker_sparql_builder_object (metadata, "nmm:Photo");
886
887 uri = g_file_get_uri (file);
888 where = g_string_new ("");
889
890 read_metadata (preupdate, metadata, where, png_ptr, info_ptr, end_ptr, uri, graph);
891 tracker_extract_info_set_where_clause (info, where->str);
892 g_string_free (where, TRUE);
893 g_free (uri);
894
895 tracker_sparql_builder_predicate (metadata, "nfo:width");
896 tracker_sparql_builder_object_int64 (metadata, width);
897
898 tracker_sparql_builder_predicate (metadata, "nfo:height");
899 tracker_sparql_builder_object_int64 (metadata, height);
900
901 if (guess_dlna_profile (bit_depth, width, height, &dlna_profile, &dlna_mimetype)) {
902 tracker_sparql_builder_predicate (metadata, "nmm:dlnaProfile");
903 tracker_sparql_builder_object_string (metadata, dlna_profile);
904 tracker_sparql_builder_predicate (metadata, "nmm:dlnaMime");
905 tracker_sparql_builder_object_string (metadata, dlna_mimetype);
906 }
907
908 png_destroy_read_struct (&png_ptr, &info_ptr, &end_ptr);
909 tracker_file_close (f, FALSE);
910
911 return TRUE;
912 }