1 
2 #include "mime_types.h"
3 
4 #define EX_UTILS_NO_FUNCS 1
5 #include "ex_utils.h"
6 
mime_types__srch(Mime_types_data * mime,const Vstr_base * fname,size_t pos,size_t len)7 static Vstr_sect_node *mime_types__srch(Mime_types_data *mime,
8                                         const Vstr_base *fname,
9                                         size_t pos, size_t len)
10 {
11   unsigned int num = 0;
12 
13   ASSERT(fname && len && mime->ents->num);
14 
15   num = mime->ents->num - 1; /* FIXME: off by one for addition */
16   while (num)
17   {
18     size_t epos  = VSTR_SECTS_NUM(mime->ents, num)->pos;
19     size_t elen  = VSTR_SECTS_NUM(mime->ents, num)->len;
20     unsigned int ext_num = num;
21 
22     --num;
23     --num;
24 
25     if (vstr_cmp_eq(fname, pos, len, mime->ent_data, epos, elen))
26       return (VSTR_SECTS_NUM(mime->ents, ext_num));
27   }
28 
29   return (NULL);
30 }
31 
mime_types_load_simple(Mime_types * pmime,const char * fname)32 int mime_types_load_simple(Mime_types *pmime, const char *fname)
33 {
34   Mime_types_data *mime = pmime->ref->ptr;
35   size_t orig_ent_data_len   = mime->ent_data->len;
36   unsigned int orig_ents_num = mime->ents->num;
37   Vstr_base *data = NULL;
38   Vstr_sects *lines = NULL;
39   unsigned int num = 0;
40   Vstr_sects *sects = NULL;
41   size_t data_pos = 0;
42   size_t data_len = 0;
43   int saved_errno = ENOMEM;
44 
45   ASSERT(pmime && pmime->ref && (pmime->ref->ref == 1));
46 
47   if (!fname || !*fname)
48     return (TRUE);
49 
50   if (!(data = vstr_make_base(NULL)))
51     goto fail_data;
52 
53   if (!(lines = vstr_sects_make(128)))
54     goto fail_sects_lines;
55 
56   if (!(sects = vstr_sects_make(4)))
57     goto fail_sects_tmp;
58 
59   if (!vstr_sc_read_len_file(data, data_pos, fname, 0, 0, NULL))
60     goto fail_read_file;
61 
62   data_len = data->len - data_pos++;
63   vstr_split_cstr_buf(data, data_pos, data_len, "\n", lines, 0, 0);
64   if (lines->malloc_bad)
65     goto fail_split_file;
66 
67   while (++num <= lines->num)
68   {
69     size_t pos = VSTR_SECTS_NUM(lines, num)->pos;
70     size_t len = VSTR_SECTS_NUM(lines, num)->len;
71     Vstr_sect_node *sct = NULL;
72 
73     if (vstr_export_chr(data, pos) == '#')
74       continue;
75 
76     sects->num = 0;
77     vstr_split_cstr_chrs(data, pos, len, " \t", sects, 0, 0);
78     if (sects->malloc_bad)
79       goto fail_split_line;
80 
81     while (sects->num > 1)
82     {
83       Vstr_sect_node *sext = VSTR_SECTS_NUM(sects, sects->num);
84       size_t spos = 0;
85       size_t slen = 0;
86       Vstr_sect_node *old_sext = NULL;
87 
88       if (!sct)
89       {
90         sct = VSTR_SECTS_NUM(sects, 1);
91         spos = mime->ent_data->len + 1;
92         vstr_add_vstr(mime->ent_data, mime->ent_data->len,
93                       data, sct->pos, sct->len, VSTR_TYPE_ADD_DEF);
94         sct->pos = spos;
95       }
96       vstr_sects_add(mime->ents, sct->pos, sct->len);
97 
98       if (vstr_export_chr(data, sext->pos) != '.')
99       {
100         vstr_add_cstr_buf(mime->ent_data, mime->ent_data->len, ".");
101         spos = mime->ent_data->len;
102         slen = sext->len + 1;
103       }
104       else
105       { /* chop the . off and use everything else */
106         sext->len--; sext->pos++;
107         spos = mime->ent_data->len + 1;
108         slen = sext->len;
109       }
110 
111       vstr_add_vstr(mime->ent_data, mime->ent_data->len,
112                     data, sext->pos, sext->len, VSTR_TYPE_ADD_DEF);
113 
114       /* replace old versions ... so we can match forwards */
115       if ((old_sext = mime_types__srch(mime, mime->ent_data, spos, slen)))
116         old_sext->len = 0;
117 
118       vstr_sects_add(mime->ents, spos, slen);
119       sects->num--;
120     }
121   }
122 
123   if (mime->ent_data->conf->malloc_bad || mime->ents->malloc_bad)
124     goto fail_end_malloc_check;
125 
126   vstr_sects_free(sects);
127   vstr_sects_free(lines);
128   vstr_free_base(data);
129 
130   return (TRUE);
131 
132  fail_end_malloc_check:
133   vstr_sc_reduce(mime->ent_data, 1, mime->ent_data->len,
134                  mime->ent_data->len - orig_ent_data_len);
135   mime->ents->num = orig_ents_num;
136  fail_split_line:
137  fail_split_file:
138   errno = ENOMEM;
139  fail_read_file:
140   saved_errno = errno;
141   vstr_sects_free(lines);
142  fail_sects_tmp:
143   vstr_sects_free(sects);
144  fail_sects_lines:
145   vstr_free_base(data);
146  fail_data:
147   errno = saved_errno;
148   return (FALSE);
149 }
150 
mime_types__filedata_free(Vstr_ref * ref)151 static void mime_types__filedata_free(Vstr_ref *ref)
152 {
153 
154   Mime_types_data *mime = ref->ptr;
155 
156   vstr_free_base(mime->ent_data); mime->ent_data = NULL;
157   vstr_sects_free(mime->ents);    mime->ents     = NULL;
158 
159   (*mime->pref_func)(ref);
160 }
161 
mime_types_init(Mime_types * pmime,const Vstr_base * def_vs1,size_t def_pos,size_t def_len)162 int mime_types_init(Mime_types *pmime,
163                     const Vstr_base *def_vs1, size_t def_pos, size_t def_len)
164 {
165   Mime_types_data *mime = NULL;
166 
167   ASSERT(pmime);
168   ASSERT(def_vs1);
169 
170   if (!(pmime->ref = vstr_ref_make_malloc(sizeof(Mime_types_data))))
171     goto ref_malloc_fail;
172   mime = pmime->ref->ptr;
173 
174   if (!(mime->ent_data = vstr_make_base(NULL)))
175     goto ent_data_malloc_fail;
176 
177   if (!(mime->ents = vstr_sects_make(128)))
178     goto ents_malloc_fail;
179 
180   /* make reference do the right thing... */
181   mime->pref_func  = pmime->ref->func;
182   pmime->ref->func = mime_types__filedata_free;
183 
184   pmime->def_type_vs1 = def_vs1;
185   pmime->def_type_pos = def_pos;
186   pmime->def_type_len = def_len;
187 
188   return (TRUE);
189 
190  ents_malloc_fail:
191   vstr_free_base(mime->ent_data);
192  ent_data_malloc_fail:
193   vstr_ref_del(pmime->ref);
194  ref_malloc_fail:
195   return (FALSE);
196 }
197 
mime_types_match(const Mime_types * pmime,const Vstr_base * fname,size_t pos,size_t len,const Vstr_base ** ret_vs1,size_t * ret_pos,size_t * ret_len)198 int mime_types_match(const Mime_types *pmime,
199                      const Vstr_base *fname, size_t pos, size_t len,
200                      const Vstr_base **ret_vs1, size_t *ret_pos,size_t *ret_len)
201 {
202   const Mime_types_data *mime = NULL;
203   unsigned int num = 0;
204 
205   ASSERT(pmime && pmime->ref && (pmime->ref->ref >= 1));
206   ASSERT(ret_vs1 && ret_pos && ret_len);
207 
208   mime = pmime->ref->ptr;
209   while (num++ < mime->ents->num)
210   {
211     size_t ctpos = VSTR_SECTS_NUM(mime->ents, num)->pos;
212     size_t ctlen = VSTR_SECTS_NUM(mime->ents, num)->len;
213     size_t epos  = 0;
214     size_t elen  = 0;
215 
216     ASSERT(num < mime->ents->num);
217     ++num;
218     epos  = VSTR_SECTS_NUM(mime->ents, num)->pos;
219     elen  = VSTR_SECTS_NUM(mime->ents, num)->len;
220 
221     if (!elen || (elen > len))
222       continue;
223 
224     if (vstr_cmp_eod_eq(fname, pos, len, mime->ent_data, epos, elen))
225     {
226       *ret_vs1 = mime->ent_data;
227       *ret_pos = ctpos;
228       *ret_len = ctlen;
229       return (TRUE);
230     }
231   }
232 
233   *ret_vs1 = pmime->def_type_vs1;
234   *ret_pos = pmime->def_type_pos;
235   *ret_len = pmime->def_type_len;
236   return (FALSE);
237 }
238 
mime_types_exit(Mime_types * pmime)239 void mime_types_exit(Mime_types *pmime)
240 {
241   ASSERT(pmime && pmime->ref);
242   vstr_ref_del(pmime->ref);       pmime->ref = NULL;
243 }
244 
mime_types_combine_filedata(Mime_types * pdst,Mime_types * psrc)245 void mime_types_combine_filedata(Mime_types *pdst, Mime_types *psrc)
246 {
247   Vstr_ref *tmp = NULL;
248 
249   ASSERT(psrc && psrc->ref && (psrc->ref->ref >= 1));
250   ASSERT(pdst && pdst->ref && (pdst->ref->ref == 1));
251 
252   tmp = pdst->ref;
253   pdst->ref = vstr_ref_add(psrc->ref);
254   vstr_ref_del(tmp);
255 }
256