Plasma GitLab Archive
Projects Blog Knowledge

(*
 * <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! *)

This web site is published by Informatikbüro Gerd Stolpmann
Powered by Caml