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 #ifdef HAVE_STDLIB_H
14 #include <stdlib.h>
15 #endif
16 #ifdef HAVE_STRING_H
17 #include <string.h>
18 #endif
19 #include "kate/kate.h"
20 
21 /**
22   \ingroup info
23   Initializes a kate_info structure.
24   When done, it should be clear using kate_info_clear.
25   \param ki the kate_info structure to initialize
26   \returns 0 success
27   \returns KATE_E_* error
28   */
kate_info_init(kate_info * ki)29 int kate_info_init(kate_info *ki)
30 {
31   if (!ki) return KATE_E_INVALID_PARAMETER;
32 
33   ki->bitstream_version_major=KATE_BITSTREAM_VERSION_MAJOR;
34   ki->bitstream_version_minor=KATE_BITSTREAM_VERSION_MINOR;
35 
36   ki->num_headers=0;
37 
38   /* default to a sensible granule encoding */
39   ki->granule_shift=32;
40   ki->gps_numerator=1000;
41   ki->gps_denominator=1;
42 
43   ki->text_encoding=kate_utf8;
44   ki->text_directionality=kate_l2r_t2b;
45   ki->text_markup_type=kate_markup_none;
46 
47   ki->language=NULL;
48   ki->category=NULL;
49 
50   ki->nregions=0;
51   ki->regions=NULL;
52   ki->nstyles=0;
53   ki->styles=NULL;
54   ki->ncurves=0;
55   ki->curves=NULL;
56   ki->nmotions=0;
57   ki->motions=NULL;
58   ki->npalettes=0;
59   ki->palettes=NULL;
60   ki->nbitmaps=0;
61   ki->bitmaps=NULL;
62   ki->nfont_ranges=0;
63   ki->font_ranges=NULL;
64   ki->nfont_mappings=0;
65   ki->font_mappings=NULL;
66 
67   ki->original_canvas_width=0;
68   ki->original_canvas_height=0;
69 
70   ki->remove_markup=0;
71   ki->no_limits=0;
72   ki->probe=0;
73 
74   return 0;
75 }
76 
kate_make_fraction(kate_float resolution,kate_uint32_t * numerator,kate_uint32_t * denominator)77 static void kate_make_fraction(kate_float resolution,kate_uint32_t *numerator,kate_uint32_t *denominator)
78 {
79   if (resolution<1) {
80     *numerator=(kate_uint32_t)(1000/resolution+(kate_float)0.5);
81     *denominator=1000;
82   }
83   else {
84     *numerator=1000;
85     *denominator=(kate_uint32_t)(resolution*1000+(kate_float)0.5);
86   }
87 }
88 
89 /**
90   \ingroup info
91   Sets up the granule encoding parameters so that events may be timestamped with the given
92   resolution, and may not last longer than the given lifetime.
93   \param ki the kate_info structure to set the granule encoding parameters in.
94   \param resolution the timestamping resolution, in seconds (eg, 0.001 means millisecond resolution)
95   \param max_length the maximum time we need to represent, in seconds
96   \param max_event_lifetime the maximum time an event may last, in seconds
97   \returns 0 success
98   \returns KATE_E_* error
99   */
kate_info_set_granule_encoding(kate_info * ki,kate_float resolution,kate_float max_length,kate_float max_event_lifetime)100 int kate_info_set_granule_encoding(kate_info *ki,kate_float resolution,kate_float max_length,kate_float max_event_lifetime)
101 {
102   kate_float offset_granules;
103   unsigned char offset_bits,bits;
104   kate_float base_min_resolution;
105 
106   if (!ki || resolution<=0 || max_event_lifetime<0) return KATE_E_INVALID_PARAMETER;
107 
108   offset_granules=max_event_lifetime/resolution;
109   offset_bits=0;
110   while (offset_granules>=1) {
111     ++offset_bits;
112     if (offset_bits>=64) return KATE_E_BAD_GRANULE;
113     offset_granules/=2;
114   }
115 
116   base_min_resolution=max_length;
117   bits=offset_bits;
118   while (bits<62) {
119     ++bits;
120     base_min_resolution/=2;
121   }
122 
123   ki->granule_shift=offset_bits;
124   kate_make_fraction(resolution,&ki->gps_numerator,&ki->gps_denominator);
125 
126   if (base_min_resolution<=resolution) {
127     /* we can represent the required encoding */
128     return 0;
129   }
130   else {
131     /* we cannot represent the required encoding */
132     return KATE_E_BAD_GRANULE;
133   }
134 }
135 
kate_replace_string(char ** sptr,const char * s,size_t len)136 static int kate_replace_string(char **sptr,const char *s,size_t len)
137 {
138   char *l=NULL;
139   int ret;
140 
141   if (!sptr) return KATE_E_INVALID_PARAMETER;
142 
143   ret=kate_check_add_overflow(len,1,NULL);
144   if (ret<0) return ret;
145 
146   if (s) {
147     l=(char*)kate_malloc(len+1);
148     if (!l) return KATE_E_OUT_OF_MEMORY;
149     memcpy(l,s,len);
150     l[len]=0;
151   }
152 
153   if (*sptr) kate_free(*sptr);
154   *sptr=l;
155 
156   return 0;
157 }
158 
159 /**
160   \ingroup info
161   Sets the default language for this bitstream.
162   The language should be a RFC 3066 language tag (most of the time, a ISO 639-1
163   code, optionally followed by a country secondary tag).
164   This function does some basic validation, and will truncate the tag according
165   to RFC 4646 rules. However, it may still accept some invalid tags.
166   The maximum length of a language tag is 15 characters. If RFC 4646 truncation
167   is possible, the tag will be truncated. If not, it will be rejected.
168   In case of truncation, the tag that was actually set may be read back from
169   the language field of the kate_info structure.
170   \param ki the kate_info structure for the stream
171   \param language the default language to set for this stream
172   \returns 0 success
173   \returns 1 success, but the tag was truncated (the resulting tag may be read back from ki->language)
174   \returns KATE_E_* error
175   */
kate_info_set_language(kate_info * ki,const char * language)176 int kate_info_set_language(kate_info *ki,const char *language)
177 {
178   int ret;
179   size_t len;
180   size_t new_len;
181   const char *sep;
182   int truncated;
183 
184   if (!ki) return KATE_E_INVALID_PARAMETER;
185   if (!language) return KATE_E_INVALID_PARAMETER;
186 
187   /* special case for empty string */
188   if (!*language) {
189     return kate_replace_string(&ki->language,language,0);
190   }
191 
192   /* basic validation of allowed characters - won't catch all */
193   for (sep=language;*sep;++sep) {
194     int c=*sep;
195     if (c>='A' && c<='Z') continue;
196     if (c>='a' && c<='z') continue;
197     if (c>='0' && c<='9') continue;
198     if (c=='-' || c=='_') continue;
199     return KATE_E_INVALID_PARAMETER;
200   }
201 
202   /* simple validity - the first tag must be 2 characters */
203   sep=strpbrk(language,"-_");
204   if (!sep) sep=language+strlen(language);
205   if (sep-language==0 || sep-language>3) return KATE_E_INVALID_PARAMETER;
206 
207   /* if the tag is too long, it has to be truncated; while we still have space,
208      find the next - or _ following a tag of more than one character, and see
209      if we can fit it */
210   len=0;
211   new_len=0;
212   truncated=1;
213   while (truncated) {
214     size_t prev_new_len=new_len;
215     sep=strpbrk(language+new_len,"-_");
216     if (sep) {
217       new_len=sep-language;
218     }
219     else {
220       /* not found, gobble the remainder of the string */
221       new_len=strlen(language);
222       truncated=0;
223     }
224     /* maximum length of a subtag is 8 characters */
225     if (new_len-prev_new_len>8) {
226       return KATE_E_INVALID_PARAMETER;
227     }
228     if (new_len>15) {
229       /* we can't fit this new tag */
230       truncated=1;
231       break;
232     }
233     /* one or less character tags aren't allowed as the last tag */
234     if (new_len-prev_new_len>=2) {
235       /* so more than this is OK to keep */
236       len=new_len;
237     }
238     else {
239       /* but less we ignore if we have more to go, but complain if we're at the end */
240       if (!truncated) return KATE_E_INVALID_PARAMETER;
241     }
242     /* if we need another go, skip the separator */
243     ++new_len;
244   }
245 
246   if (len<=1) {
247     /* we can't fit any subtag, or the first tag is less than 2 characters long */
248     return KATE_E_INVALID_PARAMETER;
249   }
250 
251   ret=kate_replace_string(&ki->language,language,len);
252   if (ret<0) return ret;
253 
254   return truncated?1:0;
255 }
256 
257 /**
258   \ingroup info
259   Sets the default text directionality for this bitstream
260   \param ki the kate_info structure for the stream
261   \param text_directionality the default text directionality to set for this stream
262   \returns 0 success
263   \returns KATE_E_* error
264   */
kate_info_set_text_directionality(kate_info * ki,kate_text_directionality text_directionality)265 int kate_info_set_text_directionality(kate_info *ki,kate_text_directionality text_directionality)
266 {
267   if (!ki) return KATE_E_INVALID_PARAMETER;
268   ki->text_directionality=text_directionality;
269   return 0;
270 }
271 
272 /**
273   \ingroup info
274   Sets the category for this bitstream.
275   The category is an ASCII string limited to 15 characters.
276   Predefined categories include "subtitles", "lyrics", etc.
277   Categories prefixed with "x-" are reserved for private use.
278   \note Categories are not meant to be localized strings, but machine readable strings.
279   While they may be displayed to the user as is, players are encouraged to recognize
280   well known predefined categories such as the ones mentioned above, and supply
281   translation for these.
282   \param ki the kate_info structure for the stream
283   \param category the stream's category
284   \returns 0 success
285   \returns KATE_E_* error
286   */
kate_info_set_category(kate_info * ki,const char * category)287 int kate_info_set_category(kate_info *ki,const char *category)
288 {
289   if (!ki) return KATE_E_INVALID_PARAMETER;
290   if (!category) return KATE_E_INVALID_PARAMETER;
291   if (strlen(category)>15) return KATE_E_LIMIT;
292   return kate_replace_string(&ki->category,category,strlen(category));
293 }
294 
295 /**
296   \ingroup info
297   Sets the default text markup type for this bitstream
298   \param ki the kate_info structure for the stream
299   \param text_markup_type the default text markup type to set for this stream
300   \returns 0 success
301   \returns KATE_E_* error
302   */
kate_info_set_markup_type(kate_info * ki,kate_markup_type text_markup_type)303 int kate_info_set_markup_type(kate_info *ki,kate_markup_type text_markup_type)
304 {
305   if (!ki) return KATE_E_INVALID_PARAMETER;
306   ki->text_markup_type=text_markup_type;
307   return 0;
308 }
309 
310 /**
311   \ingroup info
312   Sets the size of the canvas this stream is being authored for
313   \param ki the kate_info structure for the stream
314   \param width the width of the canvas
315   \param height the height of the canvas
316   \returns 0 success
317   \returns KATE_E_* error
318   */
kate_info_set_original_canvas_size(kate_info * ki,size_t width,size_t height)319 int kate_info_set_original_canvas_size(kate_info *ki,size_t width,size_t height)
320 {
321   if (!ki) return KATE_E_INVALID_PARAMETER;
322   ki->original_canvas_width=width;
323   ki->original_canvas_height=height;
324   return 0;
325 }
326 
kate_info_add_item(kate_info * ki,size_t * nitems,void *** items,void * item)327 static int kate_info_add_item(kate_info *ki,size_t *nitems,void ***items,void *item)
328 {
329   void **newitems;
330   int ret;
331 
332   if (!ki || !nitems || !items || !item) return KATE_E_INVALID_PARAMETER;
333 
334   ret=kate_check_add_overflow(*nitems,1,NULL);
335   if (ret<0) return ret;
336 
337   newitems=(void**)kate_checked_realloc(*items,(*nitems)+1,sizeof(void*));
338   if (!newitems) return KATE_E_OUT_OF_MEMORY;
339   *items=newitems;
340   newitems[*nitems]=item;
341   ++*nitems;
342 
343   return 0;
344 }
345 
346 /**
347   \ingroup info
348   Adds a predefined region so it can be referred to by index later.
349   \param ki the kate_info structure for the stream
350   \param kr the region to add
351   \returns 0 success
352   \returns KATE_E_* error
353   */
kate_info_add_region(kate_info * ki,kate_region * kr)354 int kate_info_add_region(kate_info *ki,kate_region *kr)
355 {
356   return kate_info_add_item(ki,&ki->nregions,(void***)(char*)&ki->regions,kr);
357 }
358 
359 /**
360   \ingroup info
361   Adds a predefined style so it can be referred to by index later.
362   Adds a predefined region so it can be referred to by index later.
363   \param ki the kate_info structure for the stream
364   \param ks the style to add
365   \returns 0 success
366   \returns KATE_E_* error
367   */
kate_info_add_style(kate_info * ki,kate_style * ks)368 int kate_info_add_style(kate_info *ki,kate_style *ks)
369 {
370   return kate_info_add_item(ki,&ki->nstyles,(void***)(char*)&ki->styles,ks);
371 }
372 
373 /**
374   \ingroup info
375   Adds a predefined curve so it can be referred to by index later.
376   \param ki the kate_info structure for the stream
377   \param kc the curve to add
378   \returns 0 success
379   \returns KATE_E_* error
380   */
kate_info_add_curve(kate_info * ki,kate_curve * kc)381 int kate_info_add_curve(kate_info *ki,kate_curve *kc)
382 {
383   return kate_info_add_item(ki,&ki->ncurves,(void***)(char*)&ki->curves,kc);
384 }
385 
386 /**
387   \ingroup info
388   Adds a predefined motion so it can be referred to by index later.
389   \param ki the kate_info structure for the stream
390   \param km the motion to add
391   \returns 0 success
392   \returns KATE_E_* error
393   */
kate_info_add_motion(kate_info * ki,kate_motion * km)394 int kate_info_add_motion(kate_info *ki,kate_motion *km)
395 {
396   return kate_info_add_item(ki,&ki->nmotions,(void***)(char*)&ki->motions,km);
397 }
398 
399 /**
400   \ingroup info
401   Adds a predefined palette so it can be referred to by index later.
402   \param ki the kate_info structure for the stream
403   \param kp the palette to add
404   \returns 0 success
405   \returns KATE_E_* error
406   */
kate_info_add_palette(kate_info * ki,kate_palette * kp)407 int kate_info_add_palette(kate_info *ki,kate_palette *kp)
408 {
409   return kate_info_add_item(ki,&ki->npalettes,(void***)(char*)&ki->palettes,kp);
410 }
411 
412 /**
413   \ingroup info
414   Adds a predefined bitmap so it can be referred to by index later.
415   \param ki the kate_info structure for the stream
416   \param kb the bitmap to add
417   \returns 0 success
418   \returns KATE_E_* error
419   */
kate_info_add_bitmap(kate_info * ki,kate_bitmap * kb)420 int kate_info_add_bitmap(kate_info *ki,kate_bitmap *kb)
421 {
422   return kate_info_add_item(ki,&ki->nbitmaps,(void***)(char*)&ki->bitmaps,kb);
423 }
424 
425 /**
426   \ingroup info
427   Adds a predefined font range so it can be referred to by index later.
428   \param ki the kate_info structure for the stream
429   \param kfr the font range to add
430   \returns 0 success
431   \returns KATE_E_* error
432   */
kate_info_add_font_range(kate_info * ki,kate_font_range * kfr)433 int kate_info_add_font_range(kate_info *ki,kate_font_range *kfr)
434 {
435   return kate_info_add_item(ki,&ki->nfont_ranges,(void***)(char*)&ki->font_ranges,kfr);
436 }
437 
438 /**
439   \ingroup info
440   Adds a predefined font mapping so it can be referred to by index later.
441   \param ki the kate_info structure for the stream
442   \param kfm the font mapping to add
443   \returns 0 success
444   \returns KATE_E_* error
445   */
kate_info_add_font_mapping(kate_info * ki,kate_font_mapping * kfm)446 int kate_info_add_font_mapping(kate_info *ki,kate_font_mapping *kfm)
447 {
448   return kate_info_add_item(ki,&ki->nfont_mappings,(void***)(char*)&ki->font_mappings,kfm);
449 }
450 
451 /**
452   \ingroup info
453   Checks whether the given language matches (fully or partially) the language
454   described in the kate_info structure.
455   Exact (case insensitive) matching of the two languages is required for a perfect match.
456   Exact (case insensitive) matching of the primary tags for each language (which each
457   may or may not have one or more secondary tags) is required for a partial match.
458   An empty language for either the stream language or the language passed as parameter
459   will cause a partial match.
460   \param ki the kate_info structure for the stream
461   \param language the language to check against
462   \returns 0 success, but the language doesn't match
463   \returns 1 success, the language matches perfectly
464   \returns 2 success, the language matches partially
465   \returns KATE_E_* error
466   */
kate_info_matches_language(const kate_info * ki,const char * language)467 int kate_info_matches_language(const kate_info *ki,const char *language)
468 {
469   char *sep0,*sep1;
470   size_t bytes;
471   if (!ki) return KATE_E_INVALID_PARAMETER;
472 
473   if (!language || !*language) return 2; /* if we ask for "any" language, we partially match */
474   if (!ki->language || !*ki->language) return 2; /* if the stream has no set language, it partially matches all */
475 
476   if (!kate_ascii_strncasecmp(ki->language,language,0xffffffff)) return 1; /* perfect match */
477 
478   /* if we specify a language with no subtag, it matches any subtag of the same language */
479   sep0=strpbrk(ki->language,"-_");
480   sep1=strpbrk(language,"-_");
481   if (!sep0 && !sep1) {
482     /* if none of the languages have subtags, they're different, or they'd have been picked
483        up by the first string comparison */
484     return 0; /* doesn't match */
485   }
486 
487   if (sep0 && sep1) {
488     /* if both have subtags, the primary tag must be the same length */
489     if (sep1-language!=sep0-ki->language) return 0; /* doesn't match */
490   }
491 
492   /* we now have primary tags to compare (with or without secondary tags), of the same length */
493   bytes=sep0?sep0-ki->language:sep1-language;
494 
495   if (!kate_ascii_strncasecmp(ki->language,language,bytes)) return 2; /* partial match */
496 
497   return 0; /* doesn't match */
498 }
499 
500 /**
501   \ingroup info
502   Requests whether future events will strip text of markup or not.
503   \param ki the kate_info structure for the stream
504   \param flag if zero, markup will be kept, else if will be removed
505   \returns 0 success
506   \returns KATE_E_* error
507   */
kate_info_remove_markup(kate_info * ki,int flag)508 int kate_info_remove_markup(kate_info *ki,int flag)
509 {
510   if (!ki) return KATE_E_INVALID_PARAMETER;
511   ki->remove_markup=flag;
512   return 0;
513 }
514 
515 /**
516   \ingroup info
517   Requests whether large quantities of various things should be rejected or not,
518   as a simple defense against DOS.
519   \param ki the kate_info structure for the stream
520   \param flag if zero, values deemed arbitrarily too large will be treated as an error, else they will be accepted
521   \returns 0 success
522   \returns KATE_E_* error
523   */
kate_info_no_limits(kate_info * ki,int flag)524 int kate_info_no_limits(kate_info *ki,int flag)
525 {
526   if (!ki) return KATE_E_INVALID_PARAMETER;
527   ki->no_limits=flag;
528   return 0;
529 }
530 
531 /**
532   \ingroup info
533   Clears a kate_info structure previously initialized with kate_info_init.
534   It may not be used again until kate_info_init is called again on it.
535   \param ki the kate_info structure to clear, must have been initialized with kate_info_init
536   \returns 0 success
537   \returns KATE_E_* error
538   */
kate_info_clear(kate_info * ki)539 int kate_info_clear(kate_info *ki)
540 {
541   size_t n,l;
542 
543   if (!ki) return KATE_E_INVALID_PARAMETER;
544 
545   if (ki->bitmaps) {
546     for (n=0;n<ki->nbitmaps;++n) {
547       if (ki->bitmaps[n]->internal) {
548         if (ki->bitmaps[n]->meta) kate_meta_destroy(ki->bitmaps[n]->meta);
549       }
550       kate_free(ki->bitmaps[n]->pixels);
551       kate_free(ki->bitmaps[n]);
552     }
553     kate_free(ki->bitmaps);
554   }
555   if (ki->palettes) {
556     for (n=0;n<ki->npalettes;++n) {
557       if (ki->palettes[n]->meta) kate_meta_destroy(ki->palettes[n]->meta);
558       kate_free(ki->palettes[n]->colors);
559       kate_free(ki->palettes[n]);
560     }
561     kate_free(ki->palettes);
562   }
563   if (ki->motions) {
564     kate_motion_destroy(ki,ki->motions,NULL,ki->nmotions,1);
565   }
566   if (ki->curves) {
567     for (n=0;n<ki->ncurves;++n) {
568       kate_free(ki->curves[n]->pts);
569       kate_free(ki->curves[n]);
570     }
571     kate_free(ki->curves);
572   }
573   if (ki->regions) {
574     for (n=0;n<ki->nregions;++n) {
575       if (ki->regions[n]->meta) kate_meta_destroy(ki->regions[n]->meta);
576       kate_free(ki->regions[n]);
577     }
578     kate_free(ki->regions);
579   }
580   if (ki->styles) {
581     for (n=0;n<ki->nstyles;++n) {
582       kate_style *ks=ki->styles[n];
583       if (ks->meta) kate_meta_destroy(ks->meta);
584       if (ks->font) kate_free(ks->font);
585       kate_free(ks);
586     }
587     kate_free(ki->styles);
588   }
589   if (ki->language) kate_free(ki->language);
590   if (ki->category) kate_free(ki->category);
591   if (ki->font_mappings) {
592     for (n=0;n<ki->nfont_mappings;++n) {
593       kate_font_mapping *kfm=ki->font_mappings[n];
594       if (kfm->ranges) {
595         for (l=0;l<kfm->nranges;++l) {
596           int idx=kate_find_font_range(ki,kfm->ranges[l]);
597           if (idx<0) kate_free(kfm->ranges[l]);
598         }
599         kate_free(kfm->ranges);
600       }
601       kate_free(kfm);
602     }
603     kate_free(ki->font_mappings);
604   }
605   if (ki->font_ranges) {
606     for (n=0;n<ki->nfont_ranges;++n) kate_free(ki->font_ranges[n]);
607     kate_free(ki->font_ranges);
608   }
609 
610   return 0;
611 }
612 
kate_find_item(const void * item,const void ** items,size_t nitems)613 static int kate_find_item(const void *item,const void **items,size_t nitems)
614 {
615   size_t n;
616 
617   if (!item) return KATE_E_INVALID_PARAMETER;
618 
619   if (!items) return KATE_E_NOT_FOUND; /* if nothing in the list, it may be NULL */
620   for (n=0;n<nitems;++n) if (item==items[n]) return n;
621   return KATE_E_NOT_FOUND;
622 }
623 
kate_find_region(const kate_info * ki,const kate_region * kr)624 int kate_find_region(const kate_info *ki,const kate_region *kr)
625 {
626   return kate_find_item(kr,(const void**)ki->regions,ki->nregions);
627 }
628 
kate_find_style(const kate_info * ki,const kate_style * ks)629 int kate_find_style(const kate_info *ki,const kate_style *ks)
630 {
631   return kate_find_item(ks,(const void**)ki->styles,ki->nstyles);
632 }
633 
kate_find_curve(const kate_info * ki,const kate_curve * kc)634 int kate_find_curve(const kate_info *ki,const kate_curve *kc)
635 {
636   return kate_find_item(kc,(const void**)ki->curves,ki->ncurves);
637 }
638 
kate_find_motion(const kate_info * ki,const kate_motion * km)639 int kate_find_motion(const kate_info *ki,const kate_motion *km)
640 {
641   return kate_find_item(km,(const void**)ki->motions,ki->nmotions);
642 }
643 
kate_find_palette(const kate_info * ki,const kate_palette * kp)644 int kate_find_palette(const kate_info *ki,const kate_palette *kp)
645 {
646   return kate_find_item(kp,(const void**)ki->palettes,ki->npalettes);
647 }
648 
kate_find_bitmap(const kate_info * ki,const kate_bitmap * kb)649 int kate_find_bitmap(const kate_info *ki,const kate_bitmap *kb)
650 {
651   return kate_find_item(kb,(const void**)ki->bitmaps,ki->nbitmaps);
652 }
653 
kate_find_font_range(const kate_info * ki,const kate_font_range * kfr)654 int kate_find_font_range(const kate_info *ki,const kate_font_range *kfr)
655 {
656   return kate_find_item(kfr,(const void**)ki->font_ranges,ki->nfont_ranges);
657 }
658 
kate_find_font_mapping(const kate_info * ki,const kate_font_mapping * kfm)659 int kate_find_font_mapping(const kate_info *ki,const kate_font_mapping *kfm)
660 {
661   return kate_find_item(kfm,(const void**)ki->font_mappings,ki->nfont_mappings);
662 }
663 
664