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