1/* exif-utils.c
2 *
3 * Copyright (c) 2001 Lutz Mueller <lutz@users.sourceforge.net>
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 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#include <libexif/exif-utils.h>
24
25void
26exif_array_set_byte_order (ExifFormat f, unsigned char *b, unsigned int n,
27		ExifByteOrder o_orig, ExifByteOrder o_new)
28{
29	unsigned int j;
30	unsigned int fs = exif_format_get_size (f);
31	ExifShort s;
32	ExifSShort ss;
33	ExifLong l;
34	ExifSLong sl;
35	ExifRational r;
36	ExifSRational sr;
37
38	if (!b || !n || !fs) return;
39
40	switch (f) {
41	case EXIF_FORMAT_SHORT:
42		for (j = 0; j < n; j++) {
43			s = exif_get_short (b + j * fs, o_orig);
44			exif_set_short (b + j * fs, o_new, s);
45		}
46		break;
47	case EXIF_FORMAT_SSHORT:
48		for (j = 0; j < n; j++) {
49			ss = exif_get_sshort (b + j * fs, o_orig);
50			exif_set_sshort (b + j * fs, o_new, ss);
51		}
52		break;
53	case EXIF_FORMAT_LONG:
54		for (j = 0; j < n; j++) {
55			l = exif_get_long (b + j * fs, o_orig);
56			exif_set_long (b + j * fs, o_new, l);
57		}
58		break;
59	case EXIF_FORMAT_RATIONAL:
60		for (j = 0; j < n; j++) {
61			r = exif_get_rational (b + j * fs, o_orig);
62			exif_set_rational (b + j * fs, o_new, r);
63		}
64		break;
65	case EXIF_FORMAT_SLONG:
66		for (j = 0; j < n; j++) {
67			sl = exif_get_slong (b + j * fs, o_orig);
68			exif_set_slong (b + j * fs, o_new, sl);
69		}
70		break;
71	case EXIF_FORMAT_SRATIONAL:
72		for (j = 0; j < n; j++) {
73			sr = exif_get_srational (b + j * fs, o_orig);
74			exif_set_srational (b + j * fs, o_new, sr);
75		}
76		break;
77	case EXIF_FORMAT_UNDEFINED:
78	case EXIF_FORMAT_BYTE:
79	case EXIF_FORMAT_ASCII:
80	default:
81		/* Nothing here. */
82		break;
83	}
84}
85
86ExifSShort
87exif_get_sshort (const unsigned char *buf, ExifByteOrder order)
88{
89	if (!buf) return 0;
90        switch (order) {
91        case EXIF_BYTE_ORDER_MOTOROLA:
92                return ((buf[0] << 8) | buf[1]);
93        case EXIF_BYTE_ORDER_INTEL:
94                return ((buf[1] << 8) | buf[0]);
95        }
96
97	/* Won't be reached */
98	return (0);
99}
100
101ExifShort
102exif_get_short (const unsigned char *buf, ExifByteOrder order)
103{
104	return (exif_get_sshort (buf, order) & 0xffff);
105}
106
107void
108exif_set_sshort (unsigned char *b, ExifByteOrder order, ExifSShort value)
109{
110	if (!b) return;
111	switch (order) {
112	case EXIF_BYTE_ORDER_MOTOROLA:
113		b[0] = (unsigned char) (value >> 8);
114		b[1] = (unsigned char) value;
115		break;
116	case EXIF_BYTE_ORDER_INTEL:
117		b[0] = (unsigned char) value;
118		b[1] = (unsigned char) (value >> 8);
119		break;
120	}
121}
122
123void
124exif_set_short (unsigned char *b, ExifByteOrder order, ExifShort value)
125{
126	exif_set_sshort (b, order, value);
127}
128
129ExifSLong
130exif_get_slong (const unsigned char *b, ExifByteOrder order)
131{
132	if (!b) return 0;
133        switch (order) {
134        case EXIF_BYTE_ORDER_MOTOROLA:
135                return ((b[0] << 24) | (b[1] << 16) | (b[2] << 8) | b[3]);
136        case EXIF_BYTE_ORDER_INTEL:
137                return ((b[3] << 24) | (b[2] << 16) | (b[1] << 8) | b[0]);
138        }
139
140	/* Won't be reached */
141	return (0);
142}
143
144void
145exif_set_slong (unsigned char *b, ExifByteOrder order, ExifSLong value)
146{
147	if (!b) return;
148	switch (order) {
149	case EXIF_BYTE_ORDER_MOTOROLA:
150		b[0] = (unsigned char) (value >> 24);
151		b[1] = (unsigned char) (value >> 16);
152		b[2] = (unsigned char) (value >> 8);
153		b[3] = (unsigned char) value;
154		break;
155	case EXIF_BYTE_ORDER_INTEL:
156		b[3] = (unsigned char) (value >> 24);
157		b[2] = (unsigned char) (value >> 16);
158		b[1] = (unsigned char) (value >> 8);
159		b[0] = (unsigned char) value;
160		break;
161	}
162}
163
164ExifLong
165exif_get_long (const unsigned char *buf, ExifByteOrder order)
166{
167        return (exif_get_slong (buf, order) & 0xffffffff);
168}
169
170void
171exif_set_long (unsigned char *b, ExifByteOrder order, ExifLong value)
172{
173	exif_set_slong (b, order, value);
174}
175
176ExifSRational
177exif_get_srational (const unsigned char *buf, ExifByteOrder order)
178{
179	ExifSRational r;
180
181	r.numerator   = buf ? exif_get_slong (buf, order) : 0;
182	r.denominator = buf ? exif_get_slong (buf + 4, order) : 0;
183
184	return (r);
185}
186
187ExifRational
188exif_get_rational (const unsigned char *buf, ExifByteOrder order)
189{
190	ExifRational r;
191
192	r.numerator   = buf ? exif_get_long (buf, order) : 0;
193	r.denominator = buf ? exif_get_long (buf + 4, order) : 0;
194
195	return (r);
196}
197
198void
199exif_set_rational (unsigned char *buf, ExifByteOrder order,
200		   ExifRational value)
201{
202	if (!buf) return;
203	exif_set_long (buf, order, value.numerator);
204	exif_set_long (buf + 4, order, value.denominator);
205}
206
207void
208exif_set_srational (unsigned char *buf, ExifByteOrder order,
209		    ExifSRational value)
210{
211	if (!buf) return;
212	exif_set_slong (buf, order, value.numerator);
213	exif_set_slong (buf + 4, order, value.denominator);
214}
215
216/*! This function converts rather UCS-2LE than UTF-16 to UTF-8.
217 * It should really be replaced by iconv().
218 */
219void
220exif_convert_utf16_to_utf8 (char *out, const unsigned short *in, int maxlen)
221{
222	if (maxlen <= 0) {
223		return;
224	}
225	while (*in) {
226		if (*in < 0x80) {
227			if (maxlen > 1) {
228				*out++ = (char)*in++;
229				maxlen--;
230			} else {
231				break;
232			}
233		} else if (*in < 0x800) {
234			if (maxlen > 2) {
235				*out++ = ((*in >> 6) & 0x1F) | 0xC0;
236				*out++ = (*in++ & 0x3F) | 0x80;
237				maxlen -= 2;
238			} else {
239				break;
240			}
241		} else {
242			if (maxlen > 3) {
243				*out++ = ((*in >> 12) & 0x0F) | 0xE0;
244				*out++ = ((*in >> 6) & 0x3F) | 0x80;
245				*out++ = (*in++ & 0x3F) | 0x80;
246				maxlen -= 3;
247			} else {
248				break;
249			}
250		}
251	}
252	*out = 0;
253}
254