Fixed i_transform2() so malloc(0) doesn't happen. Also corrected pod errors and
[imager.git] / tags.c
CommitLineData
faa9b3e7
TC
1/*
2=head1 NAME
3
4tags.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
21Provides functions which give write access to the tags list of an image.
22
23For read access directly access the fields (do not write any fields
24directly).
25
26A 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 */
52void i_tags_print(i_img_tags *tags);
53
54/*
55=item i_tags_new(i_img_tags *tags)
56
57Initialize a tags structure. Should not be used if the tags structure
58has been previously used.
59
60To destroy the contents use i_tags_destroy()
61
62=cut
63*/
64
65void 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
73Adds a tag that has an integer value. A simple wrapper around i_tags_add().
74
75Duplicate tags can be added.
76
77Returns non-zero on success.
78
79=cut
80*/
81
82int 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
89Adds a tag to the tags list.
90
91Duplicate tags can be added.
92
93Returns non-zero on success.
94
95=cut
96*/
97
98int 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
140void 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
153int 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
166int 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
179int 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
194int 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
208int 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
222int 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
243int 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
255int 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
276int 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
304void 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}
b8c2033e
AMH
332
333/*
334=back
335
336=head1 AUTHOR
337
338Tony Cook <tony@develop-help.com>
339
340=head1 SEE ALSO
341
342Imager(3)
343
344=cut
345*/