2143d42003-01-03Martin Nilsson // // Struct ADT // By Martin Nilsson //
1cad622003-08-24Martin Nilsson #pike __REAL_VERSION__
2143d42003-01-03Martin Nilsson //! Implements a struct which can be used for serialization and //! deserialization of data. //! @example //! class ID3 { //! inherit ADT.Struct; //! Item head = Chars(3); //! Item title = Chars(30); //! Item artist = Chars(30); //! Item album = Chars(30); //! Item year = Chars(4);
ff36ce2003-05-04Martin Nilsson //! Item comment = Chars(30);
05a6492003-10-03Martin Nilsson //! Item genre = Byte();
2143d42003-01-03Martin Nilsson //! } //! //! Stdio.File f = Stdio.File("foo.mp3"); //! f->seek(-128); //! ADT.Struct tag = ID3(f); //! if(tag->head=="TAG") { //! write("Title: %s\n", tag->title); //! tag->title = "A new title" + "\0"*19; //! f->seek(-128); //! f->write( (string)tag ); //! }
34a6fb2008-05-02Peter Bortas //! //! @example
1c32ed2008-05-03Martin Nilsson //! class HollerithString {
34a6fb2008-05-02Peter Bortas //! inherit ADT.Struct; //! Item strlen = Word(); //! Item str = Chars(strlen); //! }
2143d42003-01-03Martin Nilsson 
9eaf1d2008-06-28Martin Nilsson protected local array(Item) items = ({}); protected local mapping(string:Item) names = ([]);
2143d42003-01-03Martin Nilsson 
e391e72005-01-04Martin Nilsson constant is_struct = 1; constant is_item = 1; int id = ADT.get_item_id();
2143d42003-01-03Martin Nilsson //! @decl void create(void|string|Stdio.File data) //! @param data //! Data to be decoded and populate the struct. Can //! either be a file object or a string.
9eaf1d2008-06-28Martin Nilsson optional protected void create(void|string|object file) {
1cc1092016-12-10Martin Nilsson  foreach(::_indices(this, 0), string index) {
6abaa02013-06-11Martin Nilsson  mixed val = ::`[](index, this, 0);
43ce642003-01-03Martin Nilsson  if(objectp(val) && val->is_item) names[index]=val; } items = values(names);
2143d42003-01-03Martin Nilsson  sort(items->id, items);
43ce642003-01-03Martin Nilsson 
2143d42003-01-03Martin Nilsson  if(file) decode(file); } //! @decl void decode(string|Stdio.File data) //! Decodes @[data] according to the struct and populates //! the struct variables. The @[data] can either be a file //! object or a string. void decode(string|object file) { if(stringp(file)) file = Stdio.FakeFile(file); items->decode(file); } //! Serializes the struct into a string. This string is equal //! to the string fed to @[decode] if nothing in the struct //! has been altered. string encode() { return items->encode()*""; } // --- LFUN overloading.
ff17962014-08-15Martin Nilsson //! @decl protected mixed `[](string item) //! @decl protected mixed `->(string item)
43ce642003-01-03Martin Nilsson //! The struct can be indexed by item name to get the //! associated value.
ff17962014-08-15Martin Nilsson //! @decl protected mixed `[]=(string item) //! @decl protected mixed `->=(string item)
43ce642003-01-03Martin Nilsson //! It is possible to assign a new value to a struct //! item by indexing it by name and assign a value.
9eaf1d2008-06-28Martin Nilsson protected mixed `[](string id) {
43ce642003-01-03Martin Nilsson  if(names[id]) return names[id]->get();
6abaa02013-06-11Martin Nilsson  return ::`[](id, this, 0);
2143d42003-01-03Martin Nilsson }
e391e72005-01-04Martin Nilsson this_program get() { return this; }
9eaf1d2008-06-28Martin Nilsson protected mixed `[]=(string id, mixed value) {
43ce642003-01-03Martin Nilsson  if(names[id]) names[id]->set(value); return id;
2143d42003-01-03Martin Nilsson }
9eaf1d2008-06-28Martin Nilsson protected function `-> = `[]; protected function `->= = `[]=;
2143d42003-01-03Martin Nilsson 
43ce642003-01-03Martin Nilsson //! The indices of a struct is the name of the struct items.
9eaf1d2008-06-28Martin Nilsson protected array(string) _indices() {
43ce642003-01-03Martin Nilsson  array ret = indices(names); sort(values(names)->id, ret); return ret; } //! The values of a struct is the values of the struct items.
9eaf1d2008-06-28Martin Nilsson protected array _values() {
f762e42003-01-04Martin Nilsson  return items->get();
43ce642003-01-03Martin Nilsson }
2143d42003-01-03Martin Nilsson  //! The size of the struct object is the number of bytes //! allocated for the struct.
9eaf1d2008-06-28Martin Nilsson protected int _sizeof() {
b0df6d2005-04-03Martin Nilsson  if(!sizeof(items)) return 0;
1a16542005-04-02Martin Nilsson  return `+( @sizeof(items[*]) );
2143d42003-01-03Martin Nilsson } //! The struct can be casted into a string, which is eqivivalent //! to running @[encode], or into an array. When casted into an //! array each array element is the encoded value of that struct //! item.
9eaf1d2008-06-28Martin Nilsson protected mixed cast(string to) {
2143d42003-01-03Martin Nilsson  switch(to) { case "string": return encode(); case "array": return items->encode(); }
ec1a0f2014-08-16Martin Nilsson  return UNDEFINED;
2143d42003-01-03Martin Nilsson }
82c6512003-07-04Martin Nilsson 
2143d42003-01-03Martin Nilsson // --- Virtual struct item class //! Interface class for struct items. class Item {
e391e72005-01-04Martin Nilsson  int id = ADT.get_item_id();
2143d42003-01-03Martin Nilsson  constant is_item=1;
9eaf1d2008-06-28Martin Nilsson  protected mixed value;
2143d42003-01-03Martin Nilsson  int size; //! @ignore void decode(object); string encode(); //! @endignore void set(mixed in) { value=in; } mixed get() { return value; }
1a16542005-04-02Martin Nilsson  int _sizeof() { return size; }
9eaf1d2008-06-28Martin Nilsson  protected string _sprintf(int t) {
2143d42003-01-03Martin Nilsson  return t=='O' && sprintf("%O(%O)", this_program, value); } } // --- Struct items. //! One byte, integer value between 0 and 255. class Byte { inherit Item; int size = 1;
9eaf1d2008-06-28Martin Nilsson  protected int(0..255) value;
f7f8772003-01-03Martin Nilsson  //! The byte can be initialized with an optional value.
9eaf1d2008-06-28Martin Nilsson  protected void create(void|int(0..255) initial_value) {
f7f8772003-01-03Martin Nilsson  set(initial_value); }
2143d42003-01-03Martin Nilsson  void set(int(0..255) in) {
05a6492003-10-03Martin Nilsson  if(in<0 || in>255) error("Value %d out of bound (0..255).\n", in);
2143d42003-01-03Martin Nilsson  value = in; }
e391e72005-01-04Martin Nilsson  void decode(object f) { sscanf(f->read(1), "%c", value); } string encode() { return sprintf("%c", value); }
2143d42003-01-03Martin Nilsson 
9eaf1d2008-06-28Martin Nilsson  protected string _sprintf(int t) {
6e3a792003-12-31Martin Nilsson  return t=='O' && sprintf("%O(%d/%O)", this_program, value, (string)({value}));
2143d42003-01-03Martin Nilsson  } }
108cdd2004-08-21Martin Nilsson //! One byte, signed integer value between -128 and 127. class SByte { inherit Item; int size = 1;
9eaf1d2008-06-28Martin Nilsson  protected int(-128..127) value;
108cdd2004-08-21Martin Nilsson  //! The byte can be initialized with an optional value.
9eaf1d2008-06-28Martin Nilsson  protected void create(void|int(-128..127) initial_value) {
108cdd2004-08-21Martin Nilsson  set(initial_value); } void set(int(-128..127) in) { if(in<-128 || in>127) error("Value %d out of bound (-128..127).\n", in); value = in; }
e391e72005-01-04Martin Nilsson  void decode(object f) { sscanf(f->read(1), "%+1c", value); } string encode() { return sprintf("%1c", value); }
108cdd2004-08-21Martin Nilsson 
9eaf1d2008-06-28Martin Nilsson  protected string _sprintf(int t) {
108cdd2004-08-21Martin Nilsson  return t=='O' && sprintf("%O(%d/%O)", this_program, value, (string)({value})); } }
6e3a792003-12-31Martin Nilsson //! One word (2 bytes) in network order, integer value between 0 and 65535.
82c6512003-07-04Martin Nilsson //! @seealso //! @[Drow]
2143d42003-01-03Martin Nilsson class Word {
f7f8772003-01-03Martin Nilsson  inherit Item;
2143d42003-01-03Martin Nilsson  int size = 2;
9eaf1d2008-06-28Martin Nilsson  protected int(0..) value;
2143d42003-01-03Martin Nilsson 
16e8a12004-05-28Henrik Grubbström (Grubba)  //! The word can be initialized with an optional value.
9eaf1d2008-06-28Martin Nilsson  protected void create(void|int(0..65535) initial_value) {
f7f8772003-01-03Martin Nilsson  set(initial_value); }
82c6512003-07-04Martin Nilsson  void set(int(0..) in) {
ea0cf22004-03-19Henrik Grubbström (Grubba)  if(in<0 || in>~((-1)<<size*8)) error("Value %d out of bound (0..%d).\n", in, ~((-1)<<size*8));
2143d42003-01-03Martin Nilsson  value = in; }
82c6512003-07-04Martin Nilsson  void decode(object f) { sscanf(f->read(size), "%"+size+"c", value); } string encode() { return sprintf("%"+size+"c", value); }
2143d42003-01-03Martin Nilsson 
9eaf1d2008-06-28Martin Nilsson  protected string _sprintf(int t) {
2143d42003-01-03Martin Nilsson  return t=='O' && sprintf("%O(%d)", this_program, value); } }
108cdd2004-08-21Martin Nilsson //! One word (2 bytes) in network order, signed integer value between //! 0 and 65535. class SWord { inherit Item; int size = 2;
9eaf1d2008-06-28Martin Nilsson  protected int value;
108cdd2004-08-21Martin Nilsson  //! The word can be initialized with an optional value.
9eaf1d2008-06-28Martin Nilsson  protected void create(void|int(-32768..32767) initial_value) {
108cdd2004-08-21Martin Nilsson  set(initial_value); }
fbd3c62013-07-19Tobias S. Josefowitz  void set(int in) { int negmask; for (int i; i < size; i++) { negmask = (negmask << 8) | 0xff; } if(in<-(~(1<<size*8-1)&negmask) || in>~((-1)<<size*8-1))
108cdd2004-08-21Martin Nilsson  error("Value %d out of bound (%d..%d).\n",
fbd3c62013-07-19Tobias S. Josefowitz  in, -(~(1<<size*8-1)&negmask), ~((-1)<<size*8-1));
108cdd2004-08-21Martin Nilsson  value = in; } void decode(object f) { sscanf(f->read(size), "%+"+size+"c", value); }
fbd3c62013-07-19Tobias S. Josefowitz  string encode() { return sprintf("%"+size+"c", value); }
108cdd2004-08-21Martin Nilsson 
9eaf1d2008-06-28Martin Nilsson  protected string _sprintf(int t) {
108cdd2004-08-21Martin Nilsson  return t=='O' && sprintf("%O(%d)", this_program, value); } }
6e3a792003-12-31Martin Nilsson //! One word (2 bytes) in intel order, integer value between 0 and 65535.
82c6512003-07-04Martin Nilsson //! @seealso //! @[Word] class Drow { inherit Word; void decode(object f) { sscanf(f->read(size), "%-"+size+"c", value); } string encode() { return sprintf("%-"+size+"c", value); } }
6e3a792003-12-31Martin Nilsson //! One longword (4 bytes) in network order, integer value between 0 and 2^32.
82c6512003-07-04Martin Nilsson //! @seealso //! @[Gnol] class Long { inherit Word; int size = 4;
16e8a12004-05-28Henrik Grubbström (Grubba)  //! The longword can be initialized with an optional value.
9eaf1d2008-06-28Martin Nilsson  protected void create(void|int(0..) initial_value) {
16e8a12004-05-28Henrik Grubbström (Grubba)  set(initial_value); }
82c6512003-07-04Martin Nilsson }
108cdd2004-08-21Martin Nilsson //! One longword (4 bytes) in network order, signed integer value //! -(2^31) <= x < 2^31-1. class SLong { inherit SWord; int size = 4; //! The longword can be initialized with an optional value.
9eaf1d2008-06-28Martin Nilsson  protected void create(void|int initial_value) {
108cdd2004-08-21Martin Nilsson  set(initial_value); } }
6e3a792003-12-31Martin Nilsson //! One longword (4 bytes) in intel order, integer value between 0 and 2^32.
82c6512003-07-04Martin Nilsson //! @seealso //! @[Long] class Gnol { inherit Drow; int size = 4;
16e8a12004-05-28Henrik Grubbström (Grubba)  //! The longword can be initialized with an optional value.
9eaf1d2008-06-28Martin Nilsson  protected void create(void|int(0..) initial_value) {
16e8a12004-05-28Henrik Grubbström (Grubba)  set(initial_value); }
82c6512003-07-04Martin Nilsson }
6e3a792003-12-31Martin Nilsson 
2143d42003-01-03Martin Nilsson //! A string of bytes. class Chars { inherit Item;
9eaf1d2008-06-28Martin Nilsson  protected Item dynsize; protected string value;
2143d42003-01-03Martin Nilsson 
ff17962014-08-15Martin Nilsson  //! @decl protected void create(int|Item size, void|string value)
34a6fb2008-05-02Peter Bortas  //! @[size] is the number of bytes that are part of this struct //! item, or optionally an earlier Item that will be looked up in //! runtime.
f7f8772003-01-03Martin Nilsson  //! The initial value of the char string is @[value] or, //! if not provided, a string of zero bytes.
9eaf1d2008-06-28Martin Nilsson  protected void create(int|Item _size, void|string _value) {
34a6fb2008-05-02Peter Bortas  if(intp(_size)) size = _size;
1c32ed2008-05-03Martin Nilsson  else { dynsize = _size; size = dynsize->get(); }
f7f8772003-01-03Martin Nilsson  if(_value) set(_value); else
1c32ed2008-05-03Martin Nilsson  value = "\0"*size;
f7f8772003-01-03Martin Nilsson  }
2143d42003-01-03Martin Nilsson  void set(string in) {
1c32ed2008-05-03Martin Nilsson  if(!dynsize && sizeof(in)!=size)
05a6492003-10-03Martin Nilsson  error("String has wrong size (%d instead of %d).\n", sizeof(in), size);
2143d42003-01-03Martin Nilsson  if(String.width(in)!=8) error("Wide strings not allowed.\n");
1c32ed2008-05-03Martin Nilsson  if(dynsize) dynsize->set(sizeof(in));
2143d42003-01-03Martin Nilsson  value = in; }
a3ceaa2003-10-22Martin Nilsson  void decode(object f) {
1c32ed2008-05-03Martin Nilsson  if(objectp(dynsize)) size = dynsize->get();
a3ceaa2003-10-22Martin Nilsson  value=f->read(size); if(!value || sizeof(value)!=size) error("End of data reached.\n"); }
2143d42003-01-03Martin Nilsson  string encode() { return value; }
9eaf1d2008-06-28Martin Nilsson  protected string _sprintf(int t) {
2143d42003-01-03Martin Nilsson  return t=='O' && sprintf("%O(%O)", this_program, value); } }
a3ceaa2003-10-22Martin Nilsson class Varchars { inherit Chars;
9eaf1d2008-06-28Martin Nilsson  protected int min,max;
a3ceaa2003-10-22Martin Nilsson 
9eaf1d2008-06-28Martin Nilsson  protected void create(void|int _min, void|int _max, void|string _value) {
a3ceaa2003-10-22Martin Nilsson  min = _min; max = _max; set(_value || " "*min); } void set(string in) { if(sizeof(in)<min) error("String is too short.\n"); if(max && sizeof(in)>max) error("String is too long.\n"); if(String.width(in)!=8) error("Wide strings not allowed.\n"); size = sizeof(in)+1; value = in; } void decode(object f) { String.Buffer buf = String.Buffer( predef::max(256,min) ); string next; do { next = f->read(1); } while (next && next!="\0" && buf->add(next)); set(buf->get()); } string encode() { return value + "\0"; } }
108cdd2004-08-21Martin Nilsson //! Alias for @[SByte] class int8 { inherit SByte; } //! Alias for @[Byte] class uint8 { inherit Byte; } //! Alias for @[SWord] class int16 { inherit SWord; } //! Alias for @[Word] class uint16 { inherit Word; } //! Alias for @[SLong] class int32 { inherit SLong; } //! Alias for @[Long] class uint32 { inherit Long; } //! 64 bit signed integer.
e391e72005-01-04Martin Nilsson class int64 { inherit SLong; int size = 8; void set(int v) { value = v; } }
108cdd2004-08-21Martin Nilsson  //! 64 bit unsigned integer.
e391e72005-01-04Martin Nilsson class uint64 { inherit Long; int size = 8; void set(int v) { value = v; } }
108cdd2004-08-21Martin Nilsson 
9eaf1d2008-06-28Martin Nilsson protected string _sprintf(int t) {
6e3a792003-12-31Martin Nilsson  if(t!='O') return UNDEFINED; string ret = sprintf("%O(\n", this_program);
e391e72005-01-04Martin Nilsson  foreach(items, Item item) { string i = sprintf(" %s : %s\n", search(names,item), (sprintf("%O", item)/"->")[-1]); if(item->is_struct) i = (i/"\n")[..<1]*"\n "+"\n"; ret += i; }
6e3a792003-12-31Martin Nilsson  return ret + ")";
2143d42003-01-03Martin Nilsson }