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