f375de1c748ce4373b68aeb679f1128a260037b2
[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 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 }