mime_types.c
#include "mime_types.h"
#define EX_UTILS_NO_FUNCS 1
#include "ex_utils.h"
#include "mk.h"
#if COMPILE_DEBUG
# define MIME_TYPES__INIT_SECT_SZ 2
# define MIME_TYPES__INIT_TYPE_SZ 2
#else
# define MIME_TYPES__INIT_SECT_SZ 128
# define MIME_TYPES__INIT_TYPE_SZ 64
#endif
static Vstr_sect_node *mime_types__srch(Mime_types_data *mime,
const Vstr_base *fname,
size_t pos, size_t len)
{
unsigned int num = 0;
ASSERT(fname && len && mime->ents->num);
num = mime->ents->num - 1;
while (num)
{
size_t epos = VSTR_SECTS_NUM(mime->ents, num)->pos;
size_t elen = VSTR_SECTS_NUM(mime->ents, num)->len;
unsigned int ext_num = num;
--num;
--num;
if (vstr_cmp_eq(fname, pos, len, mime->ent_data, epos, elen))
return (VSTR_SECTS_NUM(mime->ents, ext_num));
}
return (NULL);
}
static void mime_type__type_add(Mime_types_data *mime, unsigned char type)
{
MALLOC_CHECK_SZ_MEM(mime->types, mime->type_sz);
ASSERT(mime->type_num <= mime->type_sz);
if (mime->type_num >= mime->type_sz)
{
unsigned char *tmp = NULL;
unsigned int sz = mime->type_sz * 2;
if (!MV(mime->types, tmp, sz))
{
mime->ents->malloc_bad = TRUE;
return;
}
mime->type_sz = sz;
}
mime->types[mime->type_num++] = type;
ASSERT(mime->type_num <= mime->type_sz);
}
int mime_types_load_simple(Mime_types *pmime, const char *fname)
{
Mime_types_data *mime = pmime->ref->ptr;
size_t orig_ent_data_len = mime->ent_data->len;
unsigned int orig_ents_num = mime->ents->num;
Vstr_base *data = NULL;
Vstr_sects *lines = NULL;
unsigned int num = 0;
Vstr_sects *sects = NULL;
size_t data_pos = 0;
size_t data_len = 0;
int saved_errno = ENOMEM;
ASSERT(pmime && pmime->ref && (pmime->ref->ref == 1));
if (!fname || !*fname)
return (TRUE);
if (!(data = vstr_make_base(NULL)))
goto fail_data;
if (!(lines = vstr_sects_make(128)))
goto fail_sects_lines;
if (!(sects = vstr_sects_make(4)))
goto fail_sects_tmp;
if (!vstr_sc_read_len_file(data, data_pos, fname, 0, 0, NULL))
goto fail_read_file;
data_len = data->len - data_pos++;
vstr_split_cstr_buf(data, data_pos, data_len, "\n", lines, 0, 0);
if (lines->malloc_bad)
goto fail_split_file;
while (++num <= lines->num)
{
size_t pos = VSTR_SECTS_NUM(lines, num)->pos;
size_t len = VSTR_SECTS_NUM(lines, num)->len;
Vstr_sect_node *sct = NULL;
if (vstr_export_chr(data, pos) == '#')
continue;
sects->num = 0;
vstr_split_cstr_chrs(data, pos, len, " \t", sects, 0, 0);
if (sects->malloc_bad)
goto fail_split_line;
while (sects->num > 1)
{
Vstr_sect_node *sext = VSTR_SECTS_NUM(sects, sects->num);
size_t spos = 0;
size_t slen = 0;
Vstr_sect_node *old_sext = NULL;
unsigned char type = MIME_TYPES_TYPE_END;
if (!sct)
{
sct = VSTR_SECTS_NUM(sects, 1);
spos = mime->ent_data->len + 1;
vstr_add_vstr(mime->ent_data, mime->ent_data->len,
data, sct->pos, sct->len, VSTR_TYPE_ADD_DEF);
sct->pos = spos;
}
vstr_sects_add(mime->ents, sct->pos, sct->len);
if (vstr_export_chr(data, sext->pos) != '.')
{
if (!vstr_srch_chr_fwd(data, sext->pos + 1, sext->len - 1, '.'))
type = MIME_TYPES_TYPE_EXT1;
vstr_add_cstr_buf(mime->ent_data, mime->ent_data->len, ".");
spos = mime->ent_data->len;
slen = sext->len + 1;
}
else
{
sext->len--; sext->pos++;
spos = mime->ent_data->len + 1;
slen = sext->len;
}
vstr_add_vstr(mime->ent_data, mime->ent_data->len,
data, sext->pos, sext->len, VSTR_TYPE_ADD_DEF);
if ((old_sext = mime_types__srch(mime, mime->ent_data, spos, slen)))
old_sext->len = 0;
vstr_sects_add(mime->ents, spos, slen);
mime_type__type_add(mime, type);
sects->num--;
}
}
if (mime->ent_data->conf->malloc_bad || mime->ents->malloc_bad)
goto fail_end_malloc_check;
vstr_sects_free(sects);
vstr_sects_free(lines);
vstr_free_base(data);
return (TRUE);
fail_end_malloc_check:
vstr_sc_reduce(mime->ent_data, 1, mime->ent_data->len,
mime->ent_data->len - orig_ent_data_len);
mime->ents->num = orig_ents_num;
fail_split_line:
fail_split_file:
errno = ENOMEM;
fail_read_file:
saved_errno = errno;
vstr_sects_free(lines);
fail_sects_tmp:
vstr_sects_free(sects);
fail_sects_lines:
vstr_free_base(data);
fail_data:
errno = saved_errno;
return (FALSE);
}
static void mime_types__filedata_free(Vstr_ref *ref)
{
Mime_types_data *mime = ref->ptr;
vstr_free_base(mime->ent_data); mime->ent_data = NULL;
vstr_sects_free(mime->ents); mime->ents = NULL;
F(mime->types); mime->types = NULL;
(*mime->pref_func)(ref);
}
int mime_types_init(Mime_types *pmime,
const Vstr_base *def_vs1, size_t def_pos, size_t def_len)
{
Mime_types_data *mime = NULL;
ASSERT(pmime);
ASSERT(def_vs1);
if (!(pmime->ref = vstr_ref_make_malloc(sizeof(Mime_types_data))))
goto ref_malloc_fail;
mime = pmime->ref->ptr;
if (!(mime->ent_data = vstr_make_base(NULL)))
goto ent_data_malloc_fail;
if (!(mime->ents = vstr_sects_make(MIME_TYPES__INIT_SECT_SZ)))
goto ents_malloc_fail;
if (!(mime->types = MK(MIME_TYPES__INIT_TYPE_SZ)))
goto types_malloc_fail;
mime->type_sz = MIME_TYPES__INIT_TYPE_SZ;
mime->type_num = 0;
mime->pref_func = pmime->ref->func;
pmime->ref->func = mime_types__filedata_free;
pmime->def_type_vs1 = def_vs1;
pmime->def_type_pos = def_pos;
pmime->def_type_len = def_len;
return (TRUE);
types_malloc_fail:
vstr_sects_free(mime->ents);
ents_malloc_fail:
vstr_free_base(mime->ent_data);
ent_data_malloc_fail:
vstr_ref_del(pmime->ref);
ref_malloc_fail:
return (FALSE);
}
int 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)
{
const Mime_types_data *mime = NULL;
unsigned int num = 0;
size_t pos_ext1 = 0;
size_t len_ext1 = 0;
size_t tmp = 0;
ASSERT(pmime && pmime->ref && (pmime->ref->ref >= 1));
ASSERT(ret_vs1 && ret_pos && ret_len);
mime = pmime->ref->ptr;
MALLOC_CHECK_SZ_MEM(mime->types, mime->type_sz);
tmp = vstr_srch_chr_rev(fname, pos, len, '.');
if ((pos_ext1 = tmp))
len_ext1 = len - (pos_ext1 - pos);
while (num++ < mime->ents->num)
{
size_t ctpos = VSTR_SECTS_NUM(mime->ents, num)->pos;
size_t ctlen = VSTR_SECTS_NUM(mime->ents, num)->len;
size_t epos = 0;
size_t elen = 0;
unsigned char type = mime->types[num / 2];
ASSERT(mime->type_num <= mime->type_sz);
ASSERT(mime->type_num > (num / 2));
ASSERT(num < mime->ents->num);
++num;
epos = VSTR_SECTS_NUM(mime->ents, num)->pos;
elen = VSTR_SECTS_NUM(mime->ents, num)->len;
if (!elen || (elen > len))
continue;
switch (type)
{
case MIME_TYPES_TYPE_EXT1:
if (vstr_cmp_eq(fname, pos_ext1, len_ext1, mime->ent_data, epos, elen))
{
*ret_vs1 = mime->ent_data;
*ret_pos = ctpos;
*ret_len = ctlen;
return (TRUE);
}
ASSERT(!vstr_cmp_eod_eq(fname, pos, len, mime->ent_data, epos, elen));
break;
case MIME_TYPES_TYPE_EXT2:
case MIME_TYPES_TYPE_EXT3:
case MIME_TYPES_TYPE_END:
if (vstr_cmp_eod_eq(fname, pos, len, mime->ent_data, epos, elen))
{
*ret_vs1 = mime->ent_data;
*ret_pos = ctpos;
*ret_len = ctlen;
return (TRUE);
}
ASSERT_NO_SWITCH_DEF();
}
}
*ret_vs1 = pmime->def_type_vs1;
*ret_pos = pmime->def_type_pos;
*ret_len = pmime->def_type_len;
return (FALSE);
}
void mime_types_exit(Mime_types *pmime)
{
ASSERT(pmime && pmime->ref);
vstr_ref_del(pmime->ref); pmime->ref = NULL;
}
void mime_types_combine_filedata(Mime_types *pdst, Mime_types *psrc)
{
Vstr_ref *tmp = NULL;
ASSERT(psrc && psrc->ref && (psrc->ref->ref >= 1));
ASSERT(pdst && pdst->ref && (pdst->ref->ref == 1));
tmp = pdst->ref;
pdst->ref = vstr_ref_add(psrc->ref);
vstr_ref_del(tmp);
}