Krolyxon
Commit 4fde8c8

Branches

Refs →

nsxivexif.c

141 lines · 3.0 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, 2) < 0)
77 goto abort;
78 if (btous(data, order) != JPEG_MARKER_SOI)
79 goto abort;
80 if (s_read(fd, file->name, data, 4) < 0)
81 goto abort;
82
83 if (btous(data, order) == JPEG_MARKER_APP0) {
84 len = btous(data + 2, order);
85 if (lseek(fd, len - 2, SEEK_CUR) == (off_t) -1)
86 goto abort;
87 if (s_read(fd, file->name, data, 4) < 0)
88 goto abort;
89 }
90 if (btous(data, order) != JPEG_MARKER_APP1)
91 goto abort;
92 len = btous(data + 2, order);
93 if (len < 8)
94 goto abort;
95
96 if (s_read(fd, file->name, data, 6) < 0)
97 goto abort;
98 if (btoui(data, order) != EXIF_HEAD)
99 goto abort;
100
101 len -= 8;
102 if (len < 12 || len > EXIF_MAX_LEN)
103 goto abort;
104 if (s_read(fd, file->name, data, len) < 0)
105 goto abort;
106
107 switch (btous(data, order)) {
108 case EXIF_BO_BIG_ENDIAN:
109 order = BO_BIG_ENDIAN;
110 break;
111 case EXIF_BO_LITTLE_ENDIAN:
112 order = BO_LITTLE_ENDIAN;
113 break;
114 default:
115 goto abort;
116 break;
117 }
118
119 if (btous(data + 2, order) != EXIF_TAG_MARK)
120 goto abort;
121 idx = btoui(data + 4, order);
122 if (idx > len - 2)
123 goto abort;
124
125 val = 0;
126 cnt = btous(data + idx, order);
127
128 for (idx += 2; cnt > 0 && idx < len - 12; cnt--, idx += 12) {
129 if (btous(data + idx, order) == EXIF_TAG_ORIENTATION) {
130 val = btous(data + idx + 8, order);
131 break;
132 }
133 }
134
135 close(fd);
136 return val;
137
138abort:
139 close(fd);
140 return -1;
141}