(* This file is part of licht. licht is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. licht 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 General Public License for more details. You should have received a copy of the GNU General Public License along with licht. If not, see . *) module NS = Odf_ns type tree = | Data of string | Cell of {repetition: int; cell_width: int; expression: Expression.t} | Unit let memoization cache key f = begin try Hashtbl.find cache key with Not_found -> let value = f key in Hashtbl.add cache key value; value end let load_content cache content = begin function | "float" -> Expression.Basic ( ScTypes.Type.number ( DataType.Num.of_float (float_of_string content) )) | "date" -> Expression.Basic ( ScTypes.Type.date ( DataType.Num.of_float (float_of_string content) )) | _ -> (* If the same text is present many times, use the same string instead of creating a new one *) memoization cache content (fun content -> Expression.Basic ( ScTypes.Type.string ( UTF8.from_utf8string content))) end let load_formula formula = let lineBuffer = Lexing.from_string formula in try Expression.Formula ( Expression.Expression ( Odf_ExpressionParser.value Odf_ExpressionLexer.read lineBuffer)) with e -> print_endline formula; raise e let build_cell cache (attributes:Xmlm.attribute list) (childs:tree list) = begin (* Check if the content is repeated *) let repetition = try int_of_string @@ List.assoc NS.number_columns_repeat_attr attributes with Not_found -> 1 (* cell width *) and cell_width = try int_of_string @@ List.assoc NS.number_columns_spanned_attr attributes with Not_found -> 1 and expression = try load_formula @@ List.assoc NS.formula_attr attributes with Not_found -> ( let vtype = try List.assoc NS.ovalue_type_attr attributes with Not_found -> "" in try load_content cache (List.assoc NS.value_attr attributes) vtype with Not_found -> ( (* This is not a formula, neither a value ? *) try let value = Tools.List.find_map (function | Data x -> Some x | _ -> None) childs in load_content cache value vtype with Not_found -> Expression.Undefined ) ) in Cell {repetition; cell_width; expression} end let build_p (attributes:Xmlm.attribute list) = begin function | Data x::_ -> Data x | _ -> Data "" end let build_row (sheet:Sheet.t) (row_num:int ref) (attributes:Xmlm.attribute list) (childs:tree list) = begin let repetition = try int_of_string @@ List.assoc (NS.table, "number-rows-repeated") attributes with Not_found -> 1 in for i = 1 to repetition do let cell_num = ref 1 in List.iter (function | Cell cell -> for i = 1 to cell.repetition do ignore @@ Sheet.add ~history:false cell.expression (!cell_num, !row_num) sheet; cell_num := !cell_num + cell.cell_width done; | _ -> () ) childs; incr row_num done; Unit end let data str = Data str let load catalog source = begin (* Mutable datas *) let sheet = Sheet.create catalog in let cache = Hashtbl.create 10 in let table = String_dict.of_alist_exn [ ((NS.text ^ "p"), build_p); ((NS.table ^ "table-cell"), build_cell cache); ((NS.table ^ "table-row"), build_row sheet (ref 1)) ] in let el (((ns, name), attributes):Xmlm.tag) childs = begin match String_dict.find table (ns ^ name) with | Some f -> f attributes childs | None -> Unit end in match Xmlm.input_doc_tree ~el ~data source with | _, Unit -> sheet | _ -> raise Not_found end