Fix problem with SubIFD in Exif.
[lms] / lightmediascanner / src / plugins / jpeg / jpeg.c
1 /**
2  * Copyright (C) 2007 by INdT
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program 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
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17  *
18  * @author Gustavo Sverzut Barbieri <gustavo.barbieri@openbossa.org>
19  */
20
21 /**
22  * @brief
23  *
24  * Reads EXIF tags from images.
25  *
26  * @todo: get GPS data.
27  * @todo: check if worth using mmap().
28  */
29
30 #ifdef HAVE_CONFIG_H
31 #include "config.h"
32 #endif
33
34 #define _XOPEN_SOURCE 600
35 #include <lightmediascanner_plugin.h>
36 #include <lightmediascanner_utils.h>
37 #include <lightmediascanner_db.h>
38 #include <sys/types.h>
39 #include <sys/stat.h>
40 #include <fcntl.h>
41 #include <unistd.h>
42 #include <time.h>
43 #include <stdlib.h>
44 #include <stdio.h>
45 #include <string.h>
46 #include <strings.h>
47
48 enum {
49     JPEG_MARKER_SOI = 0xd8,
50     JPEG_MARKER_DQT = 0xdb,
51     JPEG_MARKER_JFIF = 0xe0,
52     JPEG_MARKER_EXIF = 0xe1,
53     JPEG_MARKER_COMM = 0xfe,
54     JPEG_MARKER_SOF0 = 0xc0,
55     JPEG_MARKER_SOF1 = 0xc1,
56     JPEG_MARKER_SOF2 = 0xc2,
57     JPEG_MARKER_SOF9 = 0xc9,
58     JPEG_MARKER_SOF10 = 0xca,
59     JPEG_MARKER_SOS = 0xda
60 };
61
62 /**
63  * Process SOF JPEG, this contains width and height.
64  */
65 static int
66 _jpeg_sof_process(int fd, unsigned short *width, unsigned short *height)
67 {
68     unsigned char buf[6];
69
70     if (read(fd, buf, 6) != 6) {
71         perror("could not read() SOF data");
72         return -1;
73     }
74
75     *height = (buf[1] << 8) | buf[2];
76     *width = (buf[3] << 8) | buf[4];
77
78     return 0;
79 }
80
81 /**
82  * Process COM JPEG, this contains user comment.
83  */
84 static int
85 _jpeg_com_process(int fd, int len, struct lms_string_size *comment)
86 {
87     if (len < 1) {
88         comment->str = NULL;
89         comment->len = 0;
90         return 0;
91     }
92
93     comment->str = malloc(len + 1);
94     if (!comment->str) {
95         perror("malloc");
96         return -1;
97     }
98     if (read(fd, comment->str, len) != len) {
99         perror("read");
100         free(comment->str);
101         comment->str = NULL;
102         comment->len = 0;
103         return -2;
104     }
105     if (comment->str[len - 1] == '\0')
106         len--;
107     else
108         comment->str[len] = '\0';
109     comment->len = len;
110
111     lms_strstrip(comment->str, &comment->len);
112     if (comment->len == 0) {
113         free(comment->str);
114         comment->str = NULL;
115     }
116
117     return 0;
118 }
119
120 /**
121  * Walk JPEG markers in order to get useful information.
122  */
123 static int
124 _jpeg_info_get(int fd, int len, struct lms_image_info *info)
125 {
126     unsigned char buf[4];
127     int found;
128     off_t offset;
129
130     found = info->title.str ? 1 : 0;
131     offset = lseek(fd, len - 2, SEEK_CUR);
132     len = 0;
133     while (found < 2) {
134         offset = lseek(fd, offset + len, SEEK_SET);
135         if (offset == -1) {
136             perror("lseek");
137             return -1;
138         }
139
140         if (read(fd, buf, 4) != 4) {
141             perror("read");
142             return -2;
143         }
144
145         len = ((buf[2] << 8) | buf[3]) - 2;
146
147         if (buf[0] != 0xff) {
148             fprintf(stderr, "ERROR: expected 0xff marker, got %#x\n", buf[0]);
149             return -3;
150         }
151
152         if (buf[1] == JPEG_MARKER_SOF0 ||
153             buf[1] == JPEG_MARKER_SOF1 ||
154             buf[1] == JPEG_MARKER_SOF2 ||
155             buf[1] == JPEG_MARKER_SOF9 ||
156             buf[1] == JPEG_MARKER_SOF10) {
157             if (_jpeg_sof_process(fd, &info->width, &info->height) != 0)
158                 return -4;
159             found++;
160         } else if (buf[1] == JPEG_MARKER_COMM && !info->title.str) {
161             if (_jpeg_com_process(fd, len, &info->title) != 0)
162                 return -5;
163             found++;
164         } else if (buf[1] == JPEG_MARKER_SOS)
165             break;
166
167         len += 4; /* add read size */
168     }
169
170     return 0;
171 }
172
173 /**
174  * Read JPEG file start (0xffd8 marker) and return the next
175  * marker type and its length.
176  */
177 static int
178 _jpeg_data_get(int fd, int *type, int *len)
179 {
180     unsigned char buf[6];
181
182     if (lseek(fd, 0, SEEK_SET) != 0) {
183         perror("lseek");
184         return -1;
185     }
186
187     if (read(fd, buf, 6) != 6) {
188         perror("read");
189         return -2;
190     }
191
192     if (buf[0] != 0xff || buf[1] != JPEG_MARKER_SOI || buf[2] != 0xff) {
193         fprintf(stderr, "ERROR: not JPEG file (magic=%#x %#x %#x)\n",
194                 buf[0], buf[1], buf[2]);
195         return -3;
196     }
197
198     *type = buf[3];
199     *len = (buf[4] << 8) | buf[5];
200
201     return 0;
202 }
203
204 #define LE_4BYTE(a) ((a)[0] | ((a)[1] << 8) | ((a)[2] << 16) | ((a)[3] << 24))
205 #define BE_4BYTE(a) (((a)[0] << 24) | ((a)[1] << 16) | ((a)[2] << 8) | (a)[3])
206
207 #define LE_2BYTE(a) ((a)[0] | ((a)[1] << 8))
208 #define BE_2BYTE(a) (((a)[0] << 8) | (a)[1])
209
210 #define E_2BTYE(little_endian, a) ((little_endian) ? LE_2BYTE(a) : BE_2BYTE(a))
211 #define E_4BTYE(little_endian, a) ((little_endian) ? LE_4BYTE(a) : BE_4BYTE(a))
212
213 enum {
214     EXIF_TYPE_BYTE = 1, /* 8 bit unsigned */
215     EXIF_TYPE_ASCII = 2, /* 8 bit byte with 7-bit ASCII code, NULL terminated */
216     EXIF_TYPE_SHORT = 3, /* 2-byte unsigned integer */
217     EXIF_TYPE_LONG = 4, /* 4-byte unsigned integer */
218     EXIF_TYPE_RATIONAL = 5, /* 2 4-byte unsigned integer, 1st = numerator */
219     EXIF_TYPE_UNDEFINED = 7, /* 8-bit byte */
220     EXIF_TYPE_SLONG = 9, /* 4-byte signed integer (2'complement) */
221     EXIF_TYPE_SRATIONAL = 10 /* 2 4-byte signed integer, 1st = numerator */
222 };
223
224 enum {
225     EXIF_TAG_ORIENTATION = 0x0112,
226     EXIF_TAG_ARTIST = 0x013b,
227     EXIF_TAG_USER_COMMENT = 0x9286,
228     EXIF_TAG_IMAGE_DESCRIPTION = 0x010e,
229     EXIF_TAG_DATE_TIME = 0x0132,
230     EXIF_TAG_DATE_TIME_ORIGINAL = 0x9003,
231     EXIF_TAG_DATE_TIME_DIGITIZED = 0x9004,
232     EXIF_TAG_EXIF_IFD_POINTER = 0x8769
233 };
234
235
236 struct exif_ifd {
237     unsigned short tag;
238     unsigned short type;
239     unsigned int count;
240     unsigned int offset;
241 };
242
243 /**
244  * Read IFD from stream.
245  */
246 static int
247 _exif_ifd_get(int fd, int little_endian, struct exif_ifd *ifd)
248 {
249     unsigned char buf[12];
250
251     if (read(fd, buf, 12) != 12) {
252         perror("read");
253         return -1;
254     }
255
256     if (little_endian) {
257         ifd->tag = LE_2BYTE(buf);
258         ifd->type = LE_2BYTE(buf + 2);
259         ifd->count = LE_4BYTE(buf + 4);
260         ifd->offset = LE_4BYTE(buf + 8);
261     } else {
262         ifd->tag = BE_2BYTE(buf);
263         ifd->type = BE_2BYTE(buf + 2);
264         ifd->count = BE_4BYTE(buf + 4);
265         ifd->offset = BE_4BYTE(buf + 8);
266     }
267     return 0;
268 }
269
270 /**
271  * Get non-exif data based on Exif tag offset.
272  *
273  * This will setup the file description position and call _jpeg_info_get().
274  */
275 static int
276 _exif_extra_get(int fd, int abs_offset, int len, struct lms_image_info *info)
277 {
278     if (lseek(fd, abs_offset, SEEK_SET) == -1) {
279         perror("lseek");
280         return -1;
281     }
282
283     if (_jpeg_info_get(fd, len, info) != 0) {
284         fprintf(stderr, "ERROR: could not get image size.\n");
285         return -2;
286     }
287     return 0;
288 }
289
290 static int
291 _exif_text_encoding_get(int fd, unsigned int count, int offset, struct lms_string_size *s)
292 {
293     if (count <= 8)
294         return -1;
295
296     count -= 8; /* XXX don't just ignore character code, handle it. */
297     offset += 8;
298
299     if (lseek(fd, offset, SEEK_SET) == -1) {
300         perror("lseek");
301         return -2;
302     }
303
304     s->str = malloc(count + 1);
305
306     if (read(fd, s->str, count) != count) {
307         perror("read");
308         free(s->str);
309         s->str = NULL;
310         s->len = 0;
311         return -3;
312     }
313     s->str[count] = '\0';
314     s->len = count;
315
316     lms_strstrip(s->str, &s->len);
317     if (s->len == 0) {
318         free(s->str);
319         s->str = NULL;
320     }
321
322     return 0;
323 }
324
325 static int
326 _exif_text_ascii_get(int fd, unsigned int count, int offset, struct lms_string_size *s)
327 {
328     if (count < 1) {
329         s->str = NULL;
330         s->len = 0;
331         return 0;
332     }
333
334     if (lseek(fd, offset, SEEK_SET) == -1) {
335         perror("lseek");
336         return -1;
337     }
338
339     s->str = malloc(count);
340
341     if (read(fd, s->str, count) != count) {
342         perror("read");
343         free(s->str);
344         s->str = NULL;
345         s->len = 0;
346         return -1;
347     }
348     s->str[count - 1] = '\0';
349     s->len = count - 1;
350
351     lms_strstrip(s->str, &s->len);
352     if (s->len == 0) {
353         free(s->str);
354         s->str = NULL;
355     }
356
357     return 0;
358 }
359
360 static unsigned int
361 _exif_datetime_get(int fd, int offset)
362 {
363     char buf[20];
364     struct tm tm = {0};
365
366     if (lseek(fd, offset, SEEK_SET) == -1) {
367         perror("lseek");
368         return 0;
369     }
370
371     if (read(fd, buf, 20) != 20) {
372         perror("read");
373         return 0;
374     }
375
376     buf[19] = '\0';
377     if (strptime(buf, "%Y:%m:%d %H:%M:%S", &tm)) {
378         return mktime(&tm);
379     }
380     return 0;
381 }
382
383 static int _exif_private_ifd_get(int fd, int base_offset, int offset, int little_endian, struct lms_image_info *info);
384
385 /**
386  * Process IFD contents.
387  */
388 static int
389 _exif_ifd_process(int fd, int count, int ifd_offset, int tiff_base, int little_endian, struct lms_image_info *info)
390 {
391     int i, torig, tdig, tlast;
392
393     torig = tdig = tlast = 0;
394
395     for (i = 0; i < count; i++) {
396         struct exif_ifd ifd;
397
398         lseek(fd, tiff_base + ifd_offset + i * 12, SEEK_SET);
399         if (_exif_ifd_get(fd, little_endian, &ifd) != 0) {
400             fprintf(stderr, "ERROR: could not read Exif IFD.\n");
401             return -8;
402         }
403
404         switch (ifd.tag) {
405         case EXIF_TAG_ORIENTATION:
406             info->orientation = ifd.offset >> 16;
407             break;
408         case EXIF_TAG_ARTIST:
409             if (!info->artist.str)
410                 _exif_text_ascii_get(fd, ifd.count, tiff_base + ifd.offset,
411                                      &info->artist);
412             break;
413         case EXIF_TAG_USER_COMMENT:
414             if (!info->title.str)
415                 _exif_text_encoding_get(fd, ifd.count, tiff_base + ifd.offset,
416                                         &info->title);
417             break;
418         case EXIF_TAG_IMAGE_DESCRIPTION:
419             if (!info->title.str)
420                 _exif_text_ascii_get(fd, ifd.count, tiff_base + ifd.offset,
421                                      &info->title);
422             break;
423         case EXIF_TAG_DATE_TIME:
424             if (torig == 0 && info->date == 0)
425                 tlast = _exif_datetime_get(fd, tiff_base + ifd.offset);
426             break;
427         case EXIF_TAG_DATE_TIME_ORIGINAL:
428             if (torig == 0 && info->date == 0)
429                 torig = _exif_datetime_get(fd, tiff_base + ifd.offset);
430             break;
431         case EXIF_TAG_DATE_TIME_DIGITIZED:
432             if (torig == 0 && info->date == 0)
433                 tdig = _exif_datetime_get(fd, tiff_base + ifd.offset);
434             break;
435         case EXIF_TAG_EXIF_IFD_POINTER:
436             if (ifd.count == 1 && ifd.type == EXIF_TYPE_LONG)
437                 _exif_private_ifd_get(fd, ifd.offset, tiff_base,
438                                       little_endian, info);
439             break;
440         default:
441             /* ignore */
442             break;
443         }
444     }
445
446     if (info->date == 0) {
447         if (torig)
448             info->date = torig;
449         else if (tdig)
450             info->date = tdig;
451         else
452             info->date = tlast;
453     }
454
455     return 0;
456 }
457
458 /**
459  * Process Exif IFD (Exif Private Tag), with more specific info.
460  */
461 static int
462 _exif_private_ifd_get(int fd, int ifd_offset, int tiff_base, int little_endian, struct lms_image_info *info)
463 {
464     char buf[2];
465     unsigned int count;
466
467     if (lseek(fd, tiff_base + ifd_offset, SEEK_SET) == -1) {
468         perror("lseek");
469         return -1;
470     }
471
472     if (read(fd, buf, 2) != 2) {
473         perror("read");
474         return -1;
475     }
476
477     count = E_2BTYE(little_endian, buf);
478     return _exif_ifd_process(fd, count, ifd_offset + 2, tiff_base,
479                              little_endian, info);
480 }
481
482 /**
483  * Process file as it being Exif, will extract Exif as well as other
484  * JPEG markers (comment, size).
485  */
486 static int
487 _exif_data_get(int fd, int len, struct lms_image_info *info)
488 {
489     const unsigned char exif_hdr[6] = "Exif\0";
490     unsigned char buf[8];
491     unsigned int little_endian, offset, count;
492     off_t abs_offset, tiff_base;
493
494     abs_offset = lseek(fd, 0, SEEK_CUR);
495     if (abs_offset == -1) {
496         perror("lseek");
497         return -1;
498     }
499
500     if (read(fd, buf, 6) != 6) {
501         perror("read");
502         return -2;
503     }
504
505     memset(info, 0, sizeof(*info));
506     info->orientation = 1;
507
508     if (memcmp(buf, exif_hdr, 6) != 0)
509         return _exif_extra_get(fd, abs_offset, len, info);
510
511     if (read(fd, buf, 8) != 8) {
512         perror("read");
513         return -4;
514     }
515
516     if (buf[0] == 'I' && buf[1] == 'I') {
517         little_endian = 1;
518         offset = LE_4BYTE(buf + 4);
519     } else if (buf[0] == 'M' && buf[1] == 'M') {
520         little_endian = 0;
521         offset = BE_4BYTE(buf + 4);
522     } else {
523         fprintf(stderr, "ERROR: undefined byte sex \"%2.2s\".\n", buf);
524         return -5;
525     }
526
527     offset -= 8;
528     if (offset > 0 && lseek(fd, offset, SEEK_CUR) == -1) {
529         perror("lseek");
530         return -6;
531     }
532
533     tiff_base = abs_offset + 6; /* offsets are relative to TIFF base */
534
535     if (read(fd, buf, 2) != 2) {
536         perror("read");
537         return -7;
538     }
539     count = E_2BTYE(little_endian, buf);
540
541     _exif_ifd_process(fd, count, 8 + 2, tiff_base,
542                       little_endian, info);
543
544     return _exif_extra_get(fd, abs_offset, len, info);
545 }
546
547 /**
548  * Process file as it being JFIF
549  */
550 static int
551 _jfif_data_get(int fd, int len, struct lms_image_info *info)
552 {
553     unsigned char buf[4];
554
555     memset(info, 0, sizeof(*info));
556     info->orientation = 1;
557
558     /* JFIF provides no useful information, try to find out Exif */
559     if (lseek(fd, len - 2, SEEK_CUR) == -1) {
560         perror("lseek");
561         return -1;
562     }
563
564     if (read(fd, buf, 4) != 4) {
565         perror("read");
566         return -2;
567     }
568
569     len = ((buf[2] << 8) | buf[3]);
570     if (buf[0] != 0xff) {
571         fprintf(stderr, "ERROR: expected 0xff marker, got %#x\n", buf[0]);
572         return -3;
573     }
574
575     if (buf[1] == JPEG_MARKER_EXIF)
576         return _exif_data_get(fd, len, info);
577     else
578         return _jpeg_info_get(fd, len, info);
579 }
580
581 static const char _name[] = "jpeg";
582 static const struct lms_string_size _exts[] = {
583     LMS_STATIC_STRING_SIZE(".jpg"),
584     LMS_STATIC_STRING_SIZE(".jpeg"),
585     LMS_STATIC_STRING_SIZE(".jpe")
586 };
587
588 struct plugin {
589     struct lms_plugin plugin;
590     lms_db_image_t *img_db;
591 };
592
593 static void *
594 _match(struct plugin *p, const char *path, int len, int base)
595 {
596     int i;
597
598     i = lms_which_extension(path, len, _exts, LMS_ARRAY_SIZE(_exts));
599     if (i < 0)
600         return NULL;
601     else
602         return (void*)(i + 1);
603 }
604
605 static int
606 _parse(struct plugin *plugin, struct lms_context *ctxt, const struct lms_file_info *finfo, void *match)
607 {
608     struct lms_image_info info = {0};
609     int fd, type, len, r;
610
611     fd = open(finfo->path, O_RDONLY);
612     if (fd < 0) {
613         perror("open");
614         return -1;
615     }
616
617     if (_jpeg_data_get(fd, &type, &len) != 0) {
618         r = -2;
619         goto done;
620     }
621
622     if (type == JPEG_MARKER_EXIF) {
623         if (_exif_data_get(fd, len, &info) != 0) {
624             fprintf(stderr, "ERROR: could not get EXIF info (%s).\n",
625                     finfo->path);
626             r = -3;
627             goto done;
628         }
629     } else if (type == JPEG_MARKER_JFIF || type == JPEG_MARKER_DQT) {
630         if (_jfif_data_get(fd, len, &info) != 0) {
631             fprintf(stderr, "ERROR: could not get JPEG size (%s).\n",
632                     finfo->path);
633             r = -4;
634             goto done;
635         }
636     } else {
637         fprintf(stderr, "ERROR: unsupported JPEG marker %#x (%s)\n", type,
638                 finfo->path);
639         r = -6;
640         goto done;
641     }
642
643     if (info.date == 0)
644         info.date = finfo->mtime;
645
646     if (!info.title.str) {
647       int ext_idx;
648
649       ext_idx = ((int)match) - 1;
650       info.title.len = finfo->path_len - finfo->base - _exts[ext_idx].len;
651       info.title.str = malloc((info.title.len + 1) * sizeof(char));
652       memcpy(info.title.str, finfo->path + finfo->base, info.title.len);
653       info.title.str[info.title.len] = '\0';
654     }
655
656     if (info.title.str)
657       lms_charset_conv(ctxt->cs_conv, &info.title.str, &info.title.len);
658     if (info.artist.str)
659       lms_charset_conv(ctxt->cs_conv, &info.artist.str, &info.artist.len);
660
661     info.id = finfo->id;
662     r = lms_db_image_add(plugin->img_db, &info);
663
664   done:
665     if (info.title.str)
666         free(info.title.str);
667     if (info.artist.str)
668         free(info.artist.str);
669
670     posix_fadvise(fd, 0, 0, POSIX_FADV_DONTNEED);
671     close(fd);
672
673     return r;
674 }
675
676 static int
677 _setup(struct plugin *plugin, struct lms_context *ctxt)
678 {
679     plugin->img_db = lms_db_image_new(ctxt->db);
680     if (!plugin->img_db)
681         return -1;
682
683     return 0;
684 }
685
686 static int
687 _start(struct plugin *plugin, struct lms_context *ctxt)
688 {
689     return lms_db_image_start(plugin->img_db);
690 }
691
692 static int
693 _finish(struct plugin *plugin, struct lms_context *ctxt)
694 {
695     if (plugin->img_db)
696         return lms_db_image_free(plugin->img_db);
697
698     return 0;
699 }
700
701
702 static int
703 _close(struct plugin *plugin)
704 {
705     free(plugin);
706     return 0;
707 }
708
709 API struct lms_plugin *
710 lms_plugin_open(void)
711 {
712     struct plugin *plugin;
713
714     plugin = malloc(sizeof(*plugin));
715     plugin->plugin.name = _name;
716     plugin->plugin.match = (lms_plugin_match_fn_t)_match;
717     plugin->plugin.parse = (lms_plugin_parse_fn_t)_parse;
718     plugin->plugin.close = (lms_plugin_close_fn_t)_close;
719     plugin->plugin.setup = (lms_plugin_setup_fn_t)_setup;
720     plugin->plugin.start = (lms_plugin_start_fn_t)_start;
721     plugin->plugin.finish = (lms_plugin_finish_fn_t)_finish;
722
723     return (struct lms_plugin *)plugin;
724 }