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