tracker-0.16.2/src/tracker-extract/tracker-extract-png.c

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;
Value stored to 'o' is never read
(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);
pointer targets in passing argument 1 of 'tracker_exif_new' differ in signedness
(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 }