1 :
2 : #include "mime_types.h"
3 :
4 : #define EX_UTILS_NO_FUNCS 1
5 : #include "ex_utils.h"
6 :
7 : #include "mk.h"
8 :
9 : #if COMPILE_DEBUG
10 : # define MIME_TYPES__INIT_SECT_SZ 2
11 : # define MIME_TYPES__INIT_TYPE_SZ 2
12 : #else
13 : # define MIME_TYPES__INIT_SECT_SZ 128
14 : # define MIME_TYPES__INIT_TYPE_SZ 64
15 : #endif
16 :
17 : static Vstr_sect_node *mime_types__srch(Mime_types_data *mime,
18 : const Vstr_base *fname,
19 : size_t pos, size_t len)
20 3884 : {
21 3884 : unsigned int num = 0;
22 :
23 1942 : ASSERT(fname && len && mime->ents->num);
24 :
25 3884 : num = mime->ents->num - 1; /* FIXME: off by one for addition */
26 142648 : while (num)
27 : {
28 134980 : size_t epos = VSTR_SECTS_NUM(mime->ents, num)->pos;
29 134980 : size_t elen = VSTR_SECTS_NUM(mime->ents, num)->len;
30 134980 : unsigned int ext_num = num;
31 :
32 134980 : --num;
33 134980 : --num;
34 :
35 134980 : if (vstr_cmp_eq(fname, pos, len, mime->ent_data, epos, elen))
36 100 : return (VSTR_SECTS_NUM(mime->ents, ext_num));
37 : }
38 :
39 3784 : return (NULL);
40 : }
41 :
42 : static void mime_type__type_add(Mime_types_data *mime, unsigned char type)
43 3884 : {
44 1942 : MALLOC_CHECK_SZ_MEM(mime->types, mime->type_sz);
45 :
46 1942 : ASSERT(mime->type_num <= mime->type_sz);
47 :
48 3884 : if (mime->type_num >= mime->type_sz)
49 : {
50 203 : unsigned char *tmp = NULL;
51 203 : unsigned int sz = mime->type_sz * 2;
52 :
53 203 : if (!MV(mime->types, tmp, sz))
54 : {
55 0 : mime->ents->malloc_bad = TRUE;
56 0 : return;
57 : }
58 :
59 203 : mime->type_sz = sz;
60 : }
61 :
62 3884 : mime->types[mime->type_num++] = type;
63 :
64 1942 : ASSERT(mime->type_num <= mime->type_sz);
65 : }
66 :
67 : int mime_types_load_simple(Mime_types *pmime, const char *fname)
68 140 : {
69 140 : Mime_types_data *mime = pmime->ref->ptr;
70 140 : size_t orig_ent_data_len = mime->ent_data->len;
71 140 : unsigned int orig_ents_num = mime->ents->num;
72 140 : Vstr_base *data = NULL;
73 140 : Vstr_sects *lines = NULL;
74 140 : unsigned int num = 0;
75 140 : Vstr_sects *sects = NULL;
76 140 : size_t data_pos = 0;
77 140 : size_t data_len = 0;
78 140 : int saved_errno = ENOMEM;
79 :
80 70 : ASSERT(pmime && pmime->ref && (pmime->ref->ref == 1));
81 :
82 140 : if (!fname || !*fname)
83 28 : return (TRUE);
84 :
85 112 : if (!(data = vstr_make_base(NULL)))
86 0 : goto fail_data;
87 :
88 112 : if (!(lines = vstr_sects_make(128)))
89 0 : goto fail_sects_lines;
90 :
91 112 : if (!(sects = vstr_sects_make(4)))
92 0 : goto fail_sects_tmp;
93 :
94 112 : if (!vstr_sc_read_len_file(data, data_pos, fname, 0, 0, NULL))
95 0 : goto fail_read_file;
96 :
97 112 : data_len = data->len - data_pos++;
98 112 : vstr_split_cstr_buf(data, data_pos, data_len, "\n", lines, 0, 0);
99 112 : if (lines->malloc_bad)
100 0 : goto fail_split_file;
101 :
102 2932 : while (++num <= lines->num)
103 : {
104 2764 : size_t pos = VSTR_SECTS_NUM(lines, num)->pos;
105 2764 : size_t len = VSTR_SECTS_NUM(lines, num)->len;
106 2764 : Vstr_sect_node *sct = NULL;
107 :
108 2764 : if (vstr_export_chr(data, pos) == '#')
109 526 : continue;
110 :
111 2238 : sects->num = 0;
112 2238 : vstr_split_cstr_chrs(data, pos, len, " \t", sects, 0, 0);
113 2238 : if (sects->malloc_bad)
114 0 : goto fail_split_line;
115 :
116 7241 : while (sects->num > 1)
117 : {
118 3884 : Vstr_sect_node *sext = VSTR_SECTS_NUM(sects, sects->num);
119 3884 : size_t spos = 0;
120 3884 : size_t slen = 0;
121 3884 : Vstr_sect_node *old_sext = NULL;
122 3884 : unsigned char type = MIME_TYPES_TYPE_END;
123 :
124 3884 : if (!sct)
125 : {
126 1982 : sct = VSTR_SECTS_NUM(sects, 1);
127 1982 : spos = mime->ent_data->len + 1;
128 1982 : vstr_add_vstr(mime->ent_data, mime->ent_data->len,
129 : data, sct->pos, sct->len, VSTR_TYPE_ADD_DEF);
130 1982 : sct->pos = spos;
131 : }
132 3884 : vstr_sects_add(mime->ents, sct->pos, sct->len);
133 :
134 3884 : if (vstr_export_chr(data, sext->pos) != '.')
135 : {
136 3044 : if (!vstr_srch_chr_fwd(data, sext->pos + 1, sext->len - 1, '.'))
137 2792 : type = MIME_TYPES_TYPE_EXT1;
138 :
139 3044 : vstr_add_cstr_buf(mime->ent_data, mime->ent_data->len, ".");
140 3044 : spos = mime->ent_data->len;
141 3044 : slen = sext->len + 1;
142 : }
143 : else
144 : { /* chop the . off and use everything else */
145 840 : sext->len--; sext->pos++;
146 840 : spos = mime->ent_data->len + 1;
147 840 : slen = sext->len;
148 : }
149 :
150 3884 : vstr_add_vstr(mime->ent_data, mime->ent_data->len,
151 : data, sext->pos, sext->len, VSTR_TYPE_ADD_DEF);
152 :
153 : /* replace old versions ... so we can match forwards */
154 3884 : if ((old_sext = mime_types__srch(mime, mime->ent_data, spos, slen)))
155 100 : old_sext->len = 0;
156 :
157 3884 : vstr_sects_add(mime->ents, spos, slen);
158 3884 : mime_type__type_add(mime, type);
159 3884 : sects->num--;
160 : }
161 : }
162 :
163 112 : if (mime->ent_data->conf->malloc_bad || mime->ents->malloc_bad)
164 : goto fail_end_malloc_check;
165 :
166 112 : vstr_sects_free(sects);
167 112 : vstr_sects_free(lines);
168 112 : vstr_free_base(data);
169 :
170 112 : return (TRUE);
171 :
172 0 : fail_end_malloc_check:
173 0 : vstr_sc_reduce(mime->ent_data, 1, mime->ent_data->len,
174 : mime->ent_data->len - orig_ent_data_len);
175 0 : mime->ents->num = orig_ents_num;
176 0 : fail_split_line:
177 0 : fail_split_file:
178 0 : errno = ENOMEM;
179 0 : fail_read_file:
180 0 : saved_errno = errno;
181 0 : vstr_sects_free(lines);
182 0 : fail_sects_tmp:
183 0 : vstr_sects_free(sects);
184 0 : fail_sects_lines:
185 0 : vstr_free_base(data);
186 0 : fail_data:
187 0 : errno = saved_errno;
188 0 : return (FALSE);
189 : }
190 :
191 : static void mime_types__filedata_free(Vstr_ref *ref)
192 144 : {
193 :
194 144 : Mime_types_data *mime = ref->ptr;
195 :
196 144 : vstr_free_base(mime->ent_data); mime->ent_data = NULL;
197 144 : vstr_sects_free(mime->ents); mime->ents = NULL;
198 144 : F(mime->types); mime->types = NULL;
199 :
200 144 : (*mime->pref_func)(ref);
201 144 : }
202 :
203 : int mime_types_init(Mime_types *pmime,
204 : const Vstr_base *def_vs1, size_t def_pos, size_t def_len)
205 138 : {
206 138 : Mime_types_data *mime = NULL;
207 :
208 69 : ASSERT(pmime);
209 69 : ASSERT(def_vs1);
210 :
211 138 : if (!(pmime->ref = vstr_ref_make_malloc(sizeof(Mime_types_data))))
212 0 : goto ref_malloc_fail;
213 138 : mime = pmime->ref->ptr;
214 :
215 138 : if (!(mime->ent_data = vstr_make_base(NULL)))
216 0 : goto ent_data_malloc_fail;
217 :
218 138 : if (!(mime->ents = vstr_sects_make(MIME_TYPES__INIT_SECT_SZ)))
219 0 : goto ents_malloc_fail;
220 :
221 138 : if (!(mime->types = MK(MIME_TYPES__INIT_TYPE_SZ)))
222 0 : goto types_malloc_fail;
223 :
224 138 : mime->type_sz = MIME_TYPES__INIT_TYPE_SZ;
225 138 : mime->type_num = 0;
226 :
227 : /* make reference do the right thing... */
228 138 : mime->pref_func = pmime->ref->func;
229 138 : pmime->ref->func = mime_types__filedata_free;
230 :
231 138 : pmime->def_type_vs1 = def_vs1;
232 138 : pmime->def_type_pos = def_pos;
233 138 : pmime->def_type_len = def_len;
234 :
235 138 : return (TRUE);
236 :
237 0 : types_malloc_fail:
238 0 : vstr_sects_free(mime->ents);
239 0 : ents_malloc_fail:
240 0 : vstr_free_base(mime->ent_data);
241 0 : ent_data_malloc_fail:
242 0 : vstr_ref_del(pmime->ref);
243 0 : ref_malloc_fail:
244 0 : return (FALSE);
245 : }
246 :
247 : int mime_types_match(const Mime_types *pmime,
248 : const Vstr_base *fname, size_t pos, size_t len,
249 : const Vstr_base **ret_vs1, size_t *ret_pos,size_t *ret_len)
250 26305 : {
251 26305 : const Mime_types_data *mime = NULL;
252 26305 : unsigned int num = 0;
253 26305 : size_t pos_ext1 = 0;
254 26305 : size_t len_ext1 = 0;
255 26305 : size_t tmp = 0;
256 :
257 13160 : ASSERT(pmime && pmime->ref && (pmime->ref->ref >= 1));
258 13160 : ASSERT(ret_vs1 && ret_pos && ret_len);
259 :
260 26305 : mime = pmime->ref->ptr;
261 :
262 13160 : MALLOC_CHECK_SZ_MEM(mime->types, mime->type_sz);
263 :
264 : /* find extension */
265 26305 : tmp = vstr_srch_chr_rev(fname, pos, len, '.');
266 26305 : if ((pos_ext1 = tmp))
267 25208 : len_ext1 = len - (pos_ext1 - pos);
268 :
269 786587 : while (num++ < mime->ents->num)
270 : {
271 769489 : size_t ctpos = VSTR_SECTS_NUM(mime->ents, num)->pos;
272 769489 : size_t ctlen = VSTR_SECTS_NUM(mime->ents, num)->len;
273 769489 : size_t epos = 0;
274 769489 : size_t elen = 0;
275 769489 : unsigned char type = mime->types[num / 2];
276 :
277 385352 : ASSERT(mime->type_num <= mime->type_sz);
278 385352 : ASSERT(mime->type_num > (num / 2));
279 385352 : ASSERT(num < mime->ents->num);
280 769489 : ++num;
281 769489 : epos = VSTR_SECTS_NUM(mime->ents, num)->pos;
282 769489 : elen = VSTR_SECTS_NUM(mime->ents, num)->len;
283 :
284 769489 : if (!elen || (elen > len))
285 15176 : continue;
286 :
287 739167 : switch (type)
288 : {
289 : case MIME_TYPES_TYPE_EXT1:
290 616341 : if (vstr_cmp_eq(fname, pos_ext1, len_ext1, mime->ent_data, epos, elen))
291 : {
292 21872 : *ret_vs1 = mime->ent_data;
293 21872 : *ret_pos = ctpos;
294 21872 : *ret_len = ctlen;
295 21872 : return (TRUE);
296 : }
297 297632 : ASSERT(!vstr_cmp_eod_eq(fname, pos, len, mime->ent_data, epos, elen));
298 296837 : break;
299 :
300 : case MIME_TYPES_TYPE_EXT2:
301 : case MIME_TYPES_TYPE_EXT3:
302 : case MIME_TYPES_TYPE_END:
303 122826 : if (vstr_cmp_eod_eq(fname, pos, len, mime->ent_data, epos, elen))
304 : {
305 480 : *ret_vs1 = mime->ent_data;
306 480 : *ret_pos = ctpos;
307 480 : *ret_len = ctlen;
308 480 : return (TRUE);
309 : }
310 :
311 0 : ASSERT_NO_SWITCH_DEF();
312 : }
313 : }
314 :
315 3953 : *ret_vs1 = pmime->def_type_vs1;
316 3953 : *ret_pos = pmime->def_type_pos;
317 3953 : *ret_len = pmime->def_type_len;
318 3953 : return (FALSE);
319 : }
320 :
321 : void mime_types_exit(Mime_types *pmime)
322 144 : {
323 72 : ASSERT(pmime && pmime->ref);
324 144 : vstr_ref_del(pmime->ref); pmime->ref = NULL;
325 144 : }
326 :
327 : void mime_types_combine_filedata(Mime_types *pdst, Mime_types *psrc)
328 68 : {
329 68 : Vstr_ref *tmp = NULL;
330 :
331 34 : ASSERT(psrc && psrc->ref && (psrc->ref->ref >= 1));
332 34 : ASSERT(pdst && pdst->ref && (pdst->ref->ref == 1));
333 :
334 68 : tmp = pdst->ref;
335 68 : pdst->ref = vstr_ref_add(psrc->ref);
336 68 : vstr_ref_del(tmp);
337 68 : }
|