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 
25 void
exif_array_set_byte_order(ExifFormat f,unsigned char * b,unsigned int n,ExifByteOrder o_orig,ExifByteOrder o_new)26 exif_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 
86 ExifSShort
exif_get_sshort(const unsigned char * buf,ExifByteOrder order)87 exif_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 
101 ExifShort
exif_get_short(const unsigned char * buf,ExifByteOrder order)102 exif_get_short (const unsigned char *buf, ExifByteOrder order)
103 {
104 	return (exif_get_sshort (buf, order) & 0xffff);
105 }
106 
107 void
exif_set_sshort(unsigned char * b,ExifByteOrder order,ExifSShort value)108 exif_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 
123 void
exif_set_short(unsigned char * b,ExifByteOrder order,ExifShort value)124 exif_set_short (unsigned char *b, ExifByteOrder order, ExifShort value)
125 {
126 	exif_set_sshort (b, order, value);
127 }
128 
129 ExifSLong
exif_get_slong(const unsigned char * b,ExifByteOrder order)130 exif_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 
144 void
exif_set_slong(unsigned char * b,ExifByteOrder order,ExifSLong value)145 exif_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 
164 ExifLong
exif_get_long(const unsigned char * buf,ExifByteOrder order)165 exif_get_long (const unsigned char *buf, ExifByteOrder order)
166 {
167         return (exif_get_slong (buf, order) & 0xffffffff);
168 }
169 
170 void
exif_set_long(unsigned char * b,ExifByteOrder order,ExifLong value)171 exif_set_long (unsigned char *b, ExifByteOrder order, ExifLong value)
172 {
173 	exif_set_slong (b, order, value);
174 }
175 
176 ExifSRational
exif_get_srational(const unsigned char * buf,ExifByteOrder order)177 exif_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 
187 ExifRational
exif_get_rational(const unsigned char * buf,ExifByteOrder order)188 exif_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 
198 void
exif_set_rational(unsigned char * buf,ExifByteOrder order,ExifRational value)199 exif_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 
207 void
exif_set_srational(unsigned char * buf,ExifByteOrder order,ExifSRational value)208 exif_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  */
219 void
exif_convert_utf16_to_utf8(char * out,const unsigned short * in,int maxlen)220 exif_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