Krolyxon
Commit c6bfac1

Branches

Refs →

nsxivexif.c

134 lines · 2.8 KB · C

1/* Copyright 2012 Bert Muennich
2 *
3 * This file is part of sxiv.
4 *
5 * sxiv is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published
7 * by the Free Software Foundation; either version 2 of the License,
8 * or (at your option) any later version.
9 *
10 * sxiv 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
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with sxiv. If not, see <http://www.gnu.org/licenses/>.
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{
31 ssize_t ret;
32
33 ret = read(fd, buf, n);
34 if (ret < n) {
35 warn("unexpected end-of-file: %s", fn);
36 return -1;
37 } else {
38 return ret;
39 }
40}
41
42unsigned short btous(unsigned char *buf, byteorder_t order)
43{
44 if (buf == NULL)
45 return 0;
46 if (order == BO_BIG_ENDIAN)
47 return buf[0] << 8 | buf[1];
48 else
49 return buf[1] << 8 | buf[0];
50}
51
52unsigned int btoui(unsigned char *buf, byteorder_t order)
53{
54 if (buf == NULL)
55 return 0;
56 if (order == BO_BIG_ENDIAN)
57 return buf[0] << 24 | buf[1] << 16 | buf[2] << 8 | buf[3];
58 else
59 return buf[3] << 24 | buf[2] << 16 | buf[1] << 8 | buf[0];
60}
61
62int exif_orientation(const fileinfo_t *file)
63{
64 int fd;
65 unsigned char data[EXIF_MAX_LEN];
66 byteorder_t order = BO_BIG_ENDIAN;
67 unsigned int cnt, len, idx, val;
68
69 if (file == NULL || file->path == NULL)
70 return -1;
71
72 fd = open(file->path, O_RDONLY);
73 if (fd < 0)
74 return -1;
75
76 if (s_read(fd, file->name, data, 4) < 0)
77 goto abort;
78 if (btous(data, order) != JPEG_MARKER_SOI)
79 goto abort;
80 if (btous(data + 2, order) != JPEG_MARKER_APP1)
81 goto abort;
82
83 if (s_read(fd, file->name, data, 2) < 0)
84 goto abort;
85 len = btous(data, order);
86 if (len < 8)
87 goto abort;
88
89 if (s_read(fd, file->name, data, 6) < 0)
90 goto abort;
91 if (btoui(data, order) != EXIF_HEAD)
92 goto abort;
93
94 len -= 8;
95 if (len < 12 || len > EXIF_MAX_LEN)
96 goto abort;
97 if (s_read(fd, file->name, data, len) < 0)
98 goto abort;
99
100 switch (btous(data, order)) {
101 case EXIF_BO_BIG_ENDIAN:
102 order = BO_BIG_ENDIAN;
103 break;
104 case EXIF_BO_LITTLE_ENDIAN:
105 order = BO_LITTLE_ENDIAN;
106 break;
107 default:
108 goto abort;
109 break;
110 }
111
112 if (btous(data + 2, order) != EXIF_TAG_MARK)
113 goto abort;
114 idx = btoui(data + 4, order);
115 if (idx > len - 2)
116 goto abort;
117
118 val = 0;
119 cnt = btous(data + idx, order);
120
121 for (idx += 2; cnt > 0 && idx < len - 12; cnt--, idx += 12) {
122 if (btous(data + idx, order) == EXIF_TAG_ORIENTATION) {
123 val = btous(data + idx + 8, order);
124 break;
125 }
126 }
127
128 close(fd);
129 return val;
130
131abort:
132 close(fd);
133 return -1;
134}