1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65
|
// SPDX-License-Identifier: MPL-2.0
// (c) Hare authors <https://harelang.org>
use hash::fnv;
use strings;
// A pair of a Media Type and a list of file extensions associated with it. The
// extension list does not include the leading '.' character.
export type mimetype = struct {
mime: str,
exts: []str,
};
// List of media types with statically allocated fields (though the list itself
// is dynamically allocated).
let static_db: []*mimetype = [];
// List of media types with heap-allocated fields, used when loading mime types
// from the system database.
let heap_db: []*mimetype = [];
def MIME_BUCKETS: size = 256;
// Hash tables for efficient database lookup by mimetype or extension
let mimetable: [MIME_BUCKETS][]*mimetype = [[]...];
let exttable: [MIME_BUCKETS][]*mimetype = [[]...];
// Frees a [[mimetype]] and all resources associated with it.
export fn mimetype_free(m: *mimetype) void = {
free(m.mime);
strings::freeall(m.exts);
free(m);
};
// Registers a Media Type and its extensions in the internal MIME database. This
// function is designed to be used by @init functions for modules which
// implement new Media Types. The input is expected to be statically allocated
// and is never freed.
export fn register(mime: *mimetype...) (void | nomem) = {
let i = len(static_db);
append(static_db, mime...)?;
for (i < len(static_db); i += 1) {
hashtable_insert(static_db[i])?;
};
};
fn hashtable_insert(item: *mimetype) (void | nomem) = {
const hash = fnv::string(item.mime);
let bucket = &mimetable[hash % len(mimetable)];
append(bucket, item)?;
for (let ext .. item.exts) {
const hash = fnv::string(ext);
let bucket = &exttable[hash % len(exttable)];
append(bucket, item)?;
};
};
@fini fn fini() void = {
for (let m .. heap_db) {
mimetype_free(m);
};
free(heap_db);
free(static_db);
};
|