Fix decoding of Windows XP proprietary tags on big-endian machines.
[platform/upstream/libexif.git] / libexif / exif-utils.c
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
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
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
102 exif_get_short (const unsigned char *buf, ExifByteOrder order)
103 {
104         return (exif_get_sshort (buf, order) & 0xffff);
105 }
106
107 void
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
124 exif_set_short (unsigned char *b, ExifByteOrder order, ExifShort value)
125 {
126         exif_set_sshort (b, order, value);
127 }
128
129 ExifSLong
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
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
165 exif_get_long (const unsigned char *buf, ExifByteOrder order)
166 {
167         return (exif_get_slong (buf, order) & 0xffffffff);
168 }
169
170 void
171 exif_set_long (unsigned char *b, ExifByteOrder order, ExifLong value)
172 {
173         exif_set_slong (b, order, value);
174 }
175
176 ExifSRational
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
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
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
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
220 exif_convert_utf16_to_utf8 (char *out, const unsigned char *in, int maxlen)
221 {
222         if (maxlen <= 0) {
223                 return;
224         }
225         for (;;) {
226                 ExifShort v = exif_get_short(in, EXIF_BYTE_ORDER_INTEL);
227                 if (!v)
228                         break;
229                 if (v < 0x80) {
230                         if (maxlen > 1) {
231                                 *out++ = (char)v;
232                                 maxlen--;
233                         } else {
234                                 break;
235                         }
236                 } else if (v < 0x800) {
237                         if (maxlen > 2) {
238                                 *out++ = ((v >> 6) & 0x1F) | 0xC0;
239                                 *out++ = (v & 0x3F) | 0x80;
240                                 maxlen -= 2;
241                         } else {
242                                 break;
243                         }
244                 } else {
245                         if (maxlen > 3) {
246                                 *out++ = ((v >> 12) & 0x0F) | 0xE0;
247                                 *out++ = ((v >> 6) & 0x3F) | 0x80;
248                                 *out++ = (v & 0x3F) | 0x80;
249                                 maxlen -= 3;
250                         } else {
251                                 break;
252                         }
253                 }
254                 in += 2;
255         }
256         *out = 0;
257 }