1 /* Copyright (C) 2008, 2009 Vincent Penquerc'h.
2 This file is part of the Kate codec library.
3 Written by Vincent Penquerc'h.
4
5 Use, distribution and reproduction of this library is governed
6 by a BSD style source license included with this source in the
7 file 'COPYING'. Please read these terms before distributing. */
8
9
10 #define KATE_INTERNAL
11 #include "kate_internal.h"
12
13 #include <stdio.h>
14 #ifdef HAVE_STDLIB_H
15 #include <stdlib.h>
16 #endif
17 #ifdef HAVE_STRING_H
18 #include <string.h>
19 #endif
20 #include "kate/kate.h"
21
22 /**
23 \ingroup comments
24 Initializes a kate_comment structure.
25 \param kc the structure to initialize
26 \returns 0 success
27 \returns KATE_E_* error
28 */
kate_comment_init(kate_comment * kc)29 int kate_comment_init(kate_comment *kc)
30 {
31 if (!kc) return KATE_E_INVALID_PARAMETER;
32
33 kc->user_comments=NULL;
34 kc->comment_lengths=NULL;
35 kc->comments=0;
36 kc->vendor=NULL;
37
38 return 0;
39 }
40
41 /**
42 \ingroup comments
43 Destroys a kate_comment structure, it must be initialized again before being used.
44 \param kc the structure to clear
45 \returns 0 success
46 \returns KATE_E_* error
47 */
kate_comment_clear(kate_comment * kc)48 int kate_comment_clear(kate_comment *kc)
49 {
50 int n;
51
52 if (!kc) return KATE_E_INVALID_PARAMETER;
53
54 for (n=0;n<kc->comments;++n) kate_free(kc->user_comments[n]);
55 if (kc->user_comments) kate_free(kc->user_comments);
56 if (kc->comment_lengths) kate_free(kc->comment_lengths);
57 if (kc->vendor) kate_free(kc->vendor);
58
59 return 0;
60 }
61
kate_comment_check_tag(const char * tag,size_t len)62 static int kate_comment_check_tag(const char *tag,size_t len)
63 {
64 if (!tag) return KATE_E_INVALID_PARAMETER;
65
66 if (len==0) return KATE_E_BAD_TAG;
67 while (len--) {
68 int c=*tag++;
69 if (c<0x20 || c>0x7d || c=='=') return KATE_E_BAD_TAG;
70 }
71 return 0;
72 }
73
74 /**
75 \ingroup comments
76 Adds a comment to the kate_comment structure.
77 The comment must be of the form "tag=value"
78 The comment tag must be 7 bit ASCII, and may not contain embedded NULs
79 The comment value is UTF-8 and may contain embedded NULs
80 \param kc the kate_comment structure to add the comment to
81 \param comment the comment to add (a stream of len bytes)
82 \param len the number of bytes in the comment
83 \returns 0 success
84 \returns KATE_E_* error
85 */
kate_comment_add_length(kate_comment * kc,const char * comment,size_t len)86 int kate_comment_add_length(kate_comment *kc,const char *comment,size_t len)
87 {
88 int *cl;
89 char **uc;
90 const char *equals;
91 int ret;
92
93 if (!kc || !comment) return KATE_E_INVALID_PARAMETER;
94
95 ret=kate_check_add_overflow(kc->comments,1,NULL);
96 if (ret<0) return ret;
97 ret=kate_check_add_overflow(len,1,NULL);
98 if (ret<0) return ret;
99
100 equals=memchr(comment,'=',len);
101 if (!equals) return KATE_E_BAD_TAG;
102 ret=kate_comment_check_tag(comment,equals-comment);
103 if (ret<0) return ret;
104 ret=kate_text_validate(kate_utf8,equals,len-(equals-comment));
105 if (ret<0) return ret;
106
107 uc=kate_checked_realloc(kc->user_comments,(kc->comments+1),sizeof(char*));
108 if (!uc) return KATE_E_OUT_OF_MEMORY;
109 kc->user_comments=uc;
110 cl=kate_checked_realloc(kc->comment_lengths,(kc->comments+1),sizeof(int));
111 if (!cl) return KATE_E_OUT_OF_MEMORY;
112 kc->comment_lengths=cl;
113
114 kc->user_comments[kc->comments]=(char*)kate_malloc(len+1);
115 if (!kc->user_comments[kc->comments]) return KATE_E_OUT_OF_MEMORY;
116 memcpy(kc->user_comments[kc->comments],comment,len);
117 kc->user_comments[kc->comments][len]=0;
118 kc->comment_lengths[kc->comments]=len;
119
120 ++kc->comments;
121
122 return 0;
123 }
124
125 /**
126 \ingroup comments
127 Adds a comment to the kate_comment structure.
128 The comment must be of the form "tag=value"
129 The comment tag must be 7 bit ASCII, and may not contain embedded NULs
130 The comment value is UTF-8 and may not contain embedded NULs as the comments ends at the first NUL encountered
131 \param kc the kate_comment structure to add the comment to
132 \param comment the comment to add, NUL terminated
133 \returns 0 success
134 \returns KATE_E_* error
135 */
kate_comment_add(kate_comment * kc,const char * comment)136 int kate_comment_add(kate_comment *kc,const char *comment)
137 {
138 if (!kc || !comment) return KATE_E_INVALID_PARAMETER;
139
140 return kate_comment_add_length(kc,comment,strlen(comment));
141 }
142
143 /**
144 \ingroup comments
145 Adds a comment to the kate_comment structure, formatted as "tag=value".
146 The tag must be 7 bit ASCII and comply with Vorbis comment tag rules.
147 The value must be valid UTF-8 text.
148 Neither tag nor value may contain embedded NULs. To embed comments with
149 embedded NUL in the payload, see kate_comment_add_length.
150 \param kc the kate_comment structure to add the comment to
151 \param tag the tag of the comment to add
152 \param value the contents of the comment to add
153 \returns 0 success
154 \returns KATE_E_* error
155 */
kate_comment_add_tag(kate_comment * kc,const char * tag,const char * value)156 int kate_comment_add_tag(kate_comment *kc,const char *tag,const char *value)
157 {
158 char *comment;
159
160 if (!kc || !tag || !value) return KATE_E_INVALID_PARAMETER;
161
162 comment=(char*)kate_malloc(strlen(tag)+1+strlen(value)+1);
163 if (!comment) return KATE_E_OUT_OF_MEMORY;
164 sprintf(comment,"%s=%s",tag,value);
165 kate_comment_add(kc,comment);
166 kate_free(comment);
167
168 return 0;
169 }
170
171 /**
172 \ingroup comments
173 Queries the value of a comment that has the given tag.
174 The tags are case insensitive, so "tag", "TAG", "Tag", and "TaG" are all equivalent.
175 If there are multiple comments with the same tag, count may be used to
176 select which one to return.
177 The number of comments with a given tag may be retrieved using kate_comment_query_count.
178 \param kc the kate_comment structure to look into
179 \param tag the title of the comment to look for
180 \param count the index of the matching comment to return (if there are several)
181 \returns 0 success
182 \returns KATE_E_* error
183 */
kate_comment_query(const kate_comment * kc,const char * tag,int count)184 const char *kate_comment_query(const kate_comment *kc,const char *tag,int count)
185 {
186 int n;
187 size_t bytes;
188
189 if (!kc) return NULL;
190
191 for (n=0;n<kc->comments;++n) {
192 const char *eq=strchr(kc->user_comments[n],'=');
193 if (!eq) continue; /* wrong format */
194 bytes=eq-kc->user_comments[n];
195 if (!kate_ascii_strncasecmp(tag,kc->user_comments[n],bytes)) {
196 if (count==0) return eq+1;
197 --count;
198 }
199 }
200 /* not found */
201 return NULL;
202 }
203
204 /**
205 \ingroup comments
206 Returns the number of comments with the given tag.
207 The tags are case insensitive, so "tag", "TAG", "Tag", and "TaG" are all equivalent.
208 \param kc the kate_comment structure to look into
209 \param tag the title of the comment to look for
210 \returns 0 success
211 \returns KATE_E_* error
212 */
kate_comment_query_count(const kate_comment * kc,const char * tag)213 int kate_comment_query_count(const kate_comment *kc,const char *tag)
214 {
215 int n,count;
216 size_t bytes;
217
218 if (!kc) return KATE_E_INVALID_PARAMETER;
219
220 count=0;
221 for (n=0;n<kc->comments;++n) {
222 const char *eq=strchr(kc->user_comments[n],'=');
223 if (!eq) continue; /* wrong format */
224 bytes=eq-kc->user_comments[n];
225 if (!kate_ascii_strncasecmp(tag,kc->user_comments[n],bytes)) {
226 ++count;
227 }
228 }
229
230 return count;
231 }
232
233