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 #include "kate_meta.h"
22
kate_meta_init(kate_meta * km)23 static int kate_meta_init(kate_meta *km)
24 {
25 if (!km) return KATE_E_INVALID_PARAMETER;
26
27 km->nmeta=0;
28 km->meta=NULL;
29
30 return 0;
31 }
32
33 /**
34 \ingroup meta
35 Creates and initializes a kate_meta_list structure.
36 \param km the structure to initialize
37 \returns 0 success
38 \returns KATE_E_* error
39 */
kate_meta_create(kate_meta ** km)40 int kate_meta_create(kate_meta **km)
41 {
42 kate_meta *tmp;
43 int ret;
44
45 if (!km) return KATE_E_INVALID_PARAMETER;
46
47 tmp=(kate_meta*)kate_malloc(sizeof(kate_meta));
48 if (!tmp) return KATE_E_OUT_OF_MEMORY;
49
50 ret=kate_meta_init(tmp);
51 if (ret<0) {
52 kate_free(tmp);
53 return ret;
54 }
55
56 *km=tmp;
57
58 return 0;
59 }
60
kate_meta_clear(kate_meta * km)61 static int kate_meta_clear(kate_meta *km)
62 {
63 size_t n;
64
65 if (!km) return KATE_E_INVALID_PARAMETER;
66
67 for (n=0;n<km->nmeta;++n) {
68 kate_meta_leaf *kml=km->meta+n;
69 kate_free(kml->tag);
70 kate_free(kml->value);
71 }
72 kate_free(km->meta);
73
74 return 0;
75 }
76
77 /**
78 \ingroup meta
79 Destroys a kate_meta structure.
80 \param km the structure to destroy
81 \returns 0 success
82 \returns KATE_E_* error
83 */
kate_meta_destroy(kate_meta * km)84 int kate_meta_destroy(kate_meta *km)
85 {
86 if (!km) return KATE_E_INVALID_PARAMETER;
87 kate_meta_clear(km);
88 kate_free(km);
89 return 0;
90 }
91
kate_meta_check_tag(const char * tag)92 static int kate_meta_check_tag(const char *tag)
93 {
94 if (!tag || !*tag) return KATE_E_INVALID_PARAMETER;
95
96 while (*tag) {
97 int c=*tag++;
98 if (c<0x20 || c>0x7d || c=='=') return KATE_E_BAD_TAG;
99 }
100 return 0;
101 }
102
103 /**
104 \ingroup meta
105 Adds a tag/value metadata pair to the kate_meta structure.
106 The tag must be 7 bit ASCII, and may not contain embedded NULs
107 The value is binary data, and dependent on the tag.
108 Text values should be UTF-8 and may contain embedded NULs
109 \param km the kate_meta structure to add the metadata to
110 \param tag the tag for the metadata add
111 \param value the value for the metadata add (a stream of len bytes)
112 \param len the number of bytes in the value
113 \returns 0 success
114 \returns KATE_E_* error
115 */
kate_meta_add(kate_meta * km,const char * tag,const char * value,size_t len)116 int kate_meta_add(kate_meta *km,const char *tag,const char *value,size_t len)
117 {
118 kate_meta_leaf *meta;
119 char *mtag,*mvalue;
120 int ret;
121
122 if (!km || !tag || !value) return KATE_E_INVALID_PARAMETER;
123
124 ret=kate_check_add_overflow(km->nmeta,1,NULL);
125 if (ret<0) return ret;
126 ret=kate_check_add_overflow(len,1,NULL);
127 if (ret<0) return ret;
128
129 ret=kate_meta_check_tag(tag);
130 if (ret<0) return ret;
131
132 meta=(kate_meta_leaf*)kate_checked_realloc(km->meta,(km->nmeta+1),sizeof(kate_meta_leaf));
133 if (!meta) return KATE_E_OUT_OF_MEMORY;
134 km->meta=meta;
135
136 mtag=kate_malloc(strlen(tag)+1);
137 if (!mtag) return KATE_E_OUT_OF_MEMORY;
138 strcpy(mtag,tag);
139 mvalue=kate_malloc(len);
140 if (!mvalue) {
141 kate_free(mtag);
142 return KATE_E_OUT_OF_MEMORY;
143 }
144 memcpy(mvalue,value,len);
145
146 km->meta[km->nmeta].tag=mtag;
147 km->meta[km->nmeta].value=mvalue;
148 km->meta[km->nmeta].len=len;
149
150 ++km->nmeta;
151
152 return 0;
153 }
154
155 /**
156 \ingroup meta
157 Adds a tag/value metadata pair to the kate_meta structure.
158 \param km the kate_meta structure to add the metadata to
159 \param tag the tag for the metadata add
160 \param value the value for the metadata add (a NUL terminated UTF-8 string)
161 \returns 0 success
162 \returns KATE_E_* error
163 */
kate_meta_add_string(kate_meta * km,const char * tag,const char * value)164 int kate_meta_add_string(kate_meta *km,const char *tag,const char *value)
165 {
166 size_t len;
167 int ret;
168
169 if (!value) return KATE_E_INVALID_PARAMETER;
170
171 len=strlen(value)+1;
172 ret=kate_text_validate(kate_utf8,value,len);
173 if (ret<0) return ret;
174
175 return kate_meta_add(km,tag,value,len);
176 }
177
178 /**
179 \ingroup meta
180 Retrieves the data for a given metadata.
181 \param km the kate_meta structure to search in
182 \param tag the tag to search for
183 \param idx the index of the tag to search for (eg, if a tag is present more than once)
184 \param value where to store the value of the tag
185 \param len where to store the length (in bytes) of the value
186 \returns 0 success
187 \returns KATE_E_* error
188 */
kate_meta_query_tag(const kate_meta * km,const char * tag,unsigned int idx,const char ** value,size_t * len)189 int kate_meta_query_tag(const kate_meta *km,const char *tag,unsigned int idx,const char **value,size_t *len)
190 {
191 size_t n;
192
193 if (!km || !tag) return KATE_E_INVALID_PARAMETER;
194
195 for (n=0;n<km->nmeta;++n) {
196 if (!kate_ascii_strcasecmp(tag,km->meta[n].tag)) {
197 if (idx==0) {
198 if (value) *value=km->meta[n].value;
199 if (len) *len=km->meta[n].len;
200 return 0;
201 }
202 --idx;
203 }
204 }
205 return KATE_E_INVALID_PARAMETER;
206 }
207
208 /**
209 \ingroup meta
210 Retrieves the data for a given metadata.
211 \param km the kate_meta structure to search in
212 \param idx the index of the metadata to get data for
213 \param tag where to store the tag of the metadata
214 \param value where to store the value of the tag
215 \param len where to store the length (in bytes) of the value
216 \returns 0 success
217 \returns KATE_E_* error
218 */
kate_meta_query(const kate_meta * km,unsigned int idx,const char ** tag,const char ** value,size_t * len)219 int kate_meta_query(const kate_meta *km,unsigned int idx,const char **tag,const char **value,size_t *len)
220 {
221 if (!km || idx>=km->nmeta) return KATE_E_INVALID_PARAMETER;
222
223 if (tag) *tag=km->meta[idx].tag;
224 if (value) *value=km->meta[idx].value;
225 if (len) *len=km->meta[idx].len;
226 return 0;
227 }
228
229 /**
230 \ingroup meta
231 Returns the number of metadata with the given tag
232 \param km the kate_meta structure to search in
233 \param tag the tag to search for
234 \returns 0 success, no matching tags were found
235 \returns >0 success, the value is the number of tags found
236 \returns KATE_E_* error
237 */
kate_meta_query_tag_count(const kate_meta * km,const char * tag)238 int kate_meta_query_tag_count(const kate_meta *km,const char *tag)
239 {
240 size_t n;
241 int count=0;
242 int ret;
243
244 if (!km || !tag) return KATE_E_INVALID_PARAMETER;
245
246 ret=kate_meta_check_tag(tag);
247 if (ret<0) return ret;
248
249 for (n=0;n<km->nmeta;++n) {
250 if (!kate_ascii_strcasecmp(tag,km->meta[n].tag)) ++count;
251 }
252 return count;
253 }
254
255 /**
256 \ingroup meta
257 Returns the number of metadata in this structure
258 \param km the kate_meta structure to search in
259 \returns 0 success, no metadata is present
260 \returns >0 success, the value is the number of metadata found
261 \returns KATE_E_* error
262 */
kate_meta_query_count(const kate_meta * km)263 int kate_meta_query_count(const kate_meta *km)
264 {
265 if (!km) return KATE_E_INVALID_PARAMETER;
266
267 return km->nmeta;
268 }
269
270 /**
271 \ingroup meta
272 Removes a given metadata pair.
273 \param km the kate_meta structure to change
274 \param tag the tag to search for, may be NULL to match any tag
275 \param idx the index of the metadata
276 \returns 0 success
277 \returns KATE_E_* error
278 */
kate_meta_remove_tag(kate_meta * km,const char * tag,unsigned int idx)279 int kate_meta_remove_tag(kate_meta *km,const char *tag,unsigned int idx)
280 {
281 size_t n;
282
283 if (!km) return KATE_E_INVALID_PARAMETER;
284
285 for (n=0;n<km->nmeta;++n) {
286 if (!tag || !kate_ascii_strcasecmp(tag,km->meta[n].tag)) {
287 if (idx==0) {
288 kate_free(km->meta[n].tag);
289 kate_free(km->meta[n].value);
290 if (n+1!=km->nmeta) memmove(km->meta+n,km->meta+n+1,(km->nmeta-n-1)*sizeof(kate_meta_leaf));
291 --km->nmeta;
292 return 0;
293 }
294 --idx;
295 }
296 }
297 return KATE_E_INVALID_PARAMETER;
298 }
299
300 /**
301 \ingroup meta
302 Removes a given metadata pair.
303 \param km the kate_meta structure to change
304 \param idx the index of the metadata
305 \returns 0 success
306 \returns KATE_E_* error
307 */
kate_meta_remove(kate_meta * km,unsigned int idx)308 int kate_meta_remove(kate_meta *km,unsigned int idx)
309 {
310 if (!km || idx>=km->nmeta) return KATE_E_INVALID_PARAMETER;
311
312 kate_free(km->meta[idx].tag);
313 kate_free(km->meta[idx].value);
314 if (idx+1!=km->nmeta) memmove(km->meta+idx,km->meta+idx+1,(km->nmeta-idx-1)*sizeof(kate_meta_leaf));
315 --km->nmeta;
316 return 0;
317 }
318
319 /**
320 \ingroup meta
321 Merges two sets of metadata together
322 \param km the kate_meta structure to contain the merged metadata.
323 \param km2 the kate_meta structure to merge to km. It will be freed if this call is successful.
324 \returns 0 success
325 \returns KATE_E_* error
326 */
kate_meta_merge(kate_meta * km,kate_meta * km2)327 int kate_meta_merge(kate_meta *km,kate_meta *km2)
328 {
329 kate_meta_leaf *tmp;
330 size_t count,n;
331 int ret;
332
333 if (!km || !km2) return KATE_E_INVALID_PARAMETER;
334 if (km2->nmeta==0) return 0;
335
336 ret=kate_check_add_overflow(km->nmeta,km2->nmeta,&count);
337 if (ret<0) return ret;
338 tmp=(kate_meta_leaf*)kate_checked_realloc(km->meta,count,sizeof(kate_meta_leaf));
339 if (!tmp) return KATE_E_OUT_OF_MEMORY;
340
341 for (n=0;n<km2->nmeta;++n) {
342 tmp[km->nmeta+n]=km2->meta[n];
343 }
344 kate_free(km2->meta);
345
346 km->meta=tmp;
347 km->nmeta+=km2->nmeta;
348
349 kate_free(km2);
350
351 return 0;
352 }
353
kate_meta_create_copy(kate_meta ** km,const kate_meta * km2)354 int kate_meta_create_copy(kate_meta **km,const kate_meta *km2)
355 {
356 kate_meta *tmp;
357 kate_meta_leaf *kml;
358 size_t n;
359 int ret;
360
361 ret=kate_meta_create(&tmp);
362 if (ret<0) return ret;
363 kml=km2->meta;
364 for (n=0;n<km2->nmeta;++n,++kml) {
365 ret=kate_meta_add(tmp,kml->tag,kml->value,kml->len);
366 if (ret<0) {
367 kate_meta_destroy(tmp);
368 return ret;
369 }
370 }
371 *km=tmp;
372 return 0;
373 }
374
375