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