(* Mime type detection and table parsing module *) (* by Travis Bemann *) (* *) (* This program is free software; you can redistribute it and/or *) (* modify it under the terms of the GNU Lesser General Public *) (* License as published by the Free Software Foundation; either *) (* version 2 of the License, or (at your option) any later version. *) (* *) (* This program is distributed in the hope that it will be useful, *) (* but WITHOUT ANY WARRANTY; without even the implied warranty of *) (* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *) (* GNU Lesser General Public License for more details. *) let hash_start_size = 1024 let strip_init_dot str = if String.length str > 0 then if String.get str 0 = '.' then Str.string_after str 1 else str else "" class mimetypes files (log : Log.log_type) = object (self) val types = Hashtbl.create hash_start_size method lookup suffix = if String.length suffix > 0 then if String.get suffix 0 = '.' then Hashtbl.find types (Str.string_after suffix 1) else Hashtbl.find types suffix else raise Not_found method lookup_filename name = if String.length name > 0 then let name = if String.get name 0 = '.' then Str.string_after name 1 else name in try let off = String.index name '.' in self#lookup_comp (Str.string_after name (off + 1)) with Not_found -> (* Yes, this looks weird, but this is to emphasize that the * intent is to handle the Not_found exception raised by * String.index, and Not_found just happens to be the * exception used by lookup_filename to indicate no known * mimetype exists for a particular filename *) raise Not_found else raise Not_found method private lookup_comp suffix = if String.length suffix > 0 then try self#lookup suffix with Not_found -> try let off = String.index suffix '.' in self#lookup_comp (Str.string_after suffix (off + 1)) with Not_found -> (* Yes, this looks weird, but this is to emphasize that the * intent is to handle the Not_found exception raised by * String.index, and Not_found just happens to be the * exception used by lookup_filename to indicate no known * mimetype exists for a particular filename *) raise Not_found else raise Not_found method private load file = try let file_in = open_in file in self#load_lines file file_in; close_in file_in with Sys_error _ -> log#log Log.Msg_error (file ^ ": unable to open or read") method private load_lines file file_in = try let line = input_line file_in in let line_real = Strutil.strip begin try let off = String.index line '#' in Str.string_before line off with Not_found -> line end in if line_real <> "" then let parts = Str.split (Str.regexp "[ \t]+") line_real in try let suffix = strip_init_dot (List.nth parts 0) and mimetype = List.nth parts 1 in begin try let _ = Hashtbl.find types suffix in () with Not_found -> Hashtbl.add types suffix mimetype end; self#load_lines file file_in with Failure _ -> log#log Log.Msg_error (Printf.sprintf "liber: %s: unable to parse line \"%s\"\n" file line); self#load_lines file file_in else self#load_lines file file_in with End_of_file -> () method private load_defaults = let rec step = function (suffix, mimetype) :: rest -> begin try let _ = Hashtbl.find types suffix in () with Not_found -> Hashtbl.add types suffix mimetype end; step rest | [] -> () in step Mimetype_default.mappings initializer List.iter (fun file -> self#load file) files; self#load_defaults end