(* * <COPYRIGHT> * Copyright 2002 Joachim Schrod Network and Publication Consultance GmbH, Gerd Stolpmann * * <GPL> * This file is part of WDialog. * * WDialog 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 2 of the License, or * (at your option) any later version. * * WDialog 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 WDialog; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * </> *) (* $Id: wd_serialize.ml,v 3.1 2005-06-11 14:24:14 stolpmann Exp $ * ---------------------------------------------------------------------- * *) open Wd_types (* Serialization format (NEW since WDialog 2.1): * * Strings: * S(<length>)<string> * Enums: * E(<size>)<items as strings> * Dyn enums: * Y(<size>)<list of internal and external items as strings> * Alists: * A(<size>)<list of key as string and value> * Lists in general: * L(<arity>,<size>)<list of tuples> * Dialogs: * - As definition: * D() for non-existent dialog * D(<id>) * <dialog_name as string> * (from here on serialization is done in dlg#serialize) * <page_name as string> * <next_page as string> * <last_event, see below> * <IP address, as string> * <variables as Alist> * <ui_buttons as string> (serialized interactor) * <ui_imagebuttons as string> (serialized interactor) * <ui_anchors as string> (serialized interactor) * <ui_indexed_buttons as string> (serialized interactor) * <ui_indexed_imagebuttons as string> (serialized interactor) * <ui_indexed_anchors as string> (serialized interactor) * <ui_vars as string> (serialized interactor) * <ui_enumvars as string> (an L(3,<size>) list) * <ui_uploads as string> (serialized interactor) * - As reference: * R(<id>) * Interactors: * I(<length>)<length bytes, private format, see Wd_interactor> * Events: * V(b)<name as string> - Button * V(ib)<name as string><x as string><y as string> - Image_button * V(xb)<name as string><index as string> - Indexed_button * V(xib)<name as string><index as string><x as string><y as string> * - Indexed_image_button * V(n) - No_event * V(p)<name as string> - Popup_request * Missing value: * 0 *) let rec serialize_value m b v = (* Serializes [v] and adds the string representation to [b]. * m is a hashtable of the objects that have already been serialized. *) match v with | String_value s -> serialize_string b s | Enum_value e -> Buffer.add_string b "E("; Buffer.add_string b (string_of_int (List.length e)); Buffer.add_string b ")"; List.iter (serialize_string b) e | Dyn_enum_value d -> Buffer.add_string b "Y("; Buffer.add_string b (string_of_int (List.length d)); Buffer.add_string b ")"; List.iter (fun (i,x) -> serialize_string b i; serialize_string b x) d | Alist_value a -> serialize_alist m b a | Dialog_value None -> Buffer.add_string b "D()"; | Dialog_value (Some dlg) -> if Hashtbl.mem m dlg then ( Buffer.add_string b "R("; Buffer.add_string b (string_of_int (Oo.id dlg)); Buffer.add_string b ")"; ) else ( Hashtbl.add m dlg (); Buffer.add_string b "D("; Buffer.add_string b (string_of_int (Oo.id dlg)); Buffer.add_string b ")"; serialize_string b dlg#name; dlg # serialize m b ) and serialize_string b s = Buffer.add_string b "S("; Buffer.add_string b (string_of_int (String.length s)); Buffer.add_string b ")"; Buffer.add_string b s; and serialize_alist m b a = Buffer.add_string b "A("; Buffer.add_string b (string_of_int (List.length a)); Buffer.add_string b ")"; List.iter (fun (k,v) -> serialize_string b k; serialize_value m b v ) a ;; let serialize_string_option b s_opt = match s_opt with | None -> Buffer.add_string b "0" | Some s -> serialize_string b s ;; let serialize_unit b () = Buffer.add_string b "0" ;; let serialize_event b e = match e with | Button n -> Buffer.add_string b "V(b)"; serialize_string b n | Image_button (n,x,y) -> Buffer.add_string b "V(ib)"; serialize_string b n; serialize_string b (string_of_int x); serialize_string b (string_of_int y); | Indexed_button (n,idx) -> Buffer.add_string b "V(xb)"; serialize_string b n; serialize_string b idx; | Indexed_image_button (n,idx,x,y) -> Buffer.add_string b "V(xib)"; serialize_string b n; serialize_string b idx; serialize_string b (string_of_int x); serialize_string b (string_of_int y); | No_event -> Buffer.add_string b "V(n)"; | Popup_request n -> Buffer.add_string b "V(p)"; serialize_string b n; ;; type ds_token = | S_tok of int | E_tok of int | Y_tok of int | A_tok of int | L_tok of int * int | D_tok of int option | R_tok of int | I_tok of int | V_tok of string | T_tok of int * int * int * int | Null_tok ;; let int2_re = Netstring_pcre.regexp "^([0-9]+),([0-9]+)$" let int4_re = Netstring_pcre.regexp "^([0-9]+),([0-9]+),([0-9]+),([0-9]+)$" let ds_scan_token buf = let advance() = if buf.ds_pos < buf.ds_end then buf.ds_pos <- buf.ds_pos + 1 else failwith "ds_scan_token 1" in let token_arg() = let p = ref buf.ds_pos in if buf.ds_str.[ !p ] <> '(' then failwith "ds_scan_token 2"; incr p; while !p < buf.ds_end && buf.ds_str.[ !p ] <> ')' do incr p done; if !p >= buf.ds_end then failwith "ds_scan_token 3"; let s = String.sub buf.ds_str (buf.ds_pos + 1) (!p - buf.ds_pos - 1) in buf.ds_pos <- !p+1; s in let int_token_arg() = let s = token_arg() in let n = try int_of_string s with _ -> failwith "ds_scan_token 4" in n in let nat_token_arg() = let n = int_token_arg() in if n < 0 then failwith "ds_scan_token 5"; n in let int_opt_token_arg() = let s = token_arg() in if s = "" then None else try Some(int_of_string s) with _ -> failwith "ds_scan_token 6" in let nat2_token_arg() = let s = token_arg() in match Netstring_pcre.string_match int2_re s 0 with | Some m -> let s1 = Netstring_pcre.matched_group m 1 s in let s2 = Netstring_pcre.matched_group m 2 s in ( try let n1 = int_of_string s1 in let n2 = int_of_string s2 in if n1 < 0 || n2 < 0 then failwith "ds_scan_token 7"; (n1,n2) with _ -> failwith "ds_scan_token 8" ) | None -> failwith "ds_scan_token 9" in let nat4_token_arg() = let s = token_arg() in match Netstring_pcre.string_match int4_re s 0 with | Some m -> let s1 = Netstring_pcre.matched_group m 1 s in let s2 = Netstring_pcre.matched_group m 2 s in let s3 = Netstring_pcre.matched_group m 3 s in let s4 = Netstring_pcre.matched_group m 4 s in ( try let n1 = int_of_string s1 in let n2 = int_of_string s2 in let n3 = int_of_string s3 in let n4 = int_of_string s4 in if n1 < 0 || n2 < 0 || n3 < 0 || n4 < 0 then failwith "ds_scan_token 10"; (n1,n2,n3,n4) with _ -> failwith "ds_scan_token 11" ) | None -> failwith "ds_scan_token 12" in match buf.ds_str.[ buf.ds_pos ] with | 'S' -> advance(); let n = nat_token_arg() in S_tok n | 'E' -> advance(); let n = nat_token_arg() in E_tok n | 'Y' -> advance(); let n = nat_token_arg() in Y_tok n | 'A' -> advance(); let n = nat_token_arg() in A_tok n | 'L' -> advance(); let n1,n2 = nat2_token_arg() in L_tok(n1,n2) | 'D' -> advance(); let n_opt = int_opt_token_arg() in D_tok n_opt | 'R' -> advance(); let n = int_token_arg() in R_tok n | 'I' -> advance(); let n = nat_token_arg() in I_tok n | 'V' -> advance(); let s = token_arg() in V_tok s | 'T' -> advance(); let n1,n2,n3,n4 = nat4_token_arg() in T_tok(n1,n2,n3,n4) | '0' -> advance(); Null_tok | _ -> failwith "ds_scan_token 13" ;; let ds_string tok buf = match tok with | S_tok n -> if buf.ds_pos + n > buf.ds_end then failwith "ds_scan_token"; let s = String.sub buf.ds_str buf.ds_pos n in buf.ds_pos <- buf.ds_pos + n; s | _ -> failwith "ds_string" ;; let unserialize_string buf = let tok = ds_scan_token buf in ds_string tok buf ;; let rec ds_make_list n f = if n > 0 then let x = f() in x :: (ds_make_list (n-1) f) else [] ;; let rec unserialize_value buf = let tok = ds_scan_token buf in match tok with | S_tok n -> String_value (ds_string tok buf) | E_tok n -> Enum_value (ds_make_list n (fun () -> unserialize_string buf)) | Y_tok n -> Dyn_enum_value (ds_make_list n (fun () -> let x1 = unserialize_string buf in let x2 = unserialize_string buf in (x1,x2))) | A_tok n -> Alist_value (ds_alist tok buf) | D_tok n_opt -> ( match n_opt with | None -> Dialog_value None | Some n -> let name = unserialize_string buf in let dlg = try buf.ds_universe # create buf.ds_environment name with Not_found -> failwith "unserialize_value" in Hashtbl.add buf.ds_dialogs n dlg; dlg # unserialize buf; Dialog_value(Some dlg) ) | R_tok n -> ( try let dlg = Hashtbl.find buf.ds_dialogs n in Dialog_value (Some dlg) with Not_found -> failwith "unserialize_value" ) | _ -> failwith "unserialize_value" and ds_alist tok buf = match tok with | A_tok n -> ds_make_list n (fun () -> let k = unserialize_string buf in let v = unserialize_value buf in (k,v)) | _ -> failwith "ds_alist" ;; let unserialize_alist buf = let tok = ds_scan_token buf in ds_alist tok buf ;; let unserialize_event buf = let tok = ds_scan_token buf in match tok with | V_tok "b" -> Button (unserialize_string buf) | V_tok "ib" -> let name = unserialize_string buf in let x = unserialize_string buf in let y = unserialize_string buf in ( try Image_button(name,int_of_string x,int_of_string y) with _ -> failwith "unserialize_event" ) | V_tok "xb" -> let name = unserialize_string buf in let index = unserialize_string buf in Indexed_button(name,index) | V_tok "xib" -> let name = unserialize_string buf in let index = unserialize_string buf in let x = unserialize_string buf in let y = unserialize_string buf in ( try Indexed_image_button(name,index,int_of_string x,int_of_string y) with _ -> failwith "unserialize_event" ) | V_tok "n" -> No_event | V_tok "p" -> Popup_request(unserialize_string buf) | _ -> failwith "unserialize_event" ;; let unserialize_string_option buf = let tok = ds_scan_token buf in match tok with | S_tok n -> Some(ds_string tok buf) | Null_tok -> None | _ -> failwith "unserialize_string_option" ;; let unserialize_unit buf = let tok = ds_scan_token buf in match tok with | Null_tok -> () | _ -> failwith "unserialize_unit" ;; (* Some functions also in Wd_dialog and in Wd_interactor! *)