Issue-#3407 : Enhance precision for double to string conversion, useful for GEOTIFF...
[ffmpeg.git] / libavcodec / tiff_common.c
1 /*
2  * TIFF Common Routines
3  * Copyright (c) 2013 Thilo Borgmann <thilo.borgmann _at_ mail.de>
4  *
5  * This file is part of FFmpeg.
6  *
7  * FFmpeg is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * FFmpeg is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with FFmpeg; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20  */
21
22 /**
23  * @file
24  * TIFF Common Routines
25  * @author Thilo Borgmann <thilo.borgmann _at_ mail.de>
26  */
27
28 #include "tiff_common.h"
29
30
31 int ff_tis_ifd(unsigned tag)
32 {
33     int i;
34     for (i = 0; i < FF_ARRAY_ELEMS(ifd_tags); i++) {
35         if (ifd_tags[i] == tag) {
36             return i + 1;
37         }
38     }
39     return 0;
40 }
41
42
43 unsigned ff_tget_short(GetByteContext *gb, int le)
44 {
45     unsigned v = le ? bytestream2_get_le16(gb) : bytestream2_get_be16(gb);
46     return v;
47 }
48
49
50 unsigned ff_tget_long(GetByteContext *gb, int le)
51 {
52     unsigned v = le ? bytestream2_get_le32(gb) : bytestream2_get_be32(gb);
53     return v;
54 }
55
56
57 double ff_tget_double(GetByteContext *gb, int le)
58 {
59     av_alias64 i = { .u64 = le ? bytestream2_get_le64(gb) : bytestream2_get_be64(gb)};
60     return i.f64;
61 }
62
63
64 unsigned ff_tget(GetByteContext *gb, int type, int le)
65 {
66     switch (type) {
67     case TIFF_BYTE:
68         return bytestream2_get_byte(gb);
69     case TIFF_SHORT:
70         return ff_tget_short(gb, le);
71     case TIFF_LONG:
72         return ff_tget_long(gb, le);
73     default:
74         return UINT_MAX;
75     }
76 }
77
78 static const char *auto_sep(int count, const char *sep, int i, int columns)
79 {
80     if (sep)
81         return i ? sep : "";
82     if (i && i%columns) {
83         return ", ";
84     } else
85         return columns < count ? "\n" : "";
86 }
87
88 int ff_tadd_rational_metadata(int count, const char *name, const char *sep,
89                               GetByteContext *gb, int le, AVDictionary **metadata)
90 {
91     AVBPrint bp;
92     char *ap;
93     int32_t nom, denom;
94     int i;
95
96     if (count >= INT_MAX / sizeof(int64_t) || count <= 0)
97         return AVERROR_INVALIDDATA;
98     if (bytestream2_get_bytes_left(gb) < count * sizeof(int64_t))
99         return AVERROR_INVALIDDATA;
100
101     av_bprint_init(&bp, 10 * count, AV_BPRINT_SIZE_UNLIMITED);
102
103     for (i = 0; i < count; i++) {
104         nom   = ff_tget_long(gb, le);
105         denom = ff_tget_long(gb, le);
106         av_bprintf(&bp, "%s%7i:%-7i", auto_sep(count, sep, i, 4), nom, denom);
107     }
108
109     if ((i = av_bprint_finalize(&bp, &ap))) {
110         return i;
111     }
112     if (!ap) {
113         return AVERROR(ENOMEM);
114     }
115
116     av_dict_set(metadata, name, ap, AV_DICT_DONT_STRDUP_VAL);
117
118     return 0;
119 }
120
121
122 int ff_tadd_long_metadata(int count, const char *name, const char *sep,
123                           GetByteContext *gb, int le, AVDictionary **metadata)
124 {
125     AVBPrint bp;
126     char *ap;
127     int i;
128
129     if (count >= INT_MAX / sizeof(int32_t) || count <= 0)
130         return AVERROR_INVALIDDATA;
131     if (bytestream2_get_bytes_left(gb) < count * sizeof(int32_t))
132         return AVERROR_INVALIDDATA;
133
134     av_bprint_init(&bp, 10 * count, AV_BPRINT_SIZE_UNLIMITED);
135
136     for (i = 0; i < count; i++) {
137         av_bprintf(&bp, "%s%7i", auto_sep(count, sep, i, 8), ff_tget_long(gb, le));
138     }
139
140     if ((i = av_bprint_finalize(&bp, &ap))) {
141         return i;
142     }
143     if (!ap) {
144         return AVERROR(ENOMEM);
145     }
146
147     av_dict_set(metadata, name, ap, AV_DICT_DONT_STRDUP_VAL);
148
149     return 0;
150 }
151
152
153 int ff_tadd_doubles_metadata(int count, const char *name, const char *sep,
154                              GetByteContext *gb, int le, AVDictionary **metadata)
155 {
156     AVBPrint bp;
157     char *ap;
158     int i;
159
160     if (count >= INT_MAX / sizeof(int64_t) || count <= 0)
161         return AVERROR_INVALIDDATA;
162     if (bytestream2_get_bytes_left(gb) < count * sizeof(int64_t))
163         return AVERROR_INVALIDDATA;
164
165     av_bprint_init(&bp, 10 * count, 100 * count);
166
167     for (i = 0; i < count; i++) {
168         av_bprintf(&bp, "%s%.15g", auto_sep(count, sep, i, 4), ff_tget_double(gb, le));
169     }
170
171     if ((i = av_bprint_finalize(&bp, &ap))) {
172         return i;
173     }
174     if (!ap) {
175         return AVERROR(ENOMEM);
176     }
177
178     av_dict_set(metadata, name, ap, AV_DICT_DONT_STRDUP_VAL);
179
180     return 0;
181 }
182
183
184 int ff_tadd_shorts_metadata(int count, const char *name, const char *sep,
185                             GetByteContext *gb, int le, AVDictionary **metadata)
186 {
187     AVBPrint bp;
188     char *ap;
189     int i;
190
191     if (count >= INT_MAX / sizeof(int16_t) || count <= 0)
192         return AVERROR_INVALIDDATA;
193     if (bytestream2_get_bytes_left(gb) < count * sizeof(int16_t))
194         return AVERROR_INVALIDDATA;
195
196     av_bprint_init(&bp, 10 * count, AV_BPRINT_SIZE_UNLIMITED);
197
198     for (i = 0; i < count; i++) {
199         av_bprintf(&bp, "%s%5i", auto_sep(count, sep, i, 8), ff_tget_short(gb, le));
200     }
201
202     if ((i = av_bprint_finalize(&bp, &ap))) {
203         return i;
204     }
205     if (!ap) {
206         return AVERROR(ENOMEM);
207     }
208
209     av_dict_set(metadata, name, ap, AV_DICT_DONT_STRDUP_VAL);
210
211     return 0;
212 }
213
214
215 int ff_tadd_bytes_metadata(int count, const char *name, const char *sep,
216                            GetByteContext *gb, int le, AVDictionary **metadata)
217 {
218     AVBPrint bp;
219     char *ap;
220     int i;
221
222     if (count >= INT_MAX / sizeof(int8_t) || count < 0)
223         return AVERROR_INVALIDDATA;
224     if (bytestream2_get_bytes_left(gb) < count * sizeof(int8_t))
225         return AVERROR_INVALIDDATA;
226
227     av_bprint_init(&bp, 10 * count, AV_BPRINT_SIZE_UNLIMITED);
228
229     for (i = 0; i < count; i++) {
230         av_bprintf(&bp, "%s%3i", auto_sep(count, sep, i, 16), bytestream2_get_byte(gb));
231     }
232
233     if ((i = av_bprint_finalize(&bp, &ap))) {
234         return i;
235     }
236     if (!ap) {
237         return AVERROR(ENOMEM);
238     }
239
240     av_dict_set(metadata, name, ap, AV_DICT_DONT_STRDUP_VAL);
241
242     return 0;
243 }
244
245 int ff_tadd_string_metadata(int count, const char *name,
246                             GetByteContext *gb, int le, AVDictionary **metadata)
247 {
248     char *value;
249
250     if (bytestream2_get_bytes_left(gb) < count || count < 0)
251         return AVERROR_INVALIDDATA;
252
253     value = av_malloc(count + 1);
254     if (!value)
255         return AVERROR(ENOMEM);
256
257     bytestream2_get_bufferu(gb, value, count);
258     value[count] = 0;
259
260     av_dict_set(metadata, name, value, AV_DICT_DONT_STRDUP_VAL);
261     return 0;
262 }
263
264
265 int ff_tdecode_header(GetByteContext *gb, int *le, int *ifd_offset)
266 {
267     if (bytestream2_get_bytes_left(gb) < 8) {
268         return AVERROR_INVALIDDATA;
269     }
270
271     *le = bytestream2_get_le16u(gb);
272     if (*le == AV_RB16("II")) {
273         *le = 1;
274     } else if (*le == AV_RB16("MM")) {
275         *le = 0;
276     } else {
277         return AVERROR_INVALIDDATA;
278     }
279
280     if (ff_tget_short(gb, *le) != 42) {
281         return AVERROR_INVALIDDATA;
282     }
283
284     *ifd_offset = ff_tget_long(gb, *le);
285
286     return 0;
287 }
288
289
290 int ff_tread_tag(GetByteContext *gb, int le, unsigned *tag, unsigned *type,
291                  unsigned *count, int *next)
292 {
293     int ifd_tag;
294     int valid_type;
295
296     *tag    = ff_tget_short(gb, le);
297     *type   = ff_tget_short(gb, le);
298     *count  = ff_tget_long (gb, le);
299
300     ifd_tag    = ff_tis_ifd(*tag);
301     valid_type = *type != 0 && *type < FF_ARRAY_ELEMS(type_sizes);
302
303     *next = bytestream2_tell(gb) + 4;
304
305     // check for valid type
306     if (!valid_type) {
307         return AVERROR_INVALIDDATA;
308     }
309
310     // seek to offset if this is an IFD-tag or
311     // if count values do not fit into the offset value
312     if (ifd_tag || (*count > 4 || !(type_sizes[*type] * (*count) <= 4 || *type == TIFF_STRING))) {
313         bytestream2_seek(gb, ff_tget_long (gb, le), SEEK_SET);
314     }
315
316     return 0;
317 }