Fixed i_transform2() so malloc(0) doesn't happen. Also corrected pod errors and
[imager.git] / tags.c
1 /*
2 =head1 NAME
3
4 tags.c - functions for manipulating an images tags list
5
6 =head1 SYNOPSIS
7
8   i_img_tags tags;
9   i_tags_new(&tags);
10   i_tags_destroy(&tags);
11   i_tags_addn(&tags, "name", code, idata);
12   i_tags_add(&tags, "name", code, data, data_size, idata);
13   if (i_tags_find(&tags, name, start, &entry)) { found }
14   if (i_tags_findn(&tags, code, start, &entry)) { found }
15   i_tags_delete(&tags, index);
16   count = i_tags_delbyname(tags, name);
17   count = i_tags_delbycode(tags, code);
18
19 =head1 DESCRIPTION
20
21 Provides functions which give write access to the tags list of an image.
22
23 For read access directly access the fields (do not write any fields
24 directly).
25
26 A tag is represented by an i_img_tag structure:
27
28   typedef enum {
29     itt_double,
30     iit_text
31   } i_tag_type;
32
33   typedef struct {
34     char *name; // name of a given tag, might be NULL 
35     int code; // number of a given tag, -1 if it has no meaning 
36     char *data; // value of a given tag if it's not an int, may be NULL 
37     int size; // size of the data 
38     int idata; // value of a given tag if data is NULL 
39   } i_img_tag;
40
41
42 =over
43
44 =cut
45 */
46
47 #include "image.h"
48 #include <string.h>
49 #include <stdlib.h>
50
51 /* useful for debugging */
52 void i_tags_print(i_img_tags *tags);
53
54 /*
55 =item i_tags_new(i_img_tags *tags)
56
57 Initialize a tags structure.  Should not be used if the tags structure
58 has been previously used.
59
60 To destroy the contents use i_tags_destroy()
61
62 =cut
63 */
64
65 void i_tags_new(i_img_tags *tags) {
66   tags->count = tags->alloc = 0;
67   tags->tags = NULL;
68 }
69
70 /*
71 =item i_tags_addn(i_img_tags *tags, char *name, int code, int idata)
72
73 Adds a tag that has an integer value.  A simple wrapper around i_tags_add().
74
75 Duplicate tags can be added.
76
77 Returns non-zero on success.
78
79 =cut
80 */
81
82 int i_tags_addn(i_img_tags *tags, char *name, int code, int idata) {
83   return i_tags_add(tags, name, code, NULL, 0, idata);
84 }
85
86 /*
87 =item i_tags_add(i_img_tags *tags, char *name, int code, char *data, int size, i_tag_type type, int idata)
88
89 Adds a tag to the tags list.
90
91 Duplicate tags can be added.
92
93 Returns non-zero on success.
94
95 =cut
96 */
97
98 int i_tags_add(i_img_tags *tags, char *name, int code, char *data, int size, 
99                int idata) {
100   i_img_tag work = {0};
101   if (tags->tags == NULL) {
102     int alloc = 10;
103     tags->tags = malloc(sizeof(i_img_tag) * alloc);
104     if (!tags->tags)
105       return 0;
106     tags->alloc = alloc;
107   }
108   else if (tags->count == tags->alloc) {
109     int newalloc = tags->alloc + 10;
110     void *newtags = realloc(tags->tags, sizeof(i_img_tag) * newalloc);
111     if (!newtags) {
112       return 0;
113     }
114     tags->tags = newtags;
115     tags->alloc = newalloc;
116   }
117   if (name) {
118     work.name = malloc(strlen(name)+1);
119     if (!work.name)
120       return 0;
121     strcpy(work.name, name);
122   }
123   if (data) {
124     work.data = malloc(size+1);
125     if (!work.data) {
126       if (work.name) free(work.name);
127       return 0;
128     }
129     memcpy(work.data, data, size);
130     work.data[size] = '\0'; /* convenience */
131     work.size = size;
132   }
133   work.code = code;
134   work.idata = idata;
135   tags->tags[tags->count++] = work;
136
137   return 1;
138 }
139
140 void i_tags_destroy(i_img_tags *tags) {
141   if (tags->tags) {
142     int i;
143     for (i = 0; i < tags->count; ++i) {
144       if (tags->tags[i].name)
145         free(tags->tags[i].name);
146       if (tags->tags[i].data)
147         free(tags->tags[i].data);
148     }
149     free(tags->tags);
150   }
151 }
152
153 int i_tags_find(i_img_tags *tags, char *name, int start, int *entry) {
154   if (tags->tags) {
155     while (start < tags->count) {
156       if (tags->tags[start].name && strcmp(name, tags->tags[start].name) == 0) {
157         *entry = start;
158         return 1;
159       }
160       ++start;
161     }
162   }
163   return 0;
164 }
165
166 int i_tags_findn(i_img_tags *tags, int code, int start, int *entry) {
167   if (tags->tags) {
168     while (start < tags->count) {
169       if (tags->tags[start].code == code) {
170         *entry = start;
171         return 1;
172       }
173       ++start;
174     }
175   }
176   return 0;
177 }
178
179 int i_tags_delete(i_img_tags *tags, int entry) {
180   if (tags->tags && entry >= 0 && entry < tags->count) {
181     i_img_tag old = tags->tags[entry];
182     memmove(tags->tags+entry, tags->tags+entry+1,
183             tags->count-entry-1);
184     if (old.name)
185       free(old.name);
186     if (old.data)
187       free(old.data);
188     --tags->count;
189     return 1;
190   }
191   return 0;
192 }
193
194 int i_tags_delbyname(i_img_tags *tags, char *name) {
195   int count = 0;
196   int i;
197   if (tags->tags) {
198     for (i = tags->count-1; i >= 0; --i) {
199       if (tags->tags[i].name && strcmp(name, tags->tags[i].name) == 0) {
200         ++count;
201         i_tags_delete(tags, i);
202       }
203     }
204   }
205   return count;
206 }
207
208 int i_tags_delbycode(i_img_tags *tags, int code) {
209   int count = 0;
210   int i;
211   if (tags->tags) {
212     for (i = tags->count-1; i >= 0; --i) {
213       if (tags->tags[i].code == code) {
214         ++count;
215         i_tags_delete(tags, i);
216       }
217     }
218   }
219   return count;
220 }
221
222 int i_tags_get_float(i_img_tags *tags, char *name, int code, double *value) {
223   int index;
224   i_img_tag *entry;
225
226   if (name) {
227     if (!i_tags_find(tags, name, 0, &index))
228       return 0;
229   }
230   else {
231     if (!i_tags_findn(tags, code, 0, &index))
232       return 0;
233   }
234   entry = tags->tags+index;
235   if (entry->data)
236     *value = atof(entry->data);
237   else
238     *value = entry->idata;
239
240   return 1;
241 }
242
243 int i_tags_set_float(i_img_tags *tags, char *name, int code, double value) {
244   char temp[40];
245
246   sprintf(temp, "%.30g", value);
247   if (name)
248     i_tags_delbyname(tags, name);
249   else
250     i_tags_delbycode(tags, code);
251
252   return i_tags_add(tags, name, code, temp, strlen(temp), 0);
253 }
254
255 int i_tags_get_int(i_img_tags *tags, char *name, int code, int *value) {
256   int index;
257   i_img_tag *entry;
258
259   if (name) {
260     if (!i_tags_find(tags, name, 0, &index))
261       return 0;
262   }
263   else {
264     if (!i_tags_findn(tags, code, 0, &index))
265       return 0;
266   }
267   entry = tags->tags+index;
268   if (entry->data)
269     *value = atoi(entry->data);
270   else
271     *value = entry->idata;
272
273   return 1;
274 }
275
276 int i_tags_get_string(i_img_tags *tags, char *name, int code, 
277                       char *value, size_t value_size) {
278   int index;
279   i_img_tag *entry;
280
281   if (name) {
282     if (!i_tags_find(tags, name, 0, &index))
283       return 0;
284   }
285   else {
286     if (!i_tags_findn(tags, code, 0, &index))
287       return 0;
288   }
289   entry = tags->tags+index;
290   if (entry->data) {
291     size_t cpsize = value_size < entry->size ? value_size : entry->size;
292     memcpy(value, entry->data, cpsize);
293     if (cpsize == value_size)
294       --cpsize;
295     value[cpsize] = '\0';
296   }
297   else {
298     sprintf(value, "%d", entry->data);
299   }
300
301   return 1;
302 }
303
304 void i_tags_print(i_img_tags *tags) {
305   int i;
306   printf("Alloc %d\n", tags->alloc);
307   printf("Count %d\n", tags->count);
308   for (i = 0; i < tags->count; ++i) {
309     i_img_tag *tag = tags->tags + i;
310     printf("Tag %d\n", i);
311     if (tag->name)
312       printf(" Name : %s\n", tag->name);
313     printf(" Code : %d\n", tag->code);
314     if (tag->data) {
315       int pos;
316       printf(" Data : %d => '", tag->size);
317       for (pos = 0; pos < tag->size; ++pos) {
318         if (tag->data[pos] == '\\' || tag->data[pos] == '\'') {
319           putchar('\\');
320           putchar(tag->data[pos]);
321         }
322         else if (tag->data[pos] < ' ' || tag->data[pos] >= '\x7E')
323           printf("\\x%02X", tag->data[pos]);
324         else
325           putchar(tag->data[pos]);
326       }
327       printf("'\n");
328       printf(" Idata: %d\n", tag->idata);
329     }
330   }
331 }
332
333 /*
334 =back
335
336 =head1 AUTHOR
337
338 Tony Cook <tony@develop-help.com>
339
340 =head1 SEE ALSO
341
342 Imager(3)
343
344 =cut
345 */