4728522003-03-06Henrik Grubbström (Grubba) #pike __REAL_VERSION__
1b3d4e2003-03-08Martin Nilsson #pragma strict_types
83c38b2004-09-14Henrik Grubbström (Grubba)  //! Various Abstract Data Types.
8a4e052003-03-27Henrik Grubbström (Grubba) #if constant(_ADT)
d25bf52003-02-12Andreas Pettersson inherit _ADT;
8a4e052003-03-27Henrik Grubbström (Grubba) #endif /* _ADT */
4728522003-03-06Henrik Grubbström (Grubba) 
83c38b2004-09-14Henrik Grubbström (Grubba) constant List = __builtin.List;
25616a2004-03-23Martin Nilsson 
e391e72005-01-04Martin Nilsson // Internal stuff for ADT.Struct
9eaf1d2008-06-28Martin Nilsson protected int item_counter;
e391e72005-01-04Martin Nilsson int get_item_id() { return item_counter++; }
5b15a92003-03-07Martin Nilsson //! String buffer with the possibility to read and write data //! as they would be formatted in structs.
4728522003-03-06Henrik Grubbström (Grubba) class struct { string buffer; int index;
5b15a92003-03-07Martin Nilsson  //! Create a new buffer, optionally initialized with the //! value @[s].
4728522003-03-06Henrik Grubbström (Grubba)  void create(void|string s) { buffer = s || ""; index = 0; }
5b15a92003-03-07Martin Nilsson  //! Trims the buffer to only contain the data after the //! read pointer and returns the contents of the buffer.
4728522003-03-06Henrik Grubbström (Grubba)  string contents() { buffer = buffer[index..]; index = 0; return buffer; }
5b15a92003-03-07Martin Nilsson  //! Adds the data @[s] verbatim to the end of the buffer.
4728522003-03-06Henrik Grubbström (Grubba)  void add_data(string s) { buffer += s; }
5b15a92003-03-07Martin Nilsson  //! Return all the data in the buffer and empties it.
4728522003-03-06Henrik Grubbström (Grubba)  string pop_data() { string res = buffer; create(); return res; }
5b15a92003-03-07Martin Nilsson  //! Appends an unsigned integer in network order to the buffer.
4728522003-03-06Henrik Grubbström (Grubba)  //! //! @param i
5b15a92003-03-07Martin Nilsson  //! Unsigned integer to append.
4728522003-03-06Henrik Grubbström (Grubba)  //! @param len
5b15a92003-03-07Martin Nilsson  //! Length of integer in bytes.
6514d22007-04-19Martin Stjernholm  void put_uint(int i, int(0..) len)
4728522003-03-06Henrik Grubbström (Grubba)  { if (i<0)
5b15a92003-03-07Martin Nilsson  error("Negative argument.\n");
4728522003-03-06Henrik Grubbström (Grubba)  add_data(sprintf("%*c", len, i)); }
5b15a92003-03-07Martin Nilsson  //! Appends a variable string @[s] preceded with an unsigned integer //! of the size @[len_width] declaring the length of the string. The //! string @[s] should be 8 bits wide.
6514d22007-04-19Martin Stjernholm  void put_var_string(string s, int(0..) len_width)
4728522003-03-06Henrik Grubbström (Grubba)  { if ( (len_width <= 3) && (sizeof(s) >= ({ -1, 0x100, 0x10000, 0x1000000 })[len_width] ))
5b15a92003-03-07Martin Nilsson  error("Field overflow.\n");
4728522003-03-06Henrik Grubbström (Grubba)  put_uint(sizeof(s), len_width); add_data(s); }
5b15a92003-03-07Martin Nilsson #if constant(Gmp.mpz) //! Appends a bignum @[i] as a variable string preceded with an //! unsigned integer of the size @[len_width] declaring the length //! of the string. @[len_width] defaults to 2.
6514d22007-04-19Martin Stjernholm  void put_bignum(Gmp.mpz i, int(0..)|void len_width)
4728522003-03-06Henrik Grubbström (Grubba)  { if (i<0)
5b15a92003-03-07Martin Nilsson  error("Negative argument.\n"); put_var_string(i->digits(256), len_width || 2);
4728522003-03-06Henrik Grubbström (Grubba)  }
5b15a92003-03-07Martin Nilsson #endif
4728522003-03-06Henrik Grubbström (Grubba) 
5b15a92003-03-07Martin Nilsson  //! Appends the fix sized string @[s] to the buffer.
4728522003-03-06Henrik Grubbström (Grubba)  void put_fix_string(string s) { add_data(s); }
5b15a92003-03-07Martin Nilsson  //! Appends an array of unsigned integers of width @[item_size] //! to the buffer.
6514d22007-04-19Martin Stjernholm  void put_fix_uint_array(array(int) data, int(0..) item_size)
4728522003-03-06Henrik Grubbström (Grubba)  { foreach(data, int i) put_uint(i, item_size); }
5b15a92003-03-07Martin Nilsson  //! Appends an array of unsigned integers of width @[item_size] //! to the buffer, preceded with an unsigned integer @[len] declaring //! the size of the array.
6514d22007-04-19Martin Stjernholm  void put_var_uint_array(array(int) data, int(0..) item_size, int(0..) len)
4728522003-03-06Henrik Grubbström (Grubba)  { put_uint(sizeof(data), len); put_fix_uint_array(data, item_size); }
5b15a92003-03-07Martin Nilsson  //! Reads an unsigned integer from the buffer. int(0..) get_uint(int len)
4728522003-03-06Henrik Grubbström (Grubba)  {
1b3d4e2003-03-08Martin Nilsson  int(0..) i;
4728522003-03-06Henrik Grubbström (Grubba)  if ( (sizeof(buffer) - index) < len)
5b15a92003-03-07Martin Nilsson  error("No data.\n");
4728522003-03-06Henrik Grubbström (Grubba)  sscanf(buffer, "%*" + (string) index +"s%" + (string) len + "c", i); index += len; return i; }
5b15a92003-03-07Martin Nilsson  //! Reads a fixed sized string of length @[len] from the buffer.
4728522003-03-06Henrik Grubbström (Grubba)  string get_fix_string(int len) { if ((sizeof(buffer) - index) < len)
5b15a92003-03-07Martin Nilsson  error("No data\n"); string res = buffer[index .. index + len - 1];
4728522003-03-06Henrik Grubbström (Grubba)  index += len; return res; }
5b15a92003-03-07Martin Nilsson  //! Reads a string written by @[put_var_string] from the buffer.
4728522003-03-06Henrik Grubbström (Grubba)  string get_var_string(int len) { return get_fix_string(get_uint(len)); } #if constant(Gmp.mpz)
5b15a92003-03-07Martin Nilsson  //! Reads a bignum written by @[put_bignum] from the buffer. Gmp.mpz get_bignum(int|void len)
4728522003-03-06Henrik Grubbström (Grubba)  { return Gmp.mpz(get_var_string(len || 2), 256); } #endif
5b15a92003-03-07Martin Nilsson  //! Get the remaining data from the buffer and clears the buffer.
4728522003-03-06Henrik Grubbström (Grubba)  string get_rest() { string s = buffer[index..]; create(); return s; }
328cf92003-11-07Martin Nilsson  //! Reads an array of integers as written by @[put_fix_uint_array]
5b15a92003-03-07Martin Nilsson  //! from the buffer.
b6345f2004-01-23Martin Nilsson  array(int) get_fix_uint_array(int item_size, int size)
4728522003-03-06Henrik Grubbström (Grubba)  {
b6345f2004-01-23Martin Nilsson  array(int) res = allocate(size);
4728522003-03-06Henrik Grubbström (Grubba)  for(int i = 0; i<size; i++) res[i] = get_uint(item_size); return res; }
328cf92003-11-07Martin Nilsson  //! Reads an array of integers as written by @[put_var_uint_array]
5b15a92003-03-07Martin Nilsson  //! from the buffer.
b6345f2004-01-23Martin Nilsson  array(int) get_var_uint_array(int item_size, int len)
4728522003-03-06Henrik Grubbström (Grubba)  { return get_fix_uint_array(item_size, get_uint(len)); }
5b15a92003-03-07Martin Nilsson  //! Returns one of there is any more data to read. int(0..1) is_empty()
4728522003-03-06Henrik Grubbström (Grubba)  { return (index == sizeof(buffer)); } }