4 tags.c - functions for manipulating an images tags list
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 if (i_tags_get_float(&tags, name, code, &float_value)) { found }
19 i_tags_set_float(&tags, name, code, value);
20 i_tags_set_float2(&tags, name, code, value, sig_digits);
21 i_tags_get_int(&tags, name, code, &int_value);
25 Provides functions which give write access to the tags list of an image.
27 For read access directly access the fields (do not write any fields
30 A tag is represented by an i_img_tag structure:
38 char *name; // name of a given tag, might be NULL
39 int code; // number of a given tag, -1 if it has no meaning
40 char *data; // value of a given tag if it's not an int, may be NULL
41 int size; // size of the data
42 int idata; // value of a given tag if data is NULL
57 /* useful for debugging */
58 void i_tags_print(i_img_tags *tags);
61 =item i_tags_new(i_img_tags *tags)
63 Initialize a tags structure. Should not be used if the tags structure
64 has been previously used.
66 To destroy the contents use i_tags_destroy()
71 void i_tags_new(i_img_tags *tags) {
72 tags->count = tags->alloc = 0;
77 =item i_tags_addn(i_img_tags *tags, char *name, int code, int idata)
79 Adds a tag that has an integer value. A simple wrapper around i_tags_add().
81 Duplicate tags can be added.
83 Returns non-zero on success.
88 int i_tags_addn(i_img_tags *tags, char const *name, int code, int idata) {
89 return i_tags_add(tags, name, code, NULL, 0, idata);
93 =item i_tags_add(i_img_tags *tags, char *name, int code, char *data, int size, i_tag_type type, int idata)
95 Adds a tag to the tags list.
97 Duplicate tags can be added.
99 Returns non-zero on success.
104 int i_tags_add(i_img_tags *tags, char const *name, int code, char const *data,
105 int size, int idata) {
106 i_img_tag work = {0};
107 /*printf("i_tags_add(tags %p [count %d], name %s, code %d, data %p, size %d, idata %d)\n",
108 tags, tags->count, name, code, data, size, idata);*/
109 if (tags->tags == NULL) {
111 tags->tags = mymalloc(sizeof(i_img_tag) * alloc);
116 else if (tags->count == tags->alloc) {
117 int newalloc = tags->alloc + 10;
118 void *newtags = myrealloc(tags->tags, sizeof(i_img_tag) * newalloc);
122 tags->tags = newtags;
123 tags->alloc = newalloc;
126 work.name = mymalloc(strlen(name)+1);
129 strcpy(work.name, name);
134 work.data = mymalloc(size+1);
136 if (work.name) myfree(work.name);
139 memcpy(work.data, data, size);
140 work.data[size] = '\0'; /* convenience */
145 tags->tags[tags->count++] = work;
147 /*i_tags_print(tags);*/
152 void i_tags_destroy(i_img_tags *tags) {
155 for (i = 0; i < tags->count; ++i) {
156 if (tags->tags[i].name)
157 myfree(tags->tags[i].name);
158 if (tags->tags[i].data)
159 myfree(tags->tags[i].data);
165 int i_tags_find(i_img_tags *tags, char const *name, int start, int *entry) {
167 while (start < tags->count) {
168 if (tags->tags[start].name && strcmp(name, tags->tags[start].name) == 0) {
178 int i_tags_findn(i_img_tags *tags, int code, int start, int *entry) {
180 while (start < tags->count) {
181 if (tags->tags[start].code == code) {
191 int i_tags_delete(i_img_tags *tags, int entry) {
192 /*printf("i_tags_delete(tags %p [count %d], entry %d)\n",
193 tags, tags->count, entry);*/
194 if (tags->tags && entry >= 0 && entry < tags->count) {
195 i_img_tag old = tags->tags[entry];
196 memmove(tags->tags+entry, tags->tags+entry+1,
197 (tags->count-entry-1) * sizeof(i_img_tag));
209 int i_tags_delbyname(i_img_tags *tags, char const *name) {
212 /*printf("i_tags_delbyname(tags %p [count %d], name %s)\n",
213 tags, tags->count, name);*/
215 for (i = tags->count-1; i >= 0; --i) {
216 if (tags->tags[i].name && strcmp(name, tags->tags[i].name) == 0) {
218 i_tags_delete(tags, i);
222 /*i_tags_print(tags);*/
227 int i_tags_delbycode(i_img_tags *tags, int code) {
231 for (i = tags->count-1; i >= 0; --i) {
232 if (tags->tags[i].code == code) {
234 i_tags_delete(tags, i);
241 int i_tags_get_float(i_img_tags *tags, char const *name, int code,
247 if (!i_tags_find(tags, name, 0, &index))
251 if (!i_tags_findn(tags, code, 0, &index))
254 entry = tags->tags+index;
256 *value = atof(entry->data);
258 *value = entry->idata;
263 int i_tags_set_float(i_img_tags *tags, char const *name, int code,
265 return i_tags_set_float2(tags, name, code, value, 30);
269 =item i_tags_set_float2(tags, name, code, value, places)
271 Sets the tag with the given name and code to the given floating point
274 Since tags are strings or ints, we convert the value to a string before
275 storage at the precision specified by C<places>.
280 int i_tags_set_float2(i_img_tags *tags, char const *name, int code,
281 double value, int places) {
286 else if (places > 30)
289 sprintf(temp, "%.*g", places, value);
291 i_tags_delbyname(tags, name);
293 i_tags_delbycode(tags, code);
295 return i_tags_add(tags, name, code, temp, strlen(temp), 0);
298 int i_tags_get_int(i_img_tags *tags, char const *name, int code, int *value) {
303 if (!i_tags_find(tags, name, 0, &index))
307 if (!i_tags_findn(tags, code, 0, &index))
310 entry = tags->tags+index;
312 *value = atoi(entry->data);
314 *value = entry->idata;
319 static int parse_long(char *data, char **end, long *out) {
321 /* I wrote this without thinking about strtol */
323 int neg = *data == '-';
329 while (isdigit(*data)) {
330 /* this check doesn't guarantee we don't overflow, but it helps */
331 if (x > LONG_MAX / 10)
333 x = x * 10 + *data - '0';
344 int savederr = errno;
348 result = strtol(data, &myend, 10);
349 if ((result == LONG_MIN || result == LONG_MAX) && errno == ERANGE
361 /* parse a comma-separated list of integers
362 returns when it has maxcount numbers, finds a non-comma after a number
363 or can't parse a number
364 if it can't parse a number after a comma, that's considered an error
366 static int parse_long_list(char *data, char **end, int maxcount, long *out) {
370 while (i < maxcount-1) {
371 if (!parse_long(data, &data, out))
379 if (!parse_long(data, &data, out))
386 /* parse "color(red,green,blue,alpha)" */
387 static int parse_color(char *data, char **end, i_color *value) {
391 if (memcmp(data, "color(", 6))
392 return 0; /* not a color */
394 count = parse_long_list(data, &data, 4, n);
397 for (i = 0; i < count; ++i)
398 value->channel[i] = n[i];
400 value->channel[3] = 255;
405 int i_tags_get_color(i_img_tags *tags, char const *name, int code,
412 if (!i_tags_find(tags, name, 0, &index))
416 if (!i_tags_findn(tags, code, 0, &index))
419 entry = tags->tags+index;
423 if (!parse_color(entry->data, &end, value))
426 /* for now we're sloppy about the end */
431 int i_tags_set_color(i_img_tags *tags, char const *name, int code,
432 i_color const *value) {
435 sprintf(temp, "color(%d,%d,%d,%d)", value->channel[0], value->channel[1],
436 value->channel[2], value->channel[3]);
438 i_tags_delbyname(tags, name);
440 i_tags_delbycode(tags, code);
442 return i_tags_add(tags, name, code, temp, strlen(temp), 0);
445 int i_tags_get_string(i_img_tags *tags, char const *name, int code,
446 char *value, size_t value_size) {
451 if (!i_tags_find(tags, name, 0, &index))
455 if (!i_tags_findn(tags, code, 0, &index))
458 entry = tags->tags+index;
460 size_t cpsize = value_size < entry->size ? value_size : entry->size;
461 memcpy(value, entry->data, cpsize);
462 if (cpsize == value_size)
464 value[cpsize] = '\0';
467 sprintf(value, "%d", entry->data);
473 void i_tags_print(i_img_tags *tags) {
475 printf("Alloc %d\n", tags->alloc);
476 printf("Count %d\n", tags->count);
477 for (i = 0; i < tags->count; ++i) {
478 i_img_tag *tag = tags->tags + i;
479 printf("Tag %d\n", i);
481 printf(" Name : %s (%p)\n", tag->name, tag->name);
482 printf(" Code : %d\n", tag->code);
485 printf(" Data : %d (%p) => '", tag->size, tag->data);
486 for (pos = 0; pos < tag->size; ++pos) {
487 if (tag->data[pos] == '\\' || tag->data[pos] == '\'') {
489 putchar(tag->data[pos]);
491 else if (tag->data[pos] < ' ' || tag->data[pos] >= '\x7E')
492 printf("\\x%02X", tag->data[pos]);
494 putchar(tag->data[pos]);
497 printf(" Idata: %d\n", tag->idata);
507 Tony Cook <tony@develop-help.com>