]> git.street.me.uk Git - andy/viking.git/blob - src/libjpeg/jpeg-data.c
Fix waypoints may not be drawn when created by paste of a text location.
[andy/viking.git] / src / libjpeg / jpeg-data.c
1 /* jpeg-data.c
2  *
3  * Copyright © 2001 Lutz Müller <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 #include "jpeg-data.h"
23
24 #include <stdlib.h>
25 #include <stdio.h>
26 #include <string.h>
27 #include <glib/gi18n.h>
28
29 /* realloc that cleans up on memory failure and returns to caller */
30 #define CLEANUP_REALLOC(p,s) { \
31         unsigned char *cleanup_ptr = realloc((p),(s)); \
32         if (!cleanup_ptr) { free(p); (p) = NULL; return; } \
33         (p) = cleanup_ptr; \
34 }
35
36 struct _JPEGDataPrivate
37 {
38         unsigned int ref_count;
39
40         ExifLog *log;
41 };
42
43 JPEGData *
44 jpeg_data_new (void)
45 {
46         JPEGData *data;
47
48         data = malloc (sizeof (JPEGData));
49         if (!data)
50                 return (NULL);
51         memset (data, 0, sizeof (JPEGData));
52         data->priv = malloc (sizeof (JPEGDataPrivate));
53         if (!data->priv) {
54                 free (data);
55                 return (NULL);
56         }
57         memset (data->priv, 0, sizeof (JPEGDataPrivate));
58         data->priv->ref_count = 1;
59
60         return (data);
61 }
62
63 void
64 jpeg_data_append_section (JPEGData *data)
65 {
66         JPEGSection *s;
67
68         if (!data) return;
69
70         if (!data->count)
71                 s = malloc (sizeof (JPEGSection));
72         else
73                 s = realloc (data->sections,
74                              sizeof (JPEGSection) * (data->count + 1));
75         if (!s) {
76                 EXIF_LOG_NO_MEMORY (data->priv->log, "jpeg-data", 
77                                 sizeof (JPEGSection) * (data->count + 1));
78                 return;
79         }
80         memset(s + data->count, 0, sizeof (JPEGSection));
81         data->sections = s;
82         data->count++;
83 }
84
85 /*! jpeg_data_save_file returns 1 on success, 0 on failure */
86 int
87 jpeg_data_save_file (JPEGData *data, const char *path)
88 {
89         FILE *f;
90         unsigned char *d = NULL;
91         unsigned int size = 0, written;
92
93         jpeg_data_save_data (data, &d, &size);
94         if (!d)
95                 return 0;
96
97         f = fopen (path, "wb");
98         if (!f) {
99                 free (d);
100                 return 0;
101         }
102         written = fwrite (d, 1, size, f);
103         fclose (f);
104         free (d);
105         if (written == size)  {
106                 return 1;
107         }
108         remove(path);
109         return 0;
110 }
111
112 void
113 jpeg_data_save_data (JPEGData *data, unsigned char **d, unsigned int *ds)
114 {
115         unsigned int i, eds = 0;
116         JPEGSection s;
117         unsigned char *ed = NULL;
118
119         if (!data)
120                 return;
121         if (!d)
122                 return;
123         if (!ds)
124                 return;
125
126         for (*ds = i = 0; i < data->count; i++) {
127                 s = data->sections[i];
128
129                 /* Write the marker */
130                 CLEANUP_REALLOC (*d, sizeof (char) * (*ds + 2));
131                 (*d)[*ds + 0] = 0xff;
132                 (*d)[*ds + 1] = s.marker;
133                 *ds += 2;
134
135                 switch (s.marker) {
136                 case JPEG_MARKER_SOI:
137                 case JPEG_MARKER_EOI:
138                         break;
139                 case JPEG_MARKER_APP1:
140                         exif_data_save_data (s.content.app1, &ed, &eds);
141                         if (!ed) break;
142                         CLEANUP_REALLOC (*d, sizeof (char) * (*ds + 2));
143                         (*d)[*ds + 0] = (eds + 2) >> 8;
144                         (*d)[*ds + 1] = (eds + 2) >> 0;
145                         *ds += 2;
146                         CLEANUP_REALLOC (*d, sizeof (char) * (*ds + eds));
147                         memcpy (*d + *ds, ed, eds);
148                         *ds += eds;
149                         free (ed);
150                         break;
151                 default:
152                         CLEANUP_REALLOC (*d, sizeof (char) *
153                                         (*ds + s.content.generic.size + 2));
154                         (*d)[*ds + 0] = (s.content.generic.size + 2) >> 8;
155                         (*d)[*ds + 1] = (s.content.generic.size + 2) >> 0;
156                         *ds += 2;
157                         memcpy (*d + *ds, s.content.generic.data,
158                                 s.content.generic.size);
159                         *ds += s.content.generic.size;
160
161                         /* In case of SOS, we need to write the data. */
162                         if (s.marker == JPEG_MARKER_SOS) {
163                                 CLEANUP_REALLOC (*d, *ds + data->size);
164                                 memcpy (*d + *ds, data->data, data->size);
165                                 *ds += data->size;
166                         }
167                         break;
168                 }
169         }
170 }
171
172 JPEGData *
173 jpeg_data_new_from_data (const unsigned char *d,
174                          unsigned int size)
175 {
176         JPEGData *data;
177
178         data = jpeg_data_new ();
179         jpeg_data_load_data (data, d, size);
180         return (data);
181 }
182
183 void
184 jpeg_data_load_data (JPEGData *data, const unsigned char *d,
185                      unsigned int size)
186 {
187         unsigned int i, o, len;
188         JPEGSection *s;
189         JPEGMarker marker;
190
191         if (!data) return;
192         if (!d) return;
193
194         for (o = 0; o < size;) {
195
196                 /*
197                  * JPEG sections start with 0xff. The first byte that is
198                  * not 0xff is a marker (hopefully).
199                  */
200                 for (i = 0; i < MIN(7, size - o); i++)
201                         if (d[o + i] != 0xff)
202                                 break;
203                 if ((i >= size - o) || !JPEG_IS_MARKER (d[o + i])) {
204                         exif_log (data->priv->log, EXIF_LOG_CODE_CORRUPT_DATA, "jpeg-data",
205                                         _("Data does not follow JPEG specification."));
206                         return;
207                 }
208                 marker = d[o + i];
209
210                 /* Append this section */
211                 jpeg_data_append_section (data);
212                 if (!data->count) return;
213                 s = &data->sections[data->count - 1];
214                 s->marker = marker;
215                 o += i + 1;
216
217                 switch (s->marker) {
218                 case JPEG_MARKER_SOI:
219                 case JPEG_MARKER_EOI:
220                         break;
221                 default:
222
223                         /* Read the length of the section */
224                         if (2 > size - o) { o = size; break; }
225                         len = ((d[o] << 8) | d[o + 1]) - 2;
226                         if (len > size) { o = size; break; }
227                         o += 2;
228                         if (len > size - o) { o = size; break; }
229
230                         switch (s->marker) {
231                         case JPEG_MARKER_APP1:
232                                 s->content.app1 = exif_data_new_from_data (
233                                                         d + o - 4, len + 4);
234                                 break;
235                         default:
236                                 s->content.generic.data =
237                                                 malloc (sizeof (char) * len);
238                                 if (!s->content.generic.data) {
239                                         EXIF_LOG_NO_MEMORY (data->priv->log, "jpeg-data", sizeof (char) * len);
240                                         return;
241                                 }
242                                 s->content.generic.size = len;
243                                 memcpy (s->content.generic.data, &d[o], len);
244
245                                 /* In case of SOS, image data will follow. */
246                                 if (s->marker == JPEG_MARKER_SOS) {
247                                         data->size = size - o - len;
248                                         if (data->size >= 2) {
249                                                 /* -2 means 'take all but the last 2 bytes which are
250                                                    hoped to be JPEG_MARKER_EOI */
251                                                 data->size -= 2;
252                                                 if (d[o + len + data->size] != 0xFF) {
253                                                         /* A truncated file (i.e. w/o JPEG_MARKER_EOI at the end).
254                                                            Instead of trying to use the last two bytes as marker,
255                                                            touching memory beyond allocated memory and posssibly saving
256                                                            back screwed file, we rather take the rest of the file. */
257                                                         data->size += 2;
258                                                 }
259                                         }
260                                         data->data = malloc (
261                                                 sizeof (char) * data->size);
262                                         if (!data->data) {
263                                                 EXIF_LOG_NO_MEMORY (data->priv->log, "jpeg-data", sizeof (char) * data->size);
264                                                 data->size = 0;
265                                                 return;
266                                         }
267                                         memcpy (data->data, d + o + len,
268                                                 data->size);
269                                         o += data->size;
270                                 }
271                                 break;
272                         }
273                         o += len;
274                         break;
275                 }
276         }
277 }
278
279 JPEGData *
280 jpeg_data_new_from_file (const char *path)
281 {
282         JPEGData *data;
283
284         data = jpeg_data_new ();
285         jpeg_data_load_file (data, path);
286         return (data);
287 }
288
289 void
290 jpeg_data_load_file (JPEGData *data, const char *path)
291 {
292         FILE *f;
293         unsigned char *d;
294         unsigned int size;
295
296         if (!data) return;
297         if (!path) return;
298
299         f = fopen (path, "rb");
300         if (!f) {
301                 exif_log (data->priv->log, EXIF_LOG_CODE_CORRUPT_DATA, "jpeg-data",
302                                 _("Path '%s' invalid."), path);
303                 return;
304         }
305
306         /* For now, we read the data into memory. Patches welcome... */
307         fseek (f, 0, SEEK_END);
308         size = ftell (f);
309         fseek (f, 0, SEEK_SET);
310         d = malloc (size);
311         if (!d) {
312                 EXIF_LOG_NO_MEMORY (data->priv->log, "jpeg-data", size);
313                 fclose (f);
314                 return;
315         }
316         if (fread (d, 1, size, f) != size) {
317                 free (d);
318                 fclose (f);
319                 exif_log (data->priv->log, EXIF_LOG_CODE_CORRUPT_DATA, "jpeg-data",
320                                 _("Could not read '%s'."), path);
321                 return;
322         }
323         fclose (f);
324
325         jpeg_data_load_data (data, d, size);
326         free (d);
327 }
328
329 void
330 jpeg_data_ref (JPEGData *data)
331 {
332         if (!data)
333                 return;
334
335         data->priv->ref_count++;
336 }
337
338 void
339 jpeg_data_unref (JPEGData *data)
340 {
341         if (!data)
342                 return;
343
344         if (data->priv) {
345                 data->priv->ref_count--;
346                 if (!data->priv->ref_count)
347                         jpeg_data_free (data);
348         }
349 }
350
351 void
352 jpeg_data_free (JPEGData *data)
353 {
354         unsigned int i;
355         JPEGSection s;
356
357         if (!data)
358                 return;
359
360         if (data->count) {
361                 for (i = 0; i < data->count; i++) {
362                         s = data->sections[i];
363                         switch (s.marker) {
364                         case JPEG_MARKER_SOI:
365                         case JPEG_MARKER_EOI:
366                                 break;
367                         case JPEG_MARKER_APP1:
368                                 exif_data_unref (s.content.app1);
369                                 break;
370                         default:
371                                 free (s.content.generic.data);
372                                 break;
373                         }
374                 }
375                 free (data->sections);
376         }
377
378         if (data->data)
379                 free (data->data);
380
381         if (data->priv) {
382                 if (data->priv->log) {
383                         exif_log_unref (data->priv->log);
384                         data->priv->log = NULL;
385                 }
386                 free (data->priv);
387         }
388
389         free (data);
390 }
391
392 void
393 jpeg_data_dump (JPEGData *data)
394 {
395         unsigned int i;
396         JPEGContent content;
397         JPEGMarker marker;
398
399         if (!data)
400                 return;
401
402         printf ("Dumping JPEG data (%i bytes of data)...\n", data->size);
403         for (i = 0; i < data->count; i++) {
404                 marker = data->sections[i].marker;
405                 content = data->sections[i].content;
406                 printf ("Section %i (marker 0x%x - %s):\n", i, marker,
407                         jpeg_marker_get_name (marker));
408                 printf ("  Description: %s\n",
409                         jpeg_marker_get_description (marker));
410                 switch (marker) {
411                 case JPEG_MARKER_SOI:
412                 case JPEG_MARKER_EOI:
413                         break;
414                 case JPEG_MARKER_APP1:
415                         exif_data_dump (content.app1);
416                         break;
417                 default:
418                         printf ("  Size: %i\n", content.generic.size);
419                         printf ("  Unknown content.\n");
420                         break;
421                 }
422         }
423 }
424
425 static JPEGSection *
426 jpeg_data_get_section (JPEGData *data, JPEGMarker marker)
427 {
428         unsigned int i;
429
430         if (!data)
431                 return (NULL);
432
433         for (i = 0; i < data->count; i++)
434                 if (data->sections[i].marker == marker)
435                         return (&data->sections[i]);
436         return (NULL);
437 }
438
439 ExifData *
440 jpeg_data_get_exif_data (JPEGData *data)
441 {
442         JPEGSection *section;
443
444         if (!data)
445                 return NULL;
446
447         section = jpeg_data_get_section (data, JPEG_MARKER_APP1);
448         if (section) {
449                 exif_data_ref (section->content.app1);
450                 return (section->content.app1);
451         }
452
453         return (NULL);
454 }
455
456 void
457 jpeg_data_set_exif_data (JPEGData *data, ExifData *exif_data)
458 {
459         JPEGSection *section;
460
461         if (!data) return;
462
463         section = jpeg_data_get_section (data, JPEG_MARKER_APP1);
464         if (!section) {
465                 jpeg_data_append_section (data);
466                 if (data->count < 2) return;
467                 memmove (&data->sections[2], &data->sections[1],
468                          sizeof (JPEGSection) * (data->count - 2));
469                 section = &data->sections[1];
470         } else {
471                 exif_data_unref (section->content.app1);
472         }
473         section->marker = JPEG_MARKER_APP1;
474         section->content.app1 = exif_data;
475         exif_data_ref (exif_data);
476 }
477
478 void
479 jpeg_data_log (JPEGData *data, ExifLog *log)
480 {
481         if (!data || !data->priv) return;
482         if (data->priv->log) exif_log_unref (data->priv->log);
483         data->priv->log = log;
484         exif_log_ref (log);
485 }