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)
65 Initialize a tags structure. Should not be used if the tags structure
66 has been previously used.
68 This should be called tags member of an i_img object on creation (in
69 i_img_*_new() functions).
71 To destroy the contents use i_tags_destroy()
76 void i_tags_new(i_img_tags *tags) {
77 tags->count = tags->alloc = 0;
82 =item i_tags_addn(i_img_tags *tags, char *name, int code, int idata)
84 Adds a tag that has an integer value. A simple wrapper around i_tags_add().
86 Duplicate tags can be added.
88 Returns non-zero on success.
93 int i_tags_addn(i_img_tags *tags, char const *name, int code, int idata) {
94 return i_tags_add(tags, name, code, NULL, 0, idata);
98 =item i_tags_add(i_img_tags *tags, char *name, int code, char *data, int size, i_tag_type type, int idata)
100 Adds a tag to the tags list.
102 Duplicate tags can be added.
104 Returns non-zero on success.
109 int i_tags_add(i_img_tags *tags, char const *name, int code, char const *data,
110 int size, int idata) {
111 i_img_tag work = {0};
112 /*printf("i_tags_add(tags %p [count %d], name %s, code %d, data %p, size %d, idata %d)\n",
113 tags, tags->count, name, code, data, size, idata);*/
114 if (tags->tags == NULL) {
116 tags->tags = mymalloc(sizeof(i_img_tag) * alloc);
121 else if (tags->count == tags->alloc) {
122 int newalloc = tags->alloc + 10;
123 void *newtags = myrealloc(tags->tags, sizeof(i_img_tag) * newalloc);
127 tags->tags = newtags;
128 tags->alloc = newalloc;
131 work.name = mymalloc(strlen(name)+1);
134 strcpy(work.name, name);
139 work.data = mymalloc(size+1);
141 if (work.name) myfree(work.name);
144 memcpy(work.data, data, size);
145 work.data[size] = '\0'; /* convenience */
150 tags->tags[tags->count++] = work;
152 /*i_tags_print(tags);*/
158 =item i_tags_destroy(tags)
162 Destroys the given tags structure. Called by i_img_destroy().
167 void i_tags_destroy(i_img_tags *tags) {
170 for (i = 0; i < tags->count; ++i) {
171 if (tags->tags[i].name)
172 myfree(tags->tags[i].name);
173 if (tags->tags[i].data)
174 myfree(tags->tags[i].data);
181 =item i_tags_find(tags, name, start, &entry)
185 Searchs for a tag of the given I<name> starting from index I<start>.
187 On success returns true and sets *I<entry>.
189 On failure returns false.
194 int i_tags_find(i_img_tags *tags, char const *name, int start, int *entry) {
196 while (start < tags->count) {
197 if (tags->tags[start].name && strcmp(name, tags->tags[start].name) == 0) {
208 =item i_tags_findn(tags, code, start, &entry)
212 Searchs for a tag of the given I<code> starting from index I<start>.
214 On success returns true and sets *I<entry>.
216 On failure returns false.
221 int i_tags_findn(i_img_tags *tags, int code, int start, int *entry) {
223 while (start < tags->count) {
224 if (tags->tags[start].code == code) {
235 =item i_tags_delete(tags, index)
239 Delete a tag by index.
241 Returns true on success.
245 int i_tags_delete(i_img_tags *tags, int entry) {
246 /*printf("i_tags_delete(tags %p [count %d], entry %d)\n",
247 tags, tags->count, entry);*/
248 if (tags->tags && entry >= 0 && entry < tags->count) {
249 i_img_tag old = tags->tags[entry];
250 memmove(tags->tags+entry, tags->tags+entry+1,
251 (tags->count-entry-1) * sizeof(i_img_tag));
264 =item i_tags_delbyname(tags, name)
268 Delete any tags with the given name.
270 Returns the number of tags deleted.
275 int i_tags_delbyname(i_img_tags *tags, char const *name) {
278 /*printf("i_tags_delbyname(tags %p [count %d], name %s)\n",
279 tags, tags->count, name);*/
281 for (i = tags->count-1; i >= 0; --i) {
282 if (tags->tags[i].name && strcmp(name, tags->tags[i].name) == 0) {
284 i_tags_delete(tags, i);
288 /*i_tags_print(tags);*/
294 =item i_tags_delbycode(tags, code)
298 Delete any tags with the given code.
300 Returns the number of tags deleted.
305 int i_tags_delbycode(i_img_tags *tags, int code) {
309 for (i = tags->count-1; i >= 0; --i) {
310 if (tags->tags[i].code == code) {
312 i_tags_delete(tags, i);
320 =item i_tags_get_float(tags, name, code, value)
324 Retrieves a tag as a floating point value.
326 If the tag has a string value then that is parsed as a floating point
327 number, otherwise the integer value of the tag is used.
329 On success sets *I<value> and returns true.
331 On failure returns false.
336 int i_tags_get_float(i_img_tags *tags, char const *name, int code,
342 if (!i_tags_find(tags, name, 0, &index))
346 if (!i_tags_findn(tags, code, 0, &index))
349 entry = tags->tags+index;
351 *value = atof(entry->data);
353 *value = entry->idata;
359 =item i_tags_set_float(tags, name, code, value)
363 Equivalent to i_tags_set_float2(tags, name, code, value, 30).
368 int i_tags_set_float(i_img_tags *tags, char const *name, int code,
370 return i_tags_set_float2(tags, name, code, value, 30);
374 =item i_tags_set_float2(tags, name, code, value, places)
378 Sets the tag with the given name and code to the given floating point
381 Since tags are strings or ints, we convert the value to a string before
382 storage at the precision specified by C<places>.
387 int i_tags_set_float2(i_img_tags *tags, char const *name, int code,
388 double value, int places) {
393 else if (places > 30)
396 sprintf(temp, "%.*g", places, value);
398 i_tags_delbyname(tags, name);
400 i_tags_delbycode(tags, code);
402 return i_tags_add(tags, name, code, temp, strlen(temp), 0);
406 =item i_tags_get_int(tags, name, code, &value)
410 Retrieve a tag specified by name or code as an integer.
412 On success sets the int *I<value> to the integer and returns true.
414 On failure returns false.
419 int i_tags_get_int(i_img_tags *tags, char const *name, int code, int *value) {
424 if (!i_tags_find(tags, name, 0, &index))
428 if (!i_tags_findn(tags, code, 0, &index))
431 entry = tags->tags+index;
433 *value = atoi(entry->data);
435 *value = entry->idata;
440 static int parse_long(char *data, char **end, long *out) {
442 int savederr = errno;
446 result = strtol(data, &myend, 10);
447 if (((result == LONG_MIN || result == LONG_MAX) && errno == ERANGE)
460 /* parse a comma-separated list of integers
461 returns when it has maxcount numbers, finds a non-comma after a number
462 or can't parse a number
463 if it can't parse a number after a comma, that's considered an error
465 static int parse_long_list(char *data, char **end, int maxcount, long *out) {
469 while (i < maxcount-1) {
470 if (!parse_long(data, &data, out))
478 if (!parse_long(data, &data, out))
485 /* parse "color(red,green,blue,alpha)" */
486 static int parse_color(char *data, char **end, i_color *value) {
490 if (memcmp(data, "color(", 6))
491 return 0; /* not a color */
493 count = parse_long_list(data, &data, 4, n);
496 for (i = 0; i < count; ++i)
497 value->channel[i] = n[i];
499 value->channel[3] = 255;
505 =item i_tags_get_color(tags, name, code, &value)
509 Retrieve a tag specified by name or code as color.
511 On success sets the i_color *I<value> to the color and returns true.
513 On failure returns false.
518 int i_tags_get_color(i_img_tags *tags, char const *name, int code,
525 if (!i_tags_find(tags, name, 0, &index))
529 if (!i_tags_findn(tags, code, 0, &index))
532 entry = tags->tags+index;
536 if (!parse_color(entry->data, &end, value))
539 /* for now we're sloppy about the end */
545 =item i_tags_set_color(tags, name, code, &value)
549 Stores the given color as a tag with the given name and code.
554 int i_tags_set_color(i_img_tags *tags, char const *name, int code,
555 i_color const *value) {
558 sprintf(temp, "color(%d,%d,%d,%d)", value->channel[0], value->channel[1],
559 value->channel[2], value->channel[3]);
561 i_tags_delbyname(tags, name);
563 i_tags_delbycode(tags, code);
565 return i_tags_add(tags, name, code, temp, strlen(temp), 0);
569 =item i_tags_get_string(tags, name, code, value, value_size)
573 Retrieves a tag by name or code as a string.
575 On success copies the string to value for a max of value_size and
578 On failure returns false.
580 value_size must be at least large enough for a string representation
583 The copied value is always NUL terminated.
588 int i_tags_get_string(i_img_tags *tags, char const *name, int code,
589 char *value, size_t value_size) {
594 if (!i_tags_find(tags, name, 0, &index))
598 if (!i_tags_findn(tags, code, 0, &index))
601 entry = tags->tags+index;
603 size_t cpsize = value_size < entry->size ? value_size : entry->size;
604 memcpy(value, entry->data, cpsize);
605 if (cpsize == value_size)
607 value[cpsize] = '\0';
610 sprintf(value, "%d", entry->idata);
617 =item i_tags_set(tags, name, data, size)
621 Sets the given tag to the string I<data>
627 i_tags_set(i_img_tags *tags, char const *name, char const *data, int size) {
628 i_tags_delbyname(tags, name);
630 return i_tags_add(tags, name, 0, data, size, 0);
634 =item i_tags_setn(tags, name, idata)
638 Sets the given tag to the integer I<idata>
644 i_tags_setn(i_img_tags *tags, char const *name, int idata) {
645 i_tags_delbyname(tags, name);
647 return i_tags_addn(tags, name, 0, idata);
650 void i_tags_print(i_img_tags *tags) {
652 printf("Alloc %d\n", tags->alloc);
653 printf("Count %d\n", tags->count);
654 for (i = 0; i < tags->count; ++i) {
655 i_img_tag *tag = tags->tags + i;
656 printf("Tag %d\n", i);
658 printf(" Name : %s (%p)\n", tag->name, tag->name);
659 printf(" Code : %d\n", tag->code);
662 printf(" Data : %d (%p) => '", tag->size, tag->data);
663 for (pos = 0; pos < tag->size; ++pos) {
664 if (tag->data[pos] == '\\' || tag->data[pos] == '\'') {
666 putchar(tag->data[pos]);
668 else if (tag->data[pos] < ' ' || tag->data[pos] >= '\x7E')
669 printf("\\x%02X", tag->data[pos]);
671 putchar(tag->data[pos]);
674 printf(" Idata: %d\n", tag->idata);
684 Tony Cook <tony@develop-help.com>