Krolyxon
Commit 795beac

Branches

Refs →

nsxivexif.c

130 lines · 2.9 KB · C

1/* sxiv: exif.c
2 * Copyright (c) 2012 Bert Muennich <be.muennich at googlemail.com>
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License as published by the
6 * Free Software Foundation; either version 2 of the License, or (at your
7 * option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License along
15 * with this program; if not, write to the Free Software Foundation, Inc.,
16 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 */
18
19#define _POSIX_C_SOURCE 200112L
20
21#include <stdlib.h>
22#include <fcntl.h>
23#include <sys/stat.h>
24#include <unistd.h>
25
26#include "exif.h"
27#include "util.h"
28
29ssize_t s_read(int fd, const char *fn, void *buf, size_t n) {
30 ssize_t ret;
31
32 ret = read(fd, buf, n);
33 if (ret < n) {
34 warn("unexpected end-of-file: %s", fn);
35 return -1;
36 } else {
37 return ret;
38 }
39}
40
41unsigned short btous(unsigned char *buf, byteorder_t order) {
42 if (buf == NULL)
43 return 0;
44 if (order == BO_BIG_ENDIAN)
45 return buf[0] << 8 | buf[1];
46 else
47 return buf[1] << 8 | buf[0];
48}
49
50unsigned int btoui(unsigned char *buf, byteorder_t order) {
51 if (buf == NULL)
52 return 0;
53 if (order == BO_BIG_ENDIAN)
54 return buf[0] << 24 | buf[1] << 16 | buf[2] << 8 | buf[3];
55 else
56 return buf[3] << 24 | buf[2] << 16 | buf[1] << 8 | buf[0];
57}
58
59int exif_orientation(const fileinfo_t *file) {
60 int fd;
61 unsigned char data[EXIF_MAX_LEN];
62 byteorder_t order = BO_BIG_ENDIAN;
63 unsigned int cnt, len, idx, val;
64
65 if (file == NULL || file->path == NULL)
66 return -1;
67
68 fd = open(file->path, O_RDONLY);
69 if (fd < 0)
70 return -1;
71
72 if (s_read(fd, file->name, data, 4) < 0)
73 goto abort;
74 if (btous(data, order) != JPEG_MARKER_SOI)
75 goto abort;
76 if (btous(data + 2, order) != JPEG_MARKER_APP1)
77 goto abort;
78
79 if (s_read(fd, file->name, data, 2) < 0)
80 goto abort;
81 len = btous(data, order);
82 if (len < 8)
83 goto abort;
84
85 if (s_read(fd, file->name, data, 6) < 0)
86 goto abort;
87 if (btoui(data, order) != EXIF_HEAD)
88 goto abort;
89
90 len -= 8;
91 if (len < 12 || len > EXIF_MAX_LEN)
92 goto abort;
93 if (s_read(fd, file->name, data, len) < 0)
94 goto abort;
95
96 switch (btous(data, order)) {
97 case EXIF_BO_BIG_ENDIAN:
98 order = BO_BIG_ENDIAN;
99 break;
100 case EXIF_BO_LITTLE_ENDIAN:
101 order = BO_LITTLE_ENDIAN;
102 break;
103 default:
104 goto abort;
105 break;
106 }
107
108 if (btous(data + 2, order) != EXIF_TAG_MARK)
109 goto abort;
110 idx = btoui(data + 4, order);
111 if (idx > len - 2)
112 goto abort;
113
114 val = 0;
115 cnt = btous(data + idx, order);
116
117 for (idx += 2; cnt > 0 && idx < len - 12; cnt--, idx += 12) {
118 if (btous(data + idx, order) == EXIF_TAG_ORIENTATION) {
119 val = btous(data + idx + 8, order);
120 break;
121 }
122 }
123
124 close(fd);
125 return val;
126
127abort:
128 close(fd);
129 return -1;
130}