2589fcfc046f251352a6487d1ad02ac8d9a864d5
[platform/upstream/libexif.git] / libexif / exif-content.c
1 /* exif-content.c
2  *
3  * Copyright (C) 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., 59 Temple Place - Suite 330,
18  * Boston, MA 02111-1307, USA.
19  */
20 #include <config.h>
21 #include "exif-content.h"
22
23 #include <stdlib.h>
24 #include <stdio.h>
25 #include <string.h>
26
27 #include <libjpeg/jpeg-marker.h>
28
29 //#define DEBUG
30
31 static const unsigned char ExifHeader[] = {0x45, 0x78, 0x69, 0x66, 0x00, 0x00};
32
33 typedef struct _ExifContentNotifyData ExifContentNotifyData;
34 struct _ExifContentNotifyData {
35         ExifContentEvent events;
36         ExifContentNotifyFunc func;
37         void *data;
38 };
39
40 struct _ExifContentPrivate
41 {
42         ExifContentNotifyData *notifications;
43         unsigned int count;
44
45         unsigned int ref_count;
46 };
47
48 unsigned int
49 exif_content_add_notify (ExifContent *content, ExifContentEvent events,
50                          ExifContentNotifyFunc func, void *data)
51 {
52         if (!content)
53                 return (0);
54
55         if (!content->priv->notifications)
56                 content->priv->notifications =
57                                 malloc (sizeof (ExifContentNotifyData));
58         else
59                 content->priv->notifications = 
60                         realloc (content->priv->notifications,
61                                  sizeof (ExifContentNotifyData) *
62                                         (content->priv->count + 1));
63         content->priv->notifications[content->priv->count].events = events;
64         content->priv->notifications[content->priv->count].func = func;
65         content->priv->notifications[content->priv->count].data = data;
66         content->priv->count++;
67
68         return (content->priv->count);
69 }
70
71 void
72 exif_content_remove_notify (ExifContent *content, unsigned int id)
73 {
74         if (!content)
75                 return;
76         if (id > content->priv->count)
77                 return;
78
79         memmove (content->priv->notifications + id - 1,
80                  content->priv->notifications + id,
81                  sizeof (ExifContentNotifyData) *
82                         (content->priv->count - id));
83         content->priv->count--;
84 }
85
86 ExifContent *
87 exif_content_new (void)
88 {
89         ExifContent *content;
90
91         content = malloc (sizeof (ExifContent));
92         if (!content)
93                 return (NULL);
94         memset (content, 0, sizeof (ExifContent));
95         content->priv = malloc (sizeof (ExifContentPrivate));
96         if (!content->priv) {
97                 free (content);
98                 return (NULL);
99         }
100         memset (content->priv, 0, sizeof (ExifContentPrivate));
101         content->priv->ref_count = 1;
102
103         return (content);
104 }
105
106 void
107 exif_content_ref (ExifContent *content)
108 {
109         content->priv->ref_count++;
110 }
111
112 void
113 exif_content_unref (ExifContent *content)
114 {
115         content->priv->ref_count--;
116         if (!content->priv->ref_count)
117                 exif_content_free (content);
118 }
119
120 void
121 exif_content_free (ExifContent *content)
122 {
123         unsigned int i;
124
125         for (i = 0; i < content->count; i++)
126                 exif_entry_unref (content->entries[i]);
127         free (content->entries);
128         free (content->priv);
129         free (content);
130 }
131
132 void
133 exif_content_parse (ExifContent *content, const unsigned char *data,
134                     unsigned int size, unsigned int offset,
135                     ExifByteOrder order)
136 {
137         unsigned int i;
138         ExifShort n;
139         ExifEntry *entry;
140
141         if (!content)
142                 return;
143
144         content->order = order;
145
146         /* Read number of entries */
147         if (size < offset + 2)
148                 return;
149         n = exif_get_short (data + offset, order);
150 #ifdef DEBUG
151         printf ("Parsing directory with %i entries...\n", n);
152 #endif
153
154         for (i = 0; i < n; i++) {
155                 entry = exif_entry_new ();
156                 exif_content_add_entry (content, entry);
157                 exif_entry_parse (content->entries[i], data, size,
158                                   offset + 2 + 12 * i, order);
159                 exif_entry_unref (entry);
160         }
161 }
162
163 void
164 exif_content_dump (ExifContent *content, unsigned int indent)
165 {
166         char buf[1024];
167         unsigned int i;
168
169         for (i = 0; i < 2 * indent; i++)
170                 buf[i] = ' ';
171         buf[i] = '\0';
172
173         if (!content)
174                 return;
175
176         printf ("%sDumping exif content (%i entries)...\n", buf,
177                 content->count);
178         for (i = 0; i < content->count; i++)
179                 exif_entry_dump (content->entries[i], indent + 1);
180 }
181
182 static void
183 exif_content_notify (ExifContent *content, ExifEntry *entry,
184                      ExifContentEvent event)
185 {
186         unsigned int i;
187
188         for (i = 0; i < content->priv->count; i++)
189                 if (content->priv->notifications[i].events & event)
190                         content->priv->notifications[i].func (content, entry,
191                                         content->priv->notifications[i].data);
192 }
193
194 void
195 exif_content_add_entry (ExifContent *content, ExifEntry *entry)
196 {
197         if (entry->parent)
198                 return;
199
200         entry->parent = content;
201         content->entries = realloc (content->entries,
202                                     sizeof (ExifEntry) * (content->count + 1));
203         content->entries[content->count] = entry;
204         exif_entry_ref (entry);
205         content->count++;
206
207         exif_content_notify (content, entry, EXIF_CONTENT_EVENT_ADD);
208 }
209
210 void
211 exif_content_remove_entry (ExifContent *content, ExifEntry *entry)
212 {
213         unsigned int i;
214
215         if (entry->parent != content)
216                 return;
217
218         for (i = 0; i < content->count; i++)
219                 if (content->entries[i] == entry)
220                         break;
221         if (i == content->count)
222                 return;
223
224         memmove (&content->entries[i], &content->entries[i + 1],
225                  sizeof (ExifEntry) * (content->count - i - 1));
226         content->count--;
227
228         exif_content_notify (content, entry, EXIF_CONTENT_EVENT_REMOVE);
229
230         entry->parent = NULL;
231         exif_entry_unref (entry);
232 }
233
234 ExifEntry *
235 exif_content_get_entry (ExifContent *content, ExifTag tag)
236 {
237         unsigned int i;
238
239         if (!content)
240                 return (NULL);
241
242         for (i = 0; i < content->count; i++)
243                 if (content->entries[i]->tag == tag)
244                         return (content->entries[i]);
245         return (NULL);
246 }